GuDingZiChan/backend/prisma/schema.prisma

819 lines
34 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model AssetType {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(50)
short_name String? @db.VarChar(20)
status String @default("active") @db.VarChar(20)
can_be_parent Boolean @default(false) // 可作为父资产
can_be_child Boolean @default(false) // 可作为子资产
created_at DateTime @default(now())
updated_at DateTime @updatedAt
equipments Equipment[]
inventoryTasks InventoryTask[]
inventoryTaskItems InventoryTaskItem[]
@@index([status])
@@index([short_name])
@@map("asset_type")
}
model Department {
id Int @id @default(autoincrement())
name String @db.VarChar(100)
status String @default("active") @db.VarChar(20)
parent_id Int? // 父部门ID,null表示根部门
source_group_id Int? @unique
source_parent_group_id Int?
source_system String? @db.VarChar(30)
last_synced_at DateTime?
created_at DateTime @default(now())
updated_at DateTime @updatedAt
// 自关联 - 部门层级
parent Department? @relation("DepartmentHierarchy", fields: [parent_id], references: [id])
children Department[] @relation("DepartmentHierarchy")
equipments Equipment[]
mainPersons Person[] @relation("PersonMainDepartment")
personDepartments PersonDepartment[]
inventoryTasks InventoryTask[]
inventoryTaskParticipants InventoryTaskParticipant[]
inventoryTaskItems InventoryTaskItem[] @relation("InventoryTaskItemSnapshotDepartment")
@@index([status])
@@index([parent_id])
@@index([source_system])
@@index([last_synced_at])
@@map("department")
}
model Equipment {
id Int @id @default(autoincrement())
equipment_code String @unique @db.VarChar(50)
equipment_name String @db.VarChar(100)
equipment_model String? @db.VarChar(100)
equipment_type String @db.VarChar(50)
code_generation_mode String @default("auto") @db.VarChar(20)
status String @default("可用") @db.VarChar(20)
total_quantity Int @default(0)
remaining_quantity Int @default(0)
unit_price Decimal @default(0.00) @db.Decimal(10, 2)
total_value Decimal @default(0.00) @db.Decimal(12, 2)
borrowed_value Decimal @default(0.00) @db.Decimal(12, 2)
available_value Decimal @default(0.00) @db.Decimal(12, 2)
description String? @db.Text
purchase_date DateTime? @db.Date
supplier String? @db.VarChar(100)
storage_location_id Int?
asset_type_id Int?
department_id Int?
// 父子资产关联字段
parent_id Int? // 父资产ID(如果已挂载)
mount_status String @default("none") @db.VarChar(20) // none/mounted/unmounted
total_value_with_children Decimal @default(0.00) @db.Decimal(12, 2) // 含配件总价值
created_at DateTime @default(now())
updated_at DateTime @updatedAt
borrow_records BorrowRecord[]
storageLocation StorageLocation? @relation(fields: [storage_location_id], references: [id])
assetType AssetType? @relation(fields: [asset_type_id], references: [id])
department Department? @relation(fields: [department_id], references: [id])
// 父子资产自关联
parent Equipment? @relation("ParentChild", fields: [parent_id], references: [id])
children Equipment[] @relation("ParentChild")
// 挂载历史关联
mountHistories MountHistory[]
// 报废记录关联
disposalRecords DisposalRecord[]
disposalItems DisposalItem[]
// 维修记录关联
maintenanceRecords MaintenanceRecord[]
inventoryTaskItems InventoryTaskItem[]
transferRootRecords AssetTransferRecord[] @relation("AssetTransferRoot")
transferItems AssetTransferItem[]
@@index([equipment_code])
@@index([equipment_type])
@@index([status])
@@index([code_generation_mode])
@@index([unit_price])
@@index([storage_location_id])
@@index([asset_type_id])
@@index([department_id])
@@index([parent_id])
@@index([mount_status])
@@map("equipment")
}
model BorrowRecord {
id Int @id @default(autoincrement())
equipment_id Int
equipment_code String @db.VarChar(50)
person_id Int
person_name String @db.VarChar(50)
person_nickname String @db.VarChar(50)
person_identifier String? @db.VarChar(50)
borrow_time DateTime @default(now())
expected_return_time DateTime?
is_long_term Boolean @default(false)
return_time DateTime?
status String @default("已借出") @db.VarChar(20)
return_condition String @default("正常") @db.VarChar(20)
notes String? @db.Text
children_snapshot String? @db.Text // JSON格式的配件快照
created_at DateTime @default(now())
updated_at DateTime @updatedAt
equipment Equipment @relation(fields: [equipment_id], references: [id])
person Person @relation(fields: [person_id], references: [id])
@@index([equipment_id])
@@index([person_id])
@@index([status])
@@index([borrow_time])
@@map("borrow_record")
}
model User {
id Int @id @default(autoincrement())
username String @unique @db.VarChar(50)
password String @db.VarChar(255)
name String @db.VarChar(50)
email String? @db.VarChar(100)
phone String? @db.VarChar(20)
role String @default("user") @db.VarChar(20)
status String @default("active") @db.VarChar(20)
person_id Int? @unique
last_login_at DateTime? @db.DateTime
created_at DateTime @default(now())
updated_at DateTime @updatedAt
operation_logs OperationLog[]
site_configs SiteConfig[] @relation("SiteConfigUpdatedBy")
mount_histories MountHistory[]
// 报废记录关联
disposal_applied DisposalRecord[] @relation("DisposalApplier")
disposal_approved DisposalRecord[] @relation("DisposalApprover")
disposal_completed DisposalRecord[] @relation("DisposalCompleter")
disposal_actions DisposalAction[] @relation("DisposalActionOperator")
// 维修记录关联
maintenance_records MaintenanceRecord[]
notifications UserNotification[]
processed_sync_changes SyncChange[] @relation("SyncChangeProcessedBy")
inventory_tasks_created InventoryTask[] @relation("InventoryTaskCreatedBy")
inventory_actions InventoryTaskAction[] @relation("InventoryTaskActionOperator")
print_terminal_pair_codes PrintTerminalPairCode[] @relation("PrintTerminalPairCodeCreator")
requested_print_jobs PrintJob[] @relation("PrintJobRequester")
asset_transfers_operated AssetTransferRecord[] @relation("AssetTransferOperator")
dingtalk_deliveries DingTalkDelivery[] @relation("DingTalkDeliveryRecipient")
person Person? @relation(fields: [person_id], references: [id], onDelete: SetNull)
@@index([role])
@@index([status])
@@map("user")
}
model PrintTerminal {
id Int @id @default(autoincrement())
name String @db.VarChar(100)
platform String @db.VarChar(30)
machine_name String @db.VarChar(100)
status String @default("offline") @db.VarChar(20)
protocol_version Int @default(1)
is_default Boolean @default(false)
last_seen_at DateTime?
selected_printer_name String? @db.VarChar(150)
printer_snapshot_json String? @db.Text
label_profile_json String? @db.Text
terminal_token_hash String @unique @db.VarChar(128)
paired_at DateTime @default(now())
current_error_message String? @db.VarChar(255)
created_at DateTime @default(now())
updated_at DateTime @updatedAt
used_pair_codes PrintTerminalPairCode[] @relation("PrintTerminalPairCodeUsedBy")
target_jobs PrintJob[] @relation("PrintJobTargetTerminal")
claimed_jobs PrintJob[] @relation("PrintJobClaimedByTerminal")
@@index([status])
@@index([is_default])
@@index([last_seen_at])
@@map("print_terminal")
}
model PrintTerminalPairCode {
id Int @id @default(autoincrement())
code String @unique @db.VarChar(32)
expires_at DateTime
created_by Int
used_at DateTime?
used_by_terminal_id Int?
created_at DateTime @default(now())
updated_at DateTime @updatedAt
creator User @relation("PrintTerminalPairCodeCreator", fields: [created_by], references: [id])
usedByTerminal PrintTerminal? @relation("PrintTerminalPairCodeUsedBy", fields: [used_by_terminal_id], references: [id])
@@index([expires_at])
@@index([created_by])
@@index([used_by_terminal_id])
@@map("print_terminal_pair_code")
}
model PrintJob {
id Int @id @default(autoincrement())
job_type String @default("asset_label") @db.VarChar(30)
status String @default("queued") @db.VarChar(20)
target_terminal_id Int
claimed_by_terminal_id Int?
requested_by Int
payload_json String @db.Text
error_message String? @db.Text
claimed_at DateTime?
claim_token String? @db.VarChar(64)
lease_expires_at DateTime?
result_confirmed_by Int?
result_confirmed_at DateTime?
started_at DateTime?
completed_at DateTime?
attempt_count Int @default(0)
created_at DateTime @default(now())
updated_at DateTime @updatedAt
targetTerminal PrintTerminal @relation("PrintJobTargetTerminal", fields: [target_terminal_id], references: [id])
claimedByTerminal PrintTerminal? @relation("PrintJobClaimedByTerminal", fields: [claimed_by_terminal_id], references: [id])
requester User @relation("PrintJobRequester", fields: [requested_by], references: [id])
@@index([status, created_at])
@@index([status, lease_expires_at])
@@index([target_terminal_id, status, created_at])
@@index([requested_by])
@@index([claimed_by_terminal_id])
@@map("print_job")
}
model SiteConfig {
id Int @id @default(autoincrement())
site_name String @db.VarChar(100)
logo_url String? @db.VarChar(255)
favicon_url String? @db.VarChar(255)
theme_color String? @db.VarChar(20)
updated_by Int?
created_at DateTime @default(now())
updated_at DateTime @default(now())
updatedBy User? @relation("SiteConfigUpdatedBy", fields: [updated_by], references: [id])
@@map("site_config")
}
model Person {
id Int @id @default(autoincrement())
nickname String @db.VarChar(50)
real_name String @db.VarChar(50)
job_number String? @unique @db.VarChar(50)
id_number String? @unique @db.VarChar(50)
department String? @db.VarChar(100)
main_department_id Int?
position String? @db.VarChar(100)
phone String? @db.VarChar(20)
email String? @db.VarChar(100)
status String @default("active") @db.VarChar(20)
remarks String? @db.Text
source_userid String? @unique @db.VarChar(100)
source_system String? @db.VarChar(30)
source_main_department_id Int?
source_dept_ids String? @db.Text
source_department_name String? @db.VarChar(100)
source_main_department_name String? @db.VarChar(100)
department_sync_bucket String? @db.VarChar(20)
manager_source_userid String? @db.VarChar(100)
source_employee_status String? @db.VarChar(30)
last_synced_at DateTime?
created_at DateTime @default(now())
updated_at DateTime @updatedAt
borrow_records BorrowRecord[]
mainDepartment Department? @relation("PersonMainDepartment", fields: [main_department_id], references: [id])
personDepartments PersonDepartment[]
inventoryTaskParticipants InventoryTaskParticipant[]
inventoryTaskItems InventoryTaskItem[] @relation("InventoryTaskItemSnapshotPerson")
user User?
@@index([nickname])
@@index([real_name])
@@index([status])
@@index([main_department_id])
@@index([source_system])
@@index([department_sync_bucket])
@@index([last_synced_at])
@@map("person")
}
model PersonDepartment {
person_id Int
department_id Int
created_at DateTime @default(now())
updated_at DateTime @updatedAt
person Person @relation(fields: [person_id], references: [id], onDelete: Cascade)
department Department @relation(fields: [department_id], references: [id], onDelete: Cascade)
@@id([person_id, department_id])
@@index([department_id])
@@map("person_department")
}
model StorageLocation {
id Int @id @default(autoincrement())
name String @db.VarChar(100)
code String? @db.VarChar(50)
status String @default("active") @db.VarChar(20)
description String? @db.Text
created_at DateTime @default(now())
updated_at DateTime @updatedAt
equipments Equipment[]
@@index([status])
@@map("storage_location")
}
model OperationLog {
id Int @id @default(autoincrement())
user_id Int?
username String? @db.VarChar(50)
operation_type String @db.VarChar(50)
equipment_id Int?
equipment_code String? @db.VarChar(50)
operation_details String? @db.Text
ip_address String? @db.VarChar(50)
created_at DateTime @default(now())
user User? @relation(fields: [user_id], references: [id])
@@index([user_id])
@@index([operation_type])
@@index([created_at])
@@map("operation_log")
}
model SyncJob {
id Int @id @default(autoincrement())
sync_type String @db.VarChar(30)
trigger_mode String @db.VarChar(30)
status String @default("success") @db.VarChar(20)
operator String? @db.VarChar(50)
summary String? @db.Text
result_payload String? @db.Text
created_at DateTime @default(now())
changes SyncChange[]
notifications Notification[]
@@index([sync_type, created_at])
@@index([status, created_at])
@@map("sync_job")
}
model SyncChange {
id Int @id @default(autoincrement())
sync_job_id Int
entity_type String @db.VarChar(20)
entity_key String? @db.VarChar(100)
entity_name String @db.VarChar(100)
change_type String @db.VarChar(50)
title String @db.VarChar(150)
detail String? @db.Text
before_snapshot String? @db.Text
after_snapshot String? @db.Text
processing_status String @default("pending") @db.VarChar(20)
processing_notes String? @db.Text
processed_by Int?
processed_at DateTime?
created_at DateTime @default(now())
syncJob SyncJob @relation(fields: [sync_job_id], references: [id], onDelete: Cascade)
processedBy User? @relation("SyncChangeProcessedBy", fields: [processed_by], references: [id], onDelete: SetNull)
@@index([sync_job_id])
@@index([entity_type, change_type])
@@index([processing_status, created_at])
@@index([processed_by])
@@map("sync_change")
}
model Notification {
id Int @id @default(autoincrement())
title String @db.VarChar(150)
content String? @db.Text
type String @default("info") @db.VarChar(30)
level String @default("info") @db.VarChar(20)
action_url String? @db.VarChar(255)
related_sync_job_id Int?
metadata String? @db.Text
created_at DateTime @default(now())
syncJob SyncJob? @relation(fields: [related_sync_job_id], references: [id], onDelete: SetNull)
recipients UserNotification[]
@@index([related_sync_job_id])
@@index([created_at])
@@map("notification")
}
model UserNotification {
id Int @id @default(autoincrement())
user_id Int
notification_id Int
is_read Boolean @default(false)
read_at DateTime?
created_at DateTime @default(now())
user User @relation(fields: [user_id], references: [id], onDelete: Cascade)
notification Notification @relation(fields: [notification_id], references: [id], onDelete: Cascade)
@@unique([user_id, notification_id])
@@index([user_id, is_read, created_at])
@@map("user_notification")
}
model InventoryTask {
id Int @id @default(autoincrement())
title String @db.VarChar(150)
description String? @db.Text
status String @default("active") @db.VarChar(20)
identity_mode String @default("dingtalk") @db.VarChar(20)
public_token String @unique @db.VarChar(120)
scope_department_id Int?
scope_department_name String? @db.VarChar(100)
scope_asset_type_id Int?
scope_asset_type_name String? @db.VarChar(100)
scope_snapshot_json String? @db.Text
participants_count Int @default(0)
items_count Int @default(0)
completed_count Int @default(0)
exception_count Int @default(0)
unassigned_count Int @default(0)
created_by Int
deadline_at DateTime?
closed_at DateTime?
created_at DateTime @default(now())
updated_at DateTime @updatedAt
scopeDepartment Department? @relation(fields: [scope_department_id], references: [id])
scopeAssetType AssetType? @relation(fields: [scope_asset_type_id], references: [id])
creator User @relation("InventoryTaskCreatedBy", fields: [created_by], references: [id])
participants InventoryTaskParticipant[]
items InventoryTaskItem[]
actions InventoryTaskAction[]
@@index([status, created_at])
@@index([scope_department_id, status])
@@index([scope_asset_type_id, status])
@@index([created_by])
@@index([status, deadline_at])
@@map("inventory_task")
}
model InventoryTaskParticipant {
id Int @id @default(autoincrement())
task_id Int
person_id Int?
person_name String @db.VarChar(50)
person_nickname String @db.VarChar(50)
person_source_userid String? @db.VarChar(100)
department_id Int?
department_name String? @db.VarChar(100)
status String @default("pending") @db.VarChar(20)
confirmed_at DateTime?
last_action_at DateTime?
created_at DateTime @default(now())
updated_at DateTime @updatedAt
task InventoryTask @relation(fields: [task_id], references: [id], onDelete: Cascade)
person Person? @relation(fields: [person_id], references: [id], onDelete: SetNull)
department Department? @relation(fields: [department_id], references: [id], onDelete: SetNull)
assigned_items InventoryTaskItem[] @relation("InventoryTaskItemAssignee")
checked_items InventoryTaskItem[] @relation("InventoryTaskItemChecker")
actions InventoryTaskAction[]
@@unique([task_id, person_id])
@@index([task_id, status])
@@index([task_id, person_id])
@@index([task_id, person_nickname])
@@index([department_id])
@@map("inventory_task_participant")
}
model InventoryTaskItem {
id Int @id @default(autoincrement())
task_id Int
participant_id Int?
equipment_id Int
// 任务创建时冻结的直接父资产;为空表示该项在本任务中按根资产展示。
snapshot_parent_equipment_id Int?
equipment_code String @db.VarChar(50)
equipment_name String @db.VarChar(100)
equipment_model String? @db.VarChar(100)
equipment_type String @db.VarChar(50)
asset_type_id Int?
asset_type_name String? @db.VarChar(100)
snapshot_department_id Int?
snapshot_department_name String? @db.VarChar(100)
snapshot_person_id Int?
snapshot_person_name String? @db.VarChar(50)
snapshot_person_nickname String? @db.VarChar(50)
snapshot_status String? @db.VarChar(20)
source_borrow_record_id Int?
is_unassigned Boolean @default(false)
check_status String @default("pending") @db.VarChar(20)
checked_by_participant_id Int?
checked_at DateTime?
exception_type String? @db.VarChar(30)
exception_note String? @db.Text
created_at DateTime @default(now())
updated_at DateTime @updatedAt
task InventoryTask @relation(fields: [task_id], references: [id], onDelete: Cascade)
participant InventoryTaskParticipant? @relation("InventoryTaskItemAssignee", fields: [participant_id], references: [id], onDelete: SetNull)
checked_by_participant InventoryTaskParticipant? @relation("InventoryTaskItemChecker", fields: [checked_by_participant_id], references: [id], onDelete: SetNull)
equipment Equipment @relation(fields: [equipment_id], references: [id], onDelete: Cascade)
assetType AssetType? @relation(fields: [asset_type_id], references: [id], onDelete: SetNull)
snapshotDepartment Department? @relation("InventoryTaskItemSnapshotDepartment", fields: [snapshot_department_id], references: [id], onDelete: SetNull)
snapshotPerson Person? @relation("InventoryTaskItemSnapshotPerson", fields: [snapshot_person_id], references: [id], onDelete: SetNull)
actions InventoryTaskAction[]
@@unique([task_id, equipment_id])
@@index([task_id, participant_id, check_status])
@@index([task_id, equipment_id])
@@index([task_id, snapshot_parent_equipment_id])
@@index([task_id, is_unassigned])
@@index([task_id, check_status])
@@index([checked_by_participant_id])
@@index([snapshot_department_id])
@@index([snapshot_person_id])
@@map("inventory_task_item")
}
model InventoryTaskAction {
id Int @id @default(autoincrement())
task_id Int
participant_id Int?
item_id Int?
action_type String @db.VarChar(40)
action_payload String? @db.Text
ip_address String? @db.VarChar(50)
user_agent String? @db.VarChar(255)
operator_user_id Int?
created_at DateTime @default(now())
task InventoryTask @relation(fields: [task_id], references: [id], onDelete: Cascade)
participant InventoryTaskParticipant? @relation(fields: [participant_id], references: [id], onDelete: SetNull)
item InventoryTaskItem? @relation(fields: [item_id], references: [id], onDelete: SetNull)
operator User? @relation("InventoryTaskActionOperator", fields: [operator_user_id], references: [id], onDelete: SetNull)
@@index([task_id, created_at])
@@index([participant_id])
@@index([item_id])
@@index([operator_user_id])
@@map("inventory_task_action")
}
model MountHistory {
id Int @id @default(autoincrement())
child_id Int // 子资产ID
parent_id Int? // 父资产ID
operation_type String @db.VarChar(20) // mount/unmount/replace
operated_at DateTime @default(now())
operated_by Int // 操作人ID
notes String? @db.Text
old_parent_id Int? // 更换时的旧父资产ID
new_parent_id Int? // 更换时的新父资产ID
child Equipment @relation(fields: [child_id], references: [id])
operator User @relation(fields: [operated_by], references: [id])
@@index([child_id])
@@index([parent_id])
@@index([operation_type])
@@index([operated_at])
@@map("mount_history")
}
// 报废记录
model DisposalRecord {
id Int @id @default(autoincrement())
equipment_id Int
equipment_code String @db.VarChar(50)
disposal_reason String @db.Text // 报废原因
disposal_method String @db.VarChar(50) // 处置方式:报废/转让/捐赠
estimated_value Decimal @db.Decimal(12,2) // 残值估价
actual_value Decimal? @db.Decimal(12,2) // 实际处置价值
status String @default("pending") @db.VarChar(20) // pending/approved/rejected/completed
applied_by Int // 申请人
applied_at DateTime @default(now())
approved_by Int? // 审批人
approved_at DateTime?
completed_at DateTime? // 完成时间
completed_by Int?
pre_status String @default("可用") @db.VarChar(20)
reject_reason String? @db.Text
completion_notes String? @db.Text
reminded_at DateTime?
notes String? @db.Text
created_at DateTime @default(now())
updated_at DateTime @updatedAt
equipment Equipment @relation(fields: [equipment_id], references: [id])
applier User @relation("DisposalApplier", fields: [applied_by], references: [id])
approver User? @relation("DisposalApprover", fields: [approved_by], references: [id])
completer User? @relation("DisposalCompleter", fields: [completed_by], references: [id])
items DisposalItem[]
actions DisposalAction[]
@@index([equipment_id])
@@index([status])
@@index([applied_by, created_at])
@@index([approved_by, approved_at])
@@index([completed_by, completed_at])
@@map("disposal_record")
}
model DisposalItem {
id Int @id @default(autoincrement())
disposal_id Int
equipment_id Int
equipment_code String @db.VarChar(50)
equipment_name String @db.VarChar(100)
parent_equipment_id Int?
parent_equipment_code String? @db.VarChar(50)
pre_status String @db.VarChar(20)
snapshot_json String? @db.Text
created_at DateTime @default(now())
disposal DisposalRecord @relation(fields: [disposal_id], references: [id], onDelete: Cascade)
equipment Equipment @relation(fields: [equipment_id], references: [id])
@@unique([disposal_id, equipment_id])
@@index([equipment_id])
@@index([parent_equipment_id])
@@map("disposal_item")
}
model DisposalAction {
id Int @id @default(autoincrement())
disposal_id Int
action_type String @db.VarChar(30)
operator_id Int?
from_status String? @db.VarChar(20)
to_status String? @db.VarChar(20)
detail String? @db.Text
created_at DateTime @default(now())
disposal DisposalRecord @relation(fields: [disposal_id], references: [id], onDelete: Cascade)
operator User? @relation("DisposalActionOperator", fields: [operator_id], references: [id], onDelete: SetNull)
@@index([disposal_id, created_at])
@@index([operator_id])
@@map("disposal_action")
}
model AssetTransferRecord {
id Int @id @default(autoincrement())
root_equipment_id Int
action_type String @db.VarChar(20)
from_department_id Int?
from_department_name String? @db.VarChar(100)
to_department_id Int?
to_department_name String? @db.VarChar(100)
reason String? @db.Text
operated_by Int
operated_at DateTime @default(now())
created_at DateTime @default(now())
rootEquipment Equipment @relation("AssetTransferRoot", fields: [root_equipment_id], references: [id])
operator User @relation("AssetTransferOperator", fields: [operated_by], references: [id])
items AssetTransferItem[]
@@index([root_equipment_id, operated_at])
@@index([operated_by])
@@index([action_type, operated_at])
@@map("asset_transfer_record")
}
model AssetTransferItem {
id Int @id @default(autoincrement())
transfer_id Int
equipment_id Int
equipment_code String @db.VarChar(50)
equipment_name String @db.VarChar(100)
parent_equipment_id Int?
from_department_id Int?
to_department_id Int?
storage_location_id Int?
snapshot_status String @db.VarChar(20)
created_at DateTime @default(now())
transfer AssetTransferRecord @relation(fields: [transfer_id], references: [id], onDelete: Cascade)
equipment Equipment @relation(fields: [equipment_id], references: [id])
@@unique([transfer_id, equipment_id])
@@index([equipment_id, created_at])
@@index([parent_equipment_id])
@@map("asset_transfer_item")
}
model DingTalkDelivery {
id Int @id @default(autoincrement())
idempotency_key String @unique @db.VarChar(191)
event_type String @db.VarChar(50)
business_type String @db.VarChar(30)
business_id Int
recipient_user_id Int
recipient_dingtalk_userid String? @db.VarChar(100)
status String @default("pending") @db.VarChar(20)
attempt_count Int @default(0)
max_attempts Int @default(5)
next_attempt_at DateTime @default(now())
lease_owner String? @db.VarChar(100)
lease_expires_at DateTime?
provider_type String @default("notification_center") @db.VarChar(20)
dingtalk_task_id String? @db.VarChar(100)
retry_of_delivery_id Int?
manual_created_by Int?
manual_created_at DateTime?
last_manual_action_by Int?
last_manual_action_type String? @db.VarChar(30)
last_manual_action_at DateTime?
payload_json String @db.Text
last_error_code String? @db.VarChar(100)
last_error_message String? @db.Text
failure_notified_at DateTime?
sent_at DateTime?
read_at DateTime?
created_at DateTime @default(now())
updated_at DateTime @updatedAt
recipient User @relation("DingTalkDeliveryRecipient", fields: [recipient_user_id], references: [id])
@@index([status, next_attempt_at])
@@index([lease_expires_at])
@@index([business_type, business_id])
@@index([recipient_user_id, created_at])
@@index([dingtalk_task_id])
@@index([retry_of_delivery_id])
@@map("dingtalk_delivery")
}
model WebSession {
sid String @id @db.VarChar(191)
data String @db.LongText
expires_at DateTime
created_at DateTime @default(now())
updated_at DateTime @updatedAt
@@index([expires_at])
@@map("web_session")
}
// 维修记录
model MaintenanceRecord {
id Int @id @default(autoincrement())
equipment_id Int
equipment_code String @db.VarChar(50)
issue_description String @db.Text // 故障描述
repair_vendor String? @db.VarChar(100) // 维修商
estimated_cost Decimal @db.Decimal(10,2) // 预估费用
actual_cost Decimal? @db.Decimal(10,2) // 实际费用
start_date DateTime @default(now()) // 送修日期
expected_end_date DateTime? // 预计完成日期
actual_end_date DateTime? // 实际完成日期
status String @default("in_progress") @db.VarChar(20) // in_progress/completed/cancelled
repair_result String? @db.Text // 维修结果
original_tree_snapshot String? @db.LongText // 送修前整棵资产树状态和关系快照
created_by Int
created_at DateTime @default(now())
updated_at DateTime @updatedAt
equipment Equipment @relation(fields: [equipment_id], references: [id])
creator User @relation(fields: [created_by], references: [id])
@@index([equipment_id])
@@index([status])
@@map("maintenance_record")
}