R18-1/R18-3: 接入企业微信入口绑定与免登回退

这个提交包含在:
2026-03-22 08:33:53 +08:00
父节点 2a1ffe66f3
当前提交 215e3967bc
共修改 15 个文件,包含 1394 行新增和 26 行删除
+323 -10
查看文件
@@ -275,6 +275,7 @@ enum WorkspaceOrgMode {
enum WorkspacePrimaryEntryMode {
password
wecom
}
enum WorkspaceNotificationStrategy {
@@ -364,6 +365,72 @@ enum TodoSource {
weekly_report
}
enum ProjectStatus {
draft
active
paused
completed
archived
}
enum ProjectRole {
owner
manager
member
observer
}
enum ProjectMilestoneStatus {
pending
in_progress
done
delayed
cancelled
}
enum ProjectTaskStatus {
todo
doing
blocked
done
cancelled
}
enum ProjectTaskPriority {
low
normal
high
urgent
}
enum ProjectRiskLevel {
low
medium
high
}
enum ProjectDeliveryRecordType {
kickoff
onsite
stage_acceptance
final_acceptance
handover
}
enum ConfidentialityLevel {
public
internal
confidential
restricted
}
enum DocumentStorageType {
oa_link
nas
internal_share
offline_archive
}
model Department {
id String @id @default(uuid()) @db.Uuid
name String
@@ -479,15 +546,26 @@ model Employee {
workflow_tasks_assigned WorkflowTask[] @relation("WorkflowTaskAssignee")
workflow_tasks_completed WorkflowTask[] @relation("WorkflowTaskCompleter")
approval_transfers_from ApprovalTransfer[] @relation("TransferFrom")
approval_transfers_to ApprovalTransfer[] @relation("TransferTo")
password_reset_codes PasswordResetCode[]
lifecycle_events EmployeeLifecycleEvent[]
checklist_tasks EmployeeChecklistTask[]
presence_records EmployeePresence[]
weekly_reports WeeklyReport[]
todo_items_assigned TodoItem[] @relation("TodoAssignee")
todo_items_created TodoItem[] @relation("TodoCreator")
approval_transfers_from ApprovalTransfer[] @relation("TransferFrom")
approval_transfers_to ApprovalTransfer[] @relation("TransferTo")
password_reset_codes PasswordResetCode[]
lifecycle_events EmployeeLifecycleEvent[]
checklist_tasks EmployeeChecklistTask[]
presence_records EmployeePresence[]
weekly_reports WeeklyReport[]
todo_items_assigned TodoItem[] @relation("TodoAssignee")
todo_items_created TodoItem[] @relation("TodoCreator")
wecom_identity_binding WecomIdentityBinding?
owned_projects Project[] @relation("ProjectOwner")
managed_projects Project[] @relation("ProjectManager")
project_memberships ProjectMember[]
owned_project_milestones ProjectMilestone[] @relation("ProjectMilestoneOwner")
assigned_project_tasks ProjectTask[] @relation("ProjectTaskAssignee")
created_project_tasks ProjectTask[] @relation("ProjectTaskCreator")
owned_project_risks ProjectRisk[] @relation("ProjectRiskOwner")
owned_project_delivery_records ProjectDeliveryRecord[] @relation("ProjectDeliveryRecordOwner")
owned_contract_registries ContractRegistry[] @relation("ContractRegistryOwner")
owned_confidential_document_refs ConfidentialDocumentRef[] @relation("ConfidentialDocumentRefOwner")
@@index([department_id])
@@index([legal_entity_id], map: "idx_employees_legal_entity")
@@ -1052,6 +1130,7 @@ model ReimbursementForm {
payment_channel String? @db.VarChar(20)
paid_at DateTime?
paid_by String? @db.Uuid
project_id String? @db.Uuid
created_at DateTime @default(now())
created_by String? @db.Uuid
@@ -1062,6 +1141,7 @@ model ReimbursementForm {
owner Employee @relation("ReimbursementOwner", fields: [owner_id], references: [id], onDelete: Restrict)
paid_by_employee Employee? @relation("ReimbursementPaidBy", fields: [paid_by], references: [id], onDelete: SetNull)
department Department @relation(fields: [department_id], references: [id], onDelete: Restrict)
project Project? @relation(fields: [project_id], references: [id], onDelete: SetNull)
items ReimbursementItem[]
invoice_pool_items InvoicePool[]
@@ -1074,6 +1154,7 @@ model ReimbursementForm {
@@index([submitter_id])
@@index([department_id])
@@index([paid_by])
@@index([project_id], map: "idx_reimbursement_forms_project")
@@index([status])
@@index([reimbursement_date])
@@index([owner_id, status, updated_at], map: "idx_reimbursement_owner_status_updated_at")
@@ -1608,7 +1689,8 @@ model WeeklyReport {
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade)
employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade)
project_links ProjectLinkOnWeeklyReport[]
@@unique([employee_id, week_start], map: "weekly_reports_employee_week_start_ux")
@@index([week_start, status], map: "idx_weekly_reports_week_status")
@@ -1625,6 +1707,7 @@ model TodoItem {
priority TodoPriority @default(normal)
status TodoStatus @default(todo)
source TodoSource @default(manual)
project_id String? @db.Uuid
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
@@ -1632,12 +1715,239 @@ model TodoItem {
assignee Employee @relation("TodoAssignee", fields: [assignee_employee_id], references: [id], onDelete: Restrict)
creator Employee @relation("TodoCreator", fields: [created_by], references: [id], onDelete: Restrict)
project Project? @relation(fields: [project_id], references: [id], onDelete: SetNull)
@@index([assignee_employee_id, status, due_date], map: "idx_todo_items_assignee_status_due")
@@index([project_id, status], map: "idx_todo_items_project_status")
@@index([created_by, created_at], map: "idx_todo_items_creator_created")
@@map("todo_items")
}
model WecomIdentityBinding {
id String @id @default(uuid()) @db.Uuid
employee_id String @unique @db.Uuid
external_user_id String @unique @db.VarChar(128)
external_open_user_id String? @db.VarChar(128)
created_at DateTime @default(now())
created_by String? @db.Uuid
updated_at DateTime @default(now()) @updatedAt
updated_by String? @db.Uuid
employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade)
@@index([external_user_id], map: "idx_wecom_identity_bindings_external_user")
@@map("wecom_identity_bindings")
}
model Project {
id String @id @default(uuid()) @db.Uuid
project_no String @unique
name String
client_name String
client_alias String?
owner_employee_id String @db.Uuid
manager_employee_id String? @db.Uuid
status ProjectStatus @default(draft)
starts_at DateTime? @db.Date
target_end_at DateTime? @db.Date
actual_end_at DateTime? @db.Date
summary String?
is_confidential Boolean @default(false)
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
owner Employee @relation("ProjectOwner", fields: [owner_employee_id], references: [id], onDelete: Restrict)
manager Employee? @relation("ProjectManager", fields: [manager_employee_id], references: [id], onDelete: SetNull)
members ProjectMember[]
milestones ProjectMilestone[]
tasks ProjectTask[]
risks ProjectRisk[]
reimbursements ReimbursementForm[]
travel_requests TravelRequest[]
todo_items TodoItem[]
weekly_reports ProjectLinkOnWeeklyReport[]
contracts ContractRegistry[]
deliveries ProjectDeliveryRecord[]
document_refs ConfidentialDocumentRef[]
@@index([owner_employee_id, status], map: "idx_projects_owner_status")
@@index([manager_employee_id, status], map: "idx_projects_manager_status")
@@index([status, target_end_at], map: "idx_projects_status_target_end")
@@index([client_name, name], map: "idx_projects_client_name")
@@map("projects")
}
model ProjectMember {
id String @id @default(uuid()) @db.Uuid
project_id String @db.Uuid
employee_id String @db.Uuid
role ProjectRole @default(member)
joined_at DateTime @default(now())
left_at DateTime?
project Project @relation(fields: [project_id], references: [id], onDelete: Cascade)
employee Employee @relation(fields: [employee_id], references: [id], onDelete: Restrict)
@@unique([project_id, employee_id], map: "project_members_project_employee_ux")
@@index([employee_id, left_at], map: "idx_project_members_employee_open")
@@map("project_members")
}
model ProjectMilestone {
id String @id @default(uuid()) @db.Uuid
project_id String @db.Uuid
title String
description String?
status ProjectMilestoneStatus @default(pending)
due_date DateTime? @db.Date
completed_at DateTime?
owner_employee_id String? @db.Uuid
sort_order Int @default(100)
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
project Project @relation(fields: [project_id], references: [id], onDelete: Cascade)
owner Employee? @relation("ProjectMilestoneOwner", fields: [owner_employee_id], references: [id], onDelete: SetNull)
@@index([project_id, sort_order], map: "idx_project_milestones_project_sort")
@@index([owner_employee_id, due_date], map: "idx_project_milestones_owner_due")
@@map("project_milestones")
}
model ProjectTask {
id String @id @default(uuid()) @db.Uuid
project_id String @db.Uuid
title String
description String?
status ProjectTaskStatus @default(todo)
priority ProjectTaskPriority @default(normal)
assignee_employee_id String? @db.Uuid
due_date DateTime? @db.Date
blocked_reason String?
created_by String @db.Uuid
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
project Project @relation(fields: [project_id], references: [id], onDelete: Cascade)
assignee Employee? @relation("ProjectTaskAssignee", fields: [assignee_employee_id], references: [id], onDelete: SetNull)
creator Employee @relation("ProjectTaskCreator", fields: [created_by], references: [id], onDelete: Restrict)
@@index([project_id, status, priority], map: "idx_project_tasks_project_status_priority")
@@index([assignee_employee_id, status], map: "idx_project_tasks_assignee_status")
@@map("project_tasks")
}
model ProjectRisk {
id String @id @default(uuid()) @db.Uuid
project_id String @db.Uuid
title String
detail String
level ProjectRiskLevel @default(medium)
status String @default("open") @db.VarChar(32)
owner_employee_id String? @db.Uuid
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
project Project @relation(fields: [project_id], references: [id], onDelete: Cascade)
owner Employee? @relation("ProjectRiskOwner", fields: [owner_employee_id], references: [id], onDelete: SetNull)
@@index([project_id, status, level], map: "idx_project_risks_project_status_level")
@@index([owner_employee_id, status], map: "idx_project_risks_owner_status")
@@map("project_risks")
}
model ProjectLinkOnWeeklyReport {
id String @id @default(uuid()) @db.Uuid
weekly_report_id String @db.Uuid
project_id String @db.Uuid
progress_text String @default("")
risk_text String @default("")
next_step_text String @default("")
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
weekly_report WeeklyReport @relation(fields: [weekly_report_id], references: [id], onDelete: Cascade)
project Project @relation(fields: [project_id], references: [id], onDelete: Cascade)
@@unique([weekly_report_id, project_id], map: "weekly_report_project_links_report_project_ux")
@@index([project_id, updated_at], map: "idx_weekly_report_project_links_project_updated")
@@map("weekly_report_project_links")
}
model ContractRegistry {
id String @id @default(uuid()) @db.Uuid
contract_no String @unique
project_id String? @db.Uuid
counterparty_name String
summary String
confidentiality_level ConfidentialityLevel @default(internal)
archive_location String
offline_archive_no String?
owner_employee_id String @db.Uuid
status String @default("active") @db.VarChar(32)
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
project Project? @relation(fields: [project_id], references: [id], onDelete: SetNull)
owner Employee @relation("ContractRegistryOwner", fields: [owner_employee_id], references: [id], onDelete: Restrict)
document_refs ConfidentialDocumentRef[]
@@index([project_id, status], map: "idx_contract_registry_project_status")
@@index([owner_employee_id, created_at], map: "idx_contract_registry_owner_created")
@@map("contract_registry")
}
model ProjectDeliveryRecord {
id String @id @default(uuid()) @db.Uuid
project_id String @db.Uuid
title String
record_type ProjectDeliveryRecordType
summary String
occurred_at DateTime
owner_employee_id String @db.Uuid
created_at DateTime @default(now())
project Project @relation(fields: [project_id], references: [id], onDelete: Cascade)
owner Employee @relation("ProjectDeliveryRecordOwner", fields: [owner_employee_id], references: [id], onDelete: Restrict)
@@index([project_id, occurred_at], map: "idx_project_delivery_records_project_occurred")
@@map("project_delivery_records")
}
model ConfidentialDocumentRef {
id String @id @default(uuid()) @db.Uuid
project_id String? @db.Uuid
contract_registry_id String? @db.Uuid
title String
document_no String?
confidentiality_level ConfidentialityLevel @default(internal)
storage_type DocumentStorageType
storage_path String
offline_archive_no String?
owner_employee_id String @db.Uuid
access_rule_json Json?
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
project Project? @relation(fields: [project_id], references: [id], onDelete: SetNull)
contract_registry ContractRegistry? @relation(fields: [contract_registry_id], references: [id], onDelete: SetNull)
owner Employee @relation("ConfidentialDocumentRefOwner", fields: [owner_employee_id], references: [id], onDelete: Restrict)
@@index([project_id, confidentiality_level], map: "idx_confidential_doc_refs_project_level")
@@index([contract_registry_id], map: "idx_confidential_doc_refs_contract")
@@index([owner_employee_id, created_at], map: "idx_confidential_doc_refs_owner_created")
@@map("confidential_document_refs")
}
model MigrationRun {
id String @id @default(uuid()) @db.Uuid
run_type String @db.VarChar(32)
@@ -1744,6 +2054,7 @@ model TravelRequest {
legal_entity_id String @db.Uuid
cost_center_id String @db.Uuid
budget_pool_id String? @db.Uuid
project_id String? @db.Uuid
purpose String
trip_type TravelTripType
start_date DateTime @db.Date
@@ -1762,6 +2073,7 @@ model TravelRequest {
legal_entity LegalEntity @relation(fields: [legal_entity_id], references: [id], onDelete: Restrict)
cost_center CostCenter @relation(fields: [cost_center_id], references: [id], onDelete: Restrict)
budget_pool BudgetPool? @relation(fields: [budget_pool_id], references: [id], onDelete: SetNull)
project Project? @relation(fields: [project_id], references: [id], onDelete: SetNull)
segments TravelRequestSegment[]
travel_orders TravelOrder[]
@@ -1772,6 +2084,7 @@ model TravelRequest {
@@index([applicant_employee_id, start_date], map: "idx_travel_requests_applicant_start")
@@index([submitter_id], map: "idx_travel_requests_submitter")
@@index([project_id], map: "idx_travel_requests_project")
@@index([department_id, status], map: "idx_travel_requests_department_status")
@@index([legal_entity_id, cost_center_id], map: "idx_travel_requests_legal_cost_center")
@@index([budget_pool_id], map: "idx_travel_requests_budget_pool")