819 lines
34 KiB
Plaintext
819 lines
34 KiB
Plaintext
// 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")
|
||
}
|