From b9b1a775a9633a34130944d7fdbe9b9ba860aa8e Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期二, 11 八月 2026 17:35:00 +0800
Subject: [PATCH] fix: 清理配置文件

---
 /dev/null |   13 -------------
 1 files changed, 0 insertions(+), 13 deletions(-)

diff --git a/doc/1767778273_add_product_order_id_to_product_work_order.sql b/doc/1767778273_add_product_order_id_to_product_work_order.sql
deleted file mode 100644
index 8804120..0000000
--- a/doc/1767778273_add_product_order_id_to_product_work_order.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-alter table product_work_order
-    add product_order_id bigint not null default 0 comment '鐢熶骇璁㈠崟id';
diff --git a/doc/20260113-product_model.sql b/doc/20260113-product_model.sql
deleted file mode 100644
index dcbb610..0000000
--- a/doc/20260113-product_model.sql
+++ /dev/null
@@ -1,14 +0,0 @@
-alter table product_model
-    add product_code varchar(255)  null comment '浜у搧缂栫爜';
-
-alter table process_route
-    add process_route_code varchar(255)  null comment '宸ヨ壓璺嚎缂栫爜';
-
-alter table procurement_record_storage
-    add product_model_id bigint null comment '浜у搧瑙勬牸id';
-alter table procurement_record_out
-    add product_model_id bigint null comment '浜у搧瑙勬牸id';
-
-
-alter table quality_inspect
-    add product_model_id bigint null comment '浜у搧瑙勬牸id';
diff --git a/doc/20260114_add_dimission_reason_and_remark_to_staff_join_leave_record.sql b/doc/20260114_add_dimission_reason_and_remark_to_staff_join_leave_record.sql
deleted file mode 100644
index 4c4acc2..0000000
--- a/doc/20260114_add_dimission_reason_and_remark_to_staff_join_leave_record.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-alter table staff_join_leave_record
-    add dimission_reason varchar(255) null comment '绂昏亴鍘熷洜',
-    add dimission_remark text null comment '绂昏亴澶囨敞';
diff --git a/doc/20260115_add_sys_post_id_to_staff_join_leave_record.sql b/doc/20260115_add_sys_post_id_to_staff_join_leave_record.sql
deleted file mode 100644
index 7fea0ad..0000000
--- a/doc/20260115_add_sys_post_id_to_staff_join_leave_record.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-alter table staff_on_job
-    add sys_post_id bigint not null default 0 comment '宀椾綅id';
-alter table staff_on_job
-drop column post_job;
-alter table staff_on_job
-    add sys_dept_id bigint default 0 not null;
\ No newline at end of file
diff --git a/doc/20260116_create_table_staff_contract.sql b/doc/20260116_create_table_staff_contract.sql
deleted file mode 100644
index f8fc20a..0000000
--- a/doc/20260116_create_table_staff_contract.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-# 鍛樺伐鍚堝悓琛�
-drop table if exists staff_contract;
-create table staff_contract
-(
-    id                  bigint auto_increment primary key,
-    staff_on_job_id     bigint not null default 0 comment '鍛樺伐鍦ㄨ亴id',
-    contract_start_time datetime null comment '鍚堝悓寮�濮嬫椂闂�',
-    contract_end_time   datetime null comment '鍚堝悓缁撴潫鏃堕棿',
-    contract_term       int    not null default 0 comment '鍚堝悓鏈熼檺',
-    tenant_id           bigint not null comment '绉熸埛id',
-    create_time         datetime null comment '褰曞叆鏃堕棿',
-    update_time         datetime null comment '鏇存柊鏃堕棿'
-);
diff --git a/doc/20260116_create_table_staff_leave.sql b/doc/20260116_create_table_staff_leave.sql
deleted file mode 100644
index 7e4b1cf..0000000
--- a/doc/20260116_create_table_staff_leave.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-#鍛樺伐绂昏亴琛�
-drop table if exists staff_join_leave_record;
-drop table if exists staff_leave;
-create table staff_leave
-(
-    id              bigint auto_increment primary key,
-    staff_on_job_id bigint not null default 0 comment '鍛樺伐鍦ㄨ亴id',
-    reason          varchar(255) null comment '绂昏亴鍘熷洜',
-    remark          text null comment '绂昏亴澶囨敞',
-    tenant_id       bigint not null comment '绉熸埛id',
-    create_time     datetime null comment '褰曞叆鏃堕棿',
-    update_time     datetime null comment '鏇存柊鏃堕棿'
-);
diff --git a/doc/20260119-procurement_record_storage.sql b/doc/20260119-procurement_record_storage.sql
deleted file mode 100644
index 923bbd3..0000000
--- a/doc/20260119-procurement_record_storage.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-alter table procurement_record_storage
-    add quality_inspect_id bigint null comment '璐ㄦid';
\ No newline at end of file
diff --git a/doc/20260128_add_unique_to_staff_on_job.sql b/doc/20260128_add_unique_to_staff_on_job.sql
deleted file mode 100644
index 16b2221..0000000
--- a/doc/20260128_add_unique_to_staff_on_job.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE staff_on_job ADD unique (staff_no);
\ No newline at end of file
diff --git a/doc/20260209_create_personal_attendance_records.sql b/doc/20260209_create_personal_attendance_records.sql
deleted file mode 100644
index 0a25e18..0000000
--- a/doc/20260209_create_personal_attendance_records.sql
+++ /dev/null
@@ -1,18 +0,0 @@
-#鍛樺伐鑰冨嫟琛�
-drop table if exists personal_attendance_records;
-create table personal_attendance_records
-(
-    id              bigint auto_increment primary key,
-    staff_on_job_id bigint not null default 0 comment '鍛樺伐鍦ㄨ亴id',
-    date            date not null comment '鏃ユ湡',
-    work_start_at   datetime null comment '宸ヤ綔寮�濮嬫椂闂�',
-    work_end_at     datetime null comment '宸ヤ綔缁撴潫鏃堕棿',
-    work_hours      decimal(5,2) null comment '宸ヤ綔鏃堕暱',
-    status          tinyint not null default 0 comment '鐘舵�� 0姝e父 1杩熷埌 2鏃╅��',
-    remark          text null comment '澶囨敞',
-    tenant_id       bigint not null comment '绉熸埛id',
-    create_time     datetime null comment '褰曞叆鏃堕棿',
-    update_time     datetime null comment '鏇存柊鏃堕棿',
-    index idx_staff_on_job_id (staff_on_job_id),
-    unique idx_staff_on_job_id_date (staff_on_job_id, date)
-);
diff --git a/doc/20260306_create_purchase_return_orders.sql b/doc/20260306_create_purchase_return_orders.sql
deleted file mode 100644
index 328cb00..0000000
--- a/doc/20260306_create_purchase_return_orders.sql
+++ /dev/null
@@ -1,38 +0,0 @@
-#浜у搧閫�璐у崟琛�
-drop table if exists purchase_return_orders;
-create table purchase_return_orders
-(
-    id                 bigint auto_increment primary key,
-    no                 varchar(255) null comment '閫�璐у崟缂栧彿',
-    return_type        tinyint not null default 0 comment '閫�璐ф柟寮� 0閫�璐ч��娆� 1鎷掓敹',
-    supplier_id        bigint  not null default 0 comment '渚涘簲鍟唅d',
-    project_id         bigint  not null default 0 comment '椤圭洰id',
-    project_phase      tinyint not null default 0 comment '椤圭洰闃舵',
-    prepared_at        datetime null comment '鍒跺崟鏃ユ湡',
-    prepared_user_id   bigint  not null default 0 comment '鍒跺崟浜篿d',
-    return_user_id     bigint  not null default 0 comment '閫�鏂欎汉id',
-    purchase_ledger_id bigint  not null default 0 comment '閲囪喘璁㈠崟id',
-    total_discount_amount decimal(10, 2) null comment '鏁村崟鎶樻墸棰�',
-    total_discount_rate   decimal(10, 2) null comment '鏁村崟鎶樻墸鐜�',
-    total_amount decimal(10,2) null comment '鎴愪氦閲戦',
-    remark             text null comment '澶囨敞',
-    create_time        datetime null comment '褰曞叆鏃堕棿',
-    update_time        datetime null comment '鏇存柊鏃堕棿',
-    index              idx_supplier_id (supplier_id),
-    index              idx_purchase_ledger_id (purchase_ledger_id),
-    index              idx_project_id (project_id)
-);
-
-#浜у搧閫�璐у崟涓庨噰璐骇鍝佸叧鑱旇〃
-drop table if exists purchase_return_order_products;
-create table purchase_return_order_products
-(
-    id                       bigint auto_increment primary key,
-    purchase_return_order_id bigint not null default 0 comment '閫�璐у崟id',
-    sales_ledger_product_id  bigint not null default 0 comment '閲囪喘浜у搧id',
-    return_quantity          decimal(16, 4)  not null default 0 comment '閫�璐ф暟閲�',
-    create_time              datetime null comment '褰曞叆鏃堕棿',
-    update_time              datetime null comment '鏇存柊鏃堕棿',
-    index                    idx_purchase_return_order_id (purchase_return_order_id),
-    index                    idx_sales_ledger_product_id (sales_ledger_product_id)
-);
\ No newline at end of file
diff --git a/doc/20260428_create_table_ai_chat_session.sql b/doc/20260428_create_table_ai_chat_session.sql
deleted file mode 100644
index f490376..0000000
--- a/doc/20260428_create_table_ai_chat_session.sql
+++ /dev/null
@@ -1,16 +0,0 @@
-CREATE TABLE IF NOT EXISTS `ai_chat_session` (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `memory_id` varchar(64) NOT NULL COMMENT '浼氳瘽ID',
-  `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛ID',
-  `tenant_id` bigint DEFAULT NULL COMMENT '绉熸埛ID',
-  `title` varchar(128) DEFAULT NULL COMMENT '浼氳瘽鏍囬',
-  `last_message` varchar(512) DEFAULT NULL COMMENT '鏈�鍚庝竴鏉℃秷鎭�',
-  `message_count` int NOT NULL DEFAULT 0 COMMENT '娑堟伅鏁伴噺',
-  `last_chat_time` datetime DEFAULT NULL COMMENT '鏈�鍚庤亰澶╂椂闂�',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_chat_session_memory_id` (`memory_id`),
-  KEY `idx_ai_chat_session_user_tenant` (`user_id`, `tenant_id`),
-  KEY `idx_ai_chat_session_last_chat_time` (`last_chat_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI鍘嗗彶浼氳瘽鍏冩暟鎹〃';
diff --git a/doc/20260506_add_ai_enabled_to_sys_user.sql b/doc/20260506_add_ai_enabled_to_sys_user.sql
deleted file mode 100644
index 7e7ee9d..0000000
--- a/doc/20260506_add_ai_enabled_to_sys_user.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-alter table sys_user
-    add ai_enabled tinyint(1) not null default 0 comment '鏄惁寮�閫欰I鍔熻兘锛�0鍚� 1鏄級';
diff --git a/doc/20260512_add_parent_id_to_account_subject.sql b/doc/20260512_add_parent_id_to_account_subject.sql
deleted file mode 100644
index cf33a33..0000000
--- a/doc/20260512_add_parent_id_to_account_subject.sql
+++ /dev/null
@@ -1,5 +0,0 @@
--- account_subject 澧炲姞鐖剁骇绉戠洰瀛楁锛堟爲褰㈢粨鏋勶級
-ALTER TABLE `account_subject`
-ADD COLUMN `parent_id` bigint NULL COMMENT '鐖剁鐩甀D锛堜负绌鸿〃绀烘牴鑺傜偣锛�' AFTER `id`;
-
-CREATE INDEX `idx_account_subject_parent_id` ON `account_subject` (`parent_id`);
diff --git a/doc/20260512_create_financial_management_tables.sql b/doc/20260512_create_financial_management_tables.sql
deleted file mode 100644
index db3caad..0000000
--- a/doc/20260512_create_financial_management_tables.sql
+++ /dev/null
@@ -1,104 +0,0 @@
--- 璐㈠姟绠$悊妯″潡寤鸿〃鑴氭湰锛堝浐瀹氳祫浜�/鏃犲舰璧勪骇/鍑瘉/绉戠洰璐︼級
--- 璇存槑锛�
--- 1) 鎬昏处绉戠洰缁х画澶嶇敤宸叉湁琛� account_subject锛屼笉閲嶅鍒涘缓 fin_account_subject銆�
--- 2) 閲戦瀛楁缁熶竴 decimal(18,2)銆�
-
-CREATE TABLE IF NOT EXISTS `fin_fixed_asset` (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `asset_code` varchar(64) NOT NULL COMMENT '璧勪骇缂栧彿',
-  `asset_name` varchar(128) NOT NULL COMMENT '璧勪骇鍚嶇О',
-  `category` varchar(64) NOT NULL COMMENT '璧勪骇绫诲埆',
-  `specification` varchar(255) DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `purchase_date` date NOT NULL COMMENT '璐疆鏃ユ湡',
-  `original_value` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '璧勪骇鍘熷��',
-  `useful_life` int NOT NULL DEFAULT '1' COMMENT '浣跨敤骞撮檺(骞�)',
-  `residual_rate` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '娈嬪�肩巼(%)',
-  `accumulated_depreciation` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '绱鎶樻棫',
-  `net_value` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '鍑�鍊�',
-  `location` varchar(255) DEFAULT NULL COMMENT '瀛樻斁鍦扮偣',
-  `department` varchar(128) DEFAULT NULL COMMENT '浣跨敤閮ㄩ棬',
-  `keeper` varchar(64) DEFAULT NULL COMMENT '淇濈浜�',
-  `status` varchar(32) NOT NULL DEFAULT 'in_use' COMMENT '鐘舵��: in_use/idle/repair/scrapped',
-  `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` varchar(64) DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_fin_fixed_asset_code` (`asset_code`),
-  KEY `idx_fin_fixed_asset_status` (`status`),
-  KEY `idx_fin_fixed_asset_category` (`category`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='鍥哄畾璧勪骇';
-
-CREATE TABLE IF NOT EXISTS `fin_intangible_asset` (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `asset_code` varchar(64) NOT NULL COMMENT '璧勪骇缂栧彿',
-  `asset_name` varchar(128) NOT NULL COMMENT '璧勪骇鍚嶇О',
-  `category` varchar(64) NOT NULL COMMENT '璧勪骇绫诲埆',
-  `certificate_no` varchar(128) DEFAULT NULL COMMENT '璇佷功缂栧彿',
-  `acquisition_date` date NOT NULL COMMENT '鍙栧緱鏃ユ湡',
-  `original_value` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '璧勪骇鍘熷��',
-  `amortization_period` int NOT NULL DEFAULT '1' COMMENT '鎽婇攢骞撮檺(骞�)',
-  `residual_rate` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '娈嬪�肩巼(%)',
-  `accumulated_amortization` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '绱鎽婇攢',
-  `net_value` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '鍑�鍊�',
-  `validity_date` date DEFAULT NULL COMMENT '鏈夋晥鏈熻嚦',
-  `status` varchar(32) NOT NULL DEFAULT 'in_use' COMMENT '鐘舵��: in_use/expired/amortized',
-  `description` varchar(1000) DEFAULT NULL COMMENT '璧勪骇鎻忚堪',
-  `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` varchar(64) DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_fin_intangible_asset_code` (`asset_code`),
-  KEY `idx_fin_intangible_asset_status` (`status`),
-  KEY `idx_fin_intangible_asset_category` (`category`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='鏃犲舰璧勪骇';
-
-CREATE TABLE IF NOT EXISTS `fin_voucher` (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `voucher_no` varchar(64) NOT NULL COMMENT '鍑瘉瀛楀彿',
-  `voucher_date` date NOT NULL COMMENT '鍑瘉鏃ユ湡',
-  `summary` varchar(500) DEFAULT NULL COMMENT '鎽樿',
-  `debit` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '鍊熸柟鍚堣',
-  `credit` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '璐锋柟鍚堣',
-  `creator` varchar(64) DEFAULT NULL COMMENT '鍒跺崟浜�',
-  `status` varchar(32) NOT NULL DEFAULT 'unposted' COMMENT '鐘舵��: unposted/posted/cancelled',
-  `attachment_count` int NOT NULL DEFAULT '0' COMMENT '闄勪欢寮犳暟',
-  `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` varchar(64) DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_fin_voucher_no` (`voucher_no`),
-  KEY `idx_fin_voucher_date` (`voucher_date`),
-  KEY `idx_fin_voucher_status` (`status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='鍑瘉涓昏〃';
-
-CREATE TABLE IF NOT EXISTS `fin_voucher_entry` (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `voucher_id` bigint NOT NULL COMMENT '鍑瘉ID',
-  `row_no` int NOT NULL DEFAULT '1' COMMENT '琛屽彿',
-  `subject_code` varchar(64) NOT NULL COMMENT '绉戠洰缂栫爜',
-  `subject_name` varchar(128) DEFAULT NULL COMMENT '绉戠洰鍚嶇О',
-  `summary` varchar(500) DEFAULT NULL COMMENT '鎽樿',
-  `debit` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '鍊熸柟閲戦',
-  `credit` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '璐锋柟閲戦',
-  `auxiliary_type` varchar(32) DEFAULT NULL COMMENT '杈呭姪鏍哥畻绫诲瀷',
-  `auxiliary_id` varchar(64) DEFAULT NULL COMMENT '杈呭姪鏍哥畻瀵硅薄ID',
-  `auxiliary_name` varchar(128) DEFAULT NULL COMMENT '杈呭姪鏍哥畻瀵硅薄鍚嶇О',
-  `create_user` varchar(64) DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`),
-  KEY `idx_fin_voucher_entry_voucher` (`voucher_id`),
-  KEY `idx_fin_voucher_entry_subject` (`subject_code`),
-  KEY `idx_fin_voucher_entry_aux` (`auxiliary_type`, `auxiliary_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='鍑瘉鍒嗗綍';
diff --git a/doc/20260515_device_maintenance_inspection_abnormal_acceptance.sql b/doc/20260515_device_maintenance_inspection_abnormal_acceptance.sql
deleted file mode 100644
index 7f34fe0..0000000
--- a/doc/20260515_device_maintenance_inspection_abnormal_acceptance.sql
+++ /dev/null
@@ -1,22 +0,0 @@
-ALTER TABLE `inspection_task`
-    ADD COLUMN `inspection_project` VARCHAR(100) NULL COMMENT '宸℃椤圭洰' AFTER `task_name`;
-
-ALTER TABLE `inspection_task`
-    ADD COLUMN `inspection_result` VARCHAR(1) NULL COMMENT '宸℃缁撴灉 0寮傚父 1姝e父' AFTER `remarks`,
-    ADD COLUMN `abnormal_description` VARCHAR(500) NULL COMMENT '寮傚父鎻忚堪' AFTER `inspection_result`,
-    ADD COLUMN `device_repair_id` BIGINT NULL COMMENT '鍏宠仈缁翠慨鍗旾D' AFTER `abnormal_description`,
-    ADD COLUMN `acceptance_user_id` BIGINT NULL COMMENT '楠屾敹浜篒D' AFTER `device_repair_id`,
-    ADD COLUMN `acceptance_name` VARCHAR(100) NULL COMMENT '楠屾敹浜�' AFTER `acceptance_user_id`;
-
-ALTER TABLE `timing_task`
-    ADD COLUMN `inspection_project` VARCHAR(100) NULL COMMENT '宸℃椤圭洰' AFTER `task_name`,
-    ADD COLUMN `is_enabled` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '鏄惁鍚敤 0鍚� 1鏄�' AFTER `is_active`;
-
-CREATE INDEX `idx_inspection_task_device_repair_id`
-    ON `inspection_task` (`device_repair_id`);
-
-CREATE INDEX `idx_inspection_task_inspection_result`
-    ON `inspection_task` (`inspection_result`);
-
-CREATE INDEX `idx_timing_task_is_enabled`
-    ON `timing_task` (`is_enabled`);
diff --git "a/doc/20260523_ \345\215\217\345\220\214\345\256\241\346\211\271\346\226\260\345\242\236\345\207\272\345\267\256\346\227\266\351\227\264\345\222\214\347\273\223\346\235\237\346\227\266\351\227\264.sql" "b/doc/20260523_ \345\215\217\345\220\214\345\256\241\346\211\271\346\226\260\345\242\236\345\207\272\345\267\256\346\227\266\351\227\264\345\222\214\347\273\223\346\235\237\346\227\266\351\227\264.sql"
deleted file mode 100644
index 0e0c5ce..0000000
--- "a/doc/20260523_ \345\215\217\345\220\214\345\256\241\346\211\271\346\226\260\345\242\236\345\207\272\345\267\256\346\227\266\351\227\264\345\222\214\347\273\223\346\235\237\346\227\266\351\227\264.sql"
+++ /dev/null
@@ -1,3 +0,0 @@
-ALTER TABLE approve_process
-    ADD COLUMN start_date_time datetime DEFAULT NULL COMMENT '鍑哄樊寮�濮嬫椂闂�',
-    ADD COLUMN end_date_time   datetime DEFAULT NULL COMMENT '鍑哄樊缁撴潫鏃堕棿';
diff --git a/doc/20260615_add_plan_person_and_executor_to_routing_operation.sql b/doc/20260615_add_plan_person_and_executor_to_routing_operation.sql
deleted file mode 100644
index b98e8ca..0000000
--- a/doc/20260615_add_plan_person_and_executor_to_routing_operation.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-# 鐢熶骇宸ュ簭鏂板璁″垝浜哄憳鍜岃鍒掓墽琛屼汉鍛樺瓧娈�
-ALTER TABLE technology_routing_operation
-    ADD plan_person bigint NULL COMMENT '璁″垝浜哄憳ID',
-    ADD executor bigint NULL COMMENT '璁″垝鎵ц浜哄憳ID';
-
-ALTER TABLE production_order_routing_operation
-    ADD plan_person bigint NULL COMMENT '璁″垝浜哄憳ID',
-    ADD executor bigint NULL COMMENT '璁″垝鎵ц浜哄憳ID';
diff --git a/doc/alter_table_measuring_instrument_ledger.sql b/doc/alter_table_measuring_instrument_ledger.sql
deleted file mode 100644
index 2c036fe..0000000
--- a/doc/alter_table_measuring_instrument_ledger.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-ALTER TABLE measuring_instrument_ledger
-    ADD COLUMN dept_id BIGINT COMMENT '閮ㄩ棬ID',
-    ADD COLUMN installation_location VARCHAR(255) COMMENT '瀹夎浣嶇疆',
-    ADD COLUMN unit VARCHAR(100) COMMENT '妫�瀹氬崟浣�',
-    ADD COLUMN cycle INT COMMENT '妫�瀹氬懆鏈燂紙澶╋級';
diff --git a/doc/create_table_customer_user.sql b/doc/create_table_customer_user.sql
deleted file mode 100644
index dacbfb4..0000000
--- a/doc/create_table_customer_user.sql
+++ /dev/null
@@ -1,10 +0,0 @@
-drop table if exists customer_user;
-create table customer_user
-(
-    id          bigint auto_increment
-        primary key,
-    customer_id bigint not null default 0 comment '瀹㈡埛id',
-    user_id     bigint not null default 0 comment '鐢ㄦ埛id',
-    create_time datetime null comment '褰曞叆鏃堕棿',
-    tenant_id   bigint not null default 0 comment '绉熸埛id'
-);
diff --git a/doc/create_table_process_route.sql b/doc/create_table_process_route.sql
deleted file mode 100644
index 4a453f8..0000000
--- a/doc/create_table_process_route.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-# 宸ヨ壓璺嚎
-drop table if exists process_route;
-create table process_route
-(
-    id          bigint auto_increment primary key,
-    product_model_id  bigint       not null default 0 comment '浜у搧id',
-    description varchar(255) not null default '' comment '鎻忚堪',
-    tenant_id   bigint       not null comment '绉熸埛id',
-    create_time datetime     null comment '褰曞叆鏃堕棿',
-    update_time datetime     null comment '鏇存柊鏃堕棿'
-);
diff --git a/doc/create_table_process_route_item.sql b/doc/create_table_process_route_item.sql
deleted file mode 100644
index a1efff9..0000000
--- a/doc/create_table_process_route_item.sql
+++ /dev/null
@@ -1,62 +0,0 @@
-# 宸ヨ壓璺嚎椤圭洰
-drop table if exists process_route_item;
-create table process_route_item
-(
-    id               bigint auto_increment primary key,
-    route_id         bigint   not null default 0 comment '宸ヨ壓璺嚎id',
-    product_model_id bigint   not null default 0 comment '浜у搧id',
-    process_id       bigint   not null default 0 comment '宸ュ簭id',
-    tenant_id        bigint   not null comment '绉熸埛id',
-    create_time      datetime null comment '褰曞叆鏃堕棿',
-    update_time      datetime null comment '鏇存柊鏃堕棿'
-);
-
-# 鐢熶骇宸ヨ壓璺嚎椤圭洰
-drop table if exists product_process_route_item;
-create table product_process_route_item
-(
-    id               bigint auto_increment primary key,
-    route_id         bigint   not null default 0 comment '宸ヨ壓璺嚎id',
-    product_model_id bigint   not null default 0 comment '閿�鍞彴璐︿骇鍝乮d',
-    process_id       bigint   not null default 0 comment '宸ュ簭id',
-    tenant_id        bigint   not null comment '绉熸埛id',
-    create_time      datetime null comment '褰曞叆鏃堕棿',
-    update_time      datetime null comment '鏇存柊鏃堕棿'
-);
-
-# 鐢熶骇璁㈠崟
-drop table if exists product_order;
-create table product_order
-(
-    id               bigint auto_increment primary key,
-    sales_ledger_id  bigint   not null default 0 comment '閿�鍞彴璐d',
-    product_model_id bigint   not null default 0 comment '閿�鍞彴璐︿骇鍝乮d',
-    route_id         bigint   not null default 0 comment '宸ヨ壓璺嚎id',
-    nps_no          varchar(255) not null default '' comment '鐢熶骇璁㈠崟鍙�',
-    status            int not null default 0 comment '鐘舵�� 0 寰呯‘璁� 1 宸茬‘璁�',
-    tenant_id        bigint   not null comment '绉熸埛id',
-    create_time      datetime null comment '褰曞叆鏃堕棿',
-    update_time      datetime null comment '鏇存柊鏃堕棿'
-);
-alter table quality_inspect
-    add purchase_ledger_id int null comment '閲囪喘璁㈠崟id';
-
-# 鐢熶骇宸ュ崟
-drop table if exists product_work_order;
-create table product_work_order
-(
-    id               bigint auto_increment primary key,
-    product_process_route_item_id bigint   not null default 0 comment '宸ヨ壓璺嚎椤圭洰id',
-    create_time      datetime null comment '褰曞叆鏃堕棿',
-    update_time      datetime null comment '鏇存柊鏃堕棿',
-    work_order_no    varchar(255) not null default '' comment '宸ュ崟缂栧彿',
-    plan_start_time  datetime null comment '璁″垝寮�濮嬫椂闂�',
-    plan_end_time    datetime null comment '璁″垝缁撴潫鏃堕棿',
-    actual_start_time  datetime null comment '瀹為檯寮�濮嬫椂闂�',
-    actual_end_time    datetime null comment '瀹為檯缁撴潫鏃堕棿',
-    status           int not null default 0 comment '鐘舵��  1 寰呯‘璁�  2 寰呯敓浜� 3鐢熶骇涓� 4宸茬敓浜� ',
-    tenant_id        bigint   not null comment '绉熸埛id'
-);
-
-alter table product_process
-    add salary_quota numeric(16,3) null comment '宸ヨ祫瀹氶';
\ No newline at end of file
diff --git a/doc/create_table_product_process.sql b/doc/create_table_product_process.sql
deleted file mode 100644
index 6242614..0000000
--- a/doc/create_table_product_process.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-# 宸ュ簭
-drop table if exists product_process;
-create table product_process
-(
-    id          bigint auto_increment
-        primary key,
-    create_time datetime null comment '褰曞叆鏃堕棿',
-    update_time datetime null comment '鏇存柊鏃堕棿',
-    name        varchar(255) not null default '' comment '宸ヨ壓鍚嶇О',
-    no          varchar(255) not null default '' comment '宸ヨ壓缂栧彿',
-    remark      varchar(255) not null default '' comment '澶囨敞',
-    tenant_id   bigint       not null default 0 comment '绉熸埛id'
-);
\ No newline at end of file
diff --git a/doc/create_table_product_structure.sql b/doc/create_table_product_structure.sql
deleted file mode 100644
index 83af495..0000000
--- a/doc/create_table_product_structure.sql
+++ /dev/null
@@ -1,16 +0,0 @@
-# 浜у搧缁撴瀯
-drop table if exists product_structure;
-create table product_structure
-(
-    id                 bigint auto_increment
-        primary key,
-    product_model_id         bigint         not null comment '浜у搧id',
-    process_id         bigint         not null comment '宸ュ簭id',
-    unit_quantity      numeric(16, 4) not null comment '鍗曚綅浜у嚭闇�瑕佹暟閲�',
-    demanded_quantity  numeric(16, 4) not null comment '闇�姹傛暟閲�',
-    unit               varchar(255)   not null comment '鍗曚綅',
-    disk_quantity      numeric(16, 4) not null comment '鐩樻暟閲�',
-    tenant_id          bigint         not null comment '绉熸埛id'
-);
-alter table product_structure
-    add parent_id bigint null comment '鐖秈d';
diff --git a/doc/create_table_production_product_main.sql b/doc/create_table_production_product_main.sql
deleted file mode 100644
index 18fb92d..0000000
--- a/doc/create_table_production_product_main.sql
+++ /dev/null
@@ -1,36 +0,0 @@
-drop table if exists production_product_main;
-create table production_product_main
-(
-    id            bigint auto_increment
-        primary key,
-    product_no    varchar(255) not null comment '鎶ュ伐鍗曞彿',
-    user_id       bigint       not null comment '鎶ュ伐鐢ㄦ埛id',
-    work_order_id bigint       not null comment '宸ュ崟id',
-    status        int          not null comment '鐘舵�� 0 寰呮姤宸� 1 寰呯‘璁�',
-    create_time   datetime     null comment '褰曞叆鏃堕棿',
-    tenant_id          bigint         not null comment '绉熸埛id'
-);
-
-drop table if exists production_product_output;
-create table production_product_output
-(
-    id               bigint auto_increment
-        primary key,
-    product_main_id  bigint         not null comment '鎶ュ伐鍗昳d',
-    product_model_id bigint         not null comment '浜у搧id',
-    quantity         numeric(16, 4) not null comment '鏁伴噺',
-    create_time      datetime       null comment '褰曞叆鏃堕棿',
-    tenant_id          bigint         not null comment '绉熸埛id'
-);
-
-drop table if exists production_product_input;
-create table production_product_input
-(
-    id               bigint auto_increment
-        primary key,
-    product_main_id  bigint         not null comment '鎶ュ伐鍗昳d',
-    product_model_id bigint         not null comment '浜у搧id',
-    quantity         numeric(16, 4) not null comment '鏁伴噺',
-    create_time      datetime       null comment '褰曞叆鏃堕棿',
-    tenant_id          bigint         not null comment '绉熸埛id'
-)
diff --git a/doc/sql/20260609_knowledge_base_vector.sql b/doc/sql/20260609_knowledge_base_vector.sql
deleted file mode 100644
index 7b4323f..0000000
--- a/doc/sql/20260609_knowledge_base_vector.sql
+++ /dev/null
@@ -1,30 +0,0 @@
--- 鐭ヨ瘑搴撳悜閲忔绱㈠姛鑳芥暟鎹簱鍙樻洿
--- 鎵ц鍓嶈纭繚 knowledge_base 琛ㄥ凡瀛樺湪
-
--- 1. knowledge_base 琛ㄥ鍔犲瓧娈�
-ALTER TABLE knowledge_base
-ADD COLUMN IF NOT EXISTS file_count INT DEFAULT 0 COMMENT '鏂囦欢鏁伴噺',
-ADD COLUMN IF NOT EXISTS total_chunk_count INT DEFAULT 0 COMMENT '鎬诲垏鐗囨暟閲�',
-ADD COLUMN IF NOT EXISTS description VARCHAR(500) COMMENT '鐭ヨ瘑搴撴弿杩�';
-
--- 2. 鍒涘缓鐭ヨ瘑搴撴枃浠跺悜閲忚褰曡〃
-CREATE TABLE IF NOT EXISTS knowledge_base_vector (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '涓婚敭ID',
-    knowledge_base_id BIGINT NOT NULL COMMENT '鍏宠仈鐭ヨ瘑搴揑D',
-    storage_blob_id BIGINT NOT NULL COMMENT '鍏宠仈鏂囦欢blob ID',
-    file_name VARCHAR(255) NOT NULL COMMENT '鏂囦欢鍚嶇О',
-    file_type VARCHAR(50) NOT NULL COMMENT '鏂囦欢绫诲瀷(docx/pdf/xlsx/txt绛�)',
-    vector_status TINYINT DEFAULT 0 COMMENT '鍚戦噺鍖栫姸鎬�: 0-寰呭鐞�, 1-澶勭悊涓�, 2-宸插畬鎴�, 3-澶辫触',
-    vector_error VARCHAR(500) COMMENT '鍚戦噺鍖栧け璐ュ師鍥�',
-    chunk_count INT DEFAULT 0 COMMENT '鍒囩墖鏁伴噺',
-    namespace VARCHAR(100) COMMENT '鍚戦噺鍛藉悕绌洪棿',
-    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-    create_user INT COMMENT '鍒涘缓浜�',
-    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-    update_user INT COMMENT '鏇存柊浜�',
-    tenant_id BIGINT COMMENT '绉熸埛ID',
-    dept_id BIGINT COMMENT '閮ㄩ棬ID',
-    INDEX idx_knowledge_base_id (knowledge_base_id),
-    INDEX idx_storage_blob_id (storage_blob_id),
-    INDEX idx_vector_status (vector_status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鐭ヨ瘑搴撴枃浠跺悜閲忚褰曡〃';
\ No newline at end of file
diff --git "a/doc/\347\237\245\350\257\206\345\272\223RAG\345\212\237\350\203\275\345\256\236\347\216\260\346\226\207\346\241\243.md" "b/doc/\347\237\245\350\257\206\345\272\223RAG\345\212\237\350\203\275\345\256\236\347\216\260\346\226\207\346\241\243.md"
deleted file mode 100644
index 4a94cc5..0000000
--- "a/doc/\347\237\245\350\257\206\345\272\223RAG\345\212\237\350\203\275\345\256\236\347\216\260\346\226\207\346\241\243.md"
+++ /dev/null
@@ -1,1034 +0,0 @@
-# 鐭ヨ瘑搴揜AG鍚戦噺妫�绱㈠姛鑳藉疄鐜版枃妗�
-
-## 涓�銆佸姛鑳芥杩�
-
-鍩轰簬 RAG锛圧etrieval-Augmented Generation锛夋妧鏈疄鐜扮煡璇嗗簱闂瓟鍔熻兘锛屾敮鎸侊細
-- 鐭ヨ瘑搴撶鐞嗭紙CRUD锛�
-- 鏂囦欢涓婁紶涓庡悜閲忓寲澶勭悊
-- 鍩轰簬鍚戦噺妫�绱㈢殑鏅鸿兘闂瓟
-- 澶氱鏂囦欢鏍煎紡鏀寔锛坱xt銆乵d銆乨ocx銆亁lsx銆亁ls銆乸df锛�
-
-## 浜屻�佹妧鏈灦鏋�
-
-### 2.1 鎶�鏈爤
-| 缁勪欢 | 鎶�鏈� |
-|------|------|
-| 鍚戦噺鏁版嵁搴� | Pinecone |
-| Embedding妯″瀷 | 闃块噷浜� DashScope text-embedding-v3 |
-| LLM | 闃块噷浜戦�氫箟鍗冮棶 qwen-max |
-| 妗嗘灦 | langchain4j |
-| ORM | MyBatis-Plus |
-
-### 2.2 鏋舵瀯鍥�
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹�                        鍓嶇搴旂敤                              鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-                              鈹�
-                              鈻�
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹�                     Controller Layer                         鈹�
-鈹�  鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�  鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�   鈹�
-鈹�  鈹� KnowledgeBaseCtrl   鈹�  鈹� KnowledgeChatController     鈹�   鈹�
-鈹�  鈹� (鐭ヨ瘑搴撶鐞�)         鈹�  鈹� (鐭ヨ瘑搴撻棶绛�)                 鈹�   鈹�
-鈹�  鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�  鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�   鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-                              鈹�
-                              鈻�
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹�                      Service Layer                           鈹�
-鈹�  鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�  鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�   鈹�
-鈹�  鈹侹nowledgeBaseService 鈹�  鈹� KnowledgeRagService         鈹�   鈹�
-鈹�  鈹� (鐭ヨ瘑搴揅RUD)         鈹�  鈹� (鍚戦噺鍖�/妫�绱�)                鈹�   鈹�
-鈹�  鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�  鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�   鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-                              鈹�
-                              鈻�
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹�                      AI Layer                                鈹�
-鈹�  鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�  鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�   鈹�
-鈹�  鈹� KnowledgeChatAgent  鈹�  鈹� EmbeddingStore (Pinecone)   鈹�   鈹�
-鈹�  鈹� (闂瓟Agent)          鈹�  鈹� (鍚戦噺瀛樺偍)                   鈹�   鈹�
-鈹�  鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�  鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�   鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
----
-
-## 涓夈�佸悗绔疄鐜�
-
-### 3.1 鏁版嵁搴撹璁�
-
-#### 3.1.1 鐭ヨ瘑搴撹〃锛坘nowledge_base锛�
-
-```sql
-CREATE TABLE knowledge_base (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    title VARCHAR(255) COMMENT '鐭ヨ瘑鏍囬',
-    type VARCHAR(50) COMMENT '鐭ヨ瘑绫诲瀷',
-    scenario VARCHAR(255) COMMENT '閫傜敤鍦烘櫙',
-    efficiency VARCHAR(20) COMMENT '瑙e喅鏁堢巼',
-    problem TEXT COMMENT '闂鎻忚堪',
-    solution TEXT COMMENT '瑙e喅鏂规',
-    key_points TEXT COMMENT '鍏抽敭瑕佺偣',
-    creator VARCHAR(100) COMMENT '鍒涘缓浜�',
-    usage_count INT DEFAULT 0 COMMENT '浣跨敤娆℃暟',
-    file_count INT DEFAULT 0 COMMENT '鏂囦欢鏁伴噺',
-    total_chunk_count INT DEFAULT 0 COMMENT '鎬诲垏鐗囨暟閲�',
-    description VARCHAR(500) COMMENT '鐭ヨ瘑搴撴弿杩�',
-    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
-    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    create_user INT,
-    update_user INT,
-    tenant_id BIGINT,
-    dept_id BIGINT
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鐭ヨ瘑搴撹〃';
-```
-
-#### 3.1.2 鐭ヨ瘑搴撳悜閲忚褰曡〃锛坘nowledge_base_vector锛�
-
-```sql
-CREATE TABLE knowledge_base_vector (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '涓婚敭ID',
-    knowledge_base_id BIGINT NOT NULL COMMENT '鍏宠仈鐭ヨ瘑搴揑D',
-    storage_blob_id BIGINT NOT NULL COMMENT '鍏宠仈鏂囦欢blob ID',
-    file_name VARCHAR(255) NOT NULL COMMENT '鏂囦欢鍚嶇О',
-    file_type VARCHAR(50) NOT NULL COMMENT '鏂囦欢绫诲瀷',
-    vector_status TINYINT DEFAULT 0 COMMENT '鍚戦噺鍖栫姸鎬�: 0-寰呭鐞�, 1-澶勭悊涓�, 2-宸插畬鎴�, 3-澶辫触',
-    vector_error VARCHAR(500) COMMENT '鍚戦噺鍖栧け璐ュ師鍥�',
-    chunk_count INT DEFAULT 0 COMMENT '鍒囩墖鏁伴噺',
-    namespace VARCHAR(100) COMMENT '鍚戦噺鍛藉悕绌洪棿',
-    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
-    create_user INT,
-    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    update_user INT,
-    tenant_id BIGINT,
-    dept_id BIGINT,
-    INDEX idx_knowledge_base_id (knowledge_base_id),
-    INDEX idx_storage_blob_id (storage_blob_id),
-    INDEX idx_vector_status (vector_status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='鐭ヨ瘑搴撴枃浠跺悜閲忚褰曡〃';
-```
-
-### 3.2 Maven渚濊禆
-
-```xml
-<!-- langchain4j BOM -->
-<dependencyManagement>
-    <dependencies>
-        <dependency>
-            <groupId>dev.langchain4j</groupId>
-            <artifactId>langchain4j-bom</artifactId>
-            <version>1.0.0-beta3</version>
-            <type>pom</type>
-            <scope>import</scope>
-        </dependency>
-    </dependencies>
-</dependencyManagement>
-
-<dependencies>
-    <!-- langchain4j 鏍稿績 -->
-    <dependency>
-        <groupId>dev.langchain4j</groupId>
-        <artifactId>langchain4j-spring-boot-starter</artifactId>
-    </dependency>
-
-    <!-- Pinecone 鍚戦噺鏁版嵁搴� -->
-    <dependency>
-        <groupId>dev.langchain4j</groupId>
-        <artifactId>langchain4j-pinecone</artifactId>
-    </dependency>
-
-    <!-- 闃块噷浜� DashScope -->
-    <dependency>
-        <groupId>dev.langchain4j</groupId>
-        <artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
-    </dependency>
-</dependencies>
-```
-
-### 3.3 閰嶇疆鏂囦欢锛坅pplication.yml锛�
-
-```yaml
-# Pinecone 鍚戦噺鏁版嵁搴撻厤缃�
-pinecone:
-  api-key: your-pinecone-api-key
-  index: your-index-name
-  namespace: knowledge-base
-
-# langchain4j 閰嶇疆
-langchain4j:
-  community:
-    dashscope:
-      streaming-chat-model:
-        api-key: your-dashscope-api-key
-        model-name: "qwen-max"
-      embedding-model:
-        api-key: your-dashscope-api-key
-        model-name: "text-embedding-v3"
-```
-
-### 3.4 鏍稿績浠g爜瀹炵幇
-
-#### 3.4.1 瀹炰綋绫�
-
-**KnowledgeBase.java**
-```java
-@Data
-@TableName("knowledge_base")
-public class KnowledgeBase implements Serializable {
-    @TableId(type = IdType.AUTO)
-    private Long id;
-    private String title;
-    private String type;
-    private String scenario;
-    private String efficiency;
-    private String problem;
-    private String solution;
-    private String keyPoints;
-    private String creator;
-    private Integer usageCount;
-    private Integer fileCount;
-    private Integer totalChunkCount;
-    private String description;
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
-```
-
-**KnowledgeBaseVector.java**
-```java
-@Data
-@TableName("knowledge_base_vector")
-public class KnowledgeBaseVector implements Serializable {
-    @TableId(type = IdType.AUTO)
-    private Long id;
-    private Long knowledgeBaseId;
-    private Long storageBlobId;
-    private String fileName;
-    private String fileType;
-    private Integer vectorStatus;
-    private String vectorError;
-    private Integer chunkCount;
-    private String namespace;
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-
-    // 鍚戦噺鍖栫姸鎬佸父閲�
-    public static final int STATUS_PENDING = 0;
-    public static final int STATUS_PROCESSING = 1;
-    public static final int STATUS_COMPLETED = 2;
-    public static final int STATUS_FAILED = 3;
-}
-```
-
-#### 3.4.2 EmbeddingStore閰嶇疆
-
-**EmbeddingStoreConfig.java**
-```java
-@Configuration
-public class EmbeddingStoreConfig {
-
-    @Value("${pinecone.api-key}")
-    private String pineconeApiKey;
-
-    @Value("${pinecone.index}")
-    private String indexName;
-
-    @Value("${pinecone.namespace}")
-    private String namespace;
-
-    @Bean
-    public Pinecone pinecone() {
-        return new Pinecone.Builder(pineconeApiKey).build();
-    }
-
-    @Bean
-    public Index pineconeIndex(Pinecone pinecone) {
-        return pinecone.getIndexConnection(indexName);
-    }
-
-    @Bean
-    public EmbeddingStore<TextSegment> embeddingStore(EmbeddingModel embeddingModel) {
-        return PineconeEmbeddingStore.builder()
-                .apiKey(pineconeApiKey)
-                .index(indexName)
-                .nameSpace(namespace)
-                .createIndex(PineconeServerlessIndexConfig.builder()
-                        .cloud("AWS")
-                        .region("us-east-1")
-                        .dimension(embeddingModel.dimension())
-                        .build())
-                .build();
-    }
-}
-```
-
-#### 3.4.3 RAG鏈嶅姟瀹炵幇
-
-**KnowledgeRagService.java**
-```java
-public interface KnowledgeRagService {
-    void processVectorAsync(Long vectorId);
-    void processVector(Long vectorId);
-    List<String> searchRelevantContent(String namespace, String query, int maxResults);
-    void deleteEmbeddings(String namespace, Long storageBlobId);
-}
-```
-
-**KnowledgeRagServiceImpl.java**锛堟牳蹇冨疄鐜帮級
-```java
-@Slf4j
-@Service
-public class KnowledgeRagServiceImpl implements KnowledgeRagService {
-
-    private final KnowledgeBaseVectorService knowledgeBaseVectorService;
-    private final StorageBlobService storageBlobService;
-    private final EmbeddingModel embeddingModel;
-    private final EmbeddingStore<TextSegment> embeddingStore;
-    private final FileProperties fileProperties;
-    private final Index pineconeIndex;
-
-    @Value("${pinecone.namespace}")
-    private String namespace;
-
-    private static final int CHUNK_SIZE = 500;
-    private static final int CHUNK_OVERLAP = 100;
-    private static final long CHUNK_THRESHOLD_BYTES = 80L * 1024 * 1024;
-    private static final int EMBEDDING_MAX_LENGTH = 8000;
-
-    @Override
-    @Async("threadPoolTaskExecutor")
-    public void processVectorAsync(Long vectorId) {
-        processVector(vectorId);
-    }
-
-    @Override
-    public void processVector(Long vectorId) {
-        KnowledgeBaseVector vector = knowledgeBaseVectorService.getById(vectorId);
-        if (vector == null) return;
-
-        try {
-            // 鏇存柊鐘舵�佷负澶勭悊涓�
-            knowledgeBaseVectorService.updateVectorStatus(vectorId, STATUS_PROCESSING, null, null);
-
-            // 鑾峰彇鏂囦欢鍐呭
-            StorageBlob blob = storageBlobService.getById(vector.getStorageBlobId());
-            File file = getFile(blob);
-            String content = extractFileContent(file, vector.getFileName());
-
-            if (content == null || content.trim().isEmpty()) {
-                throw new RuntimeException("鏂囦欢鍐呭涓虹┖");
-            }
-
-            // 鏂囨湰鍒囩墖
-            List<TextSegment> chunks;
-            boolean needChunk = file.length() > CHUNK_THRESHOLD_BYTES || content.length() > EMBEDDING_MAX_LENGTH;
-            if (needChunk) {
-                chunks = splitText(content, vector);
-            } else {
-                Map<String, Object> metadata = buildMetadata(vector);
-                chunks = List.of(TextSegment.from(content, new Metadata(metadata)));
-            }
-
-            // 鐢熸垚宓屽叆鍚戦噺骞跺瓨鍌�
-            int chunkCount = 0;
-            for (TextSegment chunk : chunks) {
-                Embedding embedding = embeddingModel.embed(chunk).content();
-                embeddingStore.add(embedding, chunk);
-                chunkCount++;
-            }
-
-            // 鏇存柊鐘舵�佷负瀹屾垚
-            knowledgeBaseVectorService.updateVectorStatus(vectorId, STATUS_COMPLETED, chunkCount, null);
-
-        } catch (Exception e) {
-            log.error("鍚戦噺鍖栧鐞嗗け璐�", e);
-            knowledgeBaseVectorService.updateVectorStatus(vectorId, STATUS_FAILED, null, e.getMessage());
-        }
-    }
-
-    @Override
-    public List<String> searchRelevantContent(String namespace, String query, int maxResults) {
-        Embedding queryEmbedding = embeddingModel.embed(query).content();
-        EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder()
-                .queryEmbedding(queryEmbedding)
-                .maxResults(maxResults)
-                .minScore(0.7)
-                .build();
-        EmbeddingSearchResult<TextSegment> searchResult = embeddingStore.search(searchRequest);
-        return searchResult.matches().stream()
-                .map(match -> match.embedded().text())
-                .collect(Collectors.toList());
-    }
-
-    @Override
-    public void deleteEmbeddings(String namespace, Long storageBlobId) {
-        Struct filter = Struct.newBuilder()
-                .putFields("storageBlobId", Value.newBuilder()
-                        .setStructValue(Struct.newBuilder()
-                                .putFields("$eq", Value.newBuilder()
-                                        .setNumberValue(storageBlobId.doubleValue())
-                                        .build()))
-                        .build())
-                .build();
-        pineconeIndex.delete(new ArrayList<>(), false, this.namespace, filter);
-    }
-
-    private String extractFileContent(File file, String fileName) throws Exception {
-        String ext = getFileExtension(fileName);
-        if (isPlainText(ext)) {
-            return readFileWithEncoding(file);
-        }
-        if ("docx".equals(ext)) {
-            return extractDocx(file);
-        }
-        if ("xlsx".equals(ext) || "xls".equals(ext)) {
-            return extractExcel(file);
-        }
-        return readFileWithEncoding(file);
-    }
-
-    // ... 鍏朵粬杈呭姪鏂规硶
-}
-```
-
-#### 3.4.4 鐭ヨ瘑搴撻棶绛擜gent
-
-**KnowledgeChatAgent.java**
-```java
-@AiService(
-        wiringMode = EXPLICIT,
-        streamingChatModel = "qwenStreamingChatModel",
-        chatMemoryProvider = "chatMemoryProvider"
-)
-public interface KnowledgeChatAgent {
-
-    @SystemMessage("""
-            浣犳槸浼佷笟鐭ヨ瘑搴撻棶绛斿姪鎵嬨��
-            浣犻渶瑕佸熀浜庢彁渚涚殑鐭ヨ瘑搴撳唴瀹瑰洖绛旂敤鎴烽棶棰樸��
-            閬靛惊浠ヤ笅瑙勫垯锛�
-            1. 涓ユ牸鍩轰簬鐭ヨ瘑搴撳唴瀹瑰洖绛旓紝涓嶈缂栭�犱俊鎭�
-            2. 濡傛灉鐭ヨ瘑搴撲腑娌℃湁鐩稿叧淇℃伅锛屾槑纭憡鐭ョ敤鎴�
-            3. 鍥炵瓟瑕佸噯纭�佺畝娲併�佹湁鏉$悊
-            4. 寮曠敤鏉ユ簮鏃舵敞鏄�"鏍规嵁鐭ヨ瘑搴撳唴瀹�"
-            """)
-    Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage);
-}
-```
-
-#### 3.4.5 Controller灞�
-
-**KnowledgeBaseController.java**
-```java
-@RestController
-@RequestMapping("/knowledgeBase")
-@Tag(name = "鐭ヨ瘑搴撶鐞�")
-public class KnowledgeBaseController {
-
-    @GetMapping("/getList")
-    public AjaxResult getList(@RequestParam(defaultValue = "1") long current,
-                              @RequestParam(defaultValue = "10") long size,
-                              KnowledgeBase knowledgeBase) {
-        Page page = new Page(current, size);
-        return AjaxResult.success(knowledgeBaseService.listpage(page, knowledgeBase));
-    }
-
-    @PostMapping("/add")
-    public AjaxResult add(@RequestBody KnowledgeBase knowledgeBase) {
-        return AjaxResult.success(knowledgeBaseService.save(knowledgeBase));
-    }
-
-    @PostMapping("/update")
-    public AjaxResult update(@RequestBody KnowledgeBase knowledgeBase) {
-        return AjaxResult.success(knowledgeBaseService.updateById(knowledgeBase));
-    }
-
-    @DeleteMapping("/delete")
-    public AjaxResult delete(@RequestBody List<Long> ids) {
-        return AjaxResult.success(knowledgeBaseService.removeByIds(ids));
-    }
-
-    @GetMapping("/vector/status/{knowledgeBaseId}")
-    @Operation(summary = "鏌ヨ鐭ヨ瘑搴撴枃浠跺悜閲忓寲鐘舵��")
-    public AjaxResult getVectorStatus(@PathVariable Long knowledgeBaseId) {
-        return AjaxResult.success(knowledgeBaseVectorService.getVectorStatusByKnowledgeBaseId(knowledgeBaseId));
-    }
-
-    @PostMapping("/vector/reprocess/{vectorId}")
-    @Operation(summary = "閲嶆柊鍚戦噺鍖栨枃浠�")
-    public AjaxResult reprocessVector(@PathVariable Long vectorId) {
-        knowledgeBaseVectorService.reprocessVector(vectorId);
-        return AjaxResult.success("宸查噸鏂版彁浜ゅ悜閲忓寲浠诲姟");
-    }
-
-    @PostMapping("/file/save")
-    @Operation(summary = "淇濆瓨鐭ヨ瘑搴撴枃浠跺叧鑱�")
-    public AjaxResult saveKnowledgeBaseFiles(@RequestBody KnowledgeBaseFileDTO dto) {
-        // 淇濆瓨闄勪欢鍏宠仈骞惰Е鍙戝悜閲忓寲
-        // ...
-    }
-
-    @DeleteMapping("/file/delete")
-    @Operation(summary = "鍒犻櫎鐭ヨ瘑搴撴枃浠�")
-    public AjaxResult deleteKnowledgeBaseFiles(@RequestBody List<Long> vectorIds) {
-        knowledgeBaseVectorService.deleteVectors(vectorIds);
-        return AjaxResult.success();
-    }
-}
-```
-
-**KnowledgeChatController.java**
-```java
-@RestController
-@RequestMapping("/ai/knowledge")
-@Tag(name = "鐭ヨ瘑搴撻棶绛�")
-public class KnowledgeChatController {
-
-    private final KnowledgeChatAgent knowledgeChatAgent;
-    private final KnowledgeRagService knowledgeRagService;
-    private final KnowledgeBaseService knowledgeBaseService;
-
-    @PostMapping(value = "/chat", produces = "text/stream;charset=utf-8")
-    @Operation(summary = "鐭ヨ瘑搴撻棶绛�")
-    public Flux<String> chat(@RequestBody KnowledgeChatRequest request) {
-        // 妫�绱㈢浉鍏冲唴瀹�
-        String namespace = "kb-" + request.getKnowledgeBaseId();
-        List<String> relevantContents = knowledgeRagService.searchRelevantContent(
-                namespace, request.getQuestion(), 5);
-
-        if (relevantContents.isEmpty()) {
-            return Flux.just("鐭ヨ瘑搴撲腑鏈壘鍒扮浉鍏冲唴瀹�");
-        }
-
-        // 鏋勫缓涓婁笅鏂�
-        StringBuilder context = new StringBuilder();
-        context.append("浠ヤ笅鏄粠鐭ヨ瘑搴撲腑妫�绱㈠埌鐨勭浉鍏冲唴瀹癸細\n\n");
-        for (int i = 0; i < relevantContents.size(); i++) {
-            context.append("銆愬唴瀹�").append(i + 1).append("銆慭n");
-            context.append(relevantContents.get(i)).append("\n\n");
-        }
-        context.append("---\n璇峰熀浜庝互涓婄煡璇嗗簱鍐呭鍥炵瓟锛歕n").append(request.getQuestion());
-
-        return knowledgeChatAgent.chat(request.getMemoryId(), context.toString());
-    }
-
-    @GetMapping("/list")
-    @Operation(summary = "鐭ヨ瘑搴撳垪琛�")
-    public AjaxResult listKnowledgeBases() {
-        return AjaxResult.success(knowledgeBaseService.list());
-    }
-}
-```
-
----
-
-## 鍥涖�丄PI鎺ュ彛鏂囨。
-
-### 4.1 鐭ヨ瘑搴撶鐞嗘帴鍙�
-
-| 鎺ュ彛 | 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|------|
-| 鑾峰彇鍒楄〃 | GET | /knowledgeBase/getList | 鍒嗛〉鏌ヨ鐭ヨ瘑搴撳垪琛� |
-| 鏂板鐭ヨ瘑搴� | POST | /knowledgeBase/add | 鍒涘缓鐭ヨ瘑搴� |
-| 鏇存柊鐭ヨ瘑搴� | POST | /knowledgeBase/update | 鏇存柊鐭ヨ瘑搴撲俊鎭� |
-| 鍒犻櫎鐭ヨ瘑搴� | DELETE | /knowledgeBase/delete | 鎵归噺鍒犻櫎鐭ヨ瘑搴� |
-| 鏌ヨ鍚戦噺鍖栫姸鎬� | GET | /knowledgeBase/vector/status/{id} | 鏌ヨ鏂囦欢鍚戦噺鍖栫姸鎬� |
-| 閲嶆柊鍚戦噺鍖� | POST | /knowledgeBase/vector/reprocess/{id} | 閲嶆柊澶勭悊澶辫触鐨勬枃浠� |
-| 淇濆瓨鏂囦欢鍏宠仈 | POST | /knowledgeBase/file/save | 涓婁紶鏂囦欢鍚庡叧鑱斿埌鐭ヨ瘑搴� |
-| 鍒犻櫎鏂囦欢 | DELETE | /knowledgeBase/file/delete | 鍒犻櫎鐭ヨ瘑搴撴枃浠� |
-
-### 4.2 鐭ヨ瘑搴撻棶绛旀帴鍙�
-
-| 鎺ュ彛 | 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|------|
-| 鐭ヨ瘑搴撻棶绛� | POST | /ai/knowledge/chat | 娴佸紡杩斿洖闂瓟缁撴灉 |
-| 鐭ヨ瘑搴撳垪琛� | GET | /ai/knowledge/list | 鑾峰彇鍙�夌煡璇嗗簱鍒楄〃 |
-
-### 4.3 鎺ュ彛璇︾粏璇存槑
-
-#### 4.3.1 淇濆瓨鐭ヨ瘑搴撴枃浠跺叧鑱�
-
-**璇锋眰**
-```json
-POST /knowledgeBase/file/save
-{
-    "knowledgeBaseId": 1,
-    "storageBlobIds": [100, 101, 102]
-}
-```
-
-**鍝嶅簲**
-```json
-{
-    "code": 200,
-    "msg": "鎿嶄綔鎴愬姛"
-}
-```
-
-#### 4.3.2 鐭ヨ瘑搴撻棶绛�
-
-**璇锋眰**
-```json
-POST /ai/knowledge/chat
-Content-Type: application/json
-
-{
-    "knowledgeBaseId": 1,
-    "memoryId": "session-uuid",
-    "question": "濡備綍澶勭悊搴撳瓨鐩樼偣宸紓锛�"
-}
-```
-
-**鍝嶅簲**锛圫SE娴佸紡锛�
-```
-鏍规嵁鐭ヨ瘑搴撳唴瀹癸紝搴撳瓨鐩樼偣宸紓鐨勫鐞嗘祦绋嬪涓嬶細
-
-1. 鍙戠幇宸紓鍚庯紝棣栧厛鏍稿鐩樼偣璁板綍...
-2. 妫�鏌ユ槸鍚︽湁婕忕洏鎴栭敊鐩�...
-3. ...
-```
-
----
-
-## 浜斻�佸墠绔疄鐜�
-
-### 5.1 鐭ヨ瘑搴撶鐞嗛〉闈�
-
-```vue
-<template>
-  <div class="knowledge-base">
-    <!-- 鍒楄〃 -->
-    <el-table :data="tableData" border>
-      <el-table-column prop="title" label="鐭ヨ瘑鏍囬" />
-      <el-table-column prop="type" label="鐭ヨ瘑绫诲瀷" />
-      <el-table-column prop="fileCount" label="鏂囦欢鏁伴噺" />
-      <el-table-column prop="totalChunkCount" label="鍒囩墖鏁伴噺" />
-      <el-table-column label="鎿嶄綔">
-        <template #default="{ row }">
-          <el-button @click="handleEdit(row)">缂栬緫</el-button>
-          <el-button @click="handleFiles(row)">鏂囦欢绠$悊</el-button>
-          <el-button @click="handleChat(row)">闂瓟</el-button>
-          <el-button type="danger" @click="handleDelete(row)">鍒犻櫎</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-  </div>
-</template>
-
-<script setup>
-import { ref, onMounted } from 'vue'
-import { getKnowledgeBaseList, deleteKnowledgeBase } from '@/api/knowledge'
-
-const tableData = ref([])
-
-const loadData = async () => {
-  const res = await getKnowledgeBaseList({ current: 1, size: 10 })
-  tableData.value = res.data.records
-}
-
-onMounted(loadData)
-</script>
-```
-
-### 5.2 鏂囦欢涓婁紶涓庡悜閲忓寲鐘舵��
-
-```vue
-<template>
-  <div class="file-manager">
-    <!-- 鏂囦欢涓婁紶 -->
-    <el-upload
-      :action="uploadUrl"
-      :on-success="handleUploadSuccess"
-      multiple
-    >
-      <el-button type="primary">涓婁紶鏂囦欢</el-button>
-    </el-upload>
-
-    <!-- 鏂囦欢鍒楄〃涓庡悜閲忓寲鐘舵�� -->
-    <el-table :data="fileList">
-      <el-table-column prop="fileName" label="鏂囦欢鍚�" />
-      <el-table-column label="鍚戦噺鍖栫姸鎬�">
-        <template #default="{ row }">
-          <el-tag :type="getStatusType(row.vectorStatus)">
-            {{ getStatusText(row.vectorStatus) }}
-          </el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column prop="chunkCount" label="鍒囩墖鏁�" />
-      <el-table-column label="鎿嶄綔">
-        <template #default="{ row }">
-          <el-button v-if="row.vectorStatus === 3" @click="reprocess(row)">
-            閲嶆柊澶勭悊
-          </el-button>
-          <el-button type="danger" @click="deleteFile(row)">鍒犻櫎</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-  </div>
-</template>
-
-<script setup>
-const uploadUrl = import.meta.env.VITE_APP_BASE_API + '/common/upload'
-
-// 涓婁紶鎴愬姛鍚庝繚瀛樺叧鑱�
-const uploadedBlobIds = ref([])
-
-const handleUploadSuccess = (response, file) => {
-  if (response.code === 200) {
-    uploadedBlobIds.value.push(response.data.id)
-  }
-}
-
-// 淇濆瓨鏂囦欢鍏宠仈
-const saveFiles = async () => {
-  await saveKnowledgeBaseFiles({
-    knowledgeBaseId: props.knowledgeBaseId,
-    storageBlobIds: uploadedBlobIds.value
-  })
-  // 鍒锋柊鏂囦欢鍒楄〃
-  loadFileList()
-}
-
-// 鐘舵�佹枃鏈槧灏�
-const getStatusText = (status) => {
-  const map = {
-    0: '寰呭鐞�',
-    1: '澶勭悊涓�',
-    2: '宸插畬鎴�',
-    3: '澶辫触'
-  }
-  return map[status] || '鏈煡'
-}
-
-const getStatusType = (status) => {
-  const map = {
-    0: 'info',
-    1: 'warning',
-    2: 'success',
-    3: 'danger'
-  }
-  return map[status] || 'info'
-}
-</script>
-```
-
-### 5.3 鐭ヨ瘑搴撻棶绛旂晫闈�
-
-```vue
-<template>
-  <div class="knowledge-chat">
-    <!-- 鐭ヨ瘑搴撻�夋嫨 -->
-    <el-select v-model="selectedKbId" placeholder="閫夋嫨鐭ヨ瘑搴�">
-      <el-option
-        v-for="kb in knowledgeBases"
-        :key="kb.id"
-        :label="kb.title"
-        :value="kb.id"
-      />
-    </el-select>
-
-    <!-- 瀵硅瘽鍖哄煙 -->
-    <div class="chat-messages">
-      <div
-        v-for="(msg, index) in messages"
-        :key="index"
-        :class="['message', msg.role]"
-      >
-        <div class="content">{{ msg.content }}</div>
-      </div>
-    </div>
-
-    <!-- 杈撳叆妗� -->
-    <el-input
-      v-model="inputQuestion"
-      placeholder="璇疯緭鍏ラ棶棰�"
-      @keyup.enter="sendMessage"
-    >
-      <template #append>
-        <el-button @click="sendMessage" :loading="loading">鍙戦��</el-button>
-      </template>
-    </el-input>
-  </div>
-</template>
-
-<script setup>
-import { ref, onMounted } from 'vue'
-import { getKnowledgeBaseList, knowledgeChat } from '@/api/knowledge'
-
-const knowledgeBases = ref([])
-const selectedKbId = ref(null)
-const messages = ref([])
-const inputQuestion = ref('')
-const loading = ref(false)
-const memoryId = ref(crypto.randomUUID())
-
-const sendMessage = async () => {
-  if (!inputQuestion.value.trim()) return
-  if (!selectedKbId.value) {
-    ElMessage.warning('璇烽�夋嫨鐭ヨ瘑搴�')
-    return
-  }
-
-  // 娣诲姞鐢ㄦ埛娑堟伅
-  messages.value.push({
-    role: 'user',
-    content: inputQuestion.value
-  })
-
-  loading.value = true
-
-  try {
-    // 娴佸紡璇锋眰
-    const response = await fetch('/api/ai/knowledge/chat', {
-      method: 'POST',
-      headers: { 'Content-Type': 'application/json' },
-      body: JSON.stringify({
-        knowledgeBaseId: selectedKbId.value,
-        memoryId: memoryId.value,
-        question: inputQuestion.value
-      })
-    })
-
-    // 澶勭悊SSE娴佸紡鍝嶅簲
-    const reader = response.body.getReader()
-    const decoder = new TextDecoder()
-    let aiContent = ''
-
-    messages.value.push({ role: 'assistant', content: '' })
-
-    while (true) {
-      const { done, value } = await reader.read()
-      if (done) break
-
-      const text = decoder.decode(value)
-      aiContent += text
-      messages.value[messages.value.length - 1].content = aiContent
-    }
-  } finally {
-    loading.value = false
-    inputQuestion.value = ''
-  }
-}
-
-onMounted(async () => {
-  const res = await getKnowledgeBaseList()
-  knowledgeBases.value = res.data
-})
-</script>
-```
-
-### 5.4 API灏佽
-
-```javascript
-// api/knowledge.js
-import request from '@/utils/request'
-
-// 鑾峰彇鐭ヨ瘑搴撳垪琛�
-export function getKnowledgeBaseList(params) {
-  return request({
-    url: '/knowledgeBase/getList',
-    method: 'get',
-    params
-  })
-}
-
-// 鏂板鐭ヨ瘑搴�
-export function addKnowledgeBase(data) {
-  return request({
-    url: '/knowledgeBase/add',
-    method: 'post',
-    data
-  })
-}
-
-// 鏇存柊鐭ヨ瘑搴�
-export function updateKnowledgeBase(data) {
-  return request({
-    url: '/knowledgeBase/update',
-    method: 'post',
-    data
-  })
-}
-
-// 鍒犻櫎鐭ヨ瘑搴�
-export function deleteKnowledgeBase(ids) {
-  return request({
-    url: '/knowledgeBase/delete',
-    method: 'delete',
-    data: ids
-  })
-}
-
-// 鑾峰彇鏂囦欢鍚戦噺鍖栫姸鎬�
-export function getVectorStatus(knowledgeBaseId) {
-  return request({
-    url: `/knowledgeBase/vector/status/${knowledgeBaseId}`,
-    method: 'get'
-  })
-}
-
-// 閲嶆柊鍚戦噺鍖�
-export function reprocessVector(vectorId) {
-  return request({
-    url: `/knowledgeBase/vector/reprocess/${vectorId}`,
-    method: 'post'
-  })
-}
-
-// 淇濆瓨鏂囦欢鍏宠仈
-export function saveKnowledgeBaseFiles(data) {
-  return request({
-    url: '/knowledgeBase/file/save',
-    method: 'post',
-    data
-  })
-}
-
-// 鍒犻櫎鏂囦欢
-export function deleteKnowledgeBaseFiles(vectorIds) {
-  return request({
-    url: '/knowledgeBase/file/delete',
-    method: 'delete',
-    data: vectorIds
-  })
-}
-
-// 鐭ヨ瘑搴撻棶绛旓紙娴佸紡锛�
-export async function knowledgeChat(data) {
-  const response = await fetch('/api/ai/knowledge/chat', {
-    method: 'POST',
-    headers: { 'Content-Type': 'application/json' },
-    body: JSON.stringify(data)
-  })
-  return response.body
-}
-
-// 鑾峰彇鐭ヨ瘑搴撳垪琛紙闂瓟鐢級
-export function getKnowledgeBaseListForChat() {
-  return request({
-    url: '/ai/knowledge/list',
-    method: 'get'
-  })
-}
-```
-
----
-
-## 鍏�佹牳蹇冩祦绋�
-
-### 6.1 鏂囦欢涓婁紶涓庡悜閲忓寲娴佺▼
-
-```
-1. 鍓嶇璋冪敤 /common/upload 涓婁紶鏂囦欢 鈫� 杩斿洖 storageBlobId
-2. 鍓嶇璋冪敤 /knowledgeBase/file/save 鍏宠仈鏂囦欢鍒扮煡璇嗗簱
-3. 鍚庣鍒涘缓 KnowledgeBaseVector 璁板綍锛堢姸鎬侊細寰呭鐞嗭級
-4. 鍚庣寮傛璋冪敤 KnowledgeRagService.processVectorAsync()
-   鈹溾攢鈹� 鏇存柊鐘舵�佷负"澶勭悊涓�"
-   鈹溾攢鈹� 鎻愬彇鏂囦欢鍐呭锛堟敮鎸佸绉嶆牸寮忥級
-   鈹溾攢鈹� 鑷姩妫�娴嬫枃浠剁紪鐮侊紙UTF-8/GBK锛�
-   鈹溾攢鈹� 鏂囨湰鍒囩墖锛堝ぇ鏂囦欢鎴栭暱鍐呭鎵嶅垏鐗囷級
-   鈹溾攢鈹� 鐢熸垚 Embedding 鍚戦噺
-   鈹溾攢鈹� 瀛樺偍鍒� Pinecone
-   鈹斺攢鈹� 鏇存柊鐘舵�佷负"瀹屾垚"鎴�"澶辫触"
-```
-
-### 6.2 鐭ヨ瘑搴撻棶绛旀祦绋�
-
-```
-1. 鐢ㄦ埛閫夋嫨鐭ヨ瘑搴擄紝杈撳叆闂
-2. 鍓嶇璋冪敤 /ai/knowledge/chat锛堟祦寮忔帴鍙o級
-3. 鍚庣澶勭悊锛�
-   鈹溾攢鈹� 鏋勫缓鍛藉悕绌洪棿锛歬b-{knowledgeBaseId}
-   鈹溾攢鈹� 璋冪敤 Embedding 妯″瀷鐢熸垚闂鍚戦噺
-   鈹溾攢鈹� 浠� Pinecone 妫�绱㈢浉鍏冲唴瀹癸紙minScore=0.7, maxResults=5锛�
-   鈹溾攢鈹� 鏋勫缓涓婁笅鏂� Prompt
-   鈹溾攢鈹� 璋冪敤 LLM 鐢熸垚鍥炵瓟
-   鈹斺攢鈹� 娴佸紡杩斿洖缁撴灉
-```
-
----
-
-## 涓冦�佹敞鎰忎簨椤�
-
-1. **Pinecone 鍛藉悕绌洪棿**锛氫笉鑳戒娇鐢� `__default__`锛屽繀椤讳娇鐢ㄨ嚜瀹氫箟鍛藉悕绌洪棿
-2. **鏂囦欢缂栫爜**锛氳嚜鍔ㄦ娴� UTF-8/GBK锛岄伩鍏嶄贡鐮�
-3. **鍒囩墖绛栫暐**锛�
-   - 鏂囦欢 > 80MB 鎴栧唴瀹� > 8000 瀛楃鏃舵墠鍒囩墖
-   - 鍒囩墖澶у皬 500 瀛楃锛岄噸鍙� 100 瀛楃
-   - 浼樺厛鍦ㄥ彞瀛愯竟鐣屽垏鍒�
-4. **Embedding 闄愬埗**锛氶樋閲屼簯 DashScope 闄愬埗鍗曟杈撳叆鏈�澶� 8192 瀛楃
-5. **鍚戦噺鍒犻櫎**锛氫娇鐢� Pinecone 鍘熺敓瀹㈡埛绔紝閫氳繃 metadata filter 鍒犻櫎
-6. **寮傛澶勭悊**锛氬悜閲忓寲浣跨敤 `@Async` 寮傛鎵ц锛岄伩鍏嶉樆濉炴帴鍙�
-
----
-
-## 鍏�佹枃浠舵竻鍗�
-
-### 鍚庣鏂囦欢
-```
-src/main/java/com/ruoyi/
-鈹溾攢鈹� approve/
-鈹�   鈹溾攢鈹� controller/
-鈹�   鈹�   鈹斺攢鈹� KnowledgeBaseController.java
-鈹�   鈹溾攢鈹� pojo/
-鈹�   鈹�   鈹溾攢鈹� KnowledgeBase.java
-鈹�   鈹�   鈹斺攢鈹� KnowledgeBaseVector.java
-鈹�   鈹溾攢鈹� service/
-鈹�   鈹�   鈹溾攢鈹� KnowledgeBaseService.java
-鈹�   鈹�   鈹溾攢鈹� KnowledgeBaseVectorService.java
-鈹�   鈹�   鈹斺攢鈹� impl/
-鈹�   鈹�       鈹溾攢鈹� KnowledgeBaseServiceImpl.java
-鈹�   鈹�       鈹斺攢鈹� KnowledgeBaseVectorServiceImpl.java
-鈹�   鈹溾攢鈹� mapper/
-鈹�   鈹�   鈹溾攢鈹� KnowledgeBaseMapper.java
-鈹�   鈹�   鈹斺攢鈹� KnowledgeBaseVectorMapper.java
-鈹�   鈹斺攢鈹� dto/
-鈹�       鈹斺攢鈹� KnowledgeBaseVectorVO.java
-鈹斺攢鈹� ai/
-    鈹溾攢鈹� config/
-    鈹�   鈹溾攢鈹� EmbeddingStoreConfig.java
-    鈹�   鈹斺攢鈹� XiaozhiAgentConfig.java
-    鈹溾攢鈹� controller/
-    鈹�   鈹斺攢鈹� KnowledgeChatController.java
-    鈹溾攢鈹� assistant/
-    鈹�   鈹斺攢鈹� KnowledgeChatAgent.java
-    鈹溾攢鈹� service/
-    鈹�   鈹溾攢鈹� KnowledgeRagService.java
-    鈹�   鈹斺攢鈹� impl/
-    鈹�       鈹斺攢鈹� KnowledgeRagServiceImpl.java
-    鈹斺攢鈹� dto/
-        鈹斺攢鈹� KnowledgeChatRequest.java
-```
-
-### 鍓嶇鏂囦欢
-```
-src/views/knowledge/
-鈹溾攢鈹� index.vue              # 鐭ヨ瘑搴撳垪琛�
-鈹溾攢鈹� form.vue               # 鏂板/缂栬緫琛ㄥ崟
-鈹溾攢鈹� files.vue              # 鏂囦欢绠$悊
-鈹斺攢鈹� chat.vue               # 鐭ヨ瘑搴撻棶绛�
-
-src/api/knowledge.js       # API灏佽
-```
\ No newline at end of file
diff --git a/docs/mock_data_check.md b/docs/mock_data_check.md
deleted file mode 100644
index 8c67159..0000000
--- a/docs/mock_data_check.md
+++ /dev/null
@@ -1,183 +0,0 @@
-# 鏁版嵁妯℃嫙 - 鍩虹鏁版嵁妫�娴�
-
-## 娑夊強椤甸潰
-
-- 鏁版嵁妯℃嫙鎿嶄綔椤甸潰锛堟柊澧烇級
-
-## API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| POST | /mock/dataCheck | 妫�娴嬫寚瀹氭ā鍧楃殑鍩虹鏁版嵁鏄惁灏辩华 |
-
-**璇锋眰鍙傛暟锛�**
-
-| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
-|------|------|------|------|
-| modules | List\<String\> | 鏄� | 瑕佹娴嬬殑妯″潡鍒楄〃锛屽彲閫夊�硷細sales锛堥攢鍞級銆乸urchase锛堥噰璐級銆乹uality锛堣川閲忥級銆乸roduction锛堢敓浜э級 |
-
-璇锋眰浣撶ず渚嬶細
-```json
-{ "modules": ["sales", "purchase", "quality", "production"] }
-```
-
-**鍝嶅簲锛�**
-```json
-{
-  "code": 200,
-  "msg": "鎿嶄綔鎴愬姛",
-  "data": {
-    "totalItems": 6,
-    "passedItems": 3,
-    "items": [
-      {
-        "module": "common",
-        "itemName": "浜у搧鏁版嵁",
-        "minRequired": 1,
-        "currentCount": 5,
-        "passed": true,
-        "message": "閫氳繃"
-      },
-      {
-        "module": "sales",
-        "itemName": "瀹㈡埛鏁版嵁",
-        "minRequired": 1,
-        "currentCount": 0,
-        "passed": false,
-        "message": "缂哄皯瀹㈡埛鏁版嵁锛岃鍏堝湪銆愬熀纭�鏁版嵁-瀹㈡埛绠$悊銆戜腑娣诲姞鑷冲皯1鏉″鎴�"
-      }
-    ]
-  }
-}
-```
-
-## 妫�娴嬭鍒�
-
-### 閿�鍞ā鍧� (sales)
-| 妫�娴嬮」 | 鏈�浣庢暟閲� | 鏈�氳繃鎻愮ず |
-|--------|----------|------------|
-| 浜у搧鏁版嵁 | 1 | 缂哄皯浜у搧鏁版嵁锛岃鍏堝湪銆愬熀纭�鏁版嵁-浜у搧绠$悊銆戜腑娣诲姞鑷冲皯1鏉′骇鍝� |
-| 瀹㈡埛鏁版嵁 | 1 | 缂哄皯瀹㈡埛鏁版嵁锛岃鍏堝湪銆愬熀纭�鏁版嵁-瀹㈡埛绠$悊銆戜腑娣诲姞鑷冲皯1鏉″鎴� |
-| 鎶ヤ环瀹℃壒妯℃澘 | 1 | 缂哄皯鎶ヤ环瀹℃壒妯℃澘锛岃鍏堝湪銆愮郴缁熺鐞�-瀹℃壒妯℃澘銆戜腑鍒涘缓鎶ヤ环瀹℃壒妯℃澘 |
-| 鍙戣揣瀹℃壒妯℃澘 | 1 | 缂哄皯鍙戣揣瀹℃壒妯℃澘锛岃鍏堝湪銆愮郴缁熺鐞�-瀹℃壒妯℃澘銆戜腑鍒涘缓鍙戣揣瀹℃壒妯℃澘 |
-
-### 閲囪喘妯″潡 (purchase)
-| 妫�娴嬮」 | 鏈�浣庢暟閲� | 鏈�氳繃鎻愮ず |
-|--------|----------|------------|
-| 浜у搧鏁版嵁 | 1 | 缂哄皯浜у搧鏁版嵁锛岃鍏堝湪銆愬熀纭�鏁版嵁-浜у搧绠$悊銆戜腑娣诲姞鑷冲皯1鏉′骇鍝� |
-| 渚涘簲鍟嗘暟鎹� | 1 | 缂哄皯渚涘簲鍟嗘暟鎹紝璇峰厛鍦ㄣ�愬熀纭�鏁版嵁-渚涘簲鍟嗙鐞嗐�戜腑娣诲姞鑷冲皯1鏉′緵搴斿晢 |
-| 閲囪喘瀹℃壒妯℃澘 | 1 | 缂哄皯閲囪喘瀹℃壒妯℃澘锛岃鍏堝湪銆愮郴缁熺鐞�-瀹℃壒妯℃澘銆戜腑鍒涘缓閲囪喘瀹℃壒妯℃澘 |
-
-### 鐢熶骇妯″潡 (production)
-| 妫�娴嬮」 | 鏈�浣庢暟閲� | 鏈�氳繃鎻愮ず |
-|--------|----------|------------|
-| 浜у搧鏁版嵁 | 1 | 缂哄皯浜у搧鏁版嵁锛岃鍏堝湪銆愬熀纭�鏁版嵁-浜у搧绠$悊銆戜腑娣诲姞鑷冲皯1鏉′骇鍝� |
-| 浜у搧瑙勬牸 | 1 | 缂哄皯浜у搧瑙勬牸锛岃鍏堝湪銆愬熀纭�鏁版嵁-浜у搧绠$悊銆戜腑涓轰骇鍝佹坊鍔犺鏍煎瀷鍙� |
-| 宸ュ簭 | 1 | 缂哄皯宸ュ簭锛岃鍏堝湪銆愬伐鑹鸿璁�-宸ュ簭绠$悊銆戜腑鍒涘缓宸ュ簭 |
-| BOM | 1 | 缂哄皯BOM锛岃鍏堝湪銆愬伐鑹鸿璁�-BOM绠$悊銆戜腑鍒涘缓BOM |
-| BOM浜у搧缁撴瀯 | 1 | 缂哄皯BOM浜у搧缁撴瀯锛岃鍏堝湪銆愬伐鑹鸿璁�-BOM绠$悊銆戜腑涓築OM娣诲姞浜у搧缁撴瀯鑺傜偣 |
-| 宸ヨ壓璺嚎 | 1 | 缂哄皯宸ヨ壓璺嚎锛岃鍏堝湪銆愬伐鑹鸿璁�-宸ヨ壓璺嚎銆戜腑鍒涘缓宸ヨ壓璺嚎 |
-| 宸ヨ壓璺嚎宸ュ簭 | 1 | 缂哄皯宸ヨ壓璺嚎宸ュ簭锛岃鍏堝湪銆愬伐鑹鸿璁�-宸ヨ壓璺嚎銆戜腑涓哄伐鑹鸿矾绾挎坊鍔犲伐搴� |
-| 浜у搧-宸ヨ壓璺嚎鍏宠仈 | 鈮�1 | 閮ㄥ垎浜у搧瑙勬牸鏈叧鑱斿伐鑹鸿矾绾匡紝璇峰厛鍦ㄣ�愬伐鑹鸿璁�-宸ヨ壓璺嚎銆戜腑涓轰骇鍝佽鏍煎垱寤哄伐鑹鸿矾绾� |
-| 宸ヨ壓璺嚎-宸ュ簭鍏宠仈 | 鈮�1 | 閮ㄥ垎宸ヨ壓璺嚎鏈坊鍔犲伐搴忥紝璇峰厛鍦ㄣ�愬伐鑹鸿璁�-宸ヨ壓璺嚎銆戜腑涓哄伐鑹鸿矾绾挎坊鍔犲伐搴� |
-| BOM-浜у搧缁撴瀯鍏宠仈 | 鈮�1 | 閮ㄥ垎BOM鏈坊鍔犱骇鍝佺粨鏋勶紝璇峰厛鍦ㄣ�愬伐鑹鸿璁�-BOM绠$悊銆戜腑涓築OM娣诲姞浜у搧缁撴瀯鑺傜偣 |
-
-### 璐ㄩ噺妯″潡 (quality)
-| 妫�娴嬮」 | 鏈�浣庢暟閲� | 鏈�氳繃鎻愮ず |
-|--------|----------|------------|
-| 浜у搧鏁版嵁 | 1 | 缂哄皯浜у搧鏁版嵁锛岃鍏堝湪銆愬熀纭�鏁版嵁-浜у搧绠$悊銆戜腑娣诲姞鑷冲皯1鏉′骇鍝� |
-| 妫�娴嬫爣鍑� | 1 | 缂哄皯妫�娴嬫爣鍑嗭紝璇峰厛鍦ㄣ�愯川閲忕鐞�-妫�娴嬫爣鍑嗐�戜腑鍒涘缓妫�娴嬫爣鍑� |
-| 鎸囨爣缁戝畾 | 1 | 缂哄皯鎸囨爣缁戝畾锛岃鍏堝湪銆愯川閲忕鐞�-妫�娴嬫爣鍑嗙粦瀹氥�戜腑灏嗘娴嬫爣鍑嗕笌浜у搧缁戝畾 |
-
-## 鍓嶇淇敼鐐�
-
-### 1. 鏁版嵁妯℃嫙椤甸潰鍏ュ彛
-
-鍦ㄥ乏渚ц彍鍗曟柊澧�"鏁版嵁妯℃嫙"鑿滃崟椤癸紝璺敱 `/mock`銆�
-
-### 2. 鏁版嵁妫�娴嬪尯鍩�
-
-```html
-<template>
-  <div class="mock-container">
-    <el-card header="鍩虹鏁版嵁妫�娴�">
-      <el-checkbox-group v-model="selectedModules">
-        <el-checkbox label="sales">閿�鍞ā鍧�</el-checkbox>
-        <el-checkbox label="purchase">閲囪喘妯″潡</el-checkbox>
-        <el-checkbox label="quality">璐ㄩ噺妯″潡</el-checkbox>
-        <el-checkbox label="production">鐢熶骇妯″潡</el-checkbox>
-      </el-checkbox-group>
-      <el-button type="primary" @click="handleCheck" :loading="checking">
-        寮�濮嬫娴�
-      </el-button>
-    </el-card>
-
-    <el-card v-if="checkResult" header="妫�娴嬬粨鏋�" style="margin-top: 16px">
-      <el-alert
-        :title="`閫氳繃 ${checkResult.passedItems} / ${checkResult.totalItems} 椤筦"
-        :type="checkResult.passedItems === checkResult.totalItems ? 'success' : 'warning'"
-        :closable="false"
-        show-icon
-      />
-      <el-table :data="checkResult.items" style="margin-top: 12px">
-        <el-table-column prop="module" label="妯″潡" width="100" />
-        <el-table-column prop="itemName" label="妫�娴嬮」" width="160" />
-        <el-table-column prop="minRequired" label="鏈�浣庤姹�" width="80" />
-        <el-table-column prop="currentCount" label="褰撳墠鏁伴噺" width="80" />
-        <el-table-column label="鐘舵��" width="80">
-          <template #default="{ row }">
-            <el-tag :type="row.passed ? 'success' : 'danger'">
-              {{ row.passed ? '閫氳繃' : '鏈�氳繃' }}
-            </el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column prop="message" label="鎻愮ず" />
-      </el-table>
-    </el-card>
-  </div>
-</template>
-```
-
-### 3. data 鏁版嵁
-
-```js
-data() {
-  return {
-    selectedModules: ['sales', 'purchase', 'quality', 'production'],
-    checking: false,
-    checkResult: null,
-  }
-}
-```
-
-### 4. 鏂规硶
-
-```js
-import request from '@/utils/request'
-
-methods: {
-  async handleCheck() {
-    if (this.selectedModules.length === 0) {
-      this.$message.warning('璇疯嚦灏戦�夋嫨涓�涓ā鍧�')
-      return
-    }
-    this.checking = true
-    try {
-      const res = await request.post('/mock/dataCheck', {
-        modules: this.selectedModules
-      })
-      this.checkResult = res.data
-    } finally {
-      this.checking = false
-    }
-  }
-}
-```
-
-## 娉ㄦ剰浜嬮」
-
-- 浜у搧鏁版嵁锛堝叕鍏卞熀纭�锛夊湪澶氫釜妯″潡闂村叡浜紝妫�娴嬬粨鏋滀腑鍙嚭鐜颁竴娆★紝涓嶄細閲嶅灞曠ず
-- 妫�娴嬩粎鍋氬彧璇绘煡璇紝涓嶅啓鍏ヤ换浣曟暟鎹�
-- 妯″潡鍙傛暟涓虹┖鏁扮粍鏃惰繑鍥炵┖妫�娴嬪垪琛�
-- 寤鸿鍦ㄦ暟鎹ā鎷熷紑濮嬪墠鍏堣皟鐢ㄦ鎺ュ彛纭鍩虹鏁版嵁灏辩华
-- 鐢熶骇妯″潡闄や簡妫�娴嬫暟鎹噺锛岃繕浼氭娴嬪叧鑱旀�э紙浜у搧-宸ヨ壓璺嚎銆佸伐鑹鸿矾绾�-宸ュ簭銆丅OM-浜у搧缁撴瀯锛夛紝纭繚宸ヨ壓璁捐鏁版嵁瀹屾暣
diff --git a/docs/mock_data_generate.md b/docs/mock_data_generate.md
deleted file mode 100644
index 6dc801e..0000000
--- a/docs/mock_data_generate.md
+++ /dev/null
@@ -1,243 +0,0 @@
-# 鏁版嵁妯℃嫙 - AI 鏁版嵁鐢熸垚
-
-## 娑夊強椤甸潰
-
-- 鏁版嵁妯℃嫙鎿嶄綔椤甸潰锛堟柊澧�/淇敼锛�
-
-## API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| POST | /mock/generate | AI 鐢熸垚妯℃嫙鏁版嵁锛堝惈鍓嶇疆鍩虹鏁版嵁妫�娴嬶級 |
-
-**璇锋眰鍙傛暟锛�**
-
-| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
-|------|------|------|------|
-| modules | List\<String\> | 鏄� | 瑕佺敓鎴愭暟鎹殑妯″潡锛歴ales锛堥攢鍞級銆乸urchase锛堥噰璐級銆乹uality锛堣川閲忥級銆乸roduction锛堢敓浜э級銆乻tock锛堝簱瀛橈級 |
-| industries | List\<String\> | 鏄� | 琛屼笟锛屽锛歔"鏈烘鍒堕��", "椋熷搧鍔犲伐", "鐢靛瓙瑁呴厤"] |
-| countMin | int | 鍚� | 姣忎釜瀹炰綋鐢熸垚鏉℃暟鏈�灏忓�硷紝榛樿 3 |
-| countMax | int | 鍚� | 姣忎釜瀹炰綋鐢熸垚鏉℃暟鏈�澶у�硷紝榛樿 10 |
-| dateStart | String | 鍚� | 鏃堕棿鑼冨洿寮�濮嬶紙yyyy-MM-dd锛� |
-| dateEnd | String | 鍚� | 鏃堕棿鑼冨洿缁撴潫锛坹yyy-MM-dd锛� |
-| additionalInfo | String | 鍚� | 鍏朵粬琛ュ厖鎻忚堪锛屽"浜у搧浠ラ噾灞為浂閮ㄤ欢涓轰富" |
-
-璇锋眰浣撶ず渚嬶細
-```json
-{
-  "modules": ["sales", "purchase", "quality"],
-  "industries": ["鏈烘鍒堕��", "鐢靛瓙瑁呴厤"],
-  "countMin": 3,
-  "countMax": 8,
-  "dateStart": "2026-01-01",
-  "dateEnd": "2026-06-01",
-  "additionalInfo": "浜у搧浠ラ噾灞為浂閮ㄤ欢鍜岀數瀛愬厓鍣ㄤ欢涓轰富"
-}
-```
-
-**鍝嶅簲锛堟垚鍔燂級锛�**
-```json
-{
-  "code": 200,
-  "msg": "鎿嶄綔鎴愬姛",
-  "data": {
-    "status": "SUCCESS",
-    "totalGenerated": 24,
-    "moduleSummaries": [
-      { "module": "sales", "entityName": "瀹㈡埛", "generatedCount": 5, "successCount": 5, "failCount": 0 },
-      { "module": "sales", "entityName": "閿�鍞彴璐�", "generatedCount": 5, "successCount": 5, "failCount": 0 },
-      { "module": "purchase", "entityName": "渚涘簲鍟�", "generatedCount": 4, "successCount": 4, "failCount": 0 },
-      { "module": "purchase", "entityName": "閲囪喘鍙拌处", "generatedCount": 4, "successCount": 4, "failCount": 0 },
-      { "module": "quality", "entityName": "妫�娴嬫爣鍑�", "generatedCount": 3, "successCount": 3, "failCount": 0 },
-      { "module": "quality", "entityName": "鎸囨爣缁戝畾", "generatedCount": 3, "successCount": 3, "failCount": 0 }
-    ],
-    "errors": [],
-    "checkResult": null
-  }
-}
-```
-
-**鍝嶅簲锛堝熀纭�鏁版嵁涓嶈冻锛屽墠缃娴嬫湭閫氳繃锛夛細**
-```json
-{
-  "code": 500,
-  "msg": "鍩虹鏁版嵁涓嶈冻锛岃鍏堣ˉ鍏呭悗鍐嶇敓鎴�",
-  "data": {
-    "status": "CHECK_FAILED",
-    "checkResult": {
-      "totalItems": 6,
-      "passedItems": 3,
-      "items": [
-        { "module": "common", "itemName": "浜у搧鏁版嵁", "passed": true, "message": "閫氳繃" },
-        { "module": "sales", "itemName": "瀹㈡埛鏁版嵁", "passed": false, "message": "缂哄皯瀹㈡埛鏁版嵁锛岃鍏�..." }
-      ]
-    }
-  }
-}
-```
-
-## 宸ヤ綔娴佺▼
-
-1. 鐢ㄦ埛鍦ㄩ〉闈㈤�夋嫨妯″潡 + 濉啓琛屼笟/鏁伴噺/鏃堕棿绛変俊鎭�
-2. 璋冪敤 `POST /mock/generate`
-3. 鍚庣棣栧厛璋冪敤 `POST /mock/dataCheck` 妫�娴嬪熀纭�鏁版嵁鏄惁灏辩华
-4. 鑻ュ熀纭�鏁版嵁涓嶈冻锛岃繑鍥炴娴嬬粨鏋滐紝鎻愮ず鐢ㄦ埛鍏堣ˉ榻�
-5. 鑻ュ熀纭�鏁版嵁灏辩华锛岃皟鐢� AI 澶фā鍨嬬敓鎴愮鍚堣涓氱壒寰佺殑 JSON 鏁版嵁
-6. 鎸変緷璧栭『搴忓垱寤烘暟鎹紙瀹㈡埛鈫掗攢鍞彴璐︺�佷緵搴斿晢鈫掗噰璐彴璐︺�佹娴嬫爣鍑嗏啋鎸囨爣缁戝畾...锛�
-7. 杩斿洖鐢熸垚鎽樿
-
-## 鍓嶇淇敼鐐�
-
-### 1. 鏁版嵁鐢熸垚鍖哄煙锛堝湪鏁版嵁妫�娴嬪尯鍩熶笅鏂癸級
-
-```html
-<el-card header="AI 鏁版嵁鐢熸垚" style="margin-top: 16px">
-  <el-form :model="generateForm" label-width="100px">
-    <el-form-item label="閫夋嫨妯″潡">
-      <el-checkbox-group v-model="generateForm.modules">
-        <el-checkbox label="sales">閿�鍞�</el-checkbox>
-        <el-checkbox label="purchase">閲囪喘</el-checkbox>
-        <el-checkbox label="quality">璐ㄩ噺</el-checkbox>
-        <el-checkbox label="production">鐢熶骇</el-checkbox>
-        <el-checkbox label="stock">搴撳瓨</el-checkbox>
-      </el-checkbox-group>
-    </el-form-item>
-
-    <el-form-item label="琛屼笟">
-      <el-select
-        v-model="generateForm.industries"
-        multiple
-        filterable
-        allow-create
-        placeholder="杈撳叆鎴栭�夋嫨琛屼笟"
-      >
-        <el-option label="鏈烘鍒堕��" value="鏈烘鍒堕��" />
-        <el-option label="椋熷搧鍔犲伐" value="椋熷搧鍔犲伐" />
-        <el-option label="鐢靛瓙瑁呴厤" value="鐢靛瓙瑁呴厤" />
-        <el-option label="姹借溅闆堕儴浠�" value="姹借溅闆堕儴浠�" />
-        <el-option label="鍖荤枟鍣ㄦ" value="鍖荤枟鍣ㄦ" />
-        <el-option label="鍖栧伐鏉愭枡" value="鍖栧伐鏉愭枡" />
-        <el-option label="绾虹粐鏈嶈" value="绾虹粐鏈嶈" />
-        <el-option label="瀹跺叿鍒堕��" value="瀹跺叿鍒堕��" />
-      </el-select>
-    </el-form-item>
-
-    <el-row :gutter="16">
-      <el-col :span="12">
-        <el-form-item label="鐢熸垚鏉℃暟">
-          <el-slider
-            v-model="generateForm.countRange"
-            range
-            :min="1"
-            :max="50"
-            :marks="{1:'1', 10:'10', 20:'20', 50:'50'}"
-          />
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="鏃堕棿鑼冨洿">
-          <el-date-picker
-            v-model="generateForm.dateRange"
-            type="daterange"
-            range-separator="鑷�"
-            start-placeholder="寮�濮嬫棩鏈�"
-            end-placeholder="缁撴潫鏃ユ湡"
-            value-format="yyyy-MM-dd"
-          />
-        </el-form-item>
-      </el-col>
-    </el-row>
-
-    <el-form-item label="琛ュ厖淇℃伅">
-      <el-input
-        v-model="generateForm.additionalInfo"
-        type="textarea"
-        :rows="2"
-        placeholder="濡傦細浜у搧浠ラ噾灞為浂閮ㄤ欢涓轰富锛屽鎴烽泦涓湪鍗庝笢鍦板尯"
-      />
-    </el-form-item>
-
-    <el-form-item>
-      <el-button type="primary" @click="handleGenerate" :loading="generating">
-        寮�濮嬬敓鎴�
-      </el-button>
-      <el-button @click="handleCheckFirst" :loading="checking">
-        鍏堟娴嬪啀鐢熸垚
-      </el-button>
-    </el-form-item>
-  </el-form>
-</el-card>
-```
-
-### 3. data 鏁版嵁
-
-```js
-data() {
-  return {
-    generateForm: {
-      modules: [],
-      industries: [],
-      countRange: [3, 10],
-      dateRange: [],
-      additionalInfo: '',
-    },
-    generating: false,
-    generateResult: null,
-  }
-}
-```
-
-### 4. 鏂规硶
-
-```js
-methods: {
-  // 鐩存帴鐢熸垚锛堝唴閮ㄨ嚜鍔ㄦ娴嬶級
-  async handleGenerate() {
-    if (this.generateForm.modules.length === 0) {
-      this.$message.warning('璇疯嚦灏戦�夋嫨涓�涓ā鍧�')
-      return
-    }
-    this.generating = true
-    try {
-      const res = await request.post('/mock/generate', {
-        modules: this.generateForm.modules,
-        industries: this.generateForm.industries,
-        countMin: this.generateForm.countRange[0],
-        countMax: this.generateForm.countRange[1],
-        dateStart: this.generateForm.dateRange[0] || null,
-        dateEnd: this.generateForm.dateRange[1] || null,
-        additionalInfo: this.generateForm.additionalInfo,
-      })
-      if (res.code === 200) {
-        this.generateResult = res.data
-        this.$message.success(`鎴愬姛鐢熸垚 ${res.data.totalGenerated} 鏉℃暟鎹甡)
-      } else {
-        // 鍩虹鏁版嵁涓嶈冻
-        this.generateResult = res.data
-        this.checkResult = res.data.checkResult
-        this.$message.warning(res.msg)
-      }
-    } finally {
-      this.generating = false
-    }
-  },
-
-  // 鍏堟娴嬪啀鐢熸垚
-  async handleCheckFirst() {
-    await this.handleCheck()
-    if (this.checkResult && this.checkResult.passedItems === this.checkResult.totalItems) {
-      await this.handleGenerate()
-    } else {
-      this.$message.warning('璇峰厛琛ラ綈鍩虹鏁版嵁鍚庡啀鐢熸垚')
-    }
-  },
-}
-```
-
-## 娉ㄦ剰浜嬮」
-
-- `POST /mock/generate` 鍐呴儴浼氳嚜鍔ㄨ皟鐢ㄦ暟鎹娴嬶紝涓嶉渶瑕佹墜鍔ㄥ垎涓ゆ璧�
-- AI 鐢熸垚鐨勬暟鎹細灏介噺绗﹀悎琛屼笟鐗瑰緛锛屼絾寤鸿鐢熸垚鍚庢鏌ュ叧閿暟鎹殑鍚堢悊鎬�
-- 鐢熶骇妯″潡鍜屽簱瀛樻ā鍧椾緷璧栦骇鍝佹暟鎹紙Product/ProductModel锛夛紝璇风‘淇濆熀纭�鏁版嵁涓湁浜у搧
-- 閿�鍞彴璐︾殑鍚堝悓閲戦鐢变骇鍝佹槑缁嗚嚜鍔ㄨ绠楋紝AI 鍙渶鐢熸垚浜у搧琛岀殑鍗曚环鍜屾暟閲�
-- 浜х敓鐨勬暟鎹�氳繃鏈嶅姟灞傚垱寤猴紝浼氳嚜鍔ㄥ~鍏� tenantId/deptId/createUser 绛夊瓧娈�
diff --git a/docs/routing_operation_plan_person.md b/docs/routing_operation_plan_person.md
deleted file mode 100644
index 999d9a3..0000000
--- a/docs/routing_operation_plan_person.md
+++ /dev/null
@@ -1,91 +0,0 @@
-# 鐢熶骇宸ュ簭鏂板璁″垝浜哄憳鍜岃鍒掓墽琛屼汉鍛�
-
-## 娑夊強椤甸潰
-
-- 宸ヨ壓璺嚎宸ュ簭绠$悊椤甸潰锛坱echnology_routing_operation锛�
-
-## API
-
-娑夊強浠ヤ笅鎺ュ彛鐨勮姹�/鍝嶅簲鏂板瀛楁锛�
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| GET | /technologyRoutingOperation/page | 鍒嗛〉鏌ヨ |
-| GET | /technologyRoutingOperation/list | 鍒楄〃鏌ヨ |
-| GET | /technologyRoutingOperation/{id} | 璇︽儏 |
-| POST | /technologyRoutingOperation/add | 鏂板 |
-| PUT | /technologyRoutingOperation | 淇敼 |
-
-**鏂板鍝嶅簲/璇锋眰瀛楁锛�**
-
-| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
-|------|------|------|------|
-| planPerson | Long | 鍚� | 璁″垝浜哄憳ID |
-| executor | Long | 鍚� | 璁″垝鎵ц浜哄憳ID |
-| planPersonName | String | 鍚� | 璁″垝浜哄憳濮撳悕锛堝搷搴斿瓧娈碉紝鍚庣鑷姩鍏宠仈鏌ヨ锛� |
-| executorName | String | 鍚� | 璁″垝鎵ц浜哄憳濮撳悕锛堝搷搴斿瓧娈碉紝鍚庣鑷姩鍏宠仈鏌ヨ锛� |
-
-## 鍓嶇淇敼鐐�
-
-### 1. 琛ㄥ崟鏂板瀛楁
-
-鍦ㄥ伐搴忚〃鍗曚腑鏂板涓や釜浜哄憳閫夋嫨涓嬫媺妗嗭細
-
-```html
-<el-form-item label="璁″垝浜哄憳" prop="planPerson">
-  <el-select v-model="processForm.planPerson"
-             placeholder="璇烽�夋嫨璁″垝浜哄憳"
-             clearable
-             filterable
-             style="width: 100%">
-    <el-option v-for="item in employeeOptions"
-               :key="item.id"
-               :label="item.staffName"
-               :value="item.id" />
-  </el-select>
-</el-form-item>
-<el-form-item label="璁″垝鎵ц浜哄憳" prop="executor">
-  <el-select v-model="processForm.executor"
-             placeholder="璇烽�夋嫨璁″垝鎵ц浜哄憳"
-             clearable
-             filterable
-             style="width: 100%">
-    <el-option v-for="item in employeeOptions"
-               :key="item.id"
-               :label="item.staffName"
-               :value="item.id" />
-  </el-select>
-</el-form-item>
-```
-
-### 2. data 鏁版嵁
-
-```js
-data() {
-  return {
-    processForm: {
-      planPerson: null,
-      executor: null,
-      // ...鍏朵粬瀛楁
-    },
-    employeeOptions: [],  // 鍛樺伐鍒楄〃锛岄渶浠庢帴鍙h幏鍙�
-  }
-}
-```
-
-### 3. 琛ㄦ牸鍒楁柊澧�
-
-鍒楄〃涓彲鐩存帴浣跨敤鍚庣杩斿洖鐨勫鍚嶅睍绀猴細
-
-```html
-<el-table-column label="璁″垝浜哄憳" prop="planPersonName" />
-<el-table-column label="璁″垝鎵ц浜哄憳" prop="executorName" />
-```
-
-## 娉ㄦ剰浜嬮」
-
-- `planPerson` 鍜� `executor` 瀛樺偍鐨勬槸鍛樺伐ID锛圠ong绫诲瀷锛夛紝鎻愪氦琛ㄥ崟鏃朵紶ID
-- 鍝嶅簲涓� `planPersonName` 鍜� `executorName` 鐢卞悗绔�氳繃 `staff_on_job` 琛ㄨ嚜鍔ㄥ叧鑱旀煡璇紝鍓嶇鏃犻渶棰濆杞崲
-- 鍛樺伐涓嬫媺鍒楄〃鏁版嵁闇�浠庡憳宸ユ帴鍙h幏鍙栵紙鍙傝�冪幇鏈� `employeeOptions` 鏁版嵁婧愶級
-- 鏁版嵁搴撹縼绉籗QL锛歚doc/20260615_add_plan_person_and_executor_to_routing_operation.sql`
-- 鐢熶骇璁㈠崟宸ュ簭锛坄production_order_routing_operation`锛夊悓姝ユ敮鎸佽繖涓や釜瀛楁
diff --git a/sql/product-inventory-management-new-pro.sql b/sql/product-inventory-management-new-pro.sql
deleted file mode 100644
index 2752b38..0000000
--- a/sql/product-inventory-management-new-pro.sql
+++ /dev/null
@@ -1,5814 +0,0 @@
-/*
- Navicat Premium Dump SQL
-
- Source Server         : localhost
- Source Server Type    : MySQL
- Source Server Version : 80408 (8.4.8)
- Source Host           : localhost:3306
- Source Schema         : product-inventory-management-new-pro
-
- Target Server Type    : MySQL
- Target Server Version : 80408 (8.4.8)
- File Encoding         : 65001
-
- Date: 16/06/2026 10:13:25
-*/
-
-SET NAMES utf8mb4;
-SET FOREIGN_KEY_CHECKS = 0;
-
--- ----------------------------
--- Table structure for account_expense
--- ----------------------------
-DROP TABLE IF EXISTS `account_expense`;
-CREATE TABLE `account_expense`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `business_id` int NULL DEFAULT NULL COMMENT '涓氬姟id',
-  `business_type` int NULL DEFAULT NULL COMMENT '涓氬姟绫诲瀷 1-浠樻 2-杩樺�熸',
-  `expense_date` date NULL DEFAULT NULL COMMENT '鏀嚭鏃ユ湡',
-  `expense_type` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鏀嚭绫诲瀷',
-  `supplier_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉�',
-  `expense_money` decimal(18, 2) NULL DEFAULT NULL COMMENT '鏀嚭閲戦',
-  `expense_described` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鏀嚭鎻忚堪',
-  `expense_method` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '浠樻鏂瑰紡',
-  `invoice_number` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鍙戠エ鍙风爜',
-  `note` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `input_user` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '褰曞叆浜哄憳',
-  `input_time` date NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 100 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '璐㈠姟绠$悊--鏀嚭绠$悊' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for account_file
--- ----------------------------
-DROP TABLE IF EXISTS `account_file`;
-CREATE TABLE `account_file`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鏂囦欢鍚嶇О',
-  `url` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鏂囦欢璺緞',
-  `file_size` int NULL DEFAULT NULL COMMENT '鏂囦欢澶у皬',
-  `account_id` bigint NULL DEFAULT NULL COMMENT '璐㈠姟ID',
-  `account_type` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '绫诲瀷(鏀跺叆/鏀嚭)',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 272 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '璐㈠姟绠$悊--闄勪欢' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for account_income
--- ----------------------------
-DROP TABLE IF EXISTS `account_income`;
-CREATE TABLE `account_income`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `income_date` date NULL DEFAULT NULL COMMENT '鏀跺叆鏃ユ湡',
-  `income_type` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鏀跺叆绫诲瀷',
-  `customer_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '瀹㈡埛鍚嶇О',
-  `income_money` decimal(18, 2) NULL DEFAULT NULL COMMENT '鏀跺叆閲戦',
-  `income_described` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鏀跺叆鎻忚堪',
-  `income_method` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鏀舵鏂瑰紡',
-  `invoice_number` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鍙戠エ鍙风爜',
-  `note` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `input_user` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '褰曞叆浜哄憳',
-  `input_time` date NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `business_id` int NULL DEFAULT NULL COMMENT '涓氬姟id',
-  `business_type` int NULL DEFAULT NULL COMMENT '涓氬姟绫诲瀷 1-鍥炴 2-鍊熸',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 696 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '璐㈠姟绠$悊--鏀跺叆绠$悊' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for account_invoice_application
--- ----------------------------
-DROP TABLE IF EXISTS `account_invoice_application`;
-CREATE TABLE `account_invoice_application`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `customer_id` int NOT NULL COMMENT '瀹㈡埛id',
-  `stock_out_record_ids` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鍏宠仈鍑哄簱鍗昳d(澶氶��)',
-  `invoice_application_no` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '寮�绁ㄧ敵璇峰崟鍙�',
-  `invoice_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙戠エ绫诲瀷',
-  `apply_date` date NULL DEFAULT NULL COMMENT '鐢宠鏃ユ湡',
-  `invoice_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '鍙戠エ鍐呭',
-  `remark` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `status` int NULL DEFAULT 0 COMMENT '瀹℃牳鐘舵��:0寰呭鏍�1瀹℃牳閫氳繃2瀹℃牳涓嶉�氳繃',
-  `invoice_amount` decimal(18, 4) NULL DEFAULT NULL COMMENT '寮�绁ㄩ噾棰�',
-  `tax_rate` decimal(5, 0) NULL DEFAULT NULL COMMENT '绋庣巼',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '璐㈠姟绠$悊--寮�绁ㄧ敵璇�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for account_payment_application
--- ----------------------------
-DROP TABLE IF EXISTS `account_payment_application`;
-CREATE TABLE `account_payment_application`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `supplier_id` int NOT NULL COMMENT '渚涘簲鍟唅d',
-  `stock_in_record_ids` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '鍏宠仈鍏ュ簱鍗昳d(澶氶��)',
-  `invoice_application_no` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '浠樻鐢宠鍗曞彿',
-  `payment_method` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '浠樻鏂瑰紡',
-  `payment_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '浠樻浜嬬敱',
-  `apply_date` date NULL DEFAULT NULL COMMENT '鐢宠鏃ユ湡',
-  `remark` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `status` int NULL DEFAULT 0 COMMENT '瀹℃牳鐘舵��:0寰呭鏍�1瀹℃牳閫氳繃2瀹℃牳涓嶉�氳繃',
-  `payment_amount` decimal(15, 4) NULL DEFAULT NULL COMMENT '浠樻閲戦',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '璐㈠姟绠$悊--浠樻鐢宠' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for account_purchase_invoice
--- ----------------------------
-DROP TABLE IF EXISTS `account_purchase_invoice`;
-CREATE TABLE `account_purchase_invoice`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `invoice_number` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鍙戠エ鍙风爜',
-  `tax_rate` decimal(5, 0) NULL DEFAULT NULL COMMENT '绋庣巼',
-  `invoice_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙戠エ绫诲瀷',
-  `issue_date` date NULL DEFAULT NULL COMMENT '寮�绁ㄦ棩鏈�',
-  `tax_exclusivel_price` decimal(15, 2) NULL DEFAULT NULL COMMENT '閲戦(涓嶅惈绋�)',
-  `tax_price` decimal(15, 2) NULL DEFAULT NULL COMMENT '绋庨',
-  `tax_inclusive_price` decimal(15, 2) NULL DEFAULT NULL COMMENT '浠风◣鍚堣',
-  `remark` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `invoice_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '鍙戠エ鍐呭',
-  `supplier_id` int NOT NULL COMMENT '渚涘簲鍟唅d',
-  `storage_attachment_id` int NULL DEFAULT NULL COMMENT '鍏宠仈涓婁紶鐨勫彂绁ㄩ檮浠秈d',
-  `stock_in_record_ids` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '鍏宠仈鍏ュ簱鍗昳d(澶氶��)',
-  `status` int NULL DEFAULT 0 COMMENT '鐘舵�� 0鍚敤 1绂佺敤',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '璐㈠姟绠$悊--杩涢」鍙戠エ' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for account_purchase_payment
--- ----------------------------
-DROP TABLE IF EXISTS `account_purchase_payment`;
-CREATE TABLE `account_purchase_payment`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `account_payment_application_id` int NOT NULL COMMENT '鍏宠仈浠樻鐢宠id',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `supplier_id` int NOT NULL COMMENT '渚涘簲鍟唅d',
-  `payment_date` date NULL DEFAULT NULL COMMENT '浠樻鏃ユ湡',
-  `payment_method` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '浠樻鏂瑰紡',
-  `payment_amount` decimal(15, 2) NULL DEFAULT NULL COMMENT '浠樻閲戦',
-  `payment_number` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '浠樻鍗曞彿',
-  `remark` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '璐㈠姟绠$悊--浠樻鍗�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for account_sales_collection
--- ----------------------------
-DROP TABLE IF EXISTS `account_sales_collection`;
-CREATE TABLE `account_sales_collection`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `stock_out_record_ids` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鍏宠仈鍑哄簱鍗昳d(澶氶��)',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `customer_id` int NOT NULL COMMENT '瀹㈡埛id',
-  `collection_date` date NULL DEFAULT NULL COMMENT '鏀舵鏃ユ湡',
-  `collection_amount` decimal(15, 2) NULL DEFAULT NULL COMMENT '鏀舵閲戦',
-  `collection_method` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鏀舵鏂瑰紡',
-  `collection_number` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鏀舵鍗曞彿',
-  `remark` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '璐㈠姟绠$悊--鏀舵鍗�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for account_sales_invoice
--- ----------------------------
-DROP TABLE IF EXISTS `account_sales_invoice`;
-CREATE TABLE `account_sales_invoice`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `account_invoice_application_id` int NOT NULL COMMENT '鍏宠仈寮�绁ㄧ敵璇穒d',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `invoice_number` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鍙戠エ鍙风爜',
-  `tax_rate` decimal(5, 0) NULL DEFAULT NULL COMMENT '绋庣巼',
-  `invoice_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙戠エ绫诲瀷',
-  `issue_date` date NULL DEFAULT NULL COMMENT '寮�绁ㄦ棩鏈�',
-  `tax_exclusivel_price` decimal(15, 2) NULL DEFAULT NULL COMMENT '閲戦(涓嶅惈绋�)',
-  `tax_price` decimal(15, 2) NULL DEFAULT NULL COMMENT '绋庨',
-  `tax_inclusive_price` decimal(15, 2) NULL DEFAULT NULL COMMENT '浠风◣鍚堣',
-  `remark` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `invoice_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '鍙戠エ鍐呭',
-  `customer_id` int NULL DEFAULT NULL COMMENT '瀹㈡埛id',
-  `storage_attachment_id` int NULL DEFAULT NULL COMMENT '鍏宠仈涓婁紶鐨勫彂绁ㄩ檮浠秈d',
-  `status` int NULL DEFAULT 0 COMMENT '鐘舵�� 0鍚敤 1绂佺敤',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '璐㈠姟绠$悊--閿�椤瑰彂绁�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for account_statement
--- ----------------------------
-DROP TABLE IF EXISTS `account_statement`;
-CREATE TABLE `account_statement`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `customer_id` int NOT NULL COMMENT '瀹㈡埛id',
-  `statement_month` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '瀵硅处鏈堜唤(yyyy-MM)',
-  `account_type` int NOT NULL COMMENT '涓氬姟绫诲瀷(1搴旀敹瀵硅处;2搴斾粯瀵硅处)',
-  `statement_number` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '瀵硅处鍗曞彿',
-  `opening_balance` decimal(15, 2) NULL DEFAULT NULL COMMENT '鏈熷垵浣欓',
-  `current_plan` decimal(15, 2) NULL DEFAULT NULL COMMENT '鏈湡搴旀敹/搴斾粯',
-  `current_actually` decimal(15, 2) NULL DEFAULT NULL COMMENT '鏈湡鏀舵/浠樻',
-  `closing_balance` decimal(15, 2) NULL DEFAULT NULL COMMENT '鏈熸湯浣欓',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '璐㈠姟绠$悊--瀵硅处鍗�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for account_statement_details
--- ----------------------------
-DROP TABLE IF EXISTS `account_statement_details`;
-CREATE TABLE `account_statement_details`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `account_statement_id` int NOT NULL COMMENT '鍏宠仈瀵硅处鍗昳d',
-  `occurrence_date` date NULL DEFAULT NULL COMMENT '鏁版嵁鏃ユ湡',
-  `receipt_number` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鍗曟嵁缂栧彿',
-  `type` int NULL DEFAULT NULL COMMENT '鏁版嵁绫诲瀷(1鍑哄簱;2鍏ュ簱;3鏀舵;4浠樻;5閫�璐�)',
-  `amount` decimal(15, 2) NULL DEFAULT NULL COMMENT '閲戦',
-  `remark` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '璐㈠姟绠$悊--瀵硅处鍗曟槑缁�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for account_subject
--- ----------------------------
-DROP TABLE IF EXISTS `account_subject`;
-CREATE TABLE `account_subject`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `parent_id` bigint NULL DEFAULT NULL COMMENT '鐖剁鐩甀D锛堜负绌鸿〃绀烘牴鑺傜偣锛�',
-  `subject_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '绉戠洰缂栫爜(鍞竴鏍囪瘑)',
-  `subject_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '绉戠洰鍚嶇О',
-  `subject_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '绉戠洰绫诲瀷',
-  `balance_direction` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '浣欓鏂瑰悜',
-  `status` int NULL DEFAULT 0 COMMENT '鐘舵�� 0鍚敤 1绂佺敤',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_account_subject_parent_id`(`parent_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鎬昏处绉戠洰琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for after_sales_near_expiry
--- ----------------------------
-DROP TABLE IF EXISTS `after_sales_near_expiry`;
-CREATE TABLE `after_sales_near_expiry`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `product_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '涓存湡浜у搧鍚嶇О',
-  `batch_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '浜у搧鎵瑰彿',
-  `expire_date` date NULL DEFAULT NULL COMMENT '涓存湡鏃ユ湡',
-  `stock_quantity` int NULL DEFAULT NULL COMMENT '搴撳瓨鏁伴噺',
-  `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '瀹㈡埛鍚嶇О',
-  `dis_res` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '闂鎻忚堪',
-  `status` int NULL DEFAULT NULL COMMENT '澶勭悊鐘舵�� (濡�: 1-寰呭鐞� 2-宸插鐞�)',
-  `dispose_user_id` bigint NULL DEFAULT NULL COMMENT '澶勭悊浜篒D',
-  `dispose_nick_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '澶勭悊浜哄悕绉�',
-  `dis_date` date NULL DEFAULT NULL COMMENT '澶勭悊鏃ユ湡',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `contact_phone` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
-  `dispose_result` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '澶勭悊缁撴灉',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '涓存湡鍞悗绠$悊琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for after_sales_service
--- ----------------------------
-DROP TABLE IF EXISTS `after_sales_service`;
-CREATE TABLE `after_sales_service`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `status` int NULL DEFAULT NULL COMMENT '鐘舵�� 1-寰呭鐞� 2-宸插鐞�',
-  `check_user_id` bigint NULL DEFAULT NULL COMMENT '鐧昏浜�',
-  `check_nick_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '鐧昏浜哄悕绉�',
-  `dispose_user_id` bigint NULL DEFAULT NULL COMMENT '澶勭悊浜�',
-  `dispose_nick_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '澶勭悊浜哄悕绉�',
-  `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '瀹㈡埛鍚嶇О',
-  `dis_res` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '闂鎻忚堪',
-  `pro_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '澶勭悊缁撴灉',
-  `feedback_date` date NULL DEFAULT NULL COMMENT '鍙嶉鏃ユ湡',
-  `dis_date` date NULL DEFAULT NULL COMMENT '澶勭悊鏃ユ湡',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `service_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '鍞悗绫诲瀷',
-  `urgency` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '绱ф�ョ▼搴�',
-  `sales_ledger_id` bigint NULL DEFAULT NULL COMMENT '閿�鍞鍗昳d',
-  `distribution_user_id` bigint NULL DEFAULT NULL COMMENT '鍒嗛厤浜篿d',
-  `product_model_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '鍞悗浜у搧id闆嗗悎',
-  `after_sales_service_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '鍞悗鍗曞彿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '鍞悗鏈嶅姟' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for after_sales_service_file
--- ----------------------------
-DROP TABLE IF EXISTS `after_sales_service_file`;
-CREATE TABLE `after_sales_service_file`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `service_id` bigint NOT NULL COMMENT '鍞悗鏈嶅姟璁板綍ID',
-  `file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '鏂囦欢鍚嶇О',
-  `file_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '鏂囦欢璁块棶鍦板潃',
-  `file_size` bigint NULL DEFAULT NULL COMMENT '鏂囦欢澶у皬',
-  `file_suffix` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '鏂囦欢鍚庣紑',
-  `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT '0' COMMENT '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '涓婁紶鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_service_id`(`service_id` ASC) USING BTREE COMMENT '鍞悗ID绱㈠紩'
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '鍞悗鏈嶅姟闄勪欢琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for ai_chat_session
--- ----------------------------
-DROP TABLE IF EXISTS `ai_chat_session`;
-CREATE TABLE `ai_chat_session`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `memory_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '浼氳瘽ID',
-  `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛ID',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `title` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '浼氳瘽鏍囬',
-  `last_message` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鏈�鍚庝竴鏉℃秷鎭�',
-  `message_count` int NOT NULL DEFAULT 0 COMMENT '娑堟伅鏁伴噺',
-  `last_chat_time` datetime NULL DEFAULT NULL COMMENT '鏈�鍚庤亰澶╂椂闂�',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'AI鍘嗗彶浼氳瘽鍏冩暟鎹〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for annual_leave_setting
--- ----------------------------
-DROP TABLE IF EXISTS `annual_leave_setting`;
-CREATE TABLE `annual_leave_setting`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `employee_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍛樺伐绫诲瀷',
-  `work_years` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸ヤ綔骞撮檺',
-  `annual_days` int NULL DEFAULT NULL COMMENT '骞村亣澶╂暟',
-  `max_carry_over` int NULL DEFAULT NULL COMMENT '鏈�澶х粨杞ぉ鏁�',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐘舵��',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '骞村亣璁剧疆' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for approval_instance
--- ----------------------------
-DROP TABLE IF EXISTS `approval_instance`;
-CREATE TABLE `approval_instance`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瀹℃壒瀹炰緥ID',
-  `instance_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瀹℃壒缂栧彿',
-  `template_id` bigint NULL DEFAULT NULL COMMENT '妯℃澘ID',
-  `template_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '妯℃澘鍚嶇О',
-  `business_id` bigint NULL DEFAULT NULL COMMENT '涓氬姟ID',
-  `business_type` int NULL DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
-  `title` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瀹℃壒鏍囬',
-  `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瀹℃壒鐘舵��',
-  `current_level` int NULL DEFAULT NULL COMMENT '褰撳墠瀹℃壒绾у埆',
-  `applicant_id` bigint NOT NULL COMMENT '鐢宠浜篒D',
-  `applicant_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢宠浜哄悕绉�',
-  `apply_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鐢宠鏃堕棿',
-  `finish_time` datetime NULL DEFAULT NULL COMMENT '瀹屾垚鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎',
-  `dept_id` int NULL DEFAULT NULL,
-  `form_config` json NULL,
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_business`(`business_type` ASC, `business_id` ASC) USING BTREE,
-  INDEX `idx_status`(`status` ASC) USING BTREE,
-  INDEX `idx_applicant`(`applicant_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 99 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹℃壒瀹炰緥琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for approval_instance_node
--- ----------------------------
-DROP TABLE IF EXISTS `approval_instance_node`;
-CREATE TABLE `approval_instance_node`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑺傜偣瀹炰緥ID',
-  `instance_id` bigint NOT NULL COMMENT '瀹℃壒瀹炰緥ID',
-  `level_no` int NOT NULL COMMENT '瀹℃壒绾у埆',
-  `approve_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瀹℃壒绫诲瀷',
-  `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鑺傜偣鐘舵��',
-  `start_time` datetime NULL DEFAULT NULL COMMENT '寮�濮嬫椂闂�',
-  `finish_time` datetime NULL DEFAULT NULL COMMENT '瀹屾垚鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎',
-  `dept_id` int NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_instance_id`(`instance_id` ASC) USING BTREE,
-  INDEX `idx_instance_level`(`instance_id` ASC, `level_no` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 123 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹℃壒鑺傜偣瀹炰緥琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for approval_record
--- ----------------------------
-DROP TABLE IF EXISTS `approval_record`;
-CREATE TABLE `approval_record`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瀹℃壒璁板綍ID',
-  `instance_id` bigint NULL DEFAULT NULL COMMENT '瀹℃壒瀹炰緥ID',
-  `node_id` bigint NULL DEFAULT NULL COMMENT '鑺傜偣瀹炰緥ID',
-  `task_id` bigint NULL DEFAULT NULL COMMENT '瀹℃壒浠诲姟ID',
-  `operator_id` bigint NULL DEFAULT NULL COMMENT '鎿嶄綔浜篒D',
-  `operator_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎿嶄綔浜哄悕绉�',
-  `action` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎿嶄綔绫诲瀷',
-  `comment` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃壒鎰忚',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` timestamp NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `deleted` tinyint(1) NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 180 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹℃壒璁板綍琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for approval_task
--- ----------------------------
-DROP TABLE IF EXISTS `approval_task`;
-CREATE TABLE `approval_task`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瀹℃壒浠诲姟ID',
-  `instance_id` bigint NOT NULL COMMENT '瀹℃壒瀹炰緥ID',
-  `node_id` bigint NOT NULL COMMENT '鑺傜偣瀹炰緥ID',
-  `level_no` int NOT NULL COMMENT '瀹℃壒绾у埆',
-  `approver_id` bigint NOT NULL COMMENT '瀹℃壒浜篒D',
-  `approver_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃壒浜哄悕绉�',
-  `task_status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '浠诲姟鐘舵��',
-  `approve_time` datetime NULL DEFAULT NULL COMMENT '瀹℃壒鏃堕棿',
-  `comment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃壒鎰忚',
-  `is_read` tinyint NOT NULL DEFAULT 0 COMMENT '鏄惁宸茶',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎',
-  `dept_id` int NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_approver`(`approver_id` ASC, `task_status` ASC) USING BTREE,
-  INDEX `idx_instance`(`instance_id` ASC) USING BTREE,
-  INDEX `idx_node`(`node_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 124 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹℃壒浠诲姟琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for approval_template
--- ----------------------------
-DROP TABLE IF EXISTS `approval_template`;
-CREATE TABLE `approval_template`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '妯℃澘ID',
-  `template_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '妯℃澘鍚嶇О',
-  `enabled` tinyint NOT NULL DEFAULT 1 COMMENT '鍚敤鐘舵�侊細1鍚敤锛�0鍋滅敤',
-  `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '妯℃澘璇存槑',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎锛�0鍚︼紝1鏄�',
-  `dept_id` int NULL DEFAULT NULL,
-  `form_config` json NULL COMMENT '鍔ㄦ�佽〃鍗曢厤缃甁SON',
-  `template_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '妯℃澘绫诲瀷锛�0绯荤粺鍐呯疆锛�1鑷畾涔�',
-  `business_type` int NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 46 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹℃壒妯℃澘琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for approval_template_node
--- ----------------------------
-DROP TABLE IF EXISTS `approval_template_node`;
-CREATE TABLE `approval_template_node`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑺傜偣ID',
-  `template_id` bigint NOT NULL COMMENT '瀹℃壒妯℃澘ID',
-  `level_no` int NOT NULL COMMENT '瀹℃壒绾у埆锛屼粠1寮�濮�',
-  `approve_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瀹℃壒鏂瑰紡锛欰ND浼氱锛孫R鎴栫',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  `create_user` int NULL DEFAULT NULL,
-  `dept_id` int NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE,
-  UNIQUE INDEX `uk_template_level`(`template_id` ASC, `level_no` ASC) USING BTREE,
-  INDEX `idx_template_id`(`template_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 68 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹℃壒妯℃澘鑺傜偣琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for approval_template_node_approver
--- ----------------------------
-DROP TABLE IF EXISTS `approval_template_node_approver`;
-CREATE TABLE `approval_template_node_approver`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `node_id` bigint NOT NULL COMMENT '瀹℃壒鑺傜偣ID',
-  `template_id` bigint NOT NULL COMMENT '瀹℃壒妯℃澘ID',
-  `approver_id` bigint NOT NULL COMMENT '瀹℃壒浜篒D',
-  `approver_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃壒浜哄悕绉板啑浣�',
-  `sort_no` int NOT NULL DEFAULT 1 COMMENT '瀹℃壒浜烘帓搴�',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `dept_id` int NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `deleted` int NOT NULL DEFAULT 0,
-  PRIMARY KEY (`id`) USING BTREE,
-  UNIQUE INDEX `uk_node_approver`(`node_id` ASC, `approver_id` ASC) USING BTREE,
-  INDEX `idx_node_id`(`node_id` ASC) USING BTREE,
-  INDEX `idx_template_id`(`template_id` ASC) USING BTREE,
-  INDEX `idx_approver_id`(`approver_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 76 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹℃壒妯℃澘鑺傜偣瀹℃壒浜鸿〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for approve_log
--- ----------------------------
-DROP TABLE IF EXISTS `approve_log`;
-CREATE TABLE `approve_log`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `approve_id` bigint NOT NULL COMMENT '瀹℃壒id',
-  `approve_node_order` int NOT NULL COMMENT '瀹℃壒鑺傜偣椤哄簭',
-  `approve_user` bigint NOT NULL COMMENT '瀹℃壒浜篿d',
-  `approve_time` datetime NOT NULL COMMENT '瀹℃壒鏃堕棿',
-  `approve_status` int NOT NULL COMMENT '瀹℃壒鐘舵��',
-  `approve_remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃壒澶囨敞',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹℃壒鏃ュ織琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for approve_node
--- ----------------------------
-DROP TABLE IF EXISTS `approve_node`;
-CREATE TABLE `approve_node`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `approve_process_id` char(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瀹℃壒缂栧彿',
-  `approve_node_order` int NOT NULL COMMENT '瀹℃壒鑺傜偣椤哄簭',
-  `approve_node_user_id` int NULL DEFAULT NULL COMMENT '瀹℃壒鑺傜偣鐢ㄦ埛id',
-  `approve_node_user` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瀹℃壒鑺傜偣鐢ㄦ埛鍚嶅瓧',
-  `approve_node_time` datetime NOT NULL COMMENT '瀹℃壒鑺傜偣鏃堕棿',
-  `approve_node_status` int NOT NULL COMMENT '瀹℃壒鑺傜偣鐘舵��:1鍚屾剰锛�2鎷掔粷锛�0灏氭湭瀹℃牳锛堥粯璁や负0锛�',
-  `tenant_id` bigint NOT NULL COMMENT '绉熸埛id',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `delete_flag` int NOT NULL COMMENT '鍒犻櫎鏍囪:0姝e父锛�1鍒犻櫎',
-  `approve_node_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃壒鑺傜偣鎷掔粷鍘熷洜',
-  `approve_node_remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃壒鑺傜偣澶囨敞',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 115 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹℃壒鑺傜偣琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for approve_process
--- ----------------------------
-DROP TABLE IF EXISTS `approve_process`;
-CREATE TABLE `approve_process`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `approve_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瀹℃壒id',
-  `approve_user` bigint NOT NULL COMMENT '鐢宠浜篿d',
-  `approve_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢宠浜哄悕绉�',
-  `approve_dept_id` bigint NULL DEFAULT NULL COMMENT '鐢宠閮ㄩ棬id',
-  `approve_dept_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢宠閮ㄩ棬鍚嶇О',
-  `approve_user_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃壒鐢ㄦ埛ids',
-  `approve_user_names` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃壒鐢ㄦ埛鍚嶇О',
-  `approve_user_current_id` bigint NULL DEFAULT NULL COMMENT '褰撳墠瀹℃壒鐢ㄦ埛id',
-  `approve_user_current_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '褰撳墠瀹℃壒鐢ㄦ埛鍚嶇О',
-  `approve_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鐢宠鍘熷洜',
-  `approve_time` datetime NOT NULL COMMENT '鐢宠鏃ユ湡',
-  `approve_over_time` datetime NULL DEFAULT NULL COMMENT '瀹℃壒瀹屾垚鏃堕棿',
-  `approve_status` int NOT NULL COMMENT '瀹℃壒鐘舵�侊細0寰呭鏍革紝1瀹℃牳涓紝2瀹℃牳瀹屾垚',
-  `approve_delete` int NOT NULL COMMENT '瀹℃壒鏄惁鍒犻櫎锛�0姝e父锛�1鍒犻櫎',
-  `tenant_id` bigint NOT NULL COMMENT '绉熸埛id',
-  `approve_type` int NULL DEFAULT NULL COMMENT '瀹℃壒绫诲瀷',
-  `approve_remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃壒澶囨敞',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `start_date_time` datetime NULL DEFAULT NULL COMMENT '寮�濮嬫椂闂�',
-  `end_date_time` datetime NULL DEFAULT NULL COMMENT '缁撴潫鏃堕棿',
-  `start_date` date NULL DEFAULT NULL COMMENT '寮�濮嬫棩鏈�',
-  `end_date` date NULL DEFAULT NULL COMMENT '缁撴潫鏃ユ湡',
-  `location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍦扮偣',
-  `price` decimal(10, 2) NULL DEFAULT NULL COMMENT '鎶ラ攢閲戦',
-  `maintenance_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '缁翠慨浠锋牸',
-  `device_repair_id` int NULL DEFAULT NULL COMMENT '璁惧鎶ヤ慨id',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 98 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹℃壒娴佺▼琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for approve_process_config_node
--- ----------------------------
-DROP TABLE IF EXISTS `approve_process_config_node`;
-CREATE TABLE `approve_process_config_node`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `approve_type` int NULL DEFAULT NULL COMMENT '瀹℃壒绫诲瀷锛�1鍏嚭绠$悊锛�2璇峰亣绠$悊锛�3鍑哄樊绠$悊锛�4鎶ラ攢绠$悊锛�5閲囪喘瀹℃壒锛�6鎶ヤ环瀹℃壒锛�7鍙戣揣瀹℃壒锛�8鍗遍櫓浣滀笟瀹℃壒',
-  `node_order` int NULL DEFAULT NULL COMMENT '鑺傜偣椤哄簭',
-  `approver_id` int NULL DEFAULT NULL COMMENT '瀹℃壒浜篒D',
-  `approver_name` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃壒浜哄悕绉�',
-  `timeout_hours` int NULL DEFAULT NULL COMMENT '瓒呮椂鏃堕暱锛堝皬鏃讹級',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛ID',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛ID',
-  `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
-  `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '鍒犻櫎鏍囪锛�0姝e父锛�1鍒犻櫎',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹℃壒娴佺▼閰嶇疆鑺傜偣琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for bank
--- ----------------------------
-DROP TABLE IF EXISTS `bank`;
-CREATE TABLE `bank`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `bank_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閾惰鍚嶇О',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閾惰绠$悊琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for borrow_info
--- ----------------------------
-DROP TABLE IF EXISTS `borrow_info`;
-CREATE TABLE `borrow_info`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍊熸璁板綍涓婚敭ID',
-  `borrower_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍊熸浜哄鍚�',
-  `borrow_amount` decimal(18, 2) NULL DEFAULT NULL COMMENT '鍊熸閲戦锛堝厓锛�',
-  `interest_rate` decimal(5, 2) NULL DEFAULT NULL COMMENT '鍊熸鍒╃巼锛堝锛�5.85 浠h〃5.85%锛�',
-  `borrow_date` date NULL DEFAULT NULL COMMENT '鍊熸鏃ユ湡',
-  `repay_date` date NULL DEFAULT NULL COMMENT '瀹為檯杩樻鏃ユ湡锛堣繕娆惧悗濉厖锛�',
-  `status` tinyint NOT NULL DEFAULT 1 COMMENT '鍊熸鐘舵�侊細1=寰呰繕娆撅紝2=宸茶繕娆�',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞锛堝�熸璇存槑锛�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓鑰匢D',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰匢D',
-  `tenant_id` bigint NOT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍊熸淇℃伅琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for common_file
--- ----------------------------
-DROP TABLE IF EXISTS `common_file`;
-CREATE TABLE `common_file`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `common_id` int NOT NULL COMMENT '鍏宠仈閿�鍞彴璐︿富琛ㄤ富閿�',
-  `type` int NULL DEFAULT NULL COMMENT '鍏宠仈琛ㄧ被鍨�',
-  `url` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '闄勪欢璺緞',
-  `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '闄勪欢鍚嶇О',
-  `create_time` date NULL DEFAULT NULL,
-  `update_time` date NULL DEFAULT NULL,
-  `file_size` bigint NULL DEFAULT NULL COMMENT '鏂囦欢澶у皬',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閿�鍞彴璐︽枃浠�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for compensation_performance
--- ----------------------------
-DROP TABLE IF EXISTS `compensation_performance`;
-CREATE TABLE `compensation_performance`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `staff_id` bigint NOT NULL COMMENT '鍛樺伐id',
-  `pay_date` date NULL DEFAULT NULL COMMENT '钖祫鏈堜唤',
-  `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '濮撳悕',
-  `should_attended_num` decimal(10, 2) NULL DEFAULT NULL COMMENT '搴斿嚭鍕ゅぉ鏁�',
-  `actual_attended_num` decimal(10, 2) NULL DEFAULT NULL COMMENT '瀹為檯鍑哄嫟澶╂暟',
-  `basic_salary` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍩烘湰宸ヨ祫',
-  `post_salary` decimal(10, 2) NULL DEFAULT NULL COMMENT '宀椾綅宸ヨ祫',
-  `deduction_absenteeism` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍏ョ鑱岀己鍕ゆ墸娆�',
-  `sick_leave_deductions` decimal(10, 2) NULL DEFAULT NULL COMMENT '鐥呭亣鎵f',
-  `deduction_personal_leave` decimal(10, 2) NULL DEFAULT NULL COMMENT '浜嬪亣鎵f',
-  `forget_clock_deduct` decimal(10, 2) NULL DEFAULT NULL COMMENT '蹇樿鎵撳崱鎵f',
-  `performance_score` decimal(10, 2) NULL DEFAULT NULL COMMENT '缁╂晥寰楀垎',
-  `performance_pay` decimal(10, 2) NULL DEFAULT NULL COMMENT '缁╂晥宸ヨ祫',
-  `payable_wages` decimal(10, 2) NULL DEFAULT NULL COMMENT '搴斿彂鍚堣',
-  `social_security_individuals` decimal(10, 2) NULL DEFAULT NULL COMMENT '绀句繚涓汉',
-  `social_security_companies` decimal(10, 2) NULL DEFAULT NULL COMMENT '绀句繚鍏徃',
-  `social_security_total` decimal(10, 2) NULL DEFAULT NULL COMMENT '绀句繚鍚堣',
-  `provident_fund_individuals` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍏Н閲戜釜浜�',
-  `provident_fund_company` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍏Н閲戝叕鍙�',
-  `provident_fund_total` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍏Н閲戝悎璁�',
-  `taxable_waget` decimal(10, 2) NULL DEFAULT NULL COMMENT '搴旂◣宸ヨ祫',
-  `personal_income_tax` decimal(10, 2) NULL DEFAULT NULL COMMENT '涓汉鎵�寰楃◣',
-  `actual_wages` decimal(10, 2) NULL DEFAULT NULL COMMENT '瀹炲彂宸ヨ祫',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '钖叕缁╂晥' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for custom_storage
--- ----------------------------
-DROP TABLE IF EXISTS `custom_storage`;
-CREATE TABLE `custom_storage`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `item_type` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鐗╁搧绫诲瀷',
-  `inbound_date` date NULL DEFAULT NULL COMMENT '鍏ュ簱鏃堕棿',
-  `inbound_batches` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鍏ュ簱鎵规',
-  `inbound_num` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍏ュ簱鏁伴噺',
-  `supplier_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉�',
-  `product_category` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '浜у搧澶х被',
-  `specification_model` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `unit` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `tax_inclusive_unit_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍚◣鍗曚环',
-  `tax_inclusive_total_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍚◣鎬讳环',
-  `tax_rate` decimal(10, 2) NULL DEFAULT NULL COMMENT '绋庣巼(%)',
-  `tax_exclusive_total_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '涓嶅惈绋庢�讳环',
-  `create_by` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鍏ュ簱浜�',
-  `create_time` datetime NULL DEFAULT NULL,
-  `update_time` datetime NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` bigint NULL DEFAULT NULL,
-  `code` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '缂栧彿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for customer
--- ----------------------------
-DROP TABLE IF EXISTS `customer`;
-CREATE TABLE `customer`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瀹㈡埛鍚嶇О',
-  `taxpayer_identification_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '绾崇◣浜鸿瘑鍒彿',
-  `company_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍏徃鍦板潃',
-  `company_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍏徃鐢佃瘽',
-  `contact_person` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鑱旂郴浜�',
-  `contact_phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鑱旂郴鐢佃瘽',
-  `maintainer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '缁存姢浜�',
-  `maintenance_time` date NOT NULL COMMENT '缁存姢鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `basic_bank_account` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閾惰鍩烘湰鎴�',
-  `bank_account` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閾惰璐﹀彿',
-  `bank_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '寮�鎴疯鍙�',
-  `customer_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹㈡埛鍒嗙被锛氶浂鍞鎴凤紝杩涢攢鍟嗗鎴�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `usage_user` int NULL DEFAULT NULL COMMENT '浣跨敤鐢ㄦ埛',
-  `usage_status` int NULL DEFAULT NULL COMMENT '浣跨敤鐘舵��',
-  `type` smallint NOT NULL DEFAULT 0 COMMENT '绫诲瀷 0 绉佹捣瀹㈡埛 1 鍏捣瀹㈡埛',
-  `is_assigned` tinyint(1) NOT NULL DEFAULT 0 COMMENT '鏄惁琚垎閰嶏細0-鏈垎閰嶏紝1-宸插垎閰�',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 427 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹㈡埛妗f' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for customer_follow_up
--- ----------------------------
-DROP TABLE IF EXISTS `customer_follow_up`;
-CREATE TABLE `customer_follow_up`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `follow_up_method` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璺熻繘鏂瑰紡',
-  `follow_up_level` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璺熻繘绋嬪害',
-  `follow_up_time` datetime NOT NULL COMMENT '璺熻繘鏃堕棿',
-  `follower_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璺熻繘浜哄鍚�',
-  `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璺熻繘鍐呭',
-  `follower_user_id` bigint NULL DEFAULT NULL COMMENT '璺熻繘浜篒D',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `customer_id` bigint NOT NULL DEFAULT 0,
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_tenant_id`(`tenant_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹㈡埛璺熻繘杩涘害琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for customer_follow_up_file
--- ----------------------------
-DROP TABLE IF EXISTS `customer_follow_up_file`;
-CREATE TABLE `customer_follow_up_file`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `follow_up_id` int NULL DEFAULT NULL COMMENT '璺熻繘璁板綍ID',
-  `file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '鏂囦欢鍚嶇О',
-  `file_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '鏂囦欢璁块棶鍦板潃',
-  `file_size` bigint NULL DEFAULT NULL COMMENT '鏂囦欢澶у皬',
-  `file_suffix` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '鏂囦欢鍚庣紑',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '涓婁紶鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_follow_up_id`(`follow_up_id` ASC) USING BTREE COMMENT '璺熻繘璁板綍ID绱㈠紩'
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '瀹㈡埛璺熻繘闄勪欢琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for customer_private
--- ----------------------------
-DROP TABLE IF EXISTS `customer_private`;
-CREATE TABLE `customer_private`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瀹㈡埛鍚嶇О',
-  `taxpayer_identification_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '绾崇◣浜鸿瘑鍒彿',
-  `company_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍏徃鍦板潃',
-  `company_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍏徃鐢佃瘽',
-  `contact_person` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鑱旂郴浜�',
-  `contact_phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鑱旂郴鐢佃瘽',
-  `maintainer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '缁存姢浜�',
-  `maintenance_time` date NOT NULL COMMENT '缁存姢鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `basic_bank_account` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閾惰鍩烘湰鎴�',
-  `bank_account` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閾惰璐﹀彿',
-  `bank_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '寮�鎴疯鍙�',
-  `customer_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹㈡埛鍒嗙被锛氶浂鍞鎴凤紝杩涢攢鍟嗗鎴�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `usage_user` int NULL DEFAULT NULL,
-  `usage_status` int NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹㈡埛妗f' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for customer_private_pool
--- ----------------------------
-DROP TABLE IF EXISTS `customer_private_pool`;
-CREATE TABLE `customer_private_pool`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭id',
-  `customer_id` bigint NULL DEFAULT NULL COMMENT '瀹㈡埛id',
-  `bound_id` bigint NULL DEFAULT NULL COMMENT '缁戝畾浜篿d',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `create_time` timestamp NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_time` timestamp NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `dept_id` int NULL DEFAULT NULL,
-  `type` int NULL DEFAULT 0 COMMENT '绫诲瀷鍖哄垎鍏捣瀹㈡埛鍜岀娴峰鎴� 榛樿鏄娴峰鎴�0 鍏捣1',
-  `delete_flag` int NULL DEFAULT 0 COMMENT '鍒犻櫎鏍囧織',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '绉佹捣瀹㈡埛' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for customer_return_visit
--- ----------------------------
-DROP TABLE IF EXISTS `customer_return_visit`;
-CREATE TABLE `customer_return_visit`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `is_enabled` tinyint(1) NULL DEFAULT 1 COMMENT '鎻愰啋寮�鍏� (0:鍏抽棴, 1:寮�鍚�)',
-  `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '鎻愰啋鍐呭',
-  `reminder_time` datetime NOT NULL COMMENT '鎻愰啋鏃堕棿',
-  `is_completed` tinyint(1) NULL DEFAULT 0 COMMENT '澶勭悊鐘舵�� (0:寰呮彁閱�, 1:宸叉彁閱�)',
-  `remind_user_id` bigint NOT NULL COMMENT '鎺ユ敹鎻愰啋鐨勭敤鎴稩D',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `customer_id` bigint NOT NULL DEFAULT 0,
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_remind_user`(`remind_user_id` ASC, `is_completed` ASC) USING BTREE COMMENT '鐢ㄦ埛寰呭姙鏌ヨ绱㈠紩'
-) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '瀹㈡埛鍥炶鎻愰啋琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for customer_user
--- ----------------------------
-DROP TABLE IF EXISTS `customer_user`;
-CREATE TABLE `customer_user`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `customer_id` bigint NOT NULL DEFAULT 0 COMMENT '瀹㈡埛id',
-  `user_id` bigint NOT NULL DEFAULT 0 COMMENT '鐢ㄦ埛id',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '绉熸埛id',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for customer_visits
--- ----------------------------
-DROP TABLE IF EXISTS `customer_visits`;
-CREATE TABLE `customer_visits`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `customer_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹㈡埛鍚嶇О',
-  `contact` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鑱旂郴浜�',
-  `contact_phone` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
-  `location` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浣嶇疆',
-  `visiting_people` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎷滆浜�',
-  `purpose_visit` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎷滆鐩殑',
-  `purpose_date` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎷滆鏃堕棿',
-  `visit_address` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎷滆鍦板潃',
-  `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '澶囨敞',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰卛d',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰卛d',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹㈡埛鎷滆鐧昏' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for device_defect_record
--- ----------------------------
-DROP TABLE IF EXISTS `device_defect_record`;
-CREATE TABLE `device_defect_record`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `device_ledger_id` bigint NOT NULL COMMENT '璁惧鍙拌处id',
-  `defect_description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎻忚堪',
-  `eliminate_time` datetime NULL DEFAULT NULL COMMENT '娑堢己鏃堕棿',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧鐘舵��',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璁惧缂洪櫡璁板綍琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for device_ledger
--- ----------------------------
-DROP TABLE IF EXISTS `device_ledger`;
-CREATE TABLE `device_ledger`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `device_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧鍚嶇О',
-  `device_model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `supplier_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '渚涘簲鍟�',
-  `unit` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `number` decimal(10, 0) NULL DEFAULT NULL COMMENT '鏁伴噺',
-  `tax_including_price_unit` decimal(10, 0) NULL DEFAULT NULL COMMENT '鍚◣鍗曚环',
-  `tax_including_price_total` decimal(10, 0) NULL DEFAULT NULL COMMENT '鍚◣鎬讳环',
-  `tax_rate` decimal(10, 0) NULL DEFAULT NULL COMMENT '绋庣巼',
-  `un_tax_including_price_total` decimal(10, 0) NULL DEFAULT NULL COMMENT '涓嶅惈绋庢�讳环',
-  `create_time` timestamp NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` timestamp NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '褰曞叆浜�',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧鐘舵��',
-  `plan_runtime_time` date NULL DEFAULT NULL COMMENT '璁″垝杩愯鏃堕棿',
-  `start_runtime_time` datetime NULL DEFAULT NULL COMMENT '寮�濮嬭繍琛屾椂闂�',
-  `end_runtime_time` datetime NULL DEFAULT NULL COMMENT '缁撴潫杩愯鏃堕棿',
-  `runtime_duration` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '杩愯鏃堕暱',
-  `device_brand` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧鍝佺墝',
-  `storage_location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀛樻斁浣嶇疆',
-  `is_depr` int NULL DEFAULT NULL COMMENT '鏄惁鎶樻棫 1-鏄� 2-鍚�',
-  `annual_depreciation_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '姣忓勾鎶樻棫閲戦',
-  `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧绫诲瀷',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for device_maintenance
--- ----------------------------
-DROP TABLE IF EXISTS `device_maintenance`;
-CREATE TABLE `device_maintenance`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `device_ledger_id` bigint NOT NULL COMMENT '璁惧鍙拌处id',
-  `maintenance_plan_time` timestamp NULL DEFAULT NULL COMMENT '璁″垝淇濆吇鏃ユ湡',
-  `maintenance_actually_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹為檯淇濆吇浜�',
-  `maintenance_actually_time` timestamp NULL DEFAULT NULL COMMENT '瀹為檯淇濆吇鏃ユ湡',
-  `status` int NOT NULL DEFAULT 0 COMMENT '鐘舵�� 0 寰呬繚鍏� 1 瀹岀粨',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` int NOT NULL COMMENT '褰曞叆浜�',
-  `update_user` int NOT NULL COMMENT '鏇存柊浜�',
-  `tenant_id` bigint NOT NULL COMMENT '绉熸埛id',
-  `device_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `device_model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `maintenance_result` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '淇濆吇缁撴灉',
-  `maintenance_task_id` int NULL DEFAULT NULL COMMENT '淇濆吇浠诲姟id',
-  `frequency_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '棰戞',
-  `frequency_detail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '棰戞璇︽儏',
-  `next_execution_time` timestamp NULL DEFAULT NULL COMMENT '涓嬫鎵ц鏃堕棿',
-  `last_execution_time` timestamp NULL DEFAULT NULL COMMENT '鏈�鍚庢墽琛屾椂闂�',
-  `spare_parts_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `machinery_category` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 39 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for device_maintenance_file
--- ----------------------------
-DROP TABLE IF EXISTS `device_maintenance_file`;
-CREATE TABLE `device_maintenance_file`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢鍚嶇О',
-  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢璺緞',
-  `file_size` int NULL DEFAULT NULL COMMENT '鏂囦欢澶у皬',
-  `device_maintenance_id` int NULL DEFAULT NULL COMMENT '璁惧淇濆吇璁板綍ID',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璁惧淇濆吇闄勪欢' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for device_repair
--- ----------------------------
-DROP TABLE IF EXISTS `device_repair`;
-CREATE TABLE `device_repair`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `device_ledger_id` bigint NOT NULL COMMENT '璁惧鍙拌处id',
-  `repair_time` timestamp NULL DEFAULT NULL COMMENT '鎶ヤ慨鏃ユ湡',
-  `repair_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鎶ヤ慨浜�',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '鏁呴殰鐜拌薄',
-  `maintenance_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '缁翠慨浜�',
-  `maintenance_time` timestamp NULL DEFAULT NULL COMMENT '缁翠慨鏃堕棿',
-  `maintenance_result` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '缁翠慨缁撴灉',
-  `status` int NULL DEFAULT 0 COMMENT '鐘舵��',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` int NOT NULL COMMENT '褰曞叆浜�',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `tenant_id` bigint NOT NULL COMMENT '绉熸埛id',
-  `device_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `device_model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `maintenance_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '缁翠慨浠锋牸',
-  `approver_id` int NULL DEFAULT NULL COMMENT '瀹℃壒浜篿d',
-  `spare_parts_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `machinery_category` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `acceptance_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '楠屾敹浜�',
-  `acceptance_time` datetime NULL DEFAULT NULL COMMENT '楠屾敹鏃堕棿',
-  `acceptance_remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '楠屾敹澶囨敞',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for device_runtime
--- ----------------------------
-DROP TABLE IF EXISTS `device_runtime`;
-CREATE TABLE `device_runtime`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `device_ledger_id` bigint NOT NULL COMMENT '璁惧鍙拌处id',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧鐘舵��',
-  `plan_runtime_time` datetime NULL DEFAULT NULL COMMENT '璁″垝杩愯鏃堕棿',
-  `start_runtime_time` datetime NULL DEFAULT NULL COMMENT '寮�濮嬭繍琛屾椂闂�',
-  `end_runtime_time` datetime NULL DEFAULT NULL COMMENT '缁撴潫杩愯鏃堕棿',
-  `runtime_duration` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '杩愯鏃堕暱',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璁惧杩愯琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for document_classification
--- ----------------------------
-DROP TABLE IF EXISTS `document_classification`;
-CREATE TABLE `document_classification`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `category` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绫诲埆鍚嶇О',
-  `parent_id` bigint NULL DEFAULT NULL COMMENT '鐖剁被id',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鏂囨。鍒嗙被琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for documentation
--- ----------------------------
-DROP TABLE IF EXISTS `documentation`;
-CREATE TABLE `documentation`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `document_classification_id` bigint NULL DEFAULT NULL COMMENT '绫诲埆鍚嶇Оid',
-  `doc_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囨。鍚嶇О',
-  `doc_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囨。缂栧彿',
-  `year` bigint NULL DEFAULT NULL COMMENT '骞翠唤',
-  `responsible_person` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璐d换浜�',
-  `warehouse_goods_shelves_rowcol_id` bigint NULL DEFAULT NULL COMMENT '鏂囨。鏀剧疆璐ф灦id',
-  `doc_date` datetime NULL DEFAULT NULL COMMENT '鏂囨。鏃ユ湡',
-  `retention_period` bigint NULL DEFAULT NULL COMMENT '淇濈鏈熼檺',
-  `security_level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '淇濆瘑绾у埆(缁濆瘑锛屼竴鑸�)',
-  `copy_count` bigint NULL DEFAULT NULL COMMENT '浠芥暟',
-  `page_count` bigint NULL DEFAULT NULL COMMENT '椤垫暟',
-  `doc_category` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囨。绫诲埆',
-  `doc_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囨。绉嶇被',
-  `urgency_level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绱ф�ョ▼搴�(绱ф�ワ紝鏅��)',
-  `doc_status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囨。鐘舵��(鍊熷嚭锛屾甯革紝浣滃簾)',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鏂囨。淇℃伅琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for documentation_borrow_management
--- ----------------------------
-DROP TABLE IF EXISTS `documentation_borrow_management`;
-CREATE TABLE `documentation_borrow_management`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `documentation_id` bigint NULL DEFAULT NULL COMMENT '鏂囨。id',
-  `borrower` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍊熼槄浜�',
-  `borrow_purpose` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍊熼槄鐩殑',
-  `borrow_date` datetime NULL DEFAULT NULL COMMENT '鍊熼槄鏃ユ湡',
-  `due_return_date` datetime NULL DEFAULT NULL COMMENT '搴斿綊杩樻棩鏈�',
-  `returner` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '褰掕繕浜�',
-  `return_date` datetime NULL DEFAULT NULL COMMENT '瀹為檯褰掕繕鏃ユ湡',
-  `borrow_status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍊熼槄鐘舵�侊紙鍊熼槄)',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鏂囨。鍊熼槄琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for documentation_file
--- ----------------------------
-DROP TABLE IF EXISTS `documentation_file`;
-CREATE TABLE `documentation_file`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢鍚嶇О',
-  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢璺緞',
-  `file_size` bigint NULL DEFAULT NULL COMMENT '鏂囦欢澶у皬',
-  `documentation_id` bigint NULL DEFAULT NULL COMMENT '鏂囨。ID',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鏂囨。--闄勪欢' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for documentation_return_management
--- ----------------------------
-DROP TABLE IF EXISTS `documentation_return_management`;
-CREATE TABLE `documentation_return_management`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `documentation_id` bigint NULL DEFAULT NULL COMMENT '鏂囨。id',
-  `borrow_id` bigint NULL DEFAULT NULL COMMENT '鍊熼槄id',
-  `borrower` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍊熼槄浜�',
-  `borrow_purpose` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍊熼槄鐩殑',
-  `borrow_date` datetime NULL DEFAULT NULL COMMENT '鍊熼槄鏃ユ湡',
-  `due_return_date` datetime NULL DEFAULT NULL COMMENT '搴斿綊杩樻棩鏈�',
-  `returner` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '褰掕繕浜�',
-  `return_date` datetime NULL DEFAULT NULL COMMENT '瀹為檯褰掕繕鏃ユ湡',
-  `borrow_status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍊熼槄鐘舵��(褰掕繕)',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鏂囨。褰掕繕琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for duty_plan
--- ----------------------------
-DROP TABLE IF EXISTS `duty_plan`;
-CREATE TABLE `duty_plan`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁″垝鏍囬',
-  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁″垝鎻忚堪',
-  `level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁″垝绾у埆',
-  `period` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏃堕棿鍛ㄦ湡',
-  `start_date` datetime NULL DEFAULT NULL COMMENT '寮�濮嬫椂闂�',
-  `end_date` datetime NULL DEFAULT NULL COMMENT '缁撴潫鏃堕棿',
-  `assignee` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璐熻矗浜�',
-  `priority` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浼樺厛绾�',
-  `tags` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏍囩',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐘舵��',
-  `progress` int NULL DEFAULT NULL COMMENT '瀹屾垚搴�',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍊肩彮涓庤鍒�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for electricity_consumption_area
--- ----------------------------
-DROP TABLE IF EXISTS `electricity_consumption_area`;
-CREATE TABLE `electricity_consumption_area`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `area_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍖哄煙鍚嶇О',
-  `area_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍖哄煙绫诲瀷',
-  `sort` bigint NULL DEFAULT NULL COMMENT '鎺掑簭',
-  `fu_id` int NULL DEFAULT NULL COMMENT '鐖剁被id',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢ㄧ數鍖哄煙' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for energy_period
--- ----------------------------
-DROP TABLE IF EXISTS `energy_period`;
-CREATE TABLE `energy_period`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `date` date NULL DEFAULT NULL COMMENT '鏃ユ湡',
-  `price` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏃舵鍗曚环 (鍏� / 搴�)',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `peak` decimal(10, 2) NULL DEFAULT NULL COMMENT '宄版',
-  `flat` decimal(10, 2) NULL DEFAULT NULL COMMENT '骞虫',
-  `valley` decimal(10, 2) NULL DEFAULT NULL COMMENT '璋锋',
-  `sharp` decimal(10, 2) NULL DEFAULT NULL COMMENT '灏栨',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢ㄧ數鏃舵琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for enterprise_news
--- ----------------------------
-DROP TABLE IF EXISTS `enterprise_news`;
-CREATE TABLE `enterprise_news`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
-  `title` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鏍囬',
-  `summary` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '鎽樿',
-  `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '姝f枃',
-  `category` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍒嗙被',
-  `read_scope` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'all' COMMENT '闃呰鑼冨洿 all鍏ㄥ憳 dept閮ㄩ棬 custom鑷畾涔�',
-  `is_required` tinyint NOT NULL DEFAULT 0 COMMENT '鏄惁蹇呰 0鍚� 1鏄�',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT '鐘舵�� 0鑽夌 1宸插彂甯� 2宸蹭笅绾�',
-  `required_read_count` int NOT NULL DEFAULT 0 COMMENT '闇�瑕侀槄璇荤殑鏁伴噺',
-  `read_count` int NOT NULL DEFAULT 0 COMMENT '宸茬粡闃呰鐨勬暟閲�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_enterprise_news_status`(`status` ASC) USING BTREE,
-  INDEX `idx_enterprise_news_category`(`category` ASC) USING BTREE,
-  INDEX `idx_enterprise_news_dept_id`(`dept_id` ASC) USING BTREE,
-  INDEX `idx_enterprise_news_create_time`(`create_time` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '浼佷笟鏂伴椈琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for enterprise_news_scope_dept
--- ----------------------------
-DROP TABLE IF EXISTS `enterprise_news_scope_dept`;
-CREATE TABLE `enterprise_news_scope_dept`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
-  `news_id` bigint NOT NULL COMMENT '浼佷笟鏂伴椈ID',
-  `dept_id` bigint NOT NULL COMMENT '閮ㄩ棬ID',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  PRIMARY KEY (`id`) USING BTREE,
-  UNIQUE INDEX `uk_enterprise_news_scope_dept`(`news_id` ASC, `dept_id` ASC) USING BTREE,
-  INDEX `idx_enterprise_news_scope_dept_dept_id`(`dept_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '浼佷笟鏂伴椈闃呰鑼冨洿閮ㄩ棬琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for enterprise_news_scope_user
--- ----------------------------
-DROP TABLE IF EXISTS `enterprise_news_scope_user`;
-CREATE TABLE `enterprise_news_scope_user`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
-  `news_id` bigint NOT NULL COMMENT '浼佷笟鏂伴椈ID',
-  `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛ID',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  PRIMARY KEY (`id`) USING BTREE,
-  UNIQUE INDEX `uk_enterprise_news_scope_user`(`news_id` ASC, `user_id` ASC) USING BTREE,
-  INDEX `idx_enterprise_news_scope_user_user_id`(`user_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '浼佷笟鏂伴椈闃呰鑼冨洿鐢ㄦ埛琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for equipment_energy_consumption
--- ----------------------------
-DROP TABLE IF EXISTS `equipment_energy_consumption`;
-CREATE TABLE `equipment_energy_consumption`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '璁惧缂栧彿',
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '璁惧鍚嶇О',
-  `power_rating` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '棰濆畾鍔熺巼',
-  `power_actual` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '瀹為檯鍔熺巼',
-  `day_num` decimal(18, 2) NULL DEFAULT 0.00 COMMENT '褰撴棩鐢ㄧ數閲�',
-  `sum_num` decimal(18, 2) NULL DEFAULT 0.00 COMMENT '绱鐢ㄧ數閲�',
-  `every_num` decimal(18, 2) NULL DEFAULT 0.00 COMMENT '姣忔棩闄愬埗鐢甸噺',
-  `run_date` date NULL DEFAULT NULL COMMENT '杩愯鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `electricity_consumption_area_id` bigint NULL DEFAULT NULL COMMENT '鍖哄煙id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '璁惧鑳借��' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for file_sharing
--- ----------------------------
-DROP TABLE IF EXISTS `file_sharing`;
-CREATE TABLE `file_sharing`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏变韩鏍囬',
-  `departments` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎺ユ敹閮ㄩ棬',
-  `files` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓婁紶鏂囦欢',
-  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏变韩鎻忚堪',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '琛屾斂绠$悊-閫氱煡绠$悊-鏂囦欢鍏变韩' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for fin_fixed_asset
--- ----------------------------
-DROP TABLE IF EXISTS `fin_fixed_asset`;
-CREATE TABLE `fin_fixed_asset`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `asset_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '璧勪骇缂栧彿',
-  `asset_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '璧勪骇鍚嶇О',
-  `category` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '璧勪骇绫诲埆',
-  `specification` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `purchase_date` date NOT NULL COMMENT '璐疆鏃ユ湡',
-  `original_value` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '璧勪骇鍘熷��',
-  `useful_life` int NOT NULL DEFAULT 1 COMMENT '浣跨敤骞撮檺(骞�)',
-  `residual_rate` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '娈嬪�肩巼(%)',
-  `accumulated_depreciation` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '绱鎶樻棫',
-  `net_value` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '鍑�鍊�',
-  `location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '瀛樻斁鍦扮偣',
-  `department` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '浣跨敤閮ㄩ棬',
-  `keeper` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '淇濈浜�',
-  `status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'in_use' COMMENT '鐘舵��: in_use/idle/repair/scrapped',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  UNIQUE INDEX `uk_fin_fixed_asset_code`(`asset_code` ASC) USING BTREE,
-  INDEX `idx_fin_fixed_asset_status`(`status` ASC) USING BTREE,
-  INDEX `idx_fin_fixed_asset_category`(`category` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '鍥哄畾璧勪骇' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for fin_intangible_asset
--- ----------------------------
-DROP TABLE IF EXISTS `fin_intangible_asset`;
-CREATE TABLE `fin_intangible_asset`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `asset_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '璧勪骇缂栧彿',
-  `asset_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '璧勪骇鍚嶇О',
-  `category` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '璧勪骇绫诲埆',
-  `certificate_no` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '璇佷功缂栧彿',
-  `acquisition_date` date NOT NULL COMMENT '鍙栧緱鏃ユ湡',
-  `original_value` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '璧勪骇鍘熷��',
-  `amortization_period` int NOT NULL DEFAULT 1 COMMENT '鎽婇攢骞撮檺(骞�)',
-  `residual_rate` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '娈嬪�肩巼(%)',
-  `accumulated_amortization` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '绱鎽婇攢',
-  `net_value` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '鍑�鍊�',
-  `validity_date` date NULL DEFAULT NULL COMMENT '鏈夋晥鏈熻嚦',
-  `status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'in_use' COMMENT '鐘舵��: in_use/expired/amortized',
-  `description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '璧勪骇鎻忚堪',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  UNIQUE INDEX `uk_fin_intangible_asset_code`(`asset_code` ASC) USING BTREE,
-  INDEX `idx_fin_intangible_asset_status`(`status` ASC) USING BTREE,
-  INDEX `idx_fin_intangible_asset_category`(`category` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '鏃犲舰璧勪骇' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for fin_reimbursement
--- ----------------------------
-DROP TABLE IF EXISTS `fin_reimbursement`;
-CREATE TABLE `fin_reimbursement`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `bill_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鎶ラ攢鍗曞彿',
-  `reimbursement_type` tinyint NOT NULL COMMENT '鎶ラ攢绫诲瀷锛�1-宸梾鎶ラ攢锛�2-璐圭敤鎶ラ攢',
-  `expense_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '璐圭敤绫诲瀷锛氬樊鏃呰垂/鍔炲叕閲囪喘/涓氬姟鎷涘緟/浜ら�氳垂/閫氳璐�/鍏朵粬',
-  `applicant_id` bigint NOT NULL COMMENT '鐢宠浜篒D',
-  `applicant_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍛樺伐缂栧彿',
-  `applicant_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鍛樺伐濮撳悕',
-  `applicant_dept_id` bigint NULL DEFAULT NULL COMMENT '鐢宠閮ㄩ棬ID',
-  `applicant_dept_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鐢宠閮ㄩ棬鍚嶇О',
-  `reason` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鎶ラ攢鍘熷洜',
-  `apply_amount` decimal(18, 4) NOT NULL DEFAULT 0.0000 COMMENT '鐢宠閲戦',
-  `detail_total_amount` decimal(18, 4) NOT NULL DEFAULT 0.0000 COMMENT '鏄庣粏姹囨�婚噾棰�',
-  `payee_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鏀舵浜�',
-  `payee_account` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鏀舵璐﹀彿',
-  `payee_bank` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '寮�鎴锋敮琛�',
-  `approval_instance_id` bigint NULL DEFAULT NULL COMMENT '瀹℃壒瀹炰緥ID锛屽搴� approval_instance.id',
-  `approve_process_id` bigint NULL DEFAULT NULL COMMENT '瀹℃壒娴佺▼ID锛屽搴� approve_process.id',
-  `bill_status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'DRAFT' COMMENT '鍗曟嵁鐘舵�侊細DRAFT-鑽夌锛孖N_APPROVAL-瀹℃壒涓紝APPROVED-瀹℃壒閫氳繃锛孯EJECTED-瀹℃壒椹冲洖锛學ITHDRAWN-宸叉挙鍥烇紝PAID-宸蹭粯娆�',
-  `approved_time` datetime NULL DEFAULT NULL COMMENT '瀹℃壒閫氳繃鏃堕棿',
-  `paid_time` datetime NULL DEFAULT NULL COMMENT '浠樻鏃堕棿',
-  `account_expense_id` bigint NULL DEFAULT NULL COMMENT '鐢熸垚鐨勮储鍔℃敮鍑鸿褰旾D锛屽搴� account_expense.id',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '褰掑睘閮ㄩ棬ID',
-  `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎锛�0-鍚︼紝1-鏄�',
-  PRIMARY KEY (`id`) USING BTREE,
-  UNIQUE INDEX `uk_fin_reimbursement_bill_no`(`bill_no` ASC) USING BTREE,
-  INDEX `idx_fin_reimbursement_type_status`(`reimbursement_type` ASC, `bill_status` ASC) USING BTREE,
-  INDEX `idx_fin_reimbursement_applicant`(`applicant_id` ASC) USING BTREE,
-  INDEX `idx_fin_reimbursement_approval_instance`(`approval_instance_id` ASC) USING BTREE,
-  INDEX `idx_fin_reimbursement_apply_amount`(`apply_amount` ASC) USING BTREE,
-  INDEX `idx_fin_reimbursement_create_time`(`create_time` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '鎶ラ攢鍗曚富琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for fin_reimbursement_detail
--- ----------------------------
-DROP TABLE IF EXISTS `fin_reimbursement_detail`;
-CREATE TABLE `fin_reimbursement_detail`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `reimbursement_id` bigint NOT NULL COMMENT '鎶ラ攢鍗旾D锛屽搴� fin_reimbursement.id',
-  `row_no` int NOT NULL DEFAULT 1 COMMENT '鏄庣粏琛屽彿',
-  `invoice_date` date NULL DEFAULT NULL COMMENT '鍙戠エ鏃ユ湡',
-  `expense_category` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '璐圭敤绉戠洰',
-  `amount` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '閲戦',
-  `description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鎻忚堪',
-  `invoice_no` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍙戠エ鍙风爜',
-  `invoice_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍙戠エ绫诲瀷',
-  `invoice_amount` decimal(18, 2) NULL DEFAULT NULL COMMENT '绁ㄩ潰閲戦',
-  `tax_rate` decimal(8, 2) NULL DEFAULT NULL COMMENT '绋庣巼',
-  `tax_amount` decimal(18, 2) NULL DEFAULT NULL COMMENT '绋庨',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '褰掑睘閮ㄩ棬ID',
-  `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎锛�0-鍚︼紝1-鏄�',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_fin_reimbursement_detail_reimbursement`(`reimbursement_id` ASC) USING BTREE,
-  INDEX `idx_fin_reimbursement_detail_category`(`expense_category` ASC) USING BTREE,
-  INDEX `idx_fin_reimbursement_detail_invoice_date`(`invoice_date` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '鎶ラ攢鍗曟槑缁嗚〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for fin_reimbursement_travel
--- ----------------------------
-DROP TABLE IF EXISTS `fin_reimbursement_travel`;
-CREATE TABLE `fin_reimbursement_travel`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `reimbursement_id` bigint NOT NULL COMMENT '鎶ラ攢鍗旾D锛屽搴� fin_reimbursement.id',
-  `start_time` datetime NOT NULL COMMENT '鍑哄樊寮�濮嬫椂闂�',
-  `end_time` datetime NOT NULL COMMENT '鍑哄樊缁撴潫鏃堕棿',
-  `travel_days` decimal(8, 2) NULL DEFAULT NULL COMMENT '鍑哄樊澶╂暟',
-  `departure_city` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鍑哄樊鍦�/鍑哄彂鍩庡競',
-  `destination_city` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鐩殑鍦�/鐩殑鍩庡競',
-  `hotel_standard` decimal(18, 4) NULL DEFAULT 0.0000 COMMENT '閰掑簵鏍囧噯',
-  `lodging_days` decimal(8, 4) NULL DEFAULT 0.0000 COMMENT '浣忓澶╂暟',
-  `meal_allowance` decimal(18, 4) NULL DEFAULT 0.0000 COMMENT '鐢熸椿琛ヨ创',
-  `transport_allowance` decimal(18, 4) NULL DEFAULT 0.0000 COMMENT '浜ら�氳ˉ璐�',
-  `lodging_limit` decimal(18, 4) NULL DEFAULT 0.0000 COMMENT '浣忓闄愰',
-  `standard_tag` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鐗规壒鏍囪鏂囨湰锛屽鍦ㄦ爣鍑嗚寖鍥村唴/瓒呮爣鐗规壒',
-  `within_standard` tinyint NOT NULL DEFAULT 1 COMMENT '鏄惁鍦ㄦ爣鍑嗗唴锛�1-鏄紝0-鍚�',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '褰掑睘閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  UNIQUE INDEX `uk_fin_reimbursement_travel_reimbursement`(`reimbursement_id` ASC) USING BTREE,
-  INDEX `idx_fin_reimbursement_travel_start_end`(`start_time` ASC, `end_time` ASC) USING BTREE,
-  INDEX `idx_fin_reimbursement_travel_city`(`departure_city` ASC, `destination_city` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '宸梾鎶ラ攢鎵╁睍琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for fin_voucher
--- ----------------------------
-DROP TABLE IF EXISTS `fin_voucher`;
-CREATE TABLE `fin_voucher`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `voucher_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鍑瘉瀛楀彿',
-  `voucher_date` date NOT NULL COMMENT '鍑瘉鏃ユ湡',
-  `summary` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鎽樿',
-  `debit` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '鍊熸柟鍚堣',
-  `credit` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '璐锋柟鍚堣',
-  `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍒跺崟浜�',
-  `status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'unposted' COMMENT '鐘舵��: unposted/posted/cancelled',
-  `attachment_count` int NOT NULL DEFAULT 0 COMMENT '闄勪欢寮犳暟',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  UNIQUE INDEX `uk_fin_voucher_no`(`voucher_no` ASC) USING BTREE,
-  INDEX `idx_fin_voucher_date`(`voucher_date` ASC) USING BTREE,
-  INDEX `idx_fin_voucher_status`(`status` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '鍑瘉涓昏〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for fin_voucher_entry
--- ----------------------------
-DROP TABLE IF EXISTS `fin_voucher_entry`;
-CREATE TABLE `fin_voucher_entry`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `voucher_id` bigint NOT NULL COMMENT '鍑瘉ID',
-  `row_no` int NOT NULL DEFAULT 1 COMMENT '琛屽彿',
-  `subject_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '绉戠洰缂栫爜',
-  `subject_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '绉戠洰鍚嶇О',
-  `summary` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鎽樿',
-  `debit` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '鍊熸柟閲戦',
-  `credit` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '璐锋柟閲戦',
-  `auxiliary_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '杈呭姪鏍哥畻绫诲瀷',
-  `auxiliary_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '杈呭姪鏍哥畻瀵硅薄ID',
-  `auxiliary_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '杈呭姪鏍哥畻瀵硅薄鍚嶇О',
-  `create_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_fin_voucher_entry_voucher`(`voucher_id` ASC) USING BTREE,
-  INDEX `idx_fin_voucher_entry_subject`(`subject_code` ASC) USING BTREE,
-  INDEX `idx_fin_voucher_entry_aux`(`auxiliary_type` ASC, `auxiliary_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '鍑瘉鍒嗗綍' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for gas_tank_warning
--- ----------------------------
-DROP TABLE IF EXISTS `gas_tank_warning`;
-CREATE TABLE `gas_tank_warning`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `tank_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍌ㄦ皵缃愮紪鐮�',
-  `tank_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍌ㄦ皵缃愬悕绉�',
-  `tank_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍌ㄦ皵缃愮被鍨�',
-  `specification_model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `volume` bigint NULL DEFAULT NULL COMMENT '瀹圭Н(m鲁)',
-  `current_gas_level` bigint NULL DEFAULT NULL COMMENT '褰撳墠姘斾綋閲�',
-  `safety_gas_level` bigint NULL DEFAULT NULL COMMENT '瀹夊叏姘斾綋閲�',
-  `min_gas_level` bigint NULL DEFAULT NULL COMMENT '鏈�浣庢皵浣撻噺',
-  `max_gas_level` bigint NULL DEFAULT NULL COMMENT '鏈�楂樻皵浣撻噺',
-  `current_pressure` decimal(10, 1) NULL DEFAULT NULL COMMENT '褰撳墠鍘嬪姏(MPa)',
-  `warning_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '棰勮绫诲瀷',
-  `warning_level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '棰勮绾у埆',
-  `warning_threshold` bigint NULL DEFAULT NULL COMMENT '棰勮闃堝��',
-  `is_enabled` int NULL DEFAULT NULL COMMENT '鏄惁鍚敤',
-  `warning_time` datetime NULL DEFAULT NULL COMMENT '棰勮鏃堕棿',
-  `warning_duration` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '棰勮鎸佺画澶╂暟',
-  `last_update_time` datetime NULL DEFAULT NULL COMMENT '鏈�鍚庢洿鏂版椂闂�',
-  `expected_refill_time` datetime NULL DEFAULT NULL COMMENT '棰勮鍏呰鏃堕棿',
-  `expected_shortage_time` datetime NULL DEFAULT NULL COMMENT '棰勮缂烘皵鏃堕棿',
-  `warning_rule` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '褰�???鏃惰Е鍙戦璀�-棰勮瑙勫垯',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '搴撳瓨棰勮-姘旂綈璀﹀憡' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for gen_table
--- ----------------------------
-DROP TABLE IF EXISTS `gen_table`;
-CREATE TABLE `gen_table`  (
-  `table_id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
-  `table_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '琛ㄥ悕绉�',
-  `table_comment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '琛ㄦ弿杩�',
-  `sub_table_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏宠仈瀛愯〃鐨勮〃鍚�',
-  `sub_table_fk_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀛愯〃鍏宠仈鐨勫閿悕',
-  `class_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '瀹炰綋绫诲悕绉�',
-  `tpl_category` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT 'crud' COMMENT '浣跨敤鐨勬ā鏉匡紙crud鍗曡〃鎿嶄綔 tree鏍戣〃鎿嶄綔锛�',
-  `tpl_web_type` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍓嶇妯℃澘绫诲瀷锛坋lement-ui妯$増 element-plus妯$増锛�',
-  `package_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢熸垚鍖呰矾寰�',
-  `module_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢熸垚妯″潡鍚�',
-  `business_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢熸垚涓氬姟鍚�',
-  `function_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢熸垚鍔熻兘鍚�',
-  `function_author` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢熸垚鍔熻兘浣滆��',
-  `gen_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鐢熸垚浠g爜鏂瑰紡锛�0zip鍘嬬缉鍖� 1鑷畾涔夎矾寰勶級',
-  `gen_path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '/' COMMENT '鐢熸垚璺緞锛堜笉濉粯璁ら」鐩矾寰勶級',
-  `options` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏跺畠鐢熸垚閫夐」',
-  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`table_id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浠g爜鐢熸垚涓氬姟琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for gen_table_column
--- ----------------------------
-DROP TABLE IF EXISTS `gen_table_column`;
-CREATE TABLE `gen_table_column`  (
-  `column_id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
-  `table_id` bigint NULL DEFAULT NULL COMMENT '褰掑睘琛ㄧ紪鍙�',
-  `column_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒楀悕绉�',
-  `column_comment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒楁弿杩�',
-  `column_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒楃被鍨�',
-  `java_type` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'JAVA绫诲瀷',
-  `java_field` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'JAVA瀛楁鍚�',
-  `is_pk` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏄惁涓婚敭锛�1鏄級',
-  `is_increment` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏄惁鑷锛�1鏄級',
-  `is_required` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏄惁蹇呭~锛�1鏄級',
-  `is_insert` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏄惁涓烘彃鍏ュ瓧娈碉紙1鏄級',
-  `is_edit` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏄惁缂栬緫瀛楁锛�1鏄級',
-  `is_list` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏄惁鍒楄〃瀛楁锛�1鏄級',
-  `is_query` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏄惁鏌ヨ瀛楁锛�1鏄級',
-  `query_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT 'EQ' COMMENT '鏌ヨ鏂瑰紡锛堢瓑浜庛�佷笉绛変簬銆佸ぇ浜庛�佸皬浜庛�佽寖鍥达級',
-  `html_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏄剧ず绫诲瀷锛堟枃鏈銆佹枃鏈煙銆佷笅鎷夋銆佸閫夋銆佸崟閫夋銆佹棩鏈熸帶浠讹級',
-  `dict_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '瀛楀吀绫诲瀷',
-  `sort` int NULL DEFAULT NULL COMMENT '鎺掑簭',
-  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`column_id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浠g爜鐢熸垚涓氬姟琛ㄥ瓧娈�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for holiday_application
--- ----------------------------
-DROP TABLE IF EXISTS `holiday_application`;
-CREATE TABLE `holiday_application`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `staff_id` int NULL DEFAULT NULL COMMENT '鍛樺伐id',
-  `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍋囨湡绫诲瀷',
-  `start_date` datetime NULL DEFAULT NULL COMMENT '寮�濮嬫棩鏈�',
-  `end_date` datetime NULL DEFAULT NULL COMMENT '缁撴潫鏃ユ湡',
-  `days` int NULL DEFAULT NULL COMMENT '澶╂暟',
-  `reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢宠鍘熷洜',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐘舵��',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍋囨湡鐢宠' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for holiday_settings
--- ----------------------------
-DROP TABLE IF EXISTS `holiday_settings`;
-CREATE TABLE `holiday_settings`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍋囨湡鍚嶇О',
-  `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍋囨湡绫诲瀷',
-  `start_date` datetime NULL DEFAULT NULL COMMENT '寮�濮嬫棩鏈�',
-  `end_date` datetime NULL DEFAULT NULL COMMENT '缁撴潫鏃ユ湡',
-  `days` int NULL DEFAULT NULL COMMENT '澶╂暟',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐘舵��',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍋囨湡璁剧疆' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for inbound_management
--- ----------------------------
-DROP TABLE IF EXISTS `inbound_management`;
-CREATE TABLE `inbound_management`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '搴忓彿',
-  `order_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁㈠崟鍙�',
-  `arrival_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒拌揣鍗曞彿',
-  `supplier_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉�',
-  `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒拌揣鐘舵��',
-  `arrival_time` datetime NULL DEFAULT NULL COMMENT '鍒拌揣鏃堕棿',
-  `arrival_quantity` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒拌揣鏁伴噺',
-  `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '澶囨敞',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閲囪喘鍒拌揣琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for inspection_task
--- ----------------------------
-DROP TABLE IF EXISTS `inspection_task`;
-CREATE TABLE `inspection_task`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '宸℃浠诲姟鍞竴鏍囪瘑',
-  `task_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧鍚嶇О',
-  `inspection_project` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸℃椤圭洰',
-  `task_id` int NULL DEFAULT NULL COMMENT '璁惧id',
-  `inspector_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `inspector` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵ц宸℃鐨勪汉鍛樺鍚�',
-  `remarks` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '浠诲姟闄勫姞璇存槑鎴栫壒娈婃儏鍐佃褰�',
-  `inspection_result` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸℃缁撴灉 0寮傚父 1姝e父',
-  `abnormal_description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '寮傚父鎻忚堪',
-  `device_repair_id` bigint NULL DEFAULT NULL COMMENT '鍏宠仈缁翠慨鍗旾D',
-  `acceptance_user_id` bigint NULL DEFAULT NULL COMMENT '楠屾敹浜篒D',
-  `acceptance_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '楠屾敹浜�',
-  `registrant_id` bigint NULL DEFAULT NULL,
-  `registrant` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浠诲姟鐧昏浜哄鍚�',
-  `frequency_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '棰戞',
-  `inspection_location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸℃鍦扮偣璇︾粏鎻忚堪',
-  `frequency_detail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏃堕棿缁嗚妭',
-  `deleted` int NOT NULL DEFAULT 0 COMMENT '杞垹闄ゆ爣蹇楋紝0=鏈垹闄わ紝1=宸插垹闄�',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓璇ヨ褰曠殑鐢ㄦ埛',
-  `create_time` datetime(6) NULL DEFAULT NULL COMMENT '璁板綍鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏈�鍚庝慨鏀硅璁板綍鐨勭敤鎴�',
-  `update_time` datetime(6) NULL DEFAULT NULL COMMENT '璁板綍鏈�鍚庢洿鏂版椂闂�',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_inspection_task_device_repair_id`(`device_repair_id` ASC) USING BTREE,
-  INDEX `idx_inspection_task_inspection_result`(`inspection_result` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 22 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '宸℃浠诲姟琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for invoice_ledger
--- ----------------------------
-DROP TABLE IF EXISTS `invoice_ledger`;
-CREATE TABLE `invoice_ledger`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `invoice_registration_product_id` bigint NULL DEFAULT NULL COMMENT '浜у搧寮�绁ㄧ櫥璁拌褰曡〃涓婚敭',
-  `invoice_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙戠エ鍙�',
-  `invoice_total` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍙戠エ閲戦',
-  `invoice_person` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '寮�绁ㄤ汉',
-  `invoice_date` datetime NULL DEFAULT NULL COMMENT '寮�绁ㄦ棩鏈�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 666 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '寮�绁ㄥ彴璐�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for invoice_ledger_file
--- ----------------------------
-DROP TABLE IF EXISTS `invoice_ledger_file`;
-CREATE TABLE `invoice_ledger_file`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢鍚嶇О',
-  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢璺緞',
-  `file_size` int NULL DEFAULT NULL COMMENT '鏂囦欢澶у皬',
-  `invoice_ledger_id` bigint NULL DEFAULT NULL COMMENT '寮�绁ㄥ彴璐D',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 49 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '寮�绁ㄥ彴璐﹂檮浠惰〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for invoice_purchase
--- ----------------------------
-DROP TABLE IF EXISTS `invoice_purchase`;
-CREATE TABLE `invoice_purchase`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `purchase_contract_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '閲囪喘鍚堝悓鍙�',
-  `sales_contract_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '閿�鍞悎鍚屽彿',
-  `supplier_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渚涘簲鍟嗗悕绉�',
-  `invoice_number` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍙戠エ鍙�',
-  `invoice_amount` decimal(10, 2) NOT NULL COMMENT '鍙戠エ閲戦锛堝厓锛�',
-  `tax_rate` decimal(5, 2) NOT NULL COMMENT '绋庣巼',
-  `iss_uer_id` int NULL DEFAULT NULL,
-  `iss_uer` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '寮�绁ㄤ汉',
-  `issue_date` date NOT NULL COMMENT '寮�绁ㄦ棩鏈�',
-  `invoice_file` longblob NULL COMMENT '鍙戠エ鏂囦欢锛圥DF鏍煎紡锛�',
-  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `purchase_ledger_id` int NULL DEFAULT NULL,
-  `sales_ledger_id` int NULL DEFAULT NULL COMMENT '鍏宠仈閿�鍞彴璐︿富琛ㄤ富閿�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍙戠エ淇℃伅琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for invoice_registration
--- ----------------------------
-DROP TABLE IF EXISTS `invoice_registration`;
-CREATE TABLE `invoice_registration`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `sales_ledger_id` bigint NULL DEFAULT NULL COMMENT '閿�鍞彴璐ales_ledger涓婚敭',
-  `sales_contract_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閿�鍞悎鍚屽彿',
-  `customer_id` bigint NULL DEFAULT NULL COMMENT '瀹㈡埛鍚嶇ОID',
-  `salesman` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓氬姟鍛�',
-  `project_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '椤圭洰鍚嶇О',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 503 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '寮�绁ㄧ櫥璁拌褰曡〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for invoice_registration_product
--- ----------------------------
-DROP TABLE IF EXISTS `invoice_registration_product`;
-CREATE TABLE `invoice_registration_product`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `sales_ledger_id` bigint NOT NULL COMMENT '鍏宠仈閿�鍞彴璐︿富琛ㄤ富閿�',
-  `sales_ledger_product_id` bigint NULL DEFAULT NULL COMMENT '鍏宠仈sales_ledger_product涓婚敭',
-  `invoice_registration_id` bigint NULL DEFAULT NULL COMMENT '寮�绁ㄧ櫥璁拌〃invoice_registration涓婚敭',
-  `product_category` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜у搧澶х被',
-  `specification_model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `unit` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `quantity` decimal(18, 2) NOT NULL COMMENT '鏁伴噺',
-  `tax_rate` decimal(5, 2) NOT NULL COMMENT '绋庣巼',
-  `tax_inclusive_unit_price` decimal(18, 2) NOT NULL COMMENT '鍚◣鍗曚环',
-  `tax_inclusive_total_price` decimal(18, 2) NOT NULL COMMENT '鍚◣鎬讳环',
-  `tax_exclusive_total_price` decimal(18, 2) NOT NULL COMMENT '涓嶅惈绋庢�讳环',
-  `invoice_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙戠エ绫诲瀷',
-  `invoice_num` decimal(10, 2) NULL DEFAULT NULL COMMENT '寮�绁ㄦ暟',
-  `invoice_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '寮�绁ㄩ噾棰�',
-  `no_invoice_num` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏈紑绁ㄦ暟',
-  `no_invoice_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏈紑绁ㄩ噾棰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 666 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浜у搧寮�绁ㄧ櫥璁拌褰曡〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for knowledge_base
--- ----------------------------
-DROP TABLE IF EXISTS `knowledge_base`;
-CREATE TABLE `knowledge_base`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐭ヨ瘑鏍囬',
-  `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐭ヨ瘑绫诲瀷',
-  `scenario` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閫傜敤鍦烘櫙',
-  `efficiency` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙e喅鏁堢巼',
-  `problem` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '闂鎻忚堪',
-  `solution` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '瑙e喅鏂规',
-  `key_points` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '鍏抽敭瑕佺偣',
-  `creator` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `usage_count` int NULL DEFAULT 0 COMMENT '浣跨敤娆℃暟',
-  `file_count` int NULL DEFAULT 0 COMMENT '鏂囦欢鏁伴噺',
-  `total_chunk_count` int NULL DEFAULT 0 COMMENT '鎬诲垏鐗囨暟閲�',
-  `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐭ヨ瘑搴撴弿杩�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP,
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  `create_user` int NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` bigint NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐭ヨ瘑搴撹〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for knowledge_base_vector
--- ----------------------------
-DROP TABLE IF EXISTS `knowledge_base_vector`;
-CREATE TABLE `knowledge_base_vector`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `knowledge_base_id` bigint NOT NULL COMMENT '鍏宠仈鐭ヨ瘑搴揑D',
-  `storage_blob_id` bigint NOT NULL COMMENT '鍏宠仈鏂囦欢blob ID',
-  `file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏂囦欢鍚嶇О',
-  `file_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏂囦欢绫诲瀷',
-  `vector_status` tinyint NULL DEFAULT 0 COMMENT '鍚戦噺鍖栫姸鎬�: 0-寰呭鐞�, 1-澶勭悊涓�, 2-宸插畬鎴�, 3-澶辫触',
-  `vector_error` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍚戦噺鍖栧け璐ュ師鍥�',
-  `chunk_count` int NULL DEFAULT 0 COMMENT '鍒囩墖鏁伴噺',
-  `namespace` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍚戦噺鍛藉悕绌洪棿',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP,
-  `create_user` int NULL DEFAULT NULL,
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` bigint NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_knowledge_base_id`(`knowledge_base_id` ASC) USING BTREE,
-  INDEX `idx_storage_blob_id`(`storage_blob_id` ASC) USING BTREE,
-  INDEX `idx_vector_status`(`vector_status` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐭ヨ瘑搴撴枃浠跺悜閲忚褰曡〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for labor_issue
--- ----------------------------
-DROP TABLE IF EXISTS `labor_issue`;
-CREATE TABLE `labor_issue`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `order_no` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '鍔充繚鍗曞彿',
-  `staff_id` bigint NULL DEFAULT NULL COMMENT '鍛樺伐id',
-  `dict_type` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '鍔充繚绫诲瀷锛堝瓧鍏革級',
-  `dict_id` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '瀛楀吀id',
-  `num` bigint NULL DEFAULT NULL COMMENT '鍙戞斁鏁伴噺',
-  `factory_date` date NULL DEFAULT NULL COMMENT '杩涘巶鏃ユ湡',
-  `Issue_date` date NULL DEFAULT NULL COMMENT '鍙戞斁鏃ユ湡',
-  `adopted_date` date NULL DEFAULT NULL COMMENT '棰嗙敤鏃ユ湡',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '鍔充繚鍙戞斁琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for loss
--- ----------------------------
-DROP TABLE IF EXISTS `loss`;
-CREATE TABLE `loss`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `rate` decimal(10, 2) NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for maintenance_task
--- ----------------------------
-DROP TABLE IF EXISTS `maintenance_task`;
-CREATE TABLE `maintenance_task`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `task_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璁惧鍚嶇О',
-  `task_id` int NULL DEFAULT NULL COMMENT '璁惧id',
-  `frequency_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '棰戞',
-  `frequency_detail` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `next_execution_time` datetime(6) NULL DEFAULT NULL,
-  `last_execution_time` datetime(6) NULL DEFAULT NULL,
-  `is_active` tinyint(1) NULL DEFAULT NULL,
-  `remarks` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '澶囨敞',
-  `registrant_id` bigint NULL DEFAULT NULL COMMENT '褰曞叆浜篿d',
-  `registrant` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '褰曞叆浜�',
-  `registration_date` date NOT NULL COMMENT '褰曞叆鏃ユ湡',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `deleted` int NOT NULL DEFAULT 0 COMMENT '杞垹闄ゆ爣蹇楋紝0=鏈垹闄わ紝1=宸插垹闄�',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓璇ヨ褰曠殑鐢ㄦ埛',
-  `create_time` datetime(6) NULL DEFAULT NULL COMMENT '璁板綍鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏈�鍚庝慨鏀硅璁板綍鐨勭敤鎴�',
-  `update_time` datetime(6) NULL DEFAULT NULL COMMENT '璁板綍鏈�鍚庢洿鏂版椂闂�',
-  `tenant_id` int NULL DEFAULT NULL,
-  `device_model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `machinery_category` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧椤圭洰',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `maintenance_person` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '淇濆吇浜�',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹氭椂淇濆吇浠诲姟琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for measuring_instrument_ledger
--- ----------------------------
-DROP TABLE IF EXISTS `measuring_instrument_ledger`;
-CREATE TABLE `measuring_instrument_ledger`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `user_id` bigint NULL DEFAULT NULL COMMENT '褰曞叆浜篿d',
-  `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '褰曞叆浜哄悕绉�',
-  `code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '璁¢噺鍣ㄥ叿缂栧彿',
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '璁¢噺鍣ㄥ叿鍚嶇О',
-  `model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `most_date` date NULL DEFAULT NULL COMMENT '鏈�杩戜竴娆℃瀹氭棩鏈�',
-  `valid` int NULL DEFAULT NULL COMMENT '妫�瀹氭湁鏁堟湡锛堝崟浣嶅ぉ锛�',
-  `next_date` date NULL DEFAULT NULL COMMENT '棰勮涓嬫妫�瀹氭棩鏈�',
-  `record_date` date NULL DEFAULT NULL COMMENT '褰曞叆鏃ユ湡',
-  `status` int NULL DEFAULT NULL COMMENT '鐘舵�侊紙1-鏈夋晥 2-閫炬湡锛�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `instation_location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '瀹夎浣嶇疆',
-  `unit` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '妫�瀹氬崟浣�',
-  `cycle` int NULL DEFAULT NULL COMMENT '妫�瀹氬懆鏈燂紙澶╋級',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '璁¢噺鍣ㄥ叿鍙拌处' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for measuring_instrument_ledger_record
--- ----------------------------
-DROP TABLE IF EXISTS `measuring_instrument_ledger_record`;
-CREATE TABLE `measuring_instrument_ledger_record`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `measuring_instrument_ledger_id` bigint NULL DEFAULT NULL COMMENT '璁¢噺鍣ㄥ叿鍙拌处id',
-  `user_id` bigint NULL DEFAULT NULL COMMENT '妫�瀹歩d',
-  `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '妫�瀹氫汉鍚嶇О',
-  `record_date` date NULL DEFAULT NULL COMMENT '妫�瀹氭棩鏈�',
-  `entry_date` date NULL DEFAULT NULL COMMENT '褰曞叆鏃ユ湡',
-  `valid` int NULL DEFAULT NULL COMMENT '妫�瀹氭湁鏁堟湡锛堝崟浣嶅ぉ锛�',
-  `status` int NULL DEFAULT NULL COMMENT '鐘舵�侊紙1-鏈夋晥 2-閫炬湡锛�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '璁¢噺鍣ㄥ叿鍙拌处璁板綍' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for meet_application
--- ----------------------------
-DROP TABLE IF EXISTS `meet_application`;
-CREATE TABLE `meet_application`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐢宠ID',
-  `title` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浼氳涓婚',
-  `room_id` bigint NOT NULL COMMENT '浼氳瀹D',
-  `host` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '涓绘寔浜�',
-  `meeting_date` date NOT NULL COMMENT '浼氳鏃ユ湡',
-  `start_time` datetime NOT NULL COMMENT '寮�濮嬫椂闂�',
-  `end_time` datetime NOT NULL COMMENT '缁撴潫鏃堕棿',
-  `participants` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍙備細浜哄憳锛圝SON鏍煎紡瀛樺偍ID鏁扮粍锛�',
-  `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '浼氳璇存槑',
-  `application_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'approval' COMMENT '鐢宠绫诲瀷锛坅pproval:瀹℃壒娴佺▼, department:閮ㄩ棬绾�, notification:閫氱煡鍙戝竷锛�',
-  `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵�侊紙0:寰呭鎵�, 1:宸查�氳繃, 2:宸叉嫆缁�, 3:宸插彇娑堬級',
-  `applicant` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢宠浜�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `publish_status` int NULL DEFAULT 0 COMMENT '鍙戝竷鐘舵��',
-  `publish_comment` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '鍙戝竷璇勮',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_title`(`title` ASC) USING BTREE,
-  INDEX `idx_meeting_date`(`meeting_date` ASC) USING BTREE,
-  INDEX `idx_applicant`(`applicant` ASC) USING BTREE,
-  INDEX `idx_status`(`status` ASC) USING BTREE,
-  INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
-  INDEX `idx_tenant_id`(`tenant_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '浼氳鐢宠琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for meet_draft
--- ----------------------------
-DROP TABLE IF EXISTS `meet_draft`;
-CREATE TABLE `meet_draft`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑽夌ID',
-  `room_id` bigint NOT NULL COMMENT '浼氳缂栧彿',
-  `title` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浼氳涓婚',
-  `host` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '涓绘寔浜�',
-  `meeting_date` date NOT NULL COMMENT '浼氳鏃ユ湡',
-  `start_time` datetime NOT NULL COMMENT '寮�濮嬫椂闂�',
-  `end_time` datetime NOT NULL COMMENT '缁撴潫鏃堕棿',
-  `participants` int NOT NULL DEFAULT 0 COMMENT '鍙備細浜烘暟',
-  `participant_list` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '鍙備細浜哄憳鍒楄〃',
-  `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '浼氳璇存槑',
-  `creator` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍒涘缓浜�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '浼氳鑽夌琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for meeting_minutes
--- ----------------------------
-DROP TABLE IF EXISTS `meeting_minutes`;
-CREATE TABLE `meeting_minutes`  (
-  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '绾ID',
-  `meeting_id` bigint UNSIGNED NOT NULL COMMENT '鍏宠仈鐨勪細璁甀D',
-  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '绾鏍囬',
-  `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '绾鍐呭锛堝瘜鏂囨湰锛�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_meeting_id`(`meeting_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浼氳绾琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for meeting_room
--- ----------------------------
-DROP TABLE IF EXISTS `meeting_room`;
-CREATE TABLE `meeting_room`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '浼氳瀹D',
-  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浼氳瀹ゅ悕绉�',
-  `location` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浣嶇疆',
-  `capacity` int NOT NULL DEFAULT 10 COMMENT '瀹圭撼浜烘暟',
-  `equipment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '璁惧閰嶇疆锛堥�楀彿鍒嗛殧锛�',
-  `status` tinyint NOT NULL DEFAULT 1 COMMENT '鐘舵�侊紙1:鍚敤 0:绂佺敤锛�',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '浼氳瀹よ〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for notice
--- ----------------------------
-DROP TABLE IF EXISTS `notice`;
-CREATE TABLE `notice`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍏憡ID',
-  `title` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '鍏憡鏍囬',
-  `type` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '1' COMMENT '鍏憡绫诲瀷锛�1鏀惧亣閫氱煡 2璁惧缁翠慨閫氱煡锛�',
-  `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵�侊紙0鑽夌 1鍙戝竷 2宸蹭笅绾匡級',
-  `content` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '鍏憡鍐呭',
-  `priority` tinyint NOT NULL DEFAULT 0 COMMENT '浼樺厛绾�(1鏅�� 2閲嶈 3绱ф��)',
-  `create_user` bigint NOT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` timestamp NOT NULL COMMENT '鍒涘缓鏃堕棿',
-  `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '绉熸埛id',
-  `expiration_date` date NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '閫氱煡鍏憡琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for notice_type
--- ----------------------------
-DROP TABLE IF EXISTS `notice_type`;
-CREATE TABLE `notice_type`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `notice_type` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '閫氱煡鍏憡鐨勫叕鍛婄被鍨�',
-  `tenant_id` int NULL DEFAULT NULL,
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '閫氱煡鍏憡鐨勫叕鍛婄被鍨嬬淮鎶�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for notification_management
--- ----------------------------
-DROP TABLE IF EXISTS `notification_management`;
-CREATE TABLE `notification_management`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閫氱煡鏍囬',
-  `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閫氱煡绫诲瀷',
-  `priority` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浼樺厛绾�',
-  `expire_date` datetime NULL DEFAULT NULL COMMENT '鏈夋晥鏈熸椂闂�',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐘舵��',
-  `departments` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎺ユ敹閮ㄩ棬',
-  `sync_methods` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍚屾鏂瑰紡',
-  `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閫氱煡鍐呭',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '琛屾斂绠$悊-閫氱煡绠$悊' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for office_supplies
--- ----------------------------
-DROP TABLE IF EXISTS `office_supplies`;
-CREATE TABLE `office_supplies`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '娉ㄨВ',
-  `code` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '缂栧彿',
-  `applicant` varchar(15) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鐢宠浜�',
-  `item_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鐗╁搧鍚嶇О',
-  `dept` varchar(15) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '閮ㄩ棬',
-  `material_type` int NULL DEFAULT NULL COMMENT '鐗╄祫绫诲瀷锛�1-鍏朵粬 2-娓呮磥鐢ㄥ搧 3-鐢靛瓙鐢ㄥ搧 4-鐢靛瓙璁惧锛�',
-  `apply_num` int NULL DEFAULT NULL COMMENT '鐢宠鏁伴噺',
-  `approval_opinions` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '瀹℃壒鎰忚',
-  `reason` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鐢宠鍘熷洜',
-  `urgency` int NULL DEFAULT NULL COMMENT '绱ф�ョ▼搴︼紙1-鏅�� 2-绱ф�� 3-闈炲父绱ф�ワ級',
-  `status` int NULL DEFAULT NULL COMMENT '鐘舵�侊紙1-寰呭鎵� 2-宸叉嫆缁� 3-宸查�氳繃 4-宸插彂鏀撅級',
-  `apply_time` datetime NULL DEFAULT NULL COMMENT '鐢宠鏃堕棿',
-  `approval` varchar(15) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '瀹℃壒浜�',
-  `approval_time` datetime NULL DEFAULT NULL COMMENT '瀹℃壒鏃堕棿',
-  `issue_user` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '鍙戞斁浜�',
-  `issue_time` datetime NULL DEFAULT NULL COMMENT '鍙戞斁鏃堕棿',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for online_meeting
--- ----------------------------
-DROP TABLE IF EXISTS `online_meeting`;
-CREATE TABLE `online_meeting`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浼氳鏍囬',
-  `start_time` datetime NULL DEFAULT NULL COMMENT '寮�濮嬫椂闂�',
-  `duration` int NULL DEFAULT NULL COMMENT '浼氳鏃堕暱',
-  `platform` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浼氳骞冲彴',
-  `participants` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙備細浜哄憳',
-  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浼氳鎻忚堪',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '琛屾斂绠$悊-閫氱煡绠$悊-鍦ㄧ嚎浼氳' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for overtime_setting
--- ----------------------------
-DROP TABLE IF EXISTS `overtime_setting`;
-CREATE TABLE `overtime_setting`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍔犵彮瑙勫垯鍚嶇О',
-  `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍔犵彮绫诲瀷',
-  `start_time` time NULL DEFAULT NULL COMMENT '寮�濮嬫椂闂�',
-  `end_time` time NULL DEFAULT NULL COMMENT '缁撴潫鏃堕棿',
-  `rate` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍊嶇巼',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐘舵��',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍔犵彮璁剧疆' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for payment_registration
--- ----------------------------
-DROP TABLE IF EXISTS `payment_registration`;
-CREATE TABLE `payment_registration`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `sale_ledger_id` bigint NULL DEFAULT 0 COMMENT '閿�鍞彴璐d',
-  `sales_ledger_product_id` int NULL DEFAULT NULL COMMENT '閿�鍞骇鍝乮d',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `purchase_ledger_id` bigint NOT NULL DEFAULT 0 COMMENT '閲囪喘鍙拌处id',
-  `supplier_id` bigint NOT NULL DEFAULT 0 COMMENT '渚涘簲鍟唅d',
-  `ticket_registration_id` bigint NOT NULL DEFAULT 0 COMMENT '鍙戠エid',
-  `current_payment_amount` decimal(12, 2) NOT NULL COMMENT '鏈浠樻閲戦',
-  `payment_method` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浠樻褰㈠紡',
-  `registrant_id` bigint NOT NULL DEFAULT 0 COMMENT '鐧昏浜�',
-  `payment_date` date NOT NULL COMMENT '浠樻鏃ユ湡',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `registrationt_date` date NULL DEFAULT NULL COMMENT '鐧昏鏃ユ湡',
-  `tax_rate` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绋庣巼',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 45 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浠樻鐧昏琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for pda_version
--- ----------------------------
-DROP TABLE IF EXISTS `pda_version`;
-CREATE TABLE `pda_version`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍚嶇О',
-  `version` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐗堟湰',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'PDA鐗堟湰淇℃伅琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for personal_attendance_location_config
--- ----------------------------
-DROP TABLE IF EXISTS `personal_attendance_location_config`;
-CREATE TABLE `personal_attendance_location_config`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `sys_dept_id` int NOT NULL DEFAULT 0 COMMENT '閮ㄩ棬id',
-  `location_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍦扮偣鍚嶇О',
-  `longitude` double NULL DEFAULT NULL COMMENT '缁忓害',
-  `latitude` double NULL DEFAULT NULL COMMENT '绾害',
-  `radius` double NULL DEFAULT NULL COMMENT '鎵撳崱鑼冨洿',
-  `start_at` time NULL DEFAULT NULL COMMENT '涓婄彮鏃堕棿',
-  `end_at` time NULL DEFAULT NULL COMMENT '涓嬬彮鏃堕棿',
-  `shift` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐝',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  UNIQUE INDEX `shift`(`shift` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浜哄憳鎵撳崱瑙勫垯閰嶇疆' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for personal_attendance_records
--- ----------------------------
-DROP TABLE IF EXISTS `personal_attendance_records`;
-CREATE TABLE `personal_attendance_records`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `staff_on_job_id` bigint NOT NULL DEFAULT 0 COMMENT '鍛樺伐鍦ㄨ亴id',
-  `date` date NOT NULL COMMENT '鏃ユ湡',
-  `work_start_at` datetime NULL DEFAULT NULL COMMENT '宸ヤ綔寮�濮嬫椂闂�',
-  `work_end_at` datetime NULL DEFAULT NULL COMMENT '宸ヤ綔缁撴潫鏃堕棿',
-  `work_hours` decimal(5, 2) NULL DEFAULT NULL COMMENT '宸ヤ綔鏃堕暱',
-  `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵�� 0姝e父 1杩熷埌 2鏃╅��',
-  `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '澶囨敞',
-  `tenant_id` bigint NOT NULL COMMENT '绉熸埛id',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 65 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '涓汉鑰冨嫟璁板綍琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for personal_shift
--- ----------------------------
-DROP TABLE IF EXISTS `personal_shift`;
-CREATE TABLE `personal_shift`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `personal_attendance_location_config_id` int NULL DEFAULT NULL COMMENT '鐝(鎵撳崱瑙勫垯id)',
-  `staff_on_job_id` bigint NOT NULL DEFAULT 0 COMMENT '鍛樺伐鍦ㄨ亴id',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `work_time` datetime NULL DEFAULT NULL COMMENT '鎺掔彮鏃ユ湡',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 123 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for procurement_exception_record
--- ----------------------------
-DROP TABLE IF EXISTS `procurement_exception_record`;
-CREATE TABLE `procurement_exception_record`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `purchase_ledger_id` int NOT NULL COMMENT '閲囪喘鍙拌处id',
-  `exception_reason` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '寮傚父鍘熷洜',
-  `exception_num` decimal(18, 2) NULL DEFAULT NULL COMMENT '寮傚父鏁伴噺',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰卛d',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰卛d',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閲囪喘寮傚父璁板綍-涓嶅悎鏍肩墿鍝�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for procurement_plan
--- ----------------------------
-DROP TABLE IF EXISTS `procurement_plan`;
-CREATE TABLE `procurement_plan`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `code` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '缂栫爜',
-  `plan_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鍚嶇О',
-  `description` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鎻忚堪',
-  `status` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鐘舵��',
-  `is_system_preset` tinyint(1) NULL DEFAULT NULL COMMENT '鏄惁绯荤粺棰勭疆',
-  `consider_existing_stock` tinyint(1) NULL DEFAULT NULL,
-  `warehouse_control` tinyint(1) NULL DEFAULT NULL,
-  `calculate_total_demand` tinyint(1) NULL DEFAULT NULL,
-  `consider_safety_stock` tinyint(1) NULL DEFAULT NULL,
-  `consider_locked_stock` tinyint(1) NULL DEFAULT NULL,
-  `not_consider_material_aux` tinyint(1) NULL DEFAULT NULL,
-  `negative_stock_as_demand` tinyint(1) NULL DEFAULT NULL,
-  `summary_material` tinyint(1) NULL DEFAULT NULL,
-  `summary_aux_attributes` tinyint(1) NULL DEFAULT NULL,
-  `summary_demand_date` tinyint(1) NULL DEFAULT NULL,
-  `formula` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '璁$畻鍏紡',
-  `create_time` datetime NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `update_time` datetime NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin COMMENT = '閲囪喘璁″垝琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for procurement_price_management
--- ----------------------------
-DROP TABLE IF EXISTS `procurement_price_management`;
-CREATE TABLE `procurement_price_management`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `product_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鍟嗗搧鍚嶇О',
-  `specification` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `product_code` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鍟嗗搧缂栫爜',
-  `supplier_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '渚涘簲鍟�',
-  `base_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍩虹浠锋牸',
-  `unit` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `discount_type` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鎶樻墸绫诲瀷',
-  `discount_value` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鎶樻墸鍊�',
-  `discount_end_time` datetime NULL DEFAULT NULL COMMENT '鎶樻墸鏈夋晥鏈�',
-  `min_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏈�浣庝环鏍�',
-  `max_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏈�楂樹环鏍�',
-  `warning_threshold` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '棰勮闃堝��(%)',
-  `effective_time` datetime NULL DEFAULT NULL COMMENT '鐢熸晥鏃堕棿',
-  `expire_time` datetime NULL DEFAULT NULL COMMENT '澶辨晥鏃堕棿',
-  `reason` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '璋冧环鍘熷洜',
-  `remark` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin COMMENT = '閲囪喘浠锋牸绠$悊' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for procurement_record_out
--- ----------------------------
-DROP TABLE IF EXISTS `procurement_record_out`;
-CREATE TABLE `procurement_record_out`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `sales_ledger_product_id` int NOT NULL DEFAULT 0 COMMENT '浜у搧淇℃伅琛╥d',
-  `procurement_record_storage_id` int NOT NULL COMMENT '鍏ュ簱璁板綍琛╥d',
-  `inbound_batches` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍑哄簱鎵规',
-  `inbound_num` decimal(18, 2) NULL DEFAULT NULL COMMENT '鍑哄簱鏁伴噺',
-  `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍑哄簱鐢ㄦ埛鍚嶇О',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓鑰卛d',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰卛d',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `code` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '缂栧彿',
-  `type` int NULL DEFAULT NULL,
-  `product_model_id` bigint NULL DEFAULT NULL COMMENT '浜у搧瑙勬牸id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閲囪喘鍑哄簱璁板綍' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for procurement_record_storage
--- ----------------------------
-DROP TABLE IF EXISTS `procurement_record_storage`;
-CREATE TABLE `procurement_record_storage`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `sales_ledger_product_id` int NOT NULL COMMENT '浜у搧淇℃伅琛╥d',
-  `inbound_batches` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏ュ簱鎵规',
-  `total_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '鎬讳环',
-  `unit_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍗曚环',
-  `inbound_num` decimal(18, 2) NULL DEFAULT NULL COMMENT '鍏ュ簱鏁伴噺',
-  `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏ュ簱鐢ㄦ埛鍚嶇О',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰卛d',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰卛d',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `warn_num` decimal(10, 2) NULL DEFAULT NULL,
-  `type` int NULL DEFAULT 1,
-  `product_model_id` bigint NULL DEFAULT NULL COMMENT '浜у搧瑙勬牸id',
-  `quality_inspect_id` bigint NULL DEFAULT NULL COMMENT '璐ㄦid',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閲囪喘鍏ュ簱璁板綍' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for product
--- ----------------------------
-DROP TABLE IF EXISTS `product`;
-CREATE TABLE `product`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `parent_id` int NULL DEFAULT NULL COMMENT '鐖秈d',
-  `product_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜у搧',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 409 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浜у搧' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for product_borrow
--- ----------------------------
-DROP TABLE IF EXISTS `product_borrow`;
-CREATE TABLE `product_borrow`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `borrow_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '棰嗙敤鍗曞彿',
-  `product_model_id` bigint NOT NULL COMMENT '浜у搧瑙勬牸ID',
-  `batch_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵瑰彿',
-  `borrow_quantity` decimal(18, 4) NOT NULL COMMENT '棰嗙敤鏁伴噺',
-  `returned_quantity` decimal(18, 4) NULL DEFAULT 0.0000 COMMENT '宸插綊杩樻暟閲�',
-  `borrower_id` bigint NULL DEFAULT NULL COMMENT '棰嗙敤浜篒D',
-  `borrower_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '棰嗙敤浜哄鍚�',
-  `borrow_time` datetime NOT NULL COMMENT '棰嗙敤鏃堕棿',
-  `expected_return_time` datetime NULL DEFAULT NULL COMMENT '棰勮褰掕繕鏃堕棿',
-  `approval_status` tinyint NULL DEFAULT 0 COMMENT '瀹℃壒鐘舵�侊紙0-寰呭鎵癸紝1-宸查�氳繃锛�2-宸查┏鍥烇級',
-  `status` tinyint NULL DEFAULT 0 COMMENT '褰掕繕鐘舵�侊紙0-鏈綊杩橈紝1-閮ㄥ垎褰掕繕锛�2-宸插叏閮ㄥ綊杩橈級',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_borrow_no`(`borrow_no` ASC) USING BTREE,
-  INDEX `idx_product_model_id`(`product_model_id` ASC) USING BTREE,
-  INDEX `idx_borrower_id`(`borrower_id` ASC) USING BTREE,
-  INDEX `idx_approval_status`(`approval_status` ASC) USING BTREE,
-  INDEX `idx_status`(`status` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浜у搧棰嗙敤琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for product_borrow_return
--- ----------------------------
-DROP TABLE IF EXISTS `product_borrow_return`;
-CREATE TABLE `product_borrow_return`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `borrow_id` bigint NOT NULL COMMENT '棰嗙敤璁板綍ID',
-  `product_model_id` bigint NOT NULL COMMENT '浜у搧瑙勬牸ID',
-  `batch_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵瑰彿',
-  `return_quantity` decimal(18, 4) NOT NULL COMMENT '褰掕繕鏁伴噺',
-  `returner_id` bigint NULL DEFAULT NULL COMMENT '褰掕繕浜篒D',
-  `returner_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '褰掕繕浜哄鍚�',
-  `return_time` datetime NOT NULL COMMENT '褰掕繕鏃堕棿',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_borrow_id`(`borrow_id` ASC) USING BTREE,
-  INDEX `idx_product_model_id`(`product_model_id` ASC) USING BTREE,
-  INDEX `idx_returner_id`(`returner_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浜у搧褰掕繕璁板綍琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for product_model
--- ----------------------------
-DROP TABLE IF EXISTS `product_model`;
-CREATE TABLE `product_model`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `product_id` int NULL DEFAULT NULL COMMENT '鍏宠仈浜у搧id',
-  `model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勬牸淇″彿',
-  `unit` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `product_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 386 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浜у搧鍨嬪彿琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for product_record
--- ----------------------------
-DROP TABLE IF EXISTS `product_record`;
-CREATE TABLE `product_record`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `ticket_registration_id` int NULL DEFAULT NULL COMMENT '鏉ョエ鐧昏id',
-  `purchase_ledger_id` int NULL DEFAULT NULL COMMENT '閲囪喘鍙拌处id',
-  `product_category` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜у搧澶х被',
-  `specification_model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `unit` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `quantity` decimal(18, 0) NOT NULL COMMENT '鏁伴噺',
-  `tax_rate` decimal(5, 0) NOT NULL COMMENT '绋庣巼',
-  `tax_inclusive_unit_price` decimal(18, 2) NOT NULL COMMENT '鍚◣鍗曚环',
-  `tax_inclusive_total_price` decimal(18, 2) NOT NULL COMMENT '鍚◣鎬讳环',
-  `tax_exclusive_total_price` decimal(18, 2) NOT NULL COMMENT '涓嶅惈绋庢�讳环',
-  `invoice_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙戠エ绫诲瀷',
-  `type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '1.閿�鍞彴璐︼紝2.閲囪喘鍙拌处',
-  `tickets_num` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏈鏉ョエ鏁�',
-  `tickets_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏈鏉ョエ閲戦(鍏�)',
-  `future_tickets` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏈潵绁ㄦ暟',
-  `future_tickets_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏈潵绁ㄩ噾棰�(鍏�)',
-  `product_id` int NULL DEFAULT NULL COMMENT '浜у搧id',
-  `product_model_id` int NULL DEFAULT NULL COMMENT '鍨嬪彿id',
-  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `sale_ledger_project_id` int NULL DEFAULT NULL COMMENT 'sale_ledger_projectI_id',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閲囪喘鍙拌处浜у搧寮�绁ㄨ褰�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_account
--- ----------------------------
-DROP TABLE IF EXISTS `production_account`;
-CREATE TABLE `production_account`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `sales_ledger_id` bigint NULL DEFAULT NULL COMMENT '閿�鍞彴璐d',
-  `sales_ledger_product_id` bigint NULL DEFAULT NULL COMMENT '閿�鍞骇鍝佽鏍糹d',
-  `production_product_main_id` bigint NULL DEFAULT NULL COMMENT '鎶ュ伐琛╥d',
-  `scheduling_user_id` bigint NULL DEFAULT NULL COMMENT '鐢熶骇浜篿d',
-  `scheduling_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '鐢熶骇浜哄悕绉�',
-  `finished_num` decimal(18, 2) NULL DEFAULT 0.00 COMMENT '鐢熶骇鏁伴噺',
-  `work_hours` decimal(18, 2) NULL DEFAULT 0.00 COMMENT '宸ユ椂瀹氶',
-  `technology_operation_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '宸ュ簭鍚嶇О',
-  `scheduling_date` timestamp NULL DEFAULT NULL COMMENT '鐢熶骇鏃ユ湡',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 42 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '鐢熶骇鏍哥畻琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_bom_structure
--- ----------------------------
-DROP TABLE IF EXISTS `production_bom_structure`;
-CREATE TABLE `production_bom_structure`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `parent_id` bigint NULL DEFAULT NULL COMMENT '鐖惰妭鐐笽D',
-  `production_order_id` bigint NULL DEFAULT NULL COMMENT '鐢熶骇璁㈠崟id',
-  `product_model_id` bigint NOT NULL COMMENT '浜у搧瑙勬牸id',
-  `technology_operation_id` bigint NULL DEFAULT NULL COMMENT '宸ュ簭id',
-  `production_order_bom_id` bigint NULL DEFAULT NULL COMMENT '鐢熶骇璁㈠崟BOMid',
-  `unit_quantity` decimal(16, 4) NOT NULL COMMENT '鍗曚綅浜у嚭闇�瑕佹暟閲�',
-  `demanded_quantity` decimal(16, 4) NULL DEFAULT NULL COMMENT '闇�姹傛暟閲�',
-  `unit` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 327 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢熶骇璁㈠崟BOM浜у搧缁撴瀯' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_operation_main_param
--- ----------------------------
-DROP TABLE IF EXISTS `production_operation_main_param`;
-CREATE TABLE `production_operation_main_param`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `technology_routing_operation_param_id` bigint NOT NULL COMMENT '宸ヨ壓璺嚎宸ュ簭鍙傛暟琛╥d',
-  `param_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鍙傛暟缂栫爜(鍞竴鏍囪瘑)',
-  `param_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鍙傛暟鍚嶇О',
-  `param_type` tinyint NOT NULL COMMENT '鍙傛暟绫诲瀷(1鏁板瓧 2鏂囨湰 3涓嬫媺閫夋嫨 4鏃堕棿)',
-  `param_format` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍙傛暟鏍煎紡',
-  `unit` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `is_required` tinyint NULL DEFAULT 0 COMMENT '鏄惁蹇呭~',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `technology_param_id` bigint NULL DEFAULT NULL COMMENT '鍩虹鍙傛暟ID',
-  `technology_operation_id` bigint NULL DEFAULT NULL COMMENT '宸ュ簭id',
-  `technology_operation_param_id` bigint NULL DEFAULT NULL COMMENT '宸ュ簭鍙傛暟ID',
-  `technology_routing_operation_id` bigint NULL DEFAULT NULL COMMENT '宸ヨ壓璺嚎宸ュ簭ID',
-  `standard_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鏍囧噯鍊�',
-  `value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '杈撳叆鍊�',
-  `production_order_routing_operation_param_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鐢熶骇璁㈠崟宸ヨ壓璺嚎宸ュ簭鍙傛暟ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '鐢熶骇宸ュ崟鎶ュ伐鍙傛暟琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_operation_task
--- ----------------------------
-DROP TABLE IF EXISTS `production_operation_task`;
-CREATE TABLE `production_operation_task`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `production_order_routing_operation_id` bigint NOT NULL DEFAULT 0 COMMENT '鐢熶骇宸ヨ壓璺嚎宸ュ簭琛╥d',
-  `technology_routing_operation_id` bigint NOT NULL DEFAULT 0 COMMENT '宸ヨ壓璺嚎宸ュ簭琛╥d',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `work_order_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '宸ュ崟缂栧彿',
-  `plan_start_time` date NULL DEFAULT NULL COMMENT '璁″垝寮�濮嬫椂闂�',
-  `plan_end_time` date NULL DEFAULT NULL COMMENT '璁″垝缁撴潫鏃堕棿',
-  `actual_start_time` date NULL DEFAULT NULL COMMENT '瀹為檯寮�濮嬫椂闂�',
-  `actual_end_time` date NULL DEFAULT NULL COMMENT '瀹為檯缁撴潫鏃堕棿',
-  `status` int NOT NULL DEFAULT 0 COMMENT '鐘舵�� 1 寰呯‘璁� 2 寰呯敓浜� 3鐢熶骇涓� 4宸茬敓浜�',
-  `production_order_id` bigint NOT NULL DEFAULT 0 COMMENT '鐢熶骇璁㈠崟id',
-  `plan_quantity` decimal(16, 4) NULL DEFAULT NULL COMMENT '璁″垝鏁伴噺',
-  `complete_quantity` decimal(18, 2) NULL DEFAULT 0.00 COMMENT '瀹屾垚鏁伴噺',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `user_ids` json NULL COMMENT '鏉冮檺鐢ㄦ埛锛屾牸寮忥細[1,2,3]',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 238 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鐢熶骇宸ュ崟琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_order
--- ----------------------------
-DROP TABLE IF EXISTS `production_order`;
-CREATE TABLE `production_order`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `production_plan_ids` json NULL COMMENT '鐢熶骇璁″垝ID鍒楄〃锛屾牸寮忥細[1,2,3]',
-  `product_model_id` bigint NOT NULL DEFAULT 0 COMMENT '浜у搧瑙勬牸id',
-  `technology_routing_id` bigint NOT NULL DEFAULT 0 COMMENT '宸ヨ壓璺嚎id',
-  `nps_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '鐢熶骇璁㈠崟鍙�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `quantity` decimal(18, 2) NOT NULL COMMENT '闇�姹傛暟閲�',
-  `complete_quantity` decimal(18, 2) NULL DEFAULT NULL COMMENT '瀹屾垚鏁伴噺',
-  `start_time` datetime NULL DEFAULT NULL COMMENT '寮�濮嬫棩鏈�',
-  `end_time` datetime NULL DEFAULT NULL COMMENT '缁撴潫鏃ユ湡',
-  `plan_complete_time` date NULL DEFAULT NULL COMMENT '璁″垝瀹屾垚鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `status` int NULL DEFAULT 1 COMMENT '鐘舵�侊紙1.寰呭紑濮嬨��2.杩涜涓��3.宸插畬鎴愩��4.宸插彇娑堬級',
-  `is_end_order` tinyint(1) NULL DEFAULT 0 COMMENT '鏄惁缁撴潫',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 64 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢熶骇璁㈠崟琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_order_bom
--- ----------------------------
-DROP TABLE IF EXISTS `production_order_bom`;
-CREATE TABLE `production_order_bom`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `production_order_id` bigint NULL DEFAULT NULL COMMENT '鐢熶骇璁㈠崟id',
-  `product_model_id` bigint NOT NULL COMMENT '浜у搧瑙勬牸id',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `version` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐗堟湰鍙�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `bom_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'BOM缂栧彿',
-  `bom_id` bigint NOT NULL COMMENT 'bom鐨刬d',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 75 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢熶骇璁㈠崟BOM' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_order_pick
--- ----------------------------
-DROP TABLE IF EXISTS `production_order_pick`;
-CREATE TABLE `production_order_pick`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭id',
-  `product_model_id` int NULL DEFAULT NULL COMMENT '浜у搧瑙勬牸id',
-  `quantity` decimal(16, 2) NULL DEFAULT NULL COMMENT '鏁伴噺',
-  `batch_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵瑰彿',
-  `create_time` timestamp NULL DEFAULT NULL,
-  `update_time` timestamp NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `production_order_id` bigint NOT NULL DEFAULT 0 COMMENT '鐢熶骇璁㈠崟id',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `operation_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸ュ簭鍚嶇О',
-  `technology_operation_id` bigint NULL DEFAULT NULL COMMENT '宸ュ簭id\r\n',
-  `demanded_quantity` decimal(16, 2) NULL DEFAULT NULL COMMENT '闇�姹傛暟閲�',
-  `is_bom` tinyint(1) NULL DEFAULT NULL COMMENT '鏄惁bom棰嗘枡',
-  `is_returned` tinyint(1) NULL DEFAULT 0 COMMENT '鏄惁宸查��鏂�',
-  `feeding_qty` decimal(20, 2) NULL DEFAULT NULL COMMENT '琛ユ枡鎬婚噺',
-  `return_qty` decimal(20, 2) NULL DEFAULT NULL COMMENT '閫�鏂欐暟閲�',
-  `actual_qty` decimal(20, 2) NULL DEFAULT NULL COMMENT '瀹為檯鏁伴噺',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 81 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璁㈠崟棰嗘枡绾胯竟浠�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_order_pick_record
--- ----------------------------
-DROP TABLE IF EXISTS `production_order_pick_record`;
-CREATE TABLE `production_order_pick_record`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭id',
-  `pick_id` bigint NOT NULL DEFAULT 0 COMMENT '鍏宠仈棰嗘枡鍗昳d锛坧roduction_order_pick.id锛�',
-  `production_order_id` bigint NULL DEFAULT 0 COMMENT '鐢熶骇璁㈠崟id',
-  `production_operation_task_id` bigint NULL DEFAULT 0 COMMENT '鐢熶骇宸ュ崟id',
-  `product_model_id` int NULL DEFAULT NULL COMMENT '浜у搧瑙勬牸id',
-  `batch_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵瑰彿',
-  `pick_quantity` decimal(16, 4) NULL DEFAULT NULL COMMENT '棰嗘枡鏁伴噺',
-  `before_quantity` decimal(16, 4) NULL DEFAULT NULL COMMENT '棰嗘枡鍓嶆暟閲�',
-  `after_quantity` decimal(16, 4) NULL DEFAULT NULL COMMENT '棰嗘枡鍚庡墿浣欐暟閲�',
-  `pick_type` tinyint NULL DEFAULT 1 COMMENT '棰嗘枡绫诲瀷锛�1姝e父棰嗘枡  2琛ユ枡',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `feeding_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '琛ユ枡鍘熷洜',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_pick_id`(`pick_id` ASC) USING BTREE,
-  INDEX `idx_production_order_id`(`production_order_id` ASC) USING BTREE,
-  INDEX `idx_batch_no`(`batch_no` ASC) USING BTREE,
-  INDEX `idx_create_time`(`create_time` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 105 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '绾胯竟浠撳嚭鍏ュ簱璁板綍' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_order_routing
--- ----------------------------
-DROP TABLE IF EXISTS `production_order_routing`;
-CREATE TABLE `production_order_routing`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `product_model_id` bigint NOT NULL DEFAULT 0 COMMENT '浜у搧瑙勬牸id',
-  `production_order_id` bigint NOT NULL DEFAULT 0 COMMENT '鐢熶骇璁㈠崟id',
-  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '鎻忚堪',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `technology_routing_id` bigint NOT NULL DEFAULT 0 COMMENT '宸ヨ壓璺嚎id',
-  `process_route_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栫爜',
-  `bom_id` int NULL DEFAULT NULL COMMENT '鍏宠仈bom鐨刬d',
-  `order_bom_id` int NULL DEFAULT NULL COMMENT '鍏宠仈璁㈠崟bom鐨刬d',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 74 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢熶骇璁㈠崟宸ヨ壓璺嚎琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_order_routing_operation
--- ----------------------------
-DROP TABLE IF EXISTS `production_order_routing_operation`;
-CREATE TABLE `production_order_routing_operation`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `production_order_id` bigint NOT NULL DEFAULT 0 COMMENT '鐢熶骇璁㈠崟id',
-  `technology_routing_operation_id` bigint NULL DEFAULT NULL COMMENT '宸ヨ壓璺嚎宸ュ簭琛╥d',
-  `technology_operation_id` bigint NULL DEFAULT NULL COMMENT '宸ュ簭琛╥d',
-  `order_routing_id` int NULL DEFAULT NULL COMMENT '鍏宠仈璁㈠崟宸ヨ壓璺嚎鐨刬d',
-  `operation_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '宸ュ簭鍚嶇О',
-  `product_model_id` bigint NOT NULL DEFAULT 0 COMMENT '浜у搧瑙勬牸id',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `drag_sort` int NULL DEFAULT NULL COMMENT '鎷栧姩鎺掑簭',
-  `is_quality` tinyint(1) NULL DEFAULT 1 COMMENT '鏄惁璐ㄦ宸ュ簭',
-  `is_production` tinyint(1) NULL DEFAULT 1 COMMENT '鏄惁鐢熶骇',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `type` int NULL DEFAULT NULL COMMENT '绫诲瀷 鍖哄垎璁℃椂鍜岃浠�(0璁℃椂1璁′欢)',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 260 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢熶骇璁㈠崟宸ヨ壓璺嚎宸ュ簭琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_order_routing_operation_param
--- ----------------------------
-DROP TABLE IF EXISTS `production_order_routing_operation_param`;
-CREATE TABLE `production_order_routing_operation_param`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `production_order_id` bigint NULL DEFAULT NULL COMMENT '鐢熶骇璁㈠崟id',
-  `technology_routing_operation_param_id` bigint NULL DEFAULT NULL COMMENT '宸ヨ壓璺嚎宸ュ簭鍙傛暟琛╥d',
-  `param_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鍙傛暟缂栫爜(鍞竴鏍囪瘑)',
-  `param_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鍙傛暟鍚嶇О',
-  `param_type` tinyint NOT NULL COMMENT '鍙傛暟绫诲瀷(1鏁板瓧 2鏂囨湰 3涓嬫媺閫夋嫨 4鏃堕棿)',
-  `param_format` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍙傛暟鏍煎紡',
-  `unit` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `is_required` tinyint NULL DEFAULT 0 COMMENT '鏄惁蹇呭~',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `param_id` bigint NULL DEFAULT NULL COMMENT '鍩虹鍙傛暟ID',
-  `technology_operation_id` bigint NULL DEFAULT NULL COMMENT '宸ュ簭id',
-  `technology_operation_param_id` bigint NULL DEFAULT NULL COMMENT '宸ュ簭鍙傛暟ID',
-  `production_order_routing_operation_id` bigint NOT NULL COMMENT '鐢熶骇璁㈠崟宸ヨ壓璺嚎宸ュ簭ID',
-  `standard_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鏍囧噯鍊�',
-  `input_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '杈撳叆鍊�',
-  `production_product_main_id` bigint NULL DEFAULT NULL COMMENT '鎶ュ伐id',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 334 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '鐢熶骇璁㈠崟宸ヨ壓璺嚎宸ュ簭鍙傛暟琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_plan
--- ----------------------------
-DROP TABLE IF EXISTS `production_plan`;
-CREATE TABLE `production_plan`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `sales_ledger_id` bigint NULL DEFAULT 0 COMMENT '閿�鍞彴璐d',
-  `sales_ledger_product_id` bigint NULL DEFAULT NULL COMMENT '閿�鍞骇鍝佽鏍糹d',
-  `mps_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓荤敓浜ц鍒掑彿',
-  `required_date` datetime(6) NULL DEFAULT NULL COMMENT '闇�姹傛棩鏈�',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` datetime(6) NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_time` datetime(6) NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `product_model_id` bigint NULL DEFAULT NULL COMMENT '浜у搧鍨嬪彿id',
-  `qty_required` decimal(12, 6) NULL DEFAULT NULL COMMENT '闇�姹傛暟閲�',
-  `status` int NULL DEFAULT NULL COMMENT '鐘舵�� 0鏈笅鍙� 1閮ㄥ垎涓嬪彂 2宸蹭笅鍙�',
-  `source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏉ユ簮',
-  `promised_delivery_date` datetime(6) NULL DEFAULT NULL COMMENT '鎵胯鏃ユ湡',
-  `quantity_issued` decimal(12, 6) NULL DEFAULT NULL COMMENT '宸蹭笅鍙戞暟閲�',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 70 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢熶骇璁″垝琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_product_input
--- ----------------------------
-DROP TABLE IF EXISTS `production_product_input`;
-CREATE TABLE `production_product_input`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `input_quantity` decimal(18, 6) NOT NULL COMMENT '鎶曞叆鏁伴噺',
-  `production_product_main_id` bigint NOT NULL COMMENT '鎶ュ伐琛╥d',
-  `product_model_id` bigint NULL DEFAULT NULL COMMENT '浜у搧鍨嬪彿id',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊鐢ㄦ埛',
-  `product_main_id` bigint NULL DEFAULT NULL COMMENT '鐢熶骇鎶ュ伐琛╥d',
-  `quantity` decimal(18, 2) NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_product_main_id`(`production_product_main_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 52 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢熶骇鎶ュ伐鎶曞叆琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_product_main
--- ----------------------------
-DROP TABLE IF EXISTS `production_product_main`;
-CREATE TABLE `production_product_main`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `product_no` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎶ュ伐鍗曞彿',
-  `user_id` bigint NULL DEFAULT NULL COMMENT '鎶ュ伐浜哄憳id',
-  `user_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎶ュ伐浜哄憳',
-  `production_operation_task_id` bigint NULL DEFAULT NULL COMMENT '宸ュ崟id',
-  `status` int NULL DEFAULT NULL COMMENT '鎶ュ伐鐘舵��',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊鐢ㄦ埛',
-  `work_hour` decimal(10, 2) NULL DEFAULT NULL COMMENT '宸ユ椂',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 45 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢熶骇鎶ュ伐琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for production_product_output
--- ----------------------------
-DROP TABLE IF EXISTS `production_product_output`;
-CREATE TABLE `production_product_output`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `production_product_main_id` bigint NOT NULL COMMENT '鎶ュ伐鍗昳d',
-  `product_model_id` bigint NOT NULL COMMENT '浜у搧瑙勬牸id',
-  `quantity` decimal(16, 4) NOT NULL DEFAULT 0.0000 COMMENT '鎶ュ伐鏁伴噺',
-  `scrap_qty` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '鎶ュ簾鏁伴噺',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊鐢ㄦ埛',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `product_main_id` bigint NULL DEFAULT NULL COMMENT '鐢熶骇鎶ュ伐琛╥d',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 45 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢熶骇鎶ュ伐浜у嚭琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for project_management_contract_info
--- ----------------------------
-DROP TABLE IF EXISTS `project_management_contract_info`;
-CREATE TABLE `project_management_contract_info`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍚嶇О',
-  `sex` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎬у埆',
-  `birthday` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢熸棩',
-  `department` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閮ㄩ棬',
-  `job` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鑱屽姟',
-  `phone_number` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵嬫満鍙�',
-  `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閭',
-  `qq` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'QQ',
-  `linea_fissa` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍥哄畾鍙风爜',
-  `wx` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '寰俊',
-  `origine_etnica` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绫嶈疮',
-  `rappresentante_legale` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '娉曚汉浠h〃',
-  `project_management_info_id` bigint NULL DEFAULT NULL COMMENT '瀵瑰簲椤圭洰绠$悊淇℃伅id',
-  `is_delete` int NOT NULL DEFAULT 0,
-  `create_user` bigint NULL DEFAULT NULL,
-  `update_user` bigint NULL DEFAULT NULL,
-  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `update_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `create_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '椤圭洰鑱旂郴淇℃伅' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for project_management_info
--- ----------------------------
-DROP TABLE IF EXISTS `project_management_info`;
-CREATE TABLE `project_management_info`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '椤圭洰缂栧彿',
-  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓婚',
-  `client_id` bigint NULL DEFAULT NULL COMMENT '瀹㈡埛id',
-  `client_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹㈡埛鍚嶇О',
-  `project_management_info_parent_id` bigint NULL DEFAULT NULL COMMENT '绱㈠紩鐨勭埗椤圭洰id',
-  `establish_time` date NULL DEFAULT NULL COMMENT '绔嬮」鏃堕棿',
-  `project_management_plan_id` bigint NOT NULL COMMENT '椤圭洰闃舵id',
-  `source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏉ユ簮',
-  `manager_id` bigint NULL DEFAULT NULL COMMENT '椤圭洰缁忕悊id',
-  `manager_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '椤圭洰缁忕悊鍚嶅瓧',
-  `salesman_id` bigint NULL DEFAULT NULL COMMENT '涓氬姟鍛榠d',
-  `salesman_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓氬姟鍛樺悕瀛�',
-  `is_delete` int NOT NULL DEFAULT 0,
-  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `create_user` int NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `plan_start_time` date NULL DEFAULT NULL COMMENT '璁″垝寮�濮嬫椂闂�',
-  `plan_end_time` date NULL DEFAULT NULL COMMENT '璁″垝缁撴潫鏃堕棿',
-  `actual_start_time` date NULL DEFAULT NULL COMMENT '瀹為檯寮�濮嬫椂闂�',
-  `actual_end_time` date NULL DEFAULT NULL COMMENT '瀹為檯缁撴潫鏃ユ湡',
-  `review_status` int NULL DEFAULT NULL COMMENT '瀹℃牳鐘舵��',
-  `status` int NULL DEFAULT NULL COMMENT '椤圭洰鐘舵��',
-  `department_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬id',
-  `department_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閮ㄩ棬鍚嶅瓧',
-  `order_date` timestamp NULL DEFAULT NULL COMMENT '璁㈠崟鏃ユ湡',
-  `order_amount` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁㈠崟閲戦',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `attachment` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '闄勪欢',
-  `plan_stage` json NULL COMMENT '椤圭洰闃舵 json',
-  `team` json NULL COMMENT '鍥㈤槦',
-  `create_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `update_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '椤圭洰绠$悊淇℃伅' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for project_management_info_stage
--- ----------------------------
-DROP TABLE IF EXISTS `project_management_info_stage`;
-CREATE TABLE `project_management_info_stage`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `project_management_plan_node_id` bigint NOT NULL COMMENT '瀵瑰簲璁″垝鑺傜偣id',
-  `project_management_info_id` bigint NOT NULL COMMENT '瀵瑰簲椤圭洰id',
-  `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎻忚堪',
-  `actual_leader_id` bigint NULL DEFAULT NULL COMMENT '瀹為檯璐熻矗浜篿d',
-  `actual_leader_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹為檯璐熻矗浜哄悕绉�',
-  `estimated_duration` int NULL DEFAULT NULL COMMENT '棰勮宸ユ湡',
-  `plan_start_time` date NULL DEFAULT NULL COMMENT '璁″垝寮�濮�',
-  `plan_end_time` date NULL DEFAULT NULL COMMENT '璁″垝缁撴潫',
-  `progress` int NOT NULL DEFAULT 0 COMMENT '杩涘害',
-  `actual_start_time` date NULL DEFAULT NULL COMMENT '瀹為檯寮�濮嬫椂闂�',
-  `actual_end_time` date NULL DEFAULT NULL COMMENT '瀹為檯缁撴潫鏃堕棿',
-  `attachment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '闄勪欢',
-  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
-  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
-  `is_delete` int NOT NULL DEFAULT 0,
-  `create_user` bigint NULL DEFAULT NULL,
-  `update_user` bigint NULL DEFAULT NULL,
-  `create_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `update_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '椤圭洰闃舵' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for project_management_plan
--- ----------------------------
-DROP TABLE IF EXISTS `project_management_plan`;
-CREATE TABLE `project_management_plan`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璁″垝鍚嶇О',
-  `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁″垝鎻忚堪',
-  `attachment` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '闄勪欢 ,杩涜鍒嗗壊',
-  `is_delete` int NOT NULL DEFAULT 0,
-  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
-  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
-  `create_user` int NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `create_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `update_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '椤圭洰绠$悊璁″垝琛�(椤圭洰绠$悊绫诲瀷)' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for project_management_plan_node
--- ----------------------------
-DROP TABLE IF EXISTS `project_management_plan_node`;
-CREATE TABLE `project_management_plan_node`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `project_management_plan_id` bigint NOT NULL COMMENT '瀵瑰簲id',
-  `sort` int NOT NULL COMMENT '鎺掑簭',
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '闃舵鍚嶇О',
-  `leader_id` bigint NULL DEFAULT NULL COMMENT '璐熻矗浠籌D',
-  `leader_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璐熻矗浠诲悕绉�',
-  `estimated_duration` int NULL DEFAULT NULL COMMENT '棰勮宸ユ湡(澶�)',
-  `hourly_rate` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `work_content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浣滀笟鍐呭',
-  `is_delete` int NOT NULL DEFAULT 0,
-  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
-  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
-  `create_user` int NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `create_user_name` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `update_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璁″垝鑺傜偣' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for project_management_roles
--- ----------------------------
-DROP TABLE IF EXISTS `project_management_roles`;
-CREATE TABLE `project_management_roles`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'id',
-  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '鍚嶇О',
-  `status` tinyint NOT NULL DEFAULT 1 COMMENT '鐘舵��(1:鍚敤, 0:绂佺敤)',
-  `create_time` timestamp NOT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `update_time` timestamp NOT NULL COMMENT '鏇存柊鏃堕棿',
-  `update_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `create_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `update_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '椤圭洰瑙掕壊' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for project_management_shipping_address
--- ----------------------------
-DROP TABLE IF EXISTS `project_management_shipping_address`;
-CREATE TABLE `project_management_shipping_address`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `consignee` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏀惰揣浜�',
-  `contract` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鑱旂郴鏂瑰紡',
-  `address` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍦板潃',
-  `is_delete` int NOT NULL DEFAULT 0,
-  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `create_user` bigint NULL DEFAULT NULL,
-  `update_user` bigint NULL DEFAULT NULL,
-  `project_management_info_id` bigint NULL DEFAULT NULL COMMENT '瀵瑰簲椤圭洰淇℃伅id',
-  `update_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `create_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鏀惰揣鍦板潃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for purchase_ledger
--- ----------------------------
-DROP TABLE IF EXISTS `purchase_ledger`;
-CREATE TABLE `purchase_ledger`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT '鑷涓婚敭ID',
-  `purchase_contract_number` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '閲囪喘鍚堝悓鍙�',
-  `supplier_id` int NULL DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉癷d',
-  `supplier_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渚涘簲鍟嗗悕绉�',
-  `recorder_id` int NULL DEFAULT NULL COMMENT '褰曞叆浜篿d\r\n',
-  `recorder_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '褰曞叆浜哄鍚�',
-  `sales_contract_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閿�鍞悎鍚屽彿',
-  `project_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '椤圭洰鍚嶇О',
-  `entry_date` date NOT NULL COMMENT '褰曞叆鏃ユ湡',
-  `remarks` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '澶囨敞',
-  `attachment_materials` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '闄勪欢鏉愭枡璺緞鎴栧悕绉�',
-  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '璁板綍鍒涘缓鏃堕棿',
-  `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '璁板綍鏈�鍚庢洿鏂版椂闂�',
-  `sales_ledger_id` int NULL DEFAULT NULL COMMENT '鍏宠仈閿�鍞彴璐︿富琛ㄤ富閿�',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `contract_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍚堝悓閲戦',
-  `business_person` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓氬姟鍛�',
-  `business_person_id` int NULL DEFAULT NULL COMMENT '涓氬姟鍛榠d',
-  `phone_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '褰曞叆浜虹數璇�',
-  `payment_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `execution_date` datetime NULL DEFAULT NULL,
-  `approval_status` bigint NULL DEFAULT 1 COMMENT '1-寰呭鏍革紝2-瀹℃壒涓紝3-瀹℃壒閫氳繃锛�4-瀹℃壒澶辫触',
-  `template_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '妯℃澘鍚嶇О',
-  `approve_user_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃壒浜篿d',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `template_id` int NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 44 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閲囪喘鍙拌处' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for purchase_ledger_template
--- ----------------------------
-DROP TABLE IF EXISTS `purchase_ledger_template`;
-CREATE TABLE `purchase_ledger_template`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT '鑷涓婚敭ID',
-  `purchase_contract_number` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閲囪喘鍚堝悓鍙�',
-  `supplier_id` int NULL DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉癷d',
-  `supplier_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉�',
-  `recorder_id` int NULL DEFAULT NULL COMMENT '褰曞叆浜篿d\r\n',
-  `recorder_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '褰曞叆浜哄鍚�',
-  `sales_contract_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閿�鍞悎鍚屽彿',
-  `project_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '椤圭洰鍚嶇О',
-  `entry_date` date NULL DEFAULT NULL COMMENT '褰曞叆鏃ユ湡',
-  `remarks` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '澶囨敞',
-  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '璁板綍鍒涘缓鏃堕棿',
-  `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '璁板綍鏈�鍚庢洿鏂版椂闂�',
-  `sales_ledger_id` int NULL DEFAULT NULL COMMENT '鍏宠仈閿�鍞彴璐︿富琛ㄤ富閿�',
-  `contract_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍚堝悓閲戦',
-  `business_person` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓氬姟鍛�',
-  `business_person_id` int NULL DEFAULT NULL COMMENT '涓氬姟鍛榠d',
-  `phone_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '褰曞叆浜虹數璇�',
-  `payment_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `execution_date` datetime NULL DEFAULT NULL,
-  `template_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '妯℃澘鍚嶇О',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閲囪喘鍙拌处妯℃澘' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for purchase_return_order_products
--- ----------------------------
-DROP TABLE IF EXISTS `purchase_return_order_products`;
-CREATE TABLE `purchase_return_order_products`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `purchase_return_order_id` bigint NOT NULL DEFAULT 0 COMMENT '閫�璐у崟id',
-  `sales_ledger_product_id` bigint NOT NULL DEFAULT 0 COMMENT '閲囪喘浜у搧id',
-  `return_quantity` decimal(16, 4) NOT NULL DEFAULT 0.0000 COMMENT '閫�璐ф暟閲�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `stock_in_record_id` bigint NOT NULL COMMENT '鍏宠仈鍏ュ簱鍗昳d',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_purchase_return_order_id`(`purchase_return_order_id` ASC) USING BTREE,
-  INDEX `idx_sales_ledger_product_id`(`sales_ledger_product_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閲囪喘閫�璐т骇鍝佽〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for purchase_return_orders
--- ----------------------------
-DROP TABLE IF EXISTS `purchase_return_orders`;
-CREATE TABLE `purchase_return_orders`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閫�璐у崟缂栧彿',
-  `return_type` tinyint NOT NULL DEFAULT 0 COMMENT '閫�璐ф柟寮� 0閫�璐ч��娆� 1鎷掓敹',
-  `supplier_id` bigint NOT NULL DEFAULT 0 COMMENT '渚涘簲鍟唅d',
-  `shipping_type` tinyint NULL DEFAULT NULL COMMENT '鍙戣揣绫诲瀷 1璐ц溅 2蹇��',
-  `truck_plate_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙戣揣杞︾墝鍙�',
-  `express_company` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '蹇�掑叕鍙�',
-  `express_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '蹇�掑崟鍙�',
-  `project_id` bigint NOT NULL DEFAULT 0 COMMENT '椤圭洰id',
-  `project_phase` tinyint NOT NULL DEFAULT 0 COMMENT '椤圭洰闃舵',
-  `prepared_at` datetime NULL DEFAULT NULL COMMENT '鍒跺崟鏃ユ湡',
-  `prepared_user_id` bigint NOT NULL DEFAULT 0 COMMENT '鍒跺崟浜篿d',
-  `return_user_id` bigint NOT NULL DEFAULT 0 COMMENT '閫�鏂欎汉id',
-  `purchase_ledger_id` bigint NOT NULL DEFAULT 0 COMMENT '閲囪喘璁㈠崟id',
-  `total_discount_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏁村崟鎶樻墸棰�',
-  `total_discount_rate` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏁村崟鎶樻墸鐜�',
-  `total_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '鎴愪氦閲戦',
-  `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '澶囨敞',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `income_type` int NULL DEFAULT NULL COMMENT '鏀跺叆绫诲瀷',
-  `prepared_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒跺崟浜哄悕绉�',
-  `return_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閫�鏂欎汉鍚嶇О',
-  `create_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `update_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_supplier_id`(`supplier_id` ASC) USING BTREE,
-  INDEX `idx_purchase_ledger_id`(`purchase_ledger_id` ASC) USING BTREE,
-  INDEX `idx_project_id`(`project_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閲囪喘閫�璐у崟琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qr_code
--- ----------------------------
-DROP TABLE IF EXISTS `qr_code`;
-CREATE TABLE `qr_code`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '浜岀淮鐮佸敮涓�鏍囪瘑',
-  `device_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧鍚嶇О',
-  `location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵�鍦ㄤ綅缃弿杩�',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛ID锛岀敤浜庡绉熸埛闅旂',
-  `deleted` int NOT NULL DEFAULT 0 COMMENT '杞垹闄ゆ爣蹇楋紝0=鏈垹闄わ紝1=宸插垹闄�',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓璇ヨ褰曠殑鐢ㄦ埛',
-  `create_time` datetime(6) NULL DEFAULT NULL COMMENT '璁板綍鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏈�鍚庝慨鏀硅璁板綍鐨勭敤鎴�',
-  `update_time` datetime(6) NULL DEFAULT NULL COMMENT '璁板綍鏈�鍚庢洿鏂版椂闂�',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浜岀淮鐮佺鐞嗚〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qr_code_scan_record
--- ----------------------------
-DROP TABLE IF EXISTS `qr_code_scan_record`;
-CREATE TABLE `qr_code_scan_record`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鎵爜璁板綍鍞竴鏍囪瘑',
-  `qr_code_id` bigint NULL DEFAULT NULL COMMENT '鍏宠仈鐨勪簩缁寸爜ID',
-  `scanner_id` bigint NULL DEFAULT NULL COMMENT '鎵爜浜虹敤鎴稩D',
-  `device_id` int NULL DEFAULT NULL COMMENT '璁惧id',
-  `device_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧鍚嶇О',
-  `scan_time` datetime(6) NULL DEFAULT NULL COMMENT '瀹為檯鎵爜鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛ID锛岀敤浜庡绉熸埛闅旂',
-  `deleted` int NOT NULL DEFAULT 0 COMMENT '杞垹闄ゆ爣蹇楋紝0=鏈垹闄わ紝1=宸插垹闄�',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓璇ヨ褰曠殑鐢ㄦ埛',
-  `create_time` datetime(6) NULL DEFAULT NULL COMMENT '璁板綍鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏈�鍚庝慨鏀硅璁板綍鐨勭敤鎴�',
-  `update_time` datetime(6) NULL DEFAULT NULL COMMENT '璁板綍鏈�鍚庢洿鏂版椂闂�',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浜岀淮鐮佹壂鐮佽褰曡〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qrtz_blob_triggers
--- ----------------------------
-DROP TABLE IF EXISTS `qrtz_blob_triggers`;
-CREATE TABLE `qrtz_blob_triggers`  (
-  `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍚嶇О',
-  `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_triggers琛╰rigger_name鐨勫閿�',
-  `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_triggers琛╰rigger_group鐨勫閿�',
-  `blob_data` blob NULL COMMENT '瀛樻斁鎸佷箙鍖朤rigger瀵硅薄',
-  PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
-  CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'Blob绫诲瀷鐨勮Е鍙戝櫒琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qrtz_calendars
--- ----------------------------
-DROP TABLE IF EXISTS `qrtz_calendars`;
-CREATE TABLE `qrtz_calendars`  (
-  `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍚嶇О',
-  `calendar_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏃ュ巻鍚嶇О',
-  `calendar` blob NOT NULL COMMENT '瀛樻斁鎸佷箙鍖朿alendar瀵硅薄',
-  PRIMARY KEY (`sched_name`, `calendar_name`) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鏃ュ巻淇℃伅琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qrtz_cron_triggers
--- ----------------------------
-DROP TABLE IF EXISTS `qrtz_cron_triggers`;
-CREATE TABLE `qrtz_cron_triggers`  (
-  `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍚嶇О',
-  `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_triggers琛╰rigger_name鐨勫閿�',
-  `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_triggers琛╰rigger_group鐨勫閿�',
-  `cron_expression` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'cron琛ㄨ揪寮�',
-  `time_zone_id` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏃跺尯',
-  PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
-  CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'Cron绫诲瀷鐨勮Е鍙戝櫒琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qrtz_fired_triggers
--- ----------------------------
-DROP TABLE IF EXISTS `qrtz_fired_triggers`;
-CREATE TABLE `qrtz_fired_triggers`  (
-  `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍚嶇О',
-  `entry_id` varchar(95) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍣ㄥ疄渚媔d',
-  `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_triggers琛╰rigger_name鐨勫閿�',
-  `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_triggers琛╰rigger_group鐨勫閿�',
-  `instance_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍣ㄥ疄渚嬪悕',
-  `fired_time` bigint NOT NULL COMMENT '瑙﹀彂鐨勬椂闂�',
-  `sched_time` bigint NOT NULL COMMENT '瀹氭椂鍣ㄥ埗瀹氱殑鏃堕棿',
-  `priority` int NOT NULL COMMENT '浼樺厛绾�',
-  `state` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鐘舵��',
-  `job_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浠诲姟鍚嶇О',
-  `job_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浠诲姟缁勫悕',
-  `is_nonconcurrent` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏄惁骞跺彂',
-  `requests_recovery` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏄惁鎺ュ彈鎭㈠鎵ц',
-  PRIMARY KEY (`sched_name`, `entry_id`) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '宸茶Е鍙戠殑瑙﹀彂鍣ㄨ〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qrtz_job_details
--- ----------------------------
-DROP TABLE IF EXISTS `qrtz_job_details`;
-CREATE TABLE `qrtz_job_details`  (
-  `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍚嶇О',
-  `job_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '浠诲姟鍚嶇О',
-  `job_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '浠诲姟缁勫悕',
-  `description` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐩稿叧浠嬬粛',
-  `job_class_name` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鎵ц浠诲姟绫诲悕绉�',
-  `is_durable` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏄惁鎸佷箙鍖�',
-  `is_nonconcurrent` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏄惁骞跺彂',
-  `is_update_data` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏄惁鏇存柊鏁版嵁',
-  `requests_recovery` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏄惁鎺ュ彈鎭㈠鎵ц',
-  `job_data` blob NULL COMMENT '瀛樻斁鎸佷箙鍖杍ob瀵硅薄',
-  PRIMARY KEY (`sched_name`, `job_name`, `job_group`) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浠诲姟璇︾粏淇℃伅琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qrtz_locks
--- ----------------------------
-DROP TABLE IF EXISTS `qrtz_locks`;
-CREATE TABLE `qrtz_locks`  (
-  `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍚嶇О',
-  `lock_name` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鎮茶閿佸悕绉�',
-  PRIMARY KEY (`sched_name`, `lock_name`) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀛樺偍鐨勬偛瑙傞攣淇℃伅琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qrtz_paused_trigger_grps
--- ----------------------------
-DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`;
-CREATE TABLE `qrtz_paused_trigger_grps`  (
-  `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍚嶇О',
-  `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_triggers琛╰rigger_group鐨勫閿�',
-  PRIMARY KEY (`sched_name`, `trigger_group`) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鏆傚仠鐨勮Е鍙戝櫒琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qrtz_scheduler_state
--- ----------------------------
-DROP TABLE IF EXISTS `qrtz_scheduler_state`;
-CREATE TABLE `qrtz_scheduler_state`  (
-  `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍚嶇О',
-  `instance_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瀹炰緥鍚嶇О',
-  `last_checkin_time` bigint NOT NULL COMMENT '涓婃妫�鏌ユ椂闂�',
-  `checkin_interval` bigint NOT NULL COMMENT '妫�鏌ラ棿闅旀椂闂�',
-  PRIMARY KEY (`sched_name`, `instance_name`) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璋冨害鍣ㄧ姸鎬佽〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qrtz_simple_triggers
--- ----------------------------
-DROP TABLE IF EXISTS `qrtz_simple_triggers`;
-CREATE TABLE `qrtz_simple_triggers`  (
-  `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍚嶇О',
-  `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_triggers琛╰rigger_name鐨勫閿�',
-  `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_triggers琛╰rigger_group鐨勫閿�',
-  `repeat_count` bigint NOT NULL COMMENT '閲嶅鐨勬鏁扮粺璁�',
-  `repeat_interval` bigint NOT NULL COMMENT '閲嶅鐨勯棿闅旀椂闂�',
-  `times_triggered` bigint NOT NULL COMMENT '宸茬粡瑙﹀彂鐨勬鏁�',
-  PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
-  CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '绠�鍗曡Е鍙戝櫒鐨勪俊鎭〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qrtz_simprop_triggers
--- ----------------------------
-DROP TABLE IF EXISTS `qrtz_simprop_triggers`;
-CREATE TABLE `qrtz_simprop_triggers`  (
-  `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍚嶇О',
-  `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_triggers琛╰rigger_name鐨勫閿�',
-  `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_triggers琛╰rigger_group鐨勫閿�',
-  `str_prop_1` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'String绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�',
-  `str_prop_2` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'String绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟',
-  `str_prop_3` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'String绫诲瀷鐨則rigger鐨勭涓変釜鍙傛暟',
-  `int_prop_1` int NULL DEFAULT NULL COMMENT 'int绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�',
-  `int_prop_2` int NULL DEFAULT NULL COMMENT 'int绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟',
-  `long_prop_1` bigint NULL DEFAULT NULL COMMENT 'long绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�',
-  `long_prop_2` bigint NULL DEFAULT NULL COMMENT 'long绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟',
-  `dec_prop_1` decimal(13, 4) NULL DEFAULT NULL COMMENT 'decimal绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�',
-  `dec_prop_2` decimal(13, 4) NULL DEFAULT NULL COMMENT 'decimal绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟',
-  `bool_prop_1` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'Boolean绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�',
-  `bool_prop_2` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'Boolean绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟',
-  PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
-  CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍚屾鏈哄埗鐨勮閿佽〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for qrtz_triggers
--- ----------------------------
-DROP TABLE IF EXISTS `qrtz_triggers`;
-CREATE TABLE `qrtz_triggers`  (
-  `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冨害鍚嶇О',
-  `trigger_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瑙﹀彂鍣ㄧ殑鍚嶅瓧',
-  `trigger_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瑙﹀彂鍣ㄦ墍灞炵粍鐨勫悕瀛�',
-  `job_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_job_details琛╦ob_name鐨勫閿�',
-  `job_group` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'qrtz_job_details琛╦ob_group鐨勫閿�',
-  `description` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐩稿叧浠嬬粛',
-  `next_fire_time` bigint NULL DEFAULT NULL COMMENT '涓婁竴娆¤Е鍙戞椂闂达紙姣锛�',
-  `prev_fire_time` bigint NULL DEFAULT NULL COMMENT '涓嬩竴娆¤Е鍙戞椂闂达紙榛樿涓�-1琛ㄧず涓嶈Е鍙戯級',
-  `priority` int NULL DEFAULT NULL COMMENT '浼樺厛绾�',
-  `trigger_state` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瑙﹀彂鍣ㄧ姸鎬�',
-  `trigger_type` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瑙﹀彂鍣ㄧ殑绫诲瀷',
-  `start_time` bigint NOT NULL COMMENT '寮�濮嬫椂闂�',
-  `end_time` bigint NULL DEFAULT NULL COMMENT '缁撴潫鏃堕棿',
-  `calendar_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏃ョ▼琛ㄥ悕绉�',
-  `misfire_instr` smallint NULL DEFAULT NULL COMMENT '琛ュ伩鎵ц鐨勭瓥鐣�',
-  `job_data` blob NULL COMMENT '瀛樻斁鎸佷箙鍖杍ob瀵硅薄',
-  PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
-  INDEX `sched_name`(`sched_name` ASC, `job_name` ASC, `job_group` ASC) USING BTREE,
-  CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `job_name`, `job_group`) REFERENCES `qrtz_job_details` (`sched_name`, `job_name`, `job_group`) ON DELETE RESTRICT ON UPDATE RESTRICT
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瑙﹀彂鍣ㄨ缁嗕俊鎭〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for quality_inspect
--- ----------------------------
-DROP TABLE IF EXISTS `quality_inspect`;
-CREATE TABLE `quality_inspect`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `inspect_type` int NULL DEFAULT NULL COMMENT '绫诲埆(0:鍘熸潗鏂欐楠�;1:杩囩▼妫�楠�;2:鍑哄巶妫�楠�)',
-  `check_time` date NULL DEFAULT NULL COMMENT '妫�娴嬫棩鏈�',
-  `supplier` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉�(鍘熸潗鏂欐楠�)',
-  `customer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹㈡埛鍚嶇О(杩囩▼妫�楠�/鍑哄巶妫�楠�)',
-  `process` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸ュ簭(杩囩▼妫�楠�)',
-  `check_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '妫�楠屽憳',
-  `product_id` bigint NULL DEFAULT NULL COMMENT '浜у搧ID',
-  `product_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜у搧鍚嶇О',
-  `model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `unit` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `quantity` decimal(18, 2) NULL DEFAULT NULL COMMENT '鍏ㄩ儴鏁伴噺',
-  `qualified_quantity` decimal(18, 2) NULL DEFAULT NULL COMMENT '鍚堟牸鐨勬暟閲�',
-  `unqualified_quantity` decimal(18, 2) NULL DEFAULT NULL COMMENT '涓嶅悎鏍肩殑鏁伴噺',
-  `check_company` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '妫�娴嬪崟浣�',
-  `check_result` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '妫�娴嬬粨鏋�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `inspect_state` int NULL DEFAULT NULL COMMENT '绫诲埆锛�0-鏈彁浜� 1-宸叉彁浜わ級',
-  `purchase_ledger_id` int NULL DEFAULT NULL COMMENT '閲囪喘璁㈠崟id',
-  `product_main_id` bigint NULL DEFAULT NULL COMMENT '鎶ュ伐鍗昳d',
-  `defective_phenomena` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓嶅悎鏍肩幇璞℃弿杩�',
-  `product_model_id` bigint NULL DEFAULT NULL COMMENT '浜у搧瑙勬牸id',
-  `test_standard_id` int NULL DEFAULT NULL COMMENT '鍏宠仈妫�娴嬫爣鍑嗕富琛╥d',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 71 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璐ㄩ噺绠$悊--鍘熸潗鏂�/杩囩▼/鍑哄巶妫�楠�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for quality_inspect_file
--- ----------------------------
-DROP TABLE IF EXISTS `quality_inspect_file`;
-CREATE TABLE `quality_inspect_file`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢鍚嶇О',
-  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢璺緞',
-  `file_size` int NULL DEFAULT NULL COMMENT '鏂囦欢澶у皬',
-  `inspect_id` bigint NULL DEFAULT NULL COMMENT '妫�楠孖D',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璐ㄩ噺绠$悊--妫�楠岄檮浠�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for quality_inspect_param
--- ----------------------------
-DROP TABLE IF EXISTS `quality_inspect_param`;
-CREATE TABLE `quality_inspect_param`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `parameter_item` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎸囨爣',
-  `unit` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `standard_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏍囧噯鍊�',
-  `control_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍐呮帶鍊�',
-  `test_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '妫�楠屽��',
-  `inspect_id` bigint NULL DEFAULT NULL COMMENT '妫�楠孖D',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 30 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璐ㄩ噺绠$悊--妫�楠岃褰�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for quality_test_standard
--- ----------------------------
-DROP TABLE IF EXISTS `quality_test_standard`;
-CREATE TABLE `quality_test_standard`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `standard_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏍囧噯缂栧彿鎸囨爣',
-  `standard_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏍囧噯鍚嶇О',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `state` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐘舵��',
-  `process_id` int NULL DEFAULT NULL COMMENT '鍏宠仈宸ュ簭id',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `inspect_type` int NULL DEFAULT NULL COMMENT '绫诲埆(0:鍘熸潗鏂欐楠�;1:杩囩▼妫�楠�;2:鍑哄巶妫�楠�)',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璐ㄩ噺绠$悊--妫�娴嬫寚鏍囩淮鎶�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for quality_test_standard_binding
--- ----------------------------
-DROP TABLE IF EXISTS `quality_test_standard_binding`;
-CREATE TABLE `quality_test_standard_binding`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `product_id` bigint NULL DEFAULT NULL COMMENT '浜у搧ID',
-  `test_standard_id` int NULL DEFAULT NULL COMMENT '鍏宠仈妫�娴嬫爣鍑嗕富琛╥d',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '妫�娴嬫爣鍑嗕富琛ㄤ笌浜у搧鍏宠仈琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for quality_test_standard_param
--- ----------------------------
-DROP TABLE IF EXISTS `quality_test_standard_param`;
-CREATE TABLE `quality_test_standard_param`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `parameter_item` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙傛暟椤�',
-  `unit` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `standard_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏍囧噯鍊�',
-  `control_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍐呮帶鍊�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `test_standard_id` int NULL DEFAULT NULL COMMENT '鍏宠仈妫�娴嬫爣鍑嗕富琛╥d',
-  `default_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '榛樿鍊�',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '妫�娴嬫爣鍑嗗弬鏁�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for quality_unqualified
--- ----------------------------
-DROP TABLE IF EXISTS `quality_unqualified`;
-CREATE TABLE `quality_unqualified`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `inspect_type` int NULL DEFAULT NULL COMMENT '绫诲埆(0:鍘熸潗鏂欐楠�;1:杩囩▼妫�楠�;2:鍑哄巶妫�楠�)',
-  `inspect_state` int NULL DEFAULT NULL COMMENT '鐘舵��(0:寰呭鐞�;1:宸插鐞�)',
-  `check_time` date NULL DEFAULT NULL COMMENT '妫�娴嬫棩鏈�',
-  `check_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '妫�楠屽憳',
-  `product_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜у搧鍚嶇О',
-  `model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `unit` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `quantity` decimal(18, 2) NULL DEFAULT NULL COMMENT '鏁伴噺',
-  `defective_phenomena` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓嶅悎鏍肩幇璞�',
-  `deal_result` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶勭悊缁撴灉',
-  `deal_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶勭悊浜�',
-  `deal_time` date NULL DEFAULT NULL COMMENT '澶勭悊鏃ユ湡',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `product_id` bigint NULL DEFAULT NULL COMMENT '浜у搧ID',
-  `inspect_id` int NULL DEFAULT NULL COMMENT '鍏宠仈妫�楠宨d',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `product_model_id` int NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 52 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璐ㄩ噺绠$悊--涓嶅悎鏍煎搧绠$悊' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for reading_status
--- ----------------------------
-DROP TABLE IF EXISTS `reading_status`;
-CREATE TABLE `reading_status`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `rule_id` int NULL DEFAULT NULL COMMENT '鐢ㄥ嵃绠$悊-瑙勭珷鍒跺害id',
-  `employee` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍛樺伐濮撳悕',
-  `department` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵�灞為儴闂�',
-  `confirm_time` datetime NULL DEFAULT NULL COMMENT '纭鏃堕棿',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐘舵��',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '闃呰鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢ㄥ嵃绠$悊-瑙勭珷鍒跺害-闃呰鐘舵��' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for receipt_payment
--- ----------------------------
-DROP TABLE IF EXISTS `receipt_payment`;
-CREATE TABLE `receipt_payment`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `sales_ledger_id` int NULL DEFAULT NULL COMMENT '閿�鍞彴璐d',
-  `sales_ledger_product_id` int NULL DEFAULT NULL COMMENT '閿�鍞骇鍝乮d',
-  `invoice_ledger_id` bigint NULL DEFAULT NULL COMMENT 'invoice_ledger寮�绁ㄥ彴璐﹁〃涓婚敭ID',
-  `receipt_payment_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍥炴褰㈠紡 0鐢垫眹1鎵垮厬',
-  `receipt_payment_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍥炴閲戦',
-  `registrant` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐧昏浜�',
-  `receipt_payment_date` datetime NULL DEFAULT NULL COMMENT '鏉ユ鏃ユ湡',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 286 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍥炴鐧昏琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for return_management
--- ----------------------------
-DROP TABLE IF EXISTS `return_management`;
-CREATE TABLE `return_management`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '搴忓彿',
-  `return_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閫�璐у崟鍙�',
-  `customer_id` bigint NULL DEFAULT NULL COMMENT '瀹㈡埛 id',
-  `shipping_id` bigint NULL DEFAULT NULL COMMENT '鍏宠仈鍙戣揣鍗曞彿',
-  `shipping_type` tinyint NULL DEFAULT NULL COMMENT '鍙戣揣绫诲瀷 1璐ц溅 2蹇��',
-  `truck_plate_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙戣揣杞︾墝鍙�',
-  `express_company` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '蹇�掑叕鍙�',
-  `express_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '蹇�掑崟鍙�',
-  `project_stage` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '椤圭洰闃舵',
-  `maker` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒跺崟浜�',
-  `make_time` timestamp NULL DEFAULT NULL COMMENT '鍒跺崟鏃堕棿',
-  `settler` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '缁撶畻浜�',
-  `status` int NOT NULL DEFAULT 0,
-  `project_id` int NULL DEFAULT NULL COMMENT '椤圭洰id',
-  `create_time` timestamp NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_time` timestamp NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `return_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閫�璐у師鍥�',
-  `refund_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '閫�娆炬�婚',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閫�璐х鐞嗚〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for return_sale_product
--- ----------------------------
-DROP TABLE IF EXISTS `return_sale_product`;
-CREATE TABLE `return_sale_product`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭id',
-  `return_management_id` int NULL DEFAULT NULL COMMENT '閫�璐у崟id',
-  `stock_out_record_id` bigint NULL DEFAULT NULL COMMENT '鍏宠仈鍑哄簱鍗昳d',
-  `num` decimal(16, 3) NOT NULL COMMENT '閫�璐т骇鍝佹暟閲�',
-  `status` int NULL DEFAULT NULL COMMENT '閫�璐х姸鎬�',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `is_quality` int NULL DEFAULT NULL COMMENT '鏄惁鏈夎川閲忛棶棰�(1-鏄� 2-鍚�)',
-  `price` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍗曚环',
-  `amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '閲戦',
-  `product_model_id` bigint NULL DEFAULT NULL COMMENT '浜у搧瑙勬牸id',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閫�璐т骇鍝佽〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for rpa_process_automation
--- ----------------------------
-DROP TABLE IF EXISTS `rpa_process_automation`;
-CREATE TABLE `rpa_process_automation`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `program_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绋嬪簭鍚�',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵ц鐘舵��',
-  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎻忚堪',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'RPA娴佺▼鑷姩鍖�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for rules_regulations_management
--- ----------------------------
-DROP TABLE IF EXISTS `rules_regulations_management`;
-CREATE TABLE `rules_regulations_management`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `regulation_num` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒跺害缂栧彿',
-  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒跺害鏍囬',
-  `category` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒跺害鍒嗙被',
-  `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '鍒跺害鍐呭',
-  `effective_time` datetime NULL DEFAULT NULL COMMENT '鐢熸晥鏃堕棿',
-  `scope` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閫傜敤鑼冨洿',
-  `require_confirm` int NULL DEFAULT NULL COMMENT '鏄惁闇�瑕佺‘璁�',
-  `version` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐗堟湰',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐘舵��',
-  `read_count` int NULL DEFAULT NULL COMMENT '宸茶浜烘暟',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瑙勭珷鍒跺害绠$悊' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for rules_regulations_management_file
--- ----------------------------
-DROP TABLE IF EXISTS `rules_regulations_management_file`;
-CREATE TABLE `rules_regulations_management_file`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢鍚嶇О',
-  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢璺緞',
-  `file_size` int NULL DEFAULT NULL COMMENT '鏂囦欢澶у皬',
-  `rules_regulations_management_id` int NULL DEFAULT NULL COMMENT '瑙勭珷鍒跺害ID',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '瑙勭珷鍒跺害绠$悊--闄勪欢' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for rygl_add_employee
--- ----------------------------
-DROP TABLE IF EXISTS `rygl_add_employee`;
-CREATE TABLE `rygl_add_employee`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT '搴忓彿',
-  `status` int NULL DEFAULT NULL COMMENT '1鍏ヨ亴2绂昏亴',
-  `employee_number` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍛樺伐缂栧彿',
-  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '濮撳悕',
-  `sex` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎬у埆',
-  `native_place` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绫嶈疮',
-  `post` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宀椾綅',
-  `home_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹跺涵浣忓潃',
-  `first_degree` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绗竴瀛﹀巻',
-  `major` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓撲笟',
-  `id_number` int NULL DEFAULT NULL COMMENT '韬唤璇佸彿',
-  `age` int NULL DEFAULT NULL COMMENT '骞撮緞',
-  `contact_number` int NULL DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
-  `emergency_contact` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绱ф�ヨ仈绯讳汉',
-  `emergency_contact_number` int NULL DEFAULT NULL COMMENT '绱ф�ヨ仈绯荤數璇�',
-  `contract_term` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍚堝悓骞撮檺',
-  `contract_start_date` datetime NULL DEFAULT NULL COMMENT '鍚堝悓寮�濮嬫棩鏈�',
-  `contract_end_date` datetime NULL DEFAULT NULL COMMENT '鍚堝悓缁撴潫鏃ユ湡',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for safe_accident
--- ----------------------------
-DROP TABLE IF EXISTS `safe_accident`;
-CREATE TABLE `safe_accident`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `accident_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜嬫晠缂栧彿',
-  `accident_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜嬫晠鍚嶇О',
-  `accident_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜嬫晠绫诲瀷',
-  `happen_time` datetime NULL DEFAULT NULL COMMENT '浜嬫晠鍙戠敓鏃堕棿',
-  `happen_location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜嬫晠鍙戠敓浣嶇疆',
-  `accident_grade` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜嬫晠绛夌骇',
-  `accident_cause` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '浜嬫晠鐩存帴鍘熷洜',
-  `root_cause` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '浜嬫晠鏍规湰鍘熷洜',
-  `person_loss` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜哄憳鎹熷け鎯呭喌',
-  `asset_loss` decimal(10, 2) NULL DEFAULT NULL COMMENT '鐩存帴璐骇鎹熷け锛堝厓锛�	',
-  `production_loss` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢熶骇褰卞搷鎯呭喌',
-  `handle_measures` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '鐜板満搴旀�ュ缃帾鏂�',
-  `responsible_person` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜嬫晠璐d换浜�',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` timestamp NULL DEFAULT NULL COMMENT '涓婃姤鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '涓婃姤浜篿d',
-  `update_time` timestamp NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹夊叏鐢熶骇--浜嬫晠涓婃姤璁板綍' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for safe_certification
--- ----------------------------
-DROP TABLE IF EXISTS `safe_certification`;
-CREATE TABLE `safe_certification`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勭▼璧勮川鍚嶇О',
-  `code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勭▼璧勮川缂栧彿',
-  `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勭▼璧勮川绫诲瀷',
-  `version` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐗堟湰鍙�',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `effective_time` date NULL DEFAULT NULL COMMENT '鏈夋晥鏈�',
-  `create_time` timestamp NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `update_time` timestamp NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹夊叏鐢熶骇--瀹夊叏瑙勭▼涓庤祫璐ㄧ鐞�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for safe_certification_file
--- ----------------------------
-DROP TABLE IF EXISTS `safe_certification_file`;
-CREATE TABLE `safe_certification_file`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `safe_certification_id` int NULL DEFAULT NULL COMMENT '鍏宠仈瀹夊叏鐢熶骇璧勮川id',
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `file_size` double NULL DEFAULT NULL,
-  `create_time` timestamp NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `update_time` timestamp NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹夊叏鐢熶骇--瀹夊叏瑙勭▼涓庤祫璐ㄧ鐞�--闄勪欢' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for safe_contingency_plan
--- ----------------------------
-DROP TABLE IF EXISTS `safe_contingency_plan`;
-CREATE TABLE `safe_contingency_plan`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `plan_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '搴旀�ラ妗堢紪鐮�',
-  `plan_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '搴旀�ラ妗堝悕绉�',
-  `plan_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '棰勬绫诲瀷',
-  `apply_scope` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閫傜敤鑼冨洿',
-  `core_responsor_user_id` int NULL DEFAULT NULL COMMENT '鏍稿績璐d换浜�',
-  `exec_steps` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '搴旀�ュ缃楠�',
-  `publish_time` date NULL DEFAULT NULL COMMENT '鍙戝竷鐢熸晥鏃堕棿',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` timestamp NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `update_time` timestamp NULL DEFAULT NULL COMMENT '鏈�鍚庝慨璁㈡椂闂�',
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹夊叏鐢熶骇--搴旀�ラ妗堟煡闃�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for safe_hazard
--- ----------------------------
-DROP TABLE IF EXISTS `safe_hazard`;
-CREATE TABLE `safe_hazard`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗遍櫓婧愬悕绉�',
-  `code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗遍櫓婧愮紪鐮�',
-  `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗遍櫓婧愮被鍨�',
-  `risk_level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '椋庨櫓绛夌骇',
-  `location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵�鍦ㄤ綅缃�',
-  `spec_info` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勬牸 / 椋庨櫓鎻忚堪',
-  `control_measures` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绠℃帶鎺柦',
-  `principal_user_id` int NULL DEFAULT NULL COMMENT '绠℃帶璐d换浜� ID',
-  `principal_mobile` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璐d换浜鸿仈绯荤數璇�',
-  `stock_qty` decimal(10, 2) NULL DEFAULT NULL COMMENT '搴撳瓨鏁伴噺',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` timestamp NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `update_time` timestamp NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹夊叏鐢熶骇--鍗遍櫓婧愬彴璐�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for safe_hazard_record
--- ----------------------------
-DROP TABLE IF EXISTS `safe_hazard_record`;
-CREATE TABLE `safe_hazard_record`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `material_record_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曞彿',
-  `safe_hazard_id` int NULL DEFAULT NULL COMMENT '鍏宠仈鍗遍櫓婧愬彴璐� ID',
-  `apply_user_id` int NULL DEFAULT NULL COMMENT '棰嗙敤浜� ID',
-  `apply_time` date NULL DEFAULT NULL COMMENT '棰嗙敤鏃堕棿',
-  `apply_qty` decimal(10, 2) NULL DEFAULT NULL COMMENT '棰嗙敤鏁伴噺',
-  `apply_purpose` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '棰嗙敤鐢ㄩ��',
-  `return_user_id` int NULL DEFAULT NULL COMMENT '褰掕繕浜� ID',
-  `return_time` date NULL DEFAULT NULL COMMENT '褰掕繕鏃堕棿',
-  `return_remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '褰掕繕鎯呭喌璇存槑',
-  `create_time` timestamp NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `update_time` timestamp NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹夊叏鐢熶骇--鍗遍櫓鐗╂枡绠℃帶' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for safe_hidden
--- ----------------------------
-DROP TABLE IF EXISTS `safe_hidden`;
-CREATE TABLE `safe_hidden`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `hidden_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '闅愭偅缂栧彿',
-  `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '闅愭偅绫诲瀷',
-  `risk_level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '闅愭偅椋庨櫓绛夌骇',
-  `location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '闅愭偅鍏蜂綋浣嶇疆',
-  `hidden_desc` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '闅愭偅鎻忚堪',
-  `rectify_user_id` int NULL DEFAULT NULL COMMENT '鏁存敼璐d换浜� ID',
-  `rectify_user_mobile` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏁存敼浜鸿仈绯荤數璇�',
-  `rectify_time` date NULL DEFAULT NULL COMMENT '鏁存敼瀹屾垚鏈熼檺(鏃ユ湡)',
-  `rectify_measures` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '鏁存敼鍏蜂綋鎺柦',
-  `rectify_actual_time` date NULL DEFAULT NULL COMMENT '瀹為檯鏁存敼瀹屾垚鏃堕棿',
-  `verify_user_id` int NULL DEFAULT NULL COMMENT '楠屾敹浜� ID',
-  `verify_result` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '楠屾敹缁撴灉',
-  `verify_remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '楠屾敹鎰忚',
-  `verify_time` date NULL DEFAULT NULL COMMENT '楠屾敹鏃堕棿',
-  `create_time` timestamp NULL DEFAULT NULL COMMENT '涓婃姤鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '涓婃姤浜篿d',
-  `update_time` timestamp NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹夊叏鐢熶骇--闅愭偅鎺掓煡涓婃姤' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for safe_hidden_file
--- ----------------------------
-DROP TABLE IF EXISTS `safe_hidden_file`;
-CREATE TABLE `safe_hidden_file`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `safe_hidden_id` int NULL DEFAULT NULL COMMENT '鍏宠仈闅愭偅鎺掓煡涓婃姤id',
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `file_size` double NULL DEFAULT NULL,
-  `create_time` timestamp NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `update_time` timestamp NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹夊叏鐢熶骇--闅愭偅鎺掓煡涓婃姤--闄勪欢' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for safe_training
--- ----------------------------
-DROP TABLE IF EXISTS `safe_training`;
-CREATE TABLE `safe_training`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `course_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '璇剧▼缂栧彿',
-  `training_objectives` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍩硅鐩爣',
-  `training_content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍩硅鍐呭',
-  `training_mode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍩硅鏂瑰紡',
-  `state` int NULL DEFAULT NULL COMMENT '鐘舵��(0锛氭湭寮�濮�1锛氳繘琛屼腑锛�2锛氬凡缁撴潫)',
-  `participants` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍙傚姞瀵硅薄',
-  `place_training` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍩硅鍦扮偣',
-  `training_lecturer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍩硅璁插笀',
-  `training_date` date NULL DEFAULT NULL COMMENT '鍩硅鏃ユ湡',
-  `opening_time` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '寮�濮嬫椂闂�(鏃跺垎绉�)',
-  `end_time` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '缁撴潫鏃堕棿(鏃跺垎绉�)',
-  `project_credits` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '璇鹃瀛﹀垎',
-  `class_hour` double NULL DEFAULT NULL COMMENT '璇炬椂',
-  `assessment_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鑰冩牳鏂瑰紡',
-  `comprehensive_assessment` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鏈鍩硅缁煎悎璇勪环',
-  `remarks` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `assessment_user_id` int NULL DEFAULT NULL COMMENT '璇勪环浜篿d',
-  `assessment_date` date NULL DEFAULT NULL COMMENT '璇勪环鏃堕棿',
-  `training_abstract` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍩硅鎽樿',
-  `create_time` timestamp NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `update_time` timestamp NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹夊叏鐢熶骇--瀹夊叏鍩硅鑰冩牳' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for safe_training_details
--- ----------------------------
-DROP TABLE IF EXISTS `safe_training_details`;
-CREATE TABLE `safe_training_details`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `user_id` int NULL DEFAULT NULL COMMENT '鐢ㄦ埛琛ㄦ牸锛坲ser锛変富閿�',
-  `safe_training_id` int NULL DEFAULT NULL COMMENT '鍏宠仈瀹夊叏鍩硅鑰冩牳id',
-  `examination_results` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鑰冩牳缁撴灉',
-  `create_time` timestamp NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `update_time` timestamp NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹夊叏鐢熶骇--瀹夊叏鍩硅鑰冩牳--璁板綍璇︽儏' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for safe_training_file
--- ----------------------------
-DROP TABLE IF EXISTS `safe_training_file`;
-CREATE TABLE `safe_training_file`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `safe_training_id` int NULL DEFAULT NULL COMMENT '鍏宠仈瀹夊叏鍩硅鑰冩牳id',
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `file_size` double NULL DEFAULT NULL,
-  `create_time` timestamp NULL DEFAULT NULL,
-  `create_user` int NULL DEFAULT NULL,
-  `update_time` timestamp NULL DEFAULT NULL,
-  `update_user` int NULL DEFAULT NULL,
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹夊叏鐢熶骇--瀹夊叏鍩硅鑰冩牳--闄勪欢' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sales_ledger
--- ----------------------------
-DROP TABLE IF EXISTS `sales_ledger`;
-CREATE TABLE `sales_ledger`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT '閿�鍞彴璐︿富閿�',
-  `sales_contract_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '閿�鍞悎鍚屽彿',
-  `customer_contract_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹㈡埛鍚堝悓鍙�',
-  `project_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '椤圭洰鍚嶇О',
-  `entry_date` date NULL DEFAULT NULL COMMENT '褰曞叆鏃ユ湡',
-  `salesman` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓氬姟鍛�',
-  `customer_id` int NULL DEFAULT NULL COMMENT '瀹㈡埛鍚嶇Оid',
-  `customer_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹㈡埛鍚嶇О',
-  `entry_person` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '褰曞叆浜�',
-  `remarks` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '澶囨敞',
-  `attachment_materials` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '闄勪欢鏉愭枡锛屽瓨鍌ㄦ枃浠跺悕绛夌浉鍏充俊鎭�',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `contract_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍚堝悓閲戦锛堜骇鍝佸惈绋庢�讳环锛�',
-  `execution_date` datetime NULL DEFAULT NULL COMMENT '绛捐鏃ユ湡',
-  `payment_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `delivery_date` timestamp NULL DEFAULT NULL COMMENT '浜よ揣鏃ユ湡',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_sales_entry_person`(`entry_person` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 57 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閿�鍞彴璐�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sales_ledger_product
--- ----------------------------
-DROP TABLE IF EXISTS `sales_ledger_product`;
-CREATE TABLE `sales_ledger_product`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT '浜у搧淇℃伅涓婚敭',
-  `sales_ledger_id` int NOT NULL COMMENT '鍏宠仈鍙拌处涓昏〃涓婚敭',
-  `product_category` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜у搧澶х被',
-  `specification_model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `unit` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `quantity` decimal(18, 2) NOT NULL COMMENT '鏁伴噺',
-  `min_stock` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏈�浣庡簱瀛�',
-  `tax_rate` decimal(5, 0) NOT NULL COMMENT '绋庣巼',
-  `tax_inclusive_unit_price` decimal(18, 2) NOT NULL COMMENT '鍚◣鍗曚环',
-  `tax_inclusive_total_price` decimal(18, 2) NOT NULL COMMENT '鍚◣鎬讳环',
-  `tax_exclusive_total_price` decimal(18, 2) NOT NULL COMMENT '涓嶅惈绋庢�讳环',
-  `invoice_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙戠エ绫诲瀷',
-  `type` int NULL DEFAULT NULL COMMENT '1.閿�鍞彴璐︼紝2.閲囪喘鍙拌处',
-  `product_id` int NULL DEFAULT NULL COMMENT '浜у搧id',
-  `product_model_id` int NULL DEFAULT NULL COMMENT '鍨嬪彿id',
-  `register` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐧昏浜�',
-  `register_date` datetime NULL DEFAULT NULL COMMENT '鐧昏鏃ユ湡',
-  `warn_num` decimal(10, 2) NULL DEFAULT NULL COMMENT '棰勮鏁伴噺',
-  `approve_status` int NULL DEFAULT 0 COMMENT '瀹℃壒鐘舵�侊細0鏈嚭搴�,1宸插嚭搴�,2寰呭鏍�(瀹℃牳涓�),3瀹℃牳瀹屾垚,4瀹℃牳澶辫触',
-  `is_checked` tinyint(1) NOT NULL DEFAULT 1 COMMENT '鏄惁鎺ㄩ�佽川妫�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `is_production` tinyint(1) NULL DEFAULT 0 COMMENT '鏄惁鐢熶骇',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 105 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浜у搧淇℃伅' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sales_ledger_product_template
--- ----------------------------
-DROP TABLE IF EXISTS `sales_ledger_product_template`;
-CREATE TABLE `sales_ledger_product_template`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT '浜у搧淇℃伅涓婚敭',
-  `sales_ledger_id` int NOT NULL COMMENT '鍏宠仈鍙拌处妯℃澘涓昏〃涓婚敭',
-  `product_category` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜у搧澶х被',
-  `specification_model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `unit` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `quantity` decimal(18, 2) NULL DEFAULT NULL COMMENT '鏁伴噺',
-  `min_stock` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏈�浣庡簱瀛�',
-  `tax_rate` decimal(5, 0) NULL DEFAULT NULL COMMENT '绋庣巼',
-  `tax_inclusive_unit_price` decimal(18, 2) NULL DEFAULT NULL COMMENT '鍚◣鍗曚环',
-  `tax_inclusive_total_price` decimal(18, 2) NULL DEFAULT NULL COMMENT '鍚◣鎬讳环',
-  `tax_exclusive_total_price` decimal(18, 2) NULL DEFAULT NULL COMMENT '涓嶅惈绋庢�讳环',
-  `invoice_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙戠エ绫诲瀷',
-  `type` int NULL DEFAULT NULL COMMENT '1.閿�鍞彴璐︼紝2.閲囪喘鍙拌处',
-  `product_id` bigint NULL DEFAULT NULL COMMENT '浜у搧id',
-  `product_model_id` bigint NULL DEFAULT NULL COMMENT '鍨嬪彿id',
-  `register` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `register_date` datetime NULL DEFAULT NULL,
-  `warn_num` decimal(10, 2) NULL DEFAULT NULL,
-  `is_checked` tinyint NULL DEFAULT 1 COMMENT '鏄惁鎺ㄩ�佽川妫�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浜у搧淇℃伅妯℃澘' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sales_quotation
--- ----------------------------
-DROP TABLE IF EXISTS `sales_quotation`;
-CREATE TABLE `sales_quotation`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `quotation_no` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鎶ヤ环鍗曞彿',
-  `customer_id` bigint NOT NULL DEFAULT 0 COMMENT '瀹㈡埛id',
-  `salesperson` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '涓氬姟鍛�',
-  `quotation_date` date NULL DEFAULT NULL COMMENT '鎶ヤ环鏃ユ湡',
-  `valid_date` date NULL DEFAULT NULL COMMENT '鏈夋晥鏈熻嚦',
-  `total_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '鎶ヤ环閲戦',
-  `payment_method` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '浠樻鏂瑰紡',
-  `delivery_period` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '浜よ揣鏈�,澶╂暟',
-  `status` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鎶ヤ环鐘舵��',
-  `remark` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `customer` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 49 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin COMMENT = '閿�鍞�/鎶ヤ环' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sales_quotation_product
--- ----------------------------
-DROP TABLE IF EXISTS `sales_quotation_product`;
-CREATE TABLE `sales_quotation_product`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `sales_quotation_id` int NULL DEFAULT NULL COMMENT '閿�鍞姤浠峰崟id',
-  `product` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '浜у搧鍚嶇О',
-  `product_id` bigint NULL DEFAULT NULL COMMENT '浜у搧Id',
-  `specification` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-  `quantity` int NULL DEFAULT NULL COMMENT '鏁伴噺',
-  `unit` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `unit_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍗曚环',
-  `amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '閲戦',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `product_model_id` bigint NULL DEFAULT NULL COMMENT '浜у搧瑙勬牸Id',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 55 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin COMMENT = '閿�鍞姤浠蜂骇鍝佽〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sales_receipt_return
--- ----------------------------
-DROP TABLE IF EXISTS `sales_receipt_return`;
-CREATE TABLE `sales_receipt_return`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭 ID',
-  `refund_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '閫�娆惧崟鍙�',
-  `payment_account` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浠樻璐﹀彿',
-  `payment_account_name` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浠樻璐﹀彿鍚嶇О',
-  `payment_method` tinyint NULL DEFAULT NULL COMMENT '浠樻鏂瑰紡',
-  `actual_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '瀹為檯浠樻閲戦',
-  `fee` decimal(10, 2) NULL DEFAULT NULL COMMENT '鎵嬬画璐�',
-  `transaction_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜ゆ槗鍙�',
-  `discount_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '浼樻儬閲戦',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鏀舵閫�璐ц〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sales_refund_amount_order
--- ----------------------------
-DROP TABLE IF EXISTS `sales_refund_amount_order`;
-CREATE TABLE `sales_refund_amount_order`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `return_management_id` bigint NULL DEFAULT NULL COMMENT '閫�璐у崟鍙穒d',
-  `status` int NULL DEFAULT NULL COMMENT '鐘舵�� 0:寰呭鏍� 1:寰呴��娆� 2锛氬凡閫�娆�',
-  `refund_amount` decimal(16, 3) NULL DEFAULT NULL COMMENT '搴旈��娆鹃噾棰�',
-  `refunded_amount` decimal(16, 3) NULL DEFAULT NULL COMMENT '宸查��娆鹃噾棰�',
-  `not_refunded_amount` decimal(16, 3) NULL DEFAULT NULL COMMENT '鏈��娆鹃噾棰�',
-  `create_time` timestamp NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_time` timestamp NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篿d',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊浜篿d',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '閿�鍞鐞�--閫�娆惧崟' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for salesperson_management
--- ----------------------------
-DROP TABLE IF EXISTS `salesperson_management`;
-CREATE TABLE `salesperson_management`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '濮撳悕',
-  `phone` varchar(15) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
-  `email` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '閭',
-  `department` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '閮ㄩ棬',
-  `position` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鑱屼綅',
-  `hire_date` datetime NULL DEFAULT NULL COMMENT '鍏ヨ亴鏃ユ湡',
-  `permissions` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鏉冮檺',
-  `status` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鐘舵��',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃ユ湡',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin COMMENT = '涓氬姟鍛樼鐞嗚〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for scheme_applicable_staff
--- ----------------------------
-DROP TABLE IF EXISTS `scheme_applicable_staff`;
-CREATE TABLE `scheme_applicable_staff`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏍囬',
-  `dept_ids` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閮ㄩ棬ids',
-  `staff_names` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜哄憳鍚嶇О,澶氫釜浣跨敤,闅斿紑',
-  `staff_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浜哄憳id,澶氫釜浣跨敤,闅斿紑',
-  `insurance_types` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '淇濋櫓绫诲瀷鍚嶇О澶氫釜浣跨敤,闅斿紑',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` timestamp NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_time` timestamp NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '绀句繚鏂规閫傜敤浜哄憳琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for scheme_insurance_detail
--- ----------------------------
-DROP TABLE IF EXISTS `scheme_insurance_detail`;
-CREATE TABLE `scheme_insurance_detail`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏄庣粏ID锛堜富閿級',
-  `scheme_id` bigint NULL DEFAULT NULL COMMENT '鍏宠仈鐨勭ぞ淇濇柟妗圛D',
-  `insurance_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '淇濋櫓绫诲瀷锛堝鍖荤枟淇濋櫓銆佸吇鑰佷繚闄╃瓑锛�',
-  `payment_base` decimal(10, 2) NULL DEFAULT NULL COMMENT '缂磋垂鍩烘暟',
-  `use_basic_salary` int NULL DEFAULT 1 COMMENT '鏄惁璋冪敤鍩烘湰宸ヨ祫锛�1-鍚︼紝2-鏄�',
-  `personal_ratio` decimal(5, 2) NULL DEFAULT 0.00 COMMENT '涓汉缂磋垂姣斾緥锛�%锛�',
-  `personal_fixed` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '涓汉鍥哄畾缂磋垂閲戦',
-  `create_time` timestamp NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_time` timestamp NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '绀句繚鏂规淇濋櫓绂忓埄鏄庣粏琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for seal_application_management
--- ----------------------------
-DROP TABLE IF EXISTS `seal_application_management`;
-CREATE TABLE `seal_application_management`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `application_num` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢宠缂栧彿',
-  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢宠鏍囬',
-  `seal_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢ㄥ嵃绫诲瀷',
-  `reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢宠鐢ㄥ嵃鍘熷洜',
-  `urgency` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绱ф�ョ▼搴�',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐘舵��',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�-鐢宠浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿-鐢宠鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `approve_user_id` int NULL DEFAULT NULL COMMENT '瀹℃壒浜篿d',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢ㄥ嵃鐢宠绠$悊' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for shipping_info
--- ----------------------------
-DROP TABLE IF EXISTS `shipping_info`;
-CREATE TABLE `shipping_info`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `sales_ledger_id` bigint NULL DEFAULT NULL COMMENT '閿�鍞彴璐d',
-  `shipping_date` datetime NULL DEFAULT NULL COMMENT '鍙戣揣鏃ユ湡',
-  `shipping_car_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鍙戣揣杞︾墝鍙�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `sales_ledger_product_id` int NULL DEFAULT NULL COMMENT '閿�鍞彴璐︿骇鍝佽〃id',
-  `shipping_no` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鍙戣揣缂栧彿',
-  `express_number` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '蹇�掑崟鍙�',
-  `express_company` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '蹇�掑叕鍙�',
-  `type` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鍙戣揣绫诲瀷',
-  `status` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鐘舵��',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_shipping_sales_ledger_status`(`sales_ledger_id` ASC, `status` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 68 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin COMMENT = '鍙戣揣淇℃伅琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for shipping_product_detail
--- ----------------------------
-DROP TABLE IF EXISTS `shipping_product_detail`;
-CREATE TABLE `shipping_product_detail`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭id',
-  `stock_inventory_id` bigint NULL DEFAULT NULL COMMENT '搴撳瓨琛╥d',
-  `batch_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵规鍙�',
-  `quantity` decimal(16, 4) NULL DEFAULT NULL COMMENT '鍙戣揣鐨勬暟閲�',
-  `shipping_info_id` bigint NULL DEFAULT NULL COMMENT '鍙戣揣鍙拌处id',
-  `product_model_id` bigint NULL DEFAULT NULL COMMENT '浜у搧id',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 80 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍙戣揣鍙拌处璇︽儏琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for spare_parts
--- ----------------------------
-DROP TABLE IF EXISTS `spare_parts`;
-CREATE TABLE `spare_parts`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囦欢鍒嗙被鍚嶇О',
-  `parent_id` int NULL DEFAULT NULL COMMENT '澶囦欢鍒嗙被鐖秈d',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐘舵��',
-  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎻忚堪',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `price` decimal(10, 2) NULL DEFAULT NULL COMMENT '浠锋牸',
-  `quantity` decimal(10, 2) NULL DEFAULT NULL COMMENT '鏁伴噺',
-  `device_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧id闆嗗悎锛堝瓧绗︿覆,闅斿紑锛�',
-  `spare_parts_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璁惧绠$悊-澶囦欢绠$悊' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for spare_parts_requisition_record
--- ----------------------------
-DROP TABLE IF EXISTS `spare_parts_requisition_record`;
-CREATE TABLE `spare_parts_requisition_record`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `source_type` smallint NULL DEFAULT NULL COMMENT '鏉ユ簮绫诲瀷(0 缁翠慨 1 淇濆吇)',
-  `source_id` bigint NOT NULL DEFAULT 0 COMMENT '鏉ユ簮id',
-  `device_ledger_id` bigint NOT NULL DEFAULT 0 COMMENT '璁惧id',
-  `spare_parts_id` bigint NOT NULL DEFAULT 0 COMMENT '澶囦欢id',
-  `quantity` int NOT NULL DEFAULT 0 COMMENT '鏁伴噺',
-  `create_user` bigint NOT NULL DEFAULT 0 COMMENT '鍒涘缓浜�',
-  `tenant_id` bigint NOT NULL COMMENT '绉熸埛id',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '璁惧鎶ヤ慨淇濆吇鐨勫浠堕浣跨敤琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for staff_contacts_personal
--- ----------------------------
-DROP TABLE IF EXISTS `staff_contacts_personal`;
-CREATE TABLE `staff_contacts_personal`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `contact_id` int NULL DEFAULT NULL COMMENT '鍛樺伐ID',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin COMMENT = '涓汉閫氳褰�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for staff_contract
--- ----------------------------
-DROP TABLE IF EXISTS `staff_contract`;
-CREATE TABLE `staff_contract`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `staff_on_job_id` bigint NOT NULL DEFAULT 0 COMMENT '鍛樺伐鍦ㄨ亴id',
-  `contract_start_time` datetime NULL DEFAULT NULL COMMENT '鍚堝悓寮�濮嬫椂闂�',
-  `contract_end_time` datetime NULL DEFAULT NULL COMMENT '鍚堝悓缁撴潫鏃堕棿',
-  `contract_term` int NOT NULL DEFAULT 0 COMMENT '鍚堝悓鏈熼檺',
-  `tenant_id` bigint NOT NULL COMMENT '绉熸埛id',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 23 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for staff_education
--- ----------------------------
-DROP TABLE IF EXISTS `staff_education`;
-CREATE TABLE `staff_education`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `staff_on_job_id` bigint NOT NULL COMMENT '鍏宠仈staff_on_job琛ㄤ富閿甀D',
-  `education` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀛﹀巻',
-  `school_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '姣曚笟闄㈡牎',
-  `enroll_time` date NULL DEFAULT NULL COMMENT '鍏ュ鏃堕棿',
-  `graduate_time` date NULL DEFAULT NULL COMMENT '姣曚笟鏃堕棿',
-  `major` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓撲笟',
-  `degree` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀛︿綅',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍛樺伐鏁欒偛缁忓巻琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for staff_emergency_contact
--- ----------------------------
-DROP TABLE IF EXISTS `staff_emergency_contact`;
-CREATE TABLE `staff_emergency_contact`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `staff_on_job_id` bigint NOT NULL COMMENT '鍏宠仈staff_on_job琛ㄤ富閿甀D',
-  `contact_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绱ф�ヨ仈绯讳汉濮撳悕',
-  `contact_relation` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绱ф�ヨ仈绯讳汉鍏崇郴',
-  `contact_phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绱ф�ヨ仈绯讳汉鎵嬫満',
-  `contact_address` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绱ф�ヨ仈绯讳汉浣忓潃',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍛樺伐绱ф�ヨ仈绯讳汉琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for staff_join_leave_record
--- ----------------------------
-DROP TABLE IF EXISTS `staff_join_leave_record`;
-CREATE TABLE `staff_join_leave_record`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `staff_state` int NULL DEFAULT NULL COMMENT '鐘舵��(0:绂昏亴;1:鍏ヨ亴)',
-  `staff_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍛樺伐缂栧彿',
-  `leave_date` date NULL DEFAULT NULL COMMENT '绂昏亴鏃ユ湡',
-  `staff_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍛樺伐濮撳悕',
-  `sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎬у埆',
-  `native_place` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绫嶈疮',
-  `post_job` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宀椾綅',
-  `adress` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹跺涵浣忓潃',
-  `first_study` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绗竴瀛﹀巻',
-  `profession` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓撲笟',
-  `identity_card` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '韬唤璇佸彿鐮�',
-  `age` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '骞撮緞',
-  `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
-  `emergency_contact` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绱ф�ヨ仈绯讳汉',
-  `emergency_contact_phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绱ф�ヨ仈绯讳汉鐢佃瘽',
-  `contract_term` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍚堝悓骞撮檺',
-  `contract_start_time` date NULL DEFAULT NULL COMMENT '鍚堝悓寮�濮嬫棩鏈�',
-  `contract_end_time` date NULL DEFAULT NULL COMMENT '鍚堝悓缁撴潫鏃ユ湡',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `probation_period` int NULL DEFAULT NULL COMMENT '璇曠敤鏈燂紙鏈堬級',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浜哄憳绠$悊--鏂板鍏ヨ亴/绂昏亴' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for staff_leave
--- ----------------------------
-DROP TABLE IF EXISTS `staff_leave`;
-CREATE TABLE `staff_leave`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `staff_on_job_id` bigint NOT NULL DEFAULT 0 COMMENT '鍛樺伐鍦ㄨ亴id',
-  `reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绂昏亴鍘熷洜',
-  `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '绂昏亴澶囨敞',
-  `tenant_id` bigint NOT NULL COMMENT '绉熸埛id',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `leave_date` date NULL DEFAULT NULL COMMENT '绂昏亴鏃ユ湡',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for staff_on_job
--- ----------------------------
-DROP TABLE IF EXISTS `staff_on_job`;
-CREATE TABLE `staff_on_job`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `staff_state` int NULL DEFAULT NULL COMMENT '鐘舵��(0:绂昏亴;1:鍦ㄨ亴)',
-  `staff_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍛樺伐缂栧彿',
-  `staff_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍛樺伐濮撳悕',
-  `sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎬у埆',
-  `native_place` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绫嶈疮',
-  `adress` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹跺涵浣忓潃',
-  `first_study` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绗竴瀛﹀巻',
-  `profession` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓撲笟',
-  `identity_card` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '韬唤璇佸彿鐮�',
-  `age` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '骞撮緞',
-  `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
-  `emergency_contact` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绱ф�ヨ仈绯讳汉',
-  `emergency_contact_phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绱ф�ヨ仈绯讳汉鐢佃瘽',
-  `contract_term` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍚堝悓骞撮檺',
-  `contract_expire_time` date NULL DEFAULT NULL COMMENT '鍚堝悓鍒版湡鏃ユ湡',
-  `trial_end_date` date NULL DEFAULT NULL COMMENT '缁撴潫璇曠敤鏃堕棿',
-  `trial_start_date` date NULL DEFAULT NULL COMMENT '寮�濮嬭瘯鐢ㄦ椂闂�',
-  `salary_select` char(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸ヨ祫鎶ラ叕閫夋嫨鏉℃',
-  `pro_salary` decimal(10, 2) NULL DEFAULT NULL COMMENT '璇曠敤鏈熷伐璧�',
-  `date_select` char(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍔冲姩鍚堝悓鏈熼檺閫夋嫨',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '鏃�' COMMENT '澶囨敞锛堢鍒╁緟閬囷級',
-  `sign_date` date NULL DEFAULT NULL COMMENT '绛捐鏃ユ湡',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `sys_post_id` bigint NOT NULL DEFAULT 0 COMMENT '宀椾綅id',
-  `sys_dept_id` bigint NOT NULL DEFAULT 0 COMMENT '閮ㄩ棬id',
-  `role_id` bigint NULL DEFAULT NULL COMMENT '瑙掕壊id',
-  `alias` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒悕',
-  `birth_date` date NULL DEFAULT NULL COMMENT '鍑虹敓鏃ユ湡',
-  `nation` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '姹夋棌' COMMENT '姘戞棌',
-  `marital_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '鏈' COMMENT '濠氬Щ鐘跺喌',
-  `pro_term` int NULL DEFAULT 3 COMMENT '璇曠敤鏈燂紙鏈堬級',
-  `positive_date` date NULL DEFAULT NULL COMMENT '杞鏃ユ湡',
-  `basic_salary` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '鍩烘湰宸ヨ祫',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  UNIQUE INDEX `staff_no`(`staff_no` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 27 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浜哄憳绠$悊--鍛樺伐鍙拌处/鍚堝悓绠$悊' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for staff_salary_detail
--- ----------------------------
-DROP TABLE IF EXISTS `staff_salary_detail`;
-CREATE TABLE `staff_salary_detail`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `main_id` bigint NOT NULL COMMENT '鍏宠仈宸ヨ祫涓昏〃ID',
-  `staff_on_job_id` bigint NOT NULL COMMENT '鍏宠仈staff_on_job琛ㄤ富閿甀D',
-  `staff_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍛樺伐濮撳悕',
-  `post_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鑱屼綅鍚嶇О',
-  `dept_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閮ㄩ棬鍚嶇О',
-  `basic_salary` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '鍩烘湰宸ヨ祫',
-  `piece_salary` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '璁′欢宸ヨ祫',
-  `hourly_salary` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '璁℃椂宸ヨ祫',
-  `other_income` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '鍏朵粬鏀跺叆',
-  `social_personal` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '绀句繚涓汉',
-  `fund_personal` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '鍏Н閲戜釜浜�',
-  `other_deduct` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '鍏朵粬鏀嚭',
-  `salary_tax` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '宸ヨ祫涓◣',
-  `gross_salary` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '搴斿彂宸ヨ祫',
-  `deduct_salary` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '搴旀墸宸ヨ祫',
-  `net_salary` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '瀹炲彂宸ヨ祫',
-  `remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `social_supplement_amount` decimal(18, 2) NOT NULL DEFAULT 0.00 COMMENT '绀句繚琛ョ即',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 185 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍛樺伐宸ヨ祫鏄庣粏琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for staff_salary_main
--- ----------------------------
-DROP TABLE IF EXISTS `staff_salary_main`;
-CREATE TABLE `staff_salary_main`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `audit_user_id` bigint NULL DEFAULT NULL COMMENT '瀹℃牳浜篿d',
-  `audit_user_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹℃牳浜哄悕绉�',
-  `salary_title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸ヨ祫涓婚',
-  `dept_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏宠仈閮ㄩ棬ID锛屽涓敤閫楀彿鍒嗛殧',
-  `salary_month` varchar(7) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸ヨ祫鏈堜唤锛屾牸寮忥細yyyy-MM',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵�侊細1-鑽夌 2-瀹℃牳鏈�氳繃 3-寰呭鏍� 4-寰呭彂鏀� 5-宸插彂鏀�',
-  `total_salary` decimal(12, 2) NULL DEFAULT NULL COMMENT '宸ヨ祫鎬婚',
-  `pay_bank` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏀粯閾惰',
-  `pay_time` datetime NULL DEFAULT NULL COMMENT '鍙戞斁鏃堕棿',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍛樺伐宸ヨ祫涓昏〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for staff_scheduling
--- ----------------------------
-DROP TABLE IF EXISTS `staff_scheduling`;
-CREATE TABLE `staff_scheduling`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `staff_id` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鍛樺伐ID',
-  `department` int NULL DEFAULT NULL COMMENT '閮ㄩ棬',
-  `shift_type` int NULL DEFAULT NULL COMMENT '鎺掔彮绫诲瀷',
-  `work_date` date NULL DEFAULT NULL COMMENT '宸ヤ綔鏃ユ湡',
-  `work_start_time` timestamp NULL DEFAULT NULL COMMENT '寮�濮嬪伐浣滄椂闂�',
-  `lunch_time` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '鍗堜紤鏃堕棿',
-  `work_end_time` timestamp NULL DEFAULT NULL COMMENT '缁撴潫宸ヤ綔鏃堕棿',
-  `work_hours` decimal(10, 2) NULL DEFAULT NULL COMMENT '宸ヤ綔鏃堕暱',
-  `status` int NULL DEFAULT NULL COMMENT '鐘舵��',
-  `staff_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL,
-  `remark` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for staff_work_experience
--- ----------------------------
-DROP TABLE IF EXISTS `staff_work_experience`;
-CREATE TABLE `staff_work_experience`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `staff_on_job_id` bigint NOT NULL COMMENT '鍏宠仈staff_on_job琛ㄤ富閿甀D',
-  `former_company` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍓嶅叕鍙�',
-  `former_dept` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍓嶅叕鍙搁儴闂�',
-  `former_position` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍓嶅叕鍙歌亴浣�',
-  `start_date` date NULL DEFAULT NULL COMMENT '寮�濮嬫棩鏈�',
-  `end_date` date NULL DEFAULT NULL COMMENT '缁撴潫鏃ユ湡',
-  `work_desc` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸ヤ綔鎻忚堪',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍛樺伐宸ヤ綔缁忓巻琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for stock_in_record
--- ----------------------------
-DROP TABLE IF EXISTS `stock_in_record`;
-CREATE TABLE `stock_in_record`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `inbound_batches` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏ュ簱鎵规',
-  `batch_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵瑰彿',
-  `stock_in_num` decimal(16, 4) NULL DEFAULT NULL COMMENT '鍏ュ簱鏁伴噺',
-  `record_id` int NULL DEFAULT NULL COMMENT '鍏ュ簱鏉ユ簮id',
-  `record_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏ュ簱绫诲瀷',
-  `product_model_id` int NULL DEFAULT NULL COMMENT '浜у搧瑙勬牸id',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` timestamp NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_time` timestamp NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '0鍚堟牸鍏ュ簱1涓嶅悎鏍煎叆搴�',
-  `weighing_date` datetime NULL DEFAULT NULL COMMENT '杩囩鏃ユ湡',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `approval_status` int NULL DEFAULT 0,
-  `warn_num` decimal(16, 4) NULL DEFAULT NULL,
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 153 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍏ュ簱璁板綍琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for stock_inventory
--- ----------------------------
-DROP TABLE IF EXISTS `stock_inventory`;
-CREATE TABLE `stock_inventory`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭id',
-  `product_model_id` int NULL DEFAULT NULL COMMENT '瑙勬牸id',
-  `batch_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵瑰彿',
-  `qualitity` decimal(16, 4) NULL DEFAULT NULL COMMENT '鏁伴噺',
-  `create_time` timestamp NULL DEFAULT NULL,
-  `update_time` timestamp NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `version` int NULL DEFAULT NULL COMMENT '鐗堟湰鍙�',
-  `locked_quantity` decimal(16, 4) NULL DEFAULT 0.0000 COMMENT '琚鍗曢攣瀹氭暟閲�',
-  `warn_num` decimal(16, 4) NULL DEFAULT NULL COMMENT '棰勮鏁伴噺',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 72 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '搴撳瓨琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for stock_out_record
--- ----------------------------
-DROP TABLE IF EXISTS `stock_out_record`;
-CREATE TABLE `stock_out_record`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `outbound_batches` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏ュ簱鎵规',
-  `batch_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵瑰彿',
-  `stock_out_num` decimal(16, 4) NULL DEFAULT NULL COMMENT '鍏ュ簱鏁伴噺',
-  `record_id` int NULL DEFAULT NULL COMMENT '鍏ュ簱鏉ユ簮id',
-  `record_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏ュ簱绫诲瀷',
-  `product_model_id` int NULL DEFAULT NULL COMMENT '浜у搧瑙勬牸id',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_time` timestamp NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_time` timestamp NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏇存柊浜�',
-  `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '0鍚堟牸鍑哄簱1涓嶅悎鏍煎嚭搴�',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `approval_status` int NULL DEFAULT 0 COMMENT '瀹℃壒鐘舵��  0-寰呭鎵� 1-閫氳繃 2-椹冲洖 3-閿�鍞嚭搴撳緟纭',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 157 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍑哄簱璁板綍琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for stock_uninventory
--- ----------------------------
-DROP TABLE IF EXISTS `stock_uninventory`;
-CREATE TABLE `stock_uninventory`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭id',
-  `product_model_id` int NULL DEFAULT NULL COMMENT '瑙勬牸id',
-  `batch_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鎵瑰彿',
-  `qualitity` decimal(16, 4) NULL DEFAULT NULL COMMENT '鏁伴噺',
-  `create_time` timestamp NULL DEFAULT NULL,
-  `update_time` timestamp NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `version` int NULL DEFAULT NULL COMMENT '鐗堟湰鍙�',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `locked_quantity` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍐荤粨鏁伴噺',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '涓嶅悎鏍煎簱瀛樿〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for storage_attachment
--- ----------------------------
-DROP TABLE IF EXISTS `storage_attachment`;
-CREATE TABLE `storage_attachment`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `deleted` bigint NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎锛�0姝e父锛�',
-  `record_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏宠仈鐨勮褰曠被鍨�',
-  `record_id` bigint NULL DEFAULT NULL COMMENT '鍏宠仈鐨勮褰旾D',
-  `application` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢鐢ㄩ�旓紝濡� file/avatar',
-  `storage_blob_id` bigint NULL DEFAULT NULL COMMENT '鍏宠仈storage_blob璁板綍ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 215 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鏂囦欢鍏宠仈琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for storage_blob
--- ----------------------------
-DROP TABLE IF EXISTS `storage_blob`;
-CREATE TABLE `storage_blob`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `resource_key` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璧勬簮鍞竴鏍囪瘑锛堝瀵硅薄瀛樺偍key锛�',
-  `content_type` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璧勬簮绫诲瀷锛屽 image/jpeg',
-  `original_filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍘熸枃浠跺悕',
-  `uid_filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍞竴鏂囦欢鍚�',
-  `byte_size` bigint NULL DEFAULT NULL COMMENT '鏂囦欢澶у皬锛堝瓧鑺傦級',
-  `path` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢璺緞锛堟湰鍦版垨URL锛�',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 195 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鏂囦欢琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for supplier_manage
--- ----------------------------
-DROP TABLE IF EXISTS `supplier_manage`;
-CREATE TABLE `supplier_manage`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `supplier_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉�',
-  `taxpayer_identification_num` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '绾崇◣浜鸿瘑鍒彿',
-  `company_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏徃鍦板潃',
-  `supplier_type` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '渚涘簲鍟嗙被鍨�',
-  `company_phone` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍏徃鐢佃瘽',
-  `bank_account_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '寮�鎴疯',
-  `bank_account_num` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璐﹀彿',
-  `contact_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鑱旂郴浜�',
-  `contact_user_phone` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
-  `maintain_user_id` bigint NULL DEFAULT NULL COMMENT '缁存姢浜篒D',
-  `maintain_time` datetime NULL DEFAULT NULL COMMENT '缁存姢鏃堕棿',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `is_white` bigint NULL DEFAULT 0 COMMENT '鏄惁鐧藉悕鍗曪紙0鏄� 1鍚︼級',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 223 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '渚涘簲鍟嗙鐞�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for supplier_manage_file
--- ----------------------------
-DROP TABLE IF EXISTS `supplier_manage_file`;
-CREATE TABLE `supplier_manage_file`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢鍚嶇О',
-  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏂囦欢璺緞',
-  `file_size` int NULL DEFAULT NULL COMMENT '鏂囦欢澶у皬',
-  `supplier_id` bigint NULL DEFAULT NULL COMMENT '渚涘簲鍟咺D',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '渚涘簲鍟嗙鐞�--璧勮川闄勪欢' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_config
--- ----------------------------
-DROP TABLE IF EXISTS `sys_config`;
-CREATE TABLE `sys_config`  (
-  `config_id` int NOT NULL AUTO_INCREMENT COMMENT '鍙傛暟涓婚敭',
-  `config_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍙傛暟鍚嶇О',
-  `config_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍙傛暟閿悕',
-  `config_value` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍙傛暟閿��',
-  `config_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT 'N' COMMENT '绯荤粺鍐呯疆锛圷鏄� N鍚︼級',
-  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  PRIMARY KEY (`config_id`) USING BTREE,
-  INDEX `idx_config_key`(`config_key` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍙傛暟閰嶇疆琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_dept
--- ----------------------------
-DROP TABLE IF EXISTS `sys_dept`;
-CREATE TABLE `sys_dept`  (
-  `dept_id` bigint NOT NULL AUTO_INCREMENT COMMENT '閮ㄩ棬id',
-  `parent_id` bigint NULL DEFAULT 0 COMMENT '鐖堕儴闂╥d',
-  `ancestors` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '绁栫骇鍒楄〃',
-  `dept_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '閮ㄩ棬鍚嶇О',
-  `order_num` int NULL DEFAULT 0 COMMENT '鏄剧ず椤哄簭',
-  `leader` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璐熻矗浜�',
-  `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
-  `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閭',
-  `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-  `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
-  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `dept_nick` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閮ㄩ棬缂栧彿',
-  PRIMARY KEY (`dept_id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 213 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閮ㄩ棬琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_dict_data
--- ----------------------------
-DROP TABLE IF EXISTS `sys_dict_data`;
-CREATE TABLE `sys_dict_data`  (
-  `dict_code` bigint NOT NULL AUTO_INCREMENT COMMENT '瀛楀吀缂栫爜',
-  `dict_sort` int NULL DEFAULT 0 COMMENT '瀛楀吀鎺掑簭',
-  `dict_label` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '瀛楀吀鏍囩',
-  `dict_value` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '瀛楀吀閿��',
-  `dict_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '瀛楀吀绫诲瀷',
-  `css_class` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�',
-  `list_class` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '琛ㄦ牸鍥炴樉鏍峰紡',
-  `is_default` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT 'N' COMMENT '鏄惁榛樿锛圷鏄� N鍚︼級',
-  `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  PRIMARY KEY (`dict_code`) USING BTREE,
-  INDEX `idx_dict_type_status`(`dict_type` ASC, `status` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 260 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀛楀吀鏁版嵁琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_dict_type
--- ----------------------------
-DROP TABLE IF EXISTS `sys_dict_type`;
-CREATE TABLE `sys_dict_type`  (
-  `dict_id` bigint NOT NULL AUTO_INCREMENT COMMENT '瀛楀吀涓婚敭',
-  `dict_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '瀛楀吀鍚嶇О',
-  `dict_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '瀛楀吀绫诲瀷',
-  `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  PRIMARY KEY (`dict_id`) USING BTREE,
-  UNIQUE INDEX `dict_type`(`dict_type` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 137 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀛楀吀绫诲瀷琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_job
--- ----------------------------
-DROP TABLE IF EXISTS `sys_job`;
-CREATE TABLE `sys_job`  (
-  `job_id` bigint NOT NULL AUTO_INCREMENT COMMENT '浠诲姟ID',
-  `job_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '浠诲姟鍚嶇О',
-  `job_group` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'DEFAULT' COMMENT '浠诲姟缁勫悕',
-  `invoke_target` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冪敤鐩爣瀛楃涓�',
-  `cron_expression` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT 'cron鎵ц琛ㄨ揪寮�',
-  `misfire_policy` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '3' COMMENT '璁″垝鎵ц閿欒绛栫暐锛�1绔嬪嵆鎵ц 2鎵ц涓�娆� 3鏀惧純鎵ц锛�',
-  `concurrent` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '1' COMMENT '鏄惁骞跺彂鎵ц锛�0鍏佽 1绂佹锛�',
-  `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鏆傚仠锛�',
-  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '澶囨敞淇℃伅',
-  PRIMARY KEY (`job_id`, `job_name`, `job_group`) USING BTREE,
-  INDEX `idx_job_status`(`status` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹氭椂浠诲姟璋冨害琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_job_log
--- ----------------------------
-DROP TABLE IF EXISTS `sys_job_log`;
-CREATE TABLE `sys_job_log`  (
-  `job_log_id` bigint NOT NULL AUTO_INCREMENT COMMENT '浠诲姟鏃ュ織ID',
-  `job_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '浠诲姟鍚嶇О',
-  `job_group` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '浠诲姟缁勫悕',
-  `invoke_target` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璋冪敤鐩爣瀛楃涓�',
-  `job_message` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏃ュ織淇℃伅',
-  `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鎵ц鐘舵�侊紙0姝e父 1澶辫触锛�',
-  `exception_info` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '寮傚父淇℃伅',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  PRIMARY KEY (`job_log_id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹氭椂浠诲姟璋冨害鏃ュ織琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_logininfor
--- ----------------------------
-DROP TABLE IF EXISTS `sys_logininfor`;
-CREATE TABLE `sys_logininfor`  (
-  `info_id` bigint NOT NULL AUTO_INCREMENT COMMENT '璁块棶ID',
-  `user_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鐢ㄦ埛璐﹀彿',
-  `ipaddr` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鐧诲綍IP鍦板潃',
-  `login_location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鐧诲綍鍦扮偣',
-  `browser` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '娴忚鍣ㄧ被鍨�',
-  `os` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鎿嶄綔绯荤粺',
-  `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鐧诲綍鐘舵�侊紙0鎴愬姛 1澶辫触锛�',
-  `msg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鎻愮ず娑堟伅',
-  `login_time` datetime NULL DEFAULT NULL COMMENT '璁块棶鏃堕棿',
-  PRIMARY KEY (`info_id`) USING BTREE,
-  INDEX `idx_sys_logininfor_s`(`status` ASC) USING BTREE,
-  INDEX `idx_sys_logininfor_lt`(`login_time` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 4498 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '绯荤粺璁块棶璁板綍' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_menu
--- ----------------------------
-DROP TABLE IF EXISTS `sys_menu`;
-CREATE TABLE `sys_menu`  (
-  `menu_id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑿滃崟ID',
-  `menu_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鑿滃崟鍚嶇О',
-  `parent_id` bigint NULL DEFAULT 0 COMMENT '鐖惰彍鍗旾D',
-  `order_num` int NULL DEFAULT 0 COMMENT '鏄剧ず椤哄簭',
-  `path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '璺敱鍦板潃',
-  `component` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '缁勪欢璺緞',
-  `query` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璺敱鍙傛暟',
-  `route_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '璺敱鍚嶇О',
-  `is_frame` int NULL DEFAULT 1 COMMENT '鏄惁涓哄閾撅紙0鏄� 1鍚︼級',
-  `is_cache` int NULL DEFAULT 0 COMMENT '鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級',
-  `menu_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�',
-  `visible` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鑿滃崟鐘舵�侊紙0鏄剧ず 1闅愯棌锛�',
-  `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-  `perms` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏉冮檺鏍囪瘑',
-  `icon` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '#' COMMENT '鑿滃崟鍥炬爣',
-  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '澶囨敞',
-  `app_component` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'app缁勪欢璺緞',
-  PRIMARY KEY (`menu_id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2348 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鑿滃崟鏉冮檺琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_notice
--- ----------------------------
-DROP TABLE IF EXISTS `sys_notice`;
-CREATE TABLE `sys_notice`  (
-  `notice_id` int NOT NULL AUTO_INCREMENT COMMENT '鍏憡ID',
-  `notice_title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍏憡鏍囬',
-  `notice_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�',
-  `notice_content` longblob NULL COMMENT '鍏憡鍐呭',
-  `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�',
-  `consignee_id` bigint NULL DEFAULT NULL COMMENT '鍙戦�佷汉id',
-  `sender_id` bigint NULL DEFAULT NULL COMMENT '鏀朵欢浜篿d',
-  `jump_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璺宠浆璺緞',
-  `app_jump_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'APP璺宠浆璺緞',
-  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `tenant_id` int NULL DEFAULT NULL,
-  PRIMARY KEY (`notice_id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1296 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '閫氱煡鍏憡琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_oper_log
--- ----------------------------
-DROP TABLE IF EXISTS `sys_oper_log`;
-CREATE TABLE `sys_oper_log`  (
-  `oper_id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏃ュ織涓婚敭',
-  `title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '妯″潡鏍囬',
-  `business_type` int NULL DEFAULT 0 COMMENT '涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�',
-  `method` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏂规硶鍚嶇О',
-  `request_method` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '璇锋眰鏂瑰紡',
-  `operator_type` int NULL DEFAULT 0 COMMENT '鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級',
-  `oper_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鎿嶄綔浜哄憳',
-  `dept_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '閮ㄩ棬鍚嶇О',
-  `oper_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '璇锋眰URL',
-  `oper_ip` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '涓绘満鍦板潃',
-  `oper_location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鎿嶄綔鍦扮偣',
-  `oper_param` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '璇锋眰鍙傛暟',
-  `json_result` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '杩斿洖鍙傛暟',
-  `status` int NULL DEFAULT 0 COMMENT '鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�',
-  `error_msg` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '閿欒娑堟伅',
-  `oper_time` datetime NULL DEFAULT NULL COMMENT '鎿嶄綔鏃堕棿',
-  `cost_time` bigint NULL DEFAULT 0 COMMENT '娑堣�楁椂闂�',
-  PRIMARY KEY (`oper_id`) USING BTREE,
-  INDEX `idx_sys_oper_log_bt`(`business_type` ASC) USING BTREE,
-  INDEX `idx_sys_oper_log_s`(`status` ASC) USING BTREE,
-  INDEX `idx_sys_oper_log_ot`(`oper_time` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 119789 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鎿嶄綔鏃ュ織璁板綍' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_post
--- ----------------------------
-DROP TABLE IF EXISTS `sys_post`;
-CREATE TABLE `sys_post`  (
-  `post_id` bigint NOT NULL AUTO_INCREMENT COMMENT '宀椾綅ID',
-  `post_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '宀椾綅缂栫爜',
-  `post_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '宀椾綅鍚嶇О',
-  `post_sort` int NOT NULL COMMENT '鏄剧ず椤哄簭',
-  `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  PRIMARY KEY (`post_id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 26 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '宀椾綅淇℃伅琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_role
--- ----------------------------
-DROP TABLE IF EXISTS `sys_role`;
-CREATE TABLE `sys_role`  (
-  `role_id` bigint NOT NULL AUTO_INCREMENT COMMENT '瑙掕壊ID',
-  `role_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瑙掕壊鍚嶇О',
-  `role_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瑙掕壊鏉冮檺瀛楃涓�',
-  `role_sort` int NOT NULL COMMENT '鏄剧ず椤哄簭',
-  `data_scope` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '1' COMMENT '鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級',
-  `menu_check_strictly` tinyint(1) NULL DEFAULT 1 COMMENT '鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�',
-  `dept_check_strictly` tinyint(1) NULL DEFAULT 1 COMMENT '閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�',
-  `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-  `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
-  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  PRIMARY KEY (`role_id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 112 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瑙掕壊淇℃伅琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_role_dept
--- ----------------------------
-DROP TABLE IF EXISTS `sys_role_dept`;
-CREATE TABLE `sys_role_dept`  (
-  `role_id` bigint NOT NULL COMMENT '瑙掕壊ID',
-  `dept_id` bigint NOT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`role_id`, `dept_id`) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瑙掕壊鍜岄儴闂ㄥ叧鑱旇〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_role_menu
--- ----------------------------
-DROP TABLE IF EXISTS `sys_role_menu`;
-CREATE TABLE `sys_role_menu`  (
-  `role_id` bigint NOT NULL COMMENT '瑙掕壊ID',
-  `menu_id` bigint NOT NULL COMMENT '鑿滃崟ID',
-  PRIMARY KEY (`role_id`, `menu_id`) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瑙掕壊鍜岃彍鍗曞叧鑱旇〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_user
--- ----------------------------
-DROP TABLE IF EXISTS `sys_user`;
-CREATE TABLE `sys_user`  (
-  `user_id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐢ㄦ埛ID',
-  `user_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鐢ㄦ埛璐﹀彿',
-  `nick_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鐢ㄦ埛鏄电О',
-  `user_type` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '00' COMMENT '鐢ㄦ埛绫诲瀷锛�00绯荤粺鐢ㄦ埛锛�',
-  `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鐢ㄦ埛閭',
-  `phonenumber` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鎵嬫満鍙风爜',
-  `sex` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�',
-  `avatar` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '澶村儚鍦板潃',
-  `password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '瀵嗙爜',
-  `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '璐﹀彿鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-  `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
-  `login_ip` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏈�鍚庣櫥褰旾P',
-  `login_date` datetime NULL DEFAULT NULL COMMENT '鏈�鍚庣櫥褰曟椂闂�',
-  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `ai_enabled` tinyint(1) NOT NULL DEFAULT 0 COMMENT '鏄惁寮�閫欰I鍔熻兘锛�0鍚� 1鏄級',
-  PRIMARY KEY (`user_id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 262 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢ㄦ埛淇℃伅琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_user_client
--- ----------------------------
-DROP TABLE IF EXISTS `sys_user_client`;
-CREATE TABLE `sys_user_client`  (
-  `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛ID',
-  `cid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '涓帹CID',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏈�鍚庢椿璺冩椂闂�',
-  PRIMARY KEY (`user_id`) USING BTREE,
-  UNIQUE INDEX `uk_cid`(`cid` ASC) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢ㄦ埛瀹夊崜璁惧' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_user_dept
--- ----------------------------
-DROP TABLE IF EXISTS `sys_user_dept`;
-CREATE TABLE `sys_user_dept`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `user_id` bigint NULL DEFAULT NULL COMMENT 'sys_user琛ㄤ富閿�',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT 'sys_dept琛ㄤ富閿�',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 648 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_user_post
--- ----------------------------
-DROP TABLE IF EXISTS `sys_user_post`;
-CREATE TABLE `sys_user_post`  (
-  `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛ID',
-  `post_id` bigint NOT NULL COMMENT '宀椾綅ID',
-  PRIMARY KEY (`user_id`, `post_id`) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for sys_user_role
--- ----------------------------
-DROP TABLE IF EXISTS `sys_user_role`;
-CREATE TABLE `sys_user_role`  (
-  `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛ID',
-  `role_id` bigint NOT NULL COMMENT '瑙掕壊ID',
-  PRIMARY KEY (`user_id`, `role_id`) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢ㄦ埛鍜岃鑹插叧鑱旇〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for technology_bom
--- ----------------------------
-DROP TABLE IF EXISTS `technology_bom`;
-CREATE TABLE `technology_bom`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `product_model_id` bigint NOT NULL COMMENT '浜у搧瑙勬牸id',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `version` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐗堟湰鍙�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '鏇存柊鑰�',
-  `bom_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'BOM缂栧彿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'BOM琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for technology_bom_structure
--- ----------------------------
-DROP TABLE IF EXISTS `technology_bom_structure`;
-CREATE TABLE `technology_bom_structure`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `parent_id` bigint NULL DEFAULT NULL COMMENT '鐖惰妭鐐笽D',
-  `product_model_id` bigint NOT NULL COMMENT '浜у搧id',
-  `operation_id` bigint NULL DEFAULT NULL COMMENT '宸ュ簭id',
-  `unit_quantity` decimal(16, 4) NOT NULL COMMENT '鍗曚綅浜у嚭闇�瑕佹暟閲�',
-  `demanded_quantity` decimal(16, 4) NULL DEFAULT NULL COMMENT '闇�姹傛暟閲�',
-  `unit` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `bom_id` bigint NOT NULL COMMENT 'bom鐨刬d',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 61 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'BOM浜у搧缁撴瀯琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for technology_operation
--- ----------------------------
-DROP TABLE IF EXISTS `technology_operation`;
-CREATE TABLE `technology_operation`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '宸ヨ壓鍚嶇О',
-  `no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '宸ヨ壓缂栧彿',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '澶囨敞',
-  `salary_quota` decimal(16, 3) NULL DEFAULT NULL COMMENT '宸ヨ祫瀹氶',
-  `is_quality` tinyint(1) NULL DEFAULT 1 COMMENT '鏄惁璐ㄦ宸ュ簭',
-  `is_production` tinyint(1) NULL DEFAULT 1 COMMENT '鏄惁鐢熶骇',
-  `type` int NULL DEFAULT NULL COMMENT '绫诲瀷 鍖哄垎璁℃椂鍜岃浠�(0璁℃椂1璁′欢)',
-  `device_ledger_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧id',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '宸ュ簭琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for technology_operation_param
--- ----------------------------
-DROP TABLE IF EXISTS `technology_operation_param`;
-CREATE TABLE `technology_operation_param`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `technology_param_id` bigint NULL DEFAULT NULL COMMENT '鍩虹鍙傛暟琛╥d',
-  `technology_operation_id` bigint NULL DEFAULT NULL COMMENT '宸ュ簭id',
-  `standard_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '鏍囧噯鍊�',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '宸ュ簭鍙傛暟' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for technology_param
--- ----------------------------
-DROP TABLE IF EXISTS `technology_param`;
-CREATE TABLE `technology_param`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `param_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍙傛暟缂栫爜(鍞竴鏍囪瘑)',
-  `param_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍙傛暟鍚嶇О',
-  `param_type` tinyint NOT NULL COMMENT '鍙傛暟绫诲瀷(1鏁板瓧 2鏂囨湰 3涓嬫媺閫夋嫨 4鏃堕棿)',
-  `param_format` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍙傛暟鏍煎紡',
-  `unit` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `is_required` tinyint NULL DEFAULT 0 COMMENT '鏄惁蹇呭~',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 38 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鍩虹鍙傛暟琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for technology_routing
--- ----------------------------
-DROP TABLE IF EXISTS `technology_routing`;
-CREATE TABLE `technology_routing`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `product_model_id` bigint NOT NULL DEFAULT 0 COMMENT '浜у搧id',
-  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '鎻忚堪',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `process_route_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栫爜',
-  `bom_id` int NULL DEFAULT NULL COMMENT '鍏宠仈bom鐨刬d',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '宸ヨ壓璺嚎琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for technology_routing_operation
--- ----------------------------
-DROP TABLE IF EXISTS `technology_routing_operation`;
-CREATE TABLE `technology_routing_operation`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `technology_routing_id` bigint NOT NULL DEFAULT 0 COMMENT '宸ヨ壓璺嚎id',
-  `product_model_id` bigint NOT NULL DEFAULT 0 COMMENT '浜у搧id',
-  `technology_operation_id` bigint NOT NULL DEFAULT 0 COMMENT '宸ュ簭id',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '褰曞叆鏃堕棿',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
-  `drag_sort` int NULL DEFAULT NULL COMMENT '鎷栧姩鎺掑簭',
-  `is_quality` tinyint(1) NULL DEFAULT 1 COMMENT '鏄惁璐ㄦ宸ュ簭',
-  `is_production` tinyint(1) NULL DEFAULT 1 COMMENT '鏄惁鐢熶骇',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `type` int NULL DEFAULT NULL COMMENT '绫诲瀷 鍖哄垎璁℃椂鍜岃浠�(0璁℃椂1璁′欢)',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 42 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '宸ヨ壓璺嚎宸ュ簭琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for technology_routing_operation_param
--- ----------------------------
-DROP TABLE IF EXISTS `technology_routing_operation_param`;
-CREATE TABLE `technology_routing_operation_param`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
-  `param_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鍙傛暟缂栫爜(鍞竴鏍囪瘑)',
-  `param_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '鍙傛暟鍚嶇О',
-  `param_type` tinyint NOT NULL COMMENT '鍙傛暟绫诲瀷(1鏁板瓧 2鏂囨湰 3涓嬫媺閫夋嫨 4鏃堕棿)',
-  `param_format` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍙傛暟鏍煎紡',
-  `unit` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍗曚綅',
-  `is_required` tinyint NULL DEFAULT 0 COMMENT '鏄惁蹇呭~',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `create_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '淇敼浜�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  `param_id` bigint NULL DEFAULT NULL COMMENT '鍩虹鍙傛暟ID',
-  `technology_operation_id` bigint NULL DEFAULT NULL COMMENT '宸ュ簭id',
-  `technology_operation_param_id` bigint NULL DEFAULT NULL COMMENT '宸ュ簭鍙傛暟ID',
-  `technology_routing_operation_id` bigint NULL DEFAULT NULL COMMENT '宸ヨ壓璺嚎宸ュ簭ID',
-  `standard_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '鏍囧噯鍊�',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 79 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '宸ヨ壓璺嚎宸ュ簭鍙傛暟琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for temp_file
--- ----------------------------
-DROP TABLE IF EXISTS `temp_file`;
-CREATE TABLE `temp_file`  (
-  `temp_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '涓存椂鏂囦欢ID',
-  `original_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍘熷鏂囦欢鍚�',
-  `temp_path` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '涓存椂瀛樺偍璺緞',
-  `expire_time` datetime NOT NULL COMMENT '杩囨湡鏃堕棿',
-  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `status` tinyint NULL DEFAULT 0 COMMENT '鐘舵�侊細0=涓存椂锛�1=宸茬‘璁わ紝2=宸茶繃鏈�',
-  `type` int NULL DEFAULT NULL,
-  `file_size` bigint NULL DEFAULT NULL COMMENT '鏂囦欢澶у皬',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`temp_id`) USING BTREE,
-  INDEX `idx_expire_time`(`expire_time` ASC) USING BTREE COMMENT '鐢ㄤ簬杩囨湡鏂囦欢娓呯悊鐨勭储寮�',
-  INDEX `idx_status`(`status` ASC) USING BTREE COMMENT '鐢ㄤ簬鐘舵�佹煡璇㈢殑绱㈠紩'
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '涓存椂鏂囦欢璁板綍琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for ticket_registration
--- ----------------------------
-DROP TABLE IF EXISTS `ticket_registration`;
-CREATE TABLE `ticket_registration`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `purchase_contract_number` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '閲囪喘鍚堝悓鍙�',
-  `sales_contract_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閿�鍞悎鍚屽彿',
-  `customer_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹㈡埛鍚嶇О',
-  `business_person` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓氬姟鍛�',
-  `project_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '椤圭洰鍚嶇О',
-  `product_id` int NULL DEFAULT NULL COMMENT '浜у搧淇℃伅',
-  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-  `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
-  `purchase_ledger_id` int NULL DEFAULT NULL COMMENT '閲囪喘鍙拌处id',
-  `supplier_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉�',
-  `sales_ledger_id` int NULL DEFAULT NULL COMMENT '鍏宠仈閿�鍞彴璐︿富琛ㄤ富閿�',
-  `business_person_id` int NULL DEFAULT NULL COMMENT '涓氬姟鍛榠d',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `contract_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '鍚堝悓閲戦',
-  `invoice_number` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍙戠エ鍙�',
-  `invoice_amount` decimal(10, 2) NOT NULL COMMENT '鍙戠エ閲戦锛堝厓锛�',
-  `iss_uer_id` int NULL DEFAULT NULL COMMENT '寮�绁ㄤ汉id',
-  `iss_uer` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '寮�绁ㄤ汉',
-  `issue_date` date NULL DEFAULT NULL COMMENT '寮�绁ㄦ棩鏈�',
-  `enter_date` timestamp NULL DEFAULT NULL,
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓浜篒D',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 158 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鏉ョエ鐧昏琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for timing_task
--- ----------------------------
-DROP TABLE IF EXISTS `timing_task`;
-CREATE TABLE `timing_task`  (
-  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
-  `task_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璁惧鍚嶇О',
-  `inspection_project` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸℃椤圭洰',
-  `task_id` int NULL DEFAULT NULL COMMENT '璁惧id',
-  `inspector_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '宸℃浜�',
-  `inspection_location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸℃鍦扮偣',
-  `frequency_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '棰戞',
-  `frequency_detail` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `next_execution_time` datetime(6) NULL DEFAULT NULL,
-  `last_execution_time` datetime(6) NULL DEFAULT NULL,
-  `is_active` tinyint(1) NULL DEFAULT NULL,
-  `is_enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT '鏄惁鍚敤 0鍚� 1鏄�',
-  `remarks` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '澶囨敞',
-  `registrant_id` bigint NULL DEFAULT NULL COMMENT '鐧昏浜篿d',
-  `registrant` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐧昏浜�',
-  `registration_date` date NOT NULL COMMENT '鐧昏鏃ユ湡',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
-  `deleted` int NOT NULL DEFAULT 0 COMMENT '杞垹闄ゆ爣蹇楋紝0=鏈垹闄わ紝1=宸插垹闄�',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓璇ヨ褰曠殑鐢ㄦ埛',
-  `create_time` datetime(6) NULL DEFAULT NULL COMMENT '璁板綍鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '鏈�鍚庝慨鏀硅璁板綍鐨勭敤鎴�',
-  `update_time` datetime(6) NULL DEFAULT NULL COMMENT '璁板綍鏈�鍚庢洿鏂版椂闂�',
-  `tenant_id` int NULL DEFAULT NULL,
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_timing_task_is_enabled`(`is_enabled` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '瀹氭椂宸℃浠诲姟琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for warehouse
--- ----------------------------
-DROP TABLE IF EXISTS `warehouse`;
-CREATE TABLE `warehouse`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `warehouse_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '浠撳簱鍚嶇О',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浠撳簱琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for warehouse_goods_shelves
--- ----------------------------
-DROP TABLE IF EXISTS `warehouse_goods_shelves`;
-CREATE TABLE `warehouse_goods_shelves`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璐ф灦鍚嶇О',
-  `row` bigint NULL DEFAULT NULL COMMENT '灞傛暟',
-  `col` bigint NULL DEFAULT NULL COMMENT '鍒楁暟',
-  `warehouse_id` bigint NULL DEFAULT NULL COMMENT '浠撳簱id',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浠撳簱璐ф灦琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for warehouse_goods_shelves_rowcol
--- ----------------------------
-DROP TABLE IF EXISTS `warehouse_goods_shelves_rowcol`;
-CREATE TABLE `warehouse_goods_shelves_rowcol`  (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `row` bigint NULL DEFAULT NULL COMMENT '灞傛暟',
-  `col` bigint NULL DEFAULT NULL COMMENT '鍒楁暟',
-  `warehouse_goods_shelves_id` bigint NULL DEFAULT NULL COMMENT '璐ф灦id',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鐢ㄦ埛',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鐢ㄦ埛',
-  `tenant_id` bigint NULL DEFAULT NULL COMMENT '绉熸埛ID',
-  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '澶囨敞',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 101 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '浠撳簱璐ф灦灞傦紝鍒楄〃' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for water_record
--- ----------------------------
-DROP TABLE IF EXISTS `water_record`;
-CREATE TABLE `water_record`  (
-  `id` int NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
-  `device_model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '璁惧瑙勬牸鍨嬪彿',
-  `type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐢ㄦ按绫诲瀷',
-  `rated_rate` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '棰濆畾娴侀噺',
-  `actual_traffic` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '瀹為檯娴侀噺',
-  `run_time` date NULL DEFAULT NULL COMMENT '杩愯鏃堕棿',
-  `water_day` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '褰撴棩鐢ㄦ按閲�',
-  `water_day_limit` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '姣忔棩闄愬埗姘撮噺',
-  `water_price` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '姘磋垂鍗曚环',
-  `remarks` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '澶囨敞',
-  `create_user` bigint NULL DEFAULT NULL COMMENT '鍒涘缓鑰�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` bigint NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '鐢ㄦ按璁板綍' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for work_report
--- ----------------------------
-DROP TABLE IF EXISTS `work_report`;
-CREATE TABLE `work_report`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `plan_id` int NULL DEFAULT NULL COMMENT '鎵�灞炶鍒扞D锛屽叧鑱攄uty_plan琛�',
-  `report_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '姹囨姤鏍囬',
-  `progress` int NULL DEFAULT NULL COMMENT '宸ヤ綔杩涘害鐧惧垎姣�',
-  `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '宸ヤ綔鍐呭',
-  `issues` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '閬囧埌鐨勯棶棰�',
-  `next_plan` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '涓嬩竴姝ヨ鍒�',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '宸ヤ綔姹囨姤琛�' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Table structure for working_hours_setting
--- ----------------------------
-DROP TABLE IF EXISTS `working_hours_setting`;
-CREATE TABLE `working_hours_setting`  (
-  `id` int NOT NULL AUTO_INCREMENT,
-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鏃堕棿娈靛悕绉�',
-  `start_time` time NULL DEFAULT NULL COMMENT '涓婄彮鏃堕棿',
-  `end_time` time NULL DEFAULT NULL COMMENT '涓嬬彮鏃堕棿',
-  `flexible_start` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '寮规�т笂鐝�',
-  `flexible_minutes` int NULL DEFAULT NULL COMMENT '寮规�ф椂闂�(鍒嗛挓)',
-  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '鐘舵��',
-  `create_user` int NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
-  `create_time` datetime NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
-  `update_user` int NULL DEFAULT NULL COMMENT '淇敼鑰�',
-  `update_time` datetime NULL DEFAULT NULL COMMENT '淇敼鏃堕棿',
-  `tenant_id` int NULL DEFAULT NULL COMMENT '绉熸埛id',
-  `dept_id` bigint NULL DEFAULT NULL COMMENT '閮ㄩ棬ID',
-  PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '涓婄彮鏃堕棿璁剧疆' ROW_FORMAT = DYNAMIC;
-
--- ----------------------------
--- Procedure structure for add_create_user_to_all_tables
--- ----------------------------
-DROP PROCEDURE IF EXISTS `add_create_user_to_all_tables`;
-delimiter ;;
-CREATE PROCEDURE `add_create_user_to_all_tables`()
-BEGIN
-    DECLARE v_table_name VARCHAR(255);
-    DECLARE col_exists INT;
-    DECLARE done INT DEFAULT 0;
-
-    -- 娓告爣锛氳幏鍙栨墍鏈夐渶瑕佸鐞嗙殑琛紙鏄庣‘鎸囧畾琛ㄥ埆鍚嶏級
-    DECLARE table_cursor CURSOR FOR
-        SELECT t.TABLE_NAME
-        FROM information_schema.TABLES t
-        WHERE t.TABLE_SCHEMA = DATABASE()
-          AND t.TABLE_TYPE = 'BASE TABLE'
-          AND t.TABLE_NAME NOT LIKE 'sys_%'
-          AND t.TABLE_NAME NOT LIKE 'qrtz_%';
-
-    -- 娓告爣缁撴潫澶勭悊
-    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-
-    OPEN table_cursor;
-
-    table_loop: LOOP
-        FETCH table_cursor INTO v_table_name;
-        IF done = 1 THEN
-            LEAVE table_loop;
-        END IF;
-
-        -- 妫�鏌ュ瓧娈垫槸鍚﹀瓨鍦紙鏄庣‘鍒悕锛屽交搴曡В鍐� 1052 閿欒锛�
-        SELECT COUNT(*) INTO col_exists
-        FROM information_schema.COLUMNS c
-        WHERE c.TABLE_SCHEMA = DATABASE()
-          AND c.TABLE_NAME = v_table_name
-          AND c.COLUMN_NAME = 'create_user';
-
-        -- 涓嶅瓨鍦ㄥ垯娣诲姞
-        IF col_exists = 0 THEN
-            SET @sql = CONCAT('ALTER TABLE `', v_table_name, '` ADD COLUMN create_user BIGINT NULL COMMENT \'鍒涘缓浜篒D\'');
-            PREPARE stmt FROM @sql;
-            EXECUTE stmt;
-            DEALLOCATE PREPARE stmt;
-        END IF;
-
-    END LOOP table_loop;
-
-    CLOSE table_cursor;
-    SELECT '鎵ц瀹屾垚锛佹墍鏈夎〃宸叉坊鍔� create_user 瀛楁' AS result;
-END
-;;
-delimiter ;
-
--- ----------------------------
--- Procedure structure for add_dept_id_to_all_tables
--- ----------------------------
-DROP PROCEDURE IF EXISTS `add_dept_id_to_all_tables`;
-delimiter ;;
-CREATE PROCEDURE `add_dept_id_to_all_tables`()
-BEGIN
-    DECLARE v_table_name VARCHAR(255);
-    DECLARE col_exists INT;
-    DECLARE done INT DEFAULT 0;
-
-    -- 娓告爣锛氳幏鍙栨墍鏈夐渶瑕佸鐞嗙殑琛紙鏄庣‘鎸囧畾琛ㄥ埆鍚嶏級
-    DECLARE table_cursor CURSOR FOR
-        SELECT t.TABLE_NAME
-        FROM information_schema.TABLES t
-        WHERE t.TABLE_SCHEMA = DATABASE()
-          AND t.TABLE_TYPE = 'BASE TABLE'
-          AND t.TABLE_NAME NOT LIKE 'sys_%'
-          AND t.TABLE_NAME NOT LIKE 'qrtz_%';
-
-    -- 娓告爣缁撴潫澶勭悊
-    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-
-    OPEN table_cursor;
-
-    table_loop: LOOP
-        FETCH table_cursor INTO v_table_name;
-        IF done = 1 THEN
-            LEAVE table_loop;
-        END IF;
-
-        -- 妫�鏌ュ瓧娈垫槸鍚﹀瓨鍦紙鏄庣‘鍒悕锛屽交搴曡В鍐� 1052 閿欒锛�
-        SELECT COUNT(*) INTO col_exists
-        FROM information_schema.COLUMNS c
-        WHERE c.TABLE_SCHEMA = DATABASE()
-          AND c.TABLE_NAME = v_table_name
-          AND c.COLUMN_NAME = 'dept_id';
-
-        -- 涓嶅瓨鍦ㄥ垯娣诲姞
-        IF col_exists = 0 THEN
-            SET @sql = CONCAT('ALTER TABLE `', v_table_name, '` ADD COLUMN dept_id BIGINT NULL COMMENT \'閮ㄩ棬ID\'');
-            PREPARE stmt FROM @sql;
-            EXECUTE stmt;
-            DEALLOCATE PREPARE stmt;
-        END IF;
-
-    END LOOP table_loop;
-
-    CLOSE table_cursor;
-    SELECT '鎵ц瀹屾垚锛佹墍鏈夎〃宸叉坊鍔� dept_id 瀛楁' AS result;
-END
-;;
-delimiter ;
-
--- ----------------------------
--- Procedure structure for truncate_non_sys_tables
--- ----------------------------
-DROP PROCEDURE IF EXISTS `truncate_non_sys_tables`;
-delimiter ;;
-CREATE PROCEDURE `truncate_non_sys_tables`()
-BEGIN
-    DECLARE done INT DEFAULT FALSE;
-    DECLARE tbl_name VARCHAR(255);
-
-    DECLARE cur CURSOR FOR 
-        SELECT TABLE_NAME 
-        FROM INFORMATION_SCHEMA.TABLES 
-        WHERE TABLE_SCHEMA = DATABASE() 
-        AND (
-            TABLE_NAME NOT LIKE 'sys\\_%' 
-            OR TABLE_NAME IN (
-                'sys_oper_log',
-                'sys_logininfor',
-                'sys_notice',
-                'sys_job',
-                'sys_job_log'
-            )
-        )
-        -- 涓嶆竻鐞唒roduct琛�
-        AND TABLE_NAME <> 'product'
-        AND TABLE_TYPE = 'BASE TABLE';
-
-    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-
-    -- 涓存椂绂佺敤澶栭敭绾︽潫
-    SET FOREIGN_KEY_CHECKS = 0;
-    SET AUTOCOMMIT = 0;
-
-    OPEN cur;
-
-    read_loop: LOOP
-        FETCH cur INTO tbl_name;
-
-        IF done THEN
-            LEAVE read_loop;
-        END IF;
-
-        SET @sql = CONCAT('DELETE FROM `', tbl_name, '`');
-
-        PREPARE stmt FROM @sql;
-        EXECUTE stmt;
-        DEALLOCATE PREPARE stmt;
-
-        SELECT CONCAT('宸叉竻鐞嗚〃: ', tbl_name) AS message;
-    END LOOP;
-
-    CLOSE cur;
-
-    -- 鎭㈠閰嶇疆
-    SET FOREIGN_KEY_CHECKS = 1;
-    SET AUTOCOMMIT = 1;
-
-    SELECT '鎵�鏈夌洰鏍囪〃宸叉竻绌哄畬鎴愶紙宸叉帓闄roduct琛級锛�' AS final_message;
-END
-;;
-delimiter ;
-
-SET FOREIGN_KEY_CHECKS = 1;
diff --git a/src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java b/src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java
deleted file mode 100644
index bad0e0a..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import dev.langchain4j.service.MemoryId;
-import dev.langchain4j.service.SystemMessage;
-import dev.langchain4j.service.UserMessage;
-import dev.langchain4j.service.V;
-import dev.langchain4j.service.spring.AiService;
-import reactor.core.publisher.Flux;
-
-import static dev.langchain4j.service.spring.AiServiceWiringMode.EXPLICIT;
-
-@AiService(
-        wiringMode = EXPLICIT,
-        streamingChatModel = "qwenStreamingChatModel",
-        chatMemoryProvider = "chatMemoryProviderApproveTodo",
-        tools = "approveTodoTools")
-public interface ApproveTodoAgent {
-
-    @SystemMessage(fromResource = "approve-todo-agent-prompt.txt")
-    Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage, @V("currentDate") String currentDate);
-}
diff --git a/src/main/java/com/ruoyi/ai/assistant/ApproveTodoIntentExecutor.java b/src/main/java/com/ruoyi/ai/assistant/ApproveTodoIntentExecutor.java
deleted file mode 100644
index 8d8ad45..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/ApproveTodoIntentExecutor.java
+++ /dev/null
@@ -1,451 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import com.alibaba.fastjson2.JSON;
-import com.ruoyi.ai.tools.ApproveTodoTools;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-import java.math.BigDecimal;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-@Component
-public class ApproveTodoIntentExecutor {
-
-    private static final Pattern APPROVE_ID_BY_LABEL_PATTERN = Pattern.compile("(娴佺▼缂栧彿|娴佺▼鍙穦娴佺▼ID|瀹℃壒缂栧彿|缂栧彿)\\s*[:锛歖?\\s*([A-Za-z0-9_-]{2,64})");
-    private static final Pattern APPROVE_ID_PATTERN = Pattern.compile("\\b[A-Za-z]*\\d{6,}[A-Za-z0-9_-]*\\b");
-    private static final Pattern LIMIT_PATTERN = Pattern.compile("(鍓峾鏈�杩�)?\\s*(\\d{1,2})\\s*鏉�");
-    private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2})");
-    private static final Pattern NUMBER_PATTERN = Pattern.compile("(\\d+(?:\\.\\d+)?)");
-    private static final Pattern RECENT_RANGE_PATTERN = Pattern.compile("杩慭\d+(澶﹟鍛▅涓湀|鏈坾骞�)");
-    private static final Pattern HALF_RANGE_PATTERN = Pattern.compile("(鏈�杩憒杩�)?鍗�(涓�)?(鏈坾骞�)");
-    private static final Pattern EXPLICIT_RANGE_PATTERN = Pattern.compile(".*(鍒皘鑷�).*");
-
-    private final ApproveTodoTools approveTodoTools;
-
-    public ApproveTodoIntentExecutor(ApproveTodoTools approveTodoTools) {
-        this.approveTodoTools = approveTodoTools;
-    }
-
-    public String tryExecute(String memoryId, String message) {
-        if (!StringUtils.hasText(message)) {
-            return null;
-        }
-
-        String text = message.trim();
-        String quickPromptResponse = tryExecuteQuickPrompt(memoryId, text);
-        if (StringUtils.hasText(quickPromptResponse)) {
-            return quickPromptResponse;
-        }
-
-        String approveId = extractApproveId(text);
-        boolean hasApproveId = StringUtils.hasText(approveId) && !isPlaceholderApproveId(approveId);
-        String startDate = extractStartDate(text);
-        String endDate = extractEndDate(text);
-        String timeRange = extractTimeRange(text);
-
-        if (isStatsIntent(text)) {
-            return approveTodoTools.getTodoStats(
-                    memoryId,
-                    startDate,
-                    endDate,
-                    timeRange
-            );
-        }
-        if (containsAny(text, "娴佽浆", "杩涘害", "鑺傜偣", "鏃ュ織", "鍗″湪", "鍗″埌", "褰撳墠瀹℃壒浜�", "澶勭悊璁板綍")) {
-            return hasApproveId
-                    ? approveTodoTools.getTodoProgress(memoryId, approveId)
-                    : missingApproveId("todo_progress", "鏌ヨ瀹℃壒杩涘害闇�瑕佹彁渚涙祦绋嬬紪鍙枫��");
-        }
-        if (containsAny(text, "璇︽儏", "鏄庣粏") && !containsAny(text, "鍒楄〃")) {
-            return hasApproveId
-                    ? approveTodoTools.getTodoDetail(memoryId, approveId)
-                    : missingApproveId("todo_detail", "鏌ヨ瀹℃壒璇︽儏闇�瑕佹彁渚涙祦绋嬬紪鍙枫��");
-        }
-        if (containsAny(text, "鍙栨秷瀹℃牳", "鎾ら攢瀹℃牳", "鍥為��瀹℃牳", "鎾ら攢瀹℃壒", "鎾ゅ洖瀹℃壒")
-                || (containsAny(text, "鎾ら攢", "鎾ゅ洖") && containsAny(text, "瀹℃壒鎿嶄綔", "瀹℃牳鎿嶄綔"))) {
-            return hasApproveId
-                    ? approveTodoTools.cancelReviewTodo(memoryId, approveId, extractRemark(text))
-                    : missingApproveId("cancel_review_action", "鍙栨秷瀹℃牳闇�瑕佹彁渚涙祦绋嬬紪鍙枫��");
-        }
-        if (containsAny(text, "鍒犻櫎", "绉婚櫎")) {
-            return hasApproveId
-                    ? approveTodoTools.deleteTodo(memoryId, approveId)
-                    : missingApproveId("delete_action", "鍒犻櫎瀹℃壒鍗曢渶瑕佹彁渚涙祦绋嬬紪鍙枫��");
-        }
-        if (containsAny(text, "椹冲洖", "鎷掔粷")) {
-            return hasApproveId
-                    ? approveTodoTools.reviewTodo(memoryId, approveId, "reject", extractRemark(text))
-                    : missingApproveId("review_action", "椹冲洖瀹℃壒闇�瑕佹彁渚涙祦绋嬬紪鍙枫��");
-        }
-        if (containsAny(text, "瀹℃牳閫氳繃", "瀹℃壒閫氳繃", "閫氳繃瀹℃壒", "鍚屾剰瀹℃壒", "瀹℃壒鍚屾剰")) {
-            return hasApproveId
-                    ? approveTodoTools.reviewTodo(memoryId, approveId, "approve", extractRemark(text))
-                    : missingApproveId("review_action", "瀹℃壒閫氳繃闇�瑕佹彁渚涙祦绋嬬紪鍙枫��");
-        }
-        if (hasApproveId
-                && containsAny(text, "閫氳繃", "鍚屾剰")
-                && !containsAny(text, "鏈�氳繃", "閫氳繃鐜�", "瀹℃壒閫氳繃鐜�", "瀹℃牳閫氳繃鐜�")) {
-            return approveTodoTools.reviewTodo(memoryId, approveId, "approve", extractRemark(text));
-        }
-        if (containsAny(text, "淇敼", "鏇存柊", "鍙樻洿")) {
-            return hasApproveId
-                    ? approveTodoTools.updateTodo(
-                    memoryId,
-                    approveId,
-                    extractValue(text, "鏍囬"),
-                    extractDateValue(text, "寮�濮嬫棩鏈�"),
-                    extractDateValue(text, "缁撴潫鏃ユ湡"),
-                    extractBigDecimalValue(text, "閲戦"),
-                    extractValue(text, "鍦扮偣"),
-                    extractIntegerValue(text, "绫诲瀷"),
-                    extractValue(text, "澶囨敞"))
-                    : missingApproveId("update_action", "淇敼瀹℃壒鍗曢渶瑕佹彁渚涙祦绋嬬紪鍙枫��");
-        }
-        if (containsAny(text, "鍒楄〃", "寰呭姙", "鏌ヨ瀹℃壒", "鍗曟嵁", "娴佺▼", "瀹℃壒鎵�")) {
-            return approveTodoTools.listTodos(
-                    memoryId,
-                    extractStatus(text),
-                    extractApproveType(text),
-                    extractKeyword(text),
-                    extractLimit(text),
-                    extractScope(text),
-                    startDate,
-                    endDate,
-                    timeRange);
-        }
-        return null;
-    }
-
-    private String tryExecuteQuickPrompt(String memoryId, String text) {
-        String normalized = normalizeForMatch(text);
-        String approveId = extractApproveId(text);
-        boolean hasApproveId = StringUtils.hasText(approveId) && !isPlaceholderApproveId(approveId);
-
-        if ("鎴戝綋鍓嶆湁鍝簺瀹℃壒寰呭姙闇�瑕佸鐞�".equals(normalized)) {
-            return approveTodoTools.listTodos(memoryId, "pending", null, null, 10, "approver", null, null, null);
-        }
-        if ("甯垜鍒楀嚭浠婂ぉ鏂板鐨勫鎵瑰緟鍔�".equals(normalized)) {
-            return approveTodoTools.listTodos(memoryId, "all", null, null, 10, "related", null, null, "浠婂ぉ");
-        }
-        if ("褰撳墠寰呮垜瀹℃壒鐨勫崟鎹寜鏃堕棿鍊掑簭鍒楀嚭鏉�".equals(normalized)) {
-            return approveTodoTools.listTodos(memoryId, "pending", null, null, 10, "approver", null, null, null);
-        }
-        if ("鎴戝彂璧风殑瀹℃壒閲屽摢浜涜繕鍦ㄥ鐞嗕腑".equals(normalized)) {
-            return approveTodoTools.listTodos(memoryId, "processing", null, null, 10, "applicant", null, null, null);
-        }
-        if ("杩�7澶╂垜鐨勫鎵瑰緟鍔炵粺璁℃儏鍐垫�庝箞鏍�".equals(normalized)) {
-            return approveTodoTools.getTodoStats(memoryId, null, null, "杩�7澶�");
-        }
-        if ("鏈湀鎴戠殑瀹℃壒涓�氳繃椹冲洖澶勭悊涓悇鏈夊灏�".equals(normalized)) {
-            return approveTodoTools.getTodoStats(memoryId, null, null, "鏈湀");
-        }
-        if ("杩�30澶╁悇绫诲瀷瀹℃壒鏁伴噺鍒嗗竷鏄粈涔�".equals(normalized)) {
-            return approveTodoTools.getTodoStats(memoryId, null, null, "杩�30澶�");
-        }
-
-        if (normalized.startsWith("鏌ヨ娴佺▼缂栧彿") && normalized.contains("瀹℃壒璇︽儏")) {
-            return hasApproveId
-                    ? approveTodoTools.getTodoDetail(memoryId, approveId)
-                    : missingApproveId("todo_detail", "鏌ヨ瀹℃壒璇︽儏闇�瑕佹彁渚涚湡瀹炴祦绋嬬紪鍙枫��");
-        }
-        if (normalized.startsWith("娴佺▼缂栧彿")
-                && normalized.contains("鍗″湪鍝釜瀹℃壒鑺傜偣")
-                && normalized.contains("褰撳墠瀹℃壒浜烘槸璋�")) {
-            return hasApproveId
-                    ? approveTodoTools.getTodoProgress(memoryId, approveId)
-                    : missingApproveId("todo_progress", "鏌ヨ瀹℃壒杩涘害闇�瑕佹彁渚涚湡瀹炴祦绋嬬紪鍙枫��");
-        }
-        if (normalized.startsWith("甯垜鏌ョ湅娴佺▼缂栧彿") && normalized.contains("瀹℃壒娴佽浆璁板綍")) {
-            return hasApproveId
-                    ? approveTodoTools.getTodoProgress(memoryId, approveId)
-                    : missingApproveId("todo_progress", "鏌ヨ瀹℃壒娴佽浆璁板綍闇�瑕佹彁渚涚湡瀹炴祦绋嬬紪鍙枫��");
-        }
-        if (normalized.startsWith("甯垜瀹℃壒閫氳繃娴佺▼缂栧彿")) {
-            return hasApproveId
-                    ? approveTodoTools.reviewTodo(memoryId, approveId, "approve", extractRemark(text))
-                    : missingApproveId("review_action", "瀹℃壒閫氳繃闇�瑕佹彁渚涚湡瀹炴祦绋嬬紪鍙枫��");
-        }
-        if (normalized.startsWith("甯垜椹冲洖娴佺▼缂栧彿")) {
-            return hasApproveId
-                    ? approveTodoTools.reviewTodo(memoryId, approveId, "reject", extractRemark(text))
-                    : missingApproveId("review_action", "椹冲洖瀹℃壒闇�瑕佹彁渚涚湡瀹炴祦绋嬬紪鍙枫��");
-        }
-        if (normalized.startsWith("鎾ら攢鎴戝垰鍒氬娴佺▼缂栧彿") && normalized.contains("瀹℃壒鎿嶄綔")) {
-            return hasApproveId
-                    ? approveTodoTools.cancelReviewTodo(memoryId, approveId, extractRemark(text))
-                    : missingApproveId("cancel_review_action", "鎾ら攢瀹℃壒鎿嶄綔闇�瑕佹彁渚涚湡瀹炴祦绋嬬紪鍙枫��");
-        }
-        if (normalized.startsWith("甯垜淇敼娴佺▼缂栧彿") && normalized.contains("澶囨敞涓�")) {
-            return hasApproveId
-                    ? approveTodoTools.updateTodo(memoryId, approveId, null, null, null, null, null, null, extractRemark(text))
-                    : missingApproveId("update_action", "淇敼瀹℃壒鍗曢渶瑕佹彁渚涚湡瀹炴祦绋嬬紪鍙枫��");
-        }
-        if (normalized.startsWith("鍒犻櫎鎴戝彂璧风殑娴佺▼缂栧彿")) {
-            return hasApproveId
-                    ? approveTodoTools.deleteTodo(memoryId, approveId)
-                    : missingApproveId("delete_action", "鍒犻櫎瀹℃壒鍗曢渶瑕佹彁渚涚湡瀹炴祦绋嬬紪鍙枫��");
-        }
-        return null;
-    }
-
-    private boolean isStatsIntent(String text) {
-        if (containsAny(text, "缁熻", "鍒嗘瀽", "鍥捐〃", "瓒嬪娍", "鍗犳瘮", "姹囨��", "鎬婚噺", "鍒嗗竷", "鍚勬湁澶氬皯", "鏈夊灏�")) {
-            return true;
-        }
-        boolean hasQueryWord = containsAny(text, "鏌ヨ", "鏌ョ湅", "鐪嬩笅", "鐪嬬湅", "鑾峰彇");
-        boolean hasDataWord = containsAny(text, "鏁版嵁", "鎶ヨ〃", "鎯呭喌", "鏁伴噺", "閲戦");
-        boolean hasTimeWord = containsAny(text, "浠婂ぉ", "鏄ㄦ棩", "鏄ㄥぉ", "鏈懆", "涓婂懆", "鏈湀", "涓婃湀", "鏈勾", "浠婂勾", "鍘诲勾")
-                || DATE_PATTERN.matcher(text).find()
-                || RECENT_RANGE_PATTERN.matcher(text).find()
-                || HALF_RANGE_PATTERN.matcher(text).find()
-                || EXPLICIT_RANGE_PATTERN.matcher(text).matches();
-        return hasQueryWord && hasDataWord && hasTimeWord;
-    }
-
-    private boolean containsAny(String text, String... keywords) {
-        for (String keyword : keywords) {
-            if (text.contains(keyword)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private String extractApproveId(String text) {
-        Matcher keywordMatcher = APPROVE_ID_BY_LABEL_PATTERN.matcher(text);
-        if (keywordMatcher.find()) {
-            return keywordMatcher.group(2);
-        }
-        Matcher matcher = APPROVE_ID_PATTERN.matcher(text);
-        return matcher.find() ? matcher.group() : null;
-    }
-
-    private Integer extractLimit(String text) {
-        Matcher matcher = LIMIT_PATTERN.matcher(text);
-        return matcher.find() ? Integer.parseInt(matcher.group(2)) : 10;
-    }
-
-    private String extractStatus(String text) {
-        if (containsAny(text, "寰呭鏍�", "寰呭鎵�")) {
-            return "pending";
-        }
-        if (containsAny(text, "瀹℃牳涓�", "澶勭悊涓�", "澶勭悊涓殑", "鍔炵悊涓�")) {
-            return "processing";
-        }
-        if (containsAny(text, "宸查�氳繃", "閫氳繃", "瀹℃牳瀹屾垚", "瀹℃壒瀹屾垚")) {
-            return "approved";
-        }
-        if (containsAny(text, "鏈�氳繃", "椹冲洖", "宸查┏鍥�", "鎷掔粷")) {
-            return "rejected";
-        }
-        if (containsAny(text, "閲嶆柊鎻愪氦")) {
-            return "resubmitted";
-        }
-        return "all";
-    }
-
-    private Integer extractApproveType(String text) {
-        if (text.contains("鍏嚭")) {
-            return 1;
-        }
-        if (text.contains("璇峰亣")) {
-            return 2;
-        }
-        if (text.contains("鍑哄樊")) {
-            return 3;
-        }
-        if (text.contains("鎶ラ攢")) {
-            return 4;
-        }
-        if (text.contains("閲囪喘")) {
-            return 5;
-        }
-        if (text.contains("鎶ヤ环")) {
-            return 6;
-        }
-        if (text.contains("鍙戣揣")) {
-            return 7;
-        }
-        if (text.contains("鍗遍櫓浣滀笟")) {
-            return 8;
-        }
-        return null;
-    }
-
-    private String extractKeyword(String text) {
-        String cleaned = text
-                .replace("鏌ヨ", "")
-                .replace("鏌ョ湅", "")
-                .replace("鍒楀嚭", "")
-                .replace("甯垜", "")
-                .replace("瀹℃壒", "")
-                .replace("鍗曟嵁", "")
-                .replace("寰呭姙", "")
-                .replace("鍒楄〃", "")
-                .replace("娴佺▼缂栧彿", "")
-                .replace("娴佺▼鍙�", "")
-                .replace("鍓�10鏉�", "")
-                .replace("鏈�杩�10鏉�", "")
-                .trim();
-        return cleaned.length() >= 2 ? cleaned : null;
-    }
-
-    private String extractValue(String text, String fieldName) {
-        Pattern pattern = Pattern.compile(fieldName + "(鏀逛负|淇敼涓簗涓簗鏄�)[:锛歖?[\\s]*([^,锛屻�傦紱;\\s]+)");
-        Matcher matcher = pattern.matcher(text);
-        return matcher.find() ? matcher.group(2) : null;
-    }
-
-    private String extractDateValue(String text, String fieldName) {
-        int index = text.indexOf(fieldName);
-        if (index < 0) {
-            return null;
-        }
-        Matcher matcher = DATE_PATTERN.matcher(text.substring(index));
-        return matcher.find() ? matcher.group(1) : null;
-    }
-
-    private String extractStartDate(String text) {
-        Matcher matcher = DATE_PATTERN.matcher(text);
-        return matcher.find() ? matcher.group(1) : null;
-    }
-
-    private String extractEndDate(String text) {
-        Matcher matcher = DATE_PATTERN.matcher(text);
-        if (!matcher.find()) {
-            return null;
-        }
-        return matcher.find() ? matcher.group(1) : null;
-    }
-
-    private String extractTimeRange(String text) {
-        if (containsAny(text, "浠婂ぉ", "鏄ㄦ棩", "鏄ㄥぉ", "鏈懆", "涓婂懆", "鏈湀", "涓婃湀", "鏈勾", "浠婂勾", "鍘诲勾")) {
-            return text;
-        }
-        if (RECENT_RANGE_PATTERN.matcher(text).find()) {
-            return text;
-        }
-        if (HALF_RANGE_PATTERN.matcher(text).find()) {
-            return text;
-        }
-        if (EXPLICIT_RANGE_PATTERN.matcher(text).matches()) {
-            return text;
-        }
-        return null;
-    }
-
-    private Integer extractIntegerValue(String text, String fieldName) {
-        if (!text.contains(fieldName)) {
-            return null;
-        }
-        Matcher matcher = Pattern.compile(fieldName + "(鏀逛负|淇敼涓簗涓簗鏄�)[:锛歖?[\\s]*(\\d{1,2})").matcher(text);
-        return matcher.find() ? Integer.parseInt(matcher.group(2)) : null;
-    }
-
-    private BigDecimal extractBigDecimalValue(String text, String fieldName) {
-        int index = text.indexOf(fieldName);
-        if (index < 0) {
-            return null;
-        }
-        Matcher matcher = NUMBER_PATTERN.matcher(text.substring(index));
-        return matcher.find() ? new BigDecimal(matcher.group(1)) : null;
-    }
-
-    private String extractTail(String text, String key) {
-        Pattern quotedPattern = Pattern.compile(key + "(鏄瘄涓�)?[:锛歖?[\\s]*[鈥淺"]([^鈥漒"]+)[鈥漒"]");
-        Matcher quotedMatcher = quotedPattern.matcher(text);
-        if (quotedMatcher.find()) {
-            return cleanContent(quotedMatcher.group(2));
-        }
-        Pattern pattern = Pattern.compile(key + "(鏄瘄涓�)?[:锛歖?[\\s]*(.+)");
-        Matcher matcher = pattern.matcher(text);
-        return matcher.find() ? cleanContent(matcher.group(2)) : null;
-    }
-
-    private String extractScope(String text) {
-        if (containsAny(text, "鎴戝彂璧�", "鎴戞彁浜�", "鎴戠敵璇�", "鐢宠浜烘槸鎴�")) {
-            return "applicant";
-        }
-        if (containsAny(text, "寰呮垜瀹℃壒", "寰呮垜瀹℃牳", "鎴戝鐞�", "鎴戝鎵�", "褰撳墠寰呮垜", "闇�瑕佹垜澶勭悊", "闇�瑕佸鐞�")) {
-            return "approver";
-        }
-        return "related";
-    }
-
-    private String extractRemark(String text) {
-        return firstNonBlank(firstNonBlank(extractTail(text, "澶囨敞"), extractTail(text, "鍘熷洜")), extractQuotedContent(text));
-    }
-
-    private String extractQuotedContent(String text) {
-        Matcher matcher = Pattern.compile("[鈥淺"]([^鈥漒"]+)[鈥漒"]").matcher(text);
-        return matcher.find() ? cleanContent(matcher.group(1)) : null;
-    }
-
-    private String normalizeForMatch(String text) {
-        if (!StringUtils.hasText(text)) {
-            return "";
-        }
-        return text.replace("锛�", "")
-                .replace(",", "")
-                .replace("銆�", "")
-                .replace(".", "")
-                .replace("锛�", "")
-                .replace("!", "")
-                .replace("锛�", "")
-                .replace("?", "")
-                .replace("锛�", "")
-                .replace(":", "")
-                .replace("锛�", "")
-                .replace(";", "")
-                .replace("鈥�", "")
-                .replace("鈥�", "")
-                .replace("\"", "")
-                .replace(" ", "")
-                .trim();
-    }
-
-    private boolean isPlaceholderApproveId(String approveId) {
-        if (!StringUtils.hasText(approveId)) {
-            return true;
-        }
-        String value = approveId.trim();
-        return "xxx".equalsIgnoreCase(value)
-                || value.matches("[xX]{2,}")
-                || "娴佺▼缂栧彿".equals(value)
-                || "缂栧彿".equals(value)
-                || value.contains("绀轰緥")
-                || value.contains("璇疯緭鍏�");
-    }
-
-    private String cleanContent(String text) {
-        if (!StringUtils.hasText(text)) {
-            return null;
-        }
-        return text.trim()
-                .replace("鈥�", "")
-                .replace("鈥�", "")
-                .replace("\"", "")
-                .replace("銆�", "")
-                .replace("锛�", "")
-                .replace(";", "")
-                .trim();
-    }
-
-    private String firstNonBlank(String first, String second) {
-        return StringUtils.hasText(first) ? first : second;
-    }
-
-    private String missingApproveId(String type, String description) {
-        Map<String, Object> result = new LinkedHashMap<>();
-        result.put("success", false);
-        result.put("type", type);
-        result.put("description", description);
-        result.put("summary", Map.of());
-        result.put("data", Map.of());
-        result.put("charts", Map.of());
-        return JSON.toJSONString(result);
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/assistant/Assistant.java b/src/main/java/com/ruoyi/ai/assistant/Assistant.java
deleted file mode 100644
index f0718c0..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/Assistant.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import dev.langchain4j.service.spring.AiService;
-
-import static dev.langchain4j.service.spring.AiServiceWiringMode.EXPLICIT;
-
-/**
- * @author :yys
- * @date : 2025/5/2 18:26
- */
-//鍥犱负鎴戜滑鍦ㄩ厤缃枃浠朵腑鍚屾椂閰嶇疆浜嗗涓ぇ璇█妯″瀷锛屾墍浠ラ渶瑕佸湪杩欓噷鏄庣‘鎸囧畾锛圗XPLICIT锛夋ā鍨嬬殑beanName
-
-@AiService(wiringMode = EXPLICIT, chatModel = "qwenChatModel")
-public interface Assistant {
-    String chat(String userMessage);
-}
diff --git a/src/main/java/com/ruoyi/ai/assistant/FileAnalyzeAgent.java b/src/main/java/com/ruoyi/ai/assistant/FileAnalyzeAgent.java
deleted file mode 100644
index 131a9b7..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/FileAnalyzeAgent.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import dev.langchain4j.service.MemoryId;
-import dev.langchain4j.service.SystemMessage;
-import dev.langchain4j.service.UserMessage;
-import dev.langchain4j.service.spring.AiService;
-import reactor.core.publisher.Flux;
-
-import static dev.langchain4j.service.spring.AiServiceWiringMode.EXPLICIT;
-
-@AiService(
-        wiringMode = EXPLICIT,
-        streamingChatModel = "qwenStreamingChatModel",
-        chatMemoryProvider = "chatMemoryProvider"
-)
-public interface FileAnalyzeAgent {
-
-    @SystemMessage("""
-            浣犳槸浼佷笟鏂囨。鍒嗘瀽鍔╂墜銆�
-            璇蜂弗鏍煎熀浜庣敤鎴锋彁渚涚殑鏂囦欢鍐呭杩涜鍒嗘瀽锛岃緭鍑鸿缁撴瀯鍖栥�佸噯纭�佺畝娲併��
-            鑻ユ枃浠跺唴瀹逛笉瓒充互鏀寔缁撹锛屾槑纭寚鍑衡�滀笉瓒充俊鎭�濆苟缁欏嚭闇�瑕佽ˉ鍏呯殑鏁版嵁椤广��
-            """)
-    Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage);
-}
diff --git a/src/main/java/com/ruoyi/ai/assistant/FinancialAgent.java b/src/main/java/com/ruoyi/ai/assistant/FinancialAgent.java
deleted file mode 100644
index 875b98d..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/FinancialAgent.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import dev.langchain4j.service.MemoryId;
-import dev.langchain4j.service.SystemMessage;
-import dev.langchain4j.service.UserMessage;
-import dev.langchain4j.service.V;
-import dev.langchain4j.service.spring.AiService;
-import reactor.core.publisher.Flux;
-
-import static dev.langchain4j.service.spring.AiServiceWiringMode.EXPLICIT;
-
-@AiService(
-        wiringMode = EXPLICIT,
-        streamingChatModel = "qwenStreamingChatModel",
-        chatMemoryProvider = "chatMemoryProviderFinancial",
-        tools = "financialAgentTools"
-)
-public interface FinancialAgent {
-
-    @SystemMessage(fromResource = "financial-agent-prompt.txt")
-    Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage, @V("currentDate") String currentDate);
-}
diff --git a/src/main/java/com/ruoyi/ai/assistant/FinancialIntentExecutor.java b/src/main/java/com/ruoyi/ai/assistant/FinancialIntentExecutor.java
deleted file mode 100644
index f402fc2..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/FinancialIntentExecutor.java
+++ /dev/null
@@ -1,284 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import com.ruoyi.ai.tools.FinancialAgentTools;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-import java.time.LocalDate;
-import java.time.YearMonth;
-import java.time.format.DateTimeFormatter;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-@Component
-public class FinancialIntentExecutor {
-
-    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final Pattern LIMIT_PATTERN = Pattern.compile("(?:鍓峾鏈�杩憒灞曠ず|杩斿洖)?\\s*(\\d{1,2})\\s*(?:鏉涓獆鍚�)");
-    private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2})");
-    private static final Pattern RELATIVE_DAY_PATTERN = Pattern.compile("(?:杩憒鏈�杩�)\\s*(\\d{1,3})\\s*澶�");
-    private static final Pattern FUTURE_MONTH_PATTERN = Pattern.compile("(?:鏈潵|鍚庣画|鎺ヤ笅鏉�)\\s*(\\d{1,2})\\s*(?:涓�)?鏈�");
-
-    private final FinancialAgentTools financialAgentTools;
-
-    public FinancialIntentExecutor(FinancialAgentTools financialAgentTools) {
-        this.financialAgentTools = financialAgentTools;
-    }
-
-    public String tryExecute(String memoryId, String message) {
-        if (!StringUtils.hasText(message)) {
-            return null;
-        }
-        String text = message.trim();
-
-        String quickPromptResponse = tryExecuteQuickPrompt(memoryId, text);
-        if (StringUtils.hasText(quickPromptResponse)) {
-            return quickPromptResponse;
-        }
-
-        DateRange dateRange = extractDateRange(text);
-        Integer limit = extractLimit(text);
-        String keyword = extractKeyword(text);
-        String startDate = dateRange.startDate();
-        String endDate = dateRange.endDate();
-        String timeRange = dateRange.label();
-
-        if (containsAny(text, "鎴愭湰鏍哥畻", "浜у搧鎴愭湰", "宸ュ簭鎴愭湰", "浜哄伐鎴愭湰", "鎶樻棫", "鏉愭枡鎹熻��", "鎴愭湰鏈�楂�")) {
-            return financialAgentTools.calculateIntelligentCost(memoryId, startDate, endDate, timeRange, keyword, limit);
-        }
-        if (containsAny(text, "鍒╂鼎鍒嗘瀽", "璁㈠崟鍒╂鼎", "浜忔崯璁㈠崟", "浣庡埄娑�", "鏈�璧氶挶瀹㈡埛", "鍝釜瀹㈡埛鏈�璧氶挶",
-                "瀹㈡埛鏈�璧氶挶", "鍒╂鼎鏈�楂樺鎴�", "鍒╂鼎璐$尞鏈�楂�", "鍒╂鼎涓嬮檷")) {
-            return financialAgentTools.analyzeOrderProfit(memoryId, startDate, endDate, timeRange, keyword, limit);
-        }
-        if (containsAny(text, "搴撳瓨璧勯噾", "搴撳瓨绉帇", "鍛嗘粸搴撳瓨", "璧勯噾鍗犵敤", "鍛ㄨ浆鐜�", "搴撳瓨鍛ㄨ浆")) {
-            return financialAgentTools.analyzeInventoryCapital(memoryId, startDate, endDate, timeRange, keyword, limit);
-        }
-        if (containsAny(text, "鐜伴噾娴�", "鍥炴椋庨櫓", "浠樻鍘嬪姏", "璧勯噾缂哄彛", "搴旀敹", "搴斾粯", "鍥炴棰勬祴")) {
-            return financialAgentTools.forecastCashFlow(memoryId, startDate, endDate, timeRange, extractForecastMonths(text));
-        }
-        if (containsAny(text, "寮傚父棰勮", "缁忚惀寮傚父", "椋庨櫓棰勮", "鎴愭湰寮傚父", "鍒╂鼎寮傚父", "鍥炴寮傚父", "璁㈠崟椋庨櫓")) {
-            return financialAgentTools.detectBusinessAnomalies(memoryId, startDate, endDate, timeRange, limit);
-        }
-        if (containsAny(text, "椹鹃┒鑸�", "缁忚惀鐪嬫澘", "缁忚惀鎬昏", "缁忚惀浠〃鐩�", "缁忚惀澶х洏")) {
-            return financialAgentTools.getBusinessCockpit(memoryId, startDate, endDate, timeRange);
-        }
-        if (containsAny(text, "鏃ユ姤", "鍛ㄦ姤", "缁忚惀鎶ュ憡", "鍒嗘瀽鎶ュ憡")) {
-            return financialAgentTools.generateOperationReport(memoryId, startDate, endDate, timeRange,
-                    containsAny(text, "鍛ㄦ姤") ? "weekly" : "daily");
-        }
-        if (containsAny(text, "涓氳储铻嶅悎", "涓氳储鑱斿姩", "鍙e緞", "鎸囨爣瑙i噴", "涓轰粈涔�")) {
-            return financialAgentTools.retrieveFinancialKnowledge(memoryId, text);
-        }
-        return null;
-    }
-
-    private String tryExecuteQuickPrompt(String memoryId, String text) {
-        String normalized = normalizeForMatch(text);
-        if ("鐢熸垚鏈懆缁忚惀鍛ㄦ姤鍒╂鼎涓庣幇閲戞祦".equals(normalized) || "鐢熸垚鏈懆缁忚惀鍛ㄦ姤".equals(normalized) || "鐢熸垚鍛ㄦ姤".equals(normalized)) {
-            DateRange range = weekRange();
-            return financialAgentTools.generateOperationReport(memoryId, range.startDate(), range.endDate(), range.label(), "weekly");
-        }
-        if ("鍒嗘瀽鏈湀鍒╂鼎涓嬮檷鍘熷洜".equals(normalized)) {
-            DateRange range = monthRange();
-            return financialAgentTools.analyzeOrderProfit(memoryId, range.startDate(), range.endDate(), range.label(), null, null);
-        }
-        if ("杩�30澶╁摢涓鎴峰埄娑﹁础鐚渶楂�".equals(normalized)) {
-            DateRange range = recentDaysRange(30);
-            return financialAgentTools.analyzeOrderProfit(memoryId, range.startDate(), range.endDate(), range.label(), null, null);
-        }
-        if ("鏌ョ湅鏈湀缁忚惀椹鹃┒鑸�".equals(normalized) || "鏌ョ湅缁忚惀椹鹃┒鑸�".equals(normalized)) {
-            DateRange range = monthRange();
-            return financialAgentTools.getBusinessCockpit(memoryId, range.startDate(), range.endDate(), range.label());
-        }
-        if ("鏌ヨ杩�30澶╀簭鎹熻鍗�".equals(normalized)) {
-            DateRange range = recentDaysRange(30);
-            return financialAgentTools.analyzeOrderProfit(memoryId, range.startDate(), range.endDate(), range.label(), null, null);
-        }
-        if ("鍒嗘瀽杩�30澶╁簱瀛樿祫閲戝崰鐢�".equals(normalized)) {
-            DateRange range = recentDaysRange(30);
-            return financialAgentTools.analyzeInventoryCapital(memoryId, range.startDate(), range.endDate(), range.label(), null, null);
-        }
-        if ("棰勬祴鏈潵3涓湀鐜伴噾娴�".equals(normalized)) {
-            return financialAgentTools.forecastCashFlow(memoryId, null, null, null, 3);
-        }
-        if ("鍝釜宸ュ簭鎴愭湰鏈�楂�".equals(normalized)) {
-            return financialAgentTools.calculateIntelligentCost(memoryId, null, null, null, null, null);
-        }
-        return null;
-    }
-
-    private boolean containsAny(String text, String... keywords) {
-        for (String keyword : keywords) {
-            if (text.contains(keyword)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private Integer extractLimit(String text) {
-        Matcher matcher = LIMIT_PATTERN.matcher(text);
-        return matcher.find() ? Integer.parseInt(matcher.group(1)) : null;
-    }
-
-    private Integer extractForecastMonths(String text) {
-        Matcher matcher = FUTURE_MONTH_PATTERN.matcher(text);
-        return matcher.find() ? Integer.parseInt(matcher.group(1)) : null;
-    }
-
-    private DateRange extractDateRange(String text) {
-        Matcher matcher = DATE_PATTERN.matcher(text);
-        if (matcher.find()) {
-            String first = matcher.group(1);
-            String second = matcher.find() ? matcher.group(1) : first;
-            return buildDateRange(first, second, first + "鑷�" + second);
-        }
-        if (text.contains("鏈湀")) {
-            return monthRange();
-        }
-        if (text.contains("涓婃湀")) {
-            return lastMonthRange();
-        }
-        if (text.contains("浠婂勾") || text.contains("鏈勾")) {
-            return yearRange();
-        }
-        if (text.contains("鏈懆")) {
-            return weekRange();
-        }
-        Matcher relativeDayMatcher = RELATIVE_DAY_PATTERN.matcher(text);
-        if (relativeDayMatcher.find()) {
-            int days = Integer.parseInt(relativeDayMatcher.group(1));
-            return recentDaysRange(days);
-        }
-        return new DateRange(null, null, null);
-    }
-
-    private DateRange buildDateRange(String start, String end, String label) {
-        LocalDate startDate = parseDate(start);
-        LocalDate endDate = parseDate(end);
-        if (startDate == null || endDate == null) {
-            return new DateRange(null, null, null);
-        }
-        if (startDate.isAfter(endDate)) {
-            LocalDate temp = startDate;
-            startDate = endDate;
-            endDate = temp;
-        }
-        return new DateRange(formatDate(startDate), formatDate(endDate), label);
-    }
-
-    private DateRange recentDaysRange(int days) {
-        LocalDate end = LocalDate.now();
-        int safeDays = Math.max(days, 1);
-        LocalDate start = end.minusDays(safeDays - 1L);
-        return new DateRange(formatDate(start), formatDate(end), "杩�" + safeDays + "澶�");
-    }
-
-    private DateRange monthRange() {
-        LocalDate today = LocalDate.now();
-        return new DateRange(formatDate(today.withDayOfMonth(1)), formatDate(today), "鏈湀");
-    }
-
-    private DateRange weekRange() {
-        LocalDate today = LocalDate.now();
-        LocalDate start = today.minusDays(today.getDayOfWeek().getValue() - 1L);
-        return new DateRange(formatDate(start), formatDate(today), "鏈懆");
-    }
-
-    private DateRange lastMonthRange() {
-        YearMonth lastMonth = YearMonth.now().minusMonths(1);
-        return new DateRange(formatDate(lastMonth.atDay(1)), formatDate(lastMonth.atEndOfMonth()), "涓婃湀");
-    }
-
-    private DateRange yearRange() {
-        LocalDate today = LocalDate.now();
-        return new DateRange(formatDate(today.withDayOfYear(1)), formatDate(today), "浠婂勾");
-    }
-
-    private LocalDate parseDate(String text) {
-        try {
-            return LocalDate.parse(text, DATE_FMT);
-        } catch (Exception ignored) {
-            return null;
-        }
-    }
-
-    private String formatDate(LocalDate date) {
-        return date == null ? null : date.format(DATE_FMT);
-    }
-
-    private String normalizeForMatch(String text) {
-        if (!StringUtils.hasText(text)) {
-            return "";
-        }
-        return text.replace("锛�", "")
-                .replace("锛�", "")
-                .replace("(", "")
-                .replace(")", "")
-                .replace("锛�", "")
-                .replace(",", "")
-                .replace("銆�", "")
-                .replace(".", "")
-                .replace("锛�", "")
-                .replace("!", "")
-                .replace("锛�", "")
-                .replace("?", "")
-                .replace("锛�", "")
-                .replace(":", "")
-                .replace("锛�", "")
-                .replace(";", "")
-                .replace(" ", "")
-                .trim();
-    }
-
-    private String extractKeyword(String text) {
-        String cleaned = text
-                .replaceAll("\\d{4}-\\d{2}-\\d{2}", "")
-                .replaceAll("(?:杩憒鏈�杩�)\\s*\\d{1,3}\\s*澶�", "")
-                .replaceAll("(?:鍓峾鏈�杩憒灞曠ず|杩斿洖)?\\s*\\d{1,2}\\s*(?:鏉涓獆鍚�)", "")
-                .replace("鏌ヨ", "")
-                .replace("鏌ョ湅", "")
-                .replace("鐪嬩笅", "")
-                .replace("鐪嬬湅", "")
-                .replace("甯垜", "")
-                .replace("璇�", "")
-                .replace("涓�涓�", "")
-                .replace("涓轰粈涔�", "")
-                .replace("鍝釜瀹㈡埛鏈�璧氶挶", "")
-                .replace("鏈�杩戝摢涓鎴锋渶璧氶挶", "")
-                .replace("鏈湀鍝釜瀹㈡埛鏈�璧氶挶", "")
-                .replace("杩�30澶╁摢涓鎴锋渶璧氶挶", "")
-                .replace("鏈�璧氶挶瀹㈡埛", "")
-                .replace("瀹㈡埛鏈�璧氶挶", "")
-                .replace("鍝釜瀹㈡埛鍒╂鼎鏈�楂�", "")
-                .replace("鍒╂鼎鏈�楂樺鎴�", "")
-                .replace("鍝釜瀹㈡埛鍒╂鼎璐$尞鏈�楂�", "")
-                .replace("鍒╂鼎璐$尞鏈�楂樺鎴�", "")
-                .replace("鏈湀", "")
-                .replace("鏈懆", "")
-                .replace("鏈勾", "")
-                .replace("浠婂勾", "")
-                .replace("涓婃湀", "")
-                .replace("杩�30澶�", "")
-                .replace("杩�7澶�", "")
-                .replace("杩�90澶�", "")
-                .replace("鍓�10鏉�", "")
-                .replace("鏈�杩�10鏉�", "")
-                .replace("鍓�20鏉�", "")
-                .replace("鏈�杩�20鏉�", "")
-                .replace("璁㈠崟鍒╂鼎鍒嗘瀽", "")
-                .replace("鍒╂鼎鍒嗘瀽", "")
-                .replace("搴撳瓨璧勯噾鍒嗘瀽", "")
-                .replace("鐜伴噾娴侀娴�", "")
-                .replace("缁忚惀椹鹃┒鑸�", "")
-                .replace("鏃ユ姤", "")
-                .replace("鍛ㄦ姤", "")
-                .replace("寮傚父棰勮", "")
-                .replace("鏉�", "")
-                .trim();
-        return cleaned.length() >= 2 ? cleaned : null;
-    }
-
-    private record DateRange(String startDate, String endDate, String label) {
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/assistant/KnowledgeChatAgent.java b/src/main/java/com/ruoyi/ai/assistant/KnowledgeChatAgent.java
deleted file mode 100644
index 2d4072c..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/KnowledgeChatAgent.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import dev.langchain4j.service.MemoryId;
-import dev.langchain4j.service.SystemMessage;
-import dev.langchain4j.service.UserMessage;
-import dev.langchain4j.service.spring.AiService;
-import reactor.core.publisher.Flux;
-
-import static dev.langchain4j.service.spring.AiServiceWiringMode.EXPLICIT;
-
-/**
- * 鐭ヨ瘑搴撻棶绛擜gent
- * 鍩轰簬RAG妫�绱㈠寮虹敓鎴�
- */
-@AiService(
-        wiringMode = EXPLICIT,
-        streamingChatModel = "qwenStreamingChatModel",
-        chatMemoryProvider = "chatMemoryProviderXiaozhi"
-)
-public interface KnowledgeChatAgent {
-
-    @SystemMessage("""
-            浣犳槸浼佷笟鐭ヨ瘑搴撻棶绛斿姪鎵嬨��
-
-            浣犻渶瑕佸熀浜庢彁渚涚殑鐭ヨ瘑搴撳唴瀹瑰洖绛旂敤鎴烽棶棰樸��
-
-            閬靛惊浠ヤ笅瑙勫垯锛�
-            1. 涓ユ牸鍩轰簬鐭ヨ瘑搴撳唴瀹瑰洖绛旓紝涓嶈缂栭�犱俊鎭�
-            2. 濡傛灉鐭ヨ瘑搴撲腑娌℃湁鐩稿叧淇℃伅锛屾槑纭憡鐭ョ敤鎴�
-            3. 鍥炵瓟瑕佸噯纭�佺畝娲併�佹湁鏉$悊
-            4. 濡傛灉鍐呭杈冨锛屼娇鐢ㄥ垎鐐瑰垪琛ㄥ舰寮�
-            5. 寮曠敤鏉ユ簮鏃舵敞鏄�"鏍规嵁鐭ヨ瘑搴撳唴瀹�"
-            """)
-    Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage);
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java b/src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java
deleted file mode 100644
index 0d16703..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import dev.langchain4j.service.MemoryId;
-import dev.langchain4j.service.SystemMessage;
-import dev.langchain4j.service.UserMessage;
-import dev.langchain4j.service.V;
-import dev.langchain4j.service.spring.AiService;
-import reactor.core.publisher.Flux;
-
-import static dev.langchain4j.service.spring.AiServiceWiringMode.EXPLICIT;
-
-@AiService(
-        wiringMode = EXPLICIT,
-        streamingChatModel = "qwenStreamingChatModel",
-        chatMemoryProvider = "chatMemoryProviderManufacturing",
-        tools = "manufacturingAgentTools"
-)
-public interface ManufacturingAgent {
-
-    @SystemMessage(fromResource = "manufacturing-agent-prompt.txt")
-    Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage, @V("currentDate") String currentDate);
-}
diff --git a/src/main/java/com/ruoyi/ai/assistant/ManufacturingIntentExecutor.java b/src/main/java/com/ruoyi/ai/assistant/ManufacturingIntentExecutor.java
deleted file mode 100644
index e9d9396..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/ManufacturingIntentExecutor.java
+++ /dev/null
@@ -1,136 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import com.ruoyi.ai.tools.ManufacturingAgentTools;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-@Component
-public class ManufacturingIntentExecutor {
-
-    private static final Pattern LIMIT_PATTERN = Pattern.compile("(鍓峾鏈�杩�)?(\\d{1,2})鏉�");
-    private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2})");
-
-    private final ManufacturingAgentTools manufacturingAgentTools;
-
-    public ManufacturingIntentExecutor(ManufacturingAgentTools manufacturingAgentTools) {
-        this.manufacturingAgentTools = manufacturingAgentTools;
-    }
-
-    public String tryExecute(String memoryId, String message) {
-        if (!StringUtils.hasText(message)) {
-            return null;
-        }
-        String text = message.trim();
-        String keyword = extractKeyword(text);
-        Integer limit = extractLimit(text);
-        String startDate = extractStartDate(text);
-        String endDate = extractEndDate(text);
-
-        if (containsAny(text, "棰勮", "鍛婅", "椋庨櫓", "鎻愰啋")) {
-            return manufacturingAgentTools.getWarningBoard(memoryId, startDate, endDate, text);
-        }
-        if (containsAny(text, "鍒嗘瀽", "缁熻", "瓒嬪娍", "鐪嬫澘", "鎶ヨ〃", "鎬昏")) {
-            return manufacturingAgentTools.analyzeFactory(memoryId, startDate, endDate, text);
-        }
-        if (containsAny(text, "鍔�", "澶勭悊", "娲惧伐", "瀹夋帓", "闂幆", "璺熻繘", "澶勭疆")) {
-            return manufacturingAgentTools.planActions(memoryId, text);
-        }
-
-        if (containsAny(text, "鐢熶骇鐜板満", "鐜板満", "杞﹂棿")) {
-            return manufacturingAgentTools.queryDomain(memoryId, "site", keyword, limit, startDate, endDate, text);
-        }
-        if (containsAny(text, "璁″垝", "鎺掍骇", "mps")) {
-            return manufacturingAgentTools.queryDomain(memoryId, "plan", keyword, limit, startDate, endDate, text);
-        }
-        if (containsAny(text, "宸ュ崟", "浣滀笟鍗�", "浠诲姟鍗�", "浠诲姟")) {
-            return manufacturingAgentTools.queryDomain(memoryId, "workorder", keyword, limit, startDate, endDate, text);
-        }
-        if (containsAny(text, "璁惧", "缁翠慨", "淇濆吇", "鏁呴殰")) {
-            return manufacturingAgentTools.queryDomain(memoryId, "device", keyword, limit, startDate, endDate, text);
-        }
-        if (containsAny(text, "璐ㄩ噺", "璐ㄦ", "涓嶅悎鏍�", "妫�楠�")) {
-            return manufacturingAgentTools.queryDomain(memoryId, "quality", keyword, limit, startDate, endDate, text);
-        }
-        if (containsAny(text, "鐗╂枡", "搴撳瓨", "搴撲綅", "鍏ュ簱", "鍑哄簱")) {
-            return manufacturingAgentTools.queryDomain(memoryId, "material", keyword, limit, startDate, endDate, text);
-        }
-        if (containsAny(text, "寮傚父", "渚嬪", "鍋忓樊")) {
-            return manufacturingAgentTools.queryDomain(memoryId, "exception", keyword, limit, startDate, endDate, text);
-        }
-        return null;
-    }
-
-    private boolean containsAny(String text, String... keywords) {
-        for (String keyword : keywords) {
-            if (text.toLowerCase().contains(keyword.toLowerCase())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private Integer extractLimit(String text) {
-        Matcher matcher = LIMIT_PATTERN.matcher(text);
-        return matcher.find() ? Integer.parseInt(matcher.group(2)) : 10;
-    }
-
-    private String extractStartDate(String text) {
-        Matcher matcher = DATE_PATTERN.matcher(text);
-        return matcher.find() ? matcher.group(1) : null;
-    }
-
-    private String extractEndDate(String text) {
-        Matcher matcher = DATE_PATTERN.matcher(text);
-        if (!matcher.find()) {
-            return null;
-        }
-        return matcher.find() ? matcher.group(1) : null;
-    }
-
-    private String extractKeyword(String text) {
-        String cleaned = text
-                .replace("鏌ヨ", "")
-                .replace("鏌ョ湅", "")
-                .replace("甯垜", "")
-                .replace("璇�", "")
-                .replace("涓�涓�", "")
-                .replace("鎵�鏈�", "")
-                .replace("鍏ㄩ儴", "")
-                .replace("浠婂勾", "")
-                .replace("鏈勾", "")
-                .replace("鍘诲勾", "")
-                .replace("鏈湀", "")
-                .replace("涓婃湀", "")
-                .replace("鏈懆", "")
-                .replace("涓婂懆", "")
-                .replace("浠婂ぉ", "")
-                .replace("鏄ㄥぉ", "")
-                .replace("杩�30澶�", "")
-                .replace("杩�7澶�", "")
-                .replace("杩�15澶�", "")
-                .replace("杩�60澶�", "")
-                .replace("鏈�杩�30澶�", "")
-                .replace("鏈�杩�7澶�", "")
-                .replace("鏈�杩�15澶�", "")
-                .replace("鏈�杩�60澶�", "")
-                .replace("鐢熶骇鐜板満", "")
-                .replace("鐜板満", "")
-                .replace("鐢熶骇宸ュ崟", "")
-                .replace("鐢熶骇", "")
-                .replace("璁″垝", "")
-                .replace("鎺掍骇", "")
-                .replace("宸ュ崟", "")
-                .replace("璁惧", "")
-                .replace("璐ㄩ噺", "")
-                .replace("鐗╂枡", "")
-                .replace("搴撳瓨", "")
-                .replace("寮傚父", "")
-                .replace("鍓�10鏉�", "")
-                .replace("鏈�杩�10鏉�", "")
-                .trim();
-        return cleaned.length() >= 2 ? cleaned : null;
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java b/src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java
deleted file mode 100644
index 421261d..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import dev.langchain4j.service.MemoryId;
-import dev.langchain4j.service.SystemMessage;
-import dev.langchain4j.service.UserMessage;
-import dev.langchain4j.service.V;
-import dev.langchain4j.service.spring.AiService;
-import reactor.core.publisher.Flux;
-
-import static dev.langchain4j.service.spring.AiServiceWiringMode.EXPLICIT;
-
-@AiService(
-        wiringMode = EXPLICIT,
-        streamingChatModel = "qwenStreamingChatModel",
-        chatMemoryProvider = "chatMemoryProviderPurchase",
-        tools = "purchaseAgentTools"
-)
-public interface PurchaseAgent {
-
-    @SystemMessage(fromResource = "purchase-agent-prompt.txt")
-    Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage, @V("currentDate") String currentDate);
-}
diff --git a/src/main/java/com/ruoyi/ai/assistant/PurchaseIntentExecutor.java b/src/main/java/com/ruoyi/ai/assistant/PurchaseIntentExecutor.java
deleted file mode 100644
index c04915e..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/PurchaseIntentExecutor.java
+++ /dev/null
@@ -1,288 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import com.ruoyi.ai.tools.PurchaseAgentTools;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-@Component
-public class PurchaseIntentExecutor {
-
-    private static final Pattern ID_PATTERN = Pattern.compile("\\b\\d{1,12}\\b");
-    private static final Pattern LIMIT_PATTERN = Pattern.compile("(鍓峾鏈�杩�)?\\s*(\\d{1,2})\\s*鏉�");
-    private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2})");
-    private static final Pattern RELATIVE_RANGE_PATTERN = Pattern.compile("(杩憒鏈�杩�)\\s*(\\d{1,3})\\s*(澶﹟鍛▅涓湀|鏈坾骞�)");
-    private static final Pattern HALF_RANGE_PATTERN = Pattern.compile("(鏈�杩憒杩�)?鍗�(涓�)?(鏈坾骞�)");
-    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final ZoneId CHINA_ZONE_ID = ZoneId.of("Asia/Shanghai");
-
-    private final PurchaseAgentTools purchaseAgentTools;
-
-    public PurchaseIntentExecutor(PurchaseAgentTools purchaseAgentTools) {
-        this.purchaseAgentTools = purchaseAgentTools;
-    }
-
-    public String tryExecute(String memoryId, String message) {
-        if (!StringUtils.hasText(message)) {
-            return null;
-        }
-        String text = message.trim();
-        String quickPromptResponse = tryExecuteQuickPrompt(memoryId, text);
-        if (StringUtils.hasText(quickPromptResponse)) {
-            return quickPromptResponse;
-        }
-
-        String keyword = extractKeyword(text);
-        Integer limit = extractLimit(text);
-        DateRange dateRange = extractDateRange(text);
-        String startDate = dateRange.startDate();
-        String endDate = dateRange.endDate();
-
-        if (containsAny(text, "鎺掕", "鎺掑悕", "鍓嶅嚑", "鍓嶄簲", "鍓嶅崄")
-                && containsAny(text, "鐗╂枡", "浜у搧", "鍘熸潗鏂�", "閲囪喘閲戦", "閲戦")) {
-            return purchaseAgentTools.rankPurchaseMaterials(memoryId, startDate, endDate, text, limit);
-        }
-        if (containsAny(text, "鏈叆搴�", "寰呭叆搴�", "娌℃湁鍏ュ簱", "杩樻湭鍏ュ簱")) {
-            return purchaseAgentTools.listUnstockedPurchaseOrders(memoryId, startDate, endDate, keyword, limit);
-        }
-        if (containsAny(text, "鍒拌揣寮傚父", "鍒拌揣鏈夊紓甯�", "寮傚父鍒拌揣", "鍒拌揣闂", "渚涘簲鍟嗗埌璐у紓甯�")) {
-            return purchaseAgentTools.listArrivalExceptions(memoryId, startDate, endDate, text, limit);
-        }
-        if (containsAny(text, "寰呬粯娆�", "鏈粯娆�", "鏈粯娓�", "寰呮敮浠�", "搴斾粯")) {
-            return purchaseAgentTools.listPendingPaymentOrders(memoryId, startDate, endDate, keyword, limit);
-        }
-        if (containsAny(text, "閫�璐�", "閫�鏂�", "鎷掓敹")) {
-            return purchaseAgentTools.listPurchaseReturns(memoryId, startDate, endDate, keyword, limit);
-        }
-        if (isStatsIntent(text)) {
-            return purchaseAgentTools.getPurchaseStats(memoryId, startDate, endDate, text);
-        }
-
-        Long ledgerId = extractId(text);
-        if (containsAny(text, "璇︽儏", "鏄庣粏") && ledgerId != null) {
-            return purchaseAgentTools.getPurchaseLedgerDetail(memoryId, ledgerId);
-        }
-        if (containsAny(text, "鍙拌处", "閲囪喘鍗�", "閲囪喘璁㈠崟", "璁㈠崟", "鍚堝悓", "鍒楄〃", "鏌ヨ")) {
-            return purchaseAgentTools.listPurchaseLedgers(memoryId, keyword, startDate, endDate, limit);
-        }
-        return null;
-    }
-
-    private String tryExecuteQuickPrompt(String memoryId, String text) {
-        String normalized = normalizeForMatch(text);
-        if ("鏈湀閲囪喘閲戦鎺掑悕鍓嶅崄鐨勭墿鏂欐湁鍝簺".equals(normalized)) {
-            return purchaseAgentTools.rankPurchaseMaterials(memoryId, null, null, "鏈湀", 10);
-        }
-        if ("鍝簺閲囪喘璁㈠崟杩樻湭鍏ュ簱".equals(normalized)) {
-            return purchaseAgentTools.listUnstockedPurchaseOrders(memoryId, null, null, null, 10);
-        }
-        if ("鏈�杩�7澶╀緵搴斿晢鍒拌揣寮傚父鏈夊摢浜�".equals(normalized)) {
-            return purchaseAgentTools.listArrivalExceptions(memoryId, null, null, "鏈�杩�7澶�", 10);
-        }
-        if ("甯垜缁熻寰呬粯娆鹃噰璐崟".equals(normalized)) {
-            return purchaseAgentTools.listPendingPaymentOrders(memoryId, null, null, null, 10);
-        }
-        if ("鍒楀嚭鏈湀閲囪喘閫�璐ф儏鍐�".equals(normalized)) {
-            return purchaseAgentTools.listPurchaseReturns(memoryId, null, null, null, 10);
-        }
-        return null;
-    }
-
-    private boolean isStatsIntent(String text) {
-        if (containsAny(text, "缁熻", "鍒嗘瀽", "鎶ヨ〃", "姹囨��", "瓒嬪娍", "鏁版嵁鐪嬫澘", "鎯呭喌", "鏈夊灏�")) {
-            return true;
-        }
-        boolean queryWord = containsAny(text, "鏌ヨ", "鏌ョ湅", "鐪嬩笅", "鐪嬬湅", "鑾峰彇");
-        boolean dataWord = containsAny(text, "鏁版嵁", "閲戦", "鏁伴噺", "鍚堝悓棰�", "浠樻棰�", "鍙戠エ棰�");
-        boolean timeWord = containsAny(text, "浠婂ぉ", "鏄ㄥぉ", "鏈懆", "涓婂懆", "鏈湀", "涓婃湀", "浠婂勾", "鍘诲勾", "杩戝崐骞�", "鏈�杩戝崐涓湀", "鍗婁釜鏈�")
-                || DATE_PATTERN.matcher(text).find()
-                || RELATIVE_RANGE_PATTERN.matcher(text).find()
-                || HALF_RANGE_PATTERN.matcher(text).find();
-        return queryWord && dataWord && timeWord;
-    }
-
-    private boolean containsAny(String text, String... keywords) {
-        for (String keyword : keywords) {
-            if (text.contains(keyword)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private Long extractId(String text) {
-        Matcher matcher = ID_PATTERN.matcher(text);
-        if (!matcher.find()) {
-            return null;
-        }
-        return Long.parseLong(matcher.group());
-    }
-
-    private Integer extractLimit(String text) {
-        Matcher matcher = LIMIT_PATTERN.matcher(text);
-        return matcher.find() ? Integer.parseInt(matcher.group(2)) : 10;
-    }
-
-    private DateRange extractDateRange(String text) {
-        Matcher matcher = DATE_PATTERN.matcher(text);
-        if (matcher.find()) {
-            String first = matcher.group(1);
-            String second = matcher.find() ? matcher.group(1) : first;
-            return buildDateRange(first, second);
-        }
-
-        LocalDate today = LocalDate.now(CHINA_ZONE_ID);
-        if (text.contains("浠婂ぉ")) {
-            return new DateRange(formatDate(today), formatDate(today));
-        }
-        if (text.contains("鏄ㄥぉ")) {
-            LocalDate yesterday = today.minusDays(1);
-            return new DateRange(formatDate(yesterday), formatDate(yesterday));
-        }
-        if (text.contains("鏈懆")) {
-            LocalDate start = today.minusDays(today.getDayOfWeek().getValue() - 1L);
-            return new DateRange(formatDate(start), formatDate(today));
-        }
-        if (text.contains("涓婂懆")) {
-            LocalDate thisWeekStart = today.minusDays(today.getDayOfWeek().getValue() - 1L);
-            LocalDate start = thisWeekStart.minusWeeks(1);
-            LocalDate end = start.plusDays(6);
-            return new DateRange(formatDate(start), formatDate(end));
-        }
-        if (text.contains("鏈湀")) {
-            return new DateRange(formatDate(today.withDayOfMonth(1)), formatDate(today));
-        }
-        if (text.contains("涓婃湀")) {
-            LocalDate start = today.minusMonths(1).withDayOfMonth(1);
-            return new DateRange(formatDate(start), formatDate(start.withDayOfMonth(start.lengthOfMonth())));
-        }
-        if (text.contains("浠婂勾") || text.contains("鏈勾")) {
-            return new DateRange(formatDate(today.withDayOfYear(1)), formatDate(today));
-        }
-        if (text.contains("鍘诲勾")) {
-            LocalDate start = today.minusYears(1).withDayOfYear(1);
-            LocalDate end = start.withDayOfYear(start.lengthOfYear());
-            return new DateRange(formatDate(start), formatDate(end));
-        }
-        if (containsAny(text, "杩戝崐骞�", "鏈�杩戝崐骞�")) {
-            return new DateRange(formatDate(today.minusMonths(6).plusDays(1)), formatDate(today));
-        }
-        if (containsAny(text, "杩戝崐涓湀", "鏈�杩戝崐涓湀", "鍗婁釜鏈�")) {
-            return new DateRange(formatDate(today.minusDays(14)), formatDate(today));
-        }
-
-        Matcher relativeMatcher = RELATIVE_RANGE_PATTERN.matcher(text);
-        if (relativeMatcher.find()) {
-            int amount = Integer.parseInt(relativeMatcher.group(2));
-            String unit = relativeMatcher.group(3);
-            LocalDate start = switch (unit) {
-                case "澶�" -> today.minusDays(Math.max(amount - 1L, 0));
-                case "鍛�" -> today.minusWeeks(Math.max(amount, 1)).plusDays(1);
-                case "涓湀", "鏈�" -> today.minusMonths(Math.max(amount, 1)).plusDays(1);
-                case "骞�" -> today.minusYears(Math.max(amount, 1)).plusDays(1);
-                default -> today.minusDays(29);
-            };
-            return new DateRange(formatDate(start), formatDate(today));
-        }
-
-        return new DateRange(null, null);
-    }
-
-    private DateRange buildDateRange(String start, String end) {
-        LocalDate startDate = parseDate(start);
-        LocalDate endDate = parseDate(end);
-        if (startDate == null || endDate == null) {
-            return new DateRange(null, null);
-        }
-        if (startDate.isAfter(endDate)) {
-            LocalDate temp = startDate;
-            startDate = endDate;
-            endDate = temp;
-        }
-        return new DateRange(formatDate(startDate), formatDate(endDate));
-    }
-
-    private LocalDate parseDate(String text) {
-        try {
-            return LocalDate.parse(text, DATE_FMT);
-        } catch (Exception ignored) {
-            return null;
-        }
-    }
-
-    private String formatDate(LocalDate date) {
-        return date == null ? null : date.format(DATE_FMT);
-    }
-
-    private String normalizeForMatch(String text) {
-        if (!StringUtils.hasText(text)) {
-            return "";
-        }
-        return text.replace("锛�", "")
-                .replace(",", "")
-                .replace("銆�", "")
-                .replace(".", "")
-                .replace("锛�", "")
-                .replace("!", "")
-                .replace("锛�", "")
-                .replace("?", "")
-                .replace("锛�", "")
-                .replace(":", "")
-                .replace("锛�", "")
-                .replace(";", "")
-                .replace(" ", "")
-                .trim();
-    }
-
-    private String extractKeyword(String text) {
-        String cleaned = text
-                .replace("鏌ヨ", "")
-                .replace("鏌ョ湅", "")
-                .replace("鐪嬩笅", "")
-                .replace("鐪嬬湅", "")
-                .replace("璇�", "")
-                .replace("涓�涓�", "")
-                .replace("閲囪喘", "")
-                .replace("閲囪喘鍗�", "")
-                .replace("閲囪喘璁㈠崟", "")
-                .replace("璁㈠崟", "")
-                .replace("鍙拌处", "")
-                .replace("鍒楄〃", "")
-                .replace("鍝簺", "")
-                .replace("鍒楀嚭", "")
-                .replace("甯垜", "")
-                .replace("缁熻", "")
-                .replace("鍒嗘瀽", "")
-                .replace("鏈湀", "")
-                .replace("涓婃湀", "")
-                .replace("鏈勾", "")
-                .replace("浠婂勾", "")
-                .replace("鍘诲勾", "")
-                .replace("鏈懆", "")
-                .replace("涓婂懆", "")
-                .replace("浠婂ぉ", "")
-                .replace("鏄ㄥぉ", "")
-                .replace("杩�30澶�", "")
-                .replace("杩�7澶�", "")
-                .replace("杩�15澶�", "")
-                .replace("杩�60澶�", "")
-                .replace("鏈�杩�30澶�", "")
-                .replace("鏈�杩�7澶�", "")
-                .replace("鏈�杩�15澶�", "")
-                .replace("鏈�杩�60澶�", "")
-                .replace("鏈�杩�10鏉�", "")
-                .replace("鍓�10鏉�", "")
-                .replace("鍓�20鏉�", "")
-                .replace("鏈�杩�20鏉�", "")
-                .trim();
-        return cleaned.length() >= 2 ? cleaned : null;
-    }
-
-    private record DateRange(String startDate, String endDate) {
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/assistant/SalesAgent.java b/src/main/java/com/ruoyi/ai/assistant/SalesAgent.java
deleted file mode 100644
index e2f9a81..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/SalesAgent.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import dev.langchain4j.service.MemoryId;
-import dev.langchain4j.service.SystemMessage;
-import dev.langchain4j.service.UserMessage;
-import dev.langchain4j.service.V;
-import dev.langchain4j.service.spring.AiService;
-import reactor.core.publisher.Flux;
-
-import static dev.langchain4j.service.spring.AiServiceWiringMode.EXPLICIT;
-
-@AiService(
-        wiringMode = EXPLICIT,
-        streamingChatModel = "qwenStreamingChatModel",
-        chatMemoryProvider = "chatMemoryProviderSales",
-        tools = "salesAgentTools"
-)
-public interface SalesAgent {
-
-    @SystemMessage(fromResource = "sales-agent-prompt.txt")
-    Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage, @V("currentDate") String currentDate);
-}
diff --git a/src/main/java/com/ruoyi/ai/assistant/SalesIntentExecutor.java b/src/main/java/com/ruoyi/ai/assistant/SalesIntentExecutor.java
deleted file mode 100644
index 4388a3c..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/SalesIntentExecutor.java
+++ /dev/null
@@ -1,270 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import com.ruoyi.ai.tools.SalesAgentTools;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-import java.time.LocalDate;
-import java.time.YearMonth;
-import java.time.format.DateTimeFormatter;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-@Component
-public class SalesIntentExecutor {
-
-    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final Pattern LIMIT_PATTERN = Pattern.compile("(鍓峾鏈�杩�)?\\s*(\\d{1,2})\\s*鏉�");
-    private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2})");
-    private static final Pattern RELATIVE_DAY_PATTERN = Pattern.compile("(杩憒鏈�杩�)?\\s*(\\d{1,3})\\s*澶�");
-
-    private final SalesAgentTools salesAgentTools;
-
-    public SalesIntentExecutor(SalesAgentTools salesAgentTools) {
-        this.salesAgentTools = salesAgentTools;
-    }
-
-    public String tryExecute(String memoryId, String message) {
-        if (!StringUtils.hasText(message)) {
-            return null;
-        }
-        String text = message.trim();
-
-        String quickPromptResponse = tryExecuteQuickPrompt(memoryId, text);
-        if (StringUtils.hasText(quickPromptResponse)) {
-            return quickPromptResponse;
-        }
-
-        String keyword = extractKeyword(text);
-        Integer limit = extractLimit(text);
-        DateRange dateRange = extractDateRange(text);
-        String startDate = dateRange.startDate();
-        String endDate = dateRange.endDate();
-
-        if (containsAny(text, "娴佸け", "娴佸け椋庨櫓", "瀹㈡埛娴佸け", "椋庨櫓鍒嗘瀽")) {
-            return salesAgentTools.analyzeCustomerChurnRisk(memoryId, startDate, endDate, text, keyword, limit);
-        }
-        if (containsAny(text, "鍥炴", "鏀舵", "鎶ヤ环")
-                && containsAny(text, "寤鸿", "绛栫暐", "浼樺寲", "鏂规")) {
-            return salesAgentTools.suggestCollectionAndQuotationStrategy(
-                    memoryId, startDate, endDate, text, keyword, limit, shouldPrioritizeHighRisk(text));
-        }
-        if (containsAny(text, "鎸囨爣", "缁熻", "鐪嬫澘", "鎬昏", "缁忚惀鍒嗘瀽")) {
-            return salesAgentTools.getSalesDashboard(memoryId, startDate, endDate, text);
-        }
-        if (containsAny(text, "瀹㈡埛妗f", "绉佹捣", "鍏捣", "瀹㈡埛姹�")) {
-            return salesAgentTools.listCustomerProfiles(memoryId, extractSeaType(text), keyword, limit);
-        }
-        if (containsAny(text, "閿�鍞姤浠�", "鎶ヤ环鍗�", "鎶ヤ环", "璇环")) {
-            return salesAgentTools.listSalesQuotations(memoryId, keyword, startDate, endDate, limit);
-        }
-        if (containsAny(text, "閿�鍞��璐�", "閫�璐�", "閫�娆�")) {
-            return salesAgentTools.listSalesReturns(memoryId, startDate, endDate, keyword, limit);
-        }
-        if (containsAny(text, "瀹㈡埛寰�鏉�", "寰�鏉�", "鍥炴", "搴旀敹", "鏉ユ", "鏀舵鏄庣粏")) {
-            return salesAgentTools.listCustomerInteractions(memoryId, keyword, startDate, endDate, limit);
-        }
-        if (containsAny(text, "鍙戣揣鍙拌处", "鍙戣揣", "鐗╂祦", "蹇��", "杩愯緭")) {
-            return salesAgentTools.listShippingLedgers(memoryId, keyword, startDate, endDate, limit);
-        }
-        if (containsAny(text, "閿�鍞彴璐�", "閿�鍞悎鍚�", "閿�鍞鍗�", "鍚堝悓鍙拌处", "璁㈠崟鍙拌处")) {
-            return salesAgentTools.listSalesLedgers(memoryId, keyword, startDate, endDate, limit);
-        }
-        return null;
-    }
-
-    private String tryExecuteQuickPrompt(String memoryId, String text) {
-        String normalized = normalizeForMatch(text);
-        if ("鏌ヨ绉佹捣瀹㈡埛妗f鍓�10鏉�".equals(normalized)) {
-            return salesAgentTools.listCustomerProfiles(memoryId, "private", null, 10);
-        }
-        if ("鏌ヨ鍏捣瀹㈡埛妗f".equals(normalized)) {
-            return salesAgentTools.listCustomerProfiles(memoryId, "public", null, 10);
-        }
-        if ("鏌ヨ鏈湀閿�鍞姤浠�".equals(normalized)) {
-            DateRange range = monthRange();
-            return salesAgentTools.listSalesQuotations(memoryId, null, range.startDate(), range.endDate(), 10);
-        }
-        if ("鏌ヨ鏈湀閿�鍞彴璐�".equals(normalized)) {
-            DateRange range = monthRange();
-            return salesAgentTools.listSalesLedgers(memoryId, null, range.startDate(), range.endDate(), 10);
-        }
-        if ("鏌ヨ杩�30澶╅攢鍞��璐�".equals(normalized)) {
-            DateRange range = recentDaysRange(30);
-            return salesAgentTools.listSalesReturns(memoryId, range.startDate(), range.endDate(), null, 10);
-        }
-        if ("鏌ヨ杩�30澶╁鎴峰洖娆惧線鏉�".equals(normalized)) {
-            DateRange range = recentDaysRange(30);
-            return salesAgentTools.listCustomerInteractions(memoryId, null, range.startDate(), range.endDate(), 10);
-        }
-        if ("鏌ヨ鏈湀鍙戣揣鍙拌处".equals(normalized)) {
-            DateRange range = monthRange();
-            return salesAgentTools.listShippingLedgers(memoryId, null, range.startDate(), range.endDate(), 10);
-        }
-        if ("鏌ョ湅閿�鍞寚鏍囩粺璁�".equals(normalized)) {
-            return salesAgentTools.getSalesDashboard(memoryId, null, null, "鏈湀");
-        }
-        if ("甯垜鍋氬鎴锋祦澶遍闄╁垎鏋愯繎30澶╁墠20鏉�".equals(normalized)) {
-            DateRange range = recentDaysRange(30);
-            return salesAgentTools.analyzeCustomerChurnRisk(memoryId, range.startDate(), range.endDate(), "杩�30澶�", null, 20);
-        }
-        if ("鐢熸垚鍥炴涓庢姤浠风瓥鐣ュ缓璁紭鍏堥珮椋庨櫓瀹㈡埛".equals(normalized)) {
-            DateRange range = recentDaysRange(30);
-            return salesAgentTools.suggestCollectionAndQuotationStrategy(memoryId, range.startDate(), range.endDate(), "杩�30澶�", null, 10, true);
-        }
-        return null;
-    }
-
-    private boolean containsAny(String text, String... keywords) {
-        for (String keyword : keywords) {
-            if (text.contains(keyword)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private String extractSeaType(String text) {
-        if (text.contains("鍏捣")) {
-            return "public";
-        }
-        if (text.contains("绉佹捣")) {
-            return "private";
-        }
-        return null;
-    }
-
-    private Integer extractLimit(String text) {
-        Matcher matcher = LIMIT_PATTERN.matcher(text);
-        return matcher.find() ? Integer.parseInt(matcher.group(2)) : 10;
-    }
-
-    private DateRange extractDateRange(String text) {
-        Matcher matcher = DATE_PATTERN.matcher(text);
-        if (matcher.find()) {
-            String first = matcher.group(1);
-            String second = matcher.find() ? matcher.group(1) : first;
-            return buildDateRange(first, second);
-        }
-        if (text.contains("鏈湀")) {
-            return monthRange();
-        }
-        if (text.contains("涓婃湀")) {
-            return lastMonthRange();
-        }
-        if (text.contains("鏈勾") || text.contains("浠婂勾")) {
-            return yearRange();
-        }
-        Matcher relativeDayMatcher = RELATIVE_DAY_PATTERN.matcher(text);
-        if (relativeDayMatcher.find()) {
-            int days = Integer.parseInt(relativeDayMatcher.group(2));
-            return recentDaysRange(days);
-        }
-        return new DateRange(null, null);
-    }
-
-    private DateRange buildDateRange(String start, String end) {
-        LocalDate startDate = parseDate(start);
-        LocalDate endDate = parseDate(end);
-        if (startDate == null || endDate == null) {
-            return new DateRange(null, null);
-        }
-        if (startDate.isAfter(endDate)) {
-            LocalDate temp = startDate;
-            startDate = endDate;
-            endDate = temp;
-        }
-        return new DateRange(formatDate(startDate), formatDate(endDate));
-    }
-
-    private DateRange recentDaysRange(int days) {
-        LocalDate end = LocalDate.now();
-        int safeDays = Math.max(days, 1);
-        LocalDate start = end.minusDays(safeDays - 1L);
-        return new DateRange(formatDate(start), formatDate(end));
-    }
-
-    private DateRange monthRange() {
-        LocalDate today = LocalDate.now();
-        return new DateRange(formatDate(today.withDayOfMonth(1)), formatDate(today));
-    }
-
-    private DateRange lastMonthRange() {
-        YearMonth lastMonth = YearMonth.now().minusMonths(1);
-        return new DateRange(formatDate(lastMonth.atDay(1)), formatDate(lastMonth.atEndOfMonth()));
-    }
-
-    private DateRange yearRange() {
-        LocalDate today = LocalDate.now();
-        return new DateRange(formatDate(today.withDayOfYear(1)), formatDate(today));
-    }
-
-    private LocalDate parseDate(String text) {
-        try {
-            return LocalDate.parse(text, DATE_FMT);
-        } catch (Exception ignored) {
-            return null;
-        }
-    }
-
-    private String formatDate(LocalDate date) {
-        return date == null ? null : date.format(DATE_FMT);
-    }
-
-    private String normalizeForMatch(String text) {
-        if (!StringUtils.hasText(text)) {
-            return "";
-        }
-        return text.replace("锛�", "")
-                .replace(",", "")
-                .replace("銆�", "")
-                .replace(".", "")
-                .replace("锛�", "")
-                .replace("!", "")
-                .replace("锛�", "")
-                .replace("?", "")
-                .replace("锛�", "")
-                .replace(":", "")
-                .replace("锛�", "")
-                .replace(";", "")
-                .replace(" ", "")
-                .trim();
-    }
-
-    private Boolean shouldPrioritizeHighRisk(String text) {
-        return containsAny(text, "浼樺厛楂橀闄�", "楂橀闄╁鎴�", "楂橀闄�");
-    }
-
-    private String extractKeyword(String text) {
-        String cleaned = text
-                .replace("鏌ヨ", "")
-                .replace("鏌ョ湅", "")
-                .replace("鐪嬩笅", "")
-                .replace("鐪嬬湅", "")
-                .replace("甯垜", "")
-                .replace("璇�", "")
-                .replace("涓�涓�", "")
-                .replace("閿�鍞�", "")
-                .replace("瀹㈡埛妗f", "")
-                .replace("鎶ヤ环鍗�", "")
-                .replace("閿�鍞姤浠�", "")
-                .replace("閿�鍞彴璐�", "")
-                .replace("鍙戣揣鍙拌处", "")
-                .replace("瀹㈡埛寰�鏉�", "")
-                .replace("閿�鍞��璐�", "")
-                .replace("鍓�10鏉�", "")
-                .replace("鏈�杩�10鏉�", "")
-                .replace("鍓�20鏉�", "")
-                .replace("鏈�杩�20鏉�", "")
-                .replace("杩�30澶�", "")
-                .replace("鏈湀", "")
-                .replace("鏈勾", "")
-                .replace("浠婂勾", "")
-                .replace("鏉�", "")
-                .trim();
-        return cleaned.length() >= 2 ? cleaned : null;
-    }
-
-    private record DateRange(String startDate, String endDate) {
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/assistant/SeparateChatAssistant.java b/src/main/java/com/ruoyi/ai/assistant/SeparateChatAssistant.java
deleted file mode 100644
index fa36ad5..0000000
--- a/src/main/java/com/ruoyi/ai/assistant/SeparateChatAssistant.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.ruoyi.ai.assistant;
-
-import dev.langchain4j.service.MemoryId;
-import dev.langchain4j.service.SystemMessage;
-import dev.langchain4j.service.UserMessage;
-import dev.langchain4j.service.V;
-import dev.langchain4j.service.spring.AiService;
-import dev.langchain4j.service.spring.AiServiceWiringMode;
-
-/**
- * @author :yys
- * @date : 2025/5/2 19:35
- */
-@AiService(
-        wiringMode = AiServiceWiringMode.EXPLICIT,
-        chatModel = "qwenChatModel",
-        chatMemoryProvider = "chatMemoryProvider"
-)
-public interface SeparateChatAssistant {
-
-    @SystemMessage(fromResource = "my-prompt-template.txt")//绯荤粺娑堟伅鎻愮ず璇�
-    String chat(@MemoryId String memoryId, @UserMessage String userMessage);
-
-    @UserMessage("浣犳槸鎴戠殑濂芥湅鍙嬶紝璇风敤绮よ鍥炵瓟闂銆倇{message}}")
-    String chat2(@MemoryId String memoryId, @V("message") String userMessage);
-
-    @SystemMessage(fromResource = "my-prompt-template3.txt")
-    String chat3(
-            @MemoryId String memoryId,
-            @UserMessage String userMessage,
-            @V("username") String username,
-            @V("age") int age
-    );
-
-}
diff --git a/src/main/java/com/ruoyi/ai/bean/ChatForm.java b/src/main/java/com/ruoyi/ai/bean/ChatForm.java
deleted file mode 100644
index 60d1a6e..0000000
--- a/src/main/java/com/ruoyi/ai/bean/ChatForm.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.ruoyi.ai.bean;
-
-import lombok.Data;
-
-/**
- * @author :yys
- * @date : 2025/5/2 20:03
- */
-@Data
-public class ChatForm {
-
-    private String memoryId;//瀵硅瘽id
-    private String message;//鐢ㄦ埛闂
-
-}
diff --git a/src/main/java/com/ruoyi/ai/bean/PurchaseAiConfirmRequest.java b/src/main/java/com/ruoyi/ai/bean/PurchaseAiConfirmRequest.java
deleted file mode 100644
index f727981..0000000
--- a/src/main/java/com/ruoyi/ai/bean/PurchaseAiConfirmRequest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.ruoyi.ai.bean;
-
-import java.util.Map;
-
-public class PurchaseAiConfirmRequest {
-
-    private String businessType;
-
-    private Map<String, Object> payload;
-
-    public String getBusinessType() {
-        return businessType;
-    }
-
-    public void setBusinessType(String businessType) {
-        this.businessType = businessType;
-    }
-
-    public Map<String, Object> getPayload() {
-        return payload;
-    }
-
-    public void setPayload(Map<String, Object> payload) {
-        this.payload = payload;
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/config/ApproveTodoAgentConfig.java b/src/main/java/com/ruoyi/ai/config/ApproveTodoAgentConfig.java
deleted file mode 100644
index 61cc0dd..0000000
--- a/src/main/java/com/ruoyi/ai/config/ApproveTodoAgentConfig.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.ai.config;
-
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import dev.langchain4j.memory.chat.ChatMemoryProvider;
-import dev.langchain4j.memory.chat.MessageWindowChatMemory;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class ApproveTodoAgentConfig {
-
-    @Bean
-    ChatMemoryProvider chatMemoryProviderApproveTodo(MongoChatMemoryStore mongoChatMemoryStore) {
-        return memoryId -> MessageWindowChatMemory.builder()
-                .id(memoryId)
-                .maxMessages(30)
-                .chatMemoryStore(mongoChatMemoryStore)
-                .build();
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/config/EmbeddingStoreConfig.java b/src/main/java/com/ruoyi/ai/config/EmbeddingStoreConfig.java
deleted file mode 100644
index eaa487c..0000000
--- a/src/main/java/com/ruoyi/ai/config/EmbeddingStoreConfig.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.ruoyi.ai.config;
-
-import dev.langchain4j.data.segment.TextSegment;
-import dev.langchain4j.model.embedding.EmbeddingModel;
-import dev.langchain4j.store.embedding.EmbeddingStore;
-import dev.langchain4j.store.embedding.pinecone.PineconeEmbeddingStore;
-import dev.langchain4j.store.embedding.pinecone.PineconeServerlessIndexConfig;
-import io.pinecone.clients.Index;
-import io.pinecone.clients.Pinecone;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * 鍚戦噺瀛樺偍閰嶇疆
- */
-@Configuration
-public class EmbeddingStoreConfig {
-
-    @Value("${pinecone.api-key:pcsk_4SJLnh_tNB3wSLJU8tc4E5P28PcXX8eCLdURqZpVhg1FMV8CRYxjneWdzqRdB5Ftqooi9}")
-    private String pineconeApiKey;
-
-    @Value("${pinecone.index:xiaozhi-index}")
-    private String indexName;
-
-    @Value("${pinecone.namespace:knowledge-base}")
-    private String namespace;
-
-    @Bean
-    public Pinecone pinecone() {
-        return new Pinecone.Builder(pineconeApiKey).build();
-    }
-
-    @Bean
-    public Index pineconeIndex(Pinecone pinecone) {
-        return pinecone.getIndexConnection(indexName);
-    }
-
-    @Bean
-    public EmbeddingStore<TextSegment> embeddingStore(EmbeddingModel embeddingModel) {
-        return PineconeEmbeddingStore.builder()
-                .apiKey(pineconeApiKey)
-                .index(indexName)
-                .nameSpace(namespace)
-                .createIndex(PineconeServerlessIndexConfig.builder()
-                        .cloud("AWS")
-                        .region("us-east-1")
-                        .dimension(embeddingModel.dimension())
-                        .build())
-                .build();
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/ai/config/FinancialAgentConfig.java b/src/main/java/com/ruoyi/ai/config/FinancialAgentConfig.java
deleted file mode 100644
index 0706e74..0000000
--- a/src/main/java/com/ruoyi/ai/config/FinancialAgentConfig.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.ai.config;
-
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import dev.langchain4j.memory.chat.ChatMemoryProvider;
-import dev.langchain4j.memory.chat.MessageWindowChatMemory;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class FinancialAgentConfig {
-
-    @Bean
-    ChatMemoryProvider chatMemoryProviderFinancial(MongoChatMemoryStore mongoChatMemoryStore) {
-        return memoryId -> MessageWindowChatMemory.builder()
-                .id(memoryId)
-                .maxMessages(40)
-                .chatMemoryStore(mongoChatMemoryStore)
-                .build();
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/config/ManufacturingAgentConfig.java b/src/main/java/com/ruoyi/ai/config/ManufacturingAgentConfig.java
deleted file mode 100644
index 79aa222..0000000
--- a/src/main/java/com/ruoyi/ai/config/ManufacturingAgentConfig.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.ai.config;
-
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import dev.langchain4j.memory.chat.ChatMemoryProvider;
-import dev.langchain4j.memory.chat.MessageWindowChatMemory;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class ManufacturingAgentConfig {
-
-    @Bean
-    ChatMemoryProvider chatMemoryProviderManufacturing(MongoChatMemoryStore mongoChatMemoryStore) {
-        return memoryId -> MessageWindowChatMemory.builder()
-                .id(memoryId)
-                .maxMessages(30)
-                .chatMemoryStore(mongoChatMemoryStore)
-                .build();
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/config/PurchaseAgentConfig.java b/src/main/java/com/ruoyi/ai/config/PurchaseAgentConfig.java
deleted file mode 100644
index 62061ee..0000000
--- a/src/main/java/com/ruoyi/ai/config/PurchaseAgentConfig.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.ruoyi.ai.config;
-
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import dev.langchain4j.community.model.dashscope.QwenStreamingChatModel;
-import dev.langchain4j.memory.chat.ChatMemoryProvider;
-import dev.langchain4j.memory.chat.MessageWindowChatMemory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class PurchaseAgentConfig {
-
-    @Bean
-    ChatMemoryProvider chatMemoryProviderPurchase(MongoChatMemoryStore mongoChatMemoryStore) {
-        return memoryId -> MessageWindowChatMemory.builder()
-                .id(memoryId)
-                .maxMessages(30)
-                .chatMemoryStore(mongoChatMemoryStore)
-                .build();
-    }
-
-    @Bean("purchaseVisionStreamingChatModel")
-    QwenStreamingChatModel purchaseVisionStreamingChatModel(
-            @Value("${langchain4j.community.dashscope.streaming-chat-model.api-key}") String apiKey) {
-        return QwenStreamingChatModel.builder()
-                .apiKey(apiKey)
-                .modelName("qwen-vl-max")
-                .isMultimodalModel(true)
-                .build();
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/config/SalesAgentConfig.java b/src/main/java/com/ruoyi/ai/config/SalesAgentConfig.java
deleted file mode 100644
index aed3104..0000000
--- a/src/main/java/com/ruoyi/ai/config/SalesAgentConfig.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.ruoyi.ai.config;
-
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import dev.langchain4j.memory.chat.ChatMemoryProvider;
-import dev.langchain4j.memory.chat.MessageWindowChatMemory;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class SalesAgentConfig {
-
-    @Bean
-    ChatMemoryProvider chatMemoryProviderSales(MongoChatMemoryStore mongoChatMemoryStore) {
-        return memoryId -> MessageWindowChatMemory.builder()
-                .id(memoryId)
-                .maxMessages(30)
-                .chatMemoryStore(mongoChatMemoryStore)
-                .build();
-    }
-}
-
diff --git a/src/main/java/com/ruoyi/ai/config/SeparateChatAssistantConfig.java b/src/main/java/com/ruoyi/ai/config/SeparateChatAssistantConfig.java
deleted file mode 100644
index 1927843..0000000
--- a/src/main/java/com/ruoyi/ai/config/SeparateChatAssistantConfig.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.ruoyi.ai.config;
-
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import dev.langchain4j.memory.chat.ChatMemoryProvider;
-import dev.langchain4j.memory.chat.MessageWindowChatMemory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * @author :yys
- * @date : 2025/5/2 19:20
- */
-@Configuration
-public class SeparateChatAssistantConfig {
-    //娉ㄥ叆鎸佷箙鍖栧璞�
-    @Autowired
-    private MongoChatMemoryStore mongoChatMemoryStore;
-
-    @Bean
-    ChatMemoryProvider chatMemoryProvider() {
-        return memoryId -> MessageWindowChatMemory.builder()
-                .id(memoryId)
-                .maxMessages(10)
-                .chatMemoryStore(mongoChatMemoryStore)//閰嶇疆鎸佷箙鍖栧璞�
-                .build();
-    }
-
-}
diff --git a/src/main/java/com/ruoyi/ai/config/XiaozhiAgentConfig.java b/src/main/java/com/ruoyi/ai/config/XiaozhiAgentConfig.java
deleted file mode 100644
index 27e5a6b..0000000
--- a/src/main/java/com/ruoyi/ai/config/XiaozhiAgentConfig.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.ruoyi.ai.config;
-
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import dev.langchain4j.memory.chat.ChatMemoryProvider;
-import dev.langchain4j.memory.chat.MessageWindowChatMemory;
-import dev.langchain4j.model.embedding.EmbeddingModel;
-import dev.langchain4j.rag.content.retriever.ContentRetriever;
-import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
-import dev.langchain4j.store.embedding.EmbeddingStore;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * @author :yys
- * @date : 2025/5/2 20:01
- */
-@Configuration
-public class XiaozhiAgentConfig {
-
-    @Autowired
-    private MongoChatMemoryStore mongoChatMemoryStore;
-
-    @Autowired
-    private EmbeddingStore embeddingStore;
-    @Autowired
-    private EmbeddingModel embeddingModel;
-
-//    @Value("${knowledge.one}")
-//    private String one;
-//
-//    @Value("${knowledge.two}")
-//    private String two;
-//
-//    @Value("${knowledge.three}")
-//    private String three;
-
-    @Bean
-    ChatMemoryProvider chatMemoryProviderXiaozhi() {
-        return memoryId -> MessageWindowChatMemory.builder()
-                .id(memoryId)
-                .maxMessages(20)
-                .chatMemoryStore(mongoChatMemoryStore)
-                .build();
-    }
-
-//    @Bean
-//    ContentRetriever contentRetrieverXiaozhi() {
-//        //浣跨敤FileSystemDocumentLoader璇诲彇鎸囧畾鐩綍涓嬬殑鐭ヨ瘑搴撴枃妗�
-//        //骞朵娇鐢ㄩ粯璁ょ殑鏂囨。瑙f瀽鍣ㄥ鏂囨。杩涜瑙f瀽
-//        Document document1 = FileSystemDocumentLoader.loadDocument(one);
-////        Document document2 = FileSystemDocumentLoader.loadDocument(two);
-////        Document document3 = FileSystemDocumentLoader.loadDocument(three);
-////        List<Document> documents = Arrays.asList(document1, document2, document3);
-//
-//        List<Document> documents = Collections.singletonList(document1);
-////         2. 灏嗘暟鎹簱鏁版嵁杞负LangChain4j鐨凞ocument瀵硅薄
-////        List<Document> documents = new ArrayList<>();
-//
-//        //浣跨敤鍐呭瓨鍚戦噺瀛樺偍
-//        InMemoryEmbeddingStore<TextSegment> inMemoryEmbeddingStore = new InMemoryEmbeddingStore<>();
-//        //浣跨敤榛樿鐨勬枃妗e垎鍓插櫒
-//        EmbeddingStoreIngestor.builder()
-//                .embeddingModel(embeddingModel)
-//                .embeddingStore(inMemoryEmbeddingStore)
-//                .build()
-//                .ingest(documents);
-//        //浠庡祵鍏ュ瓨鍌紙EmbeddingStore锛夐噷妫�绱㈠拰鏌ヨ鍐呭鐩稿叧鐨勪俊鎭�
-//        return EmbeddingStoreContentRetriever.builder()
-//                .embeddingModel(embeddingModel)
-//                .embeddingStore(inMemoryEmbeddingStore)
-//                .build();
-//    }
-
-    @Bean
-    ContentRetriever contentRetrieverXiaozhiPincone() {
-        // 鍒涘缓涓�涓� EmbeddingStoreContentRetriever 瀵硅薄锛岀敤浜庝粠宓屽叆瀛樺偍涓绱㈠唴瀹�
-        return EmbeddingStoreContentRetriever
-                .builder()
-                // 璁剧疆鐢ㄤ簬鐢熸垚宓屽叆鍚戦噺鐨勫祵鍏ユā鍨�
-                .embeddingModel(embeddingModel)
-                // 鎸囧畾瑕佷娇鐢ㄧ殑宓屽叆瀛樺偍
-                .embeddingStore(embeddingStore)
-                // 璁剧疆鏈�澶ф绱㈢粨鏋滄暟閲忥紝杩欓噷琛ㄧず鏈�澶氳繑鍥� 1 鏉″尮閰嶇粨鏋�
-                .maxResults(1)
-                // 璁剧疆鏈�灏忓緱鍒嗛槇鍊硷紝鍙湁寰楀垎澶т簬绛変簬 0.8 鐨勭粨鏋滄墠浼氳杩斿洖
-                .minScore(0.8)
-                // 鏋勫缓鏈�缁堢殑 EmbeddingStoreContentRetriever 瀹炰緥
-                .build();
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/context/AiSessionUserContext.java b/src/main/java/com/ruoyi/ai/context/AiSessionUserContext.java
deleted file mode 100644
index 5251561..0000000
--- a/src/main/java/com/ruoyi/ai/context/AiSessionUserContext.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.ruoyi.ai.context;
-
-import com.ruoyi.framework.security.LoginUser;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-import java.time.Duration;
-import java.time.Instant;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-@Component
-public class AiSessionUserContext {
-
-    private final Map<String, LoginUser> loginUserByMemoryId = new ConcurrentHashMap<>();
-    private final Map<String, Instant> lastAccessTimeByMemoryId = new ConcurrentHashMap<>();
-    private static final Duration SESSION_TIMEOUT = Duration.ofHours(24);
-
-    public void bind(String memoryId, LoginUser loginUser) {
-        if (!StringUtils.hasText(memoryId) || loginUser == null) {
-            return;
-        }
-        loginUserByMemoryId.put(memoryId, loginUser);
-        lastAccessTimeByMemoryId.put(memoryId, Instant.now());
-    }
-
-    public LoginUser get(String memoryId) {
-        if (!StringUtils.hasText(memoryId)) {
-            return null;
-        }
-        if (isExpired(memoryId)) {
-            remove(memoryId);
-            return null;
-        }
-        lastAccessTimeByMemoryId.put(memoryId, Instant.now());
-        return loginUserByMemoryId.get(memoryId);
-    }
-
-    public void remove(String memoryId) {
-        if (!StringUtils.hasText(memoryId)) {
-            return;
-        }
-        loginUserByMemoryId.remove(memoryId);
-        lastAccessTimeByMemoryId.remove(memoryId);
-    }
-
-    public void cleanExpiredSessions() {
-        Instant now = Instant.now();
-        lastAccessTimeByMemoryId.entrySet().removeIf(entry -> {
-            boolean expired = Duration.between(entry.getValue(), now).compareTo(SESSION_TIMEOUT) > 0;
-            if (expired) {
-                loginUserByMemoryId.remove(entry.getKey());
-            }
-            return expired;
-        });
-    }
-
-    private boolean isExpired(String memoryId) {
-        Instant lastAccess = lastAccessTimeByMemoryId.get(memoryId);
-        if (lastAccess == null) {
-            return true;
-        }
-        return Duration.between(lastAccess, Instant.now()).compareTo(SESSION_TIMEOUT) > 0;
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/controller/FinancialAiController.java b/src/main/java/com/ruoyi/ai/controller/FinancialAiController.java
deleted file mode 100644
index 9465d5a..0000000
--- a/src/main/java/com/ruoyi/ai/controller/FinancialAiController.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package com.ruoyi.ai.controller;
-
-import com.ruoyi.ai.assistant.FinancialAgent;
-import com.ruoyi.ai.assistant.FinancialIntentExecutor;
-import com.ruoyi.ai.bean.ChatForm;
-import com.ruoyi.ai.context.AiSessionUserContext;
-import com.ruoyi.ai.service.AiChatSessionService;
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import dev.langchain4j.data.message.AiMessage;
-import dev.langchain4j.data.message.UserMessage;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import reactor.core.publisher.Flux;
-
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.List;
-
-@Tag(name = "璐㈠姟鏅鸿兘浣�")
-@RestController
-@RequestMapping("/financial-ai")
-public class FinancialAiController extends BaseController {
-
-    private static final DateTimeFormatter CURRENT_DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final ZoneId CHINA_ZONE_ID = ZoneId.of("Asia/Shanghai");
-
-    private final FinancialAgent financialAgent;
-    private final FinancialIntentExecutor financialIntentExecutor;
-    private final AiSessionUserContext aiSessionUserContext;
-    private final MongoChatMemoryStore mongoChatMemoryStore;
-    private final AiChatSessionService aiChatSessionService;
-
-    public FinancialAiController(FinancialAgent financialAgent,
-                                 FinancialIntentExecutor financialIntentExecutor,
-                                 AiSessionUserContext aiSessionUserContext,
-                                 MongoChatMemoryStore mongoChatMemoryStore,
-                                 AiChatSessionService aiChatSessionService) {
-        this.financialAgent = financialAgent;
-        this.financialIntentExecutor = financialIntentExecutor;
-        this.aiSessionUserContext = aiSessionUserContext;
-        this.mongoChatMemoryStore = mongoChatMemoryStore;
-        this.aiChatSessionService = aiChatSessionService;
-    }
-
-    @Operation(summary = "璐㈠姟鏅鸿兘浣撳璇�")
-    @PostMapping(value = "/chat", produces = "text/stream;charset=utf-8")
-    public Flux<String> chat(@RequestBody ChatForm chatForm) {
-        if (!StringUtils.hasText(chatForm.getMemoryId())) {
-            return Flux.just("memoryId涓嶈兘涓虹┖");
-        }
-        if (!StringUtils.hasText(chatForm.getMessage())) {
-            return Flux.just("message涓嶈兘涓虹┖");
-        }
-
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        String memoryId = chatForm.getMemoryId();
-        String userMessage = chatForm.getMessage();
-
-        aiSessionUserContext.bind(memoryId, loginUser);
-        aiChatSessionService.touchSession(memoryId, loginUser, userMessage);
-
-        String directResponse = financialIntentExecutor.tryExecute(memoryId, userMessage);
-        if (StringUtils.isNotEmpty(directResponse)) {
-            mongoChatMemoryStore.appendMessages(
-                    memoryId,
-                    List.of(UserMessage.from(userMessage), AiMessage.from(directResponse))
-            );
-            aiChatSessionService.refreshSessionStats(memoryId, loginUser);
-            return Flux.just(directResponse);
-        }
-
-        if (isBusinessDataIntent(userMessage)) {
-            String noGuessResponse = "鏈瘑鍒埌鍙墽琛岀殑鏁版嵁鏌ヨ鏉′欢銆備负淇濊瘉缁撴灉鍑嗙‘锛屽綋鍓嶄笉浼氭帹娴嬫垨缂栭�犳暟鎹紝璇疯ˉ鍏呮槑纭椂闂磋寖鍥淬�佸鎴枫�佷緵搴斿晢鎴栧崟鍙峰悗鍐嶆煡璇€��";
-            mongoChatMemoryStore.appendMessages(
-                    memoryId,
-                    List.of(UserMessage.from(userMessage), AiMessage.from(noGuessResponse))
-            );
-            aiChatSessionService.refreshSessionStats(memoryId, loginUser);
-            return Flux.just(noGuessResponse);
-        }
-
-        return financialAgent.chat(memoryId, userMessage, currentDateForPrompt())
-                .doOnComplete(() -> aiChatSessionService.refreshSessionStats(memoryId, loginUser))
-                .doOnError(ex -> aiChatSessionService.refreshSessionStats(memoryId, loginUser));
-    }
-
-    @Operation(summary = "璐㈠姟鏅鸿兘浣撲細璇濆垪琛�")
-    @GetMapping("/history/sessions")
-    public AjaxResult listSessions() {
-        return success(aiChatSessionService.listCurrentUserSessions(SecurityUtils.getLoginUser()));
-    }
-
-    @Operation(summary = "璐㈠姟鏅鸿兘浣撲細璇濇秷鎭�")
-    @GetMapping("/history/messages/{memoryId}")
-    public AjaxResult listMessages(@PathVariable String memoryId) {
-        return success(aiChatSessionService.listCurrentUserMessages(memoryId, SecurityUtils.getLoginUser()));
-    }
-
-    @Operation(summary = "鍒犻櫎璐㈠姟鏅鸿兘浣撲細璇�")
-    @DeleteMapping("/history/{memoryId}")
-    public AjaxResult deleteSession(@PathVariable String memoryId) {
-        aiSessionUserContext.remove(memoryId);
-        return toAjax(aiChatSessionService.deleteCurrentUserSession(memoryId, SecurityUtils.getLoginUser()));
-    }
-
-    private String currentDateForPrompt() {
-        return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT);
-    }
-
-    private boolean isBusinessDataIntent(String message) {
-        if (!StringUtils.hasText(message)) {
-            return false;
-        }
-        String text = message.trim();
-        return containsAny(text,
-                "鏌ヨ", "鏌ョ湅", "缁熻", "鍒嗘瀽", "寤鸿", "鎴愭湰鏍哥畻", "浜у搧鎴愭湰", "宸ュ簭鎴愭湰",
-                "璁㈠崟鍒╂鼎", "浜忔崯璁㈠崟", "浣庡埄娑�", "搴撳瓨璧勯噾", "搴撳瓨绉帇", "鍛嗘粸搴撳瓨",
-                "鐜伴噾娴�", "鍥炴椋庨櫓", "浠樻鍘嬪姏", "璧勯噾缂哄彛", "搴旀敹", "搴斾粯",
-                "寮傚父棰勮", "缁忚惀寮傚父", "椋庨櫓棰勮", "椹鹃┒鑸�", "缁忚惀鐪嬫澘", "缁忚惀鎬昏",
-                "鏃ユ姤", "鍛ㄦ姤", "缁忚惀鎶ュ憡", "鍒嗘瀽鎶ュ憡", "涓氳储铻嶅悎", "鍙e緞", "鎸囨爣瑙i噴");
-    }
-
-    private boolean containsAny(String text, String... keywords) {
-        for (String keyword : keywords) {
-            if (text.contains(keyword)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/controller/KnowledgeChatController.java b/src/main/java/com/ruoyi/ai/controller/KnowledgeChatController.java
deleted file mode 100644
index 2738439..0000000
--- a/src/main/java/com/ruoyi/ai/controller/KnowledgeChatController.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.ruoyi.ai.controller;
-
-import com.ruoyi.ai.assistant.KnowledgeChatAgent;
-import com.ruoyi.ai.dto.KnowledgeChatRequest;
-import com.ruoyi.ai.service.KnowledgeRagService;
-import com.ruoyi.approve.pojo.KnowledgeBase;
-import com.ruoyi.approve.service.KnowledgeBaseService;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.*;
-import reactor.core.publisher.Flux;
-
-import java.util.List;
-
-/**
- * 鐭ヨ瘑搴撻棶绛擟ontroller
- */
-@Slf4j
-@RestController
-@RequestMapping("/ai/knowledge")
-@RequiredArgsConstructor
-@Tag(name = "鐭ヨ瘑搴撻棶绛�")
-public class KnowledgeChatController {
-
-    private final KnowledgeChatAgent knowledgeChatAgent;
-    private final KnowledgeRagService knowledgeRagService;
-    private final KnowledgeBaseService knowledgeBaseService;
-
-    /**
-     * 鐭ヨ瘑搴撻棶绛旓紙娴佸紡杩斿洖锛�
-     */
-    @PostMapping(value = "/chat", produces = "text/stream;charset=utf-8")
-    @Operation(summary = "鐭ヨ瘑搴撻棶绛�")
-    public Flux<String> chat(@RequestBody KnowledgeChatRequest request) {
-        if (request.getKnowledgeBaseId() == null) {
-            return Flux.just("鐭ヨ瘑搴揑D涓嶈兘涓虹┖");
-        }
-        if (!StringUtils.hasText(request.getMemoryId())) {
-            return Flux.just("浼氳瘽ID涓嶈兘涓虹┖");
-        }
-        if (!StringUtils.hasText(request.getQuestion())) {
-            return Flux.just("闂涓嶈兘涓虹┖");
-        }
-
-        KnowledgeBase knowledgeBase = knowledgeBaseService.getById(request.getKnowledgeBaseId());
-        if (knowledgeBase == null) {
-            return Flux.just("鐭ヨ瘑搴撲笉瀛樺湪");
-        }
-
-        String namespace = "kb-" + request.getKnowledgeBaseId();
-
-        List<String> relevantContents = knowledgeRagService.searchRelevantContent(
-                namespace, request.getQuestion(), 5);
-
-        if (relevantContents.isEmpty()) {
-            return Flux.just("鐭ヨ瘑搴撲腑鏈壘鍒扮浉鍏冲唴瀹癸紝璇峰厛涓婁紶鐩稿叧鏂囨。銆�");
-        }
-
-        StringBuilder contextBuilder = new StringBuilder();
-        contextBuilder.append("浠ヤ笅鏄粠鐭ヨ瘑搴撲腑妫�绱㈠埌鐨勭浉鍏冲唴瀹癸細\n\n");
-        for (int i = 0; i < relevantContents.size(); i++) {
-            contextBuilder.append("銆愬唴瀹�").append(i + 1).append("銆慭n");
-            contextBuilder.append(relevantContents.get(i)).append("\n\n");
-        }
-        contextBuilder.append("---\n");
-        contextBuilder.append("璇峰熀浜庝互涓婄煡璇嗗簱鍐呭鍥炵瓟鐢ㄦ埛闂锛歕n");
-        contextBuilder.append(request.getQuestion());
-
-        return knowledgeChatAgent.chat(request.getMemoryId(), contextBuilder.toString());
-    }
-
-    /**
-     * 鐭ヨ瘑搴撳垪琛紙鐢ㄤ簬閫夋嫨鐭ヨ瘑搴擄級
-     */
-    @GetMapping("/list")
-    @Operation(summary = "鐭ヨ瘑搴撳垪琛�")
-    public AjaxResult listKnowledgeBases() {
-        List<KnowledgeBase> list = knowledgeBaseService.list();
-        return AjaxResult.success(list);
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java b/src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java
deleted file mode 100644
index 87eb418..0000000
--- a/src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.ruoyi.ai.controller;
-
-import com.ruoyi.ai.assistant.ManufacturingAgent;
-import com.ruoyi.ai.assistant.ManufacturingIntentExecutor;
-import com.ruoyi.ai.bean.ChatForm;
-import com.ruoyi.ai.context.AiSessionUserContext;
-import com.ruoyi.ai.service.AiChatSessionService;
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import dev.langchain4j.data.message.AiMessage;
-import dev.langchain4j.data.message.UserMessage;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import reactor.core.publisher.Flux;
-
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.List;
-
-@Tag(name = "鍒堕�犳櫤鑳藉姪鎵�")
-@RestController
-@RequestMapping("/manufacturing-ai")
-public class ManufacturingAiController extends BaseController {
-
-    private static final DateTimeFormatter CURRENT_DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final ZoneId CHINA_ZONE_ID = ZoneId.of("Asia/Shanghai");
-
-    private final ManufacturingAgent manufacturingAgent;
-    private final ManufacturingIntentExecutor manufacturingIntentExecutor;
-    private final AiSessionUserContext aiSessionUserContext;
-    private final MongoChatMemoryStore mongoChatMemoryStore;
-    private final AiChatSessionService aiChatSessionService;
-
-    public ManufacturingAiController(ManufacturingAgent manufacturingAgent,
-                                     ManufacturingIntentExecutor manufacturingIntentExecutor,
-                                     AiSessionUserContext aiSessionUserContext,
-                                     MongoChatMemoryStore mongoChatMemoryStore,
-                                     AiChatSessionService aiChatSessionService) {
-        this.manufacturingAgent = manufacturingAgent;
-        this.manufacturingIntentExecutor = manufacturingIntentExecutor;
-        this.aiSessionUserContext = aiSessionUserContext;
-        this.mongoChatMemoryStore = mongoChatMemoryStore;
-        this.aiChatSessionService = aiChatSessionService;
-    }
-
-    @Operation(summary = "鍒堕�犲璇�")
-    @PostMapping(value = "/chat", produces = "text/stream;charset=utf-8")
-    public Flux<String> chat(@RequestBody ChatForm chatForm) {
-        if (!StringUtils.hasText(chatForm.getMemoryId())) {
-            return Flux.just("memoryId涓嶈兘涓虹┖");
-        }
-        if (!StringUtils.hasText(chatForm.getMessage())) {
-            return Flux.just("message涓嶈兘涓虹┖");
-        }
-
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        String memoryId = chatForm.getMemoryId();
-        String userMessage = chatForm.getMessage();
-
-        aiSessionUserContext.bind(memoryId, loginUser);
-        aiChatSessionService.touchSession(memoryId, loginUser, userMessage);
-
-        String directResponse = manufacturingIntentExecutor.tryExecute(memoryId, userMessage);
-        if (StringUtils.isNotEmpty(directResponse)) {
-            mongoChatMemoryStore.appendMessages(
-                    memoryId,
-                    List.of(UserMessage.from(userMessage), AiMessage.from(directResponse))
-            );
-            aiChatSessionService.refreshSessionStats(memoryId, loginUser);
-            return Flux.just(directResponse);
-        }
-
-        return manufacturingAgent.chat(memoryId, userMessage, currentDateForPrompt())
-                .doOnComplete(() -> aiChatSessionService.refreshSessionStats(memoryId, loginUser))
-                .doOnError(ex -> aiChatSessionService.refreshSessionStats(memoryId, loginUser));
-    }
-
-    @Operation(summary = "鍒堕�犱細璇濆垪琛�")
-    @GetMapping("/history/sessions")
-    public AjaxResult listSessions() {
-        return success(aiChatSessionService.listCurrentUserSessions(SecurityUtils.getLoginUser()));
-    }
-
-    @Operation(summary = "鍒堕�犱細璇濇秷鎭�")
-    @GetMapping("/history/messages/{memoryId}")
-    public AjaxResult listMessages(@PathVariable String memoryId) {
-        return success(aiChatSessionService.listCurrentUserMessages(memoryId, SecurityUtils.getLoginUser()));
-    }
-
-    @Operation(summary = "鍒犻櫎鍒堕�犱細璇�")
-    @DeleteMapping("/history/{memoryId}")
-    public AjaxResult deleteSession(@PathVariable String memoryId) {
-        aiSessionUserContext.remove(memoryId);
-        return toAjax(aiChatSessionService.deleteCurrentUserSession(memoryId, SecurityUtils.getLoginUser()));
-    }
-
-    private String currentDateForPrompt() {
-        return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT);
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/controller/PurchaseAiController.java b/src/main/java/com/ruoyi/ai/controller/PurchaseAiController.java
deleted file mode 100644
index 158ea61..0000000
--- a/src/main/java/com/ruoyi/ai/controller/PurchaseAiController.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.ruoyi.ai.controller;
-
-import com.ruoyi.ai.bean.ChatForm;
-import com.ruoyi.ai.bean.PurchaseAiConfirmRequest;
-import com.ruoyi.ai.service.PurchaseAiService;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.multipart.MultipartFile;
-import reactor.core.publisher.Flux;
-
-@Tag(name = "閲囪喘鏅鸿兘浣�")
-@RestController
-@RequestMapping("/purchase-ai")
-public class PurchaseAiController extends BaseController {
-
-    private final PurchaseAiService purchaseAiService;
-
-    public PurchaseAiController(PurchaseAiService purchaseAiService) {
-        this.purchaseAiService = purchaseAiService;
-    }
-
-    @Operation(summary = "閲囪喘瀵硅瘽")
-    @PostMapping(value = "/chat", produces = "text/stream;charset=utf-8")
-    public Flux<String> chat(@RequestBody ChatForm chatForm) {
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        return purchaseAiService.chat(chatForm, loginUser);
-    }
-
-    @Operation(summary = "閲囪喘澶氭枃浠跺垎鏋�")
-    @PostMapping(value = "/analyze-files", consumes = "multipart/form-data", produces = "text/stream;charset=utf-8")
-    public Flux<String> analyzeFiles(@RequestParam("files") MultipartFile[] files,
-                                     @RequestParam(value = "message", required = false) String message,
-                                     @RequestParam(value = "memoryId", required = false) String memoryId) {
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        return purchaseAiService.analyzeFiles(files, message, memoryId, loginUser);
-    }
-
-    @Operation(summary = "閲囪喘澶氭枃浠跺垎鏋愮‘璁ゅ鐞�")
-    @PostMapping("/analyze-files/confirm")
-    public AjaxResult confirmAnalyzeResult(@RequestBody PurchaseAiConfirmRequest request) {
-        return purchaseAiService.confirmAnalyzeResult(request);
-    }
-
-    @Operation(summary = "閲囪喘浼氳瘽鍒楄〃")
-    @GetMapping("/history/sessions")
-    public AjaxResult listSessions() {
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        return success(purchaseAiService.listSessions(loginUser));
-    }
-
-    @Operation(summary = "閲囪喘浼氳瘽娑堟伅")
-    @GetMapping("/history/messages/{memoryId}")
-    public AjaxResult listMessages(@PathVariable String memoryId) {
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        return success(purchaseAiService.listMessages(memoryId, loginUser));
-    }
-
-    @Operation(summary = "鍒犻櫎閲囪喘浼氳瘽")
-    @DeleteMapping("/history/{memoryId}")
-    public AjaxResult deleteSession(@PathVariable String memoryId) {
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        return toAjax(purchaseAiService.deleteSession(memoryId, loginUser));
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/controller/SalesAiController.java b/src/main/java/com/ruoyi/ai/controller/SalesAiController.java
deleted file mode 100644
index 0c92ad6..0000000
--- a/src/main/java/com/ruoyi/ai/controller/SalesAiController.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package com.ruoyi.ai.controller;
-
-import com.ruoyi.ai.assistant.SalesAgent;
-import com.ruoyi.ai.assistant.SalesIntentExecutor;
-import com.ruoyi.ai.bean.ChatForm;
-import com.ruoyi.ai.context.AiSessionUserContext;
-import com.ruoyi.ai.service.AiChatSessionService;
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import dev.langchain4j.data.message.AiMessage;
-import dev.langchain4j.data.message.UserMessage;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import reactor.core.publisher.Flux;
-
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.List;
-
-@Tag(name = "閿�鍞姪鎵嬫櫤鑳戒綋")
-@RestController
-@RequestMapping("/sales-ai")
-public class SalesAiController extends BaseController {
-
-    private static final DateTimeFormatter CURRENT_DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final ZoneId CHINA_ZONE_ID = ZoneId.of("Asia/Shanghai");
-
-    private final SalesAgent salesAgent;
-    private final SalesIntentExecutor salesIntentExecutor;
-    private final AiSessionUserContext aiSessionUserContext;
-    private final MongoChatMemoryStore mongoChatMemoryStore;
-    private final AiChatSessionService aiChatSessionService;
-
-    public SalesAiController(SalesAgent salesAgent,
-                             SalesIntentExecutor salesIntentExecutor,
-                             AiSessionUserContext aiSessionUserContext,
-                             MongoChatMemoryStore mongoChatMemoryStore,
-                             AiChatSessionService aiChatSessionService) {
-        this.salesAgent = salesAgent;
-        this.salesIntentExecutor = salesIntentExecutor;
-        this.aiSessionUserContext = aiSessionUserContext;
-        this.mongoChatMemoryStore = mongoChatMemoryStore;
-        this.aiChatSessionService = aiChatSessionService;
-    }
-
-    @Operation(summary = "閿�鍞姪鎵嬪璇�")
-    @PostMapping(value = "/chat", produces = "text/stream;charset=utf-8")
-    public Flux<String> chat(@RequestBody ChatForm chatForm) {
-        if (!StringUtils.hasText(chatForm.getMemoryId())) {
-            return Flux.just("memoryId涓嶈兘涓虹┖");
-        }
-        if (!StringUtils.hasText(chatForm.getMessage())) {
-            return Flux.just("message涓嶈兘涓虹┖");
-        }
-
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        String memoryId = chatForm.getMemoryId();
-        String userMessage = chatForm.getMessage();
-
-        aiSessionUserContext.bind(memoryId, loginUser);
-        aiChatSessionService.touchSession(memoryId, loginUser, userMessage);
-
-        String directResponse = salesIntentExecutor.tryExecute(memoryId, userMessage);
-        if (StringUtils.isNotEmpty(directResponse)) {
-            mongoChatMemoryStore.appendMessages(
-                    memoryId,
-                    List.of(UserMessage.from(userMessage), AiMessage.from(directResponse))
-            );
-            aiChatSessionService.refreshSessionStats(memoryId, loginUser);
-            return Flux.just(directResponse);
-        }
-
-        if (isBusinessDataIntent(userMessage)) {
-            String noGuessResponse = "鏈瘑鍒埌鍙墽琛岀殑鏁版嵁鏌ヨ鏉′欢銆備负淇濊瘉缁撴灉鍑嗙‘锛屽綋鍓嶄笉浼氭帹娴嬫垨缂栭�犳暟鎹紝璇疯ˉ鍏呮槑纭椂闂磋寖鍥淬�佸鎴锋垨鍗曞彿鍚庡啀鏌ヨ銆�";
-            mongoChatMemoryStore.appendMessages(
-                    memoryId,
-                    List.of(UserMessage.from(userMessage), AiMessage.from(noGuessResponse))
-            );
-            aiChatSessionService.refreshSessionStats(memoryId, loginUser);
-            return Flux.just(noGuessResponse);
-        }
-
-        return salesAgent.chat(memoryId, userMessage, currentDateForPrompt())
-                .doOnComplete(() -> aiChatSessionService.refreshSessionStats(memoryId, loginUser))
-                .doOnError(ex -> aiChatSessionService.refreshSessionStats(memoryId, loginUser));
-    }
-
-    @Operation(summary = "閿�鍞姪鎵嬩細璇濆垪琛�")
-    @GetMapping("/history/sessions")
-    public AjaxResult listSessions() {
-        return success(aiChatSessionService.listCurrentUserSessions(SecurityUtils.getLoginUser()));
-    }
-
-    @Operation(summary = "閿�鍞姪鎵嬩細璇濇秷鎭�")
-    @GetMapping("/history/messages/{memoryId}")
-    public AjaxResult listMessages(@PathVariable String memoryId) {
-        return success(aiChatSessionService.listCurrentUserMessages(memoryId, SecurityUtils.getLoginUser()));
-    }
-
-    @Operation(summary = "鍒犻櫎閿�鍞姪鎵嬩細璇�")
-    @DeleteMapping("/history/{memoryId}")
-    public AjaxResult deleteSession(@PathVariable String memoryId) {
-        aiSessionUserContext.remove(memoryId);
-        return toAjax(aiChatSessionService.deleteCurrentUserSession(memoryId, SecurityUtils.getLoginUser()));
-    }
-
-    private boolean isBusinessDataIntent(String message) {
-        if (!StringUtils.hasText(message)) {
-            return false;
-        }
-        String text = message.trim();
-        return containsAny(text,
-                "鏌ヨ", "鏌ョ湅", "缁熻", "鍒嗘瀽", "寤鸿", "瀹㈡埛妗f", "绉佹捣", "鍏捣",
-                "閿�鍞姤浠�", "閿�鍞彴璐�", "閿�鍞��璐�", "瀹㈡埛寰�鏉�", "鍙戣揣鍙拌处", "鍥炴", "鎶ヤ环", "椋庨櫓");
-    }
-
-    private boolean containsAny(String text, String... keywords) {
-        for (String keyword : keywords) {
-            if (text.contains(keyword)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private String currentDateForPrompt() {
-        return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT);
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/controller/XiaozhiController.java b/src/main/java/com/ruoyi/ai/controller/XiaozhiController.java
deleted file mode 100644
index 82d088c..0000000
--- a/src/main/java/com/ruoyi/ai/controller/XiaozhiController.java
+++ /dev/null
@@ -1,202 +0,0 @@
-package com.ruoyi.ai.controller;
-
-import com.ruoyi.ai.assistant.ApproveTodoAgent;
-import com.ruoyi.ai.assistant.ApproveTodoIntentExecutor;
-import com.ruoyi.ai.assistant.FileAnalyzeAgent;
-import com.ruoyi.ai.bean.ChatForm;
-import com.ruoyi.ai.context.AiSessionUserContext;
-import com.ruoyi.ai.service.AiChatSessionService;
-import com.ruoyi.ai.service.AiFileTextExtractor;
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import dev.langchain4j.data.message.AiMessage;
-import dev.langchain4j.data.message.UserMessage;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.multipart.MultipartFile;
-import reactor.core.publisher.Flux;
-
-import java.io.IOException;
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.UUID;
-
-@Tag(name = "鍗忓悓鍔炲叕鍔╂墜")
-@RestController
-@RequestMapping("/xiaozhi")
-public class XiaozhiController extends BaseController {
-
-    private static final String FILE_ANALYZE_MEMORY_PREFIX = "file-analyze::";
-    private static final DateTimeFormatter CURRENT_DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final ZoneId CHINA_ZONE_ID = ZoneId.of("Asia/Shanghai");
-
-    private final ApproveTodoAgent approveTodoAgent;
-    private final ApproveTodoIntentExecutor approveTodoIntentExecutor;
-    private final FileAnalyzeAgent fileAnalyzeAgent;
-    private final AiSessionUserContext aiSessionUserContext;
-    private final MongoChatMemoryStore mongoChatMemoryStore;
-    private final AiFileTextExtractor aiFileTextExtractor;
-    private final AiChatSessionService aiChatSessionService;
-
-    public XiaozhiController(ApproveTodoAgent approveTodoAgent,
-                             ApproveTodoIntentExecutor approveTodoIntentExecutor,
-                             FileAnalyzeAgent fileAnalyzeAgent,
-                             AiSessionUserContext aiSessionUserContext,
-                             MongoChatMemoryStore mongoChatMemoryStore,
-                             AiFileTextExtractor aiFileTextExtractor,
-                             AiChatSessionService aiChatSessionService) {
-        this.approveTodoAgent = approveTodoAgent;
-        this.approveTodoIntentExecutor = approveTodoIntentExecutor;
-        this.fileAnalyzeAgent = fileAnalyzeAgent;
-        this.aiSessionUserContext = aiSessionUserContext;
-        this.mongoChatMemoryStore = mongoChatMemoryStore;
-        this.aiFileTextExtractor = aiFileTextExtractor;
-        this.aiChatSessionService = aiChatSessionService;
-    }
-
-    @Operation(summary = "瀵硅瘽")
-    @PostMapping(value = "/chat", produces = "text/stream;charset=utf-8")
-    public Flux<String> chat(@RequestBody ChatForm chatForm) {
-        if (!StringUtils.hasText(chatForm.getMemoryId())) {
-            return Flux.just("memoryId涓嶈兘涓虹┖");
-        }
-        if (!StringUtils.hasText(chatForm.getMessage())) {
-            return Flux.just("message涓嶈兘涓虹┖");
-        }
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        String memoryId = chatForm.getMemoryId();
-        String userMessage = chatForm.getMessage();
-
-        aiSessionUserContext.bind(memoryId, loginUser);
-        aiChatSessionService.touchSession(memoryId, loginUser, userMessage);
-
-        String directResponse = approveTodoIntentExecutor.tryExecute(memoryId, userMessage);
-        if (StringUtils.isNotEmpty(directResponse)) {
-            mongoChatMemoryStore.appendMessages(
-                    memoryId,
-                    List.of(UserMessage.from(userMessage), AiMessage.from(directResponse))
-            );
-            aiChatSessionService.refreshSessionStats(memoryId, loginUser);
-            return Flux.just(directResponse);
-        }
-
-        if (isApproveTodoBusinessIntent(userMessage)) {
-            String noGuessResponse = "鏈瘑鍒埌鍙墽琛岀殑瀹℃壒寰呭姙鎿嶄綔鏉′欢銆備负淇濊瘉缁撴灉鍑嗙‘锛屽綋鍓嶄笉浼氭帹娴嬫垨缂栭�犲鎵规暟鎹紝璇疯ˉ鍏呮祦绋嬬紪鍙枫�佹椂闂磋寖鍥存垨鏄庣‘鎿嶄綔鎸囦护鍚庡啀璇曘��";
-            mongoChatMemoryStore.appendMessages(
-                    memoryId,
-                    List.of(UserMessage.from(userMessage), AiMessage.from(noGuessResponse))
-            );
-            aiChatSessionService.refreshSessionStats(memoryId, loginUser);
-            return Flux.just(noGuessResponse);
-        }
-
-        return approveTodoAgent.chat(memoryId, userMessage, currentDateForPrompt())
-                .doOnComplete(() -> aiChatSessionService.refreshSessionStats(memoryId, loginUser))
-                .doOnError(ex -> aiChatSessionService.refreshSessionStats(memoryId, loginUser));
-    }
-
-    @Operation(summary = "涓婁紶鏂囦欢鍒嗘瀽")
-    @PostMapping(value = "/analyze-file", consumes = "multipart/form-data", produces = "text/stream;charset=utf-8")
-    public Flux<String> analyzeFile(@RequestParam("file") MultipartFile file,
-                                    @RequestParam(value = "message", required = false) String message,
-                                    @RequestParam(value = "memoryId", required = false) String memoryId) {
-        String rawMemoryId = StringUtils.hasText(memoryId) ? memoryId : UUID.randomUUID().toString();
-        String finalMemoryId = rawMemoryId.startsWith(FILE_ANALYZE_MEMORY_PREFIX)
-                ? rawMemoryId
-                : FILE_ANALYZE_MEMORY_PREFIX + rawMemoryId;
-
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        aiSessionUserContext.bind(finalMemoryId, loginUser);
-
-        String finalMessage = StringUtils.hasText(message) ? message : "璇峰垎鏋愯繖涓枃浠剁殑鏍稿績鍐呭骞剁粰鍑烘�荤粨";
-        String fileText;
-        try {
-            fileText = aiFileTextExtractor.extractText(file);
-        } catch (IllegalArgumentException ex) {
-            return Flux.just(ex.getMessage());
-        } catch (IOException ex) {
-            return Flux.just("鏂囦欢璇诲彇澶辫触");
-        }
-
-        if (!StringUtils.hasText(fileText)) {
-            return Flux.just("鏈彁鍙栧埌鏈夋晥鏂囦欢鍐呭");
-        }
-
-        String limitedContent = fileText.length() > 12000 ? fileText.substring(0, 12000) : fileText;
-        String userPrompt = "浣犲皢鍒嗘瀽鐢ㄦ埛涓婁紶鐨勬枃浠跺唴瀹广�俓n"
-                + "鏂囦欢鍚�: " + file.getOriginalFilename() + "\n"
-                + "鐢ㄦ埛闂: " + finalMessage + "\n"
-                + "鏂囦欢鍐呭濡備笅:\n"
-                + limitedContent;
-
-        aiChatSessionService.touchSession(finalMemoryId, loginUser, "鏂囦欢鍒嗘瀽: " + finalMessage);
-
-        return Flux.defer(() -> fileAnalyzeAgent.chat(finalMemoryId, userPrompt))
-                .onErrorResume(NoSuchElementException.class, ex -> {
-                    // DashScope 鍦ㄥ巻鍙叉秷鎭吋瀹瑰満鏅笅鍙兘鎶� NoSuchElementException锛屾竻绌哄悗閲嶈瘯涓�娆�
-                    mongoChatMemoryStore.deleteMessages(finalMemoryId);
-                    return fileAnalyzeAgent.chat(finalMemoryId, userPrompt);
-                })
-                .doOnComplete(() -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser))
-                .doOnError(ex -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser));
-    }
-
-    @Operation(summary = "浼氳瘽鍒楄〃")
-    @GetMapping("/history/sessions")
-    public AjaxResult listSessions() {
-        return success(aiChatSessionService.listCurrentUserSessions(SecurityUtils.getLoginUser()));
-    }
-
-    @Operation(summary = "浼氳瘽娑堟伅")
-    @GetMapping("/history/messages/{memoryId}")
-    public AjaxResult listMessages(@PathVariable String memoryId) {
-        return success(aiChatSessionService.listCurrentUserMessages(memoryId, SecurityUtils.getLoginUser()));
-    }
-
-    @Operation(summary = "鍒犻櫎浼氳瘽")
-    @DeleteMapping("/history/{memoryId}")
-    public AjaxResult deleteSession(@PathVariable String memoryId) {
-        aiSessionUserContext.remove(memoryId);
-        return toAjax(aiChatSessionService.deleteCurrentUserSession(memoryId, SecurityUtils.getLoginUser()));
-    }
-
-    private boolean isApproveTodoBusinessIntent(String message) {
-        if (!StringUtils.hasText(message)) {
-            return false;
-        }
-        String text = message.trim();
-        boolean hasDomainWord = containsAny(text,
-                "瀹℃壒", "寰呭姙", "娴佺▼缂栧彿", "娴佺▼鍙�", "瀹℃壒娴佽浆", "瀹℃壒鑺傜偣", "褰撳墠瀹℃壒浜�", "椹冲洖", "閫氳繃", "鎾ら攢", "鍒犻櫎");
-        boolean hasIntentWord = containsAny(text,
-                "鏌ヨ", "鏌ョ湅", "鍒楀嚭", "缁熻", "鍒嗘瀽", "鍒嗗竷", "閫氳繃", "椹冲洖", "鎾ら攢", "鍒犻櫎", "淇敼", "鏈夊摢浜�", "鍗″湪");
-        return hasDomainWord && hasIntentWord;
-    }
-
-    private boolean containsAny(String text, String... keywords) {
-        for (String keyword : keywords) {
-            if (text.contains(keyword)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private String currentDateForPrompt() {
-        return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT);
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/dto/AiChatMessageDto.java b/src/main/java/com/ruoyi/ai/dto/AiChatMessageDto.java
deleted file mode 100644
index 081bf12..0000000
--- a/src/main/java/com/ruoyi/ai/dto/AiChatMessageDto.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.ruoyi.ai.dto;
-
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.util.List;
-
-@Data
-@NoArgsConstructor
-public class AiChatMessageDto {
-
-    private String role;
-
-    private String content;
-
-    private List<String> filePaths;
-
-    public AiChatMessageDto(String role, String content) {
-        this.role = role;
-        this.content = content;
-    }
-
-    public AiChatMessageDto(String role, String content, List<String> filePaths) {
-        this.role = role;
-        this.content = content;
-        this.filePaths = filePaths;
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/dto/AiChatSessionDto.java b/src/main/java/com/ruoyi/ai/dto/AiChatSessionDto.java
deleted file mode 100644
index f62f3b5..0000000
--- a/src/main/java/com/ruoyi/ai/dto/AiChatSessionDto.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.ruoyi.ai.dto;
-
-import lombok.Data;
-
-import java.util.Date;
-
-@Data
-public class AiChatSessionDto {
-
-    private String memoryId;
-
-    private String title;
-
-    private String lastMessage;
-
-    private Integer messageCount;
-
-    private Date lastChatTime;
-}
diff --git a/src/main/java/com/ruoyi/ai/dto/KnowledgeChatRequest.java b/src/main/java/com/ruoyi/ai/dto/KnowledgeChatRequest.java
deleted file mode 100644
index 134c2c8..0000000
--- a/src/main/java/com/ruoyi/ai/dto/KnowledgeChatRequest.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.ruoyi.ai.dto;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-/**
- * 鐭ヨ瘑搴撻棶绛旇姹�
- */
-@Data
-@Schema(description = "鐭ヨ瘑搴撻棶绛旇姹�")
-public class KnowledgeChatRequest {
-
-    @Schema(description = "鐭ヨ瘑搴揑D", required = true)
-    private Long knowledgeBaseId;
-
-    @Schema(description = "浼氳瘽ID锛岀敤浜庝繚鎸佷笂涓嬫枃", required = true)
-    private String memoryId;
-
-    @Schema(description = "鐢ㄦ埛鎻愰棶鍐呭", required = true)
-    private String question;
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/ai/mapper/AiChatSessionMapper.java b/src/main/java/com/ruoyi/ai/mapper/AiChatSessionMapper.java
deleted file mode 100644
index 8983396..0000000
--- a/src/main/java/com/ruoyi/ai/mapper/AiChatSessionMapper.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.ruoyi.ai.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.ai.pojo.AiChatSession;
-
-public interface AiChatSessionMapper extends BaseMapper<AiChatSession> {
-}
diff --git a/src/main/java/com/ruoyi/ai/mongodbBean/ChatMessages.java b/src/main/java/com/ruoyi/ai/mongodbBean/ChatMessages.java
deleted file mode 100644
index e2944cb..0000000
--- a/src/main/java/com/ruoyi/ai/mongodbBean/ChatMessages.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.ruoyi.ai.mongodbBean;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import org.bson.types.ObjectId;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.index.Indexed;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-import java.util.Date;
-import java.util.List;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-@Document("chat_messages")
-public class ChatMessages {
-
-    @Id
-    private ObjectId id;
-
-    @Indexed(unique = true)
-    private String memoryId;
-
-    private String content;
-
-    /**
-     * 澶氭枃浠跺垎鏋愮敤鎴锋彁闂俊鎭紙涓庢枃浠惰矾寰勫垎寮�瀛樺偍锛�
-     */
-    private List<String> analyzeUserQuestions;
-
-    /**
-     * 澶氭枃浠跺垎鏋愪笂浼犳枃浠惰矾寰勶紙鍥剧墖鍜� pdf 浣跨敤棰勮鍦板潃锛屽叾浠栦娇鐢ㄤ笅杞藉湴鍧�锛�
-     */
-    private List<String> analyzeFilePaths;
-
-    /**
-     * 澶氭枃浠跺垎鏋愭瘡娆℃彁闂搴旂殑鏂囦欢璺緞鍒嗙粍
-     */
-    private List<List<String>> analyzeFilePathGroups;
-
-    private Date createTime;
-
-    private Date updateTime;
-}
diff --git a/src/main/java/com/ruoyi/ai/pojo/AiChatSession.java b/src/main/java/com/ruoyi/ai/pojo/AiChatSession.java
deleted file mode 100644
index cc289f8..0000000
--- a/src/main/java/com/ruoyi/ai/pojo/AiChatSession.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.ruoyi.ai.pojo;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-
-import java.util.Date;
-
-@Data
-@TableName("ai_chat_session")
-public class AiChatSession {
-
-    @TableId(type = IdType.AUTO)
-    private Long id;
-
-    private String memoryId;
-
-    private Long userId;
-
-    private Long tenantId;
-
-    private String title;
-
-    private String lastMessage;
-
-    private Integer messageCount;
-
-    private Date lastChatTime;
-
-    private Date createTime;
-
-    private Date updateTime;
-}
diff --git a/src/main/java/com/ruoyi/ai/schedule/AiSessionCleanupTask.java b/src/main/java/com/ruoyi/ai/schedule/AiSessionCleanupTask.java
deleted file mode 100644
index cecdba8..0000000
--- a/src/main/java/com/ruoyi/ai/schedule/AiSessionCleanupTask.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.ai.schedule;
-
-import com.ruoyi.ai.context.AiSessionUserContext;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-@Component
-public class AiSessionCleanupTask {
-
-    private final AiSessionUserContext aiSessionUserContext;
-
-    public AiSessionCleanupTask(AiSessionUserContext aiSessionUserContext) {
-        this.aiSessionUserContext = aiSessionUserContext;
-    }
-
-    @Scheduled(cron = "0 0 2 * * ?")
-    public void cleanupExpiredSessions() {
-        try {
-            aiSessionUserContext.cleanExpiredSessions();
-        } catch (Exception e) {
-            System.err.println("娓呯悊杩囨湡AI浼氳瘽澶辫触: " + e.getMessage());
-        }
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/service/AiChatSessionService.java b/src/main/java/com/ruoyi/ai/service/AiChatSessionService.java
deleted file mode 100644
index ef47e03..0000000
--- a/src/main/java/com/ruoyi/ai/service/AiChatSessionService.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.ruoyi.ai.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.ai.dto.AiChatMessageDto;
-import com.ruoyi.ai.dto.AiChatSessionDto;
-import com.ruoyi.ai.pojo.AiChatSession;
-import com.ruoyi.framework.security.LoginUser;
-
-import java.util.List;
-
-public interface AiChatSessionService extends IService<AiChatSession> {
-
-    void touchSession(String memoryId, LoginUser loginUser, String userMessage);
-
-    void refreshSessionStats(String memoryId, LoginUser loginUser);
-
-    List<AiChatSessionDto> listCurrentUserSessions(LoginUser loginUser);
-
-    List<AiChatMessageDto> listCurrentUserMessages(String memoryId, LoginUser loginUser);
-
-    boolean deleteCurrentUserSession(String memoryId, LoginUser loginUser);
-}
diff --git a/src/main/java/com/ruoyi/ai/service/AiFileTextExtractor.java b/src/main/java/com/ruoyi/ai/service/AiFileTextExtractor.java
deleted file mode 100644
index 6e37451..0000000
--- a/src/main/java/com/ruoyi/ai/service/AiFileTextExtractor.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package com.ruoyi.ai.service;
-
-import com.ruoyi.common.utils.StringUtils;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ss.usermodel.DataFormatter;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.springframework.stereotype.Component;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-
-@Component
-public class AiFileTextExtractor {
-
-    private static final long MAX_FILE_SIZE = 10L * 1024 * 1024;
-
-    public String extractText(MultipartFile file) throws IOException {
-        if (file == null || file.isEmpty()) {
-            throw new IllegalArgumentException("鏂囦欢涓嶈兘涓虹┖");
-        }
-        if (file.getSize() > MAX_FILE_SIZE) {
-            throw new IllegalArgumentException("鏂囦欢杩囧ぇ锛岃鎺у埗鍦�10MB浠ュ唴");
-        }
-
-        String filename = file.getOriginalFilename();
-        String ext = getExtension(filename);
-        byte[] bytes = file.getBytes();
-
-        if (isPlainText(ext)) {
-            return decodeText(bytes);
-        }
-        if ("docx".equals(ext)) {
-            return extractDocx(bytes);
-        }
-        if ("xlsx".equals(ext)) {
-            return extractXlsx(bytes);
-        }
-        if ("xls".equals(ext)) {
-            return extractXls(bytes);
-        }
-        if (isImage(ext)) {
-            return "鍥剧墖鏂囦欢锛�" + filename + "锛屽凡涓婁紶锛岃缁撳悎鍥剧墖鍐呭璇嗗埆閲囪喘鍗曟嵁銆佽〃鏍煎拰浜у搧鏄庣粏銆�";
-        }
-        throw new IllegalArgumentException("鏆備笉鏀寔璇ユ枃浠剁被鍨�: " + ext);
-    }
-
-    public boolean isImageFile(MultipartFile file) {
-        if (file == null) {
-            return false;
-        }
-        return isImage(getExtension(file.getOriginalFilename()));
-    }
-
-    private String extractDocx(byte[] bytes) throws IOException {
-        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
-             XWPFDocument document = new XWPFDocument(inputStream);
-             XWPFWordExtractor extractor = new XWPFWordExtractor(document)) {
-            return extractor.getText();
-        }
-    }
-
-    private String extractXlsx(byte[] bytes) throws IOException {
-        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
-             XSSFWorkbook workbook = new XSSFWorkbook(inputStream)) {
-            return extractWorkbook(workbook);
-        }
-    }
-
-    private String extractXls(byte[] bytes) throws IOException {
-        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
-             HSSFWorkbook workbook = new HSSFWorkbook(inputStream)) {
-            return extractWorkbook(workbook);
-        }
-    }
-
-    private String extractWorkbook(org.apache.poi.ss.usermodel.Workbook workbook) {
-        StringBuilder text = new StringBuilder();
-        DataFormatter formatter = new DataFormatter();
-        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
-            Sheet sheet = workbook.getSheetAt(i);
-            text.append("Sheet: ").append(sheet.getSheetName()).append("\n");
-            for (Row row : sheet) {
-                short lastCellNum = row.getLastCellNum();
-                if (lastCellNum <= 0) {
-                    text.append("\n");
-                    continue;
-                }
-                for (int c = 0; c < lastCellNum; c++) {
-                    String cellText = formatter.formatCellValue(row.getCell(c));
-                    text.append(cellText);
-                    if (c < lastCellNum - 1) {
-                        text.append('\t');
-                    }
-                }
-                text.append('\n');
-            }
-        }
-        return text.toString();
-    }
-
-    private String decodeText(byte[] bytes) {
-        String utf8 = new String(bytes, StandardCharsets.UTF_8);
-        if (utf8.contains("锟�")) {
-            return new String(bytes, java.nio.charset.Charset.forName("GBK"));
-        }
-        return utf8;
-    }
-
-    private String getExtension(String filename) {
-        if (!StringUtils.hasText(filename) || !filename.contains(".")) {
-            return "";
-        }
-        return filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
-    }
-
-    private boolean isPlainText(String ext) {
-        return StringUtils.inStringIgnoreCase(ext,
-                "txt", "md", "markdown", "json", "xml", "yaml", "yml", "csv", "log", "properties",
-                "java", "js", "ts", "vue", "html", "css", "sql", "py", "go", "sh", "bat");
-    }
-
-    private boolean isImage(String ext) {
-        return StringUtils.inStringIgnoreCase(ext, "png", "jpg", "jpeg", "webp", "bmp");
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/service/KnowledgeRagService.java b/src/main/java/com/ruoyi/ai/service/KnowledgeRagService.java
deleted file mode 100644
index 44d5f87..0000000
--- a/src/main/java/com/ruoyi/ai/service/KnowledgeRagService.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.ruoyi.ai.service;
-
-import java.util.List;
-
-/**
- * 鐭ヨ瘑搴揜AG鏈嶅姟
- * 璐熻矗鏂囦欢鍚戦噺鍖栧鐞嗗拰妫�绱�
- */
-public interface KnowledgeRagService {
-
-    /**
-     * 寮傛澶勭悊鍚戦噺鍖�
-     */
-    void processVectorAsync(Long vectorId);
-
-    /**
-     * 鍚屾澶勭悊鍚戦噺鍖�
-     */
-    void processVector(Long vectorId);
-
-    /**
-     * 妫�绱㈢浉鍏冲唴瀹�
-     * @param namespace 鍛藉悕绌洪棿
-     * @param query 鏌ヨ鏂囨湰
-     * @param maxResults 鏈�澶х粨鏋滄暟
-     * @return 鐩稿叧鍐呭鍒楄〃
-     */
-    List<String> searchRelevantContent(String namespace, String query, int maxResults);
-
-    /**
-     * 鍒犻櫎鎸囧畾鏂囦欢鐨勫悜閲忔暟鎹�
-     */
-    void deleteEmbeddings(String namespace, Long storageBlobId);
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/ai/service/PurchaseAiService.java b/src/main/java/com/ruoyi/ai/service/PurchaseAiService.java
deleted file mode 100644
index cbc936c..0000000
--- a/src/main/java/com/ruoyi/ai/service/PurchaseAiService.java
+++ /dev/null
@@ -1,1069 +0,0 @@
-package com.ruoyi.ai.service;
-
-import com.alibaba.fastjson2.JSON;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.ruoyi.ai.assistant.PurchaseAgent;
-import com.ruoyi.ai.assistant.PurchaseIntentExecutor;
-import com.ruoyi.ai.bean.ChatForm;
-import com.ruoyi.ai.bean.PurchaseAiConfirmRequest;
-import com.ruoyi.ai.context.AiSessionUserContext;
-import com.ruoyi.ai.dto.AiChatMessageDto;
-import com.ruoyi.ai.dto.AiChatSessionDto;
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import com.ruoyi.basic.dto.StorageBlobVO;
-import com.ruoyi.basic.mapper.SupplierManageMapper;
-import com.ruoyi.basic.pojo.SupplierManage;
-import com.ruoyi.basic.service.StorageBlobService;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.purchase.dto.PurchaseLedgerDto;
-import com.ruoyi.purchase.dto.PurchaseReturnOrderDto;
-import com.ruoyi.purchase.service.IPurchaseLedgerService;
-import com.ruoyi.purchase.service.PurchaseReturnOrdersService;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import dev.langchain4j.data.image.Image;
-import dev.langchain4j.data.message.AiMessage;
-import dev.langchain4j.data.message.ChatMessage;
-import dev.langchain4j.data.message.Content;
-import dev.langchain4j.data.message.ImageContent;
-import dev.langchain4j.data.message.SystemMessage;
-import dev.langchain4j.data.message.TextContent;
-import dev.langchain4j.data.message.UserMessage;
-import dev.langchain4j.model.chat.StreamingChatLanguageModel;
-import dev.langchain4j.model.chat.response.ChatResponse;
-import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.stereotype.Service;
-import org.springframework.web.multipart.MultipartFile;
-import reactor.core.publisher.Flux;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.Base64;
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.time.format.DateTimeParseException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.UUID;
-import java.nio.file.Files;
-
-@Service
-public class PurchaseAiService {
-
-    private static final String PURCHASE_FILE_ANALYZE_MEMORY_PREFIX = "purchase-file-analyze::";
-    private static final int MAX_FILE_COUNT = 10;
-    private static final int MAX_SINGLE_FILE_TEXT_LENGTH = 8000;
-    private static final int MAX_TOTAL_FILE_TEXT_LENGTH = 30000;
-    private static final DateTimeFormatter CURRENT_DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final ZoneId CHINA_ZONE_ID = ZoneId.of("Asia/Shanghai");
-
-    private final PurchaseAgent purchaseAgent;
-    private final PurchaseIntentExecutor purchaseIntentExecutor;
-    private final AiSessionUserContext aiSessionUserContext;
-    private final MongoChatMemoryStore mongoChatMemoryStore;
-    private final AiChatSessionService aiChatSessionService;
-    private final AiFileTextExtractor aiFileTextExtractor;
-    private final ObjectMapper objectMapper;
-    private final IPurchaseLedgerService purchaseLedgerService;
-    private final PurchaseReturnOrdersService purchaseReturnOrdersService;
-    private final StorageBlobService storageBlobService;
-    private final SupplierManageMapper supplierManageMapper;
-    private final StreamingChatLanguageModel purchaseVisionStreamingChatModel;
-
-    public PurchaseAiService(PurchaseAgent purchaseAgent,
-                                PurchaseIntentExecutor purchaseIntentExecutor,
-                                AiSessionUserContext aiSessionUserContext,
-                                MongoChatMemoryStore mongoChatMemoryStore,
-                                AiChatSessionService aiChatSessionService,
-                                AiFileTextExtractor aiFileTextExtractor,
-                                 ObjectMapper objectMapper,
-                                 IPurchaseLedgerService purchaseLedgerService,
-                                 PurchaseReturnOrdersService purchaseReturnOrdersService,
-                                 StorageBlobService storageBlobService,
-                                 SupplierManageMapper supplierManageMapper,
-                                 @Qualifier("purchaseVisionStreamingChatModel") StreamingChatLanguageModel purchaseVisionStreamingChatModel) {
-        this.purchaseAgent = purchaseAgent;
-        this.purchaseIntentExecutor = purchaseIntentExecutor;
-        this.aiSessionUserContext = aiSessionUserContext;
-        this.mongoChatMemoryStore = mongoChatMemoryStore;
-        this.aiChatSessionService = aiChatSessionService;
-        this.aiFileTextExtractor = aiFileTextExtractor;
-        this.objectMapper = objectMapper;
-        this.purchaseLedgerService = purchaseLedgerService;
-        this.purchaseReturnOrdersService = purchaseReturnOrdersService;
-        this.storageBlobService = storageBlobService;
-        this.supplierManageMapper = supplierManageMapper;
-        this.purchaseVisionStreamingChatModel = purchaseVisionStreamingChatModel;
-    }
-
-    public Flux<String> chat(ChatForm chatForm, LoginUser loginUser) {
-        if (!StringUtils.hasText(chatForm.getMemoryId())) {
-            return Flux.just("memoryId涓嶈兘涓虹┖");
-        }
-        if (!StringUtils.hasText(chatForm.getMessage())) {
-            return Flux.just("message涓嶈兘涓虹┖");
-        }
-
-        String memoryId = chatForm.getMemoryId();
-        String userMessage = chatForm.getMessage();
-
-        aiSessionUserContext.bind(memoryId, loginUser);
-        aiChatSessionService.touchSession(memoryId, loginUser, userMessage);
-
-        String directResponse = purchaseIntentExecutor.tryExecute(memoryId, userMessage);
-        if (StringUtils.isNotEmpty(directResponse)) {
-            mongoChatMemoryStore.appendMessages(
-                    memoryId,
-                    List.of(UserMessage.from(userMessage), AiMessage.from(directResponse))
-            );
-            aiChatSessionService.refreshSessionStats(memoryId, loginUser);
-            return Flux.just(directResponse);
-        }
-
-        if (isPurchaseBusinessIntent(userMessage)) {
-            String noGuessResponse = buildNoGuessResponse();
-            mongoChatMemoryStore.appendMessages(
-                    memoryId,
-                    List.of(UserMessage.from(userMessage), AiMessage.from(noGuessResponse))
-            );
-            aiChatSessionService.refreshSessionStats(memoryId, loginUser);
-            return Flux.just(noGuessResponse);
-        }
-
-        return purchaseAgent.chat(memoryId, userMessage, currentDateForPrompt())
-                .doOnComplete(() -> aiChatSessionService.refreshSessionStats(memoryId, loginUser))
-                .doOnError(ex -> aiChatSessionService.refreshSessionStats(memoryId, loginUser));
-    }
-
-    public Flux<String> analyzeFiles(MultipartFile[] files,
-                                     String message,
-                                     String memoryId,
-                                     LoginUser loginUser) {
-        if (files == null || files.length == 0) {
-            return Flux.just("files涓嶈兘涓虹┖");
-        }
-        if (files.length > MAX_FILE_COUNT) {
-            return Flux.just("涓�娆℃渶澶氬垎鏋�" + MAX_FILE_COUNT + "涓枃浠�");
-        }
-
-        String rawMemoryId = StringUtils.hasText(memoryId) ? memoryId : UUID.randomUUID().toString();
-        String finalMemoryId = rawMemoryId.startsWith(PURCHASE_FILE_ANALYZE_MEMORY_PREFIX)
-                ? rawMemoryId
-                : PURCHASE_FILE_ANALYZE_MEMORY_PREFIX + rawMemoryId;
-
-        aiSessionUserContext.bind(finalMemoryId, loginUser);
-
-        String finalMessage = StringUtils.hasText(message)
-                ? message
-                : "璇峰垎鏋愯繖浜涢噰璐枃浠讹紝鎻愬彇鍙敤浜庝笟鍔″鐞嗙殑鏁版嵁锛屽苟鏁寸悊鎴愬緟瀹㈡埛纭鐨勬牸寮�";
-
-        List<String> filePaths;
-        try {
-            List<StorageBlobVO> uploadedFiles = storageBlobService.upload(copyFilesForUpload(files), true);
-            filePaths = resolveFileAccessPaths(uploadedFiles);
-        } catch (Exception ex) {
-            return Flux.just("鏂囦欢涓婁紶澶辫触");
-        }
-        try {
-            mongoChatMemoryStore.appendAnalyzeFileContext(finalMemoryId, finalMessage, filePaths);
-        } catch (Exception ex) {
-            return Flux.just("浼氳瘽鏂囦欢淇℃伅淇濆瓨澶辫触");
-        }
-
-        String fileContent;
-        try {
-            fileContent = buildMultiFileContent(files);
-        } catch (IllegalArgumentException ex) {
-            return Flux.just(ex.getMessage());
-        } catch (IOException ex) {
-            return Flux.just("鏂囦欢璇诲彇澶辫触");
-        }
-
-        if (!StringUtils.hasText(fileContent)) {
-            return Flux.just("鏈彁鍙栧埌鏈夋晥鏂囦欢鍐呭");
-        }
-
-        String userPrompt = buildPurchaseFileAnalyzePrompt(finalMessage, fileContent);
-        aiChatSessionService.touchSession(finalMemoryId, loginUser, "閲囪喘澶氭枃浠跺垎鏋�: " + finalMessage);
-
-        if (containsImageFile(files)) {
-            return chatWithPurchaseVisionModel(finalMemoryId, finalMessage, userPrompt, files)
-                    .doOnComplete(() -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser))
-                    .doOnError(ex -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser));
-        }
-
-        return Flux.defer(() -> purchaseAgent.chat(finalMemoryId, userPrompt, currentDateForPrompt()))
-                .onErrorResume(NoSuchElementException.class, ex -> {
-                    mongoChatMemoryStore.deleteMessages(finalMemoryId);
-                    return purchaseAgent.chat(finalMemoryId, userPrompt, currentDateForPrompt());
-                })
-                .doOnComplete(() -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser))
-                .doOnError(ex -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser));
-    }
-
-    public AjaxResult confirmAnalyzeResult(PurchaseAiConfirmRequest request) {
-        if (request == null || !StringUtils.hasText(request.getBusinessType())) {
-            return AjaxResult.error("businessType涓嶈兘涓虹┖");
-        }
-        if (request.getPayload() == null || request.getPayload().isEmpty()) {
-            return AjaxResult.error("payload涓嶈兘涓虹┖");
-        }
-
-        try {
-            String businessType = request.getBusinessType().trim();
-            return switch (businessType) {
-                case "purchase_ledger" -> processPurchaseLedger(request.getPayload());
-                case "purchase_return_order" -> processPurchaseReturnOrder(request.getPayload());
-                default -> AjaxResult.error("鏆備笉鏀寔璇ヤ笟鍔$被鍨�: " + businessType);
-            };
-        } catch (Exception ex) {
-            return AjaxResult.error(toCustomerMessage(ex));
-        }
-    }
-
-    public List<AiChatSessionDto> listSessions(LoginUser loginUser) {
-        return aiChatSessionService.listCurrentUserSessions(loginUser);
-    }
-
-    public List<AiChatMessageDto> listMessages(String memoryId, LoginUser loginUser) {
-        return aiChatSessionService.listCurrentUserMessages(memoryId, loginUser);
-    }
-
-    public boolean deleteSession(String memoryId, LoginUser loginUser) {
-        aiSessionUserContext.remove(memoryId);
-        return aiChatSessionService.deleteCurrentUserSession(memoryId, loginUser);
-    }
-
-    private String buildMultiFileContent(MultipartFile[] files) throws IOException {
-        StringBuilder builder = new StringBuilder();
-        int totalLength = 0;
-        for (MultipartFile file : files) {
-            String text = aiFileTextExtractor.extractText(file);
-            if (!StringUtils.hasText(text)) {
-                continue;
-            }
-            String limitedText = text.length() > MAX_SINGLE_FILE_TEXT_LENGTH
-                    ? text.substring(0, MAX_SINGLE_FILE_TEXT_LENGTH)
-                    : text;
-            if (totalLength + limitedText.length() > MAX_TOTAL_FILE_TEXT_LENGTH) {
-                int remain = MAX_TOTAL_FILE_TEXT_LENGTH - totalLength;
-                if (remain <= 0) {
-                    break;
-                }
-                limitedText = limitedText.substring(0, remain);
-            }
-            builder.append("\n--- 鏂囦欢: ")
-                    .append(file.getOriginalFilename())
-                    .append(" ---\n")
-                    .append(limitedText)
-                    .append('\n');
-            totalLength += limitedText.length();
-        }
-        return builder.toString();
-    }
-
-    private boolean containsImageFile(MultipartFile[] files) {
-        for (MultipartFile file : files) {
-            if (aiFileTextExtractor.isImageFile(file)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private List<String> resolveFileAccessPaths(List<StorageBlobVO> uploadedFiles) {
-        if (StringUtils.isEmpty(uploadedFiles)) {
-            return Collections.emptyList();
-        }
-        List<String> filePaths = new ArrayList<>();
-        for (StorageBlobVO uploadedFile : uploadedFiles) {
-            if (uploadedFile == null) {
-                continue;
-            }
-            String selectedPath;
-            if (shouldUsePreviewPath(uploadedFile)) {
-                selectedPath = StringUtils.hasText(uploadedFile.getPreviewURL())
-                        ? uploadedFile.getPreviewURL()
-                        : uploadedFile.getDownloadURL();
-            } else {
-                selectedPath = StringUtils.hasText(uploadedFile.getDownloadURL())
-                        ? uploadedFile.getDownloadURL()
-                        : uploadedFile.getPreviewURL();
-            }
-            if (StringUtils.hasText(selectedPath)) {
-                filePaths.add(selectedPath);
-            }
-        }
-        return filePaths;
-    }
-
-    private boolean shouldUsePreviewPath(StorageBlobVO uploadedFile) {
-        String contentType = uploadedFile.getContentType();
-        if (StringUtils.hasText(contentType)) {
-            String normalized = contentType.toLowerCase(Locale.ROOT);
-            if (normalized.startsWith("image/") || "application/pdf".equals(normalized)) {
-                return true;
-            }
-        }
-        String filename = uploadedFile.getOriginalFilename();
-        if (!StringUtils.hasText(filename) || !filename.contains(".")) {
-            return false;
-        }
-        String ext = filename.substring(filename.lastIndexOf('.') + 1).toLowerCase(Locale.ROOT);
-        return StringUtils.inStringIgnoreCase(ext, "png", "jpg", "jpeg", "webp", "bmp", "pdf");
-    }
-
-    private List<MultipartFile> copyFilesForUpload(MultipartFile[] files) throws IOException {
-        List<MultipartFile> copies = new ArrayList<>();
-        for (MultipartFile file : files) {
-            copies.add(new InMemoryMultipartFile(
-                    file.getName(),
-                    file.getOriginalFilename(),
-                    file.getContentType(),
-                    file.getBytes()
-            ));
-        }
-        return copies;
-    }
-
-    private static final class InMemoryMultipartFile implements MultipartFile {
-        private final String name;
-        private final String originalFilename;
-        private final String contentType;
-        private final byte[] bytes;
-
-        private InMemoryMultipartFile(String name, String originalFilename, String contentType, byte[] bytes) {
-            this.name = name;
-            this.originalFilename = originalFilename;
-            this.contentType = contentType;
-            this.bytes = bytes == null ? new byte[0] : bytes;
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-
-        @Override
-        public String getOriginalFilename() {
-            return originalFilename;
-        }
-
-        @Override
-        public String getContentType() {
-            return contentType;
-        }
-
-        @Override
-        public boolean isEmpty() {
-            return bytes.length == 0;
-        }
-
-        @Override
-        public long getSize() {
-            return bytes.length;
-        }
-
-        @Override
-        public byte[] getBytes() {
-            return bytes.clone();
-        }
-
-        @Override
-        public InputStream getInputStream() {
-            return new ByteArrayInputStream(bytes);
-        }
-
-        @Override
-        public void transferTo(File dest) throws IOException, IllegalStateException {
-            Files.write(dest.toPath(), bytes);
-        }
-    }
-
-    private Flux<String> chatWithPurchaseVisionModel(String memoryId,
-                                                     String userMessage,
-                                                     String userPrompt,
-                                                     MultipartFile[] files) {
-        return Flux.create(sink -> {
-            StringBuilder assistantReply = new StringBuilder();
-            try {
-                List<Content> contents = new ArrayList<>();
-                contents.add(TextContent.from(userPrompt));
-                for (MultipartFile file : files) {
-                    if (!aiFileTextExtractor.isImageFile(file)) {
-                        continue;
-                    }
-                    contents.add(TextContent.from("涓嬮潰杩欏紶鍥剧墖鏂囦欢鍚嶏細" + file.getOriginalFilename()));
-                    contents.add(ImageContent.from(Image.builder()
-                            .base64Data(Base64.getEncoder().encodeToString(file.getBytes()))
-                            .mimeType(resolveImageMimeType(file))
-                            .build()));
-                }
-
-                List<ChatMessage> messages = List.of(
-                        SystemMessage.from("浣犳槸閲囪喘涓氬姟鏂囦欢鍒嗘瀽鍔╂墜銆傝浠庢枃鏈拰鍥剧墖涓瘑鍒噰璐彴璐︺�侀噰璐骇鍝佹槑缁嗐�佷粯娆炬垨閫�璐т俊鎭紝鍙緭鍑哄悎娉� JSON銆�"),
-                        UserMessage.from(contents)
-                );
-                safeAppendMessages(memoryId, List.of(UserMessage.from("閲囪喘澶氭枃浠跺垎鏋�: " + userMessage)));
-                purchaseVisionStreamingChatModel.chat(messages, new StreamingChatResponseHandler() {
-                    @Override
-                    public void onPartialResponse(String partialResponse) {
-                        if (partialResponse != null) {
-                            assistantReply.append(partialResponse);
-                            sink.next(partialResponse);
-                        }
-                    }
-
-                    @Override
-                    public void onCompleteResponse(ChatResponse completeResponse) {
-                        if (StringUtils.hasText(assistantReply.toString())) {
-                            safeAppendMessages(memoryId, List.of(AiMessage.from(assistantReply.toString())));
-                        }
-                        sink.complete();
-                    }
-
-                    @Override
-                    public void onError(Throwable error) {
-                        sink.error(error);
-                    }
-                });
-            } catch (Exception ex) {
-                sink.next("鍥剧墖鏂囦欢璇诲彇澶辫触锛岃纭鍥剧墖鏍煎紡涓� png銆乯pg銆乯peg銆亀ebp 鎴� bmp锛屼笖澶у皬涓嶈秴杩�10MB");
-                sink.complete();
-            }
-        });
-    }
-
-    private void safeAppendMessages(String memoryId, List<ChatMessage> messages) {
-        if (!StringUtils.hasText(memoryId) || StringUtils.isEmpty(messages)) {
-            return;
-        }
-        try {
-            mongoChatMemoryStore.appendMessages(memoryId, messages);
-        } catch (Exception ignored) {
-        }
-    }
-
-    private String resolveImageMimeType(MultipartFile file) {
-        String contentType = file.getContentType();
-        if (StringUtils.hasText(contentType) && contentType.startsWith("image/")) {
-            return contentType;
-        }
-        String filename = file.getOriginalFilename();
-        String ext = "";
-        if (StringUtils.hasText(filename) && filename.contains(".")) {
-            ext = filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
-        }
-        return switch (ext) {
-            case "jpg", "jpeg" -> "image/jpeg";
-            case "webp" -> "image/webp";
-            case "bmp" -> "image/bmp";
-            default -> "image/png";
-        };
-    }
-
-    private String currentDateForPrompt() {
-        return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT);
-    }
-
-    private boolean isPurchaseBusinessIntent(String message) {
-        if (!StringUtils.hasText(message)) {
-            return false;
-        }
-        String text = message.trim();
-        boolean hasDomainWord = containsAny(text,
-                "閲囪喘", "閲囪喘鍙拌处", "閲囪喘鍗�", "閲囪喘璁㈠崟", "渚涘簲鍟�", "鐗╂枡", "鍏ュ簱", "鍒拌揣", "寰呬粯娆�",
-                "浠樻", "閫�璐�", "閫�鏂�", "鍙戠エ", "鍚堝悓");
-        boolean hasIntentWord = containsAny(text,
-                "鏌ヨ", "鏌ョ湅", "缁熻", "鍒嗘瀽", "鎺掕", "鎺掑悕", "鍒楀嚭", "鏈夊摢浜�", "鎯呭喌", "鏄庣粏", "璇︽儏", "鎶ヨ〃");
-        return hasDomainWord && hasIntentWord;
-    }
-
-    private boolean containsAny(String text, String... keywords) {
-        for (String keyword : keywords) {
-            if (text.contains(keyword)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private String buildNoGuessResponse() {
-        Map<String, Object> result = new LinkedHashMap<>();
-        result.put("success", false);
-        result.put("type", "purchase_intent_not_recognized");
-        result.put("description", "鏈瘑鍒埌鍙墽琛岀殑閲囪喘鏌ヨ鏉′欢銆備负淇濊瘉缁撴灉鍑嗙‘锛屽綋鍓嶄笉浼氭帹娴嬫垨缂栭�犳暟鎹紝璇疯ˉ鍏呮槑纭椂闂磋寖鍥淬�佷緵搴斿晢銆侀噰璐悎鍚屽彿鎴栫墿鏂欏悗鍐嶆煡璇€��");
-        result.put("summary", Map.of());
-        result.put("data", Map.of(
-                "quickPrompts", List.of(
-                        "鏈湀閲囪喘閲戦鎺掑悕鍓嶅崄鐨勭墿鏂欐湁鍝簺锛�",
-                        "鍝簺閲囪喘璁㈠崟杩樻湭鍏ュ簱锛�",
-                        "鏈�杩�7澶╀緵搴斿晢鍒拌揣寮傚父鏈夊摢浜涳紵",
-                        "甯垜缁熻寰呬粯娆鹃噰璐崟锛�",
-                        "鍒楀嚭鏈湀閲囪喘閫�璐ф儏鍐�"
-                )
-        ));
-        result.put("charts", Map.of());
-        return JSON.toJSONString(result);
-    }
-
-    private String buildPurchaseFileAnalyzePrompt(String message, String fileContent) {
-        return """
-                浣犳槸閲囪喘涓氬姟鏂囦欢鍒嗘瀽鍔╂墜銆傝涓ユ牸鏍规嵁鐢ㄦ埛涓婁紶鐨勫涓枃浠跺拰鐢ㄦ埛瑕佹眰鎻愬彇閲囪喘涓氬姟鏁版嵁銆�
-
-                鐢ㄦ埛瑕佹眰:
-                %s
-
-                杈撳嚭瑕佹眰:
-                1. 鍙緭鍑哄悎娉� JSON锛屼笉瑕� Markdown锛屼笉瑕侀澶栬В閲娿��
-                2. JSON 椤跺眰瀛楁鍥哄畾涓�:
-                   - success: boolean
-                   - businessType: purchase_ledger  | purchase_return_order | unknown
-                   - action: confirm_required
-                   - description: 涓枃璇存槑
-                   - confidence: 0鍒�1鐨勫皬鏁�
-                   - missingFields: 缂哄け瀛楁涓枃鍚嶇О鏁扮粍锛岄潰鍚戝鎴峰睍绀猴紝涓嶈杈撳嚭鑻辨枃瀛楁鍚�
-                   - warnings: 椋庨櫓鎻愮ず鏁扮粍
-                   - payload: 寰呭鎴风‘璁ょ殑鏁版嵁锛屽瓧娈靛悕蹇呴』浣跨敤鍚庣 DTO 瀛楁鍚�
-                   - preview: 缁欏鎴风‘璁ょ敤鐨勪腑鏂囨憳瑕佹暟缁�
-                3. 濡傛灉鍙垽鏂负閲囪喘鍙拌处锛宐usinessType 浣跨敤 purchase_ledger锛宲ayload.purchaseLedgers 涓洪噰璐鍗�/閲囪喘鍙拌处鏁扮粍:
-                   - purchaseLedgers: 閲囪喘璁㈠崟/閲囪喘鍙拌处鏁扮粍锛屾瘡鏉¤褰曞瓧娈靛悕蹇呴』涓� PurchaseLedgerDto 淇濇寔涓�鑷�
-                   - 浜у搧鏄庣粏蹇呴』鏀惧湪姣忔潯閲囪喘鍙拌处璁板綍鐨� productData 瀛楁涓紝productData 绫诲瀷涓� List<SalesLedgerProduct>
-                   - 涓嶈浼樺厛浣跨敤 payload 椤跺眰 productData锛涢《灞� productData 浠呬綔涓烘棫鏍煎紡鍏煎
-                   - 鏂囦欢閲岀殑鈥滈噰璐崟鍙封�濆氨鏄�滈噰璐悎鍚屽彿鈥濓紝缁熶竴鏄犲皠涓� purchaseContractNumber
-                   - 鏂囦欢閲岀殑鈥滈攢鍞崟鍙封�濆氨鏄�滈攢鍞悎鍚屽彿鈥濓紝缁熶竴鏄犲皠涓� salesContractNo
-                   - 鎵�鏈夋棩鏈熷瓧娈靛繀椤讳娇鐢� yyyy-MM-dd锛屼緥濡� 2026-04-30锛涗笉瑕佽緭鍑� 4/30/26銆�2026/4/30銆�2026骞�4鏈�30鏃� 鎴栧甫鏃跺垎绉掔殑鏍煎紡
-                   - 閲囪喘鍙拌处涓嶉渶瑕佸湪 payload 涓紶瀹℃壒浜猴紝涓嶈杈撳嚭 approveUserIds銆乤pproverId
-                   - missingFields 鍙~鍐欎笟鍔″繀濉絾鏃犳硶璇嗗埆鐨勫瓧娈碉紝涓嶈鎶� PurchaseLedgerDto 鐨勬墍鏈夌┖瀛楁閮藉垪涓虹己澶憋紱缂哄け椤瑰繀椤诲啓涓枃锛屼緥濡傗�滀緵搴斿晢鍚嶇О鈥濃�滃惈绋庡崟浠封�濓紝涓嶈鍐� supplierId銆乼axInclusiveUnitPrice
-                   - 閲囪喘鍙拌处涓昏〃蹇呭~瀛楁浠呮寜杩欎簺鍒ゆ柇: purchaseContractNumber銆乻upplierName 鎴� supplierId
-                   - productData 姣忔潯浜у搧蹇呭~瀛楁: productCategory銆乻pecificationModel銆乽nit銆乹uantity銆乼axInclusiveUnitPrice 鎴� taxInclusiveTotalPrice锛涘鏋滃彧鏈夊惈绋庢�讳环鍜屾暟閲忥紝蹇呴』璁$畻 taxInclusiveUnitPrice锛涘鏋滃彧鏈夊惈绋庡崟浠峰拰鏁伴噺锛屽繀椤昏绠� taxInclusiveTotalPrice
-                   - 浜у搧瀛楁鎸夐噰璐鍏ユ帴鍙� PurchaseLedgerProductImportDto 瀵归綈: 閲囪喘鍗曞彿銆佷骇鍝佸ぇ绫汇�佽鏍煎瀷鍙枫�佸崟浣嶃�佹暟閲忋�佺◣鐜囥�佸惈绋庡崟浠枫�佸惈绋庢�讳环銆佸彂绁ㄧ被鍨嬨�佹槸鍚﹁川妫�
-                   - 閲囪喘浜у搧 type 鍥哄畾涓� 2
-                   - purchaseLedgers 姣忔潯璁板綍鍙娇鐢ㄨ繖浜� PurchaseLedgerDto 瀛楁鍚�:
-                     entryDateStart, entryDateEnd, id, purchaseContractNumber, supplierId, supplierName, isWhite, recorderId, recorderName, salesContractNo, salesContractNoId, projectName, entryDate, executionDate, remarks, attachmentMaterials, createdAt, updatedAt, salesLedgerId, hasChildren, Type, productData, tempFileIds, SalesLedgerFiles, phoneNumber, businessPersonId, productId, productModelId, invoiceNumber, invoiceAmount, ticketRegistrationId, contractAmount, receiptPaymentAmount, unReceiptPaymentAmount, type, paymentMethod, approvalStatus, templateName
-                   - productData 姣忔潯浜у搧鍙娇鐢ㄨ繖浜� SalesLedgerProduct 瀛楁鍚�:
-                     productCategory, specificationModel, unit, quantity, taxRate, taxInclusiveUnitPrice, taxInclusiveTotalPrice, taxExclusiveTotalPrice, invoiceType, productId, productModelId, isChecked, type
-                4. 濡傛灉鍙垽鏂负浠樻鐧昏锛宐usinessType 浣跨敤 payload.records 涓轰粯娆剧櫥璁版暟缁勶紝瀛楁灏介噺鍖呭惈 purchaseLedgerId銆乻alesLedgerProductId銆乧urrentPaymentAmount銆乸aymentMethod銆乸aymentDate銆�
-                5. 濡傛灉鍙垽鏂负閲囪喘閫�璐э紝businessType 浣跨敤 purchase_return_order锛宲ayload 鎸� PurchaseReturnOrderDto 缁勭粐锛屾槑缁嗘斁 purchaseReturnOrderProductsDtos銆�
-                6. 缂哄皯涓氬姟澶勭悊蹇呴』瀛楁鏃讹紝涓嶈缂栭�� ID锛屾妸瀛楁鏀惧叆 missingFields锛屽苟浠嶈繑鍥炲彲纭鐨勮崏绋挎暟鎹��
-                7. 鎵�鏈変腑鏂囧唴瀹圭洿鎺ヤ繚鐣欙紝涓嶈杞箟鎴� Unicode銆�
-
-                鏂囦欢鍐呭:
-                %s
-                """.formatted(message, fileContent);
-    }
-
-    private AjaxResult processPurchaseLedger(Map<String, Object> payload) throws Exception {
-        if (payload.containsKey("purchaseLedgers")) {
-            return processPurchaseLedgerBatch(payload);
-        }
-
-        Map<String, Object> normalizedPayload = normalizePurchaseLedgerMap(payload);
-        PurchaseLedgerDto dto = objectMapper.convertValue(normalizedPayload, PurchaseLedgerDto.class);
-        AjaxResult ledgerResult = validatePurchaseLedger(dto, 0);
-        if (ledgerResult != null) {
-            return ledgerResult;
-        }
-        AjaxResult supplierResult = fillSupplierIdByName(dto);
-        if (supplierResult != null) {
-            return supplierResult;
-        }
-        AjaxResult productResult = validatePurchaseProducts(dto.getProductData(), 0);
-        if (productResult != null) {
-            return productResult;
-        }
-        int result = purchaseLedgerService.addOrEditPurchase(dto);
-        return AjaxResult.success("閲囪喘鍙拌处宸插鐞�", result);
-    }
-
-    private AjaxResult processPurchaseLedgerBatch(Map<String, Object> payload) throws Exception {
-        List<Map<String, Object>> purchaseLedgers = toMapList(payload.get("purchaseLedgers"));
-        if (purchaseLedgers.isEmpty()) {
-            return AjaxResult.error("purchaseLedgers涓嶈兘涓虹┖");
-        }
-
-        List<Map<String, Object>> topLevelProductData = toMapList(payload.get("productData"));
-        List<Map<String, Object>> results = new ArrayList<>();
-        for (int i = 0; i < purchaseLedgers.size(); i++) {
-            Map<String, Object> ledgerMap = normalizePurchaseLedgerMap(purchaseLedgers.get(i));
-            PurchaseLedgerDto dto = objectMapper.convertValue(ledgerMap, PurchaseLedgerDto.class);
-            AjaxResult ledgerResult = validatePurchaseLedger(dto, i);
-            if (ledgerResult != null) {
-                return ledgerResult;
-            }
-            AjaxResult supplierResult = fillSupplierIdByName(dto);
-            if (supplierResult != null) {
-                return supplierResult;
-            }
-
-            List<SalesLedgerProduct> products = dto.getProductData();
-            if (products == null || products.isEmpty()) {
-                products = matchProductsForLedger(ledgerMap, dto, topLevelProductData, purchaseLedgers.size() == 1);
-                dto.setProductData(products);
-            }
-            AjaxResult productResult = validatePurchaseProducts(products, i);
-            if (productResult != null) {
-                return productResult;
-            }
-            int result = purchaseLedgerService.addOrEditPurchase(dto);
-
-            Map<String, Object> item = new LinkedHashMap<>();
-            item.put("index", i);
-            item.put("purchaseContractNumber", dto.getPurchaseContractNumber());
-            item.put("supplierId", dto.getSupplierId());
-            item.put("supplierName", dto.getSupplierName());
-            item.put("productCount", products.size());
-            item.put("result", result);
-            results.add(item);
-        }
-        return AjaxResult.success("閲囪喘鍙拌处宸叉壒閲忓鐞�", results);
-    }
-
-    private List<SalesLedgerProduct> matchProductsForLedger(Map<String, Object> ledgerMap,
-                                                            PurchaseLedgerDto dto,
-                                                            List<Map<String, Object>> productData,
-                                                            boolean onlyOneLedger) {
-        List<SalesLedgerProduct> products = new ArrayList<>();
-        for (Map<String, Object> productMap : productData) {
-            if (onlyOneLedger || productBelongsToLedger(productMap, ledgerMap, dto)) {
-                products.add(objectMapper.convertValue(normalizeSalesLedgerProductMap(productMap), SalesLedgerProduct.class));
-            }
-        }
-        return products;
-    }
-
-    private boolean productBelongsToLedger(Map<String, Object> productMap, Map<String, Object> ledgerMap, PurchaseLedgerDto dto) {
-        Long productPurchaseLedgerId = longValue(productMap, "purchaseLedgerId", "purchaseId", "閲囪喘璁㈠崟id", "閲囪喘鍙拌处id");
-        if (productPurchaseLedgerId != null && dto.getId() != null && productPurchaseLedgerId.equals(dto.getId())) {
-            return true;
-        }
-
-        Long productSalesLedgerId = longValue(productMap, "salesLedgerId");
-        if (productSalesLedgerId != null && dto.getId() != null && productSalesLedgerId.equals(dto.getId())) {
-            return true;
-        }
-
-        String productContractNo = stringValue(productMap, "purchaseContractNumber", "purchaseContractNo", "閲囪喘鍚堝悓鍙�", "閲囪喘鍗曞彿", "閲囪喘璁㈠崟鍙�");
-        if (StringUtils.hasText(productContractNo)
-                && StringUtils.hasText(dto.getPurchaseContractNumber())
-                && productContractNo.trim().equals(dto.getPurchaseContractNumber().trim())) {
-            return true;
-        }
-
-        String ledgerContractNo = stringValue(ledgerMap, "purchaseContractNumber", "purchaseContractNo", "閲囪喘鍚堝悓鍙�", "閲囪喘鍗曞彿", "閲囪喘璁㈠崟鍙�");
-        if (StringUtils.hasText(productContractNo)
-                && StringUtils.hasText(ledgerContractNo)
-                && productContractNo.trim().equals(ledgerContractNo.trim())) {
-            return true;
-        }
-
-        String productSalesContractNo = stringValue(productMap, "salesContractNo", "salesContractNumber", "閿�鍞悎鍚屽彿", "閿�鍞崟鍙�", "閿�鍞鍗曞彿");
-        if (StringUtils.hasText(productSalesContractNo)
-                && StringUtils.hasText(dto.getSalesContractNo())
-                && productSalesContractNo.trim().equals(dto.getSalesContractNo().trim())) {
-            return true;
-        }
-
-        String ledgerSalesContractNo = stringValue(ledgerMap, "salesContractNo", "salesContractNumber", "閿�鍞悎鍚屽彿", "閿�鍞崟鍙�", "閿�鍞鍗曞彿");
-        if (StringUtils.hasText(productSalesContractNo)
-                && StringUtils.hasText(ledgerSalesContractNo)
-                && productSalesContractNo.trim().equals(ledgerSalesContractNo.trim())) {
-            return true;
-        }
-
-        String productSupplierName = stringValue(productMap, "supplierName", "渚涘簲鍟嗗悕绉�");
-        return StringUtils.hasText(productSupplierName)
-                && StringUtils.hasText(dto.getSupplierName())
-                && productSupplierName.trim().equals(dto.getSupplierName().trim());
-    }
-
-    private Map<String, Object> normalizePurchaseLedgerMap(Map<String, Object> source) {
-        Map<String, Object> target = new LinkedHashMap<>();
-        copyPurchaseLedgerDtoFields(source, target);
-        putDtoFieldIfPresent(source, target, "entryDateStart", "褰曞叆寮�濮嬫棩鏈�", "褰曞叆鏃ユ湡寮�濮�");
-        putDtoFieldIfPresent(source, target, "entryDateEnd", "褰曞叆缁撴潫鏃ユ湡", "褰曞叆鏃ユ湡缁撴潫");
-        putDtoFieldIfPresent(source, target, "id", "閲囪喘鍙拌处id", "閲囪喘璁㈠崟id", "涓婚敭");
-        putDtoFieldIfPresent(source, target, "purchaseContractNumber", "purchaseContractNo", "閲囪喘鍚堝悓鍙�", "閲囪喘鍗曞彿", "閲囪喘璁㈠崟鍙�");
-        putDtoFieldIfPresent(source, target, "supplierId", "渚涘簲鍟唅d", "渚涘簲鍟咺D", "渚涘簲鍟嗗悕绉癷d", "渚涘簲鍟嗗悕绉癐D");
-        putDtoFieldIfPresent(source, target, "supplierName", "渚涘簲鍟�", "渚涘簲鍟嗗悕绉�");
-        putDtoFieldIfPresent(source, target, "isWhite", "鏄惁鐧藉悕鍗�");
-        putDtoFieldIfPresent(source, target, "recorderId", "褰曞叆浜篿d", "褰曞叆浜篒D", "褰曞叆浜哄鍚峣d", "褰曞叆浜哄鍚岻D");
-        putDtoFieldIfPresent(source, target, "recorderName", "褰曞叆浜�", "褰曞叆浜哄鍚�");
-        putDtoFieldIfPresent(source, target, "salesContractNo", "salesContractNumber", "閿�鍞悎鍚屽彿", "閿�鍞崟鍙�", "閿�鍞鍗曞彿");
-        putDtoFieldIfPresent(source, target, "salesContractNoId", "閿�鍞悎鍚屽彿id", "閿�鍞悎鍚屽彿ID", "閿�鍞崟鍙穒d", "閿�鍞崟鍙稩D");
-        putDtoFieldIfPresent(source, target, "projectName", "椤圭洰", "椤圭洰鍚嶇О");
-        putDtoFieldIfPresent(source, target, "entryDate", "褰曞叆鏃ユ湡");
-        putDtoFieldIfPresent(source, target, "executionDate", "绛捐鏃ユ湡", "鍚堝悓绛捐鏃ユ湡");
-        putDtoFieldIfPresent(source, target, "remarks", "澶囨敞", "璇存槑");
-        putDtoFieldIfPresent(source, target, "attachmentMaterials", "闄勪欢鏉愭枡", "闄勪欢鏉愭枡璺緞鎴栧悕绉�");
-        putDtoFieldIfPresent(source, target, "createdAt", "鍒涘缓鏃堕棿", "璁板綍鍒涘缓鏃堕棿");
-        putDtoFieldIfPresent(source, target, "updatedAt", "鏇存柊鏃堕棿", "璁板綍鏈�鍚庢洿鏂版椂闂�");
-        putDtoFieldIfPresent(source, target, "salesLedgerId", "閿�鍞彴璐d", "閿�鍞彴璐D", "鍏宠仈閿�鍞彴璐︿富琛ㄤ富閿�");
-        putDtoFieldIfPresent(source, target, "hasChildren", "鏄惁鏈夊瓙绾�", "鏄惁鏈夋槑缁�");
-        putDtoFieldIfPresent(source, target, "Type", "鍙拌处绫诲瀷", "涓氬姟绫诲瀷");
-        putDtoFieldIfPresent(source, target, "productData", "products", "浜у搧鏄庣粏", "閲囪喘浜у搧鏄庣粏");
-        putDtoFieldIfPresent(source, target, "tempFileIds", "涓存椂鏂囦欢id", "涓存椂鏂囦欢ID", "涓存椂鏂囦欢ids");
-        putDtoFieldIfPresent(source, target, "SalesLedgerFiles", "闄勪欢鍒楄〃", "閿�鍞彴璐﹂檮浠�");
-        putDtoFieldIfPresent(source, target, "phoneNumber", "涓氬姟鍛樻墜鏈哄彿", "鎵嬫満鍙�");
-        putDtoFieldIfPresent(source, target, "businessPersonId", "涓氬姟鍛榠d", "涓氬姟鍛業D");
-        putDtoFieldIfPresent(source, target, "productId", "浜у搧id", "浜у搧ID");
-        putDtoFieldIfPresent(source, target, "productModelId", "浜у搧瑙勬牸id", "浜у搧瑙勬牸ID");
-        putDtoFieldIfPresent(source, target, "invoiceNumber", "鍙戠エ鍙�", "鍙戠エ鍙风爜");
-        putDtoFieldIfPresent(source, target, "invoiceAmount", "鍙戠エ閲戦", "鍙戠エ閲戦锛堝厓锛�");
-        putDtoFieldIfPresent(source, target, "ticketRegistrationId", "鏉ョエ鐧昏id", "鏉ョエ鐧昏ID");
-        putDtoFieldIfPresent(source, target, "contractAmount", "鍚堝悓閲戦", "鍚堝悓閲戦锛堜骇鍝佸惈绋庢�讳环锛�");
-        putDtoFieldIfPresent(source, target, "receiptPaymentAmount", "鏉ョエ閲戦", "宸叉潵绁ㄩ噾棰�", "宸叉潵绁ㄩ噾棰�(鍏�)");
-        putDtoFieldIfPresent(source, target, "unReceiptPaymentAmount", "鏈潵绁ㄩ噾棰�", "鏈潵绁ㄩ噾棰�(鍏�)");
-        putDtoFieldIfPresent(source, target, "type", "鏂囦欢绫诲瀷");
-        putDtoFieldIfPresent(source, target, "paymentMethod", "浠樻鏂瑰紡");
-        putDtoFieldIfPresent(source, target, "approvalStatus", "瀹℃壒鐘舵��");
-        putDtoFieldIfPresent(source, target, "templateName", "妯℃澘鍚嶇О");
-        target.remove("approveUserIds");
-        target.remove("approverId");
-        normalizeNestedProductData(target);
-        attachImportStyleProductData(source, target);
-        if (target.get("type") == null) {
-            target.put("type", 2);
-        }
-        target.putIfAbsent("entryDate", LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE));
-        normalizePurchaseLedgerDateFields(target);
-        return target;
-    }
-
-    private void attachImportStyleProductData(Map<String, Object> source, Map<String, Object> target) {
-        if (target.get("productData") != null) {
-            return;
-        }
-        Map<String, Object> productMap = normalizeSalesLedgerProductMap(source);
-        if (hasImportStyleProductData(productMap)) {
-            target.put("productData", List.of(productMap));
-        }
-    }
-
-    private boolean hasImportStyleProductData(Map<String, Object> productMap) {
-        return hasMapText(productMap, "productCategory")
-                || hasMapText(productMap, "specificationModel")
-                || productMap.get("quantity") != null
-                || productMap.get("taxInclusiveUnitPrice") != null
-                || productMap.get("taxInclusiveTotalPrice") != null;
-    }
-
-    private boolean hasMapText(Map<String, Object> map, String key) {
-        Object value = map.get(key);
-        return value != null && StringUtils.hasText(String.valueOf(value));
-    }
-
-    private void normalizeNestedProductData(Map<String, Object> target) {
-        Object productDataValue = target.get("productData");
-        if (productDataValue == null) {
-            return;
-        }
-        List<Map<String, Object>> productMaps = toMapList(productDataValue);
-        List<Map<String, Object>> normalizedProducts = new ArrayList<>();
-        for (Map<String, Object> productMap : productMaps) {
-            normalizedProducts.add(normalizeSalesLedgerProductMap(productMap));
-        }
-        target.put("productData", normalizedProducts);
-    }
-
-    private Map<String, Object> normalizeSalesLedgerProductMap(Map<String, Object> source) {
-        Map<String, Object> target = new LinkedHashMap<>();
-        copySalesLedgerProductFields(source, target);
-        putDtoFieldIfPresent(source, target, "productCategory", "浜у搧澶х被", "浜у搧鍚嶇О", "浜у搧", "鍝佸悕", "鐗╂枡鍚嶇О");
-        putDtoFieldIfPresent(source, target, "specificationModel", "瑙勬牸鍨嬪彿", "鍨嬪彿", "瑙勬牸", "浜у搧瑙勬牸");
-        putDtoFieldIfPresent(source, target, "unit", "鍗曚綅");
-        putDtoFieldIfPresent(source, target, "quantity", "鏁伴噺", "閲囪喘鏁伴噺");
-        putDtoFieldIfPresent(source, target, "taxRate", "绋庣巼");
-        putDtoFieldIfPresent(source, target, "taxInclusiveUnitPrice", "鍚◣鍗曚环", "鍗曚环", "閲囪喘鍗曚环", "鍚◣浠锋牸");
-        putDtoFieldIfPresent(source, target, "taxInclusiveTotalPrice", "鍚◣鎬讳环", "鎬讳环", "閲囪喘閲戦", "閲戦", "鍚堝悓閲戦");
-        putDtoFieldIfPresent(source, target, "taxExclusiveTotalPrice", "涓嶅惈绋庢�讳环");
-        putDtoFieldIfPresent(source, target, "invoiceType", "鍙戠エ绫诲瀷", "鍙戠エ绫诲埆");
-        putDtoFieldIfPresent(source, target, "productId", "浜у搧id", "浜у搧ID");
-        putDtoFieldIfPresent(source, target, "productModelId", "浜у搧瑙勬牸id", "浜у搧瑙勬牸ID", "鍨嬪彿id", "鍨嬪彿ID");
-        putDtoFieldIfPresent(source, target, "isChecked", "鏄惁璐ㄦ", "鏄惁璐ㄦ楠�", "璐ㄦ");
-        putDtoFieldIfPresent(source, target, "type", "鍙拌处绫诲瀷");
-        normalizeProductAmounts(target);
-        target.putIfAbsent("type", 2);
-        return target;
-    }
-
-    private void copySalesLedgerProductFields(Map<String, Object> source, Map<String, Object> target) {
-        String[] productFields = {
-                "id", "salesLedgerId", "warnNum", "productCategory", "specificationModel", "unit",
-                "speculativeTradingName", "quantity", "minStock", "taxRate", "taxInclusiveUnitPrice",
-                "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", "invoiceType", "type", "ticketsNum",
-                "ticketsAmount", "futureTickets", "futureTicketsAmount", "invoiceNum", "noInvoiceNum",
-                "invoiceAmount", "noInvoiceAmount", "productId", "productModelId", "register", "registerDate",
-                "approveStatus", "pendingInvoiceTotal", "invoiceTotal", "pendingTicketsTotal", "ticketsTotal",
-                "isChecked", "isProduction"
-        };
-        for (String field : productFields) {
-            if (source.containsKey(field)) {
-                target.put(field, source.get(field));
-            }
-        }
-    }
-
-    private void normalizeProductAmounts(Map<String, Object> target) {
-        BigDecimal quantity = decimalValue(target.get("quantity"));
-        BigDecimal unitPrice = decimalValue(target.get("taxInclusiveUnitPrice"));
-        BigDecimal totalPrice = decimalValue(target.get("taxInclusiveTotalPrice"));
-        if (unitPrice == null && totalPrice != null && quantity != null && quantity.compareTo(BigDecimal.ZERO) != 0) {
-            target.put("taxInclusiveUnitPrice", totalPrice.divide(quantity, 6, RoundingMode.HALF_UP));
-        }
-        if (totalPrice == null && unitPrice != null && quantity != null) {
-            target.put("taxInclusiveTotalPrice", unitPrice.multiply(quantity));
-        }
-        BigDecimal taxRate = decimalValue(target.get("taxRate"));
-        totalPrice = decimalValue(target.get("taxInclusiveTotalPrice"));
-        if (target.get("taxExclusiveTotalPrice") == null && totalPrice != null && taxRate != null) {
-            BigDecimal divisor = BigDecimal.ONE.add(taxRate.divide(new BigDecimal("100"), 6, RoundingMode.HALF_UP));
-            target.put("taxExclusiveTotalPrice", totalPrice.divide(divisor, 2, RoundingMode.HALF_UP));
-        }
-    }
-
-    private AjaxResult validatePurchaseProducts(List<SalesLedgerProduct> products, int ledgerIndex) {
-        if (products == null || products.isEmpty()) {
-            return null;
-        }
-        for (int i = 0; i < products.size(); i++) {
-            SalesLedgerProduct product = products.get(i);
-            String prefix = "绗�" + (ledgerIndex + 1) + "涓噰璐彴璐︾殑绗�" + (i + 1) + "鏉′骇鍝�";
-            if (!StringUtils.hasText(product.getProductCategory())) {
-                return AjaxResult.error(prefix + "缂哄皯浜у搧鍚嶇О锛岃琛ュ厖鍚庡啀纭");
-            }
-            if (!StringUtils.hasText(product.getSpecificationModel())) {
-                return AjaxResult.error(prefix + "缂哄皯瑙勬牸鍨嬪彿锛岃琛ュ厖鍚庡啀纭");
-            }
-            if (!StringUtils.hasText(product.getUnit())) {
-                return AjaxResult.error(prefix + "缂哄皯鍗曚綅锛岃琛ュ厖鍚庡啀纭");
-            }
-            if (product.getQuantity() == null) {
-                return AjaxResult.error(prefix + "缂哄皯鏁伴噺");
-            }
-            if (product.getTaxInclusiveUnitPrice() == null) {
-                return AjaxResult.error(prefix + "缂哄皯鍚◣鍗曚环锛岃琛ュ厖鍚庡啀纭");
-            }
-            if (product.getTaxInclusiveTotalPrice() == null) {
-                return AjaxResult.error(prefix + "缂哄皯鍚◣鎬讳环锛岃琛ュ厖鍚庡啀纭");
-            }
-        }
-        return null;
-    }
-
-    private AjaxResult validatePurchaseLedger(PurchaseLedgerDto dto, int ledgerIndex) {
-        String prefix = "绗�" + (ledgerIndex + 1) + "涓噰璐彴璐�";
-        if (!StringUtils.hasText(dto.getPurchaseContractNumber())) {
-            return AjaxResult.error(prefix + "缂哄皯閲囪喘鍚堝悓鍙凤紝璇疯ˉ鍏呭悗鍐嶇‘璁�");
-        }
-        if (dto.getSupplierId() == null && !StringUtils.hasText(dto.getSupplierName())) {
-            return AjaxResult.error(prefix + "缂哄皯渚涘簲鍟嗗悕绉帮紝璇疯ˉ鍏呭悗鍐嶇‘璁�");
-        }
-        return null;
-    }
-
-    private void normalizePurchaseLedgerDateFields(Map<String, Object> target) {
-        normalizeDateField(target, "entryDate");
-        normalizeDateField(target, "executionDate");
-        normalizeDateField(target, "createdAt");
-        normalizeDateField(target, "updatedAt");
-    }
-
-    private void normalizeDateField(Map<String, Object> target, String fieldName) {
-        Object value = target.get(fieldName);
-        if (value == null) {
-            return;
-        }
-        String normalizedDate = normalizeDateValue(value);
-        if (StringUtils.hasText(normalizedDate)) {
-            target.put(fieldName, normalizedDate);
-        }
-    }
-
-    private String normalizeDateValue(Object value) {
-        if (value instanceof Date date) {
-            return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(DateTimeFormatter.ISO_LOCAL_DATE);
-        }
-        if (value instanceof Number number) {
-            return LocalDate.of(1899, 12, 30)
-                    .plusDays(number.longValue())
-                    .format(DateTimeFormatter.ISO_LOCAL_DATE);
-        }
-
-        String text = String.valueOf(value).trim();
-        if (!StringUtils.hasText(text)) {
-            return null;
-        }
-        if (text.length() >= 10 && text.charAt(4) == '-' && text.charAt(7) == '-') {
-            return text.substring(0, 10);
-        }
-
-        String normalizedText = text.replace("骞�", "-")
-                .replace("鏈�", "-")
-                .replace("鏃�", "")
-                .replace(".", "-")
-                .replace("/", "-")
-                .trim();
-        DateTimeFormatter[] formatters = {
-                DateTimeFormatter.ofPattern("yyyy-M-d"),
-                DateTimeFormatter.ofPattern("M-d-yyyy"),
-                DateTimeFormatter.ofPattern("M-d-yy")
-        };
-        for (DateTimeFormatter formatter : formatters) {
-            try {
-                return LocalDate.parse(normalizedText, formatter).format(DateTimeFormatter.ISO_LOCAL_DATE);
-            } catch (DateTimeParseException ignored) {
-                // Try the next supported input pattern.
-            }
-        }
-        return text;
-    }
-
-    private void copyPurchaseLedgerDtoFields(Map<String, Object> source, Map<String, Object> target) {
-        String[] dtoFields = {
-                "entryDateStart", "entryDateEnd", "id", "purchaseContractNumber",
-                "supplierId", "supplierName", "isWhite", "recorderId", "recorderName", "salesContractNo",
-                "salesContractNoId", "projectName", "entryDate", "executionDate", "remarks", "attachmentMaterials",
-                "createdAt", "updatedAt", "salesLedgerId", "hasChildren", "Type", "productData", "tempFileIds",
-                "SalesLedgerFiles", "phoneNumber", "businessPersonId", "productId", "productModelId", "invoiceNumber",
-                "invoiceAmount", "ticketRegistrationId", "contractAmount", "receiptPaymentAmount",
-                "unReceiptPaymentAmount", "type", "paymentMethod", "approvalStatus", "templateName"
-        };
-        for (String field : dtoFields) {
-            if (source.containsKey(field)) {
-                target.put(field, source.get(field));
-            }
-        }
-    }
-
-    private void putDtoFieldIfPresent(Map<String, Object> source, Map<String, Object> target, String dtoField, String... aliases) {
-        if (target.containsKey(dtoField) && target.get(dtoField) != null) {
-            return;
-        }
-        for (String alias : aliases) {
-            Object value = source.get(alias);
-            if (value != null && StringUtils.hasText(String.valueOf(value))) {
-                target.put(dtoField, value);
-                return;
-            }
-        }
-    }
-
-    private List<Map<String, Object>> toMapList(Object value) {
-        if (value == null) {
-            return List.of();
-        }
-        return objectMapper.convertValue(value, new TypeReference<List<Map<String, Object>>>() {
-        });
-    }
-
-    private String stringValue(Map<String, Object> map, String... keys) {
-        for (String key : keys) {
-            Object value = map.get(key);
-            if (value != null && StringUtils.hasText(String.valueOf(value))) {
-                return String.valueOf(value);
-            }
-        }
-        return null;
-    }
-
-    private Long longValue(Map<String, Object> map, String... keys) {
-        String value = stringValue(map, keys);
-        if (!StringUtils.hasText(value)) {
-            return null;
-        }
-        try {
-            return Long.parseLong(value.trim());
-        } catch (NumberFormatException ignored) {
-            return null;
-        }
-    }
-
-    private BigDecimal decimalValue(Object value) {
-        if (value == null) {
-            return null;
-        }
-        if (value instanceof BigDecimal decimal) {
-            return decimal;
-        }
-        if (value instanceof Number number) {
-            return new BigDecimal(String.valueOf(number));
-        }
-        String text = String.valueOf(value)
-                .replace(",", "")
-                .replace("锛�", "")
-                .replace("鍏�", "")
-                .replace("锟�", "")
-                .trim();
-        if (!StringUtils.hasText(text)) {
-            return null;
-        }
-        try {
-            return new BigDecimal(text);
-        } catch (NumberFormatException ignored) {
-            return null;
-        }
-    }
-
-    private String toCustomerMessage(Exception ex) {
-        String message = ex.getMessage();
-        if (!StringUtils.hasText(message)) {
-            return "澶勭悊澶辫触锛岃妫�鏌ョ‘璁ゆ暟鎹悗閲嶈瘯";
-        }
-        if (message.contains("tax_inclusive_unit_price")) {
-            return "澶勭悊澶辫触锛氫骇鍝佹槑缁嗙己灏戝惈绋庡崟浠凤紝璇疯ˉ鍏呭悗鍐嶇‘璁�";
-        }
-        if (message.contains("tax_inclusive_total_price")) {
-            return "澶勭悊澶辫触锛氫骇鍝佹槑缁嗙己灏戝惈绋庢�讳环锛岃琛ュ厖鍚庡啀纭";
-        }
-        if (message.contains("entryDate")) {
-            return "澶勭悊澶辫触锛氬綍鍏ユ棩鏈熸牸寮忎笉姝g‘锛岃浣跨敤 yyyy-MM-dd锛屼緥濡� 2026-04-30";
-        }
-        if (message.contains("supplier")) {
-            return "澶勭悊澶辫触锛氫緵搴斿晢淇℃伅涓嶅畬鏁达紝璇风‘璁や緵搴斿晢鍚嶇О鎴栦緵搴斿晢ID";
-        }
-        if (message.contains("SQL") || message.contains("java.") || message.contains("Exception")) {
-            return "澶勭悊澶辫触锛氱‘璁ゆ暟鎹笉瀹屾暣鎴栨牸寮忎笉姝g‘锛岃妫�鏌ュ繀濉瓧娈靛悗閲嶈瘯";
-        }
-        return "澶勭悊澶辫触锛�" + message;
-    }
-
-    private AjaxResult fillSupplierIdByName(PurchaseLedgerDto dto) {
-        if (dto.getSupplierId() != null) {
-            return null;
-        }
-        if (!StringUtils.hasText(dto.getSupplierName())) {
-            return AjaxResult.error("渚涘簲鍟咺D涓嶈兘涓虹┖锛涙湭璇嗗埆鍒颁緵搴斿晢鍚嶇О锛屾棤娉曡嚜鍔ㄥ尮閰嶄緵搴斿晢ID");
-        }
-
-        SupplierManage supplier = supplierManageMapper.selectOne(new LambdaQueryWrapper<SupplierManage>()
-                .eq(SupplierManage::getSupplierName, dto.getSupplierName().trim())
-                .last("limit 1"));
-        if (supplier == null) {
-            return AjaxResult.error("鏈壘鍒颁緵搴斿晢锛�" + dto.getSupplierName() + "锛岃鍏堢淮鎶や緵搴斿晢鎴栨墜鍔ㄩ�夋嫨渚涘簲鍟咺D");
-        }
-        dto.setSupplierId(supplier.getId());
-        return null;
-    }
-
-    private AjaxResult processPurchaseReturnOrder(Map<String, Object> payload) {
-        PurchaseReturnOrderDto dto = objectMapper.convertValue(payload, PurchaseReturnOrderDto.class);
-        Boolean result = purchaseReturnOrdersService.add(dto);
-        return AjaxResult.success("閲囪喘閫�璐у崟宸插鐞�", result);
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/service/impl/AiChatSessionServiceImpl.java b/src/main/java/com/ruoyi/ai/service/impl/AiChatSessionServiceImpl.java
deleted file mode 100644
index 0ea436d..0000000
--- a/src/main/java/com/ruoyi/ai/service/impl/AiChatSessionServiceImpl.java
+++ /dev/null
@@ -1,212 +0,0 @@
-package com.ruoyi.ai.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.ai.dto.AiChatMessageDto;
-import com.ruoyi.ai.dto.AiChatSessionDto;
-import com.ruoyi.ai.mapper.AiChatSessionMapper;
-import com.ruoyi.ai.pojo.AiChatSession;
-import com.ruoyi.ai.service.AiChatSessionService;
-import com.ruoyi.ai.store.MongoChatMemoryStore;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.security.LoginUser;
-import dev.langchain4j.data.message.AiMessage;
-import dev.langchain4j.data.message.ChatMessage;
-import dev.langchain4j.data.message.SystemMessage;
-import dev.langchain4j.data.message.ToolExecutionResultMessage;
-import dev.langchain4j.data.message.UserMessage;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
-
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Service
-@RequiredArgsConstructor
-public class AiChatSessionServiceImpl extends ServiceImpl<AiChatSessionMapper, AiChatSession> implements AiChatSessionService {
-
-    private static final int TITLE_MAX_LENGTH = 40;
-    private static final int LAST_MESSAGE_MAX_LENGTH = 300;
-
-    private final MongoChatMemoryStore mongoChatMemoryStore;
-
-    @Override
-    public void touchSession(String memoryId, LoginUser loginUser, String userMessage) {
-        if (!StringUtils.hasText(memoryId) || loginUser == null || loginUser.getUserId() == null) {
-            return;
-        }
-        Date now = new Date();
-        AiChatSession session = getSession(memoryId, loginUser.getUserId(), loginUser.getTenantId());
-        if (session == null) {
-            AiChatSession add = new AiChatSession();
-            add.setMemoryId(memoryId);
-            add.setUserId(loginUser.getUserId());
-            add.setTenantId(loginUser.getTenantId());
-            add.setTitle(buildTitle(userMessage));
-            add.setLastMessage(trimText(userMessage, LAST_MESSAGE_MAX_LENGTH));
-            add.setMessageCount(0);
-            add.setLastChatTime(now);
-            add.setCreateTime(now);
-            add.setUpdateTime(now);
-            save(add);
-            return;
-        }
-
-        AiChatSession update = new AiChatSession();
-        update.setId(session.getId());
-        if (!StringUtils.hasText(session.getTitle())) {
-            update.setTitle(buildTitle(userMessage));
-        }
-        update.setLastMessage(trimText(userMessage, LAST_MESSAGE_MAX_LENGTH));
-        update.setLastChatTime(now);
-        update.setUpdateTime(now);
-        updateById(update);
-    }
-
-    @Override
-    public void refreshSessionStats(String memoryId, LoginUser loginUser) {
-        if (!StringUtils.hasText(memoryId) || loginUser == null || loginUser.getUserId() == null) {
-            return;
-        }
-        AiChatSession session = getSession(memoryId, loginUser.getUserId(), loginUser.getTenantId());
-        if (session == null) {
-            return;
-        }
-        List<ChatMessage> messages = mongoChatMemoryStore.getMessages(memoryId);
-        AiChatSession update = new AiChatSession();
-        update.setId(session.getId());
-        update.setMessageCount(messages.size());
-        update.setLastMessage(trimText(lastMessageText(messages), LAST_MESSAGE_MAX_LENGTH));
-        update.setLastChatTime(new Date());
-        update.setUpdateTime(new Date());
-        updateById(update);
-    }
-
-    @Override
-    public List<AiChatSessionDto> listCurrentUserSessions(LoginUser loginUser) {
-        if (loginUser == null || loginUser.getUserId() == null) {
-            return new LinkedList<>();
-        }
-        LambdaQueryWrapper<AiChatSession> queryWrapper = new LambdaQueryWrapper<AiChatSession>()
-                .eq(AiChatSession::getUserId, loginUser.getUserId())
-                .orderByDesc(AiChatSession::getLastChatTime);
-        applyTenantCondition(queryWrapper, loginUser.getTenantId());
-        return list(queryWrapper).stream().map(item -> {
-            AiChatSessionDto dto = new AiChatSessionDto();
-            dto.setMemoryId(item.getMemoryId());
-            dto.setTitle(item.getTitle());
-            dto.setLastMessage(item.getLastMessage());
-            dto.setMessageCount(item.getMessageCount());
-            dto.setLastChatTime(item.getLastChatTime());
-            return dto;
-        }).collect(Collectors.toList());
-    }
-
-    @Override
-    public List<AiChatMessageDto> listCurrentUserMessages(String memoryId, LoginUser loginUser) {
-        if (!StringUtils.hasText(memoryId) || loginUser == null || loginUser.getUserId() == null) {
-            return new LinkedList<>();
-        }
-        AiChatSession session = getSession(memoryId, loginUser.getUserId(), loginUser.getTenantId());
-        if (session == null) {
-            return new LinkedList<>();
-        }
-        List<ChatMessage> messages = mongoChatMemoryStore.getMessages(memoryId);
-        List<AiChatMessageDto> messageDtos = messages.stream().map(this::convertMessage).collect(Collectors.toList());
-        List<List<String>> analyzeFilePathGroups = mongoChatMemoryStore.getAnalyzeFilePathGroups(memoryId);
-        attachAnalyzeFilePaths(messageDtos, analyzeFilePathGroups);
-        return messageDtos;
-    }
-
-    @Override
-    public boolean deleteCurrentUserSession(String memoryId, LoginUser loginUser) {
-        if (!StringUtils.hasText(memoryId) || loginUser == null || loginUser.getUserId() == null) {
-            return false;
-        }
-        LambdaQueryWrapper<AiChatSession> queryWrapper = new LambdaQueryWrapper<AiChatSession>()
-                .eq(AiChatSession::getMemoryId, memoryId)
-                .eq(AiChatSession::getUserId, loginUser.getUserId());
-        applyTenantCondition(queryWrapper, loginUser.getTenantId());
-        boolean removed = remove(queryWrapper);
-        mongoChatMemoryStore.deleteMessages(memoryId);
-        return removed;
-    }
-
-    private AiChatSession getSession(String memoryId, Long userId, Long tenantId) {
-        LambdaQueryWrapper<AiChatSession> queryWrapper = new LambdaQueryWrapper<AiChatSession>()
-                .eq(AiChatSession::getMemoryId, memoryId)
-                .eq(AiChatSession::getUserId, userId);
-        applyTenantCondition(queryWrapper, tenantId);
-        return getOne(queryWrapper, false);
-    }
-
-    private void applyTenantCondition(LambdaQueryWrapper<AiChatSession> queryWrapper, Long tenantId) {
-        if (tenantId == null) {
-            queryWrapper.isNull(AiChatSession::getTenantId);
-            return;
-        }
-        queryWrapper.eq(AiChatSession::getTenantId, tenantId);
-    }
-
-    private String buildTitle(String userMessage) {
-        if (!StringUtils.hasText(userMessage)) {
-            return "鏂颁細璇�";
-        }
-        return trimText(userMessage, TITLE_MAX_LENGTH);
-    }
-
-    private String trimText(String text, int maxLength) {
-        if (!StringUtils.hasText(text)) {
-            return "";
-        }
-        String source = text.trim();
-        if (source.length() <= maxLength) {
-            return source;
-        }
-        return source.substring(0, maxLength) + "...";
-    }
-
-    private String lastMessageText(List<ChatMessage> messages) {
-        if (messages == null || messages.isEmpty()) {
-            return "";
-        }
-        ChatMessage lastMessage = messages.get(messages.size() - 1);
-        return convertMessage(lastMessage).getContent();
-    }
-
-    private AiChatMessageDto convertMessage(ChatMessage message) {
-        if (message instanceof UserMessage userMessage) {
-            return new AiChatMessageDto("user", userMessage.singleText());
-        }
-        if (message instanceof AiMessage aiMessage) {
-            return new AiChatMessageDto("assistant", aiMessage.text());
-        }
-        if (message instanceof SystemMessage systemMessage) {
-            return new AiChatMessageDto("system", systemMessage.text());
-        }
-        if (message instanceof ToolExecutionResultMessage toolExecutionResultMessage) {
-            return new AiChatMessageDto("tool", toolExecutionResultMessage.text());
-        }
-        return new AiChatMessageDto("unknown", String.valueOf(message));
-    }
-
-    private void attachAnalyzeFilePaths(List<AiChatMessageDto> messages,
-                                        List<List<String>> analyzeFilePathGroups) {
-        if (StringUtils.isEmpty(messages) || StringUtils.isEmpty(analyzeFilePathGroups)) {
-            return;
-        }
-        int analyzeIndex = 0;
-        for (AiChatMessageDto message : messages) {
-            if (!"user".equals(message.getRole()) || analyzeIndex >= analyzeFilePathGroups.size()) {
-                continue;
-            }
-            List<String> filePaths = analyzeFilePathGroups.get(analyzeIndex);
-            if (!StringUtils.isEmpty(filePaths)) {
-                message.setFilePaths(filePaths);
-            }
-            analyzeIndex++;
-        }
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/service/impl/KnowledgeRagServiceImpl.java b/src/main/java/com/ruoyi/ai/service/impl/KnowledgeRagServiceImpl.java
deleted file mode 100644
index db8f308..0000000
--- a/src/main/java/com/ruoyi/ai/service/impl/KnowledgeRagServiceImpl.java
+++ /dev/null
@@ -1,342 +0,0 @@
-package com.ruoyi.ai.service.impl;
-
-import com.ruoyi.ai.service.KnowledgeRagService;
-import com.ruoyi.approve.pojo.KnowledgeBaseVector;
-import com.ruoyi.approve.service.KnowledgeBaseVectorService;
-import com.ruoyi.basic.pojo.StorageBlob;
-import com.ruoyi.basic.service.StorageBlobService;
-import com.ruoyi.common.config.FileProperties;
-import com.google.protobuf.Struct;
-import com.google.protobuf.Value;
-import dev.langchain4j.data.embedding.Embedding;
-import dev.langchain4j.data.segment.TextSegment;
-import dev.langchain4j.model.embedding.EmbeddingModel;
-import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
-import dev.langchain4j.store.embedding.EmbeddingSearchResult;
-import dev.langchain4j.store.embedding.EmbeddingStore;
-import io.pinecone.clients.Index;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.stereotype.Service;
-
-import java.io.File;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * 鐭ヨ瘑搴揜AG鏈嶅姟瀹炵幇
- */
-@Slf4j
-@Service
-public class KnowledgeRagServiceImpl implements KnowledgeRagService {
-
-    private final KnowledgeBaseVectorService knowledgeBaseVectorService;
-    private final StorageBlobService storageBlobService;
-    private final EmbeddingModel embeddingModel;
-    private final EmbeddingStore<TextSegment> embeddingStore;
-    private final FileProperties fileProperties;
-    private final Index pineconeIndex;
-
-    @org.springframework.beans.factory.annotation.Value("${pinecone.namespace:knowledge-base}")
-    private String namespace;
-
-    public KnowledgeRagServiceImpl(
-            KnowledgeBaseVectorService knowledgeBaseVectorService,
-            StorageBlobService storageBlobService,
-            EmbeddingModel embeddingModel,
-            EmbeddingStore<TextSegment> embeddingStore,
-            FileProperties fileProperties,
-            Index pineconeIndex) {
-        this.knowledgeBaseVectorService = knowledgeBaseVectorService;
-        this.storageBlobService = storageBlobService;
-        this.embeddingModel = embeddingModel;
-        this.embeddingStore = embeddingStore;
-        this.fileProperties = fileProperties;
-        this.pineconeIndex = pineconeIndex;
-    }
-
-    private static final int CHUNK_SIZE = 500;
-    private static final int CHUNK_OVERLAP = 100;
-    private static final long CHUNK_THRESHOLD_BYTES = 80L * 1024 * 1024;
-    private static final int EMBEDDING_MAX_LENGTH = 8000;
-
-    @Override
-    @Async("threadPoolTaskExecutor")
-    public void processVectorAsync(Long vectorId) {
-        log.info("寮�濮嬪紓姝ュ悜閲忓寲澶勭悊: vectorId={}, thread={}", vectorId, Thread.currentThread().getName());
-        processVector(vectorId);
-    }
-
-    @Override
-    public void processVector(Long vectorId) {
-        log.info("寮�濮嬪鐞嗗悜閲忓寲: vectorId={}", vectorId);
-        KnowledgeBaseVector vector = knowledgeBaseVectorService.getById(vectorId);
-        if (vector == null) {
-            log.error("鍚戦噺璁板綍涓嶅瓨鍦�: {}", vectorId);
-            return;
-        }
-
-        try {
-            knowledgeBaseVectorService.updateVectorStatus(vectorId,
-                    KnowledgeBaseVector.STATUS_PROCESSING, null, null);
-
-            StorageBlob blob = storageBlobService.getById(vector.getStorageBlobId());
-            if (blob == null) {
-                throw new RuntimeException("鏂囦欢涓嶅瓨鍦�: " + vector.getStorageBlobId());
-            }
-
-            File file = getFile(blob);
-            log.info("鏂囦欢璺緞: {}, 鏄惁瀛樺湪: {}", file.getAbsolutePath(), file.exists());
-            long fileSize = file.length();
-
-            String content = extractFileContent(file, vector.getFileName());
-            log.info("鏂囦欢鍐呭闀垮害: {}", content != null ? content.length() : 0);
-
-            if (content == null || content.trim().isEmpty()) {
-                throw new RuntimeException("鏂囦欢鍐呭涓虹┖");
-            }
-
-            List<TextSegment> chunks;
-            boolean needChunk = fileSize > CHUNK_THRESHOLD_BYTES || content.length() > EMBEDDING_MAX_LENGTH;
-            if (needChunk) {
-                log.info("寮�濮嬪垏鐗�: fileSize={}, contentLength={}", fileSize, content.length());
-                chunks = splitText(content, vector);
-                log.info("鍒囩墖瀹屾垚锛屽叡 {} 涓潡", chunks.size());
-            } else {
-                log.info("鏂囦欢杈冨皬锛屼笉杩涜鍒囩墖");
-                Map<String, Object> metadata = buildMetadata(vector);
-                chunks = List.of(TextSegment.from(content, new dev.langchain4j.data.document.Metadata(metadata)));
-            }
-
-            int chunkCount = 0;
-            for (TextSegment chunk : chunks) {
-                Embedding embedding = embeddingModel.embed(chunk).content();
-                embeddingStore.add(embedding, chunk);
-                chunkCount++;
-            }
-
-            knowledgeBaseVectorService.updateVectorStatus(vectorId,
-                    KnowledgeBaseVector.STATUS_COMPLETED, chunkCount, null);
-
-            log.info("鍚戦噺鍖栧鐞嗗畬鎴�: vectorId={}, chunkCount={}", vectorId, chunkCount);
-
-        } catch (Exception e) {
-            log.error("鍚戦噺鍖栧鐞嗗け璐�: vectorId={}", vectorId, e);
-            knowledgeBaseVectorService.updateVectorStatus(vectorId,
-                    KnowledgeBaseVector.STATUS_FAILED, null, e.getMessage());
-        }
-    }
-
-    @Override
-    public List<String> searchRelevantContent(String namespace, String query, int maxResults) {
-        try {
-            Embedding queryEmbedding = embeddingModel.embed(query).content();
-
-            EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder()
-                    .queryEmbedding(queryEmbedding)
-                    .maxResults(maxResults)
-                    .minScore(0.7)
-                    .build();
-
-            EmbeddingSearchResult<TextSegment> searchResult = embeddingStore.search(searchRequest);
-
-            return searchResult.matches().stream()
-                    .map(match -> match.embedded().text())
-                    .collect(Collectors.toList());
-
-        } catch (Exception e) {
-            log.error("鍚戦噺妫�绱㈠け璐�: namespace={}", namespace, e);
-            return new ArrayList<>();
-        }
-    }
-
-    @Override
-    public void deleteEmbeddings(String namespace, Long storageBlobId) {
-        log.info("鍒犻櫎鍚戦噺鏁版嵁: namespace={}, storageBlobId={}", namespace, storageBlobId);
-        try {
-            Struct filter = Struct.newBuilder()
-                    .putFields("storageBlobId", Value.newBuilder()
-                            .setStructValue(Struct.newBuilder()
-                                    .putFields("$eq", Value.newBuilder()
-                                            .setNumberValue(storageBlobId.doubleValue())
-                                            .build()))
-                            .build())
-                    .build();
-
-            List<String> emptyIds = new ArrayList<>();
-            pineconeIndex.delete(emptyIds, false, this.namespace, filter);
-            log.info("鍚戦噺鍒犻櫎瀹屾垚: storageBlobId={}", storageBlobId);
-        } catch (Exception e) {
-            log.error("鍒犻櫎鍚戦噺鏁版嵁澶辫触: namespace={}, storageBlobId={}", namespace, storageBlobId, e);
-        }
-    }
-
-    private File getFile(StorageBlob blob) {
-        String path = blob.getPath();
-        if (path != null && !path.isEmpty()) {
-            return new File(new File(fileProperties.getPath(), path), blob.getUidFilename());
-        }
-        return new File(fileProperties.getPath(), blob.getUidFilename());
-    }
-
-    private String extractFileContent(File file, String fileName) throws Exception {
-        String ext = getFileExtension(fileName);
-
-        if (isPlainText(ext)) {
-            return readFileWithEncoding(file);
-        }
-
-        if ("docx".equals(ext)) {
-            return extractDocx(file);
-        }
-
-        if ("xlsx".equals(ext)) {
-            return extractXlsx(file);
-        }
-
-        if ("xls".equals(ext)) {
-            return extractXls(file);
-        }
-
-        return readFileWithEncoding(file);
-    }
-
-    private String readFileWithEncoding(File file) throws Exception {
-        byte[] bytes = Files.readAllBytes(file.toPath());
-
-        String utf8Content = new String(bytes, StandardCharsets.UTF_8);
-        if (isValidUtf8(utf8Content)) {
-            log.debug("鏂囦欢缂栫爜: UTF-8");
-            return utf8Content;
-        }
-
-        try {
-            Charset gbk = Charset.forName("GBK");
-            String gbkContent = new String(bytes, gbk);
-            log.debug("鏂囦欢缂栫爜: GBK");
-            return gbkContent;
-        } catch (Exception e) {
-            log.warn("缂栫爜妫�娴嬪け璐ワ紝浣跨敤 UTF-8");
-            return utf8Content;
-        }
-    }
-
-    private boolean isValidUtf8(String decoded) {
-        // 妫�鏌ユ浛鎹㈠瓧绗� U+FFFD (UTF-8 瑙g爜澶辫触鏃跺嚭鐜�)
-        if (decoded.contains("锟�")) {
-            return false;
-        }
-        int invalidCount = 0;
-        int checkLen = Math.min(decoded.length(), 1000);
-        for (int i = 0; i < checkLen; i++) {
-            char c = decoded.charAt(i);
-            // 妫�鏌ョ鏈変娇鐢ㄥ尯鍩� (U+E000-U+F8FF) 鎴栧紓甯告帶鍒跺瓧绗�
-            if ((c >= '顎�' && c <= '铮�') || (c < ' ' && c != '\n' && c != '\r' && c != '\t')) {
-                invalidCount++;
-            }
-        }
-        return invalidCount < checkLen * 0.05;
-    }
-
-    private String getFileExtension(String fileName) {
-        if (fileName == null || !fileName.contains(".")) {
-            return "";
-        }
-        return fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
-    }
-
-    private boolean isPlainText(String ext) {
-        return "txt".equals(ext) || "md".equals(ext) || "json".equals(ext)
-                || "csv".equals(ext) || "xml".equals(ext) || "yaml".equals(ext)
-                || "yml".equals(ext);
-    }
-
-    private String extractDocx(File file) throws Exception {
-        try (var doc = new org.apache.poi.xwpf.usermodel.XWPFDocument(new java.io.FileInputStream(file));
-             var extractor = new org.apache.poi.xwpf.extractor.XWPFWordExtractor(doc)) {
-            return extractor.getText();
-        }
-    }
-
-    private String extractXlsx(File file) throws Exception {
-        try (var workbook = new org.apache.poi.xssf.usermodel.XSSFWorkbook(file)) {
-            return extractWorkbook(workbook);
-        }
-    }
-
-    private String extractXls(File file) throws Exception {
-        try (var workbook = new org.apache.poi.hssf.usermodel.HSSFWorkbook(new java.io.FileInputStream(file))) {
-            return extractWorkbook(workbook);
-        }
-    }
-
-    private String extractWorkbook(org.apache.poi.ss.usermodel.Workbook workbook) {
-        StringBuilder text = new StringBuilder();
-        var formatter = new org.apache.poi.ss.usermodel.DataFormatter();
-        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
-            var sheet = workbook.getSheetAt(i);
-            text.append("Sheet: ").append(sheet.getSheetName()).append("\n");
-            for (var row : sheet) {
-                for (var cell : row) {
-                    text.append(formatter.formatCellValue(cell)).append("\t");
-                }
-                text.append("\n");
-            }
-        }
-        return text.toString();
-    }
-
-    private List<TextSegment> splitText(String content, KnowledgeBaseVector vector) {
-        List<TextSegment> chunks = new ArrayList<>();
-
-        if (content.length() <= CHUNK_SIZE) {
-            Map<String, Object> metadata = buildMetadata(vector);
-            chunks.add(TextSegment.from(content, new dev.langchain4j.data.document.Metadata(metadata)));
-            return chunks;
-        }
-
-        int start = 0;
-        int chunkIndex = 0;
-        while (start < content.length()) {
-            int end = Math.min(start + CHUNK_SIZE, content.length());
-
-            if (end < content.length()) {
-                int lastPeriod = content.lastIndexOf('銆�', end);
-                int lastNewline = content.lastIndexOf('\n', end);
-                int boundary = Math.max(lastPeriod, lastNewline);
-                if (boundary > start + CHUNK_SIZE / 2) {
-                    end = boundary + 1;
-                }
-            }
-
-            String chunkText = content.substring(start, end).trim();
-            if (!chunkText.isEmpty()) {
-                Map<String, Object> metadata = buildMetadata(vector);
-                metadata.put("chunkIndex", chunkIndex);
-                chunks.add(TextSegment.from(chunkText, new dev.langchain4j.data.document.Metadata(metadata)));
-                chunkIndex++;
-            }
-
-            start = end - CHUNK_OVERLAP;
-            if (start < 0) start = 0;
-            if (start >= content.length() - CHUNK_OVERLAP) break;
-        }
-
-        return chunks;
-    }
-
-    private Map<String, Object> buildMetadata(KnowledgeBaseVector vector) {
-        Map<String, Object> metadata = new HashMap<>();
-        metadata.put("knowledgeBaseId", vector.getKnowledgeBaseId());
-        metadata.put("storageBlobId", vector.getStorageBlobId());
-        metadata.put("fileName", vector.getFileName());
-        metadata.put("namespace", vector.getNamespace());
-        return metadata;
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/store/MongoChatMemoryStore.java b/src/main/java/com/ruoyi/ai/store/MongoChatMemoryStore.java
deleted file mode 100644
index e6bcadb..0000000
--- a/src/main/java/com/ruoyi/ai/store/MongoChatMemoryStore.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package com.ruoyi.ai.store;
-
-import com.ruoyi.ai.mongodbBean.ChatMessages;
-import dev.langchain4j.data.message.ChatMessage;
-import dev.langchain4j.data.message.ChatMessageDeserializer;
-import dev.langchain4j.data.message.ChatMessageSerializer;
-import dev.langchain4j.store.memory.chat.ChatMemoryStore;
-import lombok.RequiredArgsConstructor;
-import org.springframework.data.mongodb.core.MongoTemplate;
-import org.springframework.data.mongodb.core.query.Criteria;
-import org.springframework.data.mongodb.core.query.Query;
-import org.springframework.data.mongodb.core.query.Update;
-import org.springframework.stereotype.Component;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-
-@Component
-@RequiredArgsConstructor
-public class MongoChatMemoryStore implements ChatMemoryStore {
-
-    private final MongoTemplate mongoTemplate;
-
-    @Override
-    public List<ChatMessage> getMessages(Object memoryId) {
-        ChatMessages chatMessages = findChatMessages(memoryId);
-        if (chatMessages == null || chatMessages.getContent() == null) {
-            return new LinkedList<>();
-        }
-        return ChatMessageDeserializer.messagesFromJson(chatMessages.getContent());
-    }
-
-    @Override
-    public void updateMessages(Object memoryId, List<ChatMessage> messages) {
-        String memoryIdValue = memoryIdString(memoryId);
-        Query query = Query.query(Criteria.where("memoryId").is(memoryIdValue));
-        Update update = new Update();
-        update.set("memoryId", memoryIdValue);
-        update.set("content", ChatMessageSerializer.messagesToJson(messages));
-        update.set("updateTime", new Date());
-        update.setOnInsert("createTime", new Date());
-        mongoTemplate.upsert(query, update, ChatMessages.class);
-    }
-
-    @Override
-    public void deleteMessages(Object memoryId) {
-        Query query = Query.query(Criteria.where("memoryId").is(memoryIdString(memoryId)));
-        mongoTemplate.remove(query, ChatMessages.class);
-    }
-
-    public void appendMessages(Object memoryId, List<ChatMessage> appendList) {
-        List<ChatMessage> messages = new LinkedList<>(getMessages(memoryId));
-        messages.addAll(appendList);
-        updateMessages(memoryId, messages);
-    }
-
-    public void appendAnalyzeFileContext(Object memoryId, String userQuestion, List<String> filePaths) {
-        String memoryIdValue = memoryIdString(memoryId);
-        if (!StringUtils.hasText(memoryIdValue)) {
-            return;
-        }
-        List<String> validFilePaths = new LinkedList<>();
-        if (!CollectionUtils.isEmpty(filePaths)) {
-            for (String filePath : filePaths) {
-                if (StringUtils.hasText(filePath)) {
-                    validFilePaths.add(filePath);
-                }
-            }
-        }
-        if (!StringUtils.hasText(userQuestion) && validFilePaths.isEmpty()) {
-            return;
-        }
-        Query query = Query.query(Criteria.where("memoryId").is(memoryIdValue));
-        Update update = new Update();
-        update.set("memoryId", memoryIdValue);
-        update.set("updateTime", new Date());
-        update.setOnInsert("createTime", new Date());
-        if (StringUtils.hasText(userQuestion)) {
-            update.push("analyzeUserQuestions", userQuestion);
-        }
-        if (!validFilePaths.isEmpty()) {
-            update.push("analyzeFilePaths").each(validFilePaths.toArray());
-            update.push("analyzeFilePathGroups", validFilePaths);
-        }
-        mongoTemplate.upsert(query, update, ChatMessages.class);
-    }
-
-    public List<String> getAnalyzeUserQuestions(Object memoryId) {
-        ChatMessages chatMessages = findChatMessages(memoryId);
-        if (chatMessages == null || CollectionUtils.isEmpty(chatMessages.getAnalyzeUserQuestions())) {
-            return new LinkedList<>();
-        }
-        return new LinkedList<>(chatMessages.getAnalyzeUserQuestions());
-    }
-
-    public List<List<String>> getAnalyzeFilePathGroups(Object memoryId) {
-        ChatMessages chatMessages = findChatMessages(memoryId);
-        if (chatMessages == null) {
-            return new LinkedList<>();
-        }
-        if (CollectionUtils.isEmpty(chatMessages.getAnalyzeFilePathGroups())) {
-            if (CollectionUtils.isEmpty(chatMessages.getAnalyzeFilePaths())) {
-                return new LinkedList<>();
-            }
-            List<List<String>> fallback = new LinkedList<>();
-            fallback.add(new LinkedList<>(chatMessages.getAnalyzeFilePaths()));
-            return fallback;
-        }
-        List<List<String>> groups = new LinkedList<>();
-        for (List<String> group : chatMessages.getAnalyzeFilePathGroups()) {
-            if (CollectionUtils.isEmpty(group)) {
-                groups.add(new LinkedList<>());
-            } else {
-                groups.add(new LinkedList<>(group));
-            }
-        }
-        return groups;
-    }
-
-    private String memoryIdString(Object memoryId) {
-        return memoryId == null ? "" : memoryId.toString();
-    }
-
-    private ChatMessages findChatMessages(Object memoryId) {
-        Query query = Query.query(Criteria.where("memoryId").is(memoryIdString(memoryId)));
-        return mongoTemplate.findOne(query, ChatMessages.class);
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/tools/ApproveTodoTools.java b/src/main/java/com/ruoyi/ai/tools/ApproveTodoTools.java
deleted file mode 100644
index e947ec1..0000000
--- a/src/main/java/com/ruoyi/ai/tools/ApproveTodoTools.java
+++ /dev/null
@@ -1,1012 +0,0 @@
-package com.ruoyi.ai.tools;
-
-import com.alibaba.fastjson2.JSON;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.ruoyi.ai.context.AiSessionUserContext;
-import com.ruoyi.approve.mapper.ApproveLogMapper;
-import com.ruoyi.approve.mapper.ApproveNodeMapper;
-import com.ruoyi.approve.mapper.ApproveProcessMapper;
-import com.ruoyi.approve.pojo.ApproveLog;
-import com.ruoyi.approve.pojo.ApproveNode;
-import com.ruoyi.approve.pojo.ApproveProcess;
-import com.ruoyi.approve.service.IApproveNodeService;
-import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.framework.security.LoginUser;
-import dev.langchain4j.agent.tool.P;
-import dev.langchain4j.agent.tool.Tool;
-import dev.langchain4j.agent.tool.ToolMemoryId;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.StringUtils;
-
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.YearMonth;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.ChronoUnit;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.StringJoiner;
-import java.util.regex.Matcher;
-import java.util.stream.Collectors;
-
-@Component
-public class ApproveTodoTools {
-
-    private static final int DEFAULT_LIMIT = 10;
-    private static final int MAX_LIMIT = 20;
-    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-
-    private final ApproveProcessMapper approveProcessMapper;
-    private final ApproveNodeMapper approveNodeMapper;
-    private final ApproveLogMapper approveLogMapper;
-    private final IApproveNodeService approveNodeService;
-    private final ApproveProcessServiceImpl approveProcessService;
-    private final AiSessionUserContext aiSessionUserContext;
-
-    public ApproveTodoTools(ApproveProcessMapper approveProcessMapper,
-                            ApproveNodeMapper approveNodeMapper,
-                            ApproveLogMapper approveLogMapper,
-                            IApproveNodeService approveNodeService,
-                            ApproveProcessServiceImpl approveProcessService,
-                            AiSessionUserContext aiSessionUserContext) {
-        this.approveProcessMapper = approveProcessMapper;
-        this.approveNodeMapper = approveNodeMapper;
-        this.approveLogMapper = approveLogMapper;
-        this.approveNodeService = approveNodeService;
-        this.approveProcessService = approveProcessService;
-        this.aiSessionUserContext = aiSessionUserContext;
-    }
-
-    @Tool(name = "鏌ヨ瀹℃壒寰呭姙鍒楄〃", value = "鏌ヨ褰撳墠鐧诲綍浜虹浉鍏崇殑瀹℃壒寰呭姙锛屼紭鍏堣繑鍥炶嚜宸卞緟澶勭悊鐨勫鎵癸紝鏀寔鎸夌姸鎬併�佺被鍨嬨�佸叧閿瓧鍜岃寖鍥磋繃婊ゃ��")
-    public String listTodos(@ToolMemoryId String memoryId,
-                            @P(value = "瀹℃壒鐘舵�侊紝鍙�夊�硷細all銆乸ending銆乸rocessing銆乤pproved銆乺ejected銆乺esubmitted", required = false) String status,
-                            @P(value = "瀹℃壒绫诲瀷缂栧彿锛屽彲涓嶄紶", required = false) Integer approveType,
-                            @P(value = "鍏抽敭瀛楋紝鍙尮閰嶆祦绋嬬紪鍙枫�佹爣棰樸�佺敵璇蜂汉銆佸綋鍓嶅鎵逛汉", required = false) String keyword,
-                            @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�20", required = false) Integer limit,
-                            @P(value = "鏌ヨ鑼冨洿锛屽彲閫夊�硷細related銆乤pplicant銆乤pprover锛況elated 琛ㄧず褰撳墠鐢ㄦ埛鐩稿叧锛宎pplicant 琛ㄧず鎴戝彂璧风殑锛宎pprover 琛ㄧず寰呮垜澶勭悊鐨�", required = false) String scope,
-                            @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd锛屽彲涓嶄紶", required = false) String startDate,
-                            @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd锛屽彲涓嶄紶", required = false) String endDate,
-                            @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屼緥濡� 浠婂ぉ銆佹湰鏈堛�佽繎30澶╋紝鍙笉浼�", required = false) String timeRange) {
-
-        LoginUser loginUser = currentLoginUser(memoryId);
-        Long userId = loginUser.getUserId();
-        Integer statusCode = parseStatus(status);
-        String normalizedScope = normalizeScope(scope);
-        boolean hasDateFilter = StringUtils.hasText(startDate) || StringUtils.hasText(endDate) || StringUtils.hasText(timeRange);
-        DateRange dateRange = hasDateFilter ? resolveDateRange(startDate, endDate, timeRange) : null;
-
-        LambdaQueryWrapper<ApproveProcess> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(ApproveProcess::getApproveDelete, 0);
-        if (statusCode == null) {
-            wrapper.ne(ApproveProcess::getApproveStatus, 2);
-        }
-
-        if (approveType != null) {
-            wrapper.eq(ApproveProcess::getApproveType, approveType);
-        }
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(ApproveProcess::getApproveId, keyword)
-                    .or().like(ApproveProcess::getApproveReason, keyword)
-                    .or().like(ApproveProcess::getApproveUserName, keyword)
-                    .or().like(ApproveProcess::getApproveUserCurrentName, keyword));
-        }
-        if ("applicant".equals(normalizedScope)) {
-            wrapper.eq(ApproveProcess::getApproveUser, userId);
-            if (statusCode != null) {
-                wrapper.eq(ApproveProcess::getApproveStatus, statusCode);
-            }
-        } else if ("approver".equals(normalizedScope)) {
-            wrapper.eq(ApproveProcess::getApproveUserCurrentId, userId);
-            if (statusCode != null) {
-                wrapper.eq(ApproveProcess::getApproveStatus, statusCode);
-            }
-        } else if (statusCode != null && (statusCode == 0 || statusCode == 1)) {
-            wrapper.eq(ApproveProcess::getApproveUserCurrentId, userId);
-            wrapper.eq(ApproveProcess::getApproveStatus, statusCode);
-        } else {
-            wrapper.and(w -> w.eq(ApproveProcess::getApproveUser, userId)
-                    .or().eq(ApproveProcess::getApproveUserCurrentId, userId)
-                    .or().apply("FIND_IN_SET({0}, approve_user_ids)", userId));
-            if (statusCode != null) {
-                wrapper.eq(ApproveProcess::getApproveStatus, statusCode);
-            }
-        }
-
-        if (dateRange != null) {
-            wrapper.ge(ApproveProcess::getCreateTime, dateRange.start().atStartOfDay())
-                    .lt(ApproveProcess::getCreateTime, dateRange.end().plusDays(1).atStartOfDay());
-        }
-
-        wrapper.orderByDesc(ApproveProcess::getCreateTime)
-                .last("limit " + normalizeLimit(limit));
-
-        List<ApproveProcess> processes = defaultList(approveProcessMapper.selectList(wrapper));
-        if (processes.isEmpty()) {
-            return jsonResponse(true, "todo_list", "鏈煡璇㈠埌褰撳墠鐢ㄦ埛绗﹀悎鏉′欢鐨勫鎵瑰緟鍔炪��",
-                    Map.of("count", 0),
-                    Map.of("columns", todoColumns(), "items", List.of()),
-                    Map.of());
-        }
-
-        List<Map<String, Object>> items = processes.stream()
-                .filter(process -> canView(process, userId))
-                .sorted(Comparator
-                        .comparing((ApproveProcess process) -> !Objects.equals(process.getApproveUserCurrentId(), userId))
-                        .thenComparing(ApproveProcess::getCreateTime, Comparator.nullsLast(Comparator.reverseOrder())))
-                .map(process -> {
-                    Map<String, Object> item = new LinkedHashMap<>();
-                    item.put("approveId", process.getApproveId());
-                    item.put("approveType", approveTypeName(process.getApproveType()));
-                    item.put("approveUserName", safe(process.getApproveUserName()));
-                    item.put("approveUserCurrentName", safe(process.getApproveUserCurrentName()));
-                    item.put("approveReason", safe(process.getApproveReason()));
-                    item.put("approveStatus", approveStatusName(process.getApproveStatus()));
-                    item.put("createTime", formatDateTime(process.getCreateTime()));
-                    item.put("relation", relationName(process, userId));
-                    return item;
-                })
-                .collect(Collectors.toList());
-
-        return jsonResponse(true, "todo_list", "宸茶繑鍥炲綋鍓嶇敤鎴风浉鍏冲鎵瑰垪琛ㄣ��",
-                Map.of(
-                        "count", items.size(),
-                        "statusFilter", StringUtils.hasText(status) ? status : "all",
-                        "approveType", approveType == null ? "" : approveType,
-                        "keyword", keyword == null ? "" : keyword,
-                        "scope", normalizedScope,
-                        "timeRange", dateRange == null ? "all" : dateRange.label(),
-                        "startDate", dateRange == null ? "" : dateRange.start().toString(),
-                        "endDate", dateRange == null ? "" : dateRange.end().toString()
-                ),
-                Map.of("columns", todoColumns(), "items", items),
-                Map.of());
-    }
-
-    @Tool(name = "鏌ヨ瀹℃壒寰呭姙璇︽儏", value = "鏍规嵁娴佺▼缂栧彿鏌ヨ褰撳墠鐧诲綍浜哄彲瑙佺殑瀹℃壒璇︽儏銆�")
-    public String getTodoDetail(@ToolMemoryId String memoryId,
-                                @P("娴佺▼缂栧彿 approveId") String approveId) {
-        ApproveProcess process = getAccessibleProcess(memoryId, approveId);
-        if (process == null) {
-            return "鏈壘鍒板搴斿鎵癸紝鎴栧綋鍓嶇敤鎴锋棤鏉冩煡鐪嬭娴佺▼銆�";
-        }
-
-        StringJoiner detail = new StringJoiner("\n");
-        detail.add("瀹℃壒璇︽儏");
-        detail.add("娴佺▼缂栧彿: " + safe(process.getApproveId()));
-        detail.add("瀹℃壒绫诲瀷: " + approveTypeName(process.getApproveType()));
-        detail.add("鐢宠浜�: " + safe(process.getApproveUserName()));
-        detail.add("鐢宠閮ㄩ棬: " + safe(process.getApproveDeptName()));
-        detail.add("褰撳墠瀹℃壒浜�: " + safe(process.getApproveUserCurrentName()));
-        detail.add("鏍囬: " + safe(process.getApproveReason()));
-        detail.add("鐘舵��: " + approveStatusName(process.getApproveStatus()));
-        detail.add("鐢宠鏃ユ湡: " + formatDate(process.getApproveTime()));
-        detail.add("寮�濮嬫棩鏈�: " + formatDate(process.getStartDate()));
-        detail.add("缁撴潫鏃ユ湡: " + formatDate(process.getEndDate()));
-        detail.add("鍦扮偣: " + safe(process.getLocation()));
-        detail.add("閲戦: " + (process.getPrice() == null ? "" : process.getPrice().toPlainString()));
-        detail.add("澶囨敞: " + safe(process.getApproveRemark()));
-        detail.add("鍒涘缓鏃堕棿: " + formatDateTime(process.getCreateTime()));
-        detail.add("涓庡綋鍓嶇敤鎴峰叧绯�: " + relationName(process, currentUserId(memoryId)));
-        return detail.toString();
-    }
-
-    @Tool(name = "鏌ヨ瀹℃壒娴佽浆璁板綍", value = "鏍规嵁娴佺▼缂栧彿鏌ヨ瀹℃壒鑺傜偣鍜屽鎵规棩蹇楋紝鐢ㄤ簬鍥炵瓟杩涘害銆佸綋鍓嶅崱鐐瑰拰鍘嗗彶澶勭悊璁板綍銆�")
-    public String getTodoProgress(@ToolMemoryId String memoryId,
-                                  @P("娴佺▼缂栧彿 approveId") String approveId) {
-        ApproveProcess process = getAccessibleProcess(memoryId, approveId);
-        if (process == null) {
-            return jsonResponse(false, "todo_progress", "鏈壘鍒板搴斿鎵癸紝鎴栧綋鍓嶇敤鎴锋棤鏉冩煡鐪嬭娴佺▼銆�",
-                    Map.of("approveId", safe(approveId)),
-                    Map.of(),
-                    Map.of());
-        }
-
-        List<ApproveNode> nodes = listNodes(process);
-        List<ApproveLog> logs = listLogs(process.getId());
-        ApproveNode currentNode = findCurrentNode(nodes);
-
-        List<Map<String, Object>> nodeItems = nodes.stream().map(node -> {
-            Map<String, Object> item = new LinkedHashMap<>();
-            item.put("approveNodeOrder", node.getApproveNodeOrder());
-            item.put("approveNodeUser", safe(node.getApproveNodeUser()));
-            item.put("approveNodeUserId", node.getApproveNodeUserId());
-            item.put("approveNodeStatus", approveNodeStatusName(node.getApproveNodeStatus()));
-            item.put("approveNodeTime", formatDate(node.getApproveNodeTime()));
-            item.put("approveNodeReason", safe(node.getApproveNodeReason()));
-            item.put("approveNodeRemark", safe(node.getApproveNodeRemark()));
-            item.put("isCurrent", currentNode != null && Objects.equals(currentNode.getId(), node.getId()));
-            return item;
-        }).collect(Collectors.toList());
-
-        List<Map<String, Object>> logItems = logs.stream().map(log -> {
-            Map<String, Object> item = new LinkedHashMap<>();
-            item.put("approveNodeOrder", log.getApproveNodeOrder());
-            item.put("approveUser", log.getApproveUser());
-            item.put("approveStatus", approveStatusName(log.getApproveStatus()));
-            item.put("approveTime", formatDate(log.getApproveTime()));
-            item.put("approveRemark", safe(log.getApproveRemark()));
-            return item;
-        }).collect(Collectors.toList());
-
-        return jsonResponse(true, "todo_progress", "宸茶繑鍥炲鎵规祦杞褰曘��",
-                Map.of(
-                        "approveId", safe(process.getApproveId()),
-                        "currentStatus", approveStatusName(process.getApproveStatus()),
-                        "currentApprover", safe(process.getApproveUserCurrentName()),
-                        "currentNodeOrder", currentNode == null ? "" : currentNode.getApproveNodeOrder(),
-                        "nodeCount", nodeItems.size(),
-                        "logCount", logItems.size()
-                ),
-                Map.of("nodes", nodeItems, "logs", logItems),
-                Map.of());
-    }
-
-    @Tool(name = "缁熻瀹℃壒寰呭姙鏁版嵁", value = "鎸夌敤鎴锋寚瀹氱殑鏃堕棿鑼冨洿缁熻褰撳墠鐧诲綍浜虹浉鍏冲鎵圭殑鐘舵�佸垎甯冦�佺被鍨嬪垎甯冨拰瓒嬪娍锛涙湭鎸囧畾鏃堕粯璁よ繎7澶┿��")
-    public String getTodoStats(@ToolMemoryId String memoryId,
-                               @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd锛屽彲涓嶄紶", required = false) String startDate,
-                               @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd锛屽彲涓嶄紶", required = false) String endDate,
-                               @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屼緥濡� 浠婂ぉ銆佹湰鏈堛�佽繎30澶┿��2026-04-01鍒�2026-04-27", required = false) String timeRange) {
-        Long userId = currentUserId(memoryId);
-        List<ApproveProcess> processes = defaultList(approveProcessMapper.selectList(new LambdaQueryWrapper<ApproveProcess>()
-                .eq(ApproveProcess::getApproveDelete, 0)
-                .and(w -> w.eq(ApproveProcess::getApproveUser, userId)
-                        .or().eq(ApproveProcess::getApproveUserCurrentId, userId)
-                        .or().apply("FIND_IN_SET({0}, approve_user_ids)", userId))));
-
-        DateRange dateRange = resolveDateRange(startDate, endDate, timeRange);
-        List<ApproveProcess> filteredProcesses = processes.stream()
-                .filter(process -> withinDateRange(process.getCreateTime(), dateRange))
-                .collect(Collectors.toList());
-
-        if (filteredProcesses.isEmpty()) {
-            return jsonResponse(true, "todo_stats", "褰撳墠鐢ㄦ埛娌℃湁鐩稿叧瀹℃壒鏁版嵁銆�",
-                    Map.of(
-                            "total", 0,
-                            "startDate", dateRange.start().toString(),
-                            "endDate", dateRange.end().toString(),
-                            "timeRange", dateRange.label()
-                    ),
-                    Map.of(
-                            "statusDistribution", Map.of(),
-                            "typeDistribution", Map.of(),
-                            "trend", List.of()
-                    ),
-                    Map.of());
-        }
-
-        Map<String, Long> statusStats = filteredProcesses.stream()
-                .collect(Collectors.groupingBy(p -> approveStatusName(p.getApproveStatus()), LinkedHashMap::new, Collectors.counting()));
-        Map<String, Long> typeStats = filteredProcesses.stream()
-                .collect(Collectors.groupingBy(p -> approveTypeName(p.getApproveType()), LinkedHashMap::new, Collectors.counting()));
-
-        long pendingCount = countByStatus(filteredProcesses, 0);
-        long processingCount = countByStatus(filteredProcesses, 1);
-        long approvedCount = countByStatus(filteredProcesses, 2);
-        long rejectedCount = countByStatus(filteredProcesses, 3);
-        long resubmittedCount = countByStatus(filteredProcesses, 4);
-
-        TrendRange trendRange = buildTrendRange(dateRange.start(), dateRange.end(), filteredProcesses);
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("total", filteredProcesses.size());
-        summary.put("pending", pendingCount);
-        summary.put("processing", processingCount);
-        summary.put("approved", approvedCount);
-        summary.put("rejected", rejectedCount);
-        summary.put("resubmitted", resubmittedCount);
-        summary.put("approvalCompletionRate", calculateRate(approvedCount, filteredProcesses.size()));
-        summary.put("rejectionRate", calculateRate(rejectedCount, filteredProcesses.size()));
-        summary.put("startDate", dateRange.start().toString());
-        summary.put("endDate", dateRange.end().toString());
-        summary.put("timeRange", dateRange.label());
-        summary.put("trendGranularity", trendRange.granularity());
-
-        Map<String, Object> charts = new LinkedHashMap<>();
-        charts.put("statusBarOption", buildStatusBarOption(statusStats));
-        charts.put("typePieOption", buildTypePieOption(typeStats));
-        charts.put("trendLineOption", buildTrendLineOption(trendRange.labels(), trendRange.values(), trendRange.label()));
-
-        return jsonResponse(true, "todo_stats", "宸茶繑鍥炲綋鍓嶇敤鎴风浉鍏冲鎵圭粺璁°��",
-                summary,
-                Map.of(
-                        "statusDistribution", statusStats,
-                        "typeDistribution", typeStats,
-                        "trend", toTrendItems(trendRange.labels(), trendRange.values())
-                ),
-                charts);
-    }
-
-    @Transactional(rollbackFor = Exception.class)
-    @Tool(name = "瀹℃壒寰呭姙", value = "鎵ц瀹℃壒鍔ㄤ綔锛宎ction 浠呮敮鎸� approve 鎴� reject锛屼笖鍙兘澶勭悊褰撳墠鐧诲綍浜鸿嚜宸辩殑寰呭鑺傜偣銆�")
-    public String reviewTodo(@ToolMemoryId String memoryId,
-                             @P("娴佺▼缂栧彿 approveId") String approveId,
-                             @P("鍔ㄤ綔锛宎pprove=閫氳繃锛宺eject=椹冲洖") String action,
-                             @P(value = "瀹℃壒澶囨敞锛屽彲涓嶄紶", required = false) String remark) {
-
-        ApproveProcess process = getAccessibleProcess(memoryId, approveId);
-        if (process == null) {
-            return actionResult(false, "review_action", "鏈壘鍒板搴斿鎵癸紝鎴栧綋鍓嶇敤鎴锋棤鏉冭闂娴佺▼銆�", approveId, null);
-        }
-        if (!canOperate(process, currentUserId(memoryId))) {
-            return actionResult(false, "review_action", "褰撳墠鐧诲綍浜轰笉鏄瀹℃壒鐨勫綋鍓嶅鐞嗕汉銆�", approveId, null);
-        }
-        if (process.getApproveStatus() != null && (process.getApproveStatus() == 2 || process.getApproveStatus() == 3)) {
-            return actionResult(false, "review_action", "璇ュ鎵瑰凡缁撴潫锛屼笉鑳介噸澶嶅鐞嗐��", approveId, null);
-        }
-
-        List<ApproveNode> nodes = listNodes(process);
-        ApproveNode currentNode = findCurrentNode(nodes);
-        if (currentNode == null || !Objects.equals(currentNode.getApproveNodeUserId(), currentUserId(memoryId))) {
-            return actionResult(false, "review_action", "鏈壘鍒板綋鍓嶇敤鎴峰彲澶勭悊鐨勫鎵硅妭鐐广��", approveId, null);
-        }
-
-        String normalizedAction = action == null ? "" : action.trim().toLowerCase();
-        currentNode.setApproveNodeRemark(remark);
-        currentNode.setApproveNodeReason("reject".equals(normalizedAction) ? remark : null);
-        currentNode.setUpdateUser(currentUserId(memoryId));
-        currentNode.setUpdateTime(LocalDateTime.now());
-        currentNode.setIsLast(isLastNode(nodes, currentNode));
-
-        try {
-            switch (normalizedAction) {
-                case "approve" -> currentNode.setApproveNodeStatus(1);
-                case "reject" -> currentNode.setApproveNodeStatus(2);
-                default -> {
-                    return actionResult(false, "review_action", "action 鍙敮鎸� approve 鎴� reject銆�", approveId, null);
-                }
-            }
-            approveNodeService.updateApproveNode(currentNode);
-        } catch (IOException e) {
-            throw new RuntimeException("瀹℃壒澶勭悊澶辫触", e);
-        }
-
-        ApproveProcess refreshed = getProcessByApproveId(approveId);
-        writeApproveLog(memoryId, refreshed, currentNode, remark);
-        ApproveNode nextNode = refreshed == null ? null : findCurrentNode(listNodes(refreshed));
-
-        return actionResult(true, "review_action",
-                "approve".equals(normalizedAction) ? "瀹℃壒宸查�氳繃銆�" : "瀹℃壒宸查┏鍥炪��",
-                approveId,
-                Map.of(
-                        "action", normalizedAction,
-                        "currentStatus", refreshed == null ? "" : approveStatusName(refreshed.getApproveStatus()),
-                        "nextApprover", nextNode == null ? "" : safe(nextNode.getApproveNodeUser()),
-                        "remark", safe(remark)
-                ));
-    }
-
-    @Transactional(rollbackFor = Exception.class)
-    @Tool(name = "鍙栨秷瀹℃壒寰呭姙瀹℃牳", value = "鎾ら攢鏈�杩戜竴娆″鏍哥粨鏋滐紝浠呭厑璁告渶杩戜竴娆″鏍镐汉鎴栫敵璇蜂汉鎿嶄綔銆�")
-    public String cancelReviewTodo(@ToolMemoryId String memoryId,
-                                   @P("娴佺▼缂栧彿 approveId") String approveId,
-                                   @P(value = "鍙栨秷鍘熷洜锛屽彲涓嶄紶", required = false) String reason) {
-
-        ApproveProcess process = getAccessibleProcess(memoryId, approveId);
-        if (process == null) {
-            return actionResult(false, "cancel_review_action", "鏈壘鍒板搴斿鎵癸紝鎴栧綋鍓嶇敤鎴锋棤鏉冭闂娴佺▼銆�", approveId, null);
-        }
-
-        List<ApproveNode> nodes = listNodes(process);
-        ApproveNode lastReviewedNode = nodes.stream()
-                .filter(node -> node.getApproveNodeStatus() != null && node.getApproveNodeStatus() != 0)
-                .max(Comparator.comparing(ApproveNode::getApproveNodeOrder))
-                .orElse(null);
-        if (lastReviewedNode == null) {
-            return actionResult(false, "cancel_review_action", "褰撳墠娴佺▼娌℃湁鍙挙閿�鐨勫鏍歌褰曘��", approveId, null);
-        }
-
-        Long userId = currentUserId(memoryId);
-        if (!isAdmin(userId)
-                && !Objects.equals(process.getApproveUser(), userId)
-                && !Objects.equals(lastReviewedNode.getApproveNodeUserId(), userId)) {
-            return actionResult(false, "cancel_review_action", "鍙湁鐢宠浜恒�佹渶杩戜竴娆″鏍镐汉鎴栫鐞嗗憳鍙互鎾ら攢銆�", approveId, null);
-        }
-
-        lastReviewedNode.setApproveNodeStatus(0);
-        lastReviewedNode.setApproveNodeTime(null);
-        lastReviewedNode.setApproveNodeReason(null);
-        lastReviewedNode.setApproveNodeRemark(reason);
-        lastReviewedNode.setUpdateUser(userId);
-        lastReviewedNode.setUpdateTime(LocalDateTime.now());
-        approveNodeMapper.updateById(lastReviewedNode);
-
-        ApproveLog latestLog = listLogs(process.getId()).stream()
-                .max(Comparator.comparing(ApproveLog::getApproveNodeOrder)
-                        .thenComparing(ApproveLog::getApproveTime, Comparator.nullsLast(Date::compareTo)))
-                .orElse(null);
-        if (latestLog != null) {
-            approveLogMapper.deleteById(latestLog.getId());
-        }
-
-        process.setApproveOverTime(null);
-        process.setApproveRemark(reason);
-        process.setApproveStatus(lastReviewedNode.getApproveNodeOrder() == null || lastReviewedNode.getApproveNodeOrder() <= 1 ? 0 : 1);
-        process.setApproveUserCurrentId(lastReviewedNode.getApproveNodeUserId());
-        process.setApproveUserCurrentName(lastReviewedNode.getApproveNodeUser());
-        approveProcessMapper.updateById(process);
-
-        return actionResult(true, "cancel_review_action", "鏈�杩戜竴娆″鏍稿凡鎾ら攢銆�", approveId, Map.of(
-                "rollbackNodeOrder", lastReviewedNode.getApproveNodeOrder(),
-                "currentStatus", approveStatusName(process.getApproveStatus()),
-                "currentApprover", safe(process.getApproveUserCurrentName()),
-                "reason", safe(reason)
-        ));
-    }
-
-    @Transactional(rollbackFor = Exception.class)
-    @Tool(name = "淇敼瀹℃壒寰呭姙", value = "淇敼瀹℃壒鍗曞熀纭�淇℃伅锛屼粎鍏佽鐢宠浜轰慨鏀癸紱涓嶆敮鎸侀�氳繃 AI 鍙樻洿瀹℃壒绫诲瀷銆�")
-    public String updateTodo(@ToolMemoryId String memoryId,
-                             @P("娴佺▼缂栧彿 approveId") String approveId,
-                             @P(value = "鏂扮殑鏍囬锛屽彲涓嶄紶", required = false) String approveReason,
-                             @P(value = "鏂扮殑寮�濮嬫棩鏈� yyyy-MM-dd锛屽彲涓嶄紶", required = false) String startDate,
-                             @P(value = "鏂扮殑缁撴潫鏃ユ湡 yyyy-MM-dd锛屽彲涓嶄紶", required = false) String endDate,
-                             @P(value = "鏂扮殑閲戦锛屽彲涓嶄紶", required = false) BigDecimal price,
-                             @P(value = "鏂扮殑鍦扮偣锛屽彲涓嶄紶", required = false) String location,
-                             @P(value = "鏂扮殑瀹℃壒绫诲瀷锛屽彲涓嶄紶", required = false) Integer approveType,
-                             @P(value = "鏂扮殑澶囨敞锛屽彲涓嶄紶", required = false) String approveRemark) {
-
-        ApproveProcess process = getAccessibleProcess(memoryId, approveId);
-        if (process == null) {
-            return actionResult(false, "update_action", "鏈壘鍒板搴斿鎵癸紝鎴栧綋鍓嶇敤鎴锋棤鏉冭闂娴佺▼銆�", approveId, null);
-        }
-        if (!Objects.equals(process.getApproveUser(), currentUserId(memoryId)) && !isAdmin(currentUserId(memoryId))) {
-            return actionResult(false, "update_action", "鍙湁鐢宠浜烘垨绠$悊鍛樺彲浠ヤ慨鏀瑰鎵瑰崟銆�", approveId, null);
-        }
-        if (process.getApproveStatus() != null && (process.getApproveStatus() == 1 || process.getApproveStatus() == 2)) {
-            return actionResult(false, "update_action", "瀹℃壒澶勭悊涓垨宸插畬鎴愭椂锛屼笉鍏佽閫氳繃 AI 淇敼銆�", approveId, null);
-        }
-        if (approveType != null && !Objects.equals(approveType, process.getApproveType())) {
-            return actionResult(false, "update_action", "AI 鍔╂墜鏆備笉鏀寔鐩存帴鍙樻洿瀹℃壒绫诲瀷锛岄伩鍏嶈妭鐐归厤缃け鐪熴��", approveId, null);
-        }
-        if (!StringUtils.hasText(approveReason)
-                && !StringUtils.hasText(startDate)
-                && !StringUtils.hasText(endDate)
-                && price == null
-                && !StringUtils.hasText(location)
-                && !StringUtils.hasText(approveRemark)) {
-            return actionResult(false, "update_action", "娌℃湁妫�娴嬪埌鍙洿鏂扮殑瀛楁銆�", approveId, null);
-        }
-
-        if (StringUtils.hasText(approveReason)) {
-            process.setApproveReason(approveReason);
-        }
-        if (StringUtils.hasText(startDate)) {
-            process.setStartDate(parseDate(startDate));
-        }
-        if (StringUtils.hasText(endDate)) {
-            process.setEndDate(parseDate(endDate));
-        }
-        if (price != null) {
-            process.setPrice(price);
-        }
-        if (StringUtils.hasText(location)) {
-            process.setLocation(location);
-        }
-        if (StringUtils.hasText(approveRemark)) {
-            process.setApproveRemark(approveRemark);
-        }
-
-        approveProcessMapper.updateById(process);
-        return actionResult(true, "update_action", "瀹℃壒鍗曞凡鏇存柊銆�", approveId, Map.of(
-                "approveReason", safe(process.getApproveReason()),
-                "startDate", formatDate(process.getStartDate()),
-                "endDate", formatDate(process.getEndDate()),
-                "price", process.getPrice() == null ? "" : process.getPrice(),
-                "location", safe(process.getLocation()),
-                "approveType", approveTypeName(process.getApproveType()),
-                "approveRemark", safe(process.getApproveRemark())
-        ));
-    }
-
-    @Transactional(rollbackFor = Exception.class)
-    @Tool(name = "鍒犻櫎瀹℃壒寰呭姙", value = "鍒犻櫎瀹℃壒娴佺▼锛屼粎鍏佽鐢宠浜哄垹闄ゆ湭瀹屾垚鐨勬祦绋嬨��")
-    public String deleteTodo(@ToolMemoryId String memoryId,
-                             @P("娴佺▼缂栧彿 approveId") String approveId) {
-        ApproveProcess process = getAccessibleProcess(memoryId, approveId);
-        if (process == null) {
-            return actionResult(false, "delete_action", "鏈壘鍒板搴斿鎵癸紝鎴栧綋鍓嶇敤鎴锋棤鏉冭闂娴佺▼銆�", approveId, null);
-        }
-        if (!Objects.equals(process.getApproveUser(), currentUserId(memoryId)) && !isAdmin(currentUserId(memoryId))) {
-            return actionResult(false, "delete_action", "鍙湁鐢宠浜烘垨绠$悊鍛樺彲浠ュ垹闄ゅ鎵瑰崟銆�", approveId, null);
-        }
-        if (process.getApproveStatus() != null && (process.getApproveStatus() == 1 || process.getApproveStatus() == 2)) {
-            return actionResult(false, "delete_action", "瀹℃壒澶勭悊涓垨宸插畬鎴愮殑娴佺▼涓嶅厑璁搁�氳繃 AI 鍒犻櫎銆�", approveId, null);
-        }
-
-        approveProcessService.delByIds(Collections.singletonList(process.getId()));
-        return actionResult(true, "delete_action", "瀹℃壒娴佺▼宸插垹闄ゃ��", approveId, Map.of(
-                "deletedProcessId", process.getId(),
-                "approveStatus", approveStatusName(process.getApproveStatus())
-        ));
-    }
-
-    private ApproveProcess getAccessibleProcess(String memoryId, String approveId) {
-        ApproveProcess process = getProcessByApproveId(approveId);
-        if (process == null) {
-            return null;
-        }
-        return canView(process, currentUserId(memoryId)) ? process : null;
-    }
-
-    private ApproveProcess getProcessByApproveId(String approveId) {
-        if (!StringUtils.hasText(approveId)) {
-            return null;
-        }
-        return approveProcessMapper.selectOne(new LambdaQueryWrapper<ApproveProcess>()
-                .eq(ApproveProcess::getApproveId, approveId)
-                .eq(ApproveProcess::getApproveDelete, 0)
-                .last("limit 1"));
-    }
-
-    private List<ApproveNode> listNodes(ApproveProcess process) {
-        if (process == null) {
-            return List.of();
-        }
-        List<ApproveNode> nodes = defaultList(approveNodeMapper.selectList(new LambdaQueryWrapper<ApproveNode>()
-                .eq(ApproveNode::getDeleteFlag, 0)
-                .eq(ApproveNode::getApproveProcessId, process.getApproveId())
-                .orderByAsc(ApproveNode::getApproveNodeOrder)));
-        if (!nodes.isEmpty()) {
-            return nodes;
-        }
-        return defaultList(approveNodeMapper.selectList(new LambdaQueryWrapper<ApproveNode>()
-                .eq(ApproveNode::getDeleteFlag, 0)
-                .eq(ApproveNode::getApproveProcessId, String.valueOf(process.getId()))
-                .orderByAsc(ApproveNode::getApproveNodeOrder)));
-    }
-
-    private List<ApproveLog> listLogs(Long processId) {
-        return defaultList(approveLogMapper.selectList(new LambdaQueryWrapper<ApproveLog>()
-                .eq(ApproveLog::getApproveId, processId)
-                .orderByAsc(ApproveLog::getApproveNodeOrder, ApproveLog::getApproveTime)));
-    }
-
-    private ApproveNode findCurrentNode(List<ApproveNode> nodes) {
-        return nodes.stream()
-                .filter(node -> node.getApproveNodeStatus() != null && node.getApproveNodeStatus() == 0)
-                .min(Comparator.comparing(ApproveNode::getApproveNodeOrder))
-                .orElse(null);
-    }
-
-    private boolean isLastNode(List<ApproveNode> nodes, ApproveNode currentNode) {
-        Integer maxOrder = nodes.stream()
-                .map(ApproveNode::getApproveNodeOrder)
-                .filter(Objects::nonNull)
-                .max(Integer::compareTo)
-                .orElse(null);
-        return maxOrder != null && Objects.equals(maxOrder, currentNode.getApproveNodeOrder());
-    }
-
-    private void writeApproveLog(String memoryId, ApproveProcess process, ApproveNode currentNode, String remark) {
-        if (process == null || currentNode == null) {
-            return;
-        }
-        ApproveLog log = new ApproveLog();
-        log.setApproveId(process.getId());
-        log.setApproveNodeOrder(currentNode.getApproveNodeOrder());
-        log.setApproveUser(currentUserId(memoryId));
-        log.setApproveTime(new Date());
-        log.setApproveStatus(process.getApproveStatus());
-        log.setApproveRemark(remark);
-        approveLogMapper.insert(log);
-    }
-
-    private boolean canView(ApproveProcess process, Long userId) {
-        if (process == null || userId == null) {
-            return false;
-        }
-        return isAdmin(userId)
-                || Objects.equals(process.getApproveUser(), userId)
-                || Objects.equals(process.getApproveUserCurrentId(), userId)
-                || containsUserId(process.getApproveUserIds(), userId);
-    }
-
-    private boolean canOperate(ApproveProcess process, Long userId) {
-        return process != null && userId != null && Objects.equals(process.getApproveUserCurrentId(), userId);
-    }
-
-    private boolean containsUserId(String csv, Long userId) {
-        if (!StringUtils.hasText(csv) || userId == null) {
-            return false;
-        }
-        String target = String.valueOf(userId);
-        for (String item : csv.split(",")) {
-            if (target.equals(item.trim())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private String relationName(ApproveProcess process, Long userId) {
-        if (Objects.equals(process.getApproveUserCurrentId(), userId)) {
-            return "褰撳墠瀹℃壒浜�";
-        }
-        if (Objects.equals(process.getApproveUser(), userId)) {
-            return "鐢宠浜�";
-        }
-        if (containsUserId(process.getApproveUserIds(), userId)) {
-            return "瀹℃壒閾炬垚鍛�";
-        }
-        return "鍙";
-    }
-
-    private List<String> todoColumns() {
-        return List.of("approveId", "approveType", "approveUserName", "approveUserCurrentName",
-                "approveReason", "approveStatus", "createTime", "relation");
-    }
-
-    private int normalizeLimit(Integer limit) {
-        if (limit == null || limit <= 0) {
-            return DEFAULT_LIMIT;
-        }
-        return Math.min(limit, MAX_LIMIT);
-    }
-
-    private Integer parseStatus(String status) {
-        if (!StringUtils.hasText(status) || "all".equalsIgnoreCase(status)) {
-            return null;
-        }
-        return switch (status.trim().toLowerCase()) {
-            case "pending" -> 0;
-            case "processing" -> 1;
-            case "approved" -> 2;
-            case "rejected" -> 3;
-            case "resubmitted" -> 4;
-            default -> null;
-        };
-    }
-
-    private String normalizeScope(String scope) {
-        if (!StringUtils.hasText(scope)) {
-            return "related";
-        }
-        return switch (scope.trim().toLowerCase()) {
-            case "applicant", "mine", "created", "initiated" -> "applicant";
-            case "approver", "handler", "todo", "pending" -> "approver";
-            default -> "related";
-        };
-    }
-
-    private String approveStatusName(Integer status) {
-        if (status == null) {
-            return "鏈煡";
-        }
-        return switch (status) {
-            case 0 -> "寰呭鏍�";
-            case 1 -> "瀹℃牳涓�";
-            case 2 -> "瀹℃牳瀹屾垚";
-            case 3 -> "瀹℃牳鏈�氳繃";
-            case 4 -> "宸查噸鏂版彁浜�";
-            default -> "鏈煡";
-        };
-    }
-
-    private String approveNodeStatusName(Integer status) {
-        if (status == null) {
-            return "鏈煡";
-        }
-        return switch (status) {
-            case 0 -> "鏈鏍�";
-            case 1 -> "鍚屾剰";
-            case 2 -> "鎷掔粷";
-            default -> "鏈煡";
-        };
-    }
-
-    private String approveTypeName(Integer type) {
-        if (type == null) {
-            return "鏈煡";
-        }
-        return switch (type) {
-            case 1 -> "鍏嚭绠$悊";
-            case 2 -> "璇峰亣绠$悊";
-            case 3 -> "鍑哄樊绠$悊";
-            case 4 -> "鎶ラ攢绠$悊";
-            case 5 -> "閲囪喘瀹℃壒";
-            case 6 -> "鎶ヤ环瀹℃壒";
-            case 7 -> "鍙戣揣瀹℃壒";
-            case 8 -> "鍗遍櫓浣滀笟瀹℃壒";
-            case 9 -> "鍔炲叕鐢ㄥ搧瀹℃壒";
-            default -> "绫诲瀷" + type;
-        };
-    }
-
-    private String safe(Object value) {
-        return value == null ? "" : String.valueOf(value).replace('\n', ' ').replace('\r', ' ');
-    }
-
-    private String formatDateTime(Object value) {
-        if (value == null) {
-            return "";
-        }
-        if (value instanceof LocalDateTime localDateTime) {
-            return localDateTime.format(DATE_TIME_FORMATTER);
-        }
-        return safe(value);
-    }
-
-    private String formatDate(Date value) {
-        if (value == null) {
-            return "";
-        }
-        return value.toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(DATE_FORMATTER);
-    }
-
-    private long countByStatus(List<ApproveProcess> processes, int status) {
-        return processes.stream()
-                .filter(process -> process.getApproveStatus() != null)
-                .filter(process -> process.getApproveStatus() == status)
-                .count();
-    }
-
-    private String calculateRate(long part, int total) {
-        if (total <= 0) {
-            return "0.00%";
-        }
-        return String.format("%.2f%%", part * 100.0 / total);
-    }
-
-    private List<Map<String, Object>> toTrendItems(List<String> dates, List<Long> values) {
-        List<Map<String, Object>> items = new ArrayList<>();
-        for (int i = 0; i < dates.size(); i++) {
-            Map<String, Object> item = new LinkedHashMap<>();
-            item.put("date", dates.get(i));
-            item.put("count", values.get(i));
-            items.add(item);
-        }
-        return items;
-    }
-
-    private Map<String, Object> buildStatusBarOption(Map<String, Long> statusStats) {
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "瀹℃壒鐘舵�佸垎甯�", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", new ArrayList<>(statusStats.keySet())));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of(
-                "name", "鏁伴噺",
-                "type", "bar",
-                "data", new ArrayList<>(statusStats.values()),
-                "barWidth", "40%"
-        )));
-        return option;
-    }
-
-    private Map<String, Object> buildTypePieOption(Map<String, Long> typeStats) {
-        List<Map<String, Object>> data = typeStats.entrySet().stream()
-                .map(entry -> {
-                    Map<String, Object> item = new LinkedHashMap<>();
-                    item.put("name", entry.getKey());
-                    item.put("value", entry.getValue());
-                    return item;
-                })
-                .collect(Collectors.toList());
-
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "瀹℃壒绫诲瀷鍗犳瘮", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "item"));
-        option.put("legend", Map.of("orient", "vertical", "left", "left"));
-        option.put("series", List.of(Map.of(
-                "name", "瀹℃壒绫诲瀷",
-                "type", "pie",
-                "radius", List.of("35%", "65%"),
-                "data", data
-        )));
-        return option;
-    }
-
-    private Map<String, Object> buildTrendLineOption(List<String> dates, List<Long> values, String label) {
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", label + "瀹℃壒鏂板瓒嬪娍", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", dates));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of(
-                "name", "鏂板瀹℃壒",
-                "type", "line",
-                "smooth", true,
-                "data", values,
-                "areaStyle", Map.of()
-        )));
-        return option;
-    }
-
-    private Date parseDate(String dateText) {
-        try {
-            LocalDate localDate = LocalDate.parse(dateText, DATE_FORMATTER);
-            return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
-        } catch (Exception e) {
-            throw new IllegalArgumentException("鏃ユ湡鏍煎紡蹇呴』鏄� yyyy-MM-dd");
-        }
-    }
-
-    private DateRange resolveDateRange(String startDateText, String endDateText, String timeRange) {
-        LocalDate today = LocalDate.now();
-        LocalDate explicitStart = parseLocalDate(startDateText);
-        LocalDate explicitEnd = parseLocalDate(endDateText);
-        if (explicitStart != null || explicitEnd != null) {
-            LocalDate start = explicitStart != null ? explicitStart : explicitEnd;
-            LocalDate end = explicitEnd != null ? explicitEnd : explicitStart;
-            if (start.isAfter(end)) {
-                LocalDate temp = start;
-                start = end;
-                end = temp;
-            }
-            return new DateRange(start, end, start + "鑷�" + end);
-        }
-        if (!StringUtils.hasText(timeRange)) {
-            return new DateRange(today.minusDays(6), today, "杩�7澶�");
-        }
-
-        String text = timeRange.trim();
-        if (text.contains("浠婂ぉ")) {
-            return new DateRange(today, today, "浠婂ぉ");
-        }
-        if (text.contains("鏄ㄥぉ") || text.contains("鏄ㄦ棩")) {
-            LocalDate day = today.minusDays(1);
-            return new DateRange(day, day, "鏄ㄥぉ");
-        }
-        if (text.contains("鏈懆")) {
-            LocalDate start = today.minusDays(today.getDayOfWeek().getValue() - 1L);
-            return new DateRange(start, today, "鏈懆");
-        }
-        if (text.contains("涓婂懆")) {
-            LocalDate thisWeekStart = today.minusDays(today.getDayOfWeek().getValue() - 1L);
-            LocalDate start = thisWeekStart.minusWeeks(1);
-            LocalDate end = thisWeekStart.minusDays(1);
-            return new DateRange(start, end, "涓婂懆");
-        }
-        if (text.contains("鏈湀")) {
-            LocalDate start = today.withDayOfMonth(1);
-            return new DateRange(start, today, "鏈湀");
-        }
-        if (text.contains("涓婃湀")) {
-            YearMonth lastMonth = YearMonth.from(today).minusMonths(1);
-            return new DateRange(lastMonth.atDay(1), lastMonth.atEndOfMonth(), "涓婃湀");
-        }
-        if (text.contains("鏈勾") || text.contains("浠婂勾")) {
-            LocalDate start = today.withDayOfYear(1);
-            return new DateRange(start, today, "鏈勾");
-        }
-        if (text.contains("鍘诲勾")) {
-            LocalDate start = today.minusYears(1).withDayOfYear(1);
-            LocalDate end = today.minusYears(1).withMonth(12).withDayOfMonth(31);
-            return new DateRange(start, end, "鍘诲勾");
-        }
-
-        Matcher relativeMatcher = java.util.regex.Pattern.compile("(杩憒鏈�杩�)(\\d+)(澶﹟鍛▅涓湀|鏈坾骞�)").matcher(text);
-        if (relativeMatcher.find()) {
-            int amount = Integer.parseInt(relativeMatcher.group(2));
-            String unit = relativeMatcher.group(3);
-            LocalDate start = switch (unit) {
-                case "澶�" -> today.minusDays(Math.max(amount - 1L, 0));
-                case "鍛�" -> today.minusWeeks(Math.max(amount, 1)).plusDays(1);
-                case "涓湀", "鏈�" -> today.minusMonths(Math.max(amount, 1)).plusDays(1);
-                case "骞�" -> today.minusYears(Math.max(amount, 1)).plusDays(1);
-                default -> today.minusDays(6);
-            };
-            return new DateRange(start, today, "杩�" + amount + unit);
-        }
-
-        Matcher dateMatcher = java.util.regex.Pattern.compile("(\\d{4}-\\d{2}-\\d{2})").matcher(text);
-        if (dateMatcher.find()) {
-            LocalDate start = LocalDate.parse(dateMatcher.group(1));
-            LocalDate end = dateMatcher.find() ? LocalDate.parse(dateMatcher.group(1)) : start;
-            if (start.isAfter(end)) {
-                LocalDate temp = start;
-                start = end;
-                end = temp;
-            }
-            return new DateRange(start, end, start + "鑷�" + end);
-        }
-
-        return new DateRange(today.minusDays(6), today, "杩�7澶�");
-    }
-
-    private boolean withinDateRange(LocalDateTime createTime, DateRange dateRange) {
-        if (createTime == null) {
-            return false;
-        }
-        LocalDate date = createTime.toLocalDate();
-        return !date.isBefore(dateRange.start()) && !date.isAfter(dateRange.end());
-    }
-
-    private TrendRange buildTrendRange(LocalDate start, LocalDate end, List<ApproveProcess> processes) {
-        long days = ChronoUnit.DAYS.between(start, end) + 1;
-        if (days <= 31) {
-            List<String> labels = new ArrayList<>();
-            List<Long> values = new ArrayList<>();
-            for (LocalDate cursor = start; !cursor.isAfter(end); cursor = cursor.plusDays(1)) {
-                LocalDate current = cursor;
-                labels.add(current.toString());
-                values.add(processes.stream()
-                        .filter(process -> process.getCreateTime() != null)
-                        .filter(process -> process.getCreateTime().toLocalDate().equals(current))
-                        .count());
-            }
-            return new TrendRange(labels, values, "day", start + "鑷�" + end);
-        }
-
-        List<String> labels = new ArrayList<>();
-        List<Long> values = new ArrayList<>();
-        YearMonth startMonth = YearMonth.from(start);
-        YearMonth endMonth = YearMonth.from(end);
-        for (YearMonth cursor = startMonth; !cursor.isAfter(endMonth); cursor = cursor.plusMonths(1)) {
-            YearMonth current = cursor;
-            labels.add(current.toString());
-            values.add(processes.stream()
-                    .filter(process -> process.getCreateTime() != null)
-                    .filter(process -> YearMonth.from(process.getCreateTime()).equals(current))
-                    .count());
-        }
-        return new TrendRange(labels, values, "month", start + "鑷�" + end);
-    }
-
-    private LocalDate parseLocalDate(String text) {
-        if (!StringUtils.hasText(text)) {
-            return null;
-        }
-        return LocalDate.parse(text.trim());
-    }
-
-    private String actionResult(boolean success, String type, String description, String approveId, Map<String, Object> data) {
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("approveId", safe(approveId));
-        return jsonResponse(success, type, description, summary, data == null ? Map.of() : data, Map.of());
-    }
-
-    private String jsonResponse(boolean success,
-                                String type,
-                                String description,
-                                Map<String, Object> summary,
-                                Map<String, Object> data,
-                                Map<String, Object> charts) {
-        Map<String, Object> result = new LinkedHashMap<>();
-        result.put("success", success);
-        result.put("type", type);
-        result.put("description", description);
-        result.put("summary", summary == null ? Map.of() : summary);
-        result.put("data", data == null ? Map.of() : data);
-        result.put("charts", charts == null ? Map.of() : charts);
-        return JSON.toJSONString(result);
-    }
-
-    private LoginUser currentLoginUser(String memoryId) {
-        LoginUser loginUser = aiSessionUserContext.get(memoryId);
-        if (loginUser != null) {
-            return loginUser;
-        }
-        return SecurityUtils.getLoginUser();
-    }
-
-    private Long currentUserId(String memoryId) {
-        return currentLoginUser(memoryId).getUserId();
-    }
-
-    private boolean isAdmin(Long userId) {
-        return SecurityUtils.isAdmin(userId);
-    }
-
-    private <T> List<T> defaultList(List<T> list) {
-        return list == null ? List.of() : list;
-    }
-
-    private record DateRange(LocalDate start, LocalDate end, String label) {
-    }
-
-    private record TrendRange(List<String> labels, List<Long> values, String granularity, String label) {
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/tools/FinancialAgentTools.java b/src/main/java/com/ruoyi/ai/tools/FinancialAgentTools.java
deleted file mode 100644
index e907aff..0000000
--- a/src/main/java/com/ruoyi/ai/tools/FinancialAgentTools.java
+++ /dev/null
@@ -1,2311 +0,0 @@
-package com.ruoyi.ai.tools;
-
-import com.alibaba.fastjson2.JSON;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
-import com.ruoyi.account.mapper.AccountStatementMapper;
-import com.ruoyi.account.mapper.purchase.AccountPurchasePaymentMapper;
-import com.ruoyi.account.mapper.sales.AccountSalesCollectionMapper;
-import com.ruoyi.account.pojo.AccountStatement;
-import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
-import com.ruoyi.account.pojo.sales.AccountSalesCollection;
-import com.ruoyi.account.service.impl.AccountingServiceImpl;
-import com.ruoyi.ai.context.AiSessionUserContext;
-import com.ruoyi.basic.mapper.CustomerMapper;
-import com.ruoyi.basic.mapper.ProductMapper;
-import com.ruoyi.basic.mapper.ProductModelMapper;
-import com.ruoyi.basic.mapper.SupplierManageMapper;
-import com.ruoyi.basic.pojo.Customer;
-import com.ruoyi.basic.pojo.Product;
-import com.ruoyi.basic.pojo.ProductModel;
-import com.ruoyi.basic.pojo.SupplierManage;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.device.mapper.DeviceLedgerMapper;
-import com.ruoyi.device.mapper.DeviceRepairMapper;
-import com.ruoyi.device.pojo.DeviceLedger;
-import com.ruoyi.device.pojo.DeviceRepair;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
-import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper;
-import com.ruoyi.procurementrecord.pojo.ProcurementRecordOut;
-import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
-import com.ruoyi.production.mapper.ProductionAccountMapper;
-import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
-import com.ruoyi.production.mapper.ProductionOrderMapper;
-import com.ruoyi.production.mapper.ProductionPlanMapper;
-import com.ruoyi.production.mapper.ProductionProductMainMapper;
-import com.ruoyi.production.mapper.ProductionProductOutputMapper;
-import com.ruoyi.production.pojo.ProductionAccount;
-import com.ruoyi.production.pojo.ProductionOperationTask;
-import com.ruoyi.production.pojo.ProductionOrder;
-import com.ruoyi.production.pojo.ProductionPlan;
-import com.ruoyi.production.pojo.ProductionProductMain;
-import com.ruoyi.production.pojo.ProductionProductOutput;
-import com.ruoyi.sales.mapper.SalesLedgerMapper;
-import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.pojo.SalesLedger;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import com.ruoyi.stock.mapper.StockInventoryMapper;
-import com.ruoyi.stock.pojo.StockInventory;
-import com.ruoyi.technology.mapper.TechnologyOperationMapper;
-import com.ruoyi.technology.pojo.TechnologyOperation;
-import dev.langchain4j.agent.tool.P;
-import dev.langchain4j.agent.tool.Tool;
-import dev.langchain4j.agent.tool.ToolMemoryId;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.YearMonth;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-@Component
-public class FinancialAgentTools {
-
-    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final Pattern RELATIVE_PATTERN = Pattern.compile("(杩憒鏈�杩�)?\\s*(\\d+)\\s*(澶﹟鍛▅涓湀|鏈坾骞�)");
-    private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2})");
-    private static final BigDecimal ONE_HUNDRED = new BigDecimal("100");
-    private static final int DEFAULT_LIMIT = 10;
-    private static final int MAX_LIMIT = 50;
-
-    private static final BigDecimal DEFAULT_FALLBACK_MATERIAL_COST_RATE = new BigDecimal("0.60");
-    private static final BigDecimal DEFAULT_LABOR_COST_RATE = new BigDecimal("0.15");
-    private static final BigDecimal DEFAULT_OVERHEAD_COST_RATE = new BigDecimal("0.10");
-
-    private static final BigDecimal SME_RECEIVABLE_RISK_THRESHOLD = new BigDecimal("500000");
-    private static final BigDecimal SME_INVENTORY_RISK_THRESHOLD = new BigDecimal("1000000");
-    private static final BigDecimal SME_PROFIT_WARNING_RATE = new BigDecimal("0.08");
-
-    private final SalesLedgerMapper salesLedgerMapper;
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-    private final ProductionAccountMapper productionAccountMapper;
-    private final ProductionProductMainMapper productionProductMainMapper;
-    private final ProductionOperationTaskMapper productionOperationTaskMapper;
-    private final ProductionOrderMapper productionOrderMapper;
-    private final ProductionPlanMapper productionPlanMapper;
-    private final ProductionProductOutputMapper productionProductOutputMapper;
-    private final TechnologyOperationMapper technologyOperationMapper;
-    private final DeviceLedgerMapper deviceLedgerMapper;
-    private final DeviceRepairMapper deviceRepairMapper;
-    private final ProcurementRecordMapper procurementRecordMapper;
-    private final ProcurementRecordOutMapper procurementRecordOutMapper;
-    private final StockInventoryMapper stockInventoryMapper;
-    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
-    private final AccountPurchasePaymentMapper accountPurchasePaymentMapper;
-    private final AccountStatementMapper accountStatementMapper;
-    private final CustomerMapper customerMapper;
-    private final SupplierManageMapper supplierManageMapper;
-    private final ProductModelMapper productModelMapper;
-    private final ProductMapper productMapper;
-    private final AiSessionUserContext aiSessionUserContext;
-
-    public FinancialAgentTools(SalesLedgerMapper salesLedgerMapper,
-                               SalesLedgerProductMapper salesLedgerProductMapper,
-                               ProductionAccountMapper productionAccountMapper,
-                               ProductionProductMainMapper productionProductMainMapper,
-                               ProductionOperationTaskMapper productionOperationTaskMapper,
-                               ProductionOrderMapper productionOrderMapper,
-                               ProductionPlanMapper productionPlanMapper,
-                               ProductionProductOutputMapper productionProductOutputMapper,
-                               TechnologyOperationMapper technologyOperationMapper,
-                               DeviceLedgerMapper deviceLedgerMapper,
-                               DeviceRepairMapper deviceRepairMapper,
-                               ProcurementRecordMapper procurementRecordMapper,
-                               ProcurementRecordOutMapper procurementRecordOutMapper,
-                               StockInventoryMapper stockInventoryMapper,
-                               AccountSalesCollectionMapper accountSalesCollectionMapper,
-                               AccountPurchasePaymentMapper accountPurchasePaymentMapper,
-                               AccountStatementMapper accountStatementMapper,
-                               CustomerMapper customerMapper,
-                               SupplierManageMapper supplierManageMapper,
-                               ProductModelMapper productModelMapper,
-                               ProductMapper productMapper,
-                               AiSessionUserContext aiSessionUserContext) {
-        this.salesLedgerMapper = salesLedgerMapper;
-        this.salesLedgerProductMapper = salesLedgerProductMapper;
-        this.productionAccountMapper = productionAccountMapper;
-        this.productionProductMainMapper = productionProductMainMapper;
-        this.productionOperationTaskMapper = productionOperationTaskMapper;
-        this.productionOrderMapper = productionOrderMapper;
-        this.productionPlanMapper = productionPlanMapper;
-        this.productionProductOutputMapper = productionProductOutputMapper;
-        this.technologyOperationMapper = technologyOperationMapper;
-        this.deviceLedgerMapper = deviceLedgerMapper;
-        this.deviceRepairMapper = deviceRepairMapper;
-        this.procurementRecordMapper = procurementRecordMapper;
-        this.procurementRecordOutMapper = procurementRecordOutMapper;
-        this.stockInventoryMapper = stockInventoryMapper;
-        this.accountSalesCollectionMapper = accountSalesCollectionMapper;
-        this.accountPurchasePaymentMapper = accountPurchasePaymentMapper;
-        this.accountStatementMapper = accountStatementMapper;
-        this.customerMapper = customerMapper;
-        this.supplierManageMapper = supplierManageMapper;
-        this.productModelMapper = productModelMapper;
-        this.productMapper = productMapper;
-        this.aiSessionUserContext = aiSessionUserContext;
-    }
-
-    @Tool(name = "璐㈠姟鐭ヨ瘑妫�绱�", value = "鎸夎储鍔$粡钀ラ棶棰樻绱笟璐㈣瀺鍚堢煡璇嗙墖娈典笌鎸囨爣鍙e緞锛屼綔涓篟AG涓婁笅鏂囥��")
-    public String retrieveFinancialKnowledge(@ToolMemoryId String memoryId,
-                                             @P(value = "闂鎴栧叧閿瘝锛屼緥濡傚埄娑︿笅闄嶃�佸簱瀛樺懆杞�佽祫閲戠己鍙�") String question) {
-        List<KnowledgeDoc> knowledgeDocs = financeKnowledgeBase();
-        String normalized = normalizeForMatch(question);
-        List<KnowledgeDoc> ranked = knowledgeDocs.stream()
-                .sorted(Comparator.comparingInt((KnowledgeDoc doc) -> keywordHitCount(doc.keywords(), normalized)).reversed())
-                .filter(doc -> keywordHitCount(doc.keywords(), normalized) > 0 || !StringUtils.hasText(normalized))
-                .limit(5)
-                .toList();
-
-        List<Map<String, Object>> items = ranked.stream().map(doc -> {
-            Map<String, Object> map = new LinkedHashMap<>();
-            map.put("topic", doc.topic());
-            map.put("knowledge", doc.knowledge());
-            map.put("relatedTables", doc.relatedTables());
-            map.put("suggestedQuestions", doc.suggestedQuestions());
-            return map;
-        }).toList();
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("question", safe(question));
-        summary.put("hitCount", items.size());
-        summary.put("retrievalMode", "keyword_rag");
-        return jsonResponse(true, "financial_rag_knowledge", "宸茶繑鍥炶储鍔$煡璇嗘绱㈢粨鏋�", summary, Map.of("items", items), Map.of());
-    }
-
-    @Tool(name = "鏅鸿兘鎴愭湰鏍哥畻", value = "鑷姩鏍哥畻浜у搧鎴愭湰銆佸伐搴忔垚鏈�佷汉宸ユ垚鏈�佽澶囨姌鏃с�佹潗鏂欐崯鑰椾笌璁㈠崟鍒╂鼎銆�")
-    public String calculateIntelligentCost(@ToolMemoryId String memoryId,
-                                           @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                           @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                           @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屽鏈湀銆佽繎30澶�", required = false) String timeRange,
-                                           @P(value = "鍏抽敭璇嶏紝鍙尮閰嶅悎鍚屽彿/瀹㈡埛/椤圭洰", required = false) String keyword,
-                                           @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�50", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        if (loginUser == null) {
-            return jsonResponse(false, "financial_cost_accounting", "鐢ㄦ埛淇℃伅鑾峰彇澶辫触", Map.of(), Map.of(), Map.of());
-        }
-
-        DateRange range = resolveDateRange(startDate, endDate, timeRange, "杩�30澶�");
-        AnalysisBundle bundle = buildOrderProfitBundle(loginUser, range, keyword, limit);
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", displayDate(range.start()));
-        summary.put("endDate", displayDate(range.end()));
-        summary.put("orderCount", bundle.orderMetrics().size());
-        summary.put("totalRevenue", bundle.totalRevenue());
-        summary.put("totalMaterialCost", bundle.totalMaterialCost());
-        summary.put("totalLaborCost", bundle.totalLaborCost());
-        summary.put("totalDepreciationCost", bundle.totalDepreciationCost());
-        summary.put("totalScrapCost", bundle.totalScrapCost());
-        summary.put("totalCost", bundle.totalCost());
-        summary.put("totalProfit", bundle.totalProfit());
-        summary.put("profitRate", toPercent(rate(bundle.totalProfit(), bundle.totalRevenue())));
-
-        List<Map<String, Object>> orderItems = bundle.orderMetrics().stream()
-                .map(this::toOrderCostItem)
-                .toList();
-        List<Map<String, Object>> processItems = bundle.processCostRanking().entrySet().stream()
-                .map(entry -> {
-                    Map<String, Object> map = new LinkedHashMap<>();
-                    map.put("processName", entry.getKey());
-                    map.put("cost", entry.getValue());
-                    return map;
-                }).toList();
-
-        List<Map<String, Object>> topCustomerItems = buildCustomerProfitTop(bundle.orderMetrics(), 5);
-
-        Map<String, Object> charts = new LinkedHashMap<>();
-        charts.put("costCompositionPieOption",
-                buildCostCompositionPie(bundle.totalMaterialCost(), bundle.totalLaborCost(), bundle.totalDepreciationCost(), bundle.totalScrapCost()));
-        charts.put("orderProfitBarOption", buildOrderProfitBar(bundle.orderMetrics()));
-        charts.put("processCostBarOption", buildProcessCostBar(bundle.processCostRanking()));
-
-        return jsonResponse(true, "financial_cost_accounting", "宸插畬鎴愭櫤鑳芥垚鏈牳绠�", summary,
-                Map.of(
-                        "orders", orderItems,
-                        "processCostRanking", processItems,
-                        "topCustomers", topCustomerItems
-                ),
-                charts
-        );
-    }
-
-    @Tool(name = "璁㈠崟鍒╂鼎鍒嗘瀽", value = "璇嗗埆浣庡埄娑�/浜忔崯璁㈠崟锛岃緭鍑哄師鍥犲垎鏋愬拰浼樺寲寤鸿銆�")
-    public String analyzeOrderProfit(@ToolMemoryId String memoryId,
-                                     @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                     @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                     @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屽鏈湀銆佽繎30澶�", required = false) String timeRange,
-                                     @P(value = "鍏抽敭璇嶏紝鍙尮閰嶅悎鍚屽彿/瀹㈡埛/椤圭洰", required = false) String keyword,
-                                     @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�50", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        if (loginUser == null) {
-            return jsonResponse(false, "financial_order_profit_analysis", "鐢ㄦ埛淇℃伅鑾峰彇澶辫触", Map.of(), Map.of(), Map.of());
-        }
-
-        DateRange range = resolveDateRange(startDate, endDate, timeRange, "杩�30澶�");
-        AnalysisBundle bundle = buildOrderProfitBundle(loginUser, range, keyword, limit);
-        List<OrderProfitMetric> metrics = bundle.orderMetrics();
-
-        List<OrderProfitMetric> riskyOrders = metrics.stream()
-                .filter(item -> item.profit().compareTo(BigDecimal.ZERO) < 0 || item.profitRate().compareTo(SME_PROFIT_WARNING_RATE) < 0)
-                .sorted(Comparator.comparing(OrderProfitMetric::profitRate)
-                        .thenComparing(OrderProfitMetric::profit))
-                .toList();
-
-        Map<String, BigDecimal> customerProfitMap = new LinkedHashMap<>();
-        for (OrderProfitMetric metric : metrics) {
-            customerProfitMap.merge(metric.customerName(), metric.profit(), BigDecimal::add);
-        }
-        Map.Entry<String, BigDecimal> topCustomer = customerProfitMap.entrySet().stream()
-                .max(Map.Entry.comparingByValue())
-                .orElse(Map.entry("鏆傛棤鏁版嵁", BigDecimal.ZERO));
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", displayDate(range.start()));
-        summary.put("endDate", displayDate(range.end()));
-        summary.put("orderCount", metrics.size());
-        summary.put("lossOrderCount", metrics.stream().filter(item -> item.profit().compareTo(BigDecimal.ZERO) < 0).count());
-        summary.put("lowProfitOrderCount", riskyOrders.size());
-        summary.put("avgProfitRate", toPercent(avgRate(metrics)));
-        summary.put("topCustomerByProfit", topCustomer.getKey());
-        summary.put("topCustomerProfit", topCustomer.getValue());
-
-        List<Map<String, Object>> riskyItems = riskyOrders.stream()
-                .limit(normalizeLimit(limit))
-                .map(this::toRiskOrderItem)
-                .toList();
-
-        Map<String, Object> charts = new LinkedHashMap<>();
-        charts.put("profitDistributionOption", buildProfitDistributionBar(metrics));
-        charts.put("lossOrderTrendOption", buildLossOrderTrendLine(metrics));
-        charts.put("customerProfitTopOption", buildCustomerProfitBar(customerProfitMap));
-
-        return jsonResponse(true, "financial_order_profit_analysis", "宸插畬鎴愯鍗曞埄娑﹀垎鏋�", summary,
-                Map.of(
-                        "riskOrders", riskyItems,
-                        "allOrders", metrics.stream().map(this::toOrderCostItem).toList(),
-                        "customerProfitTop", buildCustomerProfitTop(metrics, 10)
-                ),
-                charts
-        );
-    }
-
-    @Tool(name = "搴撳瓨璧勯噾鍒嗘瀽", value = "鍒嗘瀽搴撳瓨绉帇銆佸憜婊炲簱瀛樸�佽祫閲戝崰鐢ㄤ笌鍛ㄨ浆鐜囥��")
-    public String analyzeInventoryCapital(@ToolMemoryId String memoryId,
-                                          @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                          @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                          @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屽鏈湀銆佽繎30澶�", required = false) String timeRange,
-                                          @P(value = "鍏抽敭璇嶏紝鍙尮閰嶄骇鍝佸悕绉�/鍨嬪彿", required = false) String keyword,
-                                          @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�50", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, timeRange, "杩�30澶�");
-        int finalLimit = normalizeLimit(limit);
-
-        List<StockInventory> inventoryRows = queryStockInventory(loginUser);
-        if (inventoryRows.isEmpty()) {
-            return jsonResponse(true, "financial_inventory_capital_analysis", "褰撳墠鏃犲簱瀛樻暟鎹�",
-                    rangeSummary(range, 0, keyword), Map.of("items", List.of()), Map.of());
-        }
-
-        Set<Long> modelIds = inventoryRows.stream()
-                .map(StockInventory::getProductModelId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        Map<Long, ProductModel> productModelMap = queryProductModels(modelIds);
-        Map<Long, Product> productMap = queryProducts(productModelMap.values());
-        Map<Long, BigDecimal> avgUnitCostByModelId = queryAverageUnitCostByModel(loginUser, modelIds);
-        OutboundStats outboundStats = queryOutboundStats(loginUser, modelIds, range);
-
-        List<InventoryMetric> metrics = buildInventoryMetrics(inventoryRows, productModelMap, productMap, avgUnitCostByModelId, outboundStats)
-                .stream()
-                .filter(metric -> matchInventoryKeyword(metric, keyword))
-                .sorted(Comparator.comparing(InventoryMetric::inventoryValue).reversed())
-                .toList();
-
-        BigDecimal totalInventoryValue = metrics.stream().map(InventoryMetric::inventoryValue).reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal stagnantValue = metrics.stream()
-                .filter(metric -> metric.stagnantDays() >= 90)
-                .map(InventoryMetric::inventoryValue)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        long stagnantCount = metrics.stream().filter(metric -> metric.stagnantDays() >= 90).count();
-        long overstockCount = metrics.stream().filter(InventoryMetric::overstock).count();
-        BigDecimal totalOutboundCost = outboundStats.totalOutboundCost();
-        BigDecimal turnoverDays = totalOutboundCost.compareTo(BigDecimal.ZERO) > 0
-                ? totalInventoryValue.multiply(BigDecimal.valueOf(daysBetween(range.start(), range.end()) + 1L))
-                .divide(totalOutboundCost, 2, RoundingMode.HALF_UP)
-                : BigDecimal.ZERO;
-
-        List<Map<String, Object>> items = metrics.stream()
-                .limit(finalLimit)
-                .map(this::toInventoryItem)
-                .toList();
-
-        Map<String, Object> summary = rangeSummary(range, metrics.size(), keyword);
-        summary.put("totalInventoryValue", totalInventoryValue);
-        summary.put("stagnantValue", stagnantValue);
-        summary.put("stagnantCount", stagnantCount);
-        summary.put("overstockCount", overstockCount);
-        summary.put("turnoverDays", turnoverDays);
-        summary.put("capitalOccupation", totalInventoryValue);
-        summary.put("totalOutboundCost", totalOutboundCost);
-
-        Map<String, Object> charts = new LinkedHashMap<>();
-        charts.put("inventoryValueTopOption", buildInventoryTopBar(metrics));
-        charts.put("inventoryAgingPieOption", buildInventoryAgingPie(metrics));
-        charts.put("inventoryTurnoverGauge", buildTurnoverGauge(turnoverDays));
-
-        return jsonResponse(true, "financial_inventory_capital_analysis", "宸插畬鎴愬簱瀛樿祫閲戝垎鏋�", summary, Map.of("items", items), charts);
-    }
-
-    @Tool(name = "搴旀敹搴斾粯涓庣幇閲戞祦棰勬祴", value = "棰勬祴鏈潵鐜伴噾娴併�佸洖娆鹃闄┿�佷粯娆惧帇鍔涗笌璧勯噾缂哄彛銆�")
-    public String forecastCashFlow(@ToolMemoryId String memoryId,
-                                   @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                   @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                   @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屽杩�90澶┿�佹湰骞�", required = false) String timeRange,
-                                   @P(value = "棰勬祴鏈堜唤鏁帮紝榛樿3锛屾渶澶�6", required = false) Integer forecastMonths) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, timeRange, "杩�90澶�");
-        int months = forecastMonths == null || forecastMonths <= 0 ? 3 : Math.min(forecastMonths, 6);
-
-        List<AccountSalesCollection> collections = queryCollections(loginUser, range);
-        List<AccountPurchasePayment> payments = queryPayments(loginUser, range);
-        List<MonthlyCashFlow> monthlyActual = buildMonthlyCashFlow(range, collections, payments);
-        List<MonthlyCashFlow> monthlyForecast = forecastMonthlyCashFlow(monthlyActual, months);
-
-        StatementSnapshot snapshot = buildStatementSnapshot(loginUser);
-        BigDecimal receivableTotal = snapshot.receivableTotal();
-        BigDecimal payableTotal = snapshot.payableTotal();
-        BigDecimal forecastNetSum = monthlyForecast.stream().map(MonthlyCashFlow::netFlow).reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal coverage = receivableTotal.add(maxZero(forecastNetSum));
-        BigDecimal fundGap = maxZero(payableTotal.subtract(coverage));
-
-        Map<String, String> customerNameMap = queryCustomerNameMap(snapshot.receivableTop().stream().map(StatementMetric::entityId).collect(Collectors.toSet()));
-        Map<String, String> supplierNameMap = querySupplierNameMap(snapshot.payableTop().stream().map(StatementMetric::entityId).collect(Collectors.toSet()));
-
-        List<Map<String, Object>> receivableRiskItems = snapshot.receivableTop().stream().map(item -> toStatementRiskItem(item, customerNameMap, "customer")).toList();
-        List<Map<String, Object>> payablePressureItems = snapshot.payableTop().stream().map(item -> toStatementRiskItem(item, supplierNameMap, "supplier")).toList();
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", displayDate(range.start()));
-        summary.put("endDate", displayDate(range.end()));
-        summary.put("actualIncomeTotal", collections.stream().map(AccountSalesCollection::getCollectionAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
-        summary.put("actualExpenseTotal", payments.stream().map(AccountPurchasePayment::getPaymentAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
-        summary.put("receivableBalance", receivableTotal);
-        summary.put("payableBalance", payableTotal);
-        summary.put("forecastNetSum", forecastNetSum);
-        summary.put("fundGap", fundGap);
-        summary.put("forecastMonths", months);
-        summary.put("collectionRiskLevel", riskLevelByAmount(receivableTotal));
-        summary.put("paymentPressureLevel", riskLevelByAmount(payableTotal));
-
-        Map<String, Object> charts = new LinkedHashMap<>();
-        charts.put("cashFlowTrendOption", buildCashflowTrend(monthlyActual, monthlyForecast));
-        charts.put("receivablePayableBarOption", buildReceivablePayableBar(receivableTotal, payableTotal));
-        charts.put("fundGapGaugeOption", buildFundGapGauge(fundGap));
-
-        return jsonResponse(true, "financial_cashflow_forecast", "宸插畬鎴愬簲鏀跺簲浠樹笌鐜伴噾娴侀娴�", summary,
-                Map.of(
-                        "actualMonthly", monthlyActual.stream().map(this::toMonthlyCashFlowItem).toList(),
-                        "forecastMonthly", monthlyForecast.stream().map(this::toMonthlyCashFlowItem).toList(),
-                        "receivableRiskTop", receivableRiskItems,
-                        "payablePressureTop", payablePressureItems
-                ),
-                charts
-        );
-    }
-
-    @Tool(name = "缁忚惀寮傚父棰勮", value = "璇嗗埆鎴愭湰寮傚父銆佸埄娑﹀紓甯搞�佸洖娆惧紓甯搞�佽鍗曢闄┿�佸簱瀛樺紓甯搞��")
-    public String detectBusinessAnomalies(@ToolMemoryId String memoryId,
-                                          @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                          @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                          @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屽杩�30澶�", required = false) String timeRange,
-                                          @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�50", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, timeRange, "杩�30澶�");
-        int finalLimit = normalizeLimit(limit);
-
-        AnalysisBundle currentBundle = buildOrderProfitBundle(loginUser, range, null, Math.max(finalLimit, 30));
-        DateRange prevRange = previousSameLengthRange(range);
-        AnalysisBundle prevBundle = buildOrderProfitBundle(loginUser, prevRange, null, 50);
-
-        BigDecimal currentCostRate = rate(currentBundle.totalCost(), currentBundle.totalRevenue());
-        BigDecimal prevCostRate = rate(prevBundle.totalCost(), prevBundle.totalRevenue());
-        BigDecimal costRateDiff = currentCostRate.subtract(prevCostRate);
-
-        StatementSnapshot snapshot = buildStatementSnapshot(loginUser);
-        List<InventoryMetric> inventoryMetrics = buildInventoryMetrics(
-                queryStockInventory(loginUser),
-                queryProductModels(Collections.emptySet()),
-                Map.of(),
-                queryAverageUnitCostByModel(loginUser, Collections.emptySet()),
-                queryOutboundStats(loginUser, Collections.emptySet(), range)
-        );
-
-        List<Map<String, Object>> anomalyItems = new ArrayList<>();
-        if (costRateDiff.compareTo(new BigDecimal("0.10")) > 0) {
-            anomalyItems.add(anomalyItem("high", "鎴愭湰寮傚父", "鍗曚綅鏀跺叆鎴愭湰鐜囪緝涓婂懆鏈熶笂鍗囪秴杩�10%", Map.of(
-                    "currentCostRate", toPercent(currentCostRate),
-                    "previousCostRate", toPercent(prevCostRate),
-                    "delta", toPercent(costRateDiff)
-            )));
-        }
-        long lossCount = currentBundle.orderMetrics().stream().filter(item -> item.profit().compareTo(BigDecimal.ZERO) < 0).count();
-        if (lossCount > 0) {
-            anomalyItems.add(anomalyItem("high", "鍒╂鼎寮傚父", "妫�娴嬪埌浜忔崯璁㈠崟", Map.of("lossOrderCount", lossCount)));
-        }
-        if (snapshot.receivableTotal().compareTo(snapshot.payableTotal().multiply(new BigDecimal("1.2"))) > 0) {
-            anomalyItems.add(anomalyItem("medium", "鍥炴寮傚父", "搴旀敹浣欓鏄捐憲楂樹簬搴斾粯锛屽洖娆惧帇鍔涘亸澶�", Map.of(
-                    "receivableBalance", snapshot.receivableTotal(),
-                    "payableBalance", snapshot.payableTotal()
-            )));
-        }
-        long overdueOrderCount = currentBundle.orderMetrics().stream()
-                .filter(item -> item.deliveryDate() != null && item.deliveryDate().isBefore(LocalDate.now()) && item.profitRate().compareTo(new BigDecimal("0.10")) < 0)
-                .count();
-        if (overdueOrderCount > 0) {
-            anomalyItems.add(anomalyItem("medium", "璁㈠崟椋庨櫓", "瀛樺湪浣庡埄娑︿笖浜や粯宸查�炬湡璁㈠崟", Map.of("overdueRiskOrderCount", overdueOrderCount)));
-        }
-        long stagnantCount = inventoryMetrics.stream().filter(item -> item.stagnantDays() >= 90).count();
-        if (stagnantCount > 0) {
-            anomalyItems.add(anomalyItem("medium", "搴撳瓨寮傚父", "瀛樺湪瓒呰繃90澶╂湭鍛ㄨ浆搴撳瓨", Map.of("stagnantCount", stagnantCount)));
-        }
-
-        List<Map<String, Object>> topAnomalies = anomalyItems.stream().limit(finalLimit).toList();
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", displayDate(range.start()));
-        summary.put("endDate", displayDate(range.end()));
-        summary.put("anomalyCount", topAnomalies.size());
-        summary.put("highRiskCount", topAnomalies.stream().filter(item -> "high".equals(item.get("riskLevel"))).count());
-        summary.put("mediumRiskCount", topAnomalies.stream().filter(item -> "medium".equals(item.get("riskLevel"))).count());
-
-        Map<String, Object> charts = new LinkedHashMap<>();
-        charts.put("anomalyLevelPieOption", buildAnomalyLevelPie(topAnomalies));
-        charts.put("anomalyTypeBarOption", buildAnomalyTypeBar(topAnomalies));
-        return jsonResponse(true, "financial_business_anomaly_warning", "宸插畬鎴愮粡钀ュ紓甯搁璀﹀垎鏋�", summary,
-                Map.of("items", topAnomalies), charts);
-    }
-
-    @Tool(name = "AI缁忚惀椹鹃┒鑸�", value = "瀹炴椂灞曠ず浜у�笺�佸埄娑︺�佸簱瀛樸�佸洖娆俱�佽澶囧埄鐢ㄧ巼銆佽鍗曞埄娑︾巼绛夋牳蹇冪粡钀ユ寚鏍囥��")
-    public String getBusinessCockpit(@ToolMemoryId String memoryId,
-                                     @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                     @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                     @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屽鏈湀銆佽繎30澶�", required = false) String timeRange) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, timeRange, "鏈湀");
-
-        AnalysisBundle profitBundle = buildOrderProfitBundle(loginUser, range, null, 30);
-        StatementSnapshot snapshot = buildStatementSnapshot(loginUser);
-        List<StockInventory> inventories = queryStockInventory(loginUser);
-        BigDecimal inventoryValue = estimateInventoryValue(loginUser, inventories);
-
-        long deviceTotal = countDevices(loginUser);
-        long repairingCount = countRepairingDevices(loginUser);
-        BigDecimal deviceUtilization = deviceTotal > 0
-                ? new BigDecimal(deviceTotal - repairingCount).multiply(ONE_HUNDRED).divide(new BigDecimal(deviceTotal), 2, RoundingMode.HALF_UP)
-                : BigDecimal.ZERO;
-
-        BigDecimal outputValue = profitBundle.totalRevenue();
-        BigDecimal profitRate = rate(profitBundle.totalProfit(), profitBundle.totalRevenue());
-        BigDecimal collectionRate = snapshot.receivableTotal().compareTo(BigDecimal.ZERO) > 0
-                ? ONE_HUNDRED.subtract(rate(snapshot.receivableTotal(), snapshot.receivableTotal().add(snapshot.payableTotal())).multiply(ONE_HUNDRED))
-                : BigDecimal.ZERO;
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", displayDate(range.start()));
-        summary.put("endDate", displayDate(range.end()));
-        summary.put("outputValue", outputValue);
-        summary.put("profit", profitBundle.totalProfit());
-        summary.put("profitRate", toPercent(profitRate));
-        summary.put("inventoryValue", inventoryValue);
-        summary.put("receivableBalance", snapshot.receivableTotal());
-        summary.put("payableBalance", snapshot.payableTotal());
-        summary.put("collectionRate", toPercent(collectionRate.divide(ONE_HUNDRED, 4, RoundingMode.HALF_UP)));
-        summary.put("deviceUtilizationRate", deviceUtilization + "%");
-        summary.put("orderProfitRate", toPercent(avgRate(profitBundle.orderMetrics())));
-
-        Map<String, Object> indicators = new LinkedHashMap<>();
-        indicators.put("浜у��", outputValue);
-        indicators.put("鍒╂鼎", profitBundle.totalProfit());
-        indicators.put("搴撳瓨璧勯噾鍗犵敤", inventoryValue);
-        indicators.put("搴旀敹浣欓", snapshot.receivableTotal());
-        indicators.put("璁惧鍒╃敤鐜�", deviceUtilization + "%");
-        indicators.put("璁㈠崟骞冲潎鍒╂鼎鐜�", toPercent(avgRate(profitBundle.orderMetrics())));
-
-        Map<String, Object> charts = new LinkedHashMap<>();
-        charts.put("kpiCardData", indicators);
-        charts.put("profitTrendOption", buildOrderProfitBar(profitBundle.orderMetrics()));
-        charts.put("receivablePayableBarOption", buildReceivablePayableBar(snapshot.receivableTotal(), snapshot.payableTotal()));
-        charts.put("inventoryProfitGaugeOption", buildInventoryProfitGauge(inventoryValue, profitBundle.totalProfit()));
-
-        return jsonResponse(true, "financial_business_cockpit", "宸茬敓鎴怉I缁忚惀椹鹃┒鑸辨暟鎹�", summary,
-                Map.of(
-                        "orderProfitTop", profitBundle.orderMetrics().stream()
-                                .sorted(Comparator.comparing(OrderProfitMetric::profit).reversed())
-                                .limit(10)
-                                .map(this::toOrderCostItem)
-                                .toList(),
-                        "indicators", indicators
-                ),
-                charts
-        );
-    }
-
-    @Tool(name = "鏃ユ姤鍛ㄦ姤鑷姩鐢熸垚", value = "鑷姩杈撳嚭缁忚惀鍒嗘瀽鏃ユ姤/鍛ㄦ姤涓庨闄╁缓璁��")
-    public String generateOperationReport(@ToolMemoryId String memoryId,
-                                          @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                          @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                          @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屽浠婂ぉ銆佹湰鍛�", required = false) String timeRange,
-                                          @P(value = "鎶ュ憡绫诲瀷 daily/weekly", required = false) String reportType) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, timeRange,
-                "weekly".equalsIgnoreCase(reportType) ? "鏈懆" : "浠婂ぉ");
-        String type = "weekly".equalsIgnoreCase(reportType) ? "weekly" : "daily";
-
-        AnalysisBundle bundle = buildOrderProfitBundle(loginUser, range, null, 30);
-        StatementSnapshot snapshot = buildStatementSnapshot(loginUser);
-        BigDecimal inventoryValue = estimateInventoryValue(loginUser, queryStockInventory(loginUser));
-        long lossCount = bundle.orderMetrics().stream().filter(item -> item.profit().compareTo(BigDecimal.ZERO) < 0).count();
-
-        List<String> conclusions = new ArrayList<>();
-        conclusions.add("钀ユ敹" + bundle.totalRevenue() + "锛屽埄娑�" + bundle.totalProfit() + "锛屽埄娑︾巼" + toPercent(rate(bundle.totalProfit(), bundle.totalRevenue())) + "銆�");
-        conclusions.add("搴旀敹浣欓" + snapshot.receivableTotal() + "锛屽簲浠樹綑棰�" + snapshot.payableTotal() + "锛屽簱瀛樿祫閲戝崰鐢�" + inventoryValue + "銆�");
-        if (lossCount > 0) {
-            conclusions.add("鍙戠幇浜忔崯璁㈠崟" + lossCount + "涓紝寤鸿浼樺厛澶嶆牳鏉愭枡鎹熻�楀拰宸ュ簭浜哄伐鏁堢巼銆�");
-        } else {
-            conclusions.add("褰撳墠鏈彂鐜颁簭鎹熻鍗曪紝寤鸿鎸佺画璺熻釜浣庝簬8%鍒╂鼎鐜囪鍗曘��");
-        }
-        if (snapshot.receivableTotal().compareTo(snapshot.payableTotal()) > 0) {
-            conclusions.add("鍥炴鍘嬪姏鍋忛珮锛屽缓璁拡瀵归珮搴旀敹瀹㈡埛鎵ц鍒嗗眰鍌敹涓庤处鏈熶紭鍖栥��");
-        } else {
-            conclusions.add("璧勯噾鍘嬪姏鍙帶锛屽缓璁繚鎸佷粯娆捐鍒掍笌閲囪喘鑺傚鑱斿姩銆�");
-        }
-
-        List<Map<String, Object>> riskSuggestions = new ArrayList<>();
-        if (lossCount > 0) {
-            riskSuggestions.add(riskSuggestion("鍒╂鼎椋庨櫓", "楂�", "澶嶆牳浜忔崯璁㈠崟BOM鍜屽伐搴忓伐璧勫畾棰濓紝蹇呰鏃惰皟鏁存姤浠蜂笌浜や粯鑺傚銆�"));
-        }
-        if (snapshot.receivableTotal().compareTo(SME_RECEIVABLE_RISK_THRESHOLD) > 0) {
-            riskSuggestions.add(riskSuggestion("鍥炴椋庨櫓", "涓�", "瀵瑰簲鏀禩OP瀹㈡埛寤虹珛鍛ㄥ害鍥炴璁″垝锛屽苟璁剧疆棰勮闃堝�笺��"));
-        }
-        if (inventoryValue.compareTo(SME_INVENTORY_RISK_THRESHOLD) > 0) {
-            riskSuggestions.add(riskSuggestion("搴撳瓨椋庨櫓", "涓�", "瀵归珮閲戦鍛嗘粸搴撳瓨鎵ц闄嶄环銆佹浛浠e拰鐢熶骇娑堣�楃瓥鐣ャ��"));
-        }
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("reportType", type);
-        summary.put("timeRange", range.label());
-        summary.put("startDate", displayDate(range.start()));
-        summary.put("endDate", displayDate(range.end()));
-        summary.put("orderCount", bundle.orderMetrics().size());
-        summary.put("lossOrderCount", lossCount);
-        summary.put("riskSuggestionCount", riskSuggestions.size());
-
-        Map<String, Object> data = new LinkedHashMap<>();
-        data.put("headline", "weekly".equals(type) ? "缁忚惀鍛ㄦ姤" : "缁忚惀鏃ユ姤");
-        data.put("conclusions", conclusions);
-        data.put("riskSuggestions", riskSuggestions);
-        data.put("orderProfitTop", bundle.orderMetrics().stream()
-                .sorted(Comparator.comparing(OrderProfitMetric::profitRate))
-                .limit(10)
-                .map(this::toRiskOrderItem)
-                .toList());
-
-        Map<String, Object> charts = new LinkedHashMap<>();
-        charts.put("reportProfitBarOption", buildOrderProfitBar(bundle.orderMetrics()));
-        charts.put("reportReceivablePayableOption", buildReceivablePayableBar(snapshot.receivableTotal(), snapshot.payableTotal()));
-        return jsonResponse(true, "financial_operation_report", "宸茶嚜鍔ㄧ敓鎴愮粡钀ュ垎鏋愭姤鍛�", summary, data, charts);
-    }
-
-    private AnalysisBundle buildOrderProfitBundle(LoginUser loginUser, DateRange range, String keyword, Integer limit) {
-        List<SalesLedger> ledgers = querySalesLedgers(loginUser, range, keyword, limit);
-        if (ledgers.isEmpty()) {
-            return AnalysisBundle.empty();
-        }
-
-        List<Long> ledgerIds = ledgers.stream().map(SalesLedger::getId).filter(Objects::nonNull).toList();
-        List<SalesLedgerProduct> ledgerProducts = queryLedgerProducts(loginUser, ledgerIds);
-        Map<Long, List<SalesLedgerProduct>> productsByLedgerId = ledgerProducts.stream()
-                .collect(Collectors.groupingBy(SalesLedgerProduct::getSalesLedgerId));
-
-        MaterialCostResult materialCostResult = calculateMaterialCost(loginUser, range, ledgerProducts);
-        ProductionCostContext productionCostContext = calculateProductionCost(loginUser, range, ledgers, ledgerProducts, materialCostResult.avgUnitCostByModelId());
-        BigDecimal totalDepreciation = calculateTotalDepreciation(loginUser);
-
-        BigDecimal totalRevenue = ledgers.stream()
-                .map(SalesLedger::getContractAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        Map<Long, BigDecimal> depreciationCostByLedger = allocateDepreciation(ledgers, totalDepreciation, totalRevenue);
-
-        List<OrderProfitMetric> metrics = new ArrayList<>();
-        for (SalesLedger ledger : ledgers) {
-            BigDecimal revenue = defaultDecimal(ledger.getContractAmount());
-            BigDecimal materialCost = materialCostResult.materialCostByLedgerId().getOrDefault(ledger.getId(), fallbackMaterialCost(productsByLedgerId.get(ledger.getId()), revenue));
-            BigDecimal laborCost = productionCostContext.laborCostByLedgerId().getOrDefault(ledger.getId(), BigDecimal.ZERO);
-            BigDecimal scrapCost = productionCostContext.scrapCostByLedgerId().getOrDefault(ledger.getId(), BigDecimal.ZERO);
-            BigDecimal depreciationCost = depreciationCostByLedger.getOrDefault(ledger.getId(), BigDecimal.ZERO);
-            BigDecimal totalCost = materialCost.add(laborCost).add(scrapCost).add(depreciationCost);
-            BigDecimal profit = revenue.subtract(totalCost);
-            BigDecimal profitRate = rate(profit, revenue);
-            String riskLevel = profit.compareTo(BigDecimal.ZERO) < 0
-                    ? "high"
-                    : (profitRate.compareTo(new BigDecimal("0.08")) < 0 ? "medium" : "low");
-            List<String> reasons = buildProfitReasons(revenue, materialCost, laborCost, scrapCost, profit, profitRate);
-            String suggestion = buildProfitSuggestion(riskLevel, reasons);
-
-            metrics.add(new OrderProfitMetric(
-                    ledger.getId(),
-                    safe(ledger.getSalesContractNo()),
-                    safe(ledger.getCustomerName()),
-                    safe(ledger.getProjectName()),
-                    toLocalDate(ledger.getEntryDate()),
-                    ledger.getDeliveryDate(),
-                    revenue,
-                    materialCost,
-                    laborCost,
-                    depreciationCost,
-                    scrapCost,
-                    totalCost,
-                    profit,
-                    profitRate,
-                    riskLevel,
-                    reasons,
-                    suggestion
-            ));
-        }
-
-        metrics.sort(Comparator.comparing(OrderProfitMetric::entryDate, Comparator.nullsLast(Comparator.reverseOrder()))
-                .thenComparing(OrderProfitMetric::ledgerId, Comparator.nullsLast(Comparator.reverseOrder())));
-        BigDecimal totalMaterialCost = metrics.stream().map(OrderProfitMetric::materialCost).reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal totalLaborCost = metrics.stream().map(OrderProfitMetric::laborCost).reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal totalScrapCost = metrics.stream().map(OrderProfitMetric::scrapCost).reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal totalDepreciationCost = metrics.stream().map(OrderProfitMetric::depreciationCost).reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal totalCost = metrics.stream().map(OrderProfitMetric::totalCost).reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal totalProfit = metrics.stream().map(OrderProfitMetric::profit).reduce(BigDecimal.ZERO, BigDecimal::add);
-
-        return new AnalysisBundle(
-                metrics,
-                productionCostContext.processCostRanking(),
-                totalRevenue,
-                totalMaterialCost,
-                totalLaborCost,
-                totalDepreciationCost,
-                totalScrapCost,
-                totalCost,
-                totalProfit
-        );
-    }
-
-    private MaterialCostResult calculateMaterialCost(LoginUser loginUser, DateRange range, List<SalesLedgerProduct> ledgerProducts) {
-        if (ledgerProducts.isEmpty()) {
-            return new MaterialCostResult(Map.of(), Map.of());
-        }
-        List<Long> ledgerProductIds = ledgerProducts.stream().map(SalesLedgerProduct::getId).filter(Objects::nonNull).toList();
-        Set<Long> productModelIds = ledgerProducts.stream().map(SalesLedgerProduct::getProductModelId).filter(Objects::nonNull).collect(Collectors.toSet());
-        Map<Long, Long> productIdToLedgerId = ledgerProducts.stream()
-                .filter(item -> item.getId() != null && item.getSalesLedgerId() != null)
-                .collect(Collectors.toMap(SalesLedgerProduct::getId, SalesLedgerProduct::getSalesLedgerId, (a, b) -> a));
-
-        Map<Long, BigDecimal> avgUnitCostByModelId = queryAverageUnitCostByModel(loginUser, productModelIds);
-        LambdaQueryWrapper<ProcurementRecordOut> outWrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(outWrapper, loginUser.getTenantId(), ProcurementRecordOut::getTenantId);
-        applyDeptFilter(outWrapper, loginUser.getCurrentDeptId(), ProcurementRecordOut::getDeptId);
-        outWrapper.eq(ProcurementRecordOut::getType, 2)
-                .in(ProcurementRecordOut::getSalesLedgerProductId, ledgerProductIds);
-        if (range.hasDateFilter()) {
-            outWrapper.ge(ProcurementRecordOut::getCreateTime, range.start().atStartOfDay())
-                    .lt(ProcurementRecordOut::getCreateTime, range.end().plusDays(1).atStartOfDay());
-        }
-        List<ProcurementRecordOut> outList = defaultList(procurementRecordOutMapper.selectList(outWrapper));
-
-        Set<Integer> storageIds = outList.stream()
-                .map(ProcurementRecordOut::getProcurementRecordStorageId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        Map<Integer, ProcurementRecordStorage> storageMap = storageIds.isEmpty()
-                ? Map.of()
-                : defaultList(procurementRecordMapper.selectBatchIds(storageIds)).stream()
-                .collect(Collectors.toMap(ProcurementRecordStorage::getId, item -> item, (a, b) -> a));
-
-        Map<Long, BigDecimal> materialCostByLedgerId = new HashMap<>();
-        for (ProcurementRecordOut out : outList) {
-            Long ledgerId = productIdToLedgerId.get(out.getSalesLedgerProductId());
-            if (ledgerId == null) {
-                continue;
-            }
-            ProcurementRecordStorage storage = storageMap.get(out.getProcurementRecordStorageId());
-            BigDecimal unitPrice = storage == null ? BigDecimal.ZERO : defaultDecimal(storage.getUnitPrice());
-            BigDecimal quantity = defaultDecimal(out.getInboundNum());
-            BigDecimal cost = quantity.multiply(unitPrice);
-            materialCostByLedgerId.merge(ledgerId, cost, BigDecimal::add);
-        }
-        return new MaterialCostResult(materialCostByLedgerId, avgUnitCostByModelId);
-    }
-
-    private ProductionCostContext calculateProductionCost(LoginUser loginUser,
-                                                          DateRange range,
-                                                          List<SalesLedger> ledgers,
-                                                          List<SalesLedgerProduct> ledgerProducts,
-                                                          Map<Long, BigDecimal> avgUnitCostByModelId) {
-        if (ledgers.isEmpty()) {
-            return ProductionCostContext.empty();
-        }
-
-        Set<Long> ledgerIds = ledgers.stream().map(SalesLedger::getId).filter(Objects::nonNull).collect(Collectors.toSet());
-        Map<Long, Set<Long>> productModelToLedgerIds = new HashMap<>();
-        for (SalesLedgerProduct product : ledgerProducts) {
-            if (product.getProductModelId() == null || product.getSalesLedgerId() == null) {
-                continue;
-            }
-            productModelToLedgerIds.computeIfAbsent(product.getProductModelId(), key -> new HashSet<>()).add(product.getSalesLedgerId());
-        }
-
-        LambdaQueryWrapper<ProductionPlan> planWrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(planWrapper, loginUser.getCurrentDeptId(), ProductionPlan::getDeptId);
-        planWrapper.in(ProductionPlan::getSalesLedgerId, ledgerIds);
-        List<ProductionPlan> plans = defaultList(productionPlanMapper.selectList(planWrapper));
-        Map<Long, Long> planIdToLedgerId = plans.stream()
-                .filter(item -> item.getId() != null && item.getSalesLedgerId() != null)
-                .collect(Collectors.toMap(ProductionPlan::getId, ProductionPlan::getSalesLedgerId, (a, b) -> a));
-
-        LambdaQueryWrapper<ProductionOrder> orderWrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(orderWrapper, loginUser.getCurrentDeptId(), ProductionOrder::getDeptId);
-        if (range.hasDateFilter()) {
-            orderWrapper.ge(ProductionOrder::getCreateTime, range.start().atStartOfDay().minusMonths(2))
-                    .lt(ProductionOrder::getCreateTime, range.end().plusDays(1).atStartOfDay().plusMonths(1));
-        }
-        List<ProductionOrder> orders = defaultList(productionOrderMapper.selectList(orderWrapper));
-
-        Map<Long, Set<Long>> orderIdToLedgerIds = new HashMap<>();
-        for (ProductionOrder order : orders) {
-            Set<Long> orderLedgers = new HashSet<>();
-            for (Long planId : parseIdList(order.getProductionPlanIds())) {
-                Long ledgerId = planIdToLedgerId.get(planId);
-                if (ledgerId != null) {
-                    orderLedgers.add(ledgerId);
-                }
-            }
-            if (orderLedgers.isEmpty() && order.getProductModelId() != null) {
-                orderLedgers.addAll(productModelToLedgerIds.getOrDefault(order.getProductModelId(), Set.of()));
-            }
-            if (!orderLedgers.isEmpty()) {
-                orderIdToLedgerIds.put(order.getId(), orderLedgers);
-            }
-        }
-        if (orderIdToLedgerIds.isEmpty()) {
-            return ProductionCostContext.empty();
-        }
-
-        LambdaQueryWrapper<ProductionOperationTask> taskWrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(taskWrapper, loginUser.getCurrentDeptId(), ProductionOperationTask::getDeptId);
-        taskWrapper.in(ProductionOperationTask::getProductionOrderId, orderIdToLedgerIds.keySet());
-        List<ProductionOperationTask> tasks = defaultList(productionOperationTaskMapper.selectList(taskWrapper));
-        Map<Long, Long> taskIdToOrderId = tasks.stream()
-                .filter(item -> item.getId() != null && item.getProductionOrderId() != null)
-                .collect(Collectors.toMap(ProductionOperationTask::getId, ProductionOperationTask::getProductionOrderId, (a, b) -> a));
-        if (taskIdToOrderId.isEmpty()) {
-            return ProductionCostContext.empty();
-        }
-
-        LambdaQueryWrapper<ProductionProductMain> mainWrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(mainWrapper, loginUser.getCurrentDeptId(), ProductionProductMain::getDeptId);
-        mainWrapper.in(ProductionProductMain::getProductionOperationTaskId, taskIdToOrderId.keySet());
-        if (range.hasDateFilter()) {
-            mainWrapper.ge(ProductionProductMain::getCreateTime, range.start().atStartOfDay().minusMonths(2))
-                    .lt(ProductionProductMain::getCreateTime, range.end().plusDays(1).atStartOfDay().plusMonths(1));
-        }
-        List<ProductionProductMain> mainList = defaultList(productionProductMainMapper.selectList(mainWrapper));
-        Map<Long, Set<Long>> mainIdToLedgers = new HashMap<>();
-        for (ProductionProductMain main : mainList) {
-            Long orderId = taskIdToOrderId.get(main.getProductionOperationTaskId());
-            if (orderId == null) {
-                continue;
-            }
-            Set<Long> ledgerSet = orderIdToLedgerIds.get(orderId);
-            if (ledgerSet == null || ledgerSet.isEmpty()) {
-                continue;
-            }
-            mainIdToLedgers.put(main.getId(), ledgerSet);
-        }
-        if (mainIdToLedgers.isEmpty()) {
-            return ProductionCostContext.empty();
-        }
-
-        LambdaQueryWrapper<ProductionAccount> accountWrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(accountWrapper, loginUser.getCurrentDeptId(), ProductionAccount::getDeptId);
-        accountWrapper.in(ProductionAccount::getProductionProductMainId, mainIdToLedgers.keySet());
-        if (range.hasDateFilter()) {
-            accountWrapper.ge(ProductionAccount::getSchedulingDate, range.start().atStartOfDay())
-                    .lt(ProductionAccount::getSchedulingDate, range.end().plusDays(1).atStartOfDay());
-        }
-        List<ProductionAccount> accountList = defaultList(productionAccountMapper.selectList(accountWrapper));
-
-        Map<String, BigDecimal> salaryQuotaByOperation = defaultList(technologyOperationMapper.selectList(new LambdaQueryWrapper<TechnologyOperation>()
-                        .select(TechnologyOperation::getName, TechnologyOperation::getSalaryQuota)))
-                .stream()
-                .filter(item -> StringUtils.hasText(item.getName()))
-                .collect(Collectors.toMap(TechnologyOperation::getName, item -> defaultDecimal(item.getSalaryQuota()), (a, b) -> a));
-
-        Map<Long, BigDecimal> laborCostByLedger = new HashMap<>();
-        Map<String, BigDecimal> processCostMap = new HashMap<>();
-        for (ProductionAccount account : accountList) {
-            Set<Long> ledgerSet = mainIdToLedgers.get(account.getProductionProductMainId());
-            if (ledgerSet == null || ledgerSet.isEmpty()) {
-                continue;
-            }
-            BigDecimal cost = estimateLaborCost(account, salaryQuotaByOperation);
-            if (cost.compareTo(BigDecimal.ZERO) <= 0) {
-                continue;
-            }
-            BigDecimal split = cost.divide(new BigDecimal(ledgerSet.size()), 4, RoundingMode.HALF_UP);
-            for (Long ledgerId : ledgerSet) {
-                laborCostByLedger.merge(ledgerId, split, BigDecimal::add);
-            }
-            processCostMap.merge(safe(account.getTechnologyOperationName()), cost, BigDecimal::add);
-        }
-
-        LambdaQueryWrapper<ProductionProductOutput> outputWrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(outputWrapper, loginUser.getCurrentDeptId(), ProductionProductOutput::getDeptId);
-        outputWrapper.in(ProductionProductOutput::getProductionProductMainId, mainIdToLedgers.keySet());
-        if (range.hasDateFilter()) {
-            outputWrapper.ge(ProductionProductOutput::getCreateTime, range.start().atStartOfDay())
-                    .lt(ProductionProductOutput::getCreateTime, range.end().plusDays(1).atStartOfDay());
-        }
-        List<ProductionProductOutput> outputList = defaultList(productionProductOutputMapper.selectList(outputWrapper));
-        Map<Long, BigDecimal> scrapCostByLedger = new HashMap<>();
-        for (ProductionProductOutput output : outputList) {
-            Set<Long> ledgerSet = mainIdToLedgers.get(output.getProductionProductMainId());
-            if (ledgerSet == null || ledgerSet.isEmpty()) {
-                continue;
-            }
-            BigDecimal scrapQty = defaultDecimal(output.getScrapQty());
-            if (scrapQty.compareTo(BigDecimal.ZERO) <= 0) {
-                continue;
-            }
-            BigDecimal unitCost = avgUnitCostByModelId.getOrDefault(output.getProductModelId(), BigDecimal.ZERO);
-            BigDecimal scrapCost = scrapQty.multiply(unitCost);
-            BigDecimal split = scrapCost.divide(new BigDecimal(ledgerSet.size()), 4, RoundingMode.HALF_UP);
-            for (Long ledgerId : ledgerSet) {
-                scrapCostByLedger.merge(ledgerId, split, BigDecimal::add);
-            }
-        }
-
-        Map<String, BigDecimal> processCostRanking = processCostMap.entrySet().stream()
-                .sorted(Map.Entry.<String, BigDecimal>comparingByValue().reversed())
-                .limit(10)
-                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new));
-
-        return new ProductionCostContext(laborCostByLedger, scrapCostByLedger, processCostRanking);
-    }
-
-    private List<SalesLedger> querySalesLedgers(LoginUser loginUser, DateRange range, String keyword, Integer limit) {
-        LambdaQueryWrapper<SalesLedger> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), SalesLedger::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), SalesLedger::getDeptId);
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(SalesLedger::getSalesContractNo, keyword)
-                    .or().like(SalesLedger::getCustomerContractNo, keyword)
-                    .or().like(SalesLedger::getCustomerName, keyword)
-                    .or().like(SalesLedger::getProjectName, keyword)
-                    .or().like(SalesLedger::getSalesman, keyword));
-        }
-        if (range.hasDateFilter()) {
-            wrapper.ge(SalesLedger::getEntryDate, toDate(range.start()))
-                    .lt(SalesLedger::getEntryDate, toExclusiveEndDate(range.end()));
-        }
-        wrapper.orderByDesc(SalesLedger::getEntryDate, SalesLedger::getId);
-        if (limit != null && limit > 0) {
-            wrapper.last("limit " + normalizeLimit(limit));
-        }
-        return defaultList(salesLedgerMapper.selectList(wrapper));
-    }
-
-    private List<SalesLedgerProduct> queryLedgerProducts(LoginUser loginUser, List<Long> ledgerIds) {
-        if (ledgerIds == null || ledgerIds.isEmpty()) {
-            return List.of();
-        }
-        LambdaQueryWrapper<SalesLedgerProduct> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), SalesLedgerProduct::getDeptId);
-        wrapper.in(SalesLedgerProduct::getSalesLedgerId, ledgerIds)
-                .eq(SalesLedgerProduct::getType, 1);
-        return defaultList(salesLedgerProductMapper.selectList(wrapper));
-    }
-
-    private List<StockInventory> queryStockInventory(LoginUser loginUser) {
-        LambdaQueryWrapper<StockInventory> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), StockInventory::getDeptId);
-        return defaultList(stockInventoryMapper.selectList(wrapper));
-    }
-
-    private Map<Long, ProductModel> queryProductModels(Set<Long> modelIds) {
-        if (modelIds == null || modelIds.isEmpty()) {
-            return defaultList(productModelMapper.selectList(null)).stream()
-                    .filter(item -> item.getId() != null)
-                    .collect(Collectors.toMap(ProductModel::getId, item -> item, (a, b) -> a));
-        }
-        LambdaQueryWrapper<ProductModel> wrapper = new LambdaQueryWrapper<>();
-        wrapper.in(ProductModel::getId, modelIds);
-        return defaultList(productModelMapper.selectList(wrapper)).stream()
-                .filter(item -> item.getId() != null)
-                .collect(Collectors.toMap(ProductModel::getId, item -> item, (a, b) -> a));
-    }
-
-    private Map<Long, Product> queryProducts(Collection<ProductModel> models) {
-        Set<Long> productIds = models == null ? Set.of() : models.stream()
-                .map(ProductModel::getProductId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        if (productIds.isEmpty()) {
-            return Map.of();
-        }
-        LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<>();
-        wrapper.in(Product::getId, productIds);
-        return defaultList(productMapper.selectList(wrapper)).stream()
-                .filter(item -> item.getId() != null)
-                .collect(Collectors.toMap(Product::getId, item -> item, (a, b) -> a));
-    }
-
-    private Map<Long, BigDecimal> queryAverageUnitCostByModel(LoginUser loginUser, Set<Long> productModelIds) {
-        LambdaQueryWrapper<ProcurementRecordStorage> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), ProcurementRecordStorage::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProcurementRecordStorage::getDeptId);
-        wrapper.in(ProcurementRecordStorage::getType, List.of(1, 2));
-        if (productModelIds != null && !productModelIds.isEmpty()) {
-            wrapper.in(ProcurementRecordStorage::getProductModelId, productModelIds);
-        }
-        List<ProcurementRecordStorage> rows = defaultList(procurementRecordMapper.selectList(wrapper));
-        Map<Long, BigDecimal> amountByModel = new HashMap<>();
-        Map<Long, BigDecimal> qtyByModel = new HashMap<>();
-        for (ProcurementRecordStorage row : rows) {
-            if (row.getProductModelId() == null) {
-                continue;
-            }
-            BigDecimal qty = defaultDecimal(row.getInboundNum());
-            if (qty.compareTo(BigDecimal.ZERO) <= 0) {
-                continue;
-            }
-            BigDecimal amount = defaultDecimal(row.getUnitPrice()).multiply(qty);
-            amountByModel.merge(row.getProductModelId(), amount, BigDecimal::add);
-            qtyByModel.merge(row.getProductModelId(), qty, BigDecimal::add);
-        }
-        Map<Long, BigDecimal> result = new HashMap<>();
-        for (Map.Entry<Long, BigDecimal> entry : amountByModel.entrySet()) {
-            BigDecimal qty = qtyByModel.get(entry.getKey());
-            if (qty == null || qty.compareTo(BigDecimal.ZERO) <= 0) {
-                continue;
-            }
-            result.put(entry.getKey(), entry.getValue().divide(qty, 6, RoundingMode.HALF_UP));
-        }
-        return result;
-    }
-
-    private OutboundStats queryOutboundStats(LoginUser loginUser, Set<Long> productModelIds, DateRange range) {
-        LambdaQueryWrapper<ProcurementRecordOut> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), ProcurementRecordOut::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProcurementRecordOut::getDeptId);
-        if (productModelIds != null && !productModelIds.isEmpty()) {
-            wrapper.in(ProcurementRecordOut::getProductModelId, productModelIds);
-        }
-        if (range.hasDateFilter()) {
-            wrapper.ge(ProcurementRecordOut::getCreateTime, range.start().atStartOfDay())
-                    .lt(ProcurementRecordOut::getCreateTime, range.end().plusDays(1).atStartOfDay());
-        }
-        List<ProcurementRecordOut> outList = defaultList(procurementRecordOutMapper.selectList(wrapper));
-        if (outList.isEmpty()) {
-            return OutboundStats.empty();
-        }
-        Set<Integer> storageIds = outList.stream()
-                .map(ProcurementRecordOut::getProcurementRecordStorageId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        Map<Integer, ProcurementRecordStorage> storageMap = storageIds.isEmpty()
-                ? Map.of()
-                : defaultList(procurementRecordMapper.selectBatchIds(storageIds)).stream()
-                .collect(Collectors.toMap(ProcurementRecordStorage::getId, item -> item, (a, b) -> a));
-
-        Map<Long, BigDecimal> outboundQtyByModel = new HashMap<>();
-        Map<Long, LocalDateTime> lastOutboundTimeByModel = new HashMap<>();
-        BigDecimal totalOutboundCost = BigDecimal.ZERO;
-        for (ProcurementRecordOut out : outList) {
-            Long modelId = out.getProductModelId();
-            if (modelId == null) {
-                continue;
-            }
-            BigDecimal qty = defaultDecimal(out.getInboundNum());
-            outboundQtyByModel.merge(modelId, qty, BigDecimal::add);
-            if (out.getCreateTime() != null) {
-                LocalDateTime existing = lastOutboundTimeByModel.get(modelId);
-                if (existing == null || out.getCreateTime().isAfter(existing)) {
-                    lastOutboundTimeByModel.put(modelId, out.getCreateTime());
-                }
-            }
-            ProcurementRecordStorage storage = storageMap.get(out.getProcurementRecordStorageId());
-            BigDecimal unitPrice = storage == null ? BigDecimal.ZERO : defaultDecimal(storage.getUnitPrice());
-            totalOutboundCost = totalOutboundCost.add(unitPrice.multiply(qty));
-        }
-        return new OutboundStats(outboundQtyByModel, lastOutboundTimeByModel, totalOutboundCost);
-    }
-
-    private List<InventoryMetric> buildInventoryMetrics(List<StockInventory> inventoryRows,
-                                                        Map<Long, ProductModel> productModelMap,
-                                                        Map<Long, Product> productMap,
-                                                        Map<Long, BigDecimal> avgUnitCostByModelId,
-                                                        OutboundStats outboundStats) {
-        Map<Long, InventoryMetricBuilder> metricBuilderByModel = new HashMap<>();
-        for (StockInventory row : inventoryRows) {
-            if (row.getProductModelId() == null) {
-                continue;
-            }
-            InventoryMetricBuilder builder = metricBuilderByModel.computeIfAbsent(row.getProductModelId(), InventoryMetricBuilder::new);
-            builder.addQuantity(maxZero(defaultDecimal(row.getQualitity()).subtract(defaultDecimal(row.getLockedQuantity()))));
-            builder.addLockedQuantity(defaultDecimal(row.getLockedQuantity()));
-            builder.addWarnNum(defaultDecimal(row.getWarnNum()));
-            if (row.getCreateTime() != null) {
-                builder.updateFirstInTime(row.getCreateTime());
-            }
-        }
-
-        List<InventoryMetric> result = new ArrayList<>();
-        LocalDate today = LocalDate.now();
-        for (InventoryMetricBuilder builder : metricBuilderByModel.values()) {
-            Long modelId = builder.modelId();
-            ProductModel model = productModelMap.get(modelId);
-            Product product = model == null ? null : productMap.get(model.getProductId());
-            BigDecimal unitCost = avgUnitCostByModelId.getOrDefault(modelId, BigDecimal.ZERO);
-            BigDecimal value = builder.quantity().multiply(unitCost);
-            LocalDateTime lastOutTime = outboundStats.lastOutboundTimeByModel().get(modelId);
-            long stagnantDays;
-            if (lastOutTime != null) {
-                stagnantDays = daysBetween(lastOutTime.toLocalDate(), today);
-            } else if (builder.firstInTime() != null) {
-                stagnantDays = daysBetween(builder.firstInTime().toLocalDate(), today);
-            } else {
-                stagnantDays = 0;
-            }
-            BigDecimal outQty = outboundStats.outboundQtyByModel().getOrDefault(modelId, BigDecimal.ZERO);
-            boolean overstock = builder.warnNum().compareTo(BigDecimal.ZERO) > 0
-                    && builder.quantity().compareTo(builder.warnNum().multiply(new BigDecimal("3"))) > 0;
-            result.add(new InventoryMetric(
-                    modelId,
-                    product == null ? "鏈煡浜у搧" : safe(product.getProductName()),
-                    model == null ? "鏈煡鍨嬪彿" : safe(model.getModel()),
-                    builder.quantity(),
-                    builder.lockedQuantity(),
-                    unitCost,
-                    value,
-                    outQty,
-                    stagnantDays,
-                    overstock
-            ));
-        }
-        return result;
-    }
-
-    private List<AccountSalesCollection> queryCollections(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<AccountSalesCollection> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), AccountSalesCollection::getDeptId);
-        if (range.hasDateFilter()) {
-            wrapper.ge(AccountSalesCollection::getCollectionDate, range.start())
-                    .le(AccountSalesCollection::getCollectionDate, range.end());
-        }
-        wrapper.orderByAsc(AccountSalesCollection::getCollectionDate);
-        return defaultList(accountSalesCollectionMapper.selectList(wrapper));
-    }
-
-    private List<AccountPurchasePayment> queryPayments(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<AccountPurchasePayment> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), AccountPurchasePayment::getDeptId);
-        if (range.hasDateFilter()) {
-            wrapper.ge(AccountPurchasePayment::getPaymentDate, range.start())
-                    .le(AccountPurchasePayment::getPaymentDate, range.end());
-        }
-        wrapper.orderByAsc(AccountPurchasePayment::getPaymentDate);
-        return defaultList(accountPurchasePaymentMapper.selectList(wrapper));
-    }
-
-    private List<MonthlyCashFlow> buildMonthlyCashFlow(DateRange range,
-                                                       List<AccountSalesCollection> collections,
-                                                       List<AccountPurchasePayment> payments) {
-        Map<YearMonth, BigDecimal> incomeByMonth = new LinkedHashMap<>();
-        Map<YearMonth, BigDecimal> expenseByMonth = new LinkedHashMap<>();
-        DateRange monthlyRange = range.hasDateFilter() ? range : inferCashFlowRange(collections, payments);
-        if (!monthlyRange.hasDateFilter()) {
-            return List.of();
-        }
-        YearMonth startMonth = YearMonth.from(monthlyRange.start());
-        YearMonth endMonth = YearMonth.from(monthlyRange.end());
-        for (YearMonth month = startMonth; !month.isAfter(endMonth); month = month.plusMonths(1)) {
-            incomeByMonth.put(month, BigDecimal.ZERO);
-            expenseByMonth.put(month, BigDecimal.ZERO);
-        }
-
-        for (AccountSalesCollection row : collections) {
-            if (row.getCollectionDate() == null) {
-                continue;
-            }
-            YearMonth month = YearMonth.from(row.getCollectionDate());
-            if (incomeByMonth.containsKey(month)) {
-                incomeByMonth.put(month, incomeByMonth.get(month).add(defaultDecimal(row.getCollectionAmount())));
-            }
-        }
-        for (AccountPurchasePayment row : payments) {
-            if (row.getPaymentDate() == null) {
-                continue;
-            }
-            YearMonth month = YearMonth.from(row.getPaymentDate());
-            if (expenseByMonth.containsKey(month)) {
-                expenseByMonth.put(month, expenseByMonth.get(month).add(defaultDecimal(row.getPaymentAmount())));
-            }
-        }
-
-        List<MonthlyCashFlow> result = new ArrayList<>();
-        for (YearMonth month : incomeByMonth.keySet()) {
-            BigDecimal income = incomeByMonth.get(month);
-            BigDecimal expense = expenseByMonth.getOrDefault(month, BigDecimal.ZERO);
-            result.add(new MonthlyCashFlow(month.toString(), income, expense, income.subtract(expense)));
-        }
-        return result;
-    }
-
-    private DateRange inferCashFlowRange(List<AccountSalesCollection> collections,
-                                         List<AccountPurchasePayment> payments) {
-        LocalDate min = null;
-        LocalDate max = null;
-        for (AccountSalesCollection row : defaultList(collections)) {
-            if (row.getCollectionDate() == null) {
-                continue;
-            }
-            min = min == null || row.getCollectionDate().isBefore(min) ? row.getCollectionDate() : min;
-            max = max == null || row.getCollectionDate().isAfter(max) ? row.getCollectionDate() : max;
-        }
-        for (AccountPurchasePayment row : defaultList(payments)) {
-            if (row.getPaymentDate() == null) {
-                continue;
-            }
-            min = min == null || row.getPaymentDate().isBefore(min) ? row.getPaymentDate() : min;
-            max = max == null || row.getPaymentDate().isAfter(max) ? row.getPaymentDate() : max;
-        }
-        return min == null || max == null ? new DateRange(null, null, "鍏ㄩ儴") : new DateRange(min, max, "鍏ㄩ儴");
-    }
-
-    private List<MonthlyCashFlow> forecastMonthlyCashFlow(List<MonthlyCashFlow> actual, int forecastMonths) {
-        if (actual.isEmpty()) {
-            List<MonthlyCashFlow> defaults = new ArrayList<>();
-            YearMonth now = YearMonth.now();
-            for (int i = 1; i <= forecastMonths; i++) {
-                YearMonth month = now.plusMonths(i);
-                defaults.add(new MonthlyCashFlow(month.toString(), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO));
-            }
-            return defaults;
-        }
-        List<BigDecimal> series = actual.stream().map(MonthlyCashFlow::netFlow).toList();
-        BigDecimal avg = series.stream().reduce(BigDecimal.ZERO, BigDecimal::add)
-                .divide(new BigDecimal(series.size()), 4, RoundingMode.HALF_UP);
-        BigDecimal slope = BigDecimal.ZERO;
-        if (series.size() > 1) {
-            slope = series.get(series.size() - 1).subtract(series.get(0))
-                    .divide(new BigDecimal(series.size() - 1), 4, RoundingMode.HALF_UP);
-        }
-        YearMonth lastMonth = YearMonth.parse(actual.get(actual.size() - 1).month());
-        List<MonthlyCashFlow> forecast = new ArrayList<>();
-        for (int i = 1; i <= forecastMonths; i++) {
-            YearMonth month = lastMonth.plusMonths(i);
-            BigDecimal net = avg.add(slope.multiply(new BigDecimal(i))).setScale(2, RoundingMode.HALF_UP);
-            BigDecimal income = net.compareTo(BigDecimal.ZERO) >= 0 ? net : BigDecimal.ZERO;
-            BigDecimal expense = net.compareTo(BigDecimal.ZERO) >= 0 ? BigDecimal.ZERO : net.abs();
-            forecast.add(new MonthlyCashFlow(month.toString(), income, expense, net));
-        }
-        return forecast;
-    }
-
-    private StatementSnapshot buildStatementSnapshot(LoginUser loginUser) {
-        LambdaQueryWrapper<AccountStatement> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), AccountStatement::getDeptId);
-        wrapper.orderByDesc(AccountStatement::getStatementMonth);
-        List<AccountStatement> rows = defaultList(accountStatementMapper.selectList(wrapper));
-        if (rows.isEmpty()) {
-            return StatementSnapshot.empty();
-        }
-
-        Map<String, AccountStatement> latestByEntity = new HashMap<>();
-        for (AccountStatement row : rows) {
-            if (row.getAccountType() == null || row.getCustomerId() == null || !StringUtils.hasText(row.getStatementMonth())) {
-                continue;
-            }
-            String key = row.getAccountType() + "::" + row.getCustomerId();
-            AccountStatement existing = latestByEntity.get(key);
-            if (existing == null || row.getStatementMonth().compareTo(existing.getStatementMonth()) > 0) {
-                latestByEntity.put(key, row);
-            }
-        }
-
-        BigDecimal receivableTotal = BigDecimal.ZERO;
-        BigDecimal payableTotal = BigDecimal.ZERO;
-        List<StatementMetric> receivableMetrics = new ArrayList<>();
-        List<StatementMetric> payableMetrics = new ArrayList<>();
-        for (AccountStatement row : latestByEntity.values()) {
-            BigDecimal closing = defaultDecimal(row.getClosingBalance());
-            if (Objects.equals(row.getAccountType(), 1)) {
-                receivableTotal = receivableTotal.add(closing);
-                receivableMetrics.add(new StatementMetric(String.valueOf(row.getCustomerId()), closing,
-                        defaultDecimal(row.getCurrentPlan()), defaultDecimal(row.getCurrentActually()), safe(row.getStatementMonth())));
-            } else if (Objects.equals(row.getAccountType(), 2)) {
-                payableTotal = payableTotal.add(closing);
-                payableMetrics.add(new StatementMetric(String.valueOf(row.getCustomerId()), closing,
-                        defaultDecimal(row.getCurrentPlan()), defaultDecimal(row.getCurrentActually()), safe(row.getStatementMonth())));
-            }
-        }
-        receivableMetrics.sort(Comparator.comparing(StatementMetric::closingBalance).reversed());
-        payableMetrics.sort(Comparator.comparing(StatementMetric::closingBalance).reversed());
-
-        return new StatementSnapshot(
-                receivableTotal,
-                payableTotal,
-                receivableMetrics.stream().limit(10).toList(),
-                payableMetrics.stream().limit(10).toList()
-        );
-    }
-
-    private BigDecimal calculateTotalDepreciation(LoginUser loginUser) {
-        LambdaQueryWrapper<DeviceLedger> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), DeviceLedger::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), DeviceLedger::getDeptId);
-        wrapper.eq(DeviceLedger::getIsDepr, 1);
-        List<DeviceLedger> devices = defaultList(deviceLedgerMapper.selectList(wrapper));
-        BigDecimal total = BigDecimal.ZERO;
-        for (DeviceLedger device : devices) {
-            total = total.add(defaultDecimal(AccountingServiceImpl.calculatePreciseDepreciation(device)));
-        }
-        return total;
-    }
-
-    private Map<Long, BigDecimal> allocateDepreciation(List<SalesLedger> ledgers, BigDecimal totalDepreciation, BigDecimal totalRevenue) {
-        if (ledgers.isEmpty() || totalDepreciation.compareTo(BigDecimal.ZERO) <= 0) {
-            return Map.of();
-        }
-        Map<Long, BigDecimal> result = new HashMap<>();
-        if (totalRevenue.compareTo(BigDecimal.ZERO) <= 0) {
-            BigDecimal avg = totalDepreciation.divide(new BigDecimal(ledgers.size()), 4, RoundingMode.HALF_UP);
-            for (SalesLedger ledger : ledgers) {
-                result.put(ledger.getId(), avg);
-            }
-            return result;
-        }
-        for (SalesLedger ledger : ledgers) {
-            BigDecimal revenue = defaultDecimal(ledger.getContractAmount());
-            BigDecimal ratio = revenue.divide(totalRevenue, 6, RoundingMode.HALF_UP);
-            result.put(ledger.getId(), totalDepreciation.multiply(ratio));
-        }
-        return result;
-    }
-
-    private BigDecimal fallbackMaterialCost(List<SalesLedgerProduct> products, BigDecimal revenue) {
-        if (products != null && !products.isEmpty()) {
-            BigDecimal productAmount = products.stream()
-                    .map(SalesLedgerProduct::getTaxExclusiveTotalPrice)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-            if (productAmount.compareTo(BigDecimal.ZERO) > 0) {
-                return productAmount;
-            }
-        }
-
-        BigDecimal materialCost = revenue.multiply(DEFAULT_FALLBACK_MATERIAL_COST_RATE);
-        BigDecimal laborCost = revenue.multiply(DEFAULT_LABOR_COST_RATE);
-        BigDecimal overheadCost = revenue.multiply(DEFAULT_OVERHEAD_COST_RATE);
-
-        return materialCost.add(laborCost).add(overheadCost);
-    }
-
-    private BigDecimal estimateTotalCost(BigDecimal revenue, List<SalesLedgerProduct> products) {
-        if (revenue == null || revenue.compareTo(BigDecimal.ZERO) <= 0) {
-            return BigDecimal.ZERO;
-        }
-
-        BigDecimal materialCost = BigDecimal.ZERO;
-        if (products != null && !products.isEmpty()) {
-            materialCost = products.stream()
-                    .map(SalesLedgerProduct::getTaxExclusiveTotalPrice)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-        }
-
-        if (materialCost.compareTo(BigDecimal.ZERO) <= 0) {
-            materialCost = revenue.multiply(DEFAULT_FALLBACK_MATERIAL_COST_RATE);
-        }
-
-        BigDecimal laborCost = revenue.multiply(DEFAULT_LABOR_COST_RATE);
-        BigDecimal overheadCost = revenue.multiply(DEFAULT_OVERHEAD_COST_RATE);
-
-        return materialCost.add(laborCost).add(overheadCost);
-    }
-
-    private Map<String, String> queryCustomerNameMap(Set<String> idSet) {
-        if (idSet == null || idSet.isEmpty()) {
-            return Map.of();
-        }
-        Set<Long> ids = idSet.stream()
-                .map(this::toLongOrNull)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        if (ids.isEmpty()) {
-            return Map.of();
-        }
-        LambdaQueryWrapper<Customer> wrapper = new LambdaQueryWrapper<>();
-        wrapper.in(Customer::getId, ids);
-        return defaultList(customerMapper.selectList(wrapper)).stream()
-                .collect(Collectors.toMap(item -> String.valueOf(item.getId()), Customer::getCustomerName, (a, b) -> a));
-    }
-
-    private Map<String, String> querySupplierNameMap(Set<String> idSet) {
-        if (idSet == null || idSet.isEmpty()) {
-            return Map.of();
-        }
-        Set<Long> ids = idSet.stream()
-                .map(this::toLongOrNull)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        if (ids.isEmpty()) {
-            return Map.of();
-        }
-        LambdaQueryWrapper<SupplierManage> wrapper = new LambdaQueryWrapper<>();
-        wrapper.in(SupplierManage::getId, ids);
-        return defaultList(supplierManageMapper.selectList(wrapper)).stream()
-                .collect(Collectors.toMap(item -> String.valueOf(item.getId()), SupplierManage::getSupplierName, (a, b) -> a));
-    }
-
-    private String riskLevelByAmount(BigDecimal amount) {
-        if (amount.compareTo(new BigDecimal("5000000")) >= 0) {
-            return "high";
-        }
-        if (amount.compareTo(new BigDecimal("1000000")) >= 0) {
-            return "medium";
-        }
-        return "low";
-    }
-
-    private long countDevices(LoginUser loginUser) {
-        LambdaQueryWrapper<DeviceLedger> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), DeviceLedger::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), DeviceLedger::getDeptId);
-        return deviceLedgerMapper.selectCount(wrapper);
-    }
-
-    private long countRepairingDevices(LoginUser loginUser) {
-        LambdaQueryWrapper<DeviceRepair> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), DeviceRepair::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), DeviceRepair::getDeptId);
-        wrapper.in(DeviceRepair::getStatus, List.of(0, 3));
-        return deviceRepairMapper.selectCount(wrapper);
-    }
-
-    private BigDecimal estimateInventoryValue(LoginUser loginUser, List<StockInventory> inventories) {
-        if (inventories == null || inventories.isEmpty()) {
-            return BigDecimal.ZERO;
-        }
-        Set<Long> modelIds = inventories.stream().map(StockInventory::getProductModelId).filter(Objects::nonNull).collect(Collectors.toSet());
-        Map<Long, BigDecimal> costMap = queryAverageUnitCostByModel(loginUser, modelIds);
-        BigDecimal total = BigDecimal.ZERO;
-        for (StockInventory inventory : inventories) {
-            BigDecimal qty = maxZero(defaultDecimal(inventory.getQualitity()).subtract(defaultDecimal(inventory.getLockedQuantity())));
-            BigDecimal unit = costMap.getOrDefault(inventory.getProductModelId(), BigDecimal.ZERO);
-            total = total.add(qty.multiply(unit));
-        }
-        return total;
-    }
-
-    private DateRange previousSameLengthRange(DateRange range) {
-        if (!range.hasDateFilter()) {
-            return new DateRange(null, null, "鍏ㄩ儴");
-        }
-        long days = daysBetween(range.start(), range.end()) + 1L;
-        LocalDate prevEnd = range.start().minusDays(1);
-        LocalDate prevStart = prevEnd.minusDays(days - 1L);
-        return new DateRange(prevStart, prevEnd, prevStart + "鑷�" + prevEnd);
-    }
-
-    private List<String> buildProfitReasons(BigDecimal revenue,
-                                            BigDecimal materialCost,
-                                            BigDecimal laborCost,
-                                            BigDecimal scrapCost,
-                                            BigDecimal profit,
-                                            BigDecimal profitRate) {
-        List<String> reasons = new ArrayList<>();
-        BigDecimal materialRate = rate(materialCost, revenue);
-        if (materialRate.compareTo(new BigDecimal("0.70")) >= 0) {
-            reasons.add("鏉愭枡鎴愭湰鍗犳瘮瓒呰繃70%");
-        } else if (materialRate.compareTo(new BigDecimal("0.55")) >= 0) {
-            reasons.add("鏉愭枡鎴愭湰鍗犳瘮鍋忛珮");
-        }
-        BigDecimal laborRate = rate(laborCost, revenue);
-        if (laborRate.compareTo(new BigDecimal("0.20")) >= 0) {
-            reasons.add("浜哄伐鎴愭湰鍗犳瘮瓒呰繃20%");
-        } else if (laborRate.compareTo(new BigDecimal("0.12")) >= 0) {
-            reasons.add("浜哄伐鎴愭湰澧為暱鍋忓揩");
-        }
-        BigDecimal scrapRate = rate(scrapCost, revenue);
-        if (scrapRate.compareTo(new BigDecimal("0.05")) >= 0) {
-            reasons.add("鎶ュ簾鎹熻�楀崰姣斿亸楂�");
-        }
-        if (profit.compareTo(BigDecimal.ZERO) < 0) {
-            reasons.add("璁㈠崟澶勪簬浜忔崯鐘舵��");
-        } else if (profitRate.compareTo(new BigDecimal("0.08")) < 0) {
-            reasons.add("鍒╂鼎鐜囦綆浜�8%");
-        }
-        if (reasons.isEmpty()) {
-            reasons.add("鎴愭湰缁撴瀯澶勪簬鍚堢悊鍖洪棿");
-        }
-        return reasons;
-    }
-
-    private String buildProfitSuggestion(String riskLevel, List<String> reasons) {
-        if ("high".equals(riskLevel)) {
-            return "浼樺厛澶嶆牳BOM鐢ㄩ噺涓庡伐搴忓畾棰濓紝蹇呰鏃惰皟鏁存姤浠峰拰浠樻鏉℃锛屽苟闄愬埗瓒呰处鏈熶氦浠樸��";
-        }
-        if ("medium".equals(riskLevel)) {
-            return "寤鸿浼樺寲閲囪喘鎵规鍜屽伐搴忔帓浜э紝鎻愬崌涓�娆″悎鏍肩巼骞跺悓姝ユ墽琛屾瘺鍒╅璀︺��";
-        }
-        if (reasons.stream().anyMatch(item -> item.contains("鏉愭枡"))) {
-            return "淇濇寔鏉愭枡閲囪喘鎴愭湰鐪嬫澘锛屾寜鍛ㄨ窡韪富瑕佹潗鏂欏崟浠锋尝鍔ㄣ��";
-        }
-        return "缁存寔褰撳墠缁忚惀鑺傚锛岀户缁窡韪鍗曞埄娑︾巼鍜屽洖娆炬晥鐜囥��";
-    }
-
-    private Map<String, Object> toOrderCostItem(OrderProfitMetric metric) {
-        Map<String, Object> item = new LinkedHashMap<>();
-        item.put("ledgerId", metric.ledgerId());
-        item.put("salesContractNo", metric.salesContractNo());
-        item.put("customerName", metric.customerName());
-        item.put("projectName", metric.projectName());
-        item.put("entryDate", formatDate(metric.entryDate()));
-        item.put("deliveryDate", formatDate(metric.deliveryDate()));
-        item.put("revenue", metric.revenue());
-        item.put("materialCost", metric.materialCost());
-        item.put("laborCost", metric.laborCost());
-        item.put("depreciationCost", metric.depreciationCost());
-        item.put("scrapCost", metric.scrapCost());
-        item.put("totalCost", metric.totalCost());
-        item.put("profit", metric.profit());
-        item.put("profitRate", toPercent(metric.profitRate()));
-        item.put("riskLevel", metric.riskLevel());
-        item.put("reasons", metric.reasons());
-        item.put("suggestion", metric.suggestion());
-        return item;
-    }
-
-    private Map<String, Object> toRiskOrderItem(OrderProfitMetric metric) {
-        Map<String, Object> map = toOrderCostItem(metric);
-        map.put("priority", "high".equals(metric.riskLevel()) ? "high" : ("medium".equals(metric.riskLevel()) ? "medium" : "low"));
-        return map;
-    }
-
-    private List<Map<String, Object>> buildCustomerProfitTop(List<OrderProfitMetric> metrics, int topN) {
-        Map<String, BigDecimal> customerProfitMap = new HashMap<>();
-        Map<String, BigDecimal> customerRevenueMap = new HashMap<>();
-        for (OrderProfitMetric metric : metrics) {
-            customerProfitMap.merge(metric.customerName(), metric.profit(), BigDecimal::add);
-            customerRevenueMap.merge(metric.customerName(), metric.revenue(), BigDecimal::add);
-        }
-        return customerProfitMap.entrySet().stream()
-                .sorted(Map.Entry.<String, BigDecimal>comparingByValue().reversed())
-                .limit(topN)
-                .map(entry -> {
-                    Map<String, Object> map = new LinkedHashMap<>();
-                    BigDecimal revenue = customerRevenueMap.getOrDefault(entry.getKey(), BigDecimal.ZERO);
-                    map.put("customerName", entry.getKey());
-                    map.put("profit", entry.getValue());
-                    map.put("revenue", revenue);
-                    map.put("profitRate", toPercent(rate(entry.getValue(), revenue)));
-                    return map;
-                })
-                .toList();
-    }
-
-    private Map<String, Object> toInventoryItem(InventoryMetric metric) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("productModelId", metric.modelId());
-        map.put("productName", metric.productName());
-        map.put("model", metric.modelName());
-        map.put("quantity", metric.quantity());
-        map.put("lockedQuantity", metric.lockedQuantity());
-        map.put("avgUnitCost", metric.avgUnitCost());
-        map.put("inventoryValue", metric.inventoryValue());
-        map.put("outboundQuantity", metric.outboundQuantity());
-        map.put("stagnantDays", metric.stagnantDays());
-        map.put("overstock", metric.overstock());
-        map.put("riskLevel", metric.stagnantDays() >= 90 ? "high" : (metric.stagnantDays() >= 30 ? "medium" : "low"));
-        return map;
-    }
-
-    private boolean matchInventoryKeyword(InventoryMetric metric, String keyword) {
-        if (!StringUtils.hasText(keyword)) {
-            return true;
-        }
-        return metric.productName().contains(keyword.trim()) || metric.modelName().contains(keyword.trim());
-    }
-
-    private Map<String, Object> toMonthlyCashFlowItem(MonthlyCashFlow flow) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("month", flow.month());
-        map.put("income", flow.income());
-        map.put("expense", flow.expense());
-        map.put("netFlow", flow.netFlow());
-        return map;
-    }
-
-    private Map<String, Object> toStatementRiskItem(StatementMetric metric, Map<String, String> nameMap, String type) {
-        BigDecimal actualRate = rate(metric.actualAmount(), metric.planAmount());
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put(type + "Id", metric.entityId());
-        map.put(type + "Name", safe(nameMap.get(metric.entityId())));
-        map.put("statementMonth", metric.statementMonth());
-        map.put("closingBalance", metric.closingBalance());
-        map.put("planAmount", metric.planAmount());
-        map.put("actualAmount", metric.actualAmount());
-        map.put("actualRate", toPercent(actualRate));
-        map.put("riskLevel", metric.closingBalance().compareTo(new BigDecimal("1000000")) > 0 || actualRate.compareTo(new BigDecimal("0.50")) < 0 ? "high" : "medium");
-        return map;
-    }
-
-    private Map<String, Object> anomalyItem(String level, String type, String message, Map<String, Object> detail) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("riskLevel", level);
-        map.put("type", type);
-        map.put("message", message);
-        map.put("detail", detail);
-        return map;
-    }
-
-    private Map<String, Object> riskSuggestion(String type, String level, String suggestion) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("type", type);
-        map.put("level", level);
-        map.put("suggestion", suggestion);
-        return map;
-    }
-
-    private Map<String, Object> buildCostCompositionPie(BigDecimal material, BigDecimal labor, BigDecimal depreciation, BigDecimal scrap) {
-        List<Map<String, Object>> data = List.of(
-                Map.of("name", "鏉愭枡鎴愭湰", "value", material),
-                Map.of("name", "浜哄伐鎴愭湰", "value", labor),
-                Map.of("name", "鎶樻棫鎴愭湰", "value", depreciation),
-                Map.of("name", "鎹熻�楁垚鏈�", "value", scrap)
-        );
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "鎴愭湰鏋勬垚", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "item"));
-        option.put("series", List.of(Map.of("name", "鎴愭湰鏋勬垚", "type", "pie", "radius", "60%", "data", data)));
-        return option;
-    }
-
-    private Map<String, Object> buildOrderProfitBar(List<OrderProfitMetric> metrics) {
-        List<OrderProfitMetric> top = metrics.stream()
-                .sorted(Comparator.comparing(OrderProfitMetric::profit))
-                .limit(10)
-                .toList();
-        List<String> xData = top.stream().map(OrderProfitMetric::salesContractNo).toList();
-        List<BigDecimal> yData = top.stream().map(OrderProfitMetric::profit).toList();
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "璁㈠崟鍒╂鼎鍒嗗竷", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", xData));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of("name", "鍒╂鼎", "type", "bar", "data", yData)));
-        return option;
-    }
-
-    private Map<String, Object> buildProcessCostBar(Map<String, BigDecimal> processCosts) {
-        List<String> xData = new ArrayList<>(processCosts.keySet());
-        List<BigDecimal> yData = new ArrayList<>(processCosts.values());
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "宸ュ簭鎴愭湰鎺掑悕", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", xData));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of("name", "鎴愭湰", "type", "bar", "data", yData)));
-        return option;
-    }
-
-    private Map<String, Object> buildProfitDistributionBar(List<OrderProfitMetric> metrics) {
-        List<OrderProfitMetric> sorted = metrics.stream()
-                .sorted(Comparator.comparing(OrderProfitMetric::profitRate))
-                .limit(15)
-                .toList();
-        List<String> xData = sorted.stream().map(OrderProfitMetric::salesContractNo).toList();
-        List<BigDecimal> yData = sorted.stream().map(metric -> metric.profitRate().multiply(ONE_HUNDRED).setScale(2, RoundingMode.HALF_UP)).toList();
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "璁㈠崟鍒╂鼎鐜囧垎甯�", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", xData));
-        option.put("yAxis", Map.of("type", "value", "name", "%"));
-        option.put("series", List.of(Map.of("name", "鍒╂鼎鐜�", "type", "bar", "data", yData)));
-        return option;
-    }
-
-    private Map<String, Object> buildLossOrderTrendLine(List<OrderProfitMetric> metrics) {
-        Map<String, Long> lossByDate = new LinkedHashMap<>();
-        List<OrderProfitMetric> sorted = metrics.stream()
-                .filter(metric -> metric.entryDate() != null)
-                .sorted(Comparator.comparing(OrderProfitMetric::entryDate))
-                .toList();
-        for (OrderProfitMetric metric : sorted) {
-            String day = formatDate(metric.entryDate());
-            long inc = metric.profit().compareTo(BigDecimal.ZERO) < 0 ? 1L : 0L;
-            lossByDate.merge(day, inc, Long::sum);
-        }
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "浜忔崯璁㈠崟瓒嬪娍", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", new ArrayList<>(lossByDate.keySet())));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of("name", "浜忔崯璁㈠崟鏁�", "type", "line", "smooth", true, "data", new ArrayList<>(lossByDate.values()))));
-        return option;
-    }
-
-    private Map<String, Object> buildCustomerProfitBar(Map<String, BigDecimal> customerProfitMap) {
-        List<Map.Entry<String, BigDecimal>> top = customerProfitMap.entrySet().stream()
-                .sorted(Map.Entry.<String, BigDecimal>comparingByValue().reversed())
-                .limit(10)
-                .toList();
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "瀹㈡埛鍒╂鼎璐$尞TOP10", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", top.stream().map(Map.Entry::getKey).toList()));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of("name", "鍒╂鼎", "type", "bar", "data", top.stream().map(Map.Entry::getValue).toList())));
-        return option;
-    }
-
-    private Map<String, Object> buildInventoryTopBar(List<InventoryMetric> metrics) {
-        List<InventoryMetric> top = metrics.stream()
-                .sorted(Comparator.comparing(InventoryMetric::inventoryValue).reversed())
-                .limit(10)
-                .toList();
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "搴撳瓨璧勯噾鍗犵敤TOP10", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", top.stream().map(item -> item.productName() + "/" + item.modelName()).toList()));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of("name", "璧勯噾鍗犵敤", "type", "bar", "data", top.stream().map(InventoryMetric::inventoryValue).toList())));
-        return option;
-    }
-
-    private Map<String, Object> buildInventoryAgingPie(List<InventoryMetric> metrics) {
-        long normal = metrics.stream().filter(item -> item.stagnantDays() < 30).count();
-        long slow = metrics.stream().filter(item -> item.stagnantDays() >= 30 && item.stagnantDays() < 90).count();
-        long stagnant = metrics.stream().filter(item -> item.stagnantDays() >= 90).count();
-        List<Map<String, Object>> data = List.of(
-                Map.of("name", "姝e父", "value", normal),
-                Map.of("name", "缂撴參", "value", slow),
-                Map.of("name", "鍛嗘粸", "value", stagnant)
-        );
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "搴撳瓨搴撻緞鍒嗗竷", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "item"));
-        option.put("series", List.of(Map.of("type", "pie", "radius", "60%", "data", data)));
-        return option;
-    }
-
-    private Map<String, Object> buildTurnoverGauge(BigDecimal turnoverDays) {
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "搴撳瓨鍛ㄨ浆澶╂暟", "left", "center"));
-        option.put("series", List.of(Map.of(
-                "type", "gauge",
-                "min", 0,
-                "max", 180,
-                "detail", Map.of("formatter", "{value}澶�"),
-                "data", List.of(Map.of("value", turnoverDays, "name", "鍛ㄨ浆澶╂暟"))
-        )));
-        return option;
-    }
-
-    private Map<String, Object> buildCashflowTrend(List<MonthlyCashFlow> actual, List<MonthlyCashFlow> forecast) {
-        List<String> labels = new ArrayList<>();
-        List<BigDecimal> netActual = new ArrayList<>();
-        List<BigDecimal> netForecast = new ArrayList<>();
-        for (MonthlyCashFlow point : actual) {
-            labels.add(point.month());
-            netActual.add(point.netFlow());
-            netForecast.add(null);
-        }
-        for (MonthlyCashFlow point : forecast) {
-            labels.add(point.month());
-            netActual.add(null);
-            netForecast.add(point.netFlow());
-        }
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "鐜伴噾娴佽秼鍔匡紙瀹為檯+棰勬祴锛�", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", labels));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(
-                Map.of("name", "瀹為檯鍑�鐜伴噾娴�", "type", "line", "smooth", true, "data", netActual),
-                Map.of("name", "棰勬祴鍑�鐜伴噾娴�", "type", "line", "smooth", true, "data", netForecast)
-        ));
-        return option;
-    }
-
-    private Map<String, Object> buildReceivablePayableBar(BigDecimal receivable, BigDecimal payable) {
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "搴旀敹搴斾粯浣欓瀵规瘮", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", List.of("搴旀敹", "搴斾粯")));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of("name", "浣欓", "type", "bar", "data", List.of(receivable, payable))));
-        return option;
-    }
-
-    private Map<String, Object> buildFundGapGauge(BigDecimal fundGap) {
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "璧勯噾缂哄彛", "left", "center"));
-        option.put("series", List.of(Map.of(
-                "type", "gauge",
-                "min", 0,
-                "max", 10000000,
-                "detail", Map.of("formatter", "{value}"),
-                "data", List.of(Map.of("value", fundGap, "name", "璧勯噾缂哄彛"))
-        )));
-        return option;
-    }
-
-    private Map<String, Object> buildAnomalyLevelPie(List<Map<String, Object>> anomalies) {
-        long high = anomalies.stream().filter(item -> "high".equals(item.get("riskLevel"))).count();
-        long medium = anomalies.stream().filter(item -> "medium".equals(item.get("riskLevel"))).count();
-        long low = anomalies.stream().filter(item -> "low".equals(item.get("riskLevel"))).count();
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "寮傚父绛夌骇鍒嗗竷", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "item"));
-        option.put("series", List.of(Map.of("type", "pie", "radius", "60%", "data", List.of(
-                Map.of("name", "楂橀闄�", "value", high),
-                Map.of("name", "涓闄�", "value", medium),
-                Map.of("name", "浣庨闄�", "value", low)
-        ))));
-        return option;
-    }
-
-    private Map<String, Object> buildAnomalyTypeBar(List<Map<String, Object>> anomalies) {
-        Map<String, Long> countByType = new LinkedHashMap<>();
-        for (Map<String, Object> anomaly : anomalies) {
-            countByType.merge(String.valueOf(anomaly.get("type")), 1L, Long::sum);
-        }
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "寮傚父绫诲瀷鍒嗗竷", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", new ArrayList<>(countByType.keySet())));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of("name", "寮傚父鏁�", "type", "bar", "data", new ArrayList<>(countByType.values()))));
-        return option;
-    }
-
-    private Map<String, Object> buildInventoryProfitGauge(BigDecimal inventoryValue, BigDecimal profit) {
-        BigDecimal ratio = inventoryValue.compareTo(BigDecimal.ZERO) <= 0
-                ? BigDecimal.ZERO
-                : profit.divide(inventoryValue, 4, RoundingMode.HALF_UP).multiply(ONE_HUNDRED);
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "鍒╂鼎/搴撳瓨璧勯噾姣�", "left", "center"));
-        option.put("series", List.of(Map.of(
-                "type", "gauge",
-                "min", -100,
-                "max", 100,
-                "detail", Map.of("formatter", "{value}%"),
-                "data", List.of(Map.of("value", ratio.setScale(2, RoundingMode.HALF_UP), "name", "鍒╂鼎璧勯噾姣�"))
-        )));
-        return option;
-    }
-
-    private int normalizeLimit(Integer limit) {
-        if (limit == null || limit <= 0) {
-            return DEFAULT_LIMIT;
-        }
-        return Math.min(limit, MAX_LIMIT);
-    }
-
-    private DateRange resolveDateRange(String startDate, String endDate, String timeRange, String defaultLabel) {
-        LocalDate today = LocalDate.now();
-        LocalDate explicitStart = parseLocalDate(startDate);
-        LocalDate explicitEnd = parseLocalDate(endDate);
-        if (explicitStart != null || explicitEnd != null) {
-            LocalDate start = explicitStart != null ? explicitStart : explicitEnd;
-            LocalDate end = explicitEnd != null ? explicitEnd : explicitStart;
-            if (start.isAfter(end)) {
-                LocalDate temp = start;
-                start = end;
-                end = temp;
-            }
-            return new DateRange(start, end, start + "鑷�" + end);
-        }
-
-        if (!StringUtils.hasText(timeRange)) {
-            return new DateRange(null, null, "鍏ㄩ儴");
-        }
-
-        String text = timeRange.trim();
-        if (text.contains("浠婂ぉ")) {
-            return new DateRange(today, today, "浠婂ぉ");
-        }
-        if (text.contains("鏄ㄥぉ") || text.contains("鏄ㄦ棩")) {
-            LocalDate day = today.minusDays(1);
-            return new DateRange(day, day, "鏄ㄥぉ");
-        }
-        if (text.contains("鏈懆")) {
-            LocalDate start = today.minusDays(today.getDayOfWeek().getValue() - 1L);
-            return new DateRange(start, today, "鏈懆");
-        }
-        if (text.contains("涓婂懆")) {
-            LocalDate thisWeekStart = today.minusDays(today.getDayOfWeek().getValue() - 1L);
-            LocalDate start = thisWeekStart.minusWeeks(1);
-            LocalDate end = thisWeekStart.minusDays(1);
-            return new DateRange(start, end, "涓婂懆");
-        }
-        if (text.contains("鏈湀")) {
-            return new DateRange(today.withDayOfMonth(1), today, "鏈湀");
-        }
-        if (text.contains("涓婃湀")) {
-            YearMonth lastMonth = YearMonth.from(today).minusMonths(1);
-            return new DateRange(lastMonth.atDay(1), lastMonth.atEndOfMonth(), "涓婃湀");
-        }
-        if (text.contains("浠婂勾") || text.contains("鏈勾")) {
-            return new DateRange(today.withDayOfYear(1), today, "浠婂勾");
-        }
-        Matcher relativeMatcher = RELATIVE_PATTERN.matcher(text);
-        if (relativeMatcher.find()) {
-            int amount = Integer.parseInt(relativeMatcher.group(2));
-            String unit = relativeMatcher.group(3);
-            LocalDate start = switch (unit) {
-                case "澶�" -> today.minusDays(Math.max(amount - 1L, 0));
-                case "鍛�" -> today.minusWeeks(Math.max(amount, 1)).plusDays(1);
-                case "涓湀", "鏈�" -> today.minusMonths(Math.max(amount, 1)).plusDays(1);
-                case "骞�" -> today.minusYears(Math.max(amount, 1)).plusDays(1);
-                default -> today.minusDays(29);
-            };
-            return new DateRange(start, today, "杩�" + amount + unit);
-        }
-        Matcher dateMatcher = DATE_PATTERN.matcher(text);
-        if (dateMatcher.find()) {
-            LocalDate start = parseLocalDate(dateMatcher.group(1));
-            LocalDate end = dateMatcher.find() ? parseLocalDate(dateMatcher.group(1)) : start;
-            if (start != null && end != null) {
-                if (start.isAfter(end)) {
-                    LocalDate temp = start;
-                    start = end;
-                    end = temp;
-                }
-                return new DateRange(start, end, start + "鑷�" + end);
-            }
-        }
-        return new DateRange(null, null, "鍏ㄩ儴");
-    }
-
-    private LocalDate parseLocalDate(String text) {
-        if (!StringUtils.hasText(text)) {
-            return null;
-        }
-        try {
-            return LocalDate.parse(text.trim(), DATE_FMT);
-        } catch (Exception ignored) {
-            return null;
-        }
-    }
-
-    private Date toDate(LocalDate localDate) {
-        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
-    }
-
-    private Date toExclusiveEndDate(LocalDate localDate) {
-        return Date.from(localDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
-    }
-
-    private LocalDate toLocalDate(Date date) {
-        if (date == null) {
-            return null;
-        }
-        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
-    }
-
-    private String formatDate(LocalDate date) {
-        return date == null ? "" : date.format(DATE_FMT);
-    }
-
-    private String displayDate(LocalDate date) {
-        return date == null ? "" : date.format(DATE_FMT);
-    }
-
-    private long daysBetween(LocalDate start, LocalDate end) {
-        if (start == null || end == null || start.isAfter(end)) {
-            return 0;
-        }
-        return end.toEpochDay() - start.toEpochDay();
-    }
-
-    private BigDecimal defaultDecimal(BigDecimal value) {
-        return value == null ? BigDecimal.ZERO : value;
-    }
-
-    private BigDecimal maxZero(BigDecimal value) {
-        return value == null || value.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : value;
-    }
-
-    private BigDecimal rate(BigDecimal numerator, BigDecimal denominator) {
-        if (denominator == null || denominator.compareTo(BigDecimal.ZERO) <= 0) {
-            return BigDecimal.ZERO;
-        }
-        return defaultDecimal(numerator).divide(denominator, 6, RoundingMode.HALF_UP);
-    }
-
-    private String toPercent(BigDecimal decimal) {
-        if (decimal == null) {
-            return "0.00%";
-        }
-        BigDecimal rate = decimal.multiply(ONE_HUNDRED).setScale(2, RoundingMode.HALF_UP);
-        return rate.toPlainString() + "%";
-    }
-
-    private BigDecimal avgRate(List<OrderProfitMetric> metrics) {
-        if (metrics == null || metrics.isEmpty()) {
-            return BigDecimal.ZERO;
-        }
-        BigDecimal sum = metrics.stream().map(OrderProfitMetric::profitRate).reduce(BigDecimal.ZERO, BigDecimal::add);
-        return sum.divide(new BigDecimal(metrics.size()), 6, RoundingMode.HALF_UP);
-    }
-
-    private BigDecimal estimateLaborCost(ProductionAccount account, Map<String, BigDecimal> salaryQuotaByOperation) {
-        BigDecimal salaryQuota = salaryQuotaByOperation.getOrDefault(safe(account.getTechnologyOperationName()), BigDecimal.ZERO);
-        BigDecimal finishedNum = defaultDecimal(account.getFinishedNum());
-        BigDecimal workHours = defaultDecimal(account.getWorkHours());
-        if (salaryQuota.compareTo(BigDecimal.ZERO) > 0 && finishedNum.compareTo(BigDecimal.ZERO) > 0) {
-            return finishedNum.multiply(salaryQuota);
-        }
-        if (salaryQuota.compareTo(BigDecimal.ZERO) > 0 && workHours.compareTo(BigDecimal.ZERO) > 0) {
-            return workHours.multiply(salaryQuota);
-        }
-        if (workHours.compareTo(BigDecimal.ZERO) > 0) {
-            return workHours;
-        }
-        return finishedNum;
-    }
-
-    private List<Long> parseIdList(String raw) {
-        if (!StringUtils.hasText(raw)) {
-            return List.of();
-        }
-        String text = raw.replace("[", "").replace("]", "").replace(" ", "");
-        if (!StringUtils.hasText(text)) {
-            return List.of();
-        }
-        List<Long> result = new ArrayList<>();
-        for (String part : text.split(",")) {
-            if (!StringUtils.hasText(part)) {
-                continue;
-            }
-            try {
-                result.add(Long.parseLong(part.trim()));
-            } catch (Exception ignored) {
-            }
-        }
-        return result;
-    }
-
-    private int keywordHitCount(List<String> keywords, String question) {
-        if (!StringUtils.hasText(question) || keywords == null) {
-            return 0;
-        }
-        int count = 0;
-        for (String keyword : keywords) {
-            if (question.contains(keyword)) {
-                count++;
-            }
-        }
-        return count;
-    }
-
-    private String normalizeForMatch(String text) {
-        if (!StringUtils.hasText(text)) {
-            return "";
-        }
-        return text.replace("锛�", "")
-                .replace(",", "")
-                .replace("銆�", "")
-                .replace(".", "")
-                .replace("锛�", "")
-                .replace("!", "")
-                .replace("锛�", "")
-                .replace("?", "")
-                .replace("锛�", "")
-                .replace(":", "")
-                .replace("锛�", "")
-                .replace(";", "")
-                .replace(" ", "")
-                .trim();
-    }
-
-    private String safe(Object value) {
-        return value == null ? "" : String.valueOf(value).replace('\n', ' ').replace('\r', ' ').trim();
-    }
-
-    private LoginUser currentLoginUser(String memoryId) {
-        LoginUser loginUser = aiSessionUserContext.get(memoryId);
-        if (loginUser != null) {
-            return loginUser;
-        }
-        return SecurityUtils.getLoginUser();
-    }
-
-    private Map<String, Object> rangeSummary(DateRange range, int count, String keyword) {
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", displayDate(range.start()));
-        summary.put("endDate", displayDate(range.end()));
-        summary.put("count", count);
-        summary.put("keyword", safe(keyword));
-        return summary;
-    }
-
-    private Long toLongOrNull(String value) {
-        if (!StringUtils.hasText(value)) {
-            return null;
-        }
-        try {
-            return Long.valueOf(value.trim());
-        } catch (Exception ignored) {
-            return null;
-        }
-    }
-
-    private <T> List<T> defaultList(List<T> list) {
-        return list == null ? List.of() : list;
-    }
-
-    private <T> void applyTenantFilter(LambdaQueryWrapper<T> wrapper, Long tenantId, SFunction<T, Long> field) {
-        if (tenantId != null) {
-            wrapper.eq(field, tenantId);
-        }
-    }
-
-    private <T> void applyDeptFilter(LambdaQueryWrapper<T> wrapper, Long deptId, SFunction<T, Long> field) {
-        if (deptId != null) {
-            wrapper.eq(field, deptId);
-        }
-    }
-
-    private List<KnowledgeDoc> financeKnowledgeBase() {
-        return List.of(
-                new KnowledgeDoc(
-                        "鍒╂鼎涓嬮檷鍒嗘瀽妗嗘灦",
-                        List.of("鍒╂鼎涓嬮檷", "浜忔崯璁㈠崟", "姣涘埄鐜�", "鍑�鍒╃巼"),
-                        "鍏堢湅鏀跺叆绔紙璁㈠崟缁撴瀯銆佸崟浠枫�佷氦浠樺欢杩燂級锛屽啀鐪嬫垚鏈锛堟潗鏂欍�佷汉宸ャ�佹姌鏃с�佹崯鑰楋級锛屾渶鍚庣湅鐜伴噾绔紙鍥炴銆佽处鏈熴�佸潖璐﹂闄╋級銆�",
-                        List.of("sales_ledger", "sales_ledger_product", "production_account", "device_ledger", "account_statement"),
-                        List.of("涓轰粈涔堟湰鏈堝埄娑︿笅闄嶏紵", "鍝簺璁㈠崟浜忔崯鏈�涓ラ噸锛�", "鎴愭湰涓婂崌鏉ヨ嚜鍝釜宸ュ簭锛�")
-                ),
-                new KnowledgeDoc(
-                        "搴撳瓨璧勯噾鍗犵敤璇婃柇",
-                        List.of("搴撳瓨绉帇", "鍛嗘粸搴撳瓨", "鍛ㄨ浆鐜�", "璧勯噾鍗犵敤"),
-                        "搴撳瓨璧勯噾璇婃柇閲嶇偣鐪嬶細搴撳瓨浠峰�笺�佽繎30澶╁嚭搴撴垚鏈�佸憜婊炲ぉ鏁般�佽秴鍌ㄦ瘮渚嬶紝褰㈡垚鍘诲簱瀛樹笌閲囪喘鑺傚鑱斿姩绛栫暐銆�",
-                        List.of("stock_inventory", "procurement_record_storage", "procurement_record_out"),
-                        List.of("鍝簺鐗╂枡璧勯噾鍗犵敤鏈�楂橈紵", "鍝簺搴撳瓨瓒呰繃90澶╂湭鍛ㄨ浆锛�", "搴撳瓨鍛ㄨ浆澶╂暟鏄惁寮傚父锛�")
-                ),
-                new KnowledgeDoc(
-                        "鐜伴噾娴佷笌璐︽椋庨櫓",
-                        List.of("鐜伴噾娴�", "搴旀敹", "搴斾粯", "鍥炴", "璧勯噾缂哄彛"),
-                        "鐜伴噾娴佸垽鏂缁撳悎鏀舵銆佷粯娆俱�佸簲鏀跺簲浠樹綑棰濅笌棰勬祴鍑�娴侀噺锛岄噸鐐瑰叧娉ㄩ珮浣欓瀹㈡埛鍜岄珮闆嗕腑浠樻渚涘簲鍟嗐��",
-                        List.of("account_sales_collection", "account_purchase_payment", "account_statement"),
-                        List.of("鏈潵涓変釜鏈堟槸鍚︽湁璧勯噾缂哄彛锛�", "鍝釜瀹㈡埛鍥炴椋庨櫓鏈�楂橈紵", "浠樻鍘嬪姏鏈�澶х殑鏄摢浜涗緵搴斿晢锛�")
-                ),
-                new KnowledgeDoc(
-                        "涓氳储涓�浣撳寲鍙e緞",
-                        List.of("涓氳储铻嶅悎", "涓氳储鑱斿姩", "鍙e緞", "椹鹃┒鑸�"),
-                        "璁㈠崟鍒╂鼎鍙e緞=閿�鍞敹鍏�-鏉愭枡鎴愭湰-浜哄伐鎴愭湰-璁惧鎶樻棫-鎹熻�楁垚鏈紱缁忚惀椹鹃┒鑸辫仈鍔ㄨ鍗曘�佺敓浜с�佸簱瀛樸�佽澶囥�佽处娆炬暟鎹��",
-                        List.of("sales_ledger", "production_operation_task", "production_product_main", "device_ledger", "stock_inventory", "account_statement"),
-                        List.of("璁㈠崟鍒╂鼎鐜囧浣曡绠楋紵", "缁忚惀椹鹃┒鑸辨牳蹇冩寚鏍囨湁鍝簺锛�")
-                )
-        );
-    }
-
-    private String jsonResponse(boolean success,
-                                String type,
-                                String description,
-                                Map<String, Object> summary,
-                                Map<String, Object> data,
-                                Map<String, Object> charts) {
-        Map<String, Object> result = new LinkedHashMap<>();
-        result.put("success", success);
-        result.put("type", type);
-        result.put("description", description);
-        result.put("summary", summary == null ? Map.of() : summary);
-        result.put("data", data == null ? Map.of() : data);
-        result.put("charts", charts == null ? Map.of() : charts);
-        return JSON.toJSONString(result);
-    }
-
-    private record DateRange(LocalDate start, LocalDate end, String label) {
-        private boolean hasDateFilter() {
-            return start != null && end != null;
-        }
-    }
-
-    private record OrderProfitMetric(Long ledgerId,
-                                     String salesContractNo,
-                                     String customerName,
-                                     String projectName,
-                                     LocalDate entryDate,
-                                     LocalDate deliveryDate,
-                                     BigDecimal revenue,
-                                     BigDecimal materialCost,
-                                     BigDecimal laborCost,
-                                     BigDecimal depreciationCost,
-                                     BigDecimal scrapCost,
-                                     BigDecimal totalCost,
-                                     BigDecimal profit,
-                                     BigDecimal profitRate,
-                                     String riskLevel,
-                                     List<String> reasons,
-                                     String suggestion) {
-    }
-
-    private record AnalysisBundle(List<OrderProfitMetric> orderMetrics,
-                                  Map<String, BigDecimal> processCostRanking,
-                                  BigDecimal totalRevenue,
-                                  BigDecimal totalMaterialCost,
-                                  BigDecimal totalLaborCost,
-                                  BigDecimal totalDepreciationCost,
-                                  BigDecimal totalScrapCost,
-                                  BigDecimal totalCost,
-                                  BigDecimal totalProfit) {
-        private static AnalysisBundle empty() {
-            return new AnalysisBundle(List.of(), Map.of(), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO,
-                    BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
-        }
-    }
-
-    private record MaterialCostResult(Map<Long, BigDecimal> materialCostByLedgerId,
-                                      Map<Long, BigDecimal> avgUnitCostByModelId) {
-    }
-
-    private record ProductionCostContext(Map<Long, BigDecimal> laborCostByLedgerId,
-                                         Map<Long, BigDecimal> scrapCostByLedgerId,
-                                         Map<String, BigDecimal> processCostRanking) {
-        private static ProductionCostContext empty() {
-            return new ProductionCostContext(Map.of(), Map.of(), Map.of());
-        }
-    }
-
-    private record InventoryMetric(Long modelId,
-                                   String productName,
-                                   String modelName,
-                                   BigDecimal quantity,
-                                   BigDecimal lockedQuantity,
-                                   BigDecimal avgUnitCost,
-                                   BigDecimal inventoryValue,
-                                   BigDecimal outboundQuantity,
-                                   long stagnantDays,
-                                   boolean overstock) {
-    }
-
-    private static class InventoryMetricBuilder {
-        private final Long modelId;
-        private BigDecimal quantity = BigDecimal.ZERO;
-        private BigDecimal lockedQuantity = BigDecimal.ZERO;
-        private BigDecimal warnNum = BigDecimal.ZERO;
-        private LocalDateTime firstInTime;
-
-        private InventoryMetricBuilder(Long modelId) {
-            this.modelId = modelId;
-        }
-
-        private void addQuantity(BigDecimal quantity) {
-            this.quantity = this.quantity.add(quantity);
-        }
-
-        private void addLockedQuantity(BigDecimal lockedQuantity) {
-            this.lockedQuantity = this.lockedQuantity.add(lockedQuantity);
-        }
-
-        private void addWarnNum(BigDecimal warnNum) {
-            this.warnNum = this.warnNum.max(warnNum);
-        }
-
-        private void updateFirstInTime(LocalDateTime createTime) {
-            if (this.firstInTime == null || createTime.isBefore(this.firstInTime)) {
-                this.firstInTime = createTime;
-            }
-        }
-
-        private Long modelId() {
-            return modelId;
-        }
-
-        private BigDecimal quantity() {
-            return quantity;
-        }
-
-        private BigDecimal lockedQuantity() {
-            return lockedQuantity;
-        }
-
-        private BigDecimal warnNum() {
-            return warnNum;
-        }
-
-        private LocalDateTime firstInTime() {
-            return firstInTime;
-        }
-    }
-
-    private record OutboundStats(Map<Long, BigDecimal> outboundQtyByModel,
-                                 Map<Long, LocalDateTime> lastOutboundTimeByModel,
-                                 BigDecimal totalOutboundCost) {
-        private static OutboundStats empty() {
-            return new OutboundStats(Map.of(), Map.of(), BigDecimal.ZERO);
-        }
-    }
-
-    private record MonthlyCashFlow(String month, BigDecimal income, BigDecimal expense, BigDecimal netFlow) {
-    }
-
-    private record StatementMetric(String entityId,
-                                   BigDecimal closingBalance,
-                                   BigDecimal planAmount,
-                                   BigDecimal actualAmount,
-                                   String statementMonth) {
-    }
-
-    private record StatementSnapshot(BigDecimal receivableTotal,
-                                     BigDecimal payableTotal,
-                                     List<StatementMetric> receivableTop,
-                                     List<StatementMetric> payableTop) {
-        private static StatementSnapshot empty() {
-            return new StatementSnapshot(BigDecimal.ZERO, BigDecimal.ZERO, List.of(), List.of());
-        }
-    }
-
-    private record KnowledgeDoc(String topic,
-                                List<String> keywords,
-                                String knowledge,
-                                List<String> relatedTables,
-                                List<String> suggestedQuestions) {
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/tools/ManufacturingAgentTools.java b/src/main/java/com/ruoyi/ai/tools/ManufacturingAgentTools.java
deleted file mode 100644
index 1ff96c1..0000000
--- a/src/main/java/com/ruoyi/ai/tools/ManufacturingAgentTools.java
+++ /dev/null
@@ -1,1035 +0,0 @@
-package com.ruoyi.ai.tools;
-
-import com.alibaba.fastjson2.JSON;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
-import com.ruoyi.ai.context.AiSessionUserContext;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.device.mapper.DeviceDefectRecordMapper;
-import com.ruoyi.device.mapper.DeviceLedgerMapper;
-import com.ruoyi.device.mapper.DeviceRepairMapper;
-import com.ruoyi.device.pojo.DeviceDefectRecord;
-import com.ruoyi.device.pojo.DeviceLedger;
-import com.ruoyi.device.pojo.DeviceRepair;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.procurementrecord.mapper.ProcurementExceptionRecordMapper;
-import com.ruoyi.procurementrecord.pojo.ProcurementExceptionRecord;
-import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
-import com.ruoyi.production.mapper.ProductionOrderMapper;
-import com.ruoyi.production.mapper.ProductionPlanMapper;
-import com.ruoyi.production.mapper.ProductionProductMainMapper;
-import com.ruoyi.production.pojo.ProductionOperationTask;
-import com.ruoyi.production.pojo.ProductionOrder;
-import com.ruoyi.production.pojo.ProductionPlan;
-import com.ruoyi.production.pojo.ProductionProductMain;
-import com.ruoyi.quality.mapper.QualityInspectMapper;
-import com.ruoyi.quality.mapper.QualityUnqualifiedMapper;
-import com.ruoyi.quality.pojo.QualityInspect;
-import com.ruoyi.quality.pojo.QualityUnqualified;
-import com.ruoyi.stock.mapper.StockInventoryMapper;
-import com.ruoyi.stock.pojo.StockInventory;
-import dev.langchain4j.agent.tool.P;
-import dev.langchain4j.agent.tool.Tool;
-import dev.langchain4j.agent.tool.ToolMemoryId;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.ChronoUnit;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-@Component
-public class ManufacturingAgentTools {
-
-    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final int DEFAULT_LIMIT = 10;
-    private static final int MAX_LIMIT = 30;
-    private static final int DEVICE_REPAIR_STATUS_PENDING = 0;
-
-    private final ProductionPlanMapper productionPlanMapper;
-    private final ProductionOrderMapper productionOrderMapper;
-    private final ProductionOperationTaskMapper productionOperationTaskMapper;
-    private final ProductionProductMainMapper productionProductMainMapper;
-    private final DeviceLedgerMapper deviceLedgerMapper;
-    private final DeviceRepairMapper deviceRepairMapper;
-    private final DeviceDefectRecordMapper deviceDefectRecordMapper;
-    private final QualityInspectMapper qualityInspectMapper;
-    private final QualityUnqualifiedMapper qualityUnqualifiedMapper;
-    private final StockInventoryMapper stockInventoryMapper;
-    private final ProcurementExceptionRecordMapper procurementExceptionRecordMapper;
-    private final AiSessionUserContext aiSessionUserContext;
-
-    public ManufacturingAgentTools(ProductionPlanMapper productionPlanMapper,
-                                   ProductionOrderMapper productionOrderMapper,
-                                   ProductionOperationTaskMapper productionOperationTaskMapper,
-                                   ProductionProductMainMapper productionProductMainMapper,
-                                   DeviceLedgerMapper deviceLedgerMapper,
-                                   DeviceRepairMapper deviceRepairMapper,
-                                   DeviceDefectRecordMapper deviceDefectRecordMapper,
-                                   QualityInspectMapper qualityInspectMapper,
-                                   QualityUnqualifiedMapper qualityUnqualifiedMapper,
-                                   StockInventoryMapper stockInventoryMapper,
-                                   ProcurementExceptionRecordMapper procurementExceptionRecordMapper,
-                                   AiSessionUserContext aiSessionUserContext) {
-        this.productionPlanMapper = productionPlanMapper;
-        this.productionOrderMapper = productionOrderMapper;
-        this.productionOperationTaskMapper = productionOperationTaskMapper;
-        this.productionProductMainMapper = productionProductMainMapper;
-        this.deviceLedgerMapper = deviceLedgerMapper;
-        this.deviceRepairMapper = deviceRepairMapper;
-        this.deviceDefectRecordMapper = deviceDefectRecordMapper;
-        this.qualityInspectMapper = qualityInspectMapper;
-        this.qualityUnqualifiedMapper = qualityUnqualifiedMapper;
-        this.stockInventoryMapper = stockInventoryMapper;
-        this.procurementExceptionRecordMapper = procurementExceptionRecordMapper;
-        this.aiSessionUserContext = aiSessionUserContext;
-    }
-
-    @Tool(name = "鏌ヨ鍒堕�犱笟鍔″煙鏁版嵁", value = "鎸変笟鍔″煙鏌ヨ鐢熶骇鐜板満銆佽鍒掋�佸伐鍗曘�佽澶囥�佽川閲忋�佺墿鏂欍�佸紓甯稿鐞嗙浉鍏虫暟鎹��")
-    public String queryDomain(@ToolMemoryId String memoryId,
-                              @P(value = "涓氬姟鍩燂紝site/plan/workorder/device/quality/material/exception") String domain,
-                              @P(value = "鍏抽敭瀛楋紝鍙笉浼�", required = false) String keyword,
-                              @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit,
-                              @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd锛屽彲涓嶄紶", required = false) String startDate,
-                              @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd锛屽彲涓嶄紶", required = false) String endDate,
-                              @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屼緥濡備粖骞淬�佹湰鏈堛�佽繎30澶�", required = false) String timeRange) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        int finalLimit = normalizeLimit(limit);
-        DateRange range = resolveDateRange(startDate, endDate, timeRange);
-        boolean hasTimeConstraint = hasTimeConstraint(startDate, endDate, timeRange);
-        String normalizedDomain = normalizeDomain(domain);
-
-        return switch (normalizedDomain) {
-            case "site" -> siteSnapshot(loginUser, range);
-            case "plan" -> listProductionPlans(loginUser, keyword, finalLimit, range);
-            case "workorder" -> listWorkOrders(loginUser, keyword, finalLimit, range);
-            case "device" -> isRepairIntent(keyword, timeRange)
-                    ? listDeviceRepairs(loginUser, normalizeDeviceQueryKeyword(keyword, timeRange), finalLimit, range, hasTimeConstraint)
-                    : listDevices(loginUser, normalizeDeviceQueryKeyword(keyword, timeRange), finalLimit);
-            case "repair" -> listDeviceRepairs(loginUser, normalizeDeviceQueryKeyword(keyword, timeRange), finalLimit, range, hasTimeConstraint);
-            case "quality" -> listQualityIssues(loginUser, keyword, finalLimit, range);
-            case "material" -> listMaterialInventory(loginUser, keyword, finalLimit);
-            case "exception" -> listExceptions(loginUser, keyword, finalLimit, range);
-            default -> jsonResponse(false, "manufacturing_query", "涓嶆敮鎸佺殑涓氬姟鍩�: " + safe(domain), Map.of(), Map.of(), Map.of());
-        };
-    }
-
-    @Tool(name = "鍒堕�犻璀︾湅鏉�", value = "璁$畻璁″垝銆佸伐鍗曘�佽澶囥�佽川閲忋�佺墿鏂欍�佸紓甯稿鐞嗙殑棰勮淇℃伅銆�")
-    public String getWarningBoard(@ToolMemoryId String memoryId,
-                                  @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd锛屽彲涓嶄紶", required = false) String startDate,
-                                  @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd锛屽彲涓嶄紶", required = false) String endDate,
-                                  @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屼緥濡備粖澶┿�佹湰鍛ㄣ�佹湰鏈堛�佽繎30澶�", required = false) String timeRange) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, timeRange);
-        LocalDate today = LocalDate.now();
-
-        long overduePlanCount = countOverduePlans(loginUser, today);
-        long overdueWorkOrderCount = countOverdueWorkOrders(loginUser, today);
-        long pendingRepairCount = countPendingRepairs(loginUser);
-        long qualityOpenCount = countOpenQualityIssues(loginUser, range);
-        long lowStockCount = countLowStock(loginUser);
-        long exceptionCount = countExceptionRecords(loginUser, range);
-
-        List<Map<String, Object>> warningItems = new ArrayList<>();
-        if (overduePlanCount > 0) {
-            warningItems.add(warningItem("high", "璁″垝閫炬湡", overduePlanCount, "鏈夌敓浜ц鍒掕秴杩囬渶姹傛棩鏈熶粛鏈畬鎴�"));
-        }
-        if (overdueWorkOrderCount > 0) {
-            warningItems.add(warningItem("high", "宸ュ崟閫炬湡", overdueWorkOrderCount, "鏈夊伐鍗曡鍒掔粨鏉熸棩鏈熷凡杩囦粛鏈畬宸�"));
-        }
-        if (pendingRepairCount > 0) {
-            warningItems.add(warningItem("medium", "璁惧寰呯淮淇�", pendingRepairCount, "瀛樺湪寰呯淮淇�/缁翠慨涓殑璁惧"));
-        }
-        if (qualityOpenCount > 0) {
-            warningItems.add(warningItem("high", "璐ㄩ噺鏈棴鐜�", qualityOpenCount, "瀛樺湪鏈鐞嗗畬鎴愮殑涓嶅悎鏍艰褰�"));
-        }
-        if (lowStockCount > 0) {
-            warningItems.add(warningItem("medium", "鐗╂枡浣庡簱瀛�", lowStockCount, "搴撳瓨鏁伴噺浣庝簬鎴栫瓑浜庨璀﹂槇鍊�"));
-        }
-        if (exceptionCount > 0) {
-            warningItems.add(warningItem("medium", "寮傚父璁板綍", exceptionCount, "鏃堕棿鑼冨洿鍐呭瓨鍦ㄥ紓甯稿鐞嗚褰�"));
-        }
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", range.start().toString());
-        summary.put("endDate", range.end().toString());
-        summary.put("warningCount", warningItems.size());
-        summary.put("overduePlanCount", overduePlanCount);
-        summary.put("overdueWorkOrderCount", overdueWorkOrderCount);
-        summary.put("pendingRepairCount", pendingRepairCount);
-        summary.put("qualityOpenCount", qualityOpenCount);
-        summary.put("lowStockCount", lowStockCount);
-        summary.put("exceptionCount", exceptionCount);
-
-        return jsonResponse(true, "manufacturing_warning", "宸茶繑鍥炲埗閫犻璀︾湅鏉裤��", summary,
-                Map.of("items", warningItems), Map.of());
-    }
-
-    @Tool(name = "鍒堕�犵粡钀ュ垎鏋�", value = "鎸夋椂闂磋寖鍥磋緭鍑哄埗閫犲叧閿寚鏍囷紝鏀寔鏌ャ�侀棶銆佸垎鏋愬満鏅��")
-    public String analyzeFactory(@ToolMemoryId String memoryId,
-                                 @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd锛屽彲涓嶄紶", required = false) String startDate,
-                                 @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd锛屽彲涓嶄紶", required = false) String endDate,
-                                 @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屼緥濡傛湰鏈堛�佽繎30澶�", required = false) String timeRange) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, timeRange);
-
-        long planTotal = countPlans(loginUser, range);
-        long planCompleted = countPlansByStatus(loginUser, range, 2);
-        long workOrderTotal = countWorkOrders(loginUser, range);
-        long workOrderCompleted = countWorkOrdersByStatus(loginUser, range, 2);
-        long workOrderInProgress = countWorkOrdersByStatus(loginUser, range, 1);
-
-        long outputCount = countOutputs(loginUser, range);
-        long deviceTotal = countDevices(loginUser);
-        long pendingRepairCount = countPendingRepairs(loginUser);
-        long qualityInspectTotal = countQualityInspect(loginUser, range);
-        long qualityNgCount = countOpenQualityIssues(loginUser, range);
-        long materialSkuCount = countInventorySku(loginUser);
-        long lowStockCount = countLowStock(loginUser);
-        long exceptionCount = countExceptionRecords(loginUser, range);
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", range.start().toString());
-        summary.put("endDate", range.end().toString());
-        summary.put("planTotal", planTotal);
-        summary.put("planCompleted", planCompleted);
-        summary.put("planCompletionRate", toRate(planCompleted, planTotal));
-        summary.put("workOrderTotal", workOrderTotal);
-        summary.put("workOrderCompleted", workOrderCompleted);
-        summary.put("workOrderInProgress", workOrderInProgress);
-        summary.put("workOrderCompletionRate", toRate(workOrderCompleted, workOrderTotal));
-        summary.put("outputCount", outputCount);
-        summary.put("deviceTotal", deviceTotal);
-        summary.put("pendingRepairCount", pendingRepairCount);
-        summary.put("qualityInspectTotal", qualityInspectTotal);
-        summary.put("qualityNgCount", qualityNgCount);
-        summary.put("qualityIssueRate", toRate(qualityNgCount, qualityInspectTotal));
-        summary.put("materialSkuCount", materialSkuCount);
-        summary.put("lowStockCount", lowStockCount);
-        summary.put("exceptionCount", exceptionCount);
-
-        List<Map<String, Object>> coreMetrics = List.of(
-                metric("璁″垝瀹屾垚鐜�", toRate(planCompleted, planTotal)),
-                metric("宸ュ崟瀹屾垚鐜�", toRate(workOrderCompleted, workOrderTotal)),
-                metric("璐ㄩ噺寮傚父鐜�", toRate(qualityNgCount, qualityInspectTotal)),
-                metric("浣庡簱瀛樺崰姣�", toRate(lowStockCount, materialSkuCount))
-        );
-
-        Map<String, Object> charts = new LinkedHashMap<>();
-        charts.put("domainBarOption", buildDomainBarOption(summary));
-        charts.put("qualityPieOption", buildQualityPieOption(qualityInspectTotal, qualityNgCount));
-
-        return jsonResponse(true, "manufacturing_analysis", "宸茶繑鍥炲埗閫犲垎鏋愮粨鏋溿��", summary,
-                Map.of("coreMetrics", coreMetrics), charts);
-    }
-
-    @Tool(name = "鐢熸垚鍒堕�犲姙鐞嗗缓璁�", value = "鏍规嵁鐢ㄦ埛闂杈撳嚭鍙墽琛岀殑鍔炵悊鍔ㄤ綔寤鸿锛屽寘鎷洰鏍囦笟鍔℃帴鍙c�佸繀濉瓧娈靛拰绀轰緥銆�")
-    public String planActions(@ToolMemoryId String memoryId,
-                              @P("鐢ㄦ埛璇夋眰鍘熸枃") String userQuery) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        List<Map<String, Object>> actionCards = new ArrayList<>();
-
-        if (!StringUtils.hasText(userQuery) || containsAny(userQuery, "宸ュ崟", "娲惧伐", "浣滀笟")) {
-            actionCards.add(actionCard(
-                    "workorder_assign",
-                    "宸ュ崟娲惧伐",
-                    "POST",
-                    "/productionOperationTask/assign",
-                    List.of("id", "userIds"),
-                    Map.of("id", 10001, "userIds", "12,13"),
-                    "灏嗗伐鍗曞垎閰嶇粰鎸囧畾浜哄憳锛岄�傜敤浜庣幇鍦鸿皟搴︺��"));
-        }
-        if (!StringUtils.hasText(userQuery) || containsAny(userQuery, "璁惧", "缁翠慨", "鏁呴殰")) {
-            actionCards.add(actionCard(
-                    "device_repair_create",
-                    "鍒涘缓璁惧缁翠慨鍗�",
-                    "POST",
-                    "/device/repair",
-                    List.of("deviceLedgerId", "deviceName", "repairName", "remark"),
-                    Map.of("deviceLedgerId", 1001, "deviceName", "绌哄帇鏈篈-01", "repairName", "寮犱笁", "remark", "寮傚搷骞朵即闅忔俯鍗�"),
-                    "鏂板缓缁翠慨鍗曪紝杩涘叆璁惧寮傚父澶勭悊闂幆銆�"));
-        }
-        if (!StringUtils.hasText(userQuery) || containsAny(userQuery, "璐ㄩ噺", "涓嶅悎鏍�", "闂幆")) {
-            actionCards.add(actionCard(
-                    "quality_unqualified_deal",
-                    "澶勭悊涓嶅悎鏍煎崟",
-                    "POST",
-                    "/quality/qualityUnqualified/deal",
-                    List.of("id", "dealResult", "dealName"),
-                    Map.of("id", 3001, "dealResult", "杩斿伐鍚庡妫�", "dealName", "鏉庡洓"),
-                    "瀵逛笉鍚堟牸璁板綍鎵ц澶勭疆骞堕棴鐜��"));
-        }
-        if (!StringUtils.hasText(userQuery) || containsAny(userQuery, "鐗╂枡", "搴撳瓨", "琛ユ枡")) {
-            actionCards.add(actionCard(
-                    "material_inbound",
-                    "琛ュ厖搴撳瓨",
-                    "POST",
-                    "/stockInventory/addstockInventory",
-                    List.of("productModelId", "batchNo", "qualitity"),
-                    Map.of("productModelId", 5001, "batchNo", "B2026051601", "qualitity", 120),
-                    "褰撲綆搴撳瓨棰勮瑙﹀彂鏃讹紝澧炲姞搴撳瓨鏁伴噺銆�"));
-        }
-        if (!StringUtils.hasText(userQuery) || containsAny(userQuery, "寮傚父", "閲囪喘寮傚父", "鏉ユ枡寮傚父")) {
-            actionCards.add(actionCard(
-                    "procurement_exception_add",
-                    "鐧昏寮傚父璁板綍",
-                    "POST",
-                    "/procurementExceptionRecord/add",
-                    List.of("purchaseLedgerId", "exceptionReason", "exceptionNum"),
-                    Map.of("purchaseLedgerId", 888, "exceptionReason", "鍒版枡鐭己", "exceptionNum", 24),
-                    "鐧昏閲囪喘/鏉ユ枡寮傚父锛屼究浜庡悗缁拷韪拰鍒嗘瀽銆�"));
-        }
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("actionCount", actionCards.size());
-        summary.put("userId", loginUser.getUserId());
-        summary.put("tenantId", loginUser.getTenantId());
-
-        return jsonResponse(true, "manufacturing_action_plan", "宸茬敓鎴愬姙鐞嗗缓璁紝璇峰墠绔紩瀵肩敤鎴风‘璁ゅ悗璋冪敤鐩爣涓氬姟鎺ュ彛銆�",
-                summary, Map.of("actionCards", actionCards), Map.of());
-    }
-
-    private String siteSnapshot(LoginUser loginUser, DateRange range) {
-        long planTotal = countPlans(loginUser, range);
-        long workOrderTotal = countWorkOrders(loginUser, range);
-        long outputCount = countOutputs(loginUser, range);
-        long deviceTotal = countDevices(loginUser);
-        long pendingRepairCount = countPendingRepairs(loginUser);
-        long qualityOpenCount = countOpenQualityIssues(loginUser, range);
-        long lowStockCount = countLowStock(loginUser);
-        long exceptionCount = countExceptionRecords(loginUser, range);
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", range.start().toString());
-        summary.put("endDate", range.end().toString());
-        summary.put("planTotal", planTotal);
-        summary.put("workOrderTotal", workOrderTotal);
-        summary.put("outputCount", outputCount);
-        summary.put("deviceTotal", deviceTotal);
-        summary.put("pendingRepairCount", pendingRepairCount);
-        summary.put("qualityOpenCount", qualityOpenCount);
-        summary.put("lowStockCount", lowStockCount);
-        summary.put("exceptionCount", exceptionCount);
-
-        return jsonResponse(true, "manufacturing_site_snapshot", "宸茶繑鍥炵敓浜х幇鍦烘瑙堛��", summary, Map.of(), Map.of());
-    }
-
-    private String listProductionPlans(LoginUser loginUser, String keyword, int limit, DateRange range) {
-        LambdaQueryWrapper<ProductionPlan> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProductionPlan::getDeptId);
-        wrapper.ge(ProductionPlan::getRequiredDate, range.start()).le(ProductionPlan::getRequiredDate, range.end());
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(ProductionPlan::getMpsNo, keyword)
-                    .or().like(ProductionPlan::getRemark, keyword)
-                    .or().like(ProductionPlan::getSource, keyword));
-        }
-        wrapper.orderByDesc(ProductionPlan::getRequiredDate, ProductionPlan::getId).last("limit " + limit);
-
-        List<Map<String, Object>> items = defaultList(productionPlanMapper.selectList(wrapper)).stream()
-                .map(this::toPlanItem)
-                .collect(Collectors.toList());
-        return jsonResponse(true, "manufacturing_plan_list", "宸茶繑鍥炵敓浜ц鍒掑垪琛ㄣ��",
-                rangeSummary(range, items.size(), keyword), Map.of("items", items), Map.of());
-    }
-
-    private String listWorkOrders(LoginUser loginUser, String keyword, int limit, DateRange range) {
-        LambdaQueryWrapper<ProductionOperationTask> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProductionOperationTask::getDeptId);
-        wrapper.ge(ProductionOperationTask::getPlanStartTime, range.start())
-                .le(ProductionOperationTask::getPlanEndTime, range.end());
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(ProductionOperationTask::getWorkOrderNo, keyword)
-                    .or().like(ProductionOperationTask::getUserIds, keyword));
-        }
-        wrapper.orderByDesc(ProductionOperationTask::getPlanEndTime, ProductionOperationTask::getId)
-                .last("limit " + limit);
-
-        List<Map<String, Object>> items = defaultList(productionOperationTaskMapper.selectList(wrapper)).stream()
-                .map(this::toWorkOrderItem)
-                .collect(Collectors.toList());
-        return jsonResponse(true, "manufacturing_workorder_list", "宸茶繑鍥炲伐鍗曞垪琛ㄣ��",
-                rangeSummary(range, items.size(), keyword), Map.of("items", items), Map.of());
-    }
-
-    private String listDevices(LoginUser loginUser, String keyword, int limit) {
-        LambdaQueryWrapper<DeviceLedger> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), DeviceLedger::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), DeviceLedger::getDeptId);
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(DeviceLedger::getDeviceName, keyword)
-                    .or().like(DeviceLedger::getDeviceModel, keyword)
-                    .or().like(DeviceLedger::getDeviceBrand, keyword));
-        }
-        wrapper.orderByDesc(DeviceLedger::getId).last("limit " + limit);
-
-        Map<Long, Long> pendingRepairMap = pendingRepairCountByDevice(loginUser);
-        List<Map<String, Object>> items = defaultList(deviceLedgerMapper.selectList(wrapper)).stream()
-                .map(item -> toDeviceItem(item, pendingRepairMap.getOrDefault(item.getId(), 0L)))
-                .collect(Collectors.toList());
-        return jsonResponse(true, "manufacturing_device_list", "宸茶繑鍥炶澶囧垪琛ㄣ��",
-                Map.of("count", items.size(), "keyword", safe(keyword)), Map.of("items", items), Map.of());
-    }
-
-    private String listDeviceRepairs(LoginUser loginUser, String keyword, int limit, DateRange range, boolean hasTimeConstraint) {
-        LambdaQueryWrapper<DeviceRepair> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), DeviceRepair::getTenantId);
-        Long currentDeptId = loginUser.getCurrentDeptId();
-        if (currentDeptId != null) {
-            wrapper.and(w -> w.eq(DeviceRepair::getDeptId, currentDeptId).or().isNull(DeviceRepair::getDeptId));
-        }
-        if (hasTimeConstraint) {
-            wrapper.ge(DeviceRepair::getCreateTime, range.start().atStartOfDay())
-                    .lt(DeviceRepair::getCreateTime, range.end().plusDays(1).atStartOfDay());
-        }
-        if (StringUtils.hasText(keyword)) {
-            List<Long> matchedDeviceIds = findDeviceLedgerIdsByKeyword(loginUser, keyword);
-            wrapper.and(w -> {
-                w.like(DeviceRepair::getDeviceName, keyword)
-                        .or().like(DeviceRepair::getDeviceModel, keyword)
-                        .or().like(DeviceRepair::getRemark, keyword)
-                        .or().like(DeviceRepair::getRepairName, keyword)
-                        .or().like(DeviceRepair::getMaintenanceName, keyword);
-                if (!matchedDeviceIds.isEmpty()) {
-                    w.or().in(DeviceRepair::getDeviceLedgerId, matchedDeviceIds);
-                }
-            });
-        }
-        wrapper.orderByDesc(DeviceRepair::getCreateTime, DeviceRepair::getId).last("limit " + limit);
-
-        List<Map<String, Object>> items = defaultList(deviceRepairMapper.selectList(wrapper)).stream()
-                .map(this::toDeviceRepairItem)
-                .collect(Collectors.toList());
-        return jsonResponse(true, "manufacturing_device_repair_list", "宸茶繑鍥炶澶囩淮淇褰曘��",
-                rangeSummary(range, items.size(), keyword), Map.of("items", items), Map.of());
-    }
-
-    private String listQualityIssues(LoginUser loginUser, String keyword, int limit, DateRange range) {
-        LambdaQueryWrapper<QualityUnqualified> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), QualityUnqualified::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), QualityUnqualified::getDeptId);
-        wrapper.ge(QualityUnqualified::getCheckTime, toDate(range.start()))
-                .lt(QualityUnqualified::getCheckTime, toExclusiveEndDate(range.end()));
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(QualityUnqualified::getProductName, keyword)
-                    .or().like(QualityUnqualified::getDefectivePhenomena, keyword)
-                    .or().like(QualityUnqualified::getDealResult, keyword));
-        }
-        wrapper.orderByDesc(QualityUnqualified::getCheckTime, QualityUnqualified::getId).last("limit " + limit);
-
-        List<Map<String, Object>> items = defaultList(qualityUnqualifiedMapper.selectList(wrapper)).stream()
-                .map(this::toQualityItem)
-                .collect(Collectors.toList());
-        return jsonResponse(true, "manufacturing_quality_list", "宸茶繑鍥炶川閲忓紓甯稿垪琛ㄣ��",
-                rangeSummary(range, items.size(), keyword), Map.of("items", items), Map.of());
-    }
-
-    private String listMaterialInventory(LoginUser loginUser, String keyword, int limit) {
-        LambdaQueryWrapper<StockInventory> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), StockInventory::getDeptId);
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(StockInventory::getBatchNo, keyword)
-                    .or().like(StockInventory::getProductModelId, keyword));
-        }
-        wrapper.orderByDesc(StockInventory::getId).last("limit " + limit);
-
-        List<Map<String, Object>> items = defaultList(stockInventoryMapper.selectList(wrapper)).stream()
-                .map(this::toMaterialItem)
-                .collect(Collectors.toList());
-        return jsonResponse(true, "manufacturing_material_list", "宸茶繑鍥炵墿鏂欏簱瀛樺垪琛ㄣ��",
-                Map.of("count", items.size(), "keyword", safe(keyword)), Map.of("items", items), Map.of());
-    }
-
-    private String listExceptions(LoginUser loginUser, String keyword, int limit, DateRange range) {
-        LambdaQueryWrapper<ProcurementExceptionRecord> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), ProcurementExceptionRecord::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProcurementExceptionRecord::getDeptId);
-        wrapper.ge(ProcurementExceptionRecord::getCreateTime, range.start().atStartOfDay())
-                .lt(ProcurementExceptionRecord::getCreateTime, range.end().plusDays(1).atStartOfDay());
-        if (StringUtils.hasText(keyword)) {
-            wrapper.like(ProcurementExceptionRecord::getExceptionReason, keyword);
-        }
-        wrapper.orderByDesc(ProcurementExceptionRecord::getCreateTime, ProcurementExceptionRecord::getId)
-                .last("limit " + limit);
-
-        List<Map<String, Object>> items = defaultList(procurementExceptionRecordMapper.selectList(wrapper)).stream()
-                .map(this::toExceptionItem)
-                .collect(Collectors.toList());
-        return jsonResponse(true, "manufacturing_exception_list", "宸茶繑鍥炲紓甯稿鐞嗗垪琛ㄣ��",
-                rangeSummary(range, items.size(), keyword), Map.of("items", items), Map.of());
-    }
-
-    private long countPlans(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<ProductionPlan> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProductionPlan::getDeptId);
-        wrapper.ge(ProductionPlan::getRequiredDate, range.start()).le(ProductionPlan::getRequiredDate, range.end());
-        return productionPlanMapper.selectCount(wrapper);
-    }
-
-    private long countPlansByStatus(LoginUser loginUser, DateRange range, int status) {
-        LambdaQueryWrapper<ProductionPlan> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProductionPlan::getDeptId);
-        wrapper.ge(ProductionPlan::getRequiredDate, range.start())
-                .le(ProductionPlan::getRequiredDate, range.end())
-                .eq(ProductionPlan::getStatus, status);
-        return productionPlanMapper.selectCount(wrapper);
-    }
-
-    private long countWorkOrders(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<ProductionOperationTask> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProductionOperationTask::getDeptId);
-        wrapper.ge(ProductionOperationTask::getPlanStartTime, range.start())
-                .le(ProductionOperationTask::getPlanEndTime, range.end());
-        return productionOperationTaskMapper.selectCount(wrapper);
-    }
-
-    private long countWorkOrdersByStatus(LoginUser loginUser, DateRange range, int status) {
-        LambdaQueryWrapper<ProductionOperationTask> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProductionOperationTask::getDeptId);
-        wrapper.ge(ProductionOperationTask::getPlanStartTime, range.start())
-                .le(ProductionOperationTask::getPlanEndTime, range.end())
-                .eq(ProductionOperationTask::getStatus, status);
-        return productionOperationTaskMapper.selectCount(wrapper);
-    }
-
-    private long countOutputs(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<ProductionProductMain> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProductionProductMain::getDeptId);
-        wrapper.ge(ProductionProductMain::getCreateTime, range.start().atStartOfDay())
-                .lt(ProductionProductMain::getCreateTime, range.end().plusDays(1).atStartOfDay());
-        return productionProductMainMapper.selectCount(wrapper);
-    }
-
-    private long countDevices(LoginUser loginUser) {
-        LambdaQueryWrapper<DeviceLedger> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), DeviceLedger::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), DeviceLedger::getDeptId);
-        return deviceLedgerMapper.selectCount(wrapper);
-    }
-
-    private long countPendingRepairs(LoginUser loginUser) {
-        LambdaQueryWrapper<DeviceRepair> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), DeviceRepair::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), DeviceRepair::getDeptId);
-        wrapper.eq(DeviceRepair::getStatus, DEVICE_REPAIR_STATUS_PENDING);
-        return deviceRepairMapper.selectCount(wrapper);
-    }
-
-    private long countQualityInspect(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<QualityInspect> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), QualityInspect::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), QualityInspect::getDeptId);
-        wrapper.ge(QualityInspect::getCheckTime, toDate(range.start()))
-                .lt(QualityInspect::getCheckTime, toExclusiveEndDate(range.end()));
-        return qualityInspectMapper.selectCount(wrapper);
-    }
-
-    private long countOpenQualityIssues(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<QualityUnqualified> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), QualityUnqualified::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), QualityUnqualified::getDeptId);
-        wrapper.ge(QualityUnqualified::getCheckTime, toDate(range.start()))
-                .lt(QualityUnqualified::getCheckTime, toExclusiveEndDate(range.end()))
-                .ne(QualityUnqualified::getInspectState, 2);
-        return qualityUnqualifiedMapper.selectCount(wrapper);
-    }
-
-    private long countInventorySku(LoginUser loginUser) {
-        LambdaQueryWrapper<StockInventory> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), StockInventory::getDeptId);
-        return stockInventoryMapper.selectCount(wrapper);
-    }
-
-    private long countLowStock(LoginUser loginUser) {
-        LambdaQueryWrapper<StockInventory> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), StockInventory::getDeptId);
-        wrapper.isNotNull(StockInventory::getWarnNum);
-        List<StockInventory> stocks = defaultList(stockInventoryMapper.selectList(wrapper));
-        return stocks.stream()
-                .filter(this::isLowStock)
-                .count();
-    }
-
-    private long countExceptionRecords(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<ProcurementExceptionRecord> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), ProcurementExceptionRecord::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProcurementExceptionRecord::getDeptId);
-        wrapper.ge(ProcurementExceptionRecord::getCreateTime, range.start().atStartOfDay())
-                .lt(ProcurementExceptionRecord::getCreateTime, range.end().plusDays(1).atStartOfDay());
-        return procurementExceptionRecordMapper.selectCount(wrapper);
-    }
-
-    private long countOverduePlans(LoginUser loginUser, LocalDate today) {
-        LambdaQueryWrapper<ProductionPlan> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProductionPlan::getDeptId);
-        wrapper.lt(ProductionPlan::getRequiredDate, today).ne(ProductionPlan::getStatus, 2);
-        return productionPlanMapper.selectCount(wrapper);
-    }
-
-    private long countOverdueWorkOrders(LoginUser loginUser, LocalDate today) {
-        LambdaQueryWrapper<ProductionOperationTask> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ProductionOperationTask::getDeptId);
-        wrapper.lt(ProductionOperationTask::getPlanEndTime, today).ne(ProductionOperationTask::getStatus, 2);
-        return productionOperationTaskMapper.selectCount(wrapper);
-    }
-
-    private Map<Long, Long> pendingRepairCountByDevice(LoginUser loginUser) {
-        LambdaQueryWrapper<DeviceRepair> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), DeviceRepair::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), DeviceRepair::getDeptId);
-        wrapper.eq(DeviceRepair::getStatus, DEVICE_REPAIR_STATUS_PENDING);
-        return defaultList(deviceRepairMapper.selectList(wrapper)).stream()
-                .filter(item -> item.getDeviceLedgerId() != null)
-                .collect(Collectors.groupingBy(DeviceRepair::getDeviceLedgerId, Collectors.counting()));
-    }
-
-    private Map<String, Object> toPlanItem(ProductionPlan item) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("id", item.getId());
-        map.put("mpsNo", safe(item.getMpsNo()));
-        map.put("requiredDate", formatDate(item.getRequiredDate()));
-        map.put("promisedDeliveryDate", formatDate(item.getPromisedDeliveryDate()));
-        map.put("qtyRequired", item.getQtyRequired());
-        map.put("quantityIssued", item.getQuantityIssued());
-        map.put("status", item.getStatus());
-        map.put("source", safe(item.getSource()));
-        map.put("remark", safe(item.getRemark()));
-        return map;
-    }
-
-    private Map<String, Object> toWorkOrderItem(ProductionOperationTask item) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("id", item.getId());
-        map.put("workOrderNo", safe(item.getWorkOrderNo()));
-        map.put("productionOrderId", item.getProductionOrderId());
-        map.put("planStartTime", formatDate(item.getPlanStartTime()));
-        map.put("planEndTime", formatDate(item.getPlanEndTime()));
-        map.put("actualStartTime", formatDate(item.getActualStartTime()));
-        map.put("actualEndTime", formatDate(item.getActualEndTime()));
-        map.put("planQuantity", item.getPlanQuantity());
-        map.put("completeQuantity", item.getCompleteQuantity());
-        map.put("status", item.getStatus());
-        map.put("userIds", safe(item.getUserIds()));
-        return map;
-    }
-
-    private Map<String, Object> toDeviceItem(DeviceLedger item, long pendingRepairCount) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("id", item.getId());
-        map.put("deviceName", safe(item.getDeviceName()));
-        map.put("deviceModel", safe(item.getDeviceModel()));
-        map.put("deviceBrand", safe(item.getDeviceBrand()));
-        map.put("status", safe(item.getStatus()));
-        map.put("storageLocation", safe(item.getStorageLocation()));
-        map.put("supplierName", safe(item.getSupplierName()));
-        map.put("pendingRepairCount", pendingRepairCount);
-        return map;
-    }
-
-    private Map<String, Object> toDeviceRepairItem(DeviceRepair item) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("id", item.getId());
-        map.put("deviceLedgerId", item.getDeviceLedgerId());
-        map.put("deviceName", safe(item.getDeviceName()));
-        map.put("deviceModel", safe(item.getDeviceModel()));
-        map.put("repairTime", formatDate(item.getRepairTime()));
-        map.put("repairName", safe(item.getRepairName()));
-        map.put("maintenanceName", safe(item.getMaintenanceName()));
-        map.put("maintenanceTime", formatDateTime(item.getMaintenanceTime()));
-        map.put("maintenanceResult", safe(item.getMaintenanceResult()));
-        map.put("acceptanceName", safe(item.getAcceptanceName()));
-        map.put("acceptanceTime", formatDateTime(item.getAcceptanceTime()));
-        map.put("status", item.getStatus());
-        map.put("remark", safe(item.getRemark()));
-        map.put("createTime", formatDateTime(item.getCreateTime()));
-        return map;
-    }
-
-    private Map<String, Object> toQualityItem(QualityUnqualified item) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("id", item.getId());
-        map.put("checkTime", formatDate(item.getCheckTime()));
-        map.put("inspectState", item.getInspectState());
-        map.put("productId", item.getProductId());
-        map.put("productName", safe(item.getProductName()));
-        map.put("model", safe(item.getModel()));
-        map.put("quantity", item.getQuantity());
-        map.put("defectivePhenomena", safe(item.getDefectivePhenomena()));
-        map.put("dealResult", safe(item.getDealResult()));
-        map.put("dealName", safe(item.getDealName()));
-        map.put("dealTime", formatDate(item.getDealTime()));
-        return map;
-    }
-
-    private Map<String, Object> toMaterialItem(StockInventory item) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("id", item.getId());
-        map.put("productModelId", item.getProductModelId());
-        map.put("batchNo", safe(item.getBatchNo()));
-        map.put("qualitity", item.getQualitity());
-        map.put("lockedQuantity", item.getLockedQuantity());
-        map.put("warnNum", item.getWarnNum());
-        map.put("lowStock", isLowStock(item));
-        map.put("remark", safe(item.getRemark()));
-        return map;
-    }
-
-    private Map<String, Object> toExceptionItem(ProcurementExceptionRecord item) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("id", item.getId());
-        map.put("purchaseLedgerId", item.getPurchaseLedgerId());
-        map.put("exceptionReason", safe(item.getExceptionReason()));
-        map.put("exceptionNum", item.getExceptionNum());
-        map.put("createTime", formatDateTime(item.getCreateTime()));
-        return map;
-    }
-
-    private boolean isLowStock(StockInventory item) {
-        BigDecimal quantity = item.getQualitity();
-        BigDecimal warnNum = item.getWarnNum();
-        if (quantity == null || warnNum == null) {
-            return false;
-        }
-        return quantity.compareTo(warnNum) <= 0;
-    }
-
-    private Map<String, Object> warningItem(String level, String title, long count, String detail) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("level", level);
-        map.put("title", title);
-        map.put("count", count);
-        map.put("detail", detail);
-        return map;
-    }
-
-    private Map<String, Object> actionCard(String code,
-                                           String name,
-                                           String method,
-                                           String targetApi,
-                                           List<String> requiredFields,
-                                           Map<String, Object> examplePayload,
-                                           String description) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("code", code);
-        map.put("name", name);
-        map.put("method", method);
-        map.put("targetApi", targetApi);
-        map.put("requiredFields", requiredFields);
-        map.put("examplePayload", examplePayload);
-        map.put("description", description);
-        return map;
-    }
-
-    private Map<String, Object> metric(String label, String value) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("label", label);
-        map.put("value", value);
-        return map;
-    }
-
-    private Map<String, Object> rangeSummary(DateRange range, int count, String keyword) {
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", range.start().toString());
-        summary.put("endDate", range.end().toString());
-        summary.put("count", count);
-        summary.put("keyword", safe(keyword));
-        return summary;
-    }
-
-    private Map<String, Object> buildDomainBarOption(Map<String, Object> summary) {
-        List<String> xData = List.of("璁″垝", "宸ュ崟", "璁惧", "璐ㄩ噺", "鐗╂枡", "寮傚父");
-        List<Number> yData = List.of(
-                numberValue(summary.get("planTotal")),
-                numberValue(summary.get("workOrderTotal")),
-                numberValue(summary.get("deviceTotal")),
-                numberValue(summary.get("qualityNgCount")),
-                numberValue(summary.get("lowStockCount")),
-                numberValue(summary.get("exceptionCount"))
-        );
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "鍒堕�犲煙鍏抽敭鏁伴噺", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", xData));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of("name", "鏁伴噺", "type", "bar", "data", yData)));
-        return option;
-    }
-
-    private Map<String, Object> buildQualityPieOption(long inspectTotal, long ngCount) {
-        long passCount = Math.max(inspectTotal - ngCount, 0);
-        List<Map<String, Object>> data = List.of(
-                Map.of("name", "涓嶅悎鏍�", "value", ngCount),
-                Map.of("name", "闈炰笉鍚堟牸", "value", passCount)
-        );
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "璐ㄩ噺缁撴灉鍒嗗竷", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "item"));
-        option.put("series", List.of(Map.of("name", "璐ㄩ噺", "type", "pie", "radius", "60%", "data", data)));
-        return option;
-    }
-
-    private int numberValue(Object value) {
-        if (value instanceof Number number) {
-            return number.intValue();
-        }
-        return 0;
-    }
-
-    private String toRate(long numerator, long denominator) {
-        if (denominator <= 0) {
-            return "0.00%";
-        }
-        BigDecimal rate = new BigDecimal(numerator)
-                .multiply(new BigDecimal("100"))
-                .divide(new BigDecimal(denominator), 2, RoundingMode.HALF_UP);
-        return rate.toPlainString() + "%";
-    }
-
-    private String normalizeDomain(String domain) {
-        if (!StringUtils.hasText(domain)) {
-            return "";
-        }
-        String value = domain.trim().toLowerCase();
-        return switch (value) {
-            case "鐢熶骇鐜板満", "site", "factory", "workshop" -> "site";
-            case "璁″垝", "plan", "schedule" -> "plan";
-            case "宸ュ崟", "workorder", "work_order", "task" -> "workorder";
-            case "璁惧", "device", "equipment" -> "device";
-            case "缁翠慨", "repair", "maintenance" -> "repair";
-            case "璐ㄩ噺", "quality", "qc" -> "quality";
-            case "鐗╂枡", "material", "inventory", "stock" -> "material";
-            case "寮傚父", "exception", "abnormal" -> "exception";
-            default -> value;
-        };
-    }
-
-    private boolean isRepairIntent(String keyword, String userQuery) {
-        String query = safe(userQuery);
-        return containsAny(safe(keyword), "缁翠慨", "鎶ヤ慨", "妫�淇�", "缁存姢")
-                || containsAny(query, "缁翠慨", "鎶ヤ慨", "妫�淇�", "缁存姢");
-    }
-
-    private String normalizeDeviceQueryKeyword(String keyword, String userQuery) {
-        String source = StringUtils.hasText(keyword) ? keyword : userQuery;
-        if (!StringUtils.hasText(source)) {
-            return null;
-        }
-        String cleaned = source
-                .replace("鏌ヨ", "")
-                .replace("鏌ョ湅", "")
-                .replace("甯垜", "")
-                .replace("璇�", "")
-                .replace("鏌�", "")
-                .replace("璁惧", "")
-                .replace("缁翠慨璁板綍", "")
-                .replace("缁翠慨鎯呭喌", "")
-                .replace("鎶ヤ慨璁板綍", "")
-                .replace("鎶ヤ慨鎯呭喌", "")
-                .replace("缁翠慨", "")
-                .replace("鎶ヤ慨", "")
-                .replace("鎯呭喌", "")
-                .replace("璁板綍", "")
-                .replace("淇℃伅", "")
-                .replace("鐨�", "")
-                .replace("涓�涓�", "")
-                .trim();
-        return cleaned.length() >= 2 ? cleaned : null;
-    }
-
-    private List<Long> findDeviceLedgerIdsByKeyword(LoginUser loginUser, String keyword) {
-        if (!StringUtils.hasText(keyword)) {
-            return List.of();
-        }
-        LambdaQueryWrapper<DeviceLedger> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), DeviceLedger::getTenantId);
-        Long currentDeptId = loginUser.getCurrentDeptId();
-        if (currentDeptId != null) {
-            wrapper.and(w -> w.eq(DeviceLedger::getDeptId, currentDeptId).or().isNull(DeviceLedger::getDeptId));
-        }
-        wrapper.and(w -> w.like(DeviceLedger::getDeviceName, keyword)
-                .or().like(DeviceLedger::getDeviceModel, keyword)
-                .or().like(DeviceLedger::getDeviceBrand, keyword));
-        wrapper.orderByDesc(DeviceLedger::getId).last("limit 200");
-        return defaultList(deviceLedgerMapper.selectList(wrapper)).stream()
-                .map(DeviceLedger::getId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toList());
-    }
-
-    private boolean hasTimeConstraint(String startDate, String endDate, String userQuery) {
-        if (StringUtils.hasText(startDate) || StringUtils.hasText(endDate)) {
-            return true;
-        }
-        if (!StringUtils.hasText(userQuery)) {
-            return false;
-        }
-        String text = userQuery.trim();
-        return containsAny(text, "浠婂ぉ", "鏄ㄥぉ", "鏈懆", "涓婂懆", "鏈湀", "涓婃湀", "浠婂勾", "鍘诲勾", "杩�", "鏈�杩�");
-    }
-
-    private DateRange resolveDateRange(String startDate, String endDate, String timeRange) {
-        LocalDate today = LocalDate.now();
-        LocalDate start = parseLocalDate(startDate);
-        LocalDate end = parseLocalDate(endDate);
-        if (start != null || end != null) {
-            LocalDate s = start != null ? start : end;
-            LocalDate e = end != null ? end : start;
-            if (s.isAfter(e)) {
-                LocalDate temp = s;
-                s = e;
-                e = temp;
-            }
-            return new DateRange(s, e, s + "鑷�" + e);
-        }
-        if (!StringUtils.hasText(timeRange)) {
-            return new DateRange(today.minusDays(29), today, "杩�30澶�");
-        }
-        String text = timeRange.trim();
-        if (text.contains("浠婂ぉ")) {
-            return new DateRange(today, today, "浠婂ぉ");
-        }
-        if (text.contains("鏈懆")) {
-            LocalDate startOfWeek = today.minusDays(today.getDayOfWeek().getValue() - 1L);
-            return new DateRange(startOfWeek, today, "鏈懆");
-        }
-        if (text.contains("鏈湀")) {
-            return new DateRange(today.withDayOfMonth(1), today, "鏈湀");
-        }
-        if (text.contains("鏈勾") || text.contains("浠婂勾")) {
-            return new DateRange(today.withDayOfYear(1), today, "浠婂勾");
-        }
-        if (text.contains("鍘诲勾")) {
-            LocalDate firstDay = today.minusYears(1).withDayOfYear(1);
-            LocalDate lastDay = today.minusYears(1).withMonth(12).withDayOfMonth(31);
-            return new DateRange(firstDay, lastDay, "鍘诲勾");
-        }
-        if (text.contains("涓婃湀")) {
-            LocalDate startOfLastMonth = today.minusMonths(1).withDayOfMonth(1);
-            return new DateRange(startOfLastMonth, startOfLastMonth.withDayOfMonth(startOfLastMonth.lengthOfMonth()), "涓婃湀");
-        }
-        java.util.regex.Matcher matcher = java.util.regex.Pattern.compile("(杩憒鏈�杩�)(\\d+)(澶﹟鍛▅涓湀|鏈坾骞�)").matcher(text);
-        if (matcher.find()) {
-            int amount = Integer.parseInt(matcher.group(2));
-            String unit = matcher.group(3);
-            LocalDate relativeStart = switch (unit) {
-                case "澶�" -> today.minusDays(Math.max(amount - 1L, 0));
-                case "鍛�" -> today.minusWeeks(Math.max(amount, 1)).plusDays(1);
-                case "涓湀", "鏈�" -> today.minusMonths(Math.max(amount, 1)).plusDays(1);
-                case "骞�" -> today.minusYears(Math.max(amount, 1)).plusDays(1);
-                default -> today.minusDays(29);
-            };
-            return new DateRange(relativeStart, today, "杩�" + amount + unit);
-        }
-        return new DateRange(today.minusDays(29), today, "杩�30澶�");
-    }
-
-    private LocalDate parseLocalDate(String text) {
-        if (!StringUtils.hasText(text)) {
-            return null;
-        }
-        return LocalDate.parse(text.trim(), DATE_FMT);
-    }
-
-    private Date toDate(LocalDate date) {
-        return Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
-    }
-
-    private Date toExclusiveEndDate(LocalDate date) {
-        return Date.from(date.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
-    }
-
-    private String formatDate(LocalDate date) {
-        return date == null ? "" : DATE_FMT.format(date);
-    }
-
-    private String formatDate(Date date) {
-        if (date == null) {
-            return "";
-        }
-        return DATE_FMT.format(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
-    }
-
-    private String formatDateTime(LocalDateTime time) {
-        if (time == null) {
-            return "";
-        }
-        return time.truncatedTo(ChronoUnit.SECONDS).toString().replace('T', ' ');
-    }
-
-    private int normalizeLimit(Integer limit) {
-        if (limit == null || limit <= 0) {
-            return DEFAULT_LIMIT;
-        }
-        return Math.min(limit, MAX_LIMIT);
-    }
-
-    private boolean containsAny(String text, String... values) {
-        for (String value : values) {
-            if (text.contains(value)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private <T> void applyTenantFilter(LambdaQueryWrapper<T> wrapper, Long tenantId, SFunction<T, Long> field) {
-        if (tenantId != null) {
-            wrapper.eq(field, tenantId);
-        }
-    }
-
-    private <T> void applyDeptFilter(LambdaQueryWrapper<T> wrapper, Long deptId, SFunction<T, Long> field) {
-        if (deptId != null) {
-            wrapper.eq(field, deptId);
-        }
-    }
-
-    private LoginUser currentLoginUser(String memoryId) {
-        LoginUser loginUser = aiSessionUserContext.get(memoryId);
-        if (loginUser != null) {
-            return loginUser;
-        }
-        return SecurityUtils.getLoginUser();
-    }
-
-    private String safe(Object value) {
-        return value == null ? "" : String.valueOf(value).replace('\n', ' ').replace('\r', ' ');
-    }
-
-    private <T> List<T> defaultList(List<T> list) {
-        return list == null ? List.of() : list;
-    }
-
-    private String jsonResponse(boolean success,
-                                String type,
-                                String description,
-                                Map<String, Object> summary,
-                                Map<String, Object> data,
-                                Map<String, Object> charts) {
-        Map<String, Object> result = new LinkedHashMap<>();
-        result.put("success", success);
-        result.put("type", type);
-        result.put("description", description);
-        result.put("summary", summary == null ? Map.of() : summary);
-        result.put("data", data == null ? Map.of() : data);
-        result.put("charts", charts == null ? Map.of() : charts);
-        return JSON.toJSONString(result);
-    }
-
-    private record DateRange(LocalDate start, LocalDate end, String label) {
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java b/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
deleted file mode 100644
index bdd1f1f..0000000
--- a/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
+++ /dev/null
@@ -1,846 +0,0 @@
-package com.ruoyi.ai.tools;
-
-import com.alibaba.fastjson2.JSON;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.ruoyi.account.mapper.purchase.AccountPaymentApplicationMapper;
-import com.ruoyi.account.mapper.purchase.AccountPurchaseInvoiceMapper;
-import com.ruoyi.account.mapper.purchase.AccountPurchasePaymentMapper;
-import com.ruoyi.account.pojo.purchase.AccountPaymentApplication;
-import com.ruoyi.account.pojo.purchase.AccountPurchaseInvoice;
-import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
-import com.ruoyi.ai.context.AiSessionUserContext;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.procurementrecord.mapper.InboundManagementMapper;
-import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
-import com.ruoyi.procurementrecord.pojo.InboundManagement;
-import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
-import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
-import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper;
-import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.purchase.pojo.PurchaseReturnOrders;
-import com.ruoyi.quality.mapper.QualityInspectMapper;
-import com.ruoyi.quality.pojo.QualityInspect;
-import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import com.ruoyi.stock.mapper.StockInRecordMapper;
-import com.ruoyi.stock.pojo.StockInRecord;
-import dev.langchain4j.agent.tool.P;
-import dev.langchain4j.agent.tool.Tool;
-import dev.langchain4j.agent.tool.ToolMemoryId;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.*;
-import java.util.stream.Collectors;
-
-@Component
-public class PurchaseAgentTools {
-
-    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final ZoneId CHINA_ZONE_ID = ZoneId.of("Asia/Shanghai");
-    private static final int DEFAULT_LIMIT = 10;
-    private static final int MAX_LIMIT = 30;
-
-    private final PurchaseLedgerMapper purchaseLedgerMapper;
-    private final PurchaseReturnOrdersMapper purchaseReturnOrdersMapper;
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-    private final ProcurementRecordMapper procurementRecordMapper;
-    private final InboundManagementMapper inboundManagementMapper;
-    private final AccountPurchasePaymentMapper accountPurchasePaymentMapper;
-    private final AccountPaymentApplicationMapper accountPaymentApplicationMapper;
-    private final AccountPurchaseInvoiceMapper accountPurchaseInvoiceMapper;
-    private final StockInRecordMapper stockInRecordMapper;
-    private final QualityInspectMapper qualityInspectMapper;
-    private final AiSessionUserContext aiSessionUserContext;
-
-    public PurchaseAgentTools(PurchaseLedgerMapper purchaseLedgerMapper,
-                              PurchaseReturnOrdersMapper purchaseReturnOrdersMapper,
-                              SalesLedgerProductMapper salesLedgerProductMapper,
-                              ProcurementRecordMapper procurementRecordMapper,
-                              InboundManagementMapper inboundManagementMapper,
-                              AccountPurchasePaymentMapper accountPurchasePaymentMapper,
-                              AccountPaymentApplicationMapper accountPaymentApplicationMapper,
-                              AccountPurchaseInvoiceMapper accountPurchaseInvoiceMapper,
-                              StockInRecordMapper stockInRecordMapper,
-                              QualityInspectMapper qualityInspectMapper,
-                              AiSessionUserContext aiSessionUserContext) {
-        this.purchaseLedgerMapper = purchaseLedgerMapper;
-        this.purchaseReturnOrdersMapper = purchaseReturnOrdersMapper;
-        this.salesLedgerProductMapper = salesLedgerProductMapper;
-        this.procurementRecordMapper = procurementRecordMapper;
-        this.inboundManagementMapper = inboundManagementMapper;
-        this.accountPurchasePaymentMapper = accountPurchasePaymentMapper;
-        this.accountPaymentApplicationMapper = accountPaymentApplicationMapper;
-        this.accountPurchaseInvoiceMapper = accountPurchaseInvoiceMapper;
-        this.stockInRecordMapper = stockInRecordMapper;
-        this.qualityInspectMapper = qualityInspectMapper;
-        this.aiSessionUserContext = aiSessionUserContext;
-    }
-
-    @Tool(name = "鏌ヨ閲囪喘鍙拌处鍒楄〃", value = "鎸夊叧閿瓧鍜屾椂闂磋寖鍥存煡璇㈤噰璐彴璐︼紝鏀寔杩斿洖鏈�杩慛鏉�")
-    public String listPurchaseLedgers(@ToolMemoryId String memoryId,
-                                      @P(value = "鍏抽敭瀛楋紝鍙尮閰嶉噰璐悎鍚屽彿/渚涘簲鍟�/椤圭洰鍚�", required = false) String keyword,
-                                      @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                      @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                      @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        LocalDate start = parseLocalDate(startDate);
-        LocalDate end = parseLocalDate(endDate);
-        int finalLimit = normalizeLimit(limit);
-
-        LambdaQueryWrapper<PurchaseLedger> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), PurchaseLedger::getTenantId);
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(PurchaseLedger::getPurchaseContractNumber, keyword)
-                    .or().like(PurchaseLedger::getSupplierName, keyword)
-                    .or().like(PurchaseLedger::getProjectName, keyword));
-        }
-        if (start != null) {
-            wrapper.ge(PurchaseLedger::getEntryDate, toDate(start));
-        }
-        if (end != null) {
-            wrapper.lt(PurchaseLedger::getEntryDate, toExclusiveEndDate(end));
-        }
-        wrapper.orderByDesc(PurchaseLedger::getEntryDate, PurchaseLedger::getId).last("limit " + finalLimit);
-
-        List<PurchaseLedger> rows = defaultList(purchaseLedgerMapper.selectList(wrapper));
-        List<Map<String, Object>> items = rows.stream().map(this::toLedgerItem).collect(Collectors.toList());
-        return jsonResponse(true, "purchase_ledger_list", "宸茶繑鍥為噰璐彴璐﹀垪琛�",
-                Map.of("count", items.size(), "limit", finalLimit, "keyword", safe(keyword)),
-                Map.of("items", items), Map.of());
-    }
-
-    @Tool(name = "鏌ヨ閲囪喘鍙拌处璇︽儏", value = "鎸夐噰璐彴璐D鏌ヨ璇︽儏")
-    public String getPurchaseLedgerDetail(@ToolMemoryId String memoryId, @P("閲囪喘鍙拌处ID") Long ledgerId) {
-        if (ledgerId == null) {
-            return jsonResponse(false, "purchase_ledger_detail", "閲囪喘鍙拌处ID涓嶈兘涓虹┖", Map.of(), Map.of(), Map.of());
-        }
-        LoginUser loginUser = currentLoginUser(memoryId);
-        PurchaseLedger ledger = purchaseLedgerMapper.selectById(ledgerId);
-        if (ledger == null || !tenantMatched(ledger.getTenantId(), loginUser.getTenantId())) {
-            return jsonResponse(false, "purchase_ledger_detail", "鏈壘鍒拌閲囪喘鍙拌处鎴栨棤鏉冮檺璁块棶", Map.of("ledgerId", ledgerId), Map.of(), Map.of());
-        }
-        return jsonResponse(true, "purchase_ledger_detail", "宸茶繑鍥為噰璐彴璐﹁鎯�",
-                Map.of("ledgerId", ledgerId),
-                Map.of("detail", toLedgerItem(ledger)),
-                Map.of());
-    }
-
-    @Tool(name = "缁熻閲囪喘鏁版嵁", value = "缁熻鏃堕棿鑼冨洿鍐呴噰璐悎鍚屾暟銆佸悎鍚岄噾棰濄�佷粯娆鹃噾棰濄�佸彂绁ㄩ噾棰濄�侀��璐ч噾棰�")
-    public String getPurchaseStats(@ToolMemoryId String memoryId,
-                                   @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                   @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                   @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屼緥濡備粖骞淬�佹湰鏈堛�佽繎30澶�", required = false) String timeRange) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, timeRange);
-
-        List<PurchaseLedger> ledgers = queryLedgers(loginUser, range);
-        List<AccountPurchasePayment> payments = queryPayments(loginUser, range);
-        List<AccountPurchaseInvoice> invoices = queryInvoices(loginUser, range);
-        List<PurchaseReturnOrders> returns = queryReturns(loginUser, range);
-
-        BigDecimal contractAmount = ledgers.stream()
-                .map(PurchaseLedger::getContractAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal paymentAmount = payments.stream()
-                .map(AccountPurchasePayment::getPaymentAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal invoiceAmount = invoices.stream()
-                .map(this::invoiceAmountOf)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal returnAmount = returns.stream()
-                .map(PurchaseReturnOrders::getTotalAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", range.start().toString());
-        summary.put("endDate", range.end().toString());
-        summary.put("ledgerCount", ledgers.size());
-        summary.put("paymentCount", payments.size());
-        summary.put("invoiceCount", invoices.size());
-        summary.put("returnCount", returns.size());
-        summary.put("contractAmount", contractAmount);
-        summary.put("paymentAmount", paymentAmount);
-        summary.put("invoiceAmount", invoiceAmount);
-        summary.put("returnAmount", returnAmount);
-
-        return jsonResponse(true, "purchase_stats", "宸茶繑鍥為噰璐粺璁℃暟鎹�", summary, Map.of(), Map.of());
-    }
-
-    @Tool(name = "閲囪喘鐗╂枡閲戦鎺掕", value = "鎸夋椂闂磋寖鍥寸粺璁¢噰璐墿鏂欓噾棰濇帓琛岋紝鍙洖绛旀湰鏈堥噰璐噾棰濇帓鍚嶉潬鍓嶇殑鐗╂枡銆�")
-    public String rankPurchaseMaterials(@ToolMemoryId String memoryId,
-                                        @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                        @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                        @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屼緥濡傛湰鏈堛�佽繎7澶┿�佽繎30澶�", required = false) String timeRange,
-                                        @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, timeRange);
-        List<Long> ledgerIds = queryLedgers(loginUser, range).stream()
-                .map(PurchaseLedger::getId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toList());
-        if (ledgerIds.isEmpty()) {
-            return jsonResponse(true, "purchase_material_rank", "褰撳墠鏃堕棿鑼冨洿鍐呮病鏈夐噰璐墿鏂欐暟鎹��",
-                    rangeSummary(range, 0), Map.of("items", List.of()), Map.of());
-        }
-
-        List<SalesLedgerProduct> products = defaultList(salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
-                .eq(SalesLedgerProduct::getType, 2)
-                .in(SalesLedgerProduct::getSalesLedgerId, ledgerIds)));
-
-        Map<String, MaterialRankItem> grouped = new LinkedHashMap<>();
-        for (SalesLedgerProduct product : products) {
-            String name = safe(product.getProductCategory());
-            String model = safe(product.getSpecificationModel());
-            String key = name + "|" + model;
-            MaterialRankItem item = grouped.computeIfAbsent(key, ignored -> new MaterialRankItem(name, model, safe(product.getUnit())));
-            item.quantity = item.quantity.add(defaultDecimal(product.getQuantity()));
-            item.amount = item.amount.add(defaultDecimal(product.getTaxInclusiveTotalPrice()));
-        }
-
-        List<Map<String, Object>> items = grouped.values().stream()
-                .sorted(Comparator.comparing((MaterialRankItem item) -> item.amount).reversed())
-                .limit(normalizeLimit(limit))
-                .map(MaterialRankItem::toMap)
-                .collect(Collectors.toList());
-
-        return jsonResponse(true, "purchase_material_rank", "宸茶繑鍥為噰璐墿鏂欓噾棰濇帓琛屻��",
-                rangeSummary(range, items.size()), Map.of("items", items), Map.of());
-    }
-
-    @Tool(name = "鏌ヨ鏈叆搴撻噰璐鍗�", value = "鏌ヨ閲囪喘璁㈠崟涓嬩粛鏈夊緟鍏ュ簱鏁伴噺鐨勭墿鏂欐槑缁嗐��")
-    public String listUnstockedPurchaseOrders(@ToolMemoryId String memoryId,
-                                              @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                              @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                              @P(value = "鍏抽敭瀛楋紝鍙尮閰嶉噰璐悎鍚屽彿/渚涘簲鍟�/鐗╂枡", required = false) String keyword,
-                                              @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, null);
-        List<PurchaseLedger> ledgers = queryLedgers(loginUser, range).stream()
-                .filter(ledger -> matchLedgerKeyword(ledger, keyword))
-                .collect(Collectors.toList());
-        Map<Long, PurchaseLedger> ledgerMap = ledgers.stream()
-                .filter(ledger -> ledger.getId() != null)
-                .collect(Collectors.toMap(PurchaseLedger::getId, ledger -> ledger, (a, b) -> a, LinkedHashMap::new));
-        if (ledgerMap.isEmpty()) {
-            return jsonResponse(true, "purchase_unstocked_list", "鏈煡璇㈠埌绗﹀悎鏉′欢鐨勯噰璐鍗曘��",
-                    rangeSummary(range, 0), Map.of("items", List.of()), Map.of());
-        }
-
-        List<SalesLedgerProduct> products = defaultList(salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
-                .eq(SalesLedgerProduct::getType, 2)
-                .in(SalesLedgerProduct::getSalesLedgerId, ledgerMap.keySet())));
-
-        List<Map<String, Object>> items = products.stream()
-                .filter(product -> matchProductKeyword(product, keyword))
-                .map(product -> toUnstockedItem(product, ledgerMap.get(product.getSalesLedgerId())))
-                .filter(Objects::nonNull)
-                .limit(normalizeLimit(limit))
-                .collect(Collectors.toList());
-
-        return jsonResponse(true, "purchase_unstocked_list", "宸茶繑鍥炴湭鍏ュ簱閲囪喘璁㈠崟銆�",
-                rangeSummary(range, items.size()), Map.of("items", items), Map.of());
-    }
-
-    @Tool(name = "鏌ヨ閲囪喘鍒拌揣寮傚父", value = "鏌ヨ鍒拌揣鐘舵�佸紓甯告垨澶囨敞鍖呭惈寮傚父淇℃伅鐨勫埌璐ц褰曘��")
-    public String listArrivalExceptions(@ToolMemoryId String memoryId,
-                                        @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                        @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                        @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屼緥濡傝繎7澶┿�佹湰鏈�", required = false) String timeRange,
-                                        @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, timeRange);
-        LambdaQueryWrapper<InboundManagement> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), InboundManagement::getTenantId);
-        wrapper.ge(InboundManagement::getArrivalTime, toDate(range.start()))
-                .lt(InboundManagement::getArrivalTime, toExclusiveEndDate(range.end()))
-                .and(w -> w.notLike(InboundManagement::getStatus, "姝e父")
-                        .notLike(InboundManagement::getStatus, "瀹屾垚")
-                        .notLike(InboundManagement::getStatus, "宸插埌璐�")
-                        .or().like(InboundManagement::getStatus, "寮傚父")
-                        .or().like(InboundManagement::getRemark, "寮傚父")
-                        .or().like(InboundManagement::getRemark, "闂")
-                        .or().like(InboundManagement::getRemark, "寤惰繜")
-                        .or().like(InboundManagement::getRemark, "鐭己"));
-        wrapper.orderByDesc(InboundManagement::getArrivalTime).last("limit " + normalizeLimit(limit));
-
-        List<Map<String, Object>> items = defaultList(inboundManagementMapper.selectList(wrapper)).stream()
-                .map(this::toArrivalItem)
-                .collect(Collectors.toList());
-        return jsonResponse(true, "purchase_arrival_exception_list", "宸茶繑鍥為噰璐埌璐у紓甯歌褰曘��",
-                rangeSummary(range, items.size()), Map.of("items", items), Map.of());
-    }
-
-    @Tool(name = "鏌ヨ寰呬粯娆鹃噰璐崟", value = "鏌ヨ鍚堝悓閲戦澶т簬宸蹭粯娆鹃噾棰濈殑閲囪喘鍗曘��")
-    public String listPendingPaymentOrders(@ToolMemoryId String memoryId,
-                                           @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                           @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                           @P(value = "鍏抽敭瀛楋紝鍙尮閰嶉噰璐悎鍚屽彿/渚涘簲鍟�/椤圭洰鍚�", required = false) String keyword,
-                                           @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, null);
-        List<PurchaseLedger> matchedLedgers = queryLedgers(loginUser, range).stream()
-                .filter(ledger -> matchLedgerKeyword(ledger, keyword))
-                .collect(Collectors.toList());
-        Map<Long, BigDecimal> paidAmountByLedgerId = sumPaymentAmountByLedgerId(loginUser, matchedLedgers.stream()
-                .map(PurchaseLedger::getId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toList()));
-        List<Map<String, Object>> items = matchedLedgers.stream()
-                .map(ledger -> toPendingPaymentItem(ledger, paidAmountByLedgerId.getOrDefault(ledger.getId(), BigDecimal.ZERO)))
-                .filter(Objects::nonNull)
-                .sorted(Comparator.comparing(item -> (BigDecimal) item.get("pendingAmount"), Comparator.reverseOrder()))
-                .limit(normalizeLimit(limit))
-                .collect(Collectors.toList());
-
-        BigDecimal totalContractAmount = items.stream()
-                .map(item -> asBigDecimal(item.get("contractAmount")))
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal totalPaidAmount = items.stream()
-                .map(item -> asBigDecimal(item.get("paidAmount")))
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal totalPendingAmount = items.stream()
-                .map(item -> asBigDecimal(item.get("pendingAmount")))
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        Map<String, Object> summary = rangeSummary(range, items.size());
-        summary.put("pendingOrderCount", items.size());
-        summary.put("totalContractAmount", totalContractAmount);
-        summary.put("totalPaidAmount", totalPaidAmount);
-        summary.put("totalPendingAmount", totalPendingAmount);
-
-        return jsonResponse(true, "purchase_pending_payment_list", "宸茶繑鍥炲緟浠樻閲囪喘鍗曘��",
-                summary, Map.of("items", items), Map.of());
-    }
-
-    @Tool(name = "鏌ヨ閲囪喘閫�璐ф儏鍐�", value = "鎸夋椂闂磋寖鍥存煡璇㈤噰璐��璐у崟鍒楄〃鍜岄��璐ч噾棰濄��")
-    public String listPurchaseReturns(@ToolMemoryId String memoryId,
-                                      @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                      @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                      @P(value = "鍏抽敭瀛楋紝鍙尮閰嶉��璐у崟鍙�/澶囨敞", required = false) String keyword,
-                                      @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, null);
-        LambdaQueryWrapper<PurchaseReturnOrders> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), PurchaseReturnOrders::getDeptId);
-        wrapper.ge(PurchaseReturnOrders::getPreparedAt, range.start())
-                .le(PurchaseReturnOrders::getPreparedAt, range.end());
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(PurchaseReturnOrders::getNo, keyword)
-                    .or().like(PurchaseReturnOrders::getRemark, keyword)
-                    .or().like(PurchaseReturnOrders::getReturnUserName, keyword));
-        }
-        wrapper.orderByDesc(PurchaseReturnOrders::getPreparedAt).last("limit " + normalizeLimit(limit));
-
-        List<PurchaseReturnOrders> returns = defaultList(purchaseReturnOrdersMapper.selectList(wrapper));
-        BigDecimal totalAmount = returns.stream()
-                .map(PurchaseReturnOrders::getTotalAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        Map<String, Object> summary = rangeSummary(range, returns.size());
-        summary.put("returnAmount", totalAmount);
-
-        return jsonResponse(true, "purchase_return_list", "宸茶繑鍥為噰璐��璐ф儏鍐点��",
-                summary,
-                Map.of("items", returns.stream().map(this::toReturnItem).collect(Collectors.toList())),
-                Map.of());
-    }
-
-    private List<PurchaseLedger> queryLedgers(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<PurchaseLedger> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), PurchaseLedger::getTenantId);
-        wrapper.ge(PurchaseLedger::getEntryDate, toDate(range.start()))
-                .lt(PurchaseLedger::getEntryDate, toExclusiveEndDate(range.end()));
-        return defaultList(purchaseLedgerMapper.selectList(wrapper));
-    }
-
-    private Map<String, Object> rangeSummary(DateRange range, int count) {
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", range.start().toString());
-        summary.put("endDate", range.end().toString());
-        summary.put("count", count);
-        return summary;
-    }
-
-    private boolean matchLedgerKeyword(PurchaseLedger ledger, String keyword) {
-        if (!StringUtils.hasText(keyword)) {
-            return true;
-        }
-        String text = keyword.trim();
-        return safe(ledger.getPurchaseContractNumber()).contains(text)
-                || safe(ledger.getSupplierName()).contains(text)
-                || safe(ledger.getProjectName()).contains(text);
-    }
-
-    private boolean matchProductKeyword(SalesLedgerProduct product, String keyword) {
-        if (!StringUtils.hasText(keyword)) {
-            return true;
-        }
-        String text = keyword.trim();
-        return safe(product.getProductCategory()).contains(text)
-                || safe(product.getSpecificationModel()).contains(text);
-    }
-
-    private Map<String, Object> toUnstockedItem(SalesLedgerProduct product, PurchaseLedger ledger) {
-        if (product == null || ledger == null || product.getId() == null) {
-            return null;
-        }
-        BigDecimal orderedQuantity = defaultDecimal(product.getQuantity());
-        BigDecimal inboundQuantity = sumInboundQuantity(product.getId());
-        BigDecimal pendingQuantity = orderedQuantity.subtract(inboundQuantity);
-        if (pendingQuantity.compareTo(BigDecimal.ZERO) <= 0) {
-            return null;
-        }
-        Map<String, Object> item = new LinkedHashMap<>();
-        item.put("purchaseLedgerId", ledger.getId());
-        item.put("purchaseContractNumber", safe(ledger.getPurchaseContractNumber()));
-        item.put("supplierName", safe(ledger.getSupplierName()));
-        item.put("productCategory", safe(product.getProductCategory()));
-        item.put("specificationModel", safe(product.getSpecificationModel()));
-        item.put("unit", safe(product.getUnit()));
-        item.put("orderedQuantity", orderedQuantity);
-        item.put("inboundQuantity", inboundQuantity);
-        item.put("pendingInboundQuantity", pendingQuantity);
-        item.put("entryDate", formatDate(ledger.getEntryDate()));
-        return item;
-    }
-
-    private BigDecimal sumInboundQuantity(Long salesLedgerProductId) {
-        List<ProcurementRecordStorage> records = defaultList(procurementRecordMapper.selectList(new LambdaQueryWrapper<ProcurementRecordStorage>()
-                .eq(ProcurementRecordStorage::getType, 1)
-                .eq(ProcurementRecordStorage::getSalesLedgerProductId, salesLedgerProductId)));
-        return records.stream()
-                .map(ProcurementRecordStorage::getInboundNum)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-    }
-
-    private Map<String, Object> toArrivalItem(InboundManagement item) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("id", item.getId());
-        map.put("orderNo", safe(item.getOrderNo()));
-        map.put("arrivalNo", safe(item.getArrivalNo()));
-        map.put("supplierName", safe(item.getSupplierName()));
-        map.put("status", safe(item.getStatus()));
-        map.put("arrivalTime", formatDate(item.getArrivalTime()));
-        map.put("arrivalQuantity", safe(item.getArrivalQuantity()));
-        map.put("remark", safe(item.getRemark()));
-        return map;
-    }
-
-    private Map<String, Object> toPendingPaymentItem(PurchaseLedger ledger, BigDecimal paidAmount) {
-        BigDecimal contractAmount = defaultDecimal(ledger.getContractAmount());
-        BigDecimal safePaidAmount = defaultDecimal(paidAmount);
-        BigDecimal pendingAmount = contractAmount.subtract(safePaidAmount);
-        if (pendingAmount.compareTo(BigDecimal.ZERO) <= 0) {
-            return null;
-        }
-        Map<String, Object> item = toLedgerItem(ledger);
-        item.put("paidAmount", safePaidAmount);
-        item.put("pendingAmount", pendingAmount);
-        return item;
-    }
-
-    private Map<Long, BigDecimal> sumPaymentAmountByLedgerId(LoginUser loginUser, List<Long> purchaseLedgerIds) {
-        if (purchaseLedgerIds == null || purchaseLedgerIds.isEmpty()) {
-            return Map.of();
-        }
-        List<AccountPurchasePayment> payments = queryPayments(loginUser);
-        if (payments.isEmpty()) {
-            return Map.of();
-        }
-
-        Map<Integer, AccountPaymentApplication> applicationById = queryPaymentApplications(payments);
-        if (applicationById.isEmpty()) {
-            return Map.of();
-        }
-
-        Map<Long, StockInRecord> stockInRecordById = queryStockInRecords(applicationById.values());
-        Map<Long, Long> purchaseLedgerIdByQualityInspectId = queryPurchaseLedgerIdByQualityInspectId(stockInRecordById.values());
-        Set<Long> targetLedgerIdSet = new HashSet<>(purchaseLedgerIds);
-        Map<Long, BigDecimal> result = new HashMap<>();
-
-        for (AccountPurchasePayment payment : payments) {
-            if (payment.getAccountPaymentApplicationId() == null) {
-                continue;
-            }
-            AccountPaymentApplication application = applicationById.get(payment.getAccountPaymentApplicationId());
-            if (application == null) {
-                continue;
-            }
-            Set<Long> ledgerIds = resolvePurchaseLedgerIds(application, stockInRecordById, purchaseLedgerIdByQualityInspectId);
-            if (ledgerIds.isEmpty()) {
-                continue;
-            }
-            BigDecimal amount = defaultDecimal(payment.getPaymentAmount());
-            for (Long ledgerId : ledgerIds) {
-                if (targetLedgerIdSet.contains(ledgerId)) {
-                    result.merge(ledgerId, amount, BigDecimal::add);
-                }
-            }
-        }
-        return result;
-    }
-
-    private Map<String, Object> toReturnItem(PurchaseReturnOrders item) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("id", item.getId());
-        map.put("no", safe(item.getNo()));
-        map.put("returnType", item.getReturnType());
-        map.put("purchaseLedgerId", item.getPurchaseLedgerId());
-        map.put("preparedAt", item.getPreparedAt() == null ? "" : item.getPreparedAt().toString());
-        map.put("returnUserName", safe(item.getReturnUserName()));
-        map.put("totalAmount", item.getTotalAmount());
-        map.put("remark", safe(item.getRemark()));
-        return map;
-    }
-
-    private BigDecimal defaultDecimal(BigDecimal value) {
-        return value == null ? BigDecimal.ZERO : value;
-    }
-
-    private BigDecimal asBigDecimal(Object value) {
-        if (value == null) {
-            return BigDecimal.ZERO;
-        }
-        if (value instanceof BigDecimal decimal) {
-            return decimal;
-        }
-        if (value instanceof Number number) {
-            return new BigDecimal(String.valueOf(number));
-        }
-        try {
-            return new BigDecimal(String.valueOf(value));
-        } catch (Exception ignored) {
-            return BigDecimal.ZERO;
-        }
-    }
-
-    private BigDecimal invoiceAmountOf(AccountPurchaseInvoice invoice) {
-        if (invoice == null) {
-            return BigDecimal.ZERO;
-        }
-        BigDecimal amount = defaultDecimal(invoice.getTaxInclusivePrice());
-        if (amount.compareTo(BigDecimal.ZERO) > 0) {
-            return amount;
-        }
-        return defaultDecimal(invoice.getTaxExclusivelPrice()).add(defaultDecimal(invoice.getTaxPrice()));
-    }
-
-    private List<AccountPurchasePayment> queryPayments(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<AccountPurchasePayment> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), AccountPurchasePayment::getDeptId);
-        wrapper.ge(AccountPurchasePayment::getPaymentDate, range.start())
-                .le(AccountPurchasePayment::getPaymentDate, range.end())
-                .orderByDesc(AccountPurchasePayment::getPaymentDate, AccountPurchasePayment::getId);
-        return defaultList(accountPurchasePaymentMapper.selectList(wrapper));
-    }
-
-    private List<AccountPurchasePayment> queryPayments(LoginUser loginUser) {
-        LambdaQueryWrapper<AccountPurchasePayment> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), AccountPurchasePayment::getDeptId);
-        return defaultList(accountPurchasePaymentMapper.selectList(wrapper));
-    }
-
-    private List<AccountPurchaseInvoice> queryInvoices(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<AccountPurchaseInvoice> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), AccountPurchaseInvoice::getDeptId);
-        wrapper.ge(AccountPurchaseInvoice::getIssueDate, range.start())
-                .le(AccountPurchaseInvoice::getIssueDate, range.end())
-                .orderByDesc(AccountPurchaseInvoice::getIssueDate, AccountPurchaseInvoice::getId);
-        return defaultList(accountPurchaseInvoiceMapper.selectList(wrapper));
-    }
-
-    private Map<Integer, AccountPaymentApplication> queryPaymentApplications(List<AccountPurchasePayment> payments) {
-        List<Integer> ids = payments.stream()
-                .map(AccountPurchasePayment::getAccountPaymentApplicationId)
-                .filter(Objects::nonNull)
-                .distinct()
-                .collect(Collectors.toList());
-        if (ids.isEmpty()) {
-            return Map.of();
-        }
-        return defaultList(accountPaymentApplicationMapper.selectBatchIds(ids)).stream()
-                .filter(item -> item.getId() != null)
-                .collect(Collectors.toMap(AccountPaymentApplication::getId, item -> item, (a, b) -> a));
-    }
-
-    private Map<Long, StockInRecord> queryStockInRecords(Collection<AccountPaymentApplication> applications) {
-        Set<Long> stockInRecordIds = new HashSet<>();
-        for (AccountPaymentApplication application : applications) {
-            stockInRecordIds.addAll(parseLongIds(application.getStockInRecordIds()));
-        }
-        if (stockInRecordIds.isEmpty()) {
-            return Map.of();
-        }
-        return defaultList(stockInRecordMapper.selectBatchIds(stockInRecordIds)).stream()
-                .filter(item -> item.getId() != null)
-                .collect(Collectors.toMap(StockInRecord::getId, item -> item, (a, b) -> a));
-    }
-
-    private Map<Long, Long> queryPurchaseLedgerIdByQualityInspectId(Collection<StockInRecord> stockInRecords) {
-        Set<Long> qualityInspectIds = stockInRecords.stream()
-                .filter(Objects::nonNull)
-                .filter(item -> item.getRecordId() != null && "10".equals(safe(item.getRecordType()).trim()))
-                .map(StockInRecord::getRecordId)
-                .collect(Collectors.toSet());
-        if (qualityInspectIds.isEmpty()) {
-            return Map.of();
-        }
-        return defaultList(qualityInspectMapper.selectBatchIds(qualityInspectIds)).stream()
-                .filter(item -> item.getId() != null && item.getPurchaseLedgerId() != null)
-                .collect(Collectors.toMap(QualityInspect::getId, QualityInspect::getPurchaseLedgerId, (a, b) -> a));
-    }
-
-    private Set<Long> resolvePurchaseLedgerIds(AccountPaymentApplication application,
-                                               Map<Long, StockInRecord> stockInRecordById,
-                                               Map<Long, Long> purchaseLedgerIdByQualityInspectId) {
-        Set<Long> result = new LinkedHashSet<>();
-        for (Long stockInRecordId : parseLongIds(application.getStockInRecordIds())) {
-            StockInRecord stockInRecord = stockInRecordById.get(stockInRecordId);
-            if (stockInRecord == null || stockInRecord.getRecordId() == null) {
-                continue;
-            }
-            if (stockInRecord.getApprovalStatus() != null && stockInRecord.getApprovalStatus() != 1) {
-                continue;
-            }
-            String recordType = safe(stockInRecord.getRecordType()).trim();
-            if ("7".equals(recordType)) {
-                result.add(stockInRecord.getRecordId());
-            } else if ("10".equals(recordType)) {
-                Long purchaseLedgerId = purchaseLedgerIdByQualityInspectId.get(stockInRecord.getRecordId());
-                if (purchaseLedgerId != null) {
-                    result.add(purchaseLedgerId);
-                }
-            }
-        }
-        return result;
-    }
-
-    private List<Long> parseLongIds(String raw) {
-        if (!StringUtils.hasText(raw)) {
-            return List.of();
-        }
-        List<Long> result = new ArrayList<>();
-        for (String part : raw.split(",")) {
-            if (!StringUtils.hasText(part)) {
-                continue;
-            }
-            try {
-                result.add(Long.parseLong(part.trim()));
-            } catch (Exception ignored) {
-            }
-        }
-        return result;
-    }
-
-
-    private List<PurchaseReturnOrders> queryReturns(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<PurchaseReturnOrders> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), PurchaseReturnOrders::getDeptId);
-        wrapper.ge(PurchaseReturnOrders::getPreparedAt, range.start())
-                .le(PurchaseReturnOrders::getPreparedAt, range.end());
-        return defaultList(purchaseReturnOrdersMapper.selectList(wrapper));
-    }
-
-    private Map<String, Object> toLedgerItem(PurchaseLedger item) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("id", item.getId());
-        map.put("purchaseContractNumber", safe(item.getPurchaseContractNumber()));
-        map.put("supplierName", safe(item.getSupplierName()));
-        map.put("projectName", safe(item.getProjectName()));
-        map.put("entryDate", formatDate(item.getEntryDate()));
-        map.put("contractAmount", item.getContractAmount());
-        map.put("approvalStatus", item.getApprovalStatus());
-        map.put("paymentMethod", safe(item.getPaymentMethod()));
-        return map;
-    }
-
-    private DateRange resolveDateRange(String startDate, String endDate, String timeRange) {
-        LocalDate today = LocalDate.now(CHINA_ZONE_ID);
-        LocalDate start = parseLocalDate(startDate);
-        LocalDate end = parseLocalDate(endDate);
-        if (start != null || end != null) {
-            LocalDate s = start != null ? start : end;
-            LocalDate e = end != null ? end : start;
-            if (s.isAfter(e)) {
-                LocalDate temp = s;
-                s = e;
-                e = temp;
-            }
-            return new DateRange(s, e, s + "鑷�" + e);
-        }
-        if (!StringUtils.hasText(timeRange)) {
-            return new DateRange(today.minusDays(29), today, "杩�30澶�");
-        }
-        String text = timeRange.trim();
-        if (text.contains("浠婂ぉ")) {
-            return new DateRange(today, today, "浠婂ぉ");
-        }
-        if (text.contains("鏄ㄥぉ")) {
-            LocalDate yesterday = today.minusDays(1);
-            return new DateRange(yesterday, yesterday, "鏄ㄥぉ");
-        }
-        if (text.contains("鏈懆")) {
-            LocalDate startOfWeek = today.minusDays(today.getDayOfWeek().getValue() - 1L);
-            return new DateRange(startOfWeek, today, "鏈懆");
-        }
-        if (text.contains("涓婂懆")) {
-            LocalDate thisWeekStart = today.minusDays(today.getDayOfWeek().getValue() - 1L);
-            LocalDate startOfLastWeek = thisWeekStart.minusWeeks(1);
-            return new DateRange(startOfLastWeek, startOfLastWeek.plusDays(6), "涓婂懆");
-        }
-        if (text.contains("浠婂勾") || text.contains("鏈勾")) {
-            return new DateRange(today.withDayOfYear(1), today, "浠婂勾");
-        }
-        if (text.contains("鏈湀")) {
-            return new DateRange(today.withDayOfMonth(1), today, "鏈湀");
-        }
-        if (text.contains("涓婃湀")) {
-            LocalDate first = today.minusMonths(1).withDayOfMonth(1);
-            LocalDate last = first.withDayOfMonth(first.lengthOfMonth());
-            return new DateRange(first, last, "涓婃湀");
-        }
-        if (text.contains("杩戝崐骞�") || text.contains("鏈�杩戝崐骞�")) {
-            return new DateRange(today.minusMonths(6).plusDays(1), today, "杩戝崐骞�");
-        }
-        if (text.contains("杩戝崐涓湀") || text.contains("鏈�杩戝崐涓湀") || text.contains("鍗婁釜鏈�")) {
-            return new DateRange(today.minusDays(14), today, "杩戝崐涓湀");
-        }
-        java.util.regex.Matcher relativeMatcher = java.util.regex.Pattern.compile("(杩憒鏈�杩�)(\\d+)(澶﹟鍛▅涓湀|鏈坾骞�)").matcher(text);
-        if (relativeMatcher.find()) {
-            int amount = Integer.parseInt(relativeMatcher.group(2));
-            String unit = relativeMatcher.group(3);
-            LocalDate relativeStart = switch (unit) {
-                case "澶�" -> today.minusDays(Math.max(amount - 1L, 0));
-                case "鍛�" -> today.minusWeeks(Math.max(amount, 1)).plusDays(1);
-                case "涓湀", "鏈�" -> today.minusMonths(Math.max(amount, 1)).plusDays(1);
-                case "骞�" -> today.minusYears(Math.max(amount, 1)).plusDays(1);
-                default -> today.minusDays(29);
-            };
-            return new DateRange(relativeStart, today, "杩�" + amount + unit);
-        }
-        return new DateRange(today.minusDays(29), today, "杩�30澶�");
-    }
-
-    private LocalDate parseLocalDate(String text) {
-        if (!StringUtils.hasText(text)) {
-            return null;
-        }
-        try {
-            return LocalDate.parse(text.trim(), DATE_FMT);
-        } catch (Exception ignored) {
-            return null;
-        }
-    }
-
-    private Date toDate(LocalDate localDate) {
-        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
-    }
-
-    private Date toExclusiveEndDate(LocalDate localDate) {
-        return Date.from(localDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
-    }
-
-    private String formatDate(Date date) {
-        if (date == null) {
-            return "";
-        }
-        return DATE_FMT.format(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
-    }
-
-    private boolean tenantMatched(Long dataTenantId, Long userTenantId) {
-        if (userTenantId == null) {
-            return true;
-        }
-        return Objects.equals(dataTenantId, userTenantId);
-    }
-
-    private <T> void applyTenantFilter(LambdaQueryWrapper<T> wrapper, Long tenantId, com.baomidou.mybatisplus.core.toolkit.support.SFunction<T, Long> field) {
-        if (tenantId != null) {
-            wrapper.eq(field, tenantId);
-        }
-    }
-
-    private <T> void applyDeptFilter(LambdaQueryWrapper<T> wrapper, Long deptId, com.baomidou.mybatisplus.core.toolkit.support.SFunction<T, Long> field) {
-        if (deptId != null) {
-            wrapper.eq(field, deptId);
-        }
-    }
-
-    private LoginUser currentLoginUser(String memoryId) {
-        LoginUser loginUser = aiSessionUserContext.get(memoryId);
-        if (loginUser != null) {
-            return loginUser;
-        }
-        return SecurityUtils.getLoginUser();
-    }
-
-    private int normalizeLimit(Integer limit) {
-        if (limit == null || limit <= 0) {
-            return DEFAULT_LIMIT;
-        }
-        return Math.min(limit, MAX_LIMIT);
-    }
-
-    private String safe(Object value) {
-        return value == null ? "" : String.valueOf(value).replace('\n', ' ').replace('\r', ' ');
-    }
-
-    private <T> List<T> defaultList(List<T> list) {
-        return list == null ? List.of() : list;
-    }
-
-    private String jsonResponse(boolean success,
-                                String type,
-                                String description,
-                                Map<String, Object> summary,
-                                Map<String, Object> data,
-                                Map<String, Object> charts) {
-        Map<String, Object> result = new LinkedHashMap<>();
-        result.put("success", success);
-        result.put("type", type);
-        result.put("description", description);
-        result.put("summary", summary == null ? Map.of() : summary);
-        result.put("data", data == null ? Map.of() : data);
-        result.put("charts", charts == null ? Map.of() : charts);
-        return JSON.toJSONString(result);
-    }
-
-    private record DateRange(LocalDate start, LocalDate end, String label) {
-    }
-
-    private static class MaterialRankItem {
-        private final String productCategory;
-        private final String specificationModel;
-        private final String unit;
-        private BigDecimal quantity = BigDecimal.ZERO;
-        private BigDecimal amount = BigDecimal.ZERO;
-
-        private MaterialRankItem(String productCategory, String specificationModel, String unit) {
-            this.productCategory = productCategory;
-            this.specificationModel = specificationModel;
-            this.unit = unit;
-        }
-
-        private Map<String, Object> toMap() {
-            Map<String, Object> map = new LinkedHashMap<>();
-            map.put("productCategory", productCategory);
-            map.put("specificationModel", specificationModel);
-            map.put("unit", unit);
-            map.put("quantity", quantity);
-            map.put("amount", amount);
-            return map;
-        }
-    }
-}
diff --git a/src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java b/src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java
deleted file mode 100644
index 0f7e586..0000000
--- a/src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java
+++ /dev/null
@@ -1,1633 +0,0 @@
-package com.ruoyi.ai.tools;
-
-import com.alibaba.fastjson2.JSON;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
-import com.ruoyi.account.mapper.sales.AccountSalesCollectionMapper;
-import com.ruoyi.account.pojo.sales.AccountSalesCollection;
-import com.ruoyi.ai.context.AiSessionUserContext;
-import com.ruoyi.basic.dto.CustomerDto;
-import com.ruoyi.basic.mapper.CustomerMapper;
-import com.ruoyi.basic.vo.CustomerVo;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.sales.mapper.SalesLedgerMapper;
-import com.ruoyi.sales.mapper.SalesQuotationMapper;
-import com.ruoyi.sales.mapper.ShippingInfoMapper;
-import com.ruoyi.sales.pojo.SalesLedger;
-import com.ruoyi.sales.pojo.SalesQuotation;
-import com.ruoyi.sales.pojo.ShippingInfo;
-import com.ruoyi.stock.mapper.StockOutRecordMapper;
-import com.ruoyi.stock.pojo.StockOutRecord;
-import dev.langchain4j.agent.tool.P;
-import dev.langchain4j.agent.tool.Tool;
-import dev.langchain4j.agent.tool.ToolMemoryId;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.YearMonth;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-@Component
-public class SalesAgentTools {
-
-    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final int DEFAULT_LIMIT = 10;
-    private static final int MAX_LIMIT = 30;
-    private static final BigDecimal ONE_HUNDRED = new BigDecimal("100");
-    private static final Pattern RELATIVE_PATTERN = Pattern.compile("(杩憒鏈�杩�)?\\s*(\\d+)\\s*(澶﹟鍛▅涓湀|鏈坾骞�)");
-    private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2})");
-
-    private final CustomerMapper customerMapper;
-    private final SalesLedgerMapper salesLedgerMapper;
-    private final SalesQuotationMapper salesQuotationMapper;
-    private final ShippingInfoMapper shippingInfoMapper;
-    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
-    private final StockOutRecordMapper stockOutRecordMapper;
-    private final AiSessionUserContext aiSessionUserContext;
-
-    public SalesAgentTools(CustomerMapper customerMapper,
-                           SalesLedgerMapper salesLedgerMapper,
-                           SalesQuotationMapper salesQuotationMapper,
-                           ShippingInfoMapper shippingInfoMapper,
-                           AccountSalesCollectionMapper accountSalesCollectionMapper,
-                           StockOutRecordMapper stockOutRecordMapper,
-                           AiSessionUserContext aiSessionUserContext) {
-        this.customerMapper = customerMapper;
-        this.salesLedgerMapper = salesLedgerMapper;
-        this.salesQuotationMapper = salesQuotationMapper;
-        this.shippingInfoMapper = shippingInfoMapper;
-        this.accountSalesCollectionMapper = accountSalesCollectionMapper;
-        this.stockOutRecordMapper = stockOutRecordMapper;
-        this.aiSessionUserContext = aiSessionUserContext;
-    }
-
-    @Tool(name = "鏌ヨ瀹㈡埛妗f", value = "鎸夌娴�/鍏捣绫诲瀷鍜屽叧閿瘝鏌ヨ瀹㈡埛妗f鍒楄〃")
-    public String listCustomerProfiles(@ToolMemoryId String memoryId,
-                                       @P(value = "瀹㈡埛姹犵被鍨嬶紝鍙�� private/public", required = false) String seaType,
-                                       @P(value = "鍏抽敭璇嶏紝鍙尮閰嶅鎴峰悕绉�/鑱旂郴浜�/鐢佃瘽", required = false) String keyword,
-                                       @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        CustomerDto customerDto = new CustomerDto();
-        customerDto.setType(normalizeSeaType(seaType));
-        customerDto.setUsageStatus(1L);
-
-        List<CustomerVo> rows = defaultList(customerMapper.list(customerDto, loginUser.getUserId()));
-        List<CustomerVo> filtered = rows.stream()
-                .filter(item -> matchCustomerKeyword(item, keyword))
-                .sorted(Comparator.comparing(CustomerVo::getId, Comparator.nullsLast(Comparator.reverseOrder())))
-                .limit(normalizeLimit(limit))
-                .collect(Collectors.toList());
-
-        List<Map<String, Object>> items = filtered.stream().map(item -> {
-            Map<String, Object> map = new LinkedHashMap<>();
-            map.put("id", item.getId());
-            map.put("customerName", safe(item.getCustomerName()));
-            map.put("customerType", safe(item.getCustomerType()));
-            map.put("contactPerson", safe(item.getContactPerson()));
-            map.put("contactPhone", safe(item.getContactPhone()));
-            map.put("companyPhone", safe(item.getCompanyPhone()));
-            map.put("maintainer", safe(item.getMaintainer()));
-            map.put("maintenanceTime", formatDate(item.getMaintenanceTime()));
-            map.put("usageUserName", safe(item.getUsageUserName()));
-            map.put("seaType", customerSeaTypeName(item.getType()));
-            map.put("isAssigned", item.getIsAssigned());
-            return map;
-        }).collect(Collectors.toList());
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("count", items.size());
-        summary.put("seaType", seaType == null ? "all" : seaType);
-        summary.put("keyword", safe(keyword));
-        summary.put("userId", loginUser.getUserId());
-
-        return jsonResponse(true, "sales_customer_profile_list", "宸茶繑鍥炲鎴锋。妗堝垪琛�", summary, Map.of("items", items), Map.of());
-    }
-
-    @Tool(name = "鏌ヨ閿�鍞姤浠�", value = "鎸夊叧閿瘝鍜屾椂闂磋寖鍥存煡璇㈤攢鍞姤浠峰崟")
-    public String listSalesQuotations(@ToolMemoryId String memoryId,
-                                      @P(value = "鍏抽敭璇嶏紝鍙尮閰嶆姤浠峰崟鍙�/瀹㈡埛/涓氬姟鍛�/鐘舵��", required = false) String keyword,
-                                      @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                      @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                      @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, null);
-        LambdaQueryWrapper<SalesQuotation> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), SalesQuotation::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), SalesQuotation::getDeptId);
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(SalesQuotation::getQuotationNo, keyword)
-                    .or().like(SalesQuotation::getCustomer, keyword)
-                    .or().like(SalesQuotation::getSalesperson, keyword)
-                    .or().like(SalesQuotation::getStatus, keyword));
-        }
-        wrapper.ge(SalesQuotation::getQuotationDate, range.start())
-                .le(SalesQuotation::getQuotationDate, range.end())
-                .orderByDesc(SalesQuotation::getQuotationDate, SalesQuotation::getId)
-                .last("limit " + normalizeLimit(limit));
-
-        List<SalesQuotation> rows = defaultList(salesQuotationMapper.selectList(wrapper));
-        BigDecimal quotationAmountTotal = rows.stream()
-                .map(SalesQuotation::getTotalAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-        List<Map<String, Object>> items = rows.stream().map(item -> {
-            Map<String, Object> map = new LinkedHashMap<>();
-            map.put("id", item.getId());
-            map.put("quotationNo", safe(item.getQuotationNo()));
-            map.put("customer", safe(item.getCustomer()));
-            map.put("salesperson", safe(item.getSalesperson()));
-            map.put("quotationDate", formatDate(item.getQuotationDate()));
-            map.put("validDate", formatDate(item.getValidDate()));
-            map.put("status", safe(item.getStatus()));
-            map.put("paymentMethod", safe(item.getPaymentMethod()));
-            map.put("deliveryPeriod", safe(item.getDeliveryPeriod()));
-            map.put("totalAmount", item.getTotalAmount());
-            return map;
-        }).collect(Collectors.toList());
-
-        Map<String, Object> summary = rangeSummary(range, items.size(), keyword);
-        summary.put("quotationAmountTotal", quotationAmountTotal);
-        return jsonResponse(true, "sales_quotation_list", "宸茶繑鍥為攢鍞姤浠峰垪琛�", summary, Map.of("items", items), Map.of());
-    }
-
-    @Tool(name = "鏌ヨ閿�鍞彴璐�", value = "鎸夊叧閿瘝鍜屾椂闂磋寖鍥存煡璇㈤攢鍞彴璐︼紝骞惰繑鍥炲紑绁ㄥ洖娆句笌鍙戣揣鐘舵��")
-    public String listSalesLedgers(@ToolMemoryId String memoryId,
-                                   @P(value = "鍏抽敭璇嶏紝鍙尮閰嶉攢鍞悎鍚屽彿/瀹㈡埛鍚堝悓鍙�/瀹㈡埛/椤圭洰", required = false) String keyword,
-                                   @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                   @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                   @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, null);
-        LambdaQueryWrapper<SalesLedger> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), SalesLedger::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), SalesLedger::getDeptId);
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(SalesLedger::getSalesContractNo, keyword)
-                    .or().like(SalesLedger::getCustomerContractNo, keyword)
-                    .or().like(SalesLedger::getCustomerName, keyword)
-                    .or().like(SalesLedger::getProjectName, keyword)
-                    .or().like(SalesLedger::getSalesman, keyword));
-        }
-        wrapper.ge(SalesLedger::getEntryDate, toDate(range.start()))
-                .lt(SalesLedger::getEntryDate, toExclusiveEndDate(range.end()))
-                .orderByDesc(SalesLedger::getEntryDate, SalesLedger::getId)
-                .last("limit " + normalizeLimit(limit));
-        List<SalesLedger> rows = defaultList(salesLedgerMapper.selectList(wrapper));
-        if (rows.isEmpty()) {
-            return jsonResponse(true, "sales_ledger_list", "鏈煡璇㈠埌绗﹀悎鏉′欢鐨勯攢鍞彴璐�", rangeSummary(range, 0, keyword), Map.of("items", List.of()), Map.of());
-        }
-
-        List<Long> ledgerIds = rows.stream().map(SalesLedger::getId).filter(Objects::nonNull).collect(Collectors.toList());
-        Map<Long, BigDecimal> invoiceAmountByLedgerId = sumInvoiceAmounts(ledgerIds);
-        Map<Long, BigDecimal> receiptAmountByLedgerId = sumReceiptAmounts(loginUser, ledgerIds);
-        Map<Long, List<ShippingInfo>> shippingByLedgerId = queryShippingsByLedgerIds(loginUser, ledgerIds).stream()
-                .collect(Collectors.groupingBy(ShippingInfo::getSalesLedgerId));
-
-        BigDecimal contractAmountTotal = BigDecimal.ZERO;
-        BigDecimal invoicedAmountTotal = BigDecimal.ZERO;
-        BigDecimal receivedAmountTotal = BigDecimal.ZERO;
-        BigDecimal pendingAmountTotal = BigDecimal.ZERO;
-
-        List<Map<String, Object>> items = new ArrayList<>();
-        for (SalesLedger ledger : rows) {
-            BigDecimal contractAmount = defaultDecimal(ledger.getContractAmount());
-            BigDecimal invoicedAmount = invoiceAmountByLedgerId.getOrDefault(ledger.getId(), BigDecimal.ZERO);
-            BigDecimal receivedAmount = receiptAmountByLedgerId.getOrDefault(ledger.getId(), BigDecimal.ZERO);
-            BigDecimal unbilledAmount = maxZero(contractAmount.subtract(invoicedAmount));
-            BigDecimal pendingAmount = maxZero(invoicedAmount.subtract(receivedAmount));
-
-            contractAmountTotal = contractAmountTotal.add(contractAmount);
-            invoicedAmountTotal = invoicedAmountTotal.add(invoicedAmount);
-            receivedAmountTotal = receivedAmountTotal.add(receivedAmount);
-            pendingAmountTotal = pendingAmountTotal.add(pendingAmount);
-
-            Map<String, Object> item = new LinkedHashMap<>();
-            item.put("id", ledger.getId());
-            item.put("salesContractNo", safe(ledger.getSalesContractNo()));
-            item.put("customerContractNo", safe(ledger.getCustomerContractNo()));
-            item.put("customerName", safe(ledger.getCustomerName()));
-            item.put("projectName", safe(ledger.getProjectName()));
-            item.put("salesman", safe(ledger.getSalesman()));
-            item.put("entryDate", formatDate(ledger.getEntryDate()));
-            item.put("executionDate", formatDate(ledger.getExecutionDate()));
-            item.put("deliveryDate", formatDate(ledger.getDeliveryDate()));
-            item.put("contractAmount", contractAmount);
-            item.put("invoicedAmount", invoicedAmount);
-            item.put("receivedAmount", receivedAmount);
-            item.put("unbilledAmount", unbilledAmount);
-            item.put("pendingAmount", pendingAmount);
-            item.put("shippingStatus", calcLedgerShippingStatus(shippingByLedgerId.get(ledger.getId())));
-            items.add(item);
-        }
-
-        Map<String, Object> summary = rangeSummary(range, items.size(), keyword);
-        summary.put("contractAmountTotal", contractAmountTotal);
-        summary.put("invoicedAmountTotal", invoicedAmountTotal);
-        summary.put("receivedAmountTotal", receivedAmountTotal);
-        summary.put("pendingAmountTotal", pendingAmountTotal);
-        return jsonResponse(true, "sales_ledger_list", "宸茶繑鍥為攢鍞彴璐﹀垪琛�", summary, Map.of("items", items), Map.of());
-    }
-
-    @Tool(name = "鏌ヨ閿�鍞��璐�", value = "鎸夋椂闂磋寖鍥村拰鍏抽敭璇嶆煡璇㈤攢鍞��璐ц褰�")
-    public String listSalesReturns(@ToolMemoryId String memoryId,
-                                   @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                   @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                   @P(value = "鍏抽敭璇嶏紝鍙尮閰嶉��娆惧崟鍙�/浜ゆ槗鍙�/浠樻璐︽埛", required = false) String keyword,
-                                   @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, null);
-        LambdaQueryWrapper<AccountSalesCollection> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), AccountSalesCollection::getDeptId);
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(AccountSalesCollection::getCollectionNumber, keyword)
-                    .or().like(AccountSalesCollection::getCollectionMethod, keyword)
-                    .or().like(AccountSalesCollection::getRemark, keyword));
-        }
-        wrapper.ge(AccountSalesCollection::getCollectionDate, range.start())
-                .le(AccountSalesCollection::getCollectionDate, range.end())
-                .orderByDesc(AccountSalesCollection::getCollectionDate, AccountSalesCollection::getId)
-                .last("limit " + normalizeLimit(limit));
-        List<AccountSalesCollection> rows = defaultList(accountSalesCollectionMapper.selectList(wrapper));
-
-        BigDecimal returnAmount = rows.stream()
-                .map(AccountSalesCollection::getCollectionAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-        List<Map<String, Object>> items = rows.stream().map(item -> {
-            Map<String, Object> map = new LinkedHashMap<>();
-            map.put("id", item.getId());
-            map.put("refundId", safe(item.getCollectionNumber()));
-            map.put("collectionNumber", safe(item.getCollectionNumber()));
-            map.put("paymentMethod", safe(item.getCollectionMethod()));
-            map.put("actualAmount", item.getCollectionAmount());
-            map.put("collectionAmount", item.getCollectionAmount());
-            map.put("customerId", item.getCustomerId());
-            map.put("remark", safe(item.getRemark()));
-            map.put("createTime", formatDate(item.getCollectionDate()));
-            return map;
-        }).collect(Collectors.toList());
-
-        Map<String, Object> summary = rangeSummary(range, items.size(), keyword);
-        summary.put("returnAmount", returnAmount);
-        return jsonResponse(true, "sales_return_list", "宸茶繑鍥為攢鍞��璐ц褰�", summary, Map.of("items", items), Map.of());
-    }
-
-    @Tool(name = "鏌ヨ瀹㈡埛寰�鏉�", value = "鎸夋椂闂磋寖鍥村拰鍏抽敭璇嶆煡璇㈠鎴峰洖娆惧線鏉ユ槑缁�")
-    public String listCustomerInteractions(@ToolMemoryId String memoryId,
-                                           @P(value = "鍏抽敭璇嶏紝鍙尮閰嶅鎴峰悕绉�/閿�鍞悎鍚屽彿/椤圭洰鍚�", required = false) String keyword,
-                                           @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                           @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                           @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, null);
-        List<AccountSalesCollection> collections = queryCollections(loginUser, range);
-        if (collections.isEmpty()) {
-            return jsonResponse(true, "sales_customer_interaction_list", "no_customer_interactions", rangeSummary(range, 0, keyword), Map.of("items", List.of()), Map.of());
-        }
-
-        Map<Integer, Set<Long>> ledgerIdsByCollectionId = mapCollectionLedgerIds(loginUser, collections);
-        Set<Long> ledgerIds = ledgerIdsByCollectionId.values().stream()
-                .flatMap(Collection::stream)
-                .collect(Collectors.toSet());
-        Map<Long, SalesLedger> ledgerMap = defaultList(salesLedgerMapper.selectBatchIds(ledgerIds)).stream()
-                .filter(ledger -> tenantMatched(ledger.getTenantId(), loginUser.getTenantId()))
-                .collect(Collectors.toMap(SalesLedger::getId, item -> item, (a, b) -> a, LinkedHashMap::new));
-
-        int finalLimit = normalizeLimit(limit);
-        List<Map<String, Object>> items = new ArrayList<>();
-        for (AccountSalesCollection collection : collections) {
-            Set<Long> relatedLedgerIds = ledgerIdsByCollectionId.get(collection.getId());
-            if (relatedLedgerIds == null || relatedLedgerIds.isEmpty()) {
-                if (!matchInteractionKeyword(collection, null, keyword)) {
-                    continue;
-                }
-                items.add(toInteractionItem(collection, null));
-                if (items.size() >= finalLimit) {
-                    break;
-                }
-                continue;
-            }
-            for (Long ledgerId : relatedLedgerIds) {
-                SalesLedger ledger = ledgerMap.get(ledgerId);
-                if (ledger == null || !matchInteractionKeyword(collection, ledger, keyword)) {
-                    continue;
-                }
-                items.add(toInteractionItem(collection, ledger));
-                if (items.size() >= finalLimit) {
-                    break;
-                }
-            }
-            if (items.size() >= finalLimit) {
-                break;
-            }
-        }
-
-        BigDecimal totalReceiptAmount = items.stream()
-                .map(item -> asBigDecimal(item.get("receiptPaymentAmount")))
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        Map<String, Object> summary = rangeSummary(range, items.size(), keyword);
-        summary.put("totalReceiptAmount", totalReceiptAmount);
-        summary.put("customerCount", items.stream()
-                .map(item -> String.valueOf(item.get("customerName")))
-                .filter(StringUtils::hasText)
-                .distinct()
-                .count());
-        return jsonResponse(true, "sales_customer_interaction_list", "ok", summary, Map.of("items", items), Map.of());
-    }
-
-    @Tool(name = "鏌ヨ鍙戣揣鍙拌处", value = "鎸夊叧閿瘝鍜屾椂闂磋寖鍥存煡璇㈠彂璐у彴璐�")
-    public String listShippingLedgers(@ToolMemoryId String memoryId,
-                                      @P(value = "鍏抽敭璇嶏紝鍙尮閰嶅彂璐у崟鍙�/蹇�掑崟鍙�/鐗╂祦鍏徃/杞︾墝鍙�", required = false) String keyword,
-                                      @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                      @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                      @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, null);
-        LambdaQueryWrapper<ShippingInfo> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), ShippingInfo::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ShippingInfo::getDeptId);
-        if (StringUtils.hasText(keyword)) {
-            wrapper.and(w -> w.like(ShippingInfo::getShippingNo, keyword)
-                    .or().like(ShippingInfo::getExpressNumber, keyword)
-                    .or().like(ShippingInfo::getExpressCompany, keyword)
-                    .or().like(ShippingInfo::getShippingCarNumber, keyword)
-                    .or().like(ShippingInfo::getStatus, keyword));
-        }
-        wrapper.ge(ShippingInfo::getShippingDate, toDate(range.start()))
-                .lt(ShippingInfo::getShippingDate, toExclusiveEndDate(range.end()))
-                .orderByDesc(ShippingInfo::getShippingDate, ShippingInfo::getId)
-                .last("limit " + normalizeLimit(limit));
-        List<ShippingInfo> rows = defaultList(shippingInfoMapper.selectList(wrapper));
-        if (rows.isEmpty()) {
-            return jsonResponse(true, "sales_shipping_list", "鏈煡璇㈠埌鍙戣揣鍙拌处璁板綍", rangeSummary(range, 0, keyword), Map.of("items", List.of()), Map.of());
-        }
-
-        List<Long> ledgerIds = rows.stream().map(ShippingInfo::getSalesLedgerId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
-        Map<Long, SalesLedger> ledgerMap = defaultList(salesLedgerMapper.selectBatchIds(ledgerIds)).stream()
-                .filter(ledger -> tenantMatched(ledger.getTenantId(), loginUser.getTenantId()))
-                .collect(Collectors.toMap(SalesLedger::getId, item -> item, (a, b) -> a, LinkedHashMap::new));
-
-        long shippedCount = rows.stream().filter(item -> isShippedStatus(item.getStatus())).count();
-        List<Map<String, Object>> items = rows.stream().map(item -> {
-            SalesLedger ledger = ledgerMap.get(item.getSalesLedgerId());
-            Map<String, Object> map = new LinkedHashMap<>();
-            map.put("id", item.getId());
-            map.put("salesLedgerId", item.getSalesLedgerId());
-            map.put("salesContractNo", ledger == null ? "" : safe(ledger.getSalesContractNo()));
-            map.put("customerName", ledger == null ? "" : safe(ledger.getCustomerName()));
-            map.put("shippingNo", safe(item.getShippingNo()));
-            map.put("status", safe(item.getStatus()));
-            map.put("shippingDate", formatDate(item.getShippingDate()));
-            map.put("type", safe(item.getType()));
-            map.put("shippingCarNumber", safe(item.getShippingCarNumber()));
-            map.put("expressCompany", safe(item.getExpressCompany()));
-            map.put("expressNumber", safe(item.getExpressNumber()));
-            return map;
-        }).collect(Collectors.toList());
-
-        Map<String, Object> summary = rangeSummary(range, items.size(), keyword);
-        summary.put("shippingCount", rows.size());
-        summary.put("shippedCount", shippedCount);
-        summary.put("pendingCount", Math.max(rows.size() - shippedCount, 0));
-        return jsonResponse(true, "sales_shipping_list", "宸茶繑鍥炲彂璐у彴璐﹁褰�", summary, Map.of("items", items), Map.of());
-    }
-
-    @Tool(name = "鏌ヨ閿�鍞寚鏍囩粺璁�", value = "鎸夋椂闂磋寖鍥寸粺璁¢攢鍞悎鍚屻�佹姤浠枫�佸彂璐с�佸洖娆剧瓑鍏抽敭鎸囨爣")
-    public String getSalesDashboard(@ToolMemoryId String memoryId,
-                                    @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                    @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                    @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屽鏈湀銆佹湰骞淬�佽繎30澶�", required = false) String timeRange) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, timeRange);
-
-        List<SalesLedger> ledgers = querySalesLedgers(loginUser, range);
-        List<SalesQuotation> quotations = querySalesQuotations(loginUser, range);
-        List<ShippingInfo> shippings = queryShippings(loginUser, range);
-
-
-        BigDecimal contractAmountTotal = ledgers.stream()
-                .map(SalesLedger::getContractAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal quotationAmountTotal = quotations.stream()
-                .map(SalesQuotation::getTotalAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-        long shippingCount = shippings.size();
-        long shippedCount = shippings.stream().filter(item -> isShippedStatus(item.getStatus())).count();
-        String shipRate = toRate(shippedCount, shippingCount);
-
-        List<Map<String, Object>> topCustomers = buildTopCustomers(ledgers);
-        TrendData trendData = buildContractTrendData(ledgers, range);
-
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", range.start().toString());
-        summary.put("endDate", range.end().toString());
-        summary.put("orderCount", ledgers.size());
-        summary.put("quotationCount", quotations.size());
-        summary.put("shippingCount", shippingCount);
-        summary.put("shippedCount", shippedCount);
-        summary.put("shipRate", shipRate);
-        summary.put("contractAmountTotal", contractAmountTotal);
-        summary.put("quotationAmountTotal", quotationAmountTotal);
-        summary.put("receivedAmountTotal", BigDecimal.ZERO);
-        summary.put("pendingAmountTotal", BigDecimal.ZERO);
-
-        Map<String, Object> charts = new LinkedHashMap<>();
-//        charts.put("amountBarOption", buildAmountBarOption(contractAmountTotal, quotationAmountTotal, receivedAmountTotal, pendingAmountTotal));
-        charts.put("amountBarOption", buildAmountBarOption(contractAmountTotal, quotationAmountTotal, BigDecimal.ONE, BigDecimal.ONE));
-        charts.put("shippingPieOption", buildShippingPieOption(shippedCount, Math.max(shippingCount - shippedCount, 0)));
-        charts.put("customerTopBarOption", buildCustomerTopBarOption(topCustomers));
-        charts.put("contractTrendLineOption", buildContractTrendLineOption(trendData.labels(), trendData.values()));
-
-        Map<String, Object> data = new LinkedHashMap<>();
-        data.put("topCustomers", topCustomers);
-        data.put("contractTrend", trendData.toItemList());
-
-        return jsonResponse(true, "sales_dashboard", "宸茶繑鍥為攢鍞寚鏍囩粺璁�", summary, data, charts);
-    }
-
-    @Tool(name = "瀹㈡埛娴佸け椋庨櫓鍒嗘瀽", value = "鎸夊鎴风淮搴﹁瘎浼版祦澶遍闄╋紝杈撳嚭椋庨櫓鍒嗙骇銆佸師鍥犲拰寤鸿浼樺厛绾�")
-    public String analyzeCustomerChurnRisk(@ToolMemoryId String memoryId,
-                                           @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                           @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                           @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屽杩�90澶┿�佹湰骞�", required = false) String timeRange,
-                                           @P(value = "鍏抽敭璇嶏紝鍙尮閰嶅鎴峰悕绉�", required = false) String keyword,
-                                           @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, StringUtils.hasText(timeRange) ? timeRange : "杩�180澶�");
-        List<CustomerRiskMetric> metrics = buildCustomerRiskMetrics(loginUser, range, keyword);
-        if (metrics.isEmpty()) {
-            return jsonResponse(true, "sales_customer_churn_risk", "褰撳墠鑼冨洿鍐呮湭鏌ヨ鍒板彲鍒嗘瀽鐨勫鎴锋暟鎹�",
-                    rangeSummary(range, 0, keyword), Map.of("items", List.of()), Map.of());
-        }
-
-        List<CustomerRiskMetric> sorted = metrics.stream()
-                .sorted(Comparator.comparing(CustomerRiskMetric::getRiskScore).reversed()
-                        .thenComparing(CustomerRiskMetric::getPendingAmount, Comparator.reverseOrder()))
-                .limit(normalizeLimit(limit))
-                .collect(Collectors.toList());
-
-        long highCount = sorted.stream().filter(item -> "high".equals(item.getRiskLevel())).count();
-        long mediumCount = sorted.stream().filter(item -> "medium".equals(item.getRiskLevel())).count();
-        long lowCount = sorted.stream().filter(item -> "low".equals(item.getRiskLevel())).count();
-
-        List<Map<String, Object>> items = sorted.stream().map(this::toRiskItem).collect(Collectors.toList());
-        Map<String, Object> summary = rangeSummary(range, items.size(), keyword);
-        summary.put("highRiskCount", highCount);
-        summary.put("mediumRiskCount", mediumCount);
-        summary.put("lowRiskCount", lowCount);
-
-        Map<String, Object> charts = new LinkedHashMap<>();
-        charts.put("riskLevelPieOption", buildRiskLevelPieOption(highCount, mediumCount, lowCount));
-        charts.put("riskScoreBarOption", buildRiskScoreBarOption(sorted));
-
-        return jsonResponse(true, "sales_customer_churn_risk", "宸插畬鎴愬鎴锋祦澶遍闄╁垎鏋�", summary, Map.of("items", items), charts);
-    }
-
-    @Tool(name = "鍥炴涓庢姤浠风瓥鐣ュ缓璁�", value = "鍩轰簬瀹㈡埛椋庨櫓銆佸洖娆惧拰鎶ヤ环鎯呭喌鐢熸垚鍙墽琛岀殑璺熻繘绛栫暐")
-    public String suggestCollectionAndQuotationStrategy(@ToolMemoryId String memoryId,
-                                                        @P(value = "寮�濮嬫棩鏈� yyyy-MM-dd", required = false) String startDate,
-                                                        @P(value = "缁撴潫鏃ユ湡 yyyy-MM-dd", required = false) String endDate,
-                                                        @P(value = "鏃堕棿鑼冨洿鎻忚堪锛屽杩�90澶┿�佹湰鏈�", required = false) String timeRange,
-                                                        @P(value = "鍏抽敭璇嶏紝鍙尮閰嶅鎴峰悕绉�", required = false) String keyword,
-                                                        @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit,
-                                                        @P(value = "鏄惁浼樺厛楂橀闄╁鎴凤紝true 琛ㄧず楂橀闄╀紭鍏�", required = false) Boolean prioritizeHighRisk) {
-        LoginUser loginUser = currentLoginUser(memoryId);
-        DateRange range = resolveDateRange(startDate, endDate, StringUtils.hasText(timeRange) ? timeRange : "杩�90澶�");
-        List<CustomerRiskMetric> metrics = buildCustomerRiskMetrics(loginUser, range, keyword);
-        if (metrics.isEmpty()) {
-            return jsonResponse(true, "sales_collection_quote_strategy", "褰撳墠鑼冨洿鍐呮湭鏌ヨ鍒板彲鐢熸垚绛栫暐鐨勫鎴锋暟鎹�",
-                    rangeSummary(range, 0, keyword), Map.of("items", List.of()), Map.of());
-        }
-
-        boolean highRiskFirst = Boolean.TRUE.equals(prioritizeHighRisk);
-        Comparator<CustomerRiskMetric> sortComparator;
-        if (highRiskFirst) {
-            sortComparator = Comparator
-                    .comparingInt((CustomerRiskMetric metric) -> riskLevelRank(metric.getRiskLevel())).reversed()
-                    .thenComparing(CustomerRiskMetric::getRiskScore, Comparator.reverseOrder())
-                    .thenComparing(CustomerRiskMetric::getPendingAmount, Comparator.reverseOrder());
-        } else {
-            sortComparator = Comparator
-                    .comparing(CustomerRiskMetric::getPendingAmount, Comparator.reverseOrder())
-                    .thenComparing(CustomerRiskMetric::getRiskScore, Comparator.reverseOrder());
-        }
-
-        List<CustomerRiskMetric> sorted = metrics.stream()
-                .sorted(sortComparator)
-                .limit(normalizeLimit(limit))
-                .collect(Collectors.toList());
-
-        List<Map<String, Object>> items = sorted.stream().map(this::toStrategyItem).collect(Collectors.toList());
-        long highPriorityCount = items.stream().filter(item -> "high".equals(item.get("priority"))).count();
-        long mediumPriorityCount = items.stream().filter(item -> "medium".equals(item.get("priority"))).count();
-        long lowPriorityCount = items.stream().filter(item -> "low".equals(item.get("priority"))).count();
-
-        Map<String, Object> summary = rangeSummary(range, items.size(), keyword);
-        summary.put("highPriorityCount", highPriorityCount);
-        summary.put("mediumPriorityCount", mediumPriorityCount);
-        summary.put("lowPriorityCount", lowPriorityCount);
-        summary.put("prioritizeHighRisk", highRiskFirst);
-        summary.put("priorityMode", highRiskFirst ? "high_risk_first" : "pending_amount_first");
-
-        Map<String, Object> charts = new LinkedHashMap<>();
-        charts.put("pendingAmountBarOption", buildPendingAmountBarOption(sorted));
-        charts.put("priorityPieOption", buildPriorityPieOption(highPriorityCount, mediumPriorityCount, lowPriorityCount));
-
-        return jsonResponse(true, "sales_collection_quote_strategy", "宸茬敓鎴愬洖娆句笌鎶ヤ环绛栫暐寤鸿", summary, Map.of("items", items), charts);
-    }
-
-    private List<CustomerRiskMetric> buildCustomerRiskMetrics(LoginUser loginUser, DateRange range, String keyword) {
-        List<SalesLedger> ledgers = querySalesLedgers(loginUser, range).stream()
-                .filter(item -> matchLedgerCustomerKeyword(item, keyword))
-                .collect(Collectors.toList());
-        if (ledgers.isEmpty()) {
-            return List.of();
-        }
-
-        Map<String, CustomerRiskMetric> metricMap = new LinkedHashMap<>();
-        for (SalesLedger ledger : ledgers) {
-            String customerName = StringUtils.hasText(ledger.getCustomerName()) ? ledger.getCustomerName().trim() : "鏈煡瀹㈡埛";
-            CustomerRiskMetric metric = metricMap.computeIfAbsent(customerName, CustomerRiskMetric::new);
-            metric.setOrderCount(metric.getOrderCount() + 1);
-            metric.setContractAmount(metric.getContractAmount().add(defaultDecimal(ledger.getContractAmount())));
-            metric.setTopSingleOrderAmount(metric.getTopSingleOrderAmount().max(defaultDecimal(ledger.getContractAmount())));
-            LocalDate entryDate = toLocalDate(ledger.getEntryDate());
-            if (entryDate != null && (metric.getLastOrderDate() == null || entryDate.isAfter(metric.getLastOrderDate()))) {
-                metric.setLastOrderDate(entryDate);
-            }
-            if (ledger.getId() != null) {
-                metric.getLedgerIds().add(ledger.getId());
-                if (ledger.getDeliveryDate() != null) {
-                    metric.getDeliveryDateByLedgerId().put(ledger.getId(), ledger.getDeliveryDate());
-                }
-            }
-        }
-
-        List<Long> allLedgerIds = metricMap.values().stream()
-                .flatMap(metric -> metric.getLedgerIds().stream())
-                .distinct()
-                .collect(Collectors.toList());
-        Map<Long, BigDecimal> receiptAmountByLedgerId = sumReceiptAmounts(loginUser, allLedgerIds);
-        Map<Long, List<ShippingInfo>> shippingByLedgerId = queryShippingsByLedgerIds(loginUser, allLedgerIds).stream()
-                .collect(Collectors.groupingBy(ShippingInfo::getSalesLedgerId));
-
-        List<SalesQuotation> quotations = querySalesQuotations(loginUser, range);
-        for (SalesQuotation quotation : quotations) {
-            String customerName = safe(quotation.getCustomer());
-            CustomerRiskMetric metric = metricMap.get(customerName);
-            if (metric == null) {
-                continue;
-            }
-            metric.setQuoteCount(metric.getQuoteCount() + 1);
-            metric.setQuoteAmount(metric.getQuoteAmount().add(defaultDecimal(quotation.getTotalAmount())));
-        }
-
-        LocalDate today = LocalDate.now();
-        for (CustomerRiskMetric metric : metricMap.values()) {
-            BigDecimal receivedAmount = BigDecimal.ZERO;
-            long overdueDeliveryCount = 0;
-            for (Long ledgerId : metric.getLedgerIds()) {
-                receivedAmount = receivedAmount.add(receiptAmountByLedgerId.getOrDefault(ledgerId, BigDecimal.ZERO));
-                LocalDate deliveryDate = metric.getDeliveryDateByLedgerId().get(ledgerId);
-                if (deliveryDate != null && deliveryDate.isBefore(today) && !isLedgerFullyShipped(ledgerId, shippingByLedgerId)) {
-                    overdueDeliveryCount++;
-                }
-            }
-            metric.setReceivedAmount(receivedAmount);
-            metric.setPendingAmount(maxZero(metric.getContractAmount().subtract(receivedAmount)));
-            if (metric.getContractAmount().compareTo(BigDecimal.ZERO) > 0) {
-                metric.setPendingRate(metric.getPendingAmount()
-                        .divide(metric.getContractAmount(), 4, RoundingMode.HALF_UP));
-            } else {
-                metric.setPendingRate(BigDecimal.ZERO);
-            }
-            metric.setOverdueDeliveryCount(overdueDeliveryCount);
-            if (metric.getLastOrderDate() == null) {
-                metric.setDaysSinceLastOrder(999);
-            } else {
-                metric.setDaysSinceLastOrder(Math.max(today.toEpochDay() - metric.getLastOrderDate().toEpochDay(), 0));
-            }
-            evaluateRiskMetric(metric);
-        }
-        return new ArrayList<>(metricMap.values());
-    }
-
-    private void evaluateRiskMetric(CustomerRiskMetric metric) {
-        int score = 0;
-        List<String> reasons = new ArrayList<>();
-        if (metric.getDaysSinceLastOrder() >= 90) {
-            score += 35;
-            reasons.add("杩�90澶╂棤鏂板璁㈠崟");
-        } else if (metric.getDaysSinceLastOrder() >= 60) {
-            score += 25;
-            reasons.add("杩�60澶╄鍗曟椿璺冨害涓嬮檷");
-        } else if (metric.getDaysSinceLastOrder() >= 30) {
-            score += 12;
-            reasons.add("杩�30澶╄鍗曟尝鍔ㄥ亸寮�");
-        }
-
-        if (metric.getPendingRate().compareTo(new BigDecimal("0.60")) >= 0) {
-            score += 30;
-            reasons.add("寰呭洖娆惧崰姣旈珮浜�60%");
-        } else if (metric.getPendingRate().compareTo(new BigDecimal("0.30")) >= 0) {
-            score += 20;
-            reasons.add("寰呭洖娆惧崰姣旈珮浜�30%");
-        } else if (metric.getPendingRate().compareTo(new BigDecimal("0.10")) >= 0) {
-            score += 10;
-            reasons.add("瀛樺湪寰呭洖娆鹃闄�");
-        }
-
-        if (metric.getOverdueDeliveryCount() > 0) {
-            score += Math.min((int) metric.getOverdueDeliveryCount() * 6, 20);
-            reasons.add("瀛樺湪浜ゆ湡閫炬湡璁㈠崟");
-        }
-
-        if (metric.getOrderCount() <= 1) {
-            score += 8;
-            reasons.add("璁㈠崟鍩烘暟鍋忎綆");
-        }
-
-        if (metric.getQuoteCount() > 0 && metric.getOrderCount() == 0) {
-            score += 10;
-            reasons.add("鎶ヤ环鏈舰鎴愯鍗曡浆鍖�");
-        }
-
-        score = Math.min(score, 100);
-        metric.setRiskScore(score);
-        if (score >= 70) {
-            metric.setRiskLevel("high");
-        } else if (score >= 40) {
-            metric.setRiskLevel("medium");
-        } else {
-            metric.setRiskLevel("low");
-        }
-        metric.setRiskReasons(reasons);
-    }
-
-    private Map<String, Object> toRiskItem(CustomerRiskMetric metric) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("customerName", metric.getCustomerName());
-        map.put("riskLevel", metric.getRiskLevel());
-        map.put("riskScore", metric.getRiskScore());
-        map.put("contractAmount", metric.getContractAmount());
-        map.put("receivedAmount", metric.getReceivedAmount());
-        map.put("pendingAmount", metric.getPendingAmount());
-        map.put("pendingRate", toPercent(metric.getPendingRate()));
-        map.put("orderCount", metric.getOrderCount());
-        map.put("quoteCount", metric.getQuoteCount());
-        map.put("overdueDeliveryCount", metric.getOverdueDeliveryCount());
-        map.put("daysSinceLastOrder", metric.getDaysSinceLastOrder());
-        map.put("lastOrderDate", formatDate(metric.getLastOrderDate()));
-        map.put("riskReasons", metric.getRiskReasons());
-        return map;
-    }
-
-    private Map<String, Object> toStrategyItem(CustomerRiskMetric metric) {
-        String priority = strategyPriority(metric);
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("customerName", metric.getCustomerName());
-        map.put("riskLevel", metric.getRiskLevel());
-        map.put("riskScore", metric.getRiskScore());
-        map.put("priority", priority);
-        map.put("pendingAmount", metric.getPendingAmount());
-        map.put("pendingRate", toPercent(metric.getPendingRate()));
-        map.put("quoteCount", metric.getQuoteCount());
-        map.put("orderCount", metric.getOrderCount());
-        map.put("quoteConversionRate", toRate(metric.getOrderCount(), Math.max(metric.getQuoteCount(), 1)));
-        map.put("collectionStrategy", buildCollectionStrategy(metric));
-        map.put("quotationStrategy", buildQuotationStrategy(metric));
-        map.put("nextAction", buildNextAction(priority));
-        map.put("topSingleOrderAmount", metric.getTopSingleOrderAmount());
-        return map;
-    }
-
-    private String buildCollectionStrategy(CustomerRiskMetric metric) {
-        if (metric.getPendingAmount().compareTo(BigDecimal.ZERO) <= 0) {
-            return "淇濇寔姝e父鏈堝害瀵硅处涓庡洖娆剧‘璁わ紝缁存寔瀹㈡埛鍥炴鑺傚銆�";
-        }
-        if (metric.getPendingRate().compareTo(new BigDecimal("0.60")) >= 0) {
-            return "浼樺厛閿佸畾鍥炴璁″垝锛屾寜鍛ㄦ媶鍒嗗洖娆捐妭鐐瑰苟缁戝畾鍙戣揣鏉′欢锛岄伩鍏嶆柊澧炰俊鐢ㄦ暈鍙c��";
-        }
-        if (metric.getPendingRate().compareTo(new BigDecimal("0.30")) >= 0) {
-            return "寤鸿鎵ц鍙屽懆鍌敹鏈哄埗锛屽悓姝ヨ储鍔′笌涓氬姟鑱斿悎璺熻繘閲嶇偣鍚堝悓銆�";
-        }
-        return "淇濇寔姝e父鍌敹鑺傚锛屾寜鍚堝悓鑺傜偣鎻愬墠3澶╂彁閱掑鎴蜂粯娆俱��";
-    }
-
-    private String buildQuotationStrategy(CustomerRiskMetric metric) {
-        if ("high".equals(metric.getRiskLevel())) {
-            return "鎶ヤ环浼樺厛淇濇瘺鍒╀笌鍥炴鏉℃锛屽噺灏戣秴闀胯处鏈燂紝蹇呰鏃堕噰鐢ㄥ垎闃舵鎶ヤ环銆�";
-        }
-        if (metric.getQuoteCount() > 0 && metric.getOrderCount() < metric.getQuoteCount()) {
-            return "浼樺寲鎶ヤ环缁撴瀯锛屽缓璁彁渚涘熀纭�鐗�+鍗囩骇鐗堢粍鍚堟姤浠凤紝鎻愰珮杞寲鐜囥��";
-        }
-        if (metric.getOrderCount() <= 1) {
-            return "鍔犲己闇�姹傛寲鎺橈紝鍥寸粫瀹㈡埛鍦烘櫙琛ュ厖澧炲�奸」涓庝氦浠樹繚闅滄潯娆俱��";
-        }
-        return "淇濇寔褰撳墠鎶ヤ环绛栫暐锛岄噸鐐瑰洿缁曚氦鏈熷拰鏈嶅姟鑳藉姏鍋氬樊寮傚寲鍛堢幇銆�";
-    }
-
-    private String buildNextAction(String priority) {
-        return switch (priority) {
-            case "high" -> "48灏忔椂鍐呭畬鎴愬鎴峰洖璁匡紝纭鍥炴璁″垝骞跺鏍告姤浠锋湁鏁堟湡銆�";
-            case "medium" -> "鏈懆鍐呭畬鎴愬鎴烽渶姹傚鐩橈紝鏇存柊鎶ヤ环鐗堟湰骞跺悓姝ュ洖娆捐妭鐐广��";
-            default -> "淇濇寔鏈堝害渚嬭璺熻繘锛屾寔缁拷韪鎴烽噰璐鍒掑彉鍖栥��";
-        };
-    }
-
-    private String strategyPriority(CustomerRiskMetric metric) {
-        if ("high".equals(metric.getRiskLevel()) || metric.getPendingRate().compareTo(new BigDecimal("0.50")) >= 0) {
-            return "high";
-        }
-        if ("medium".equals(metric.getRiskLevel()) || metric.getPendingRate().compareTo(new BigDecimal("0.30")) >= 0) {
-            return "medium";
-        }
-        return "low";
-    }
-
-    private int riskLevelRank(String riskLevel) {
-        if ("high".equals(riskLevel)) {
-            return 3;
-        }
-        if ("medium".equals(riskLevel)) {
-            return 2;
-        }
-        return 1;
-    }
-
-    private List<Map<String, Object>> buildTopCustomers(List<SalesLedger> ledgers) {
-        Map<String, BigDecimal> grouped = new LinkedHashMap<>();
-        for (SalesLedger ledger : ledgers) {
-            String customerName = StringUtils.hasText(ledger.getCustomerName()) ? ledger.getCustomerName().trim() : "鏈煡瀹㈡埛";
-            grouped.merge(customerName, defaultDecimal(ledger.getContractAmount()), BigDecimal::add);
-        }
-        return grouped.entrySet().stream()
-                .sorted(Map.Entry.<String, BigDecimal>comparingByValue().reversed())
-                .limit(5)
-                .map(entry -> {
-                    Map<String, Object> map = new LinkedHashMap<>();
-                    map.put("customerName", entry.getKey());
-                    map.put("contractAmount", entry.getValue());
-                    return map;
-                })
-                .collect(Collectors.toList());
-    }
-
-    private TrendData buildContractTrendData(List<SalesLedger> ledgers, DateRange range) {
-        Map<String, BigDecimal> amountByMonth = new LinkedHashMap<>();
-        YearMonth startMonth = YearMonth.from(range.start());
-        YearMonth endMonth = YearMonth.from(range.end());
-        for (YearMonth month = startMonth; !month.isAfter(endMonth); month = month.plusMonths(1)) {
-            amountByMonth.put(month.toString(), BigDecimal.ZERO);
-        }
-        for (SalesLedger ledger : ledgers) {
-            LocalDate entryDate = toLocalDate(ledger.getEntryDate());
-            if (entryDate == null) {
-                continue;
-            }
-            String monthKey = YearMonth.from(entryDate).toString();
-            if (!amountByMonth.containsKey(monthKey)) {
-                continue;
-            }
-            amountByMonth.put(monthKey, amountByMonth.get(monthKey).add(defaultDecimal(ledger.getContractAmount())));
-        }
-        return new TrendData(new ArrayList<>(amountByMonth.keySet()), new ArrayList<>(amountByMonth.values()));
-    }
-
-    private List<SalesLedger> querySalesLedgers(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<SalesLedger> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), SalesLedger::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), SalesLedger::getDeptId);
-        if (range != null) {
-            wrapper.ge(SalesLedger::getEntryDate, toDate(range.start()))
-                    .lt(SalesLedger::getEntryDate, toExclusiveEndDate(range.end()));
-        }
-        return defaultList(salesLedgerMapper.selectList(wrapper));
-    }
-
-    private List<SalesQuotation> querySalesQuotations(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<SalesQuotation> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), SalesQuotation::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), SalesQuotation::getDeptId);
-        if (range != null) {
-            wrapper.ge(SalesQuotation::getQuotationDate, range.start())
-                    .le(SalesQuotation::getQuotationDate, range.end());
-        }
-        return defaultList(salesQuotationMapper.selectList(wrapper));
-    }
-
-    private List<ShippingInfo> queryShippings(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<ShippingInfo> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), ShippingInfo::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ShippingInfo::getDeptId);
-        if (range != null) {
-            wrapper.ge(ShippingInfo::getShippingDate, toDate(range.start()))
-                    .lt(ShippingInfo::getShippingDate, toExclusiveEndDate(range.end()));
-        }
-        return defaultList(shippingInfoMapper.selectList(wrapper));
-    }
-
-    private List<ShippingInfo> queryShippingsByLedgerIds(LoginUser loginUser, List<Long> ledgerIds) {
-        if (ledgerIds == null || ledgerIds.isEmpty()) {
-            return List.of();
-        }
-        LambdaQueryWrapper<ShippingInfo> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), ShippingInfo::getTenantId);
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ShippingInfo::getDeptId);
-        wrapper.in(ShippingInfo::getSalesLedgerId, ledgerIds);
-        return defaultList(shippingInfoMapper.selectList(wrapper));
-    }
-
-    private Map<Long, BigDecimal> sumInvoiceAmounts(List<Long> ledgerIds) {
-        if (ledgerIds == null || ledgerIds.isEmpty()) {
-            return Map.of();
-        }
-        Map<Long, BigDecimal> result = new HashMap<>();
-        return result;
-    }
-
-    private Map<Long, BigDecimal> sumReceiptAmounts(LoginUser loginUser, List<Long> ledgerIds) {
-        if (ledgerIds == null || ledgerIds.isEmpty()) {
-            return Map.of();
-        }
-        List<SalesLedger> ledgers = defaultList(salesLedgerMapper.selectBatchIds(ledgerIds)).stream()
-                .filter(ledger -> tenantMatched(ledger.getTenantId(), loginUser.getTenantId()))
-                .collect(Collectors.toList());
-        if (ledgers.isEmpty()) {
-            return Map.of();
-        }
-
-        Set<Integer> customerIds = ledgers.stream()
-                .map(SalesLedger::getCustomerId)
-                .filter(Objects::nonNull)
-                .map(Long::intValue)
-                .collect(Collectors.toSet());
-        if (customerIds.isEmpty()) {
-            return Map.of();
-        }
-
-        LambdaQueryWrapper<AccountSalesCollection> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), AccountSalesCollection::getDeptId);
-        wrapper.in(AccountSalesCollection::getCustomerId, customerIds);
-        List<AccountSalesCollection> collections = defaultList(accountSalesCollectionMapper.selectList(wrapper));
-        if (collections.isEmpty()) {
-            return Map.of();
-        }
-
-        Map<Integer, Set<Long>> ledgerIdsByCollectionId = mapCollectionLedgerIds(loginUser, collections);
-        Map<Long, List<Long>> ledgerIdsByCustomerId = ledgers.stream()
-                .filter(item -> item.getId() != null && item.getCustomerId() != null)
-                .collect(Collectors.groupingBy(item -> item.getCustomerId().longValue(),
-                        Collectors.mapping(SalesLedger::getId, Collectors.toList())));
-        Set<Long> targetLedgerIdSet = new HashSet<>(ledgerIds);
-
-        Map<Long, BigDecimal> result = new HashMap<>();
-        for (AccountSalesCollection collection : collections) {
-            BigDecimal amount = defaultDecimal(collection.getCollectionAmount());
-            if (amount.compareTo(BigDecimal.ZERO) == 0) {
-                continue;
-            }
-            Set<Long> relatedLedgerIds = ledgerIdsByCollectionId.getOrDefault(collection.getId(), Set.of());
-            if (!relatedLedgerIds.isEmpty()) {
-                for (Long ledgerId : relatedLedgerIds) {
-                    if (targetLedgerIdSet.contains(ledgerId)) {
-                        result.merge(ledgerId, amount, BigDecimal::add);
-                    }
-                }
-                continue;
-            }
-            if (collection.getCustomerId() == null) {
-                continue;
-            }
-            List<Long> customerLedgerIds = ledgerIdsByCustomerId.get(collection.getCustomerId().longValue());
-            if (customerLedgerIds == null || customerLedgerIds.isEmpty()) {
-                continue;
-            }
-            for (Long ledgerId : customerLedgerIds) {
-                if (targetLedgerIdSet.contains(ledgerId)) {
-                    result.merge(ledgerId, amount, BigDecimal::add);
-                }
-            }
-        }
-        return result;
-    }
-
-    private List<AccountSalesCollection> queryCollections(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<AccountSalesCollection> wrapper = new LambdaQueryWrapper<>();
-        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), AccountSalesCollection::getDeptId);
-        if (range != null) {
-            wrapper.ge(AccountSalesCollection::getCollectionDate, range.start())
-                    .le(AccountSalesCollection::getCollectionDate, range.end());
-        }
-        wrapper.orderByDesc(AccountSalesCollection::getCollectionDate, AccountSalesCollection::getId);
-        return defaultList(accountSalesCollectionMapper.selectList(wrapper));
-    }
-
-    private Map<Integer, Set<Long>> mapCollectionLedgerIds(LoginUser loginUser, List<AccountSalesCollection> collections) {
-        Map<Integer, Set<Long>> result = new HashMap<>();
-        if (collections == null || collections.isEmpty()) {
-            return result;
-        }
-
-        Map<Integer, List<Long>> stockOutRecordIdsByCollection = new HashMap<>();
-        Set<Long> allStockOutRecordIds = new HashSet<>();
-        for (AccountSalesCollection collection : collections) {
-            if (collection.getId() == null) {
-                continue;
-            }
-            List<Long> stockOutRecordIds = parseLongIds(collection.getStockOutRecordIds());
-            if (stockOutRecordIds.isEmpty()) {
-                continue;
-            }
-            stockOutRecordIdsByCollection.put(collection.getId(), stockOutRecordIds);
-            allStockOutRecordIds.addAll(stockOutRecordIds);
-        }
-        if (allStockOutRecordIds.isEmpty()) {
-            return result;
-        }
-
-        List<StockOutRecord> stockOutRecords = defaultList(stockOutRecordMapper.selectList(new LambdaQueryWrapper<StockOutRecord>()
-                .in(StockOutRecord::getId, allStockOutRecordIds)));
-        if (stockOutRecords.isEmpty()) {
-            return result;
-        }
-        Map<Long, StockOutRecord> stockOutRecordMap = stockOutRecords.stream()
-                .filter(item -> item.getId() != null)
-                .collect(Collectors.toMap(StockOutRecord::getId, item -> item, (a, b) -> a));
-
-        Set<Long> shippingIds = stockOutRecords.stream()
-                .filter(this::isSalesOutboundRecord)
-                .map(StockOutRecord::getRecordId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        if (shippingIds.isEmpty()) {
-            return result;
-        }
-
-        LambdaQueryWrapper<ShippingInfo> shippingWrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(shippingWrapper, loginUser.getTenantId(), ShippingInfo::getTenantId);
-        applyDeptFilter(shippingWrapper, loginUser.getCurrentDeptId(), ShippingInfo::getDeptId);
-        shippingWrapper.in(ShippingInfo::getId, shippingIds);
-        Map<Long, Long> ledgerIdByShippingId = defaultList(shippingInfoMapper.selectList(shippingWrapper)).stream()
-                .filter(item -> item.getId() != null && item.getSalesLedgerId() != null)
-                .collect(Collectors.toMap(ShippingInfo::getId, ShippingInfo::getSalesLedgerId, (a, b) -> a));
-
-        for (Map.Entry<Integer, List<Long>> entry : stockOutRecordIdsByCollection.entrySet()) {
-            Set<Long> ledgerIds = new LinkedHashSet<>();
-            for (Long stockOutRecordId : entry.getValue()) {
-                StockOutRecord stockOutRecord = stockOutRecordMap.get(stockOutRecordId);
-                if (!isSalesOutboundRecord(stockOutRecord)) {
-                    continue;
-                }
-                Long ledgerId = ledgerIdByShippingId.get(stockOutRecord.getRecordId());
-                if (ledgerId != null) {
-                    ledgerIds.add(ledgerId);
-                }
-            }
-            if (!ledgerIds.isEmpty()) {
-                result.put(entry.getKey(), ledgerIds);
-            }
-        }
-        return result;
-    }
-
-    private boolean isSalesOutboundRecord(StockOutRecord stockOutRecord) {
-        if (stockOutRecord == null || !StringUtils.hasText(stockOutRecord.getRecordType())) {
-            return false;
-        }
-        if (stockOutRecord.getApprovalStatus() != null && stockOutRecord.getApprovalStatus() != 1) {
-            return false;
-        }
-        return "13".equals(stockOutRecord.getRecordType().trim());
-    }
-
-    private List<Long> parseLongIds(String raw) {
-        if (!StringUtils.hasText(raw)) {
-            return List.of();
-        }
-        List<Long> result = new ArrayList<>();
-        for (String part : raw.split(",")) {
-            if (!StringUtils.hasText(part)) {
-                continue;
-            }
-            try {
-                result.add(Long.parseLong(part.trim()));
-            } catch (Exception ignored) {
-            }
-        }
-        return result;
-    }
-
-    private boolean matchInteractionKeyword(AccountSalesCollection collection, SalesLedger ledger, String keyword) {
-        if (!StringUtils.hasText(keyword)) {
-            return true;
-        }
-        String text = keyword.trim();
-        if (safe(collection.getCollectionNumber()).contains(text)
-                || safe(collection.getCollectionMethod()).contains(text)
-                || safe(collection.getRemark()).contains(text)) {
-            return true;
-        }
-        if (ledger == null) {
-            return false;
-        }
-        return safe(ledger.getSalesContractNo()).contains(text)
-                || safe(ledger.getCustomerName()).contains(text)
-                || safe(ledger.getProjectName()).contains(text);
-    }
-
-    private Map<String, Object> toInteractionItem(AccountSalesCollection collection, SalesLedger ledger) {
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("id", collection.getId());
-        map.put("salesLedgerId", ledger == null ? null : ledger.getId());
-        map.put("salesContractNo", ledger == null ? "" : safe(ledger.getSalesContractNo()));
-        map.put("customerName", ledger == null ? "" : safe(ledger.getCustomerName()));
-        map.put("projectName", ledger == null ? "" : safe(ledger.getProjectName()));
-        map.put("receiptPaymentDate", formatDate(collection.getCollectionDate()));
-        map.put("receiptPaymentAmount", collection.getCollectionAmount());
-        map.put("receiptPaymentType", safe(collection.getCollectionMethod()));
-        map.put("collectionNumber", safe(collection.getCollectionNumber()));
-        map.put("registrant", collection.getCreateUser());
-        map.put("remark", safe(collection.getRemark()));
-        return map;
-    }
-
-    private boolean isLedgerFullyShipped(Long ledgerId, Map<Long, List<ShippingInfo>> shippingByLedgerId) {
-        List<ShippingInfo> shippingInfos = shippingByLedgerId.get(ledgerId);
-        if (shippingInfos == null || shippingInfos.isEmpty()) {
-            return false;
-        }
-        return shippingInfos.stream().allMatch(item -> isShippedStatus(item.getStatus()));
-    }
-
-    private String calcLedgerShippingStatus(List<ShippingInfo> shippingInfos) {
-        if (shippingInfos == null || shippingInfos.isEmpty()) {
-            return "鏈彂璐�";
-        }
-        long shippedCount = shippingInfos.stream().filter(item -> isShippedStatus(item.getStatus())).count();
-        if (shippedCount == 0) {
-            return "寰呭彂璐�";
-        }
-        if (shippedCount == shippingInfos.size()) {
-            return "宸插彂璐�";
-        }
-        return "閮ㄥ垎鍙戣揣";
-    }
-
-    private boolean isShippedStatus(String status) {
-        return StringUtils.hasText(status) && status.contains("宸插彂璐�");
-    }
-
-    private boolean matchCustomerKeyword(CustomerVo customer, String keyword) {
-        if (!StringUtils.hasText(keyword)) {
-            return true;
-        }
-        String text = keyword.trim();
-        return safe(customer.getCustomerName()).contains(text)
-                || safe(customer.getContactPerson()).contains(text)
-                || safe(customer.getContactPhone()).contains(text)
-                || safe(customer.getCompanyPhone()).contains(text)
-                || safe(customer.getUsageUserName()).contains(text);
-    }
-
-    private boolean matchLedgerCustomerKeyword(SalesLedger ledger, String keyword) {
-        if (!StringUtils.hasText(keyword)) {
-            return true;
-        }
-        String text = keyword.trim();
-        return safe(ledger.getCustomerName()).contains(text)
-                || safe(ledger.getSalesContractNo()).contains(text)
-                || safe(ledger.getProjectName()).contains(text);
-    }
-
-    private Integer normalizeSeaType(String seaType) {
-        if (!StringUtils.hasText(seaType)) {
-            return null;
-        }
-        String value = seaType.trim().toLowerCase(Locale.ROOT);
-        return switch (value) {
-            case "private", "绉佹捣", "0" -> 0;
-            case "public", "鍏捣", "1" -> 1;
-            default -> null;
-        };
-    }
-
-    private String customerSeaTypeName(Integer type) {
-        if (type == null) {
-            return "鏈煡";
-        }
-        return type == 1 ? "鍏捣" : "绉佹捣";
-    }
-
-    private int normalizeLimit(Integer limit) {
-        if (limit == null || limit <= 0) {
-            return DEFAULT_LIMIT;
-        }
-        return Math.min(limit, MAX_LIMIT);
-    }
-
-    private boolean tenantMatched(Long dataTenantId, Long userTenantId) {
-        if (userTenantId == null) {
-            return true;
-        }
-        return Objects.equals(dataTenantId, userTenantId);
-    }
-
-    private <T> void applyTenantFilter(LambdaQueryWrapper<T> wrapper, Long tenantId, SFunction<T, Long> field) {
-        if (tenantId != null) {
-            wrapper.eq(field, tenantId);
-        }
-    }
-
-    private <T> void applyDeptFilter(LambdaQueryWrapper<T> wrapper, Long deptId, SFunction<T, Long> field) {
-        if (deptId != null) {
-            wrapper.eq(field, deptId);
-        }
-    }
-
-    private LoginUser currentLoginUser(String memoryId) {
-        LoginUser loginUser = aiSessionUserContext.get(memoryId);
-        if (loginUser != null) {
-            return loginUser;
-        }
-        return SecurityUtils.getLoginUser();
-    }
-
-    private DateRange resolveDateRange(String startDate, String endDate, String timeRange) {
-        LocalDate today = LocalDate.now();
-        LocalDate explicitStart = parseLocalDate(startDate);
-        LocalDate explicitEnd = parseLocalDate(endDate);
-        if (explicitStart != null || explicitEnd != null) {
-            LocalDate start = explicitStart != null ? explicitStart : explicitEnd;
-            LocalDate end = explicitEnd != null ? explicitEnd : explicitStart;
-            if (start.isAfter(end)) {
-                LocalDate temp = start;
-                start = end;
-                end = temp;
-            }
-            return new DateRange(start, end, start + "鑷�" + end);
-        }
-        if (!StringUtils.hasText(timeRange)) {
-            return new DateRange(today.minusDays(29), today, "杩�30澶�");
-        }
-        String text = timeRange.trim();
-        if (text.contains("浠婂ぉ")) {
-            return new DateRange(today, today, "浠婂ぉ");
-        }
-        if (text.contains("鏄ㄥぉ") || text.contains("鏄ㄦ棩")) {
-            LocalDate day = today.minusDays(1);
-            return new DateRange(day, day, "鏄ㄥぉ");
-        }
-        if (text.contains("鏈懆")) {
-            LocalDate start = today.minusDays(today.getDayOfWeek().getValue() - 1L);
-            return new DateRange(start, today, "鏈懆");
-        }
-        if (text.contains("涓婂懆")) {
-            LocalDate thisWeekStart = today.minusDays(today.getDayOfWeek().getValue() - 1L);
-            LocalDate start = thisWeekStart.minusWeeks(1);
-            LocalDate end = thisWeekStart.minusDays(1);
-            return new DateRange(start, end, "涓婂懆");
-        }
-        if (text.contains("鏈湀")) {
-            return new DateRange(today.withDayOfMonth(1), today, "鏈湀");
-        }
-        if (text.contains("涓婃湀")) {
-            YearMonth lastMonth = YearMonth.from(today).minusMonths(1);
-            return new DateRange(lastMonth.atDay(1), lastMonth.atEndOfMonth(), "涓婃湀");
-        }
-        if (text.contains("浠婂勾") || text.contains("鏈勾")) {
-            return new DateRange(today.withDayOfYear(1), today, "浠婂勾");
-        }
-        if (text.contains("鍘诲勾")) {
-            LocalDate start = today.minusYears(1).withDayOfYear(1);
-            LocalDate end = today.minusYears(1).withMonth(12).withDayOfMonth(31);
-            return new DateRange(start, end, "鍘诲勾");
-        }
-        Matcher relativeMatcher = RELATIVE_PATTERN.matcher(text);
-        if (relativeMatcher.find()) {
-            int amount = Integer.parseInt(relativeMatcher.group(2));
-            String unit = relativeMatcher.group(3);
-            LocalDate start = switch (unit) {
-                case "澶�" -> today.minusDays(Math.max(amount - 1L, 0));
-                case "鍛�" -> today.minusWeeks(Math.max(amount, 1)).plusDays(1);
-                case "涓湀", "鏈�" -> today.minusMonths(Math.max(amount, 1)).plusDays(1);
-                case "骞�" -> today.minusYears(Math.max(amount, 1)).plusDays(1);
-                default -> today.minusDays(29);
-            };
-            return new DateRange(start, today, "杩�" + amount + unit);
-        }
-        Matcher dateMatcher = DATE_PATTERN.matcher(text);
-        if (dateMatcher.find()) {
-            LocalDate start = parseLocalDate(dateMatcher.group(1));
-            LocalDate end = dateMatcher.find() ? parseLocalDate(dateMatcher.group(1)) : start;
-            if (start != null && end != null) {
-                if (start.isAfter(end)) {
-                    LocalDate temp = start;
-                    start = end;
-                    end = temp;
-                }
-                return new DateRange(start, end, start + "鑷�" + end);
-            }
-        }
-        return new DateRange(today.minusDays(29), today, "杩�30澶�");
-    }
-
-    private LocalDate parseLocalDate(String text) {
-        if (!StringUtils.hasText(text)) {
-            return null;
-        }
-        try {
-            return LocalDate.parse(text.trim(), DATE_FMT);
-        } catch (Exception ignored) {
-            return null;
-        }
-    }
-
-    private Date toDate(LocalDate localDate) {
-        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
-    }
-
-    private Date toExclusiveEndDate(LocalDate localDate) {
-        return Date.from(localDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
-    }
-
-    private LocalDate toLocalDate(Date date) {
-        if (date == null) {
-            return null;
-        }
-        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
-    }
-
-    private String formatDate(Date date) {
-        LocalDate localDate = toLocalDate(date);
-        return formatDate(localDate);
-    }
-
-    private String formatDate(LocalDate date) {
-        return date == null ? "" : date.format(DATE_FMT);
-    }
-
-    private String formatDateTime(LocalDateTime time) {
-        return time == null ? "" : time.toString().replace('T', ' ');
-    }
-
-    private BigDecimal defaultDecimal(BigDecimal value) {
-        return value == null ? BigDecimal.ZERO : value;
-    }
-
-    private BigDecimal asBigDecimal(Object value) {
-        if (value == null) {
-            return BigDecimal.ZERO;
-        }
-        if (value instanceof BigDecimal decimal) {
-            return decimal;
-        }
-        if (value instanceof Number number) {
-            return new BigDecimal(String.valueOf(number));
-        }
-        try {
-            return new BigDecimal(String.valueOf(value));
-        } catch (Exception ignored) {
-            return BigDecimal.ZERO;
-        }
-    }
-
-    private BigDecimal maxZero(BigDecimal value) {
-        return value == null || value.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : value;
-    }
-
-    private String toRate(long numerator, long denominator) {
-        if (denominator <= 0) {
-            return "0.00%";
-        }
-        BigDecimal rate = new BigDecimal(numerator)
-                .multiply(ONE_HUNDRED)
-                .divide(new BigDecimal(denominator), 2, RoundingMode.HALF_UP);
-        return rate.toPlainString() + "%";
-    }
-
-    private String toPercent(BigDecimal decimal) {
-        if (decimal == null) {
-            return "0.00%";
-        }
-        BigDecimal rate = decimal.multiply(ONE_HUNDRED).setScale(2, RoundingMode.HALF_UP);
-        return rate.toPlainString() + "%";
-    }
-
-    private String safe(Object value) {
-        return value == null ? "" : String.valueOf(value).replace('\n', ' ').replace('\r', ' ').trim();
-    }
-
-    private <T> List<T> defaultList(List<T> list) {
-        return list == null ? List.of() : list;
-    }
-
-    private Map<String, Object> rangeSummary(DateRange range, int count, String keyword) {
-        Map<String, Object> summary = new LinkedHashMap<>();
-        summary.put("timeRange", range.label());
-        summary.put("startDate", range.start().toString());
-        summary.put("endDate", range.end().toString());
-        summary.put("count", count);
-        summary.put("keyword", safe(keyword));
-        return summary;
-    }
-
-    private Map<String, Object> buildAmountBarOption(BigDecimal contractAmount,
-                                                      BigDecimal quotationAmount,
-                                                      BigDecimal receivedAmount,
-                                                      BigDecimal pendingAmount) {
-        List<String> xData = List.of("鍚堝悓棰�", "鎶ヤ环棰�", "鍥炴棰�", "寰呭洖娆�");
-        List<BigDecimal> yData = List.of(contractAmount, quotationAmount, receivedAmount, pendingAmount);
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "閿�鍞粡钀ラ噾棰濇瑙�", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", xData));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of("name", "閲戦", "type", "bar", "data", yData)));
-        return option;
-    }
-
-    private Map<String, Object> buildShippingPieOption(long shippedCount, long pendingCount) {
-        List<Map<String, Object>> data = List.of(
-                Map.of("name", "宸插彂璐�", "value", shippedCount),
-                Map.of("name", "鏈彂璐�", "value", pendingCount)
-        );
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "鍙戣揣鐘舵�佸垎甯�", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "item"));
-        option.put("series", List.of(Map.of("type", "pie", "radius", "60%", "data", data)));
-        return option;
-    }
-
-    private Map<String, Object> buildCustomerTopBarOption(List<Map<String, Object>> topCustomers) {
-        List<String> xData = new ArrayList<>();
-        List<BigDecimal> yData = new ArrayList<>();
-        for (Map<String, Object> item : topCustomers) {
-            xData.add(String.valueOf(item.get("customerName")));
-            yData.add((BigDecimal) item.get("contractAmount"));
-        }
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "瀹㈡埛鍚堝悓棰漈OP5", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", xData));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of("name", "鍚堝悓棰�", "type", "bar", "data", yData)));
-        return option;
-    }
-
-    private Map<String, Object> buildContractTrendLineOption(List<String> labels, List<BigDecimal> values) {
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "鍚堝悓棰濇湀搴﹁秼鍔�", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", labels));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of("name", "鍚堝悓棰�", "type", "line", "smooth", true, "data", values)));
-        return option;
-    }
-
-    private Map<String, Object> buildRiskLevelPieOption(long highCount, long mediumCount, long lowCount) {
-        List<Map<String, Object>> data = List.of(
-                Map.of("name", "楂橀闄�", "value", highCount),
-                Map.of("name", "涓闄�", "value", mediumCount),
-                Map.of("name", "浣庨闄�", "value", lowCount)
-        );
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "瀹㈡埛椋庨櫓绛夌骇鍒嗗竷", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "item"));
-        option.put("series", List.of(Map.of("name", "椋庨櫓绛夌骇", "type", "pie", "radius", "60%", "data", data)));
-        return option;
-    }
-
-    private Map<String, Object> buildRiskScoreBarOption(List<CustomerRiskMetric> metrics) {
-        List<String> xData = metrics.stream().map(CustomerRiskMetric::getCustomerName).collect(Collectors.toList());
-        List<Integer> yData = metrics.stream().map(CustomerRiskMetric::getRiskScore).collect(Collectors.toList());
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "瀹㈡埛椋庨櫓鍒嗗��", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", xData));
-        option.put("yAxis", Map.of("type", "value", "max", 100));
-        option.put("series", List.of(Map.of("name", "椋庨櫓鍒嗗��", "type", "bar", "data", yData)));
-        return option;
-    }
-
-    private Map<String, Object> buildPendingAmountBarOption(List<CustomerRiskMetric> metrics) {
-        List<String> xData = metrics.stream().map(CustomerRiskMetric::getCustomerName).collect(Collectors.toList());
-        List<BigDecimal> yData = metrics.stream().map(CustomerRiskMetric::getPendingAmount).collect(Collectors.toList());
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "瀹㈡埛寰呭洖娆炬帓鍚�", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "axis"));
-        option.put("xAxis", Map.of("type", "category", "data", xData));
-        option.put("yAxis", Map.of("type", "value"));
-        option.put("series", List.of(Map.of("name", "寰呭洖娆�", "type", "bar", "data", yData)));
-        return option;
-    }
-
-    private Map<String, Object> buildPriorityPieOption(long high, long medium, long low) {
-        List<Map<String, Object>> data = List.of(
-                Map.of("name", "楂樹紭鍏堢骇", "value", high),
-                Map.of("name", "涓紭鍏堢骇", "value", medium),
-                Map.of("name", "浣庝紭鍏堢骇", "value", low)
-        );
-        Map<String, Object> option = new LinkedHashMap<>();
-        option.put("title", Map.of("text", "绛栫暐浼樺厛绾у垎甯�", "left", "center"));
-        option.put("tooltip", Map.of("trigger", "item"));
-        option.put("series", List.of(Map.of("name", "浼樺厛绾�", "type", "pie", "radius", "60%", "data", data)));
-        return option;
-    }
-
-    private String jsonResponse(boolean success,
-                                String type,
-                                String description,
-                                Map<String, Object> summary,
-                                Map<String, Object> data,
-                                Map<String, Object> charts) {
-        Map<String, Object> result = new LinkedHashMap<>();
-        result.put("success", success);
-        result.put("type", type);
-        result.put("description", description);
-        result.put("summary", summary == null ? Map.of() : summary);
-        result.put("data", data == null ? Map.of() : data);
-        result.put("charts", charts == null ? Map.of() : charts);
-        return JSON.toJSONString(result);
-    }
-
-    private record DateRange(LocalDate start, LocalDate end, String label) {
-    }
-
-    private record TrendData(List<String> labels, List<BigDecimal> values) {
-        private List<Map<String, Object>> toItemList() {
-            List<Map<String, Object>> items = new LinkedList<>();
-            for (int i = 0; i < labels.size(); i++) {
-                Map<String, Object> item = new LinkedHashMap<>();
-                item.put("month", labels.get(i));
-                item.put("amount", values.get(i));
-                items.add(item);
-            }
-            return items;
-        }
-    }
-
-    private static class CustomerRiskMetric {
-        private final String customerName;
-        private final List<Long> ledgerIds = new ArrayList<>();
-        private final Map<Long, LocalDate> deliveryDateByLedgerId = new HashMap<>();
-        private BigDecimal contractAmount = BigDecimal.ZERO;
-        private BigDecimal receivedAmount = BigDecimal.ZERO;
-        private BigDecimal pendingAmount = BigDecimal.ZERO;
-        private BigDecimal pendingRate = BigDecimal.ZERO;
-        private BigDecimal quoteAmount = BigDecimal.ZERO;
-        private BigDecimal topSingleOrderAmount = BigDecimal.ZERO;
-        private int orderCount;
-        private int quoteCount;
-        private LocalDate lastOrderDate;
-        private long daysSinceLastOrder;
-        private long overdueDeliveryCount;
-        private int riskScore;
-        private String riskLevel = "low";
-        private List<String> riskReasons = new ArrayList<>();
-
-        private CustomerRiskMetric(String customerName) {
-            this.customerName = customerName;
-        }
-
-        private String getCustomerName() {
-            return customerName;
-        }
-
-        private List<Long> getLedgerIds() {
-            return ledgerIds;
-        }
-
-        private Map<Long, LocalDate> getDeliveryDateByLedgerId() {
-            return deliveryDateByLedgerId;
-        }
-
-        private BigDecimal getContractAmount() {
-            return contractAmount;
-        }
-
-        private void setContractAmount(BigDecimal contractAmount) {
-            this.contractAmount = contractAmount;
-        }
-
-        private BigDecimal getReceivedAmount() {
-            return receivedAmount;
-        }
-
-        private void setReceivedAmount(BigDecimal receivedAmount) {
-            this.receivedAmount = receivedAmount;
-        }
-
-        private BigDecimal getPendingAmount() {
-            return pendingAmount;
-        }
-
-        private void setPendingAmount(BigDecimal pendingAmount) {
-            this.pendingAmount = pendingAmount;
-        }
-
-        private BigDecimal getPendingRate() {
-            return pendingRate;
-        }
-
-        private void setPendingRate(BigDecimal pendingRate) {
-            this.pendingRate = pendingRate;
-        }
-
-        private BigDecimal getQuoteAmount() {
-            return quoteAmount;
-        }
-
-        private void setQuoteAmount(BigDecimal quoteAmount) {
-            this.quoteAmount = quoteAmount;
-        }
-
-        private BigDecimal getTopSingleOrderAmount() {
-            return topSingleOrderAmount;
-        }
-
-        private void setTopSingleOrderAmount(BigDecimal topSingleOrderAmount) {
-            this.topSingleOrderAmount = topSingleOrderAmount;
-        }
-
-        private int getOrderCount() {
-            return orderCount;
-        }
-
-        private void setOrderCount(int orderCount) {
-            this.orderCount = orderCount;
-        }
-
-        private int getQuoteCount() {
-            return quoteCount;
-        }
-
-        private void setQuoteCount(int quoteCount) {
-            this.quoteCount = quoteCount;
-        }
-
-        private LocalDate getLastOrderDate() {
-            return lastOrderDate;
-        }
-
-        private void setLastOrderDate(LocalDate lastOrderDate) {
-            this.lastOrderDate = lastOrderDate;
-        }
-
-        private long getDaysSinceLastOrder() {
-            return daysSinceLastOrder;
-        }
-
-        private void setDaysSinceLastOrder(long daysSinceLastOrder) {
-            this.daysSinceLastOrder = daysSinceLastOrder;
-        }
-
-        private long getOverdueDeliveryCount() {
-            return overdueDeliveryCount;
-        }
-
-        private void setOverdueDeliveryCount(long overdueDeliveryCount) {
-            this.overdueDeliveryCount = overdueDeliveryCount;
-        }
-
-        private int getRiskScore() {
-            return riskScore;
-        }
-
-        private void setRiskScore(int riskScore) {
-            this.riskScore = riskScore;
-        }
-
-        private String getRiskLevel() {
-            return riskLevel;
-        }
-
-        private void setRiskLevel(String riskLevel) {
-            this.riskLevel = riskLevel;
-        }
-
-        private List<String> getRiskReasons() {
-            return riskReasons;
-        }
-
-        private void setRiskReasons(List<String> riskReasons) {
-            this.riskReasons = riskReasons;
-        }
-    }
-}
diff --git a/src/main/java/com/ruoyi/approve/bean/dto/ApprovalInstanceDto.java b/src/main/java/com/ruoyi/approve/bean/dto/ApprovalInstanceDto.java
deleted file mode 100644
index a2df482..0000000
--- a/src/main/java/com/ruoyi/approve/bean/dto/ApprovalInstanceDto.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.ruoyi.approve.bean.dto;
-
-import com.ruoyi.approve.pojo.ApprovalInstance;
-import com.ruoyi.basic.dto.StorageBlobDTO;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class ApprovalInstanceDto extends ApprovalInstance {
-
-    private String approveAction;
-
-    private String approveComment;
-
-    private String createTimeEnd;
-
-    private String createTimeStart;
-
-    private List<StorageBlobDTO> storageBlobDTOs;
-}
diff --git a/src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateDto.java b/src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateDto.java
deleted file mode 100644
index 668bc8c..0000000
--- a/src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateDto.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.ruoyi.approve.bean.dto;
-
-import com.ruoyi.approve.pojo.ApprovalTemplate;
-import com.ruoyi.basic.dto.StorageBlobDTO;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class ApprovalTemplateDto  extends ApprovalTemplate {
-
-    private List<ApprovalTemplateNodeDto> nodes;
-
-    private List<StorageBlobDTO> storageBlobDTOs;
-}
diff --git a/src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateNodeApproverDto.java b/src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateNodeApproverDto.java
deleted file mode 100644
index 8382619..0000000
--- a/src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateNodeApproverDto.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.ruoyi.approve.bean.dto;
-
-import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
-import lombok.Data;
-
-@Data
-public class ApprovalTemplateNodeApproverDto extends ApprovalTemplateNodeApprover {
-}
diff --git a/src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateNodeDto.java b/src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateNodeDto.java
deleted file mode 100644
index e85aee9..0000000
--- a/src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateNodeDto.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.ruoyi.approve.bean.dto;
-
-import com.ruoyi.approve.pojo.ApprovalTemplateNode;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class ApprovalTemplateNodeDto extends ApprovalTemplateNode {
-
-    private List<ApprovalTemplateNodeApproverDto> approvers;
-}
diff --git a/src/main/java/com/ruoyi/approve/bean/dto/FinReimbursementDto.java b/src/main/java/com/ruoyi/approve/bean/dto/FinReimbursementDto.java
deleted file mode 100644
index 2f14376..0000000
--- a/src/main/java/com/ruoyi/approve/bean/dto/FinReimbursementDto.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.ruoyi.approve.bean.dto;
-
-import com.ruoyi.approve.pojo.FinReimbursement;
-import com.ruoyi.approve.pojo.FinReimbursementDetail;
-import com.ruoyi.approve.pojo.FinReimbursementTravel;
-import com.ruoyi.basic.dto.StorageBlobDTO;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class FinReimbursementDto extends FinReimbursement {
-
-    private String createTimeStart;
-    private String createTimeEnd;
-
-    private FinReimbursementTravel  travel;
-    private List<FinReimbursementDetail> details;
-    private List<ApprovalTemplateNodeDto> nodes;
-    private List<StorageBlobDTO> storageBlobDTOs;
-}
diff --git a/src/main/java/com/ruoyi/approve/bean/vo/ApprovalInstanceVo.java b/src/main/java/com/ruoyi/approve/bean/vo/ApprovalInstanceVo.java
deleted file mode 100644
index 41ad4e4..0000000
--- a/src/main/java/com/ruoyi/approve/bean/vo/ApprovalInstanceVo.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.ruoyi.approve.bean.vo;
-
-import com.ruoyi.approve.pojo.ApprovalInstance;
-import com.ruoyi.approve.pojo.ApprovalRecord;
-import com.ruoyi.approve.pojo.ApprovalTask;
-import com.ruoyi.basic.dto.StorageBlobVO;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class ApprovalInstanceVo extends ApprovalInstance {
-    //褰撳墠鐢ㄦ埛鏄惁鍙互瀹℃壒
-    @Schema(description = "褰撳墠鐢ㄦ埛鏄惁鍙互瀹℃壒")
-    private Boolean isApprove;
-
-    //瀹℃壒娴佺▼
-    private List<ApprovalTask> tasks;
-
-    //瀹℃壒璁板綍
-    private List<ApprovalRecord>  records;
-
-    @Schema(description = "涓氬姟鍚嶇О")
-    private String businessName;
-
-    @Schema(description = "鎶ヤ环鍗曞彿")
-    private String quotationNo;
-
-    @Schema(description = "閲囪喘鍗曞彿")
-    private String purchaseContractNumber;
-
-    @Schema(description = "鍙戣揣鍗曞彿")
-    private String shippingNo;
-
-    private List<StorageBlobVO> storageBlobVOList;
-}
diff --git a/src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateNodeApproverVo.java b/src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateNodeApproverVo.java
deleted file mode 100644
index 4c0ce0f..0000000
--- a/src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateNodeApproverVo.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.ruoyi.approve.bean.vo;
-
-
-import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
-import lombok.Data;
-
-@Data
-public class ApprovalTemplateNodeApproverVo extends ApprovalTemplateNodeApprover {
-}
diff --git a/src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateNodeVo.java b/src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateNodeVo.java
deleted file mode 100644
index 9acd0af..0000000
--- a/src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateNodeVo.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.ruoyi.approve.bean.vo;
-
-
-import com.ruoyi.approve.pojo.ApprovalTemplateNode;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class ApprovalTemplateNodeVo extends ApprovalTemplateNode {
-
-    private List<ApprovalTemplateNodeApproverVo> approvers;
-}
diff --git a/src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateVo.java b/src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateVo.java
deleted file mode 100644
index 84a6904..0000000
--- a/src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateVo.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.ruoyi.approve.bean.vo;
-
-import com.ruoyi.approve.pojo.ApprovalTemplate;
-import com.ruoyi.basic.dto.StorageBlobVO;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class ApprovalTemplateVo extends ApprovalTemplate {
-
-    private List<ApprovalTemplateNodeVo> nodes;
-
-    private String createdUserName;
-
-    private List<StorageBlobVO> storageBlobDTOs;
-}
diff --git a/src/main/java/com/ruoyi/approve/bean/vo/FinReimbursementVo.java b/src/main/java/com/ruoyi/approve/bean/vo/FinReimbursementVo.java
deleted file mode 100644
index 5706ff3..0000000
--- a/src/main/java/com/ruoyi/approve/bean/vo/FinReimbursementVo.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.ruoyi.approve.bean.vo;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.approve.pojo.*;
-import com.ruoyi.basic.dto.StorageBlobVO;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.time.LocalDateTime;
-import java.util.List;
-
-@Data
-public class FinReimbursementVo extends FinReimbursement {
-
-
-    private String createTimeStart;
-    private String createTimeEnd;
-
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime startTime;
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime endTime;
-
-    private FinReimbursementTravel travel;
-    private List<FinReimbursementDetail> details;
-    //瀹℃壒娴佺▼
-    private List<ApprovalTask> tasks;
-
-    //瀹℃壒璁板綍
-    private List<ApprovalRecord>  records;
-    private List<StorageBlobVO> storageBlobVOList;
-}
diff --git a/src/main/java/com/ruoyi/approve/controller/ApprovalInstanceController.java b/src/main/java/com/ruoyi/approve/controller/ApprovalInstanceController.java
deleted file mode 100644
index 36dcfc3..0000000
--- a/src/main/java/com/ruoyi/approve/controller/ApprovalInstanceController.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.ruoyi.approve.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
-import com.ruoyi.approve.bean.vo.ApprovalInstanceVo;
-import com.ruoyi.approve.service.ApprovalInstanceService;
-import com.ruoyi.framework.aspectj.lang.annotation.Log;
-import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.R;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import lombok.AllArgsConstructor;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-/**
- * <p>
- * 瀹℃壒瀹炰緥琛� 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:27:46
- */
-@RestController
-@RequestMapping("/approvalInstance")
-@Tag(name = "瀹℃壒瀹炰緥琛�")
-@AllArgsConstructor
-public class ApprovalInstanceController extends BaseController {
-
-    private final ApprovalInstanceService approvalInstanceService;
-    @GetMapping("/listPage")
-    @Operation(summary = "鍒嗛〉鏌ヨ")
-    @Log(title = "瀹℃壒鍒楄〃鍒嗛〉鏌ヨ", businessType = BusinessType.OTHER)
-    public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) {
-        return approvalInstanceService.listPage(page, approvalInstanceDto);
-    }
-
-    @PostMapping("/save")
-    @Operation(summary = "淇濆瓨")
-    @Log(title = "瀹℃壒鍒楄〃淇濆瓨", businessType = BusinessType.INSERT)
-    public R save(@RequestBody ApprovalInstanceDto approvalInstanceDto) {
-        return approvalInstanceService.add(approvalInstanceDto) ? R.ok() : R.fail();
-    }
-
-    @PutMapping("/update")
-    @Operation(summary = "鏇存柊")
-    @Log(title = "瀹℃壒鍒楄〃鏇存柊", businessType = BusinessType.UPDATE)
-    public R update(@RequestBody ApprovalInstanceDto approvalInstanceDto) {
-        return approvalInstanceService.update(approvalInstanceDto) ? R.ok() : R.fail();
-    }
-
-    @DeleteMapping("/delete")
-    @Log(title = "瀹℃壒鍒楄〃鍒犻櫎", businessType = BusinessType.DELETE)
-    @Operation(summary = "鍒犻櫎")
-    public R delete(@RequestBody List<Long> ids) {
-        return approvalInstanceService.delete(ids) ? R.ok() : R.fail();
-    }
-
-    @Operation(summary = "瀹℃壒")
-    @PostMapping("/approve")
-    @Log(title = "瀹℃壒鍒楄〃瀹℃壒", businessType = BusinessType.UPDATE)
-    public R approve(@RequestBody ApprovalInstanceDto approvalInstanceDto) {
-        return approvalInstanceService.approve(approvalInstanceDto);
-    }
-}
diff --git a/src/main/java/com/ruoyi/approve/controller/ApprovalInstanceNodeController.java b/src/main/java/com/ruoyi/approve/controller/ApprovalInstanceNodeController.java
deleted file mode 100644
index e42af42..0000000
--- a/src/main/java/com/ruoyi/approve/controller/ApprovalInstanceNodeController.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.ruoyi.approve.controller;
-
-import com.ruoyi.framework.web.controller.BaseController;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 瀹℃壒鑺傜偣瀹炰緥琛� 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:27:54
- */
-@RestController
-@RequestMapping("/approvalInstanceNode")
-public class ApprovalInstanceNodeController extends BaseController {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/controller/ApprovalRecordController.java b/src/main/java/com/ruoyi/approve/controller/ApprovalRecordController.java
deleted file mode 100644
index 2d6f9dd..0000000
--- a/src/main/java/com/ruoyi/approve/controller/ApprovalRecordController.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.controller;
-
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 瀹℃壒璁板綍琛� 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:28:21
- */
-@RestController
-@RequestMapping("/approvalRecord")
-public class ApprovalRecordController {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/controller/ApprovalTaskController.java b/src/main/java/com/ruoyi/approve/controller/ApprovalTaskController.java
deleted file mode 100644
index 8682caa..0000000
--- a/src/main/java/com/ruoyi/approve/controller/ApprovalTaskController.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.controller;
-
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 瀹℃壒浠诲姟琛� 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:32:37
- */
-@RestController
-@RequestMapping("/approvalTask")
-public class ApprovalTaskController {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/controller/ApprovalTemplateController.java b/src/main/java/com/ruoyi/approve/controller/ApprovalTemplateController.java
deleted file mode 100644
index 674d278..0000000
--- a/src/main/java/com/ruoyi/approve/controller/ApprovalTemplateController.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.ruoyi.approve.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.approve.bean.dto.ApprovalTemplateDto;
-import com.ruoyi.approve.bean.vo.ApprovalTemplateVo;
-import com.ruoyi.approve.service.ApprovalTemplateService;
-import com.ruoyi.framework.aspectj.lang.annotation.Log;
-import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.R;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import lombok.AllArgsConstructor;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘琛� 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺嬮亾杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:08
- */
-@RestController
-@RequestMapping("/approvalTemplate")
-@Tag(name = "瀹℃壒妯℃澘琛�")
-@AllArgsConstructor
-public class ApprovalTemplateController  extends BaseController {
-
-    private final ApprovalTemplateService approvalTemplateService;
-
-    @GetMapping("/listPage")
-    @Operation(summary = "鍒嗛〉鏌ヨ")
-    @Log(title = "瀹℃壒妯℃澘鍒嗛〉鏌ヨ", businessType = BusinessType.OTHER)
-    public R listPage(Page<ApprovalTemplateVo> page, ApprovalTemplateDto approvalTemplateDto) {
-        return R.ok(approvalTemplateService.listPage(page, approvalTemplateDto));
-    }
-
-    @PostMapping("/add")
-    @Operation(summary = "娣诲姞")
-    @Log(title = "娣诲姞瀹℃壒妯℃澘", businessType = BusinessType.INSERT)
-    public R add(@RequestBody ApprovalTemplateDto approvalTemplateDto) {
-        return R.ok(approvalTemplateService.saveApprovalTemplateDto(approvalTemplateDto));
-    }
-
-    @PutMapping("/update")
-    @Operation(summary = "淇敼")
-    @Log(title = "淇敼瀹℃壒妯℃澘", businessType = BusinessType.UPDATE)
-    public R update(@RequestBody ApprovalTemplateDto approvalTemplateDto) {
-        return R.ok(approvalTemplateService.updateApprovalTemplateDto(approvalTemplateDto));
-    }
-
-    @PostMapping("/delete")
-    @Operation(summary = "鍒犻櫎")
-    @Log(title = "鍒犻櫎瀹℃壒妯℃澘", businessType = BusinessType.DELETE)
-    public R delete(@RequestBody List<Long> ids) {
-        return R.ok(approvalTemplateService.delete(ids));
-    }
-
-    @GetMapping("/list/{type}")
-    @Operation(summary = "鏌ヨ鎵�鏈夊鎵规ā鏉�")
-    public R list(@PathVariable("type") Integer type) {
-        return R.ok(approvalTemplateService.listApprovalTemplateVo(type));
-    }
-
-    @GetMapping("/detail/{id}")
-    @Operation(summary = "鏌ヨ瀹℃壒妯℃澘璇︽儏")
-    @Log(title = "鏌ヨ瀹℃壒妯℃澘璇︽儏", businessType = BusinessType.OTHER)
-    public R detail(@PathVariable("id") Long id) {
-        return R.ok(approvalTemplateService.getApprovalTemplateVoById(id));
-    }
-}
diff --git a/src/main/java/com/ruoyi/approve/controller/ApprovalTemplateNodeApproverController.java b/src/main/java/com/ruoyi/approve/controller/ApprovalTemplateNodeApproverController.java
deleted file mode 100644
index b0e2bff..0000000
--- a/src/main/java/com/ruoyi/approve/controller/ApprovalTemplateNodeApproverController.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.controller;
-
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘鑺傜偣瀹℃壒浜鸿〃 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:30
- */
-@RestController
-@RequestMapping("/approvalTemplateNodeApprover")
-public class ApprovalTemplateNodeApproverController {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/controller/ApprovalTemplateNodeController.java b/src/main/java/com/ruoyi/approve/controller/ApprovalTemplateNodeController.java
deleted file mode 100644
index 5a1ed88..0000000
--- a/src/main/java/com/ruoyi/approve/controller/ApprovalTemplateNodeController.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.controller;
-
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘鑺傜偣琛� 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:19
- */
-@RestController
-@RequestMapping("/approvalTemplateNode")
-public class ApprovalTemplateNodeController {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/controller/FinReimbursementController.java b/src/main/java/com/ruoyi/approve/controller/FinReimbursementController.java
deleted file mode 100644
index a2eecdb..0000000
--- a/src/main/java/com/ruoyi/approve/controller/FinReimbursementController.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.ruoyi.approve.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.approve.bean.dto.FinReimbursementDto;
-import com.ruoyi.approve.bean.vo.FinReimbursementVo;
-import com.ruoyi.approve.service.FinReimbursementService;
-import com.ruoyi.framework.web.domain.R;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import lombok.AllArgsConstructor;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-/**
- * <p>
- * 鎶ラ攢鍗曚富琛� 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:15
- */
-@RestController
-@RequestMapping("/finReimbursement")
-@Tag(name = "鎶ラ攢鍗曚富琛�", description = "鎶ラ攢鍗曚富琛�")
-@AllArgsConstructor
-public class FinReimbursementController {
-
-    private final FinReimbursementService finReimbursementService;
-
-    @GetMapping("/listPage")
-    @Operation(summary = "鍒嗛〉鏌ヨ")
-    public R listPage(Page<FinReimbursementVo> page, FinReimbursementDto finReimbursementDto) {
-        return R.ok(finReimbursementService.listPage(finReimbursementDto, page));
-    }
-
-    @PostMapping("/save")
-    @Operation(summary = "淇濆瓨")
-    public R save(@RequestBody FinReimbursementDto finReimbursementDto) {
-        return R.ok(finReimbursementService.add(finReimbursementDto));
-    }
-
-    @GetMapping("/detail")
-    @Operation(summary = "璇︽儏")
-    public R detail(Long id) {
-        return R.ok(finReimbursementService.detail(id));
-    }
-
-    @PostMapping("/update")
-    @Operation(summary = "淇敼")
-    public R update(@RequestBody FinReimbursementDto finReimbursementDto) {
-        return R.ok(finReimbursementService.update(finReimbursementDto));
-    }
-
-    @DeleteMapping("/delete")
-    @Operation(summary = "鍒犻櫎")
-    public R delete(@RequestBody List<Long> ids) {
-        return R.ok(finReimbursementService.delete(ids));
-    }
-}
diff --git a/src/main/java/com/ruoyi/approve/controller/FinReimbursementDetailController.java b/src/main/java/com/ruoyi/approve/controller/FinReimbursementDetailController.java
deleted file mode 100644
index 18e4f73..0000000
--- a/src/main/java/com/ruoyi/approve/controller/FinReimbursementDetailController.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.controller;
-
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 鎶ラ攢鍗曟槑缁嗚〃 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:38
- */
-@RestController
-@RequestMapping("/finReimbursementDetail")
-public class FinReimbursementDetailController {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/controller/FinReimbursementTravelController.java b/src/main/java/com/ruoyi/approve/controller/FinReimbursementTravelController.java
deleted file mode 100644
index 0e67feb..0000000
--- a/src/main/java/com/ruoyi/approve/controller/FinReimbursementTravelController.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.controller;
-
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 宸梾鎶ラ攢鎵╁睍琛� 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:47
- */
-@RestController
-@RequestMapping("/finReimbursementTravel")
-public class FinReimbursementTravelController {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/dto/KnowledgeBaseVectorVO.java b/src/main/java/com/ruoyi/approve/dto/KnowledgeBaseVectorVO.java
deleted file mode 100644
index 9cfb721..0000000
--- a/src/main/java/com/ruoyi/approve/dto/KnowledgeBaseVectorVO.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.ruoyi.approve.dto;
-
-import com.ruoyi.approve.pojo.KnowledgeBaseVector;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * 鐭ヨ瘑搴撴枃浠跺悜閲忕姸鎬乂O
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Schema(description = "鐭ヨ瘑搴撴枃浠跺悜閲忕姸鎬乂O")
-public class KnowledgeBaseVectorVO extends KnowledgeBaseVector {
-
-    @Schema(description = "鏂囦欢棰勮URL")
-    private String previewUrl;
-
-    @Schema(description = "鏂囦欢涓嬭浇URL")
-    private String downloadUrl;
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/approve/mapper/ApprovalInstanceMapper.java b/src/main/java/com/ruoyi/approve/mapper/ApprovalInstanceMapper.java
deleted file mode 100644
index a541b90..0000000
--- a/src/main/java/com/ruoyi/approve/mapper/ApprovalInstanceMapper.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.approve.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
-import com.ruoyi.approve.bean.vo.ApprovalInstanceVo;
-import com.ruoyi.approve.pojo.ApprovalInstance;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-
-/**
- * <p>
- * 瀹℃壒瀹炰緥琛� Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:27:46
- */
-@Mapper
-public interface ApprovalInstanceMapper extends BaseMapper<ApprovalInstance> {
-
-    IPage<ApprovalInstanceVo> listPage(Page<ApprovalInstanceVo> page,@Param("ew") ApprovalInstanceDto approvalInstanceDto);
-}
diff --git a/src/main/java/com/ruoyi/approve/mapper/ApprovalInstanceNodeMapper.java b/src/main/java/com/ruoyi/approve/mapper/ApprovalInstanceNodeMapper.java
deleted file mode 100644
index 8787e55..0000000
--- a/src/main/java/com/ruoyi/approve/mapper/ApprovalInstanceNodeMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.approve.pojo.ApprovalInstanceNode;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * <p>
- * 瀹℃壒鑺傜偣瀹炰緥琛� Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:27:54
- */
-@Mapper
-public interface ApprovalInstanceNodeMapper extends BaseMapper<ApprovalInstanceNode> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/mapper/ApprovalRecordMapper.java b/src/main/java/com/ruoyi/approve/mapper/ApprovalRecordMapper.java
deleted file mode 100644
index fcf5ec6..0000000
--- a/src/main/java/com/ruoyi/approve/mapper/ApprovalRecordMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.approve.pojo.ApprovalRecord;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * <p>
- * 瀹℃壒璁板綍琛� Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:28:21
- */
-@Mapper
-public interface ApprovalRecordMapper extends BaseMapper<ApprovalRecord> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/mapper/ApprovalTaskMapper.java b/src/main/java/com/ruoyi/approve/mapper/ApprovalTaskMapper.java
deleted file mode 100644
index 2531d8e..0000000
--- a/src/main/java/com/ruoyi/approve/mapper/ApprovalTaskMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.approve.pojo.ApprovalTask;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * <p>
- * 瀹℃壒浠诲姟琛� Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:32:37
- */
-@Mapper
-public interface ApprovalTaskMapper extends BaseMapper<ApprovalTask> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateMapper.java b/src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateMapper.java
deleted file mode 100644
index 693f4b2..0000000
--- a/src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateMapper.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.approve.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.approve.bean.dto.ApprovalTemplateDto;
-import com.ruoyi.approve.bean.vo.ApprovalTemplateVo;
-import com.ruoyi.approve.pojo.ApprovalTemplate;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘琛� Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:08
- */
-@Mapper
-public interface ApprovalTemplateMapper extends BaseMapper<ApprovalTemplate> {
-
-    IPage<ApprovalTemplateVo> listPage(Page<ApprovalTemplateVo> page,@Param("ew") ApprovalTemplateDto approvalTemplateDto);
-}
diff --git a/src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateNodeApproverMapper.java b/src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateNodeApproverMapper.java
deleted file mode 100644
index d96f1e3..0000000
--- a/src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateNodeApproverMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘鑺傜偣瀹℃壒浜鸿〃 Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:30
- */
-@Mapper
-public interface ApprovalTemplateNodeApproverMapper extends BaseMapper<ApprovalTemplateNodeApprover> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateNodeMapper.java b/src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateNodeMapper.java
deleted file mode 100644
index dc4a67f..0000000
--- a/src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateNodeMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.approve.pojo.ApprovalTemplateNode;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘鑺傜偣琛� Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:19
- */
-@Mapper
-public interface ApprovalTemplateNodeMapper extends BaseMapper<ApprovalTemplateNode> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/mapper/FinReimbursementDetailMapper.java b/src/main/java/com/ruoyi/approve/mapper/FinReimbursementDetailMapper.java
deleted file mode 100644
index edc039a..0000000
--- a/src/main/java/com/ruoyi/approve/mapper/FinReimbursementDetailMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.approve.pojo.FinReimbursementDetail;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * <p>
- * 鎶ラ攢鍗曟槑缁嗚〃 Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:38
- */
-@Mapper
-public interface FinReimbursementDetailMapper extends BaseMapper<FinReimbursementDetail> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/mapper/FinReimbursementMapper.java b/src/main/java/com/ruoyi/approve/mapper/FinReimbursementMapper.java
deleted file mode 100644
index 19ac354..0000000
--- a/src/main/java/com/ruoyi/approve/mapper/FinReimbursementMapper.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.approve.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.approve.bean.dto.FinReimbursementDto;
-import com.ruoyi.approve.bean.vo.FinReimbursementVo;
-import com.ruoyi.approve.pojo.FinReimbursement;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-
-/**
- * <p>
- * 鎶ラ攢鍗曚富琛� Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:15
- */
-@Mapper
-public interface FinReimbursementMapper extends BaseMapper<FinReimbursement> {
-
-    IPage<FinReimbursementVo> listPage(@Param("ew") FinReimbursementDto finReimbursementDto, Page<FinReimbursementVo> page);
-}
diff --git a/src/main/java/com/ruoyi/approve/mapper/FinReimbursementTravelMapper.java b/src/main/java/com/ruoyi/approve/mapper/FinReimbursementTravelMapper.java
deleted file mode 100644
index bc5e1b8..0000000
--- a/src/main/java/com/ruoyi/approve/mapper/FinReimbursementTravelMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.approve.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.approve.pojo.FinReimbursementTravel;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * <p>
- * 宸梾鎶ラ攢鎵╁睍琛� Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:47
- */
-@Mapper
-public interface FinReimbursementTravelMapper extends BaseMapper<FinReimbursementTravel> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/mapper/KnowledgeBaseVectorMapper.java b/src/main/java/com/ruoyi/approve/mapper/KnowledgeBaseVectorMapper.java
deleted file mode 100644
index 5fb19fe..0000000
--- a/src/main/java/com/ruoyi/approve/mapper/KnowledgeBaseVectorMapper.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.ruoyi.approve.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.approve.dto.KnowledgeBaseVectorVO;
-import com.ruoyi.approve.pojo.KnowledgeBaseVector;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-import org.apache.ibatis.annotations.Select;
-
-import java.util.List;
-
-/**
- * 鐭ヨ瘑搴撴枃浠跺悜閲忚褰� Mapper
- */
-@Mapper
-public interface KnowledgeBaseVectorMapper extends BaseMapper<KnowledgeBaseVector> {
-
-    /**
-     * 鏌ヨ鐭ヨ瘑搴撶殑鏂囦欢鍚戦噺鐘舵�佸垪琛�
-     */
-    @Select("SELECT v.*, b.path as previewUrl " +
-            "FROM knowledge_base_vector v " +
-            "LEFT JOIN storage_blob b ON v.storage_blob_id = b.id " +
-            "WHERE v.knowledge_base_id = #{knowledgeBaseId} " +
-            "ORDER BY v.create_time DESC")
-    List<KnowledgeBaseVectorVO> selectByKnowledgeBaseId(@Param("knowledgeBaseId") Long knowledgeBaseId);
-
-    /**
-     * 缁熻鐭ヨ瘑搴撶殑鏂囦欢鏁伴噺
-     */
-    @Select("SELECT COUNT(*) FROM knowledge_base_vector WHERE knowledge_base_id = #{knowledgeBaseId}")
-    int countByKnowledgeBaseId(@Param("knowledgeBaseId") Long knowledgeBaseId);
-
-    /**
-     * 缁熻鐭ヨ瘑搴撶殑鎬诲垏鐗囨暟閲�
-     */
-    @Select("SELECT COALESCE(SUM(chunk_count), 0) FROM knowledge_base_vector WHERE knowledge_base_id = #{knowledgeBaseId} AND vector_status = 2")
-    int sumChunkCountByKnowledgeBaseId(@Param("knowledgeBaseId") Long knowledgeBaseId);
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApprovalInstance.java b/src/main/java/com/ruoyi/approve/pojo/ApprovalInstance.java
deleted file mode 100644
index 5bac3a9..0000000
--- a/src/main/java/com/ruoyi/approve/pojo/ApprovalInstance.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package com.ruoyi.approve.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.annotations.ApiModel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * <p>
- * 瀹℃壒瀹炰緥琛�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:27:46
- */
-@Getter
-@Setter
-@ToString
-@TableName("approval_instance")
-@ApiModel(value = "ApprovalInstance瀵硅薄", description = "瀹℃壒瀹炰緥琛�")
-public class ApprovalInstance implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 瀹℃壒瀹炰緥ID
-     */
-    @Schema(description ="瀹℃壒瀹炰緥ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 瀹℃壒缂栧彿
-     */
-    @Schema(description ="瀹℃壒缂栧彿")
-    private String instanceNo;
-
-    /**
-     * 妯℃澘ID
-     */
-    @Schema(description ="妯℃澘ID")
-    private Long templateId;
-
-    /**
-     * 妯℃澘鍚嶇О
-     */
-    @Schema(description ="妯℃澘鍚嶇О")
-    private String templateName;
-
-    /**
-     * 涓氬姟ID
-     */
-    @Schema(description ="涓氬姟ID")
-    private Long businessId;
-
-    /**
-     * 涓氬姟绫诲瀷
-     */
-    @Schema(description ="涓氬姟绫诲瀷")
-    private Long businessType;
-
-    /**
-     * 瀹℃壒鏍囬
-     */
-    @Schema(description ="瀹℃壒鏍囬")
-    private String title;
-
-    /**
-     * 瀹℃壒鐘舵��
-     */
-    @Schema(description ="瀹℃壒鐘舵�� PENDING - 寰呭鎵�/杩涜涓�  APPROVED - 宸查�氳繃/宸插畬鎴�  REJECTED - 宸查┏鍥�")
-    private String status;
-
-    /**
-     * 褰撳墠瀹℃壒绾у埆
-     */
-    @Schema(description ="褰撳墠瀹℃壒绾у埆")
-    private Integer currentLevel;
-
-    /**
-     * 鐢宠浜篒D
-     */
-    @Schema(description ="鐢宠浜篒D")
-    private Long applicantId;
-
-    /**
-     * 鐢宠浜哄悕绉�
-     */
-    @Schema(description ="鐢宠浜哄悕绉�")
-    private String applicantName;
-
-    /**
-     * 鐢宠鏃堕棿
-     */
-    @Schema(description ="鐢宠鏃堕棿")
-    private LocalDateTime applyTime;
-
-    /**
-     * 瀹屾垚鏃堕棿
-     */
-    @Schema(description ="瀹屾垚鏃堕棿")
-    private LocalDateTime finishTime;
-
-    /**
-     * 鍒涘缓浜�
-     */
-    @Schema(description ="鍒涘缓浜�")
-    @TableField(fill = FieldFill.INSERT)
-    private Long createUser;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @Schema(description ="鍒涘缓鏃堕棿")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime createTime;
-
-    /**
-     * 鏇存柊浜�
-     */
-    @Schema(description ="鏇存柊浜�")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Long updateUser;
-
-    /**
-     * 鏇存柊鏃堕棿
-     */
-    @Schema(description ="鏇存柊鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-    /**
-     * 閫昏緫鍒犻櫎
-     */
-    @Schema(description ="閫昏緫鍒犻櫎")
-    private Byte deleted;
-
-    @Schema(description = "琛ㄥ崟鏁版嵁")
-    private String formConfig;
-}
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApprovalInstanceNode.java b/src/main/java/com/ruoyi/approve/pojo/ApprovalInstanceNode.java
deleted file mode 100644
index 621ce1f..0000000
--- a/src/main/java/com/ruoyi/approve/pojo/ApprovalInstanceNode.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package com.ruoyi.approve.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import io.swagger.annotations.ApiModel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * <p>
- * 瀹℃壒鑺傜偣瀹炰緥琛�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:27:54
- */
-@Getter
-@Setter
-@ToString
-@TableName("approval_instance_node")
-@ApiModel(value = "ApprovalInstanceNode瀵硅薄", description = "瀹℃壒鑺傜偣瀹炰緥琛�")
-public class ApprovalInstanceNode implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 鑺傜偣瀹炰緥ID
-     */
-    @Schema(description ="鑺傜偣瀹炰緥ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 瀹℃壒瀹炰緥ID
-     */
-    @Schema(description ="瀹℃壒瀹炰緥ID")
-    private Long instanceId;
-
-    /**
-     * 瀹℃壒绾у埆
-     */
-    @Schema(description ="瀹℃壒绾у埆")
-    private Integer levelNo;
-
-    /**
-     * 瀹℃壒绫诲瀷
-     */
-    @Schema(description ="瀹℃壒绫诲瀷")
-    private String approveType;
-
-    /**
-     * 鑺傜偣鐘舵��
-     */
-    @Schema(description ="鑺傜偣鐘舵�� PENDING - 寰呭鐞� APPROVED - 宸查�氳繃 REJECTED - 宸查┏鍥�")
-    private String status;
-
-    /**
-     * 寮�濮嬫椂闂�
-     */
-    @Schema(description ="寮�濮嬫椂闂�")
-    private LocalDateTime startTime;
-
-    /**
-     * 瀹屾垚鏃堕棿
-     */
-    @Schema(description ="瀹屾垚鏃堕棿")
-    private LocalDateTime finishTime;
-
-    /**
-     * 鍒涘缓浜�
-     */
-    @Schema(description ="鍒涘缓浜�")
-    @TableField(fill = FieldFill.INSERT)
-    private Long createUser;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @Schema(description ="鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    /**
-     * 鏇存柊浜�
-     */
-    @Schema(description ="鏇存柊浜�")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Long updateUser;
-
-    /**
-     * 鏇存柊鏃堕棿
-     */
-    @Schema(description ="鏇存柊鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    /**
-     * 閫昏緫鍒犻櫎
-     */
-    @Schema(description ="閫昏緫鍒犻櫎")
-    private Byte deleted;
-}
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApprovalRecord.java b/src/main/java/com/ruoyi/approve/pojo/ApprovalRecord.java
deleted file mode 100644
index 21bc52b..0000000
--- a/src/main/java/com/ruoyi/approve/pojo/ApprovalRecord.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.ruoyi.approve.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import io.swagger.annotations.ApiModel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * <p>
- * 瀹℃壒璁板綍琛�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:28:21
- */
-@Getter
-@Setter
-@ToString
-@TableName("approval_record")
-@ApiModel(value = "ApprovalRecord瀵硅薄", description = "瀹℃壒璁板綍琛�")
-public class ApprovalRecord implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 瀹℃壒璁板綍ID
-     */
-    @Schema(description ="瀹℃壒璁板綍ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 瀹℃壒瀹炰緥ID
-     */
-    @Schema(description ="瀹℃壒瀹炰緥ID")
-    private Long instanceId;
-
-    /**
-     * 鑺傜偣瀹炰緥ID
-     */
-    @Schema(description ="鑺傜偣瀹炰緥ID")
-    private Long nodeId;
-
-    /**
-     * 瀹℃壒浠诲姟ID
-     */
-    @Schema(description ="瀹℃壒浠诲姟ID")
-    private Long taskId;
-
-    /**
-     * 鎿嶄綔浜篒D
-     */
-    @Schema(description ="鎿嶄綔浜篒D")
-    private Long operatorId;
-
-    /**
-     * 鎿嶄綔浜哄悕绉�
-     */
-    @Schema(description ="鎿嶄綔浜哄悕绉�")
-    private String operatorName;
-
-    /**
-     * 鎿嶄綔绫诲瀷
-     */
-    @Schema(description ="鎿嶄綔绫诲瀷")
-    private String action;
-
-    /**
-     * 瀹℃壒鎰忚
-     */
-    @Schema(description ="瀹℃壒鎰忚")
-    private String comment;
-
-    /**
-     * 鍒涘缓浜�
-     */
-    @Schema(description ="鍒涘缓浜�")
-    @TableField(fill = FieldFill.INSERT)
-    private Long createUser;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @Schema(description ="鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    /**
-     * 閫昏緫鍒犻櫎
-     */
-    @Schema(description ="閫昏緫鍒犻櫎")
-    private Byte deleted;
-}
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApprovalTask.java b/src/main/java/com/ruoyi/approve/pojo/ApprovalTask.java
deleted file mode 100644
index d78c964..0000000
--- a/src/main/java/com/ruoyi/approve/pojo/ApprovalTask.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package com.ruoyi.approve.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import io.swagger.annotations.ApiModel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * <p>
- * 瀹℃壒浠诲姟琛�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:32:37
- */
-@Getter
-@Setter
-@ToString
-@TableName("approval_task")
-@ApiModel(value = "ApprovalTask瀵硅薄", description = "瀹℃壒浠诲姟琛�")
-public class ApprovalTask implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 瀹℃壒浠诲姟ID
-     */
-    @Schema(description ="瀹℃壒浠诲姟ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 瀹℃壒瀹炰緥ID
-     */
-    @Schema(description ="瀹℃壒瀹炰緥ID")
-    private Long instanceId;
-
-    /**
-     * 鑺傜偣瀹炰緥ID
-     */
-    @Schema(description ="鑺傜偣瀹炰緥ID")
-    private Long nodeId;
-
-    /**
-     * 瀹℃壒绾у埆
-     */
-    @Schema(description ="瀹℃壒绾у埆")
-    private Integer levelNo;
-
-    /**
-     * 瀹℃壒浜篒D
-     */
-    @Schema(description ="瀹℃壒浜篒D")
-    private Long approverId;
-
-    /**
-     * 瀹℃壒浜哄悕绉�
-     */
-    @Schema(description ="瀹℃壒浜哄悕绉�")
-    private String approverName;
-
-    /**
-     * 浠诲姟鐘舵��
-     */
-    @Schema(description ="浠诲姟鐘舵�� PENDING - 寰呭鎵� APPROVED - 宸插悓鎰�  REJECTED - 宸叉嫆缁�")
-    private String taskStatus;
-
-    /**
-     * 瀹℃壒鏃堕棿
-     */
-    @Schema(description ="瀹℃壒鏃堕棿")
-    private LocalDateTime approveTime;
-
-    /**
-     * 瀹℃壒鎰忚
-     */
-    @Schema(description ="瀹℃壒鎰忚")
-    private String comment;
-
-    /**
-     * 鏄惁宸茶
-     */
-    @Schema(description ="鏄惁宸茶")
-    private Byte isRead;
-
-    /**
-     * 鍒涘缓浜�
-     */
-    @Schema(description ="鍒涘缓浜�")
-    @TableField(fill = FieldFill.INSERT)
-    private Long createUser;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @Schema(description ="鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    /**
-     * 鏇存柊浜�
-     */
-    @Schema(description ="鏇存柊浜�")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Long updateUser;
-
-    /**
-     * 鏇存柊鏃堕棿
-     */
-    @Schema(description ="鏇存柊鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    /**
-     * 閫昏緫鍒犻櫎
-     */
-    @Schema(description ="閫昏緫鍒犻櫎")
-    private Byte deleted;
-
-    @Schema(description ="閮ㄩ棬ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApprovalTemplate.java b/src/main/java/com/ruoyi/approve/pojo/ApprovalTemplate.java
deleted file mode 100644
index 272b945..0000000
--- a/src/main/java/com/ruoyi/approve/pojo/ApprovalTemplate.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package com.ruoyi.approve.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.annotations.ApiModel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘琛�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:08
- */
-@Getter
-@Setter
-@ToString
-@TableName("approval_template")
-@ApiModel(value = "ApprovalTemplate瀵硅薄", description = "瀹℃壒妯℃澘琛�")
-public class ApprovalTemplate implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 妯℃澘ID
-     */
-    @Schema(description ="妯℃澘ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 妯℃澘鍚嶇О
-     */
-    @Schema(description ="妯℃澘鍚嶇О")
-    private String templateName;
-
-    /**
-     * 鍚敤鐘舵�侊細1鍚敤锛�0鍋滅敤
-     */
-    @Schema(description ="鍚敤鐘舵�侊細1鍚敤锛�0鍋滅敤")
-    private Byte enabled;
-
-    /**
-     * 妯℃澘璇存槑
-     */
-    @Schema(description ="妯℃澘璇存槑")
-    private String description;
-
-    /**
-     * 鍒涘缓浜�
-     */
-    @Schema(description ="鍒涘缓浜�")
-    @TableField(fill = FieldFill.INSERT)
-    private Long createUser;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @Schema(description ="鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime createTime;
-
-    /**
-     * 鏇存柊浜�
-     */
-    @Schema(description ="鏇存柊浜�")
-    @TableField(fill = FieldFill.UPDATE)
-    private Long updateUser;
-
-    /**
-     * 鏇存柊鏃堕棿
-     */
-    @Schema(description ="鏇存柊鏃堕棿")
-    @TableField(fill = FieldFill.UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime updateTime;
-
-    /**
-     * 閫昏緫鍒犻櫎锛�0鍚︼紝1鏄�
-     */
-    @Schema(description ="閫昏緫鍒犻櫎锛�0鍚︼紝1鏄�")
-    private Integer deleted;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-
-    @Schema(description = "琛ㄥ崟閰嶇疆")
-    private String formConfig;
-
-    @Schema(description = "妯℃澘绫诲瀷锛�0绯荤粺鍐呯疆锛�1鑷畾涔�")
-    private Integer templateType;
-
-    @Schema(description = "涓氬姟绫诲瀷")
-    private Long businessType;
-
-}
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApprovalTemplateNode.java b/src/main/java/com/ruoyi/approve/pojo/ApprovalTemplateNode.java
deleted file mode 100644
index cd77198..0000000
--- a/src/main/java/com/ruoyi/approve/pojo/ApprovalTemplateNode.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.ruoyi.approve.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import io.swagger.annotations.ApiModel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘鑺傜偣琛�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:19
- */
-@Getter
-@Setter
-@ToString
-@TableName("approval_template_node")
-@ApiModel(value = "ApprovalTemplateNode瀵硅薄", description = "瀹℃壒妯℃澘鑺傜偣琛�")
-public class ApprovalTemplateNode implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 鑺傜偣ID
-     */
-    @Schema(description ="鑺傜偣ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 瀹℃壒妯℃澘ID
-     */
-    @Schema(description ="瀹℃壒妯℃澘ID")
-    private Long templateId;
-
-    /**
-     * 瀹℃壒绾у埆锛屼粠1寮�濮�
-     */
-    @Schema(description ="瀹℃壒绾у埆锛屼粠1寮�濮�")
-    private Integer levelNo;
-
-    /**
-     * 瀹℃壒鏂瑰紡锛欰ND浼氱锛孫R鎴栫
-     */
-    @Schema(description ="瀹℃壒鏂瑰紡锛欰ND浼氱锛孫R鎴栫")
-    private String approveType;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long createUser;
-
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    @TableField(fill = FieldFill.UPDATE)
-    private LocalDateTime updateTime;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApprovalTemplateNodeApprover.java b/src/main/java/com/ruoyi/approve/pojo/ApprovalTemplateNodeApprover.java
deleted file mode 100644
index 4113bff..0000000
--- a/src/main/java/com/ruoyi/approve/pojo/ApprovalTemplateNodeApprover.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.ruoyi.approve.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import io.swagger.annotations.ApiModel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘鑺傜偣瀹℃壒浜鸿〃
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:30
- */
-@Getter
-@Setter
-@ToString
-@TableName("approval_template_node_approver")
-@ApiModel(value = "ApprovalTemplateNodeApprover瀵硅薄", description = "瀹℃壒妯℃澘鑺傜偣瀹℃壒浜鸿〃")
-public class ApprovalTemplateNodeApprover implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭ID
-     */
-    @Schema(description = "涓婚敭ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 瀹℃壒鑺傜偣ID
-     */
-    @Schema(description ="瀹℃壒鑺傜偣ID")
-    private Long nodeId;
-
-    /**
-     * 瀹℃壒妯℃澘ID
-     */
-    @Schema(description ="瀹℃壒妯℃澘ID")
-    private Long templateId;
-
-    /**
-     * 瀹℃壒浜篒D
-     */
-    @Schema(description ="瀹℃壒浜篒D")
-    private Long approverId;
-
-    /**
-     * 瀹℃壒浜哄悕绉板啑浣�
-     */
-    @Schema(description ="瀹℃壒浜哄悕绉板啑浣�")
-    private String approverName;
-
-    /**
-     * 瀹℃壒浜烘帓搴�
-     */
-    @Schema(description ="瀹℃壒浜烘帓搴�")
-    private Integer sortNo;
-
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-    @TableField(fill = FieldFill.INSERT)
-    private Long createUser;
-    @TableField(fill = FieldFill.INSERT)
-    private Long deleted ;
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-
-}
diff --git a/src/main/java/com/ruoyi/approve/pojo/FinReimbursement.java b/src/main/java/com/ruoyi/approve/pojo/FinReimbursement.java
deleted file mode 100644
index 7e5c81f..0000000
--- a/src/main/java/com/ruoyi/approve/pojo/FinReimbursement.java
+++ /dev/null
@@ -1,209 +0,0 @@
-package com.ruoyi.approve.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import io.swagger.annotations.ApiModel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-
-/**
- * <p>
- * 鎶ラ攢鍗曚富琛�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:15
- */
-@Getter
-@Setter
-@ToString
-@TableName("fin_reimbursement")
-@ApiModel(value = "FinReimbursement瀵硅薄", description = "鎶ラ攢鍗曚富琛�")
-public class FinReimbursement implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭ID
-     */
-    @Schema(description = "涓婚敭ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 鎶ラ攢鍗曞彿
-     */
-    @Schema(description = "鎶ラ攢鍗曞彿")
-    private String billNo;
-
-    /**
-     * 鎶ラ攢绫诲瀷锛�1-宸梾鎶ラ攢锛�2-璐圭敤鎶ラ攢
-     */
-    @Schema(description = "鎶ラ攢绫诲瀷锛�1-宸梾鎶ラ攢锛�2-璐圭敤鎶ラ攢")
-    private Byte reimbursementType;
-
-    /**
-     * 璐圭敤绫诲瀷锛氬樊鏃呰垂/鍔炲叕閲囪喘/涓氬姟鎷涘緟/浜ら�氳垂/閫氳璐�/鍏朵粬
-     */
-    @Schema(description = "璐圭敤绫诲瀷锛氬樊鏃呰垂/鍔炲叕閲囪喘/涓氬姟鎷涘緟/浜ら�氳垂/閫氳璐�/鍏朵粬")
-    private String expenseType;
-
-    /**
-     * 鐢宠浜篒D
-     */
-    @Schema(description = "鐢宠浜篒D")
-    private Long applicantId;
-
-    /**
-     * 鍛樺伐缂栧彿
-     */
-    @Schema(description = "鍛樺伐缂栧彿")
-    private String applicantCode;
-
-    /**
-     * 鍛樺伐濮撳悕
-     */
-    @Schema(description = "鍛樺伐濮撳悕")
-    private String applicantName;
-
-    /**
-     * 鐢宠閮ㄩ棬ID
-     */
-    @Schema(description = "鐢宠閮ㄩ棬ID")
-    private Long applicantDeptId;
-
-    /**
-     * 鐢宠閮ㄩ棬鍚嶇О
-     */
-    @Schema(description = "鐢宠閮ㄩ棬鍚嶇О")
-    private String applicantDeptName;
-
-    /**
-     * 鎶ラ攢鍘熷洜
-     */
-    @Schema(description = "鎶ラ攢鍘熷洜")
-    private String reason;
-
-    /**
-     * 鐢宠閲戦
-     */
-    @Schema(description = "鐢宠閲戦")
-    private BigDecimal applyAmount;
-
-    /**
-     * 鏄庣粏姹囨�婚噾棰�
-     */
-    @Schema(description = "鏄庣粏姹囨�婚噾棰�")
-    private BigDecimal detailTotalAmount;
-
-    /**
-     * 鏀舵浜�
-     */
-    @Schema(description = "鏀舵浜�")
-    private String payeeName;
-
-    /**
-     * 鏀舵璐﹀彿
-     */
-    @Schema(description = "鏀舵璐﹀彿")
-    private String payeeAccount;
-
-    /**
-     * 寮�鎴锋敮琛�
-     */
-    @Schema(description = "寮�鎴锋敮琛�")
-    private String payeeBank;
-
-    /**
-     * 瀹℃壒瀹炰緥ID锛屽搴� approval_instance.id
-     */
-    @Schema(description = "瀹℃壒瀹炰緥ID锛屽搴� approval_instance.id")
-    private Long approvalInstanceId;
-
-    /**
-     * 瀹℃壒娴佺▼ID锛屽搴� approve_process.id
-     */
-    @Schema(description = "瀹℃壒娴佺▼ID锛屽搴� approve_process.id")
-    private Long approveProcessId;
-
-    /**
-     * 鍗曟嵁鐘舵�侊細DRAFT-鑽夌锛孖N_APPROVAL-瀹℃壒涓紝APPROVED-瀹℃壒閫氳繃锛孯EJECTED-瀹℃壒椹冲洖锛學ITHDRAWN-宸叉挙鍥烇紝PAID-宸蹭粯娆�
-     */
-    @Schema(description = "鍗曟嵁鐘舵�侊細DRAFT-鑽夌锛孖N_APPROVAL-瀹℃壒涓紝APPROVED-瀹℃壒閫氳繃锛孯EJECTED-瀹℃壒椹冲洖锛學ITHDRAWN-宸叉挙鍥烇紝PAID-宸蹭粯娆�")
-    private String billStatus;
-
-    /**
-     * 瀹℃壒閫氳繃鏃堕棿
-     */
-    @Schema(description = "瀹℃壒閫氳繃鏃堕棿")
-    private LocalDateTime approvedTime;
-
-    /**
-     * 浠樻鏃堕棿
-     */
-    @Schema(description = "浠樻鏃堕棿")
-    private LocalDateTime paidTime;
-
-    /**
-     * 鐢熸垚鐨勮储鍔℃敮鍑鸿褰旾D锛屽搴� account_expense.id
-     */
-    @Schema(description = "鐢熸垚鐨勮储鍔℃敮鍑鸿褰旾D锛屽搴� account_expense.id")
-    private Long accountExpenseId;
-
-    /**
-     * 澶囨敞
-     */
-    @Schema(description = "澶囨敞")
-    private String remark;
-
-    /**
-     * 绉熸埛ID
-     */
-    @Schema(description = "绉熸埛ID")
-    private Long tenantId;
-
-    /**
-     * 鍒涘缓浜�
-     */
-    @Schema(description = "鍒涘缓浜�")
-    @TableField(fill = FieldFill.INSERT)
-    private Long createUser;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @Schema(description = "鍒涘缓鏃堕棿")
-    private LocalDateTime createTime;
-
-    /**
-     * 鏇存柊浜�
-     */
-    @Schema(description = "鏇存柊浜�")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Long updateUser;
-
-    /**
-     * 鏇存柊鏃堕棿
-     */
-    @Schema(description = "鏇存柊鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    /**
-     * 褰掑睘閮ㄩ棬ID
-     */
-    @Schema(description = "褰掑睘閮ㄩ棬ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-
-    /**
-     * 閫昏緫鍒犻櫎锛�0-鍚︼紝1-鏄�
-     */
-    @Schema(description = "閫昏緫鍒犻櫎锛�0-鍚︼紝1-鏄�")
-    private Byte deleted;
-}
diff --git a/src/main/java/com/ruoyi/approve/pojo/FinReimbursementDetail.java b/src/main/java/com/ruoyi/approve/pojo/FinReimbursementDetail.java
deleted file mode 100644
index 5d0220e..0000000
--- a/src/main/java/com/ruoyi/approve/pojo/FinReimbursementDetail.java
+++ /dev/null
@@ -1,157 +0,0 @@
-package com.ruoyi.approve.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import io.swagger.annotations.ApiModel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-
-/**
- * <p>
- * 鎶ラ攢鍗曟槑缁嗚〃
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:38
- */
-@Getter
-@Setter
-@ToString
-@TableName("fin_reimbursement_detail")
-@ApiModel(value = "FinReimbursementDetail瀵硅薄", description = "鎶ラ攢鍗曟槑缁嗚〃")
-public class FinReimbursementDetail implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭ID
-     */
-    @Schema(description = "涓婚敭ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 鎶ラ攢鍗旾D锛屽搴� fin_reimbursement.id
-     */
-    @Schema(description = "鎶ラ攢鍗旾D锛屽搴� fin_reimbursement.id")
-    private Long reimbursementId;
-
-    /**
-     * 鏄庣粏琛屽彿
-     */
-    @Schema(description = "鏄庣粏琛屽彿")
-    private Integer rowNo;
-
-    /**
-     * 鍙戠エ鏃ユ湡
-     */
-    @Schema(description = "鍙戠エ鏃ユ湡")
-    private LocalDate invoiceDate;
-
-    /**
-     * 璐圭敤绉戠洰
-     */
-    @Schema(description = "璐圭敤绉戠洰")
-    private String expenseCategory;
-
-    /**
-     * 閲戦
-     */
-    @Schema(description = "閲戦")
-    private BigDecimal amount;
-
-    /**
-     * 鎻忚堪
-     */
-    @Schema(description = "鎻忚堪")
-    private String description;
-
-    /**
-     * 鍙戠エ鍙风爜
-     */
-    @Schema(description = "鍙戠エ鍙风爜")
-    private String invoiceNo;
-
-    /**
-     * 鍙戠エ绫诲瀷
-     */
-    @Schema(description = "鍙戠エ绫诲瀷")
-    private String invoiceType;
-
-    /**
-     * 绁ㄩ潰閲戦
-     */
-    @Schema(description = "绁ㄩ潰閲戦")
-    private BigDecimal invoiceAmount;
-
-    /**
-     * 绋庣巼
-     */
-    @Schema(description = "绋庣巼")
-    private BigDecimal taxRate;
-
-    /**
-     * 绋庨
-     */
-    @Schema(description = "绋庨")
-    private BigDecimal taxAmount;
-
-    /**
-     * 澶囨敞
-     */
-    @Schema(description = "澶囨敞")
-    private String remark;
-
-    /**
-     * 绉熸埛ID
-     */
-    @Schema(description = "绉熸埛ID")
-    private Long tenantId;
-
-    /**
-     * 鍒涘缓浜�
-     */
-    @Schema(description = "鍒涘缓浜�")
-    @TableField(fill = FieldFill.INSERT)
-    private Long createUser;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    /**
-     * 鏇存柊浜�
-     */
-    @Schema(description = "鏇存柊浜�")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Long updateUser;
-
-    /**
-     * 鏇存柊鏃堕棿
-     */
-    @Schema(description = "鏇存柊鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    /**
-     * 褰掑睘閮ㄩ棬ID
-     */
-    @Schema(description = "褰掑睘閮ㄩ棬ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-
-    /**
-     * 閫昏緫鍒犻櫎锛�0-鍚︼紝1-鏄�
-     */
-    @Schema(description = "閫昏緫鍒犻櫎锛�0-鍚︼紝1-鏄�")
-    private Byte deleted;
-}
diff --git a/src/main/java/com/ruoyi/approve/pojo/FinReimbursementTravel.java b/src/main/java/com/ruoyi/approve/pojo/FinReimbursementTravel.java
deleted file mode 100644
index 10c607c..0000000
--- a/src/main/java/com/ruoyi/approve/pojo/FinReimbursementTravel.java
+++ /dev/null
@@ -1,162 +0,0 @@
-package com.ruoyi.approve.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.annotations.ApiModel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-
-/**
- * <p>
- * 宸梾鎶ラ攢鎵╁睍琛�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:47
- */
-@Getter
-@Setter
-@ToString
-@TableName("fin_reimbursement_travel")
-@ApiModel(value = "FinReimbursementTravel瀵硅薄", description = "宸梾鎶ラ攢鎵╁睍琛�")
-public class FinReimbursementTravel implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭ID
-     */
-    @Schema(description = "涓婚敭ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 鎶ラ攢鍗旾D锛屽搴� fin_reimbursement.id
-     */
-    @Schema(description = "鎶ラ攢鍗旾D锛屽搴� fin_reimbursement.id")
-    private Long reimbursementId;
-
-    /**
-     * 鍑哄樊寮�濮嬫椂闂�
-     */
-    @Schema(description = "鍑哄樊寮�濮嬫椂闂�")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime startTime;
-
-    /**
-     * 鍑哄樊缁撴潫鏃堕棿
-     */
-    @Schema(description = "鍑哄樊缁撴潫鏃堕棿")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime endTime;
-
-    /**
-     * 鍑哄樊澶╂暟
-     */
-    @Schema(description = "鍑哄樊澶╂暟")
-    private BigDecimal travelDays;
-
-    /**
-     * 鍑哄樊鍦�/鍑哄彂鍩庡競
-     */
-    @Schema(description = "鍑哄樊鍦�/鍑哄彂鍩庡競")
-    private String departureCity;
-
-    /**
-     * 鐩殑鍦�/鐩殑鍩庡競
-     */
-    @Schema(description = "鐩殑鍦�/鐩殑鍩庡競")
-    private String destinationCity;
-
-    /**
-     * 閰掑簵鏍囧噯
-     */
-    @Schema(description = "閰掑簵鏍囧噯")
-    private BigDecimal hotelStandard;
-
-    /**
-     * 浣忓澶╂暟
-     */
-    @Schema(description = "浣忓澶╂暟")
-    private BigDecimal lodgingDays;
-
-    /**
-     * 鐢熸椿琛ヨ创
-     */
-    @Schema(description = "鐢熸椿琛ヨ创")
-    private BigDecimal mealAllowance;
-
-    /**
-     * 浜ら�氳ˉ璐�
-     */
-    @Schema(description = "浜ら�氳ˉ璐�")
-    private BigDecimal transportAllowance;
-
-    /**
-     * 浣忓闄愰
-     */
-    @Schema(description = "浣忓闄愰")
-    private BigDecimal lodgingLimit;
-
-    /**
-     * 鐗规壒鏍囪鏂囨湰锛屽鍦ㄦ爣鍑嗚寖鍥村唴/瓒呮爣鐗规壒
-     */
-    @Schema(description = "鐗规壒鏍囪鏂囨湰锛屽鍦ㄦ爣鍑嗚寖鍥村唴/瓒呮爣鐗规壒")
-    private String standardTag;
-
-    /**
-     * 鏄惁鍦ㄦ爣鍑嗗唴锛�1-鏄紝0-鍚�
-     */
-    @Schema(description = "鏄惁鍦ㄦ爣鍑嗗唴锛�1-鏄紝0-鍚�")
-    private Byte withinStandard;
-
-    /**
-     * 绉熸埛ID
-     */
-    @Schema(description = "绉熸埛ID")
-    private Long tenantId;
-
-    /**
-     * 鍒涘缓浜�
-     */
-    @Schema(description = "鍒涘缓浜�")
-    @TableField(fill = FieldFill.INSERT)
-    private Long createUser;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    /**
-     * 鏇存柊浜�
-     */
-    @Schema(description = "鏇存柊浜�")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Long updateUser;
-
-    /**
-     * 鏇存柊鏃堕棿
-     */
-    @Schema(description = "鏇存柊鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    /**
-     * 褰掑睘閮ㄩ棬ID
-     */
-    @Schema(description = "褰掑睘閮ㄩ棬ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/approve/pojo/KnowledgeBaseVector.java b/src/main/java/com/ruoyi/approve/pojo/KnowledgeBaseVector.java
deleted file mode 100644
index 1db31fc..0000000
--- a/src/main/java/com/ruoyi/approve/pojo/KnowledgeBaseVector.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.ruoyi.approve.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * 鐭ヨ瘑搴撴枃浠跺悜閲忚褰曡〃
- * knowledge_base_vector
- */
-@Data
-@TableName("knowledge_base_vector")
-@Schema(description = "鐭ヨ瘑搴撴枃浠跺悜閲忚褰�")
-public class KnowledgeBaseVector implements Serializable {
-    private static final long serialVersionUID = 1L;
-
-    @TableId(type = IdType.AUTO)
-    @Schema(description = "涓婚敭ID")
-    private Long id;
-
-    @Schema(description = "鍏宠仈鐭ヨ瘑搴揑D")
-    private Long knowledgeBaseId;
-
-    @Schema(description = "鍏宠仈鏂囦欢blob ID")
-    private Long storageBlobId;
-
-    @Schema(description = "鏂囦欢鍚嶇О")
-    private String fileName;
-
-    @Schema(description = "鏂囦欢绫诲瀷(docx/pdf/xlsx/txt绛�)")
-    private String fileType;
-
-    @Schema(description = "鍚戦噺鍖栫姸鎬�: 0-寰呭鐞�, 1-澶勭悊涓�, 2-宸插畬鎴�, 3-澶辫触")
-    private Integer vectorStatus;
-
-    @Schema(description = "鍚戦噺鍖栧け璐ュ師鍥�")
-    private String vectorError;
-
-    @Schema(description = "鍒囩墖鏁伴噺")
-    private Integer chunkCount;
-
-    @Schema(description = "鍚戦噺鍛藉悕绌洪棿")
-    private String namespace;
-
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @Schema(description = "鍒涘缓鏃堕棿")
-    private LocalDateTime createTime;
-
-    @TableField(fill = FieldFill.INSERT)
-    @Schema(description = "鍒涘缓浜�")
-    private Integer createUser;
-
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @Schema(description = "鏇存柊鏃堕棿")
-    private LocalDateTime updateTime;
-
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    @Schema(description = "鏇存柊浜�")
-    private Integer updateUser;
-
-    @TableField(fill = FieldFill.INSERT)
-    @Schema(description = "绉熸埛ID")
-    private Long tenantId;
-
-    @TableField(fill = FieldFill.INSERT)
-    @Schema(description = "閮ㄩ棬ID")
-    private Long deptId;
-
-    // 鍚戦噺鍖栫姸鎬佸父閲�
-    public static final int STATUS_PENDING = 0;
-    public static final int STATUS_PROCESSING = 1;
-    public static final int STATUS_COMPLETED = 2;
-    public static final int STATUS_FAILED = 3;
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/approve/service/ApprovalInstanceNodeService.java b/src/main/java/com/ruoyi/approve/service/ApprovalInstanceNodeService.java
deleted file mode 100644
index 8fa7c60..0000000
--- a/src/main/java/com/ruoyi/approve/service/ApprovalInstanceNodeService.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.approve.service;
-
-import com.ruoyi.approve.pojo.ApprovalInstanceNode;
-import com.baomidou.mybatisplus.extension.service.IService;
-
-/**
- * <p>
- * 瀹℃壒鑺傜偣瀹炰緥琛� 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:27:54
- */
-public interface ApprovalInstanceNodeService extends IService<ApprovalInstanceNode> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/ApprovalInstanceService.java b/src/main/java/com/ruoyi/approve/service/ApprovalInstanceService.java
deleted file mode 100644
index 005795d..0000000
--- a/src/main/java/com/ruoyi/approve/service/ApprovalInstanceService.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.ruoyi.approve.service;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
-import com.ruoyi.approve.bean.vo.ApprovalInstanceVo;
-import com.ruoyi.approve.pojo.ApprovalInstance;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.framework.web.domain.R;
-
-import java.util.List;
-
-/**
- * <p>
- * 瀹℃壒瀹炰緥琛� 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:27:46
- */
-public interface ApprovalInstanceService extends IService<ApprovalInstance> {
-
-    R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto);
-
-    Boolean add(ApprovalInstanceDto approvalInstanceDto);
-
-    Boolean update(ApprovalInstanceDto approvalInstanceDto);
-
-    Boolean delete(List<Long> ids);
-
-    R approve(ApprovalInstanceDto approvalInstanceDto);
-
-    R autoApprove(Long instanceId);
-}
diff --git a/src/main/java/com/ruoyi/approve/service/ApprovalRecordService.java b/src/main/java/com/ruoyi/approve/service/ApprovalRecordService.java
deleted file mode 100644
index 041571c..0000000
--- a/src/main/java/com/ruoyi/approve/service/ApprovalRecordService.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.approve.service;
-
-import com.ruoyi.approve.pojo.ApprovalRecord;
-import com.baomidou.mybatisplus.extension.service.IService;
-
-/**
- * <p>
- * 瀹℃壒璁板綍琛� 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:28:21
- */
-public interface ApprovalRecordService extends IService<ApprovalRecord> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/ApprovalTaskService.java b/src/main/java/com/ruoyi/approve/service/ApprovalTaskService.java
deleted file mode 100644
index 491e57d..0000000
--- a/src/main/java/com/ruoyi/approve/service/ApprovalTaskService.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.approve.service;
-
-import com.ruoyi.approve.pojo.ApprovalTask;
-import com.baomidou.mybatisplus.extension.service.IService;
-
-/**
- * <p>
- * 瀹℃壒浠诲姟琛� 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:32:37
- */
-public interface ApprovalTaskService extends IService<ApprovalTask> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/ApprovalTemplateNodeApproverService.java b/src/main/java/com/ruoyi/approve/service/ApprovalTemplateNodeApproverService.java
deleted file mode 100644
index e335276..0000000
--- a/src/main/java/com/ruoyi/approve/service/ApprovalTemplateNodeApproverService.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.approve.service;
-
-import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
-import com.baomidou.mybatisplus.extension.service.IService;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘鑺傜偣瀹℃壒浜鸿〃 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:30
- */
-public interface ApprovalTemplateNodeApproverService extends IService<ApprovalTemplateNodeApprover> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/ApprovalTemplateNodeService.java b/src/main/java/com/ruoyi/approve/service/ApprovalTemplateNodeService.java
deleted file mode 100644
index 4a8d6a8..0000000
--- a/src/main/java/com/ruoyi/approve/service/ApprovalTemplateNodeService.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.approve.service;
-
-import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeDto;
-import com.ruoyi.approve.pojo.ApprovalTemplateNode;
-import com.baomidou.mybatisplus.extension.service.IService;
-
-import java.util.List;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘鑺傜偣琛� 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:19
- */
-public interface ApprovalTemplateNodeService extends IService<ApprovalTemplateNode> {
-
-    Boolean saveApprovalTemplateNode(Long id, List<ApprovalTemplateNodeDto> nodes);
-}
diff --git a/src/main/java/com/ruoyi/approve/service/ApprovalTemplateService.java b/src/main/java/com/ruoyi/approve/service/ApprovalTemplateService.java
deleted file mode 100644
index 38bbabc..0000000
--- a/src/main/java/com/ruoyi/approve/service/ApprovalTemplateService.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.ruoyi.approve.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.approve.bean.dto.ApprovalTemplateDto;
-import com.ruoyi.approve.bean.vo.ApprovalTemplateVo;
-import com.ruoyi.approve.pojo.ApprovalTemplate;
-import com.baomidou.mybatisplus.extension.service.IService;
-
-import java.util.List;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘琛� 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:08
- */
-public interface ApprovalTemplateService extends IService<ApprovalTemplate> {
-
-    IPage<ApprovalTemplateVo> listPage(Page<ApprovalTemplateVo> page, ApprovalTemplateDto approvalTemplateDto);
-
-    Boolean saveApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto);
-
-    Boolean updateApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto);
-
-    Boolean delete(List<Long> ids);
-
-    List<ApprovalTemplateVo> listApprovalTemplateVo(Integer type);
-
-    ApprovalTemplateVo getApprovalTemplateVoById(Long id);
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/FinReimbursementDetailService.java b/src/main/java/com/ruoyi/approve/service/FinReimbursementDetailService.java
deleted file mode 100644
index 0279c25..0000000
--- a/src/main/java/com/ruoyi/approve/service/FinReimbursementDetailService.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.approve.service;
-
-import com.ruoyi.approve.pojo.FinReimbursementDetail;
-import com.baomidou.mybatisplus.extension.service.IService;
-
-/**
- * <p>
- * 鎶ラ攢鍗曟槑缁嗚〃 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:38
- */
-public interface FinReimbursementDetailService extends IService<FinReimbursementDetail> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/FinReimbursementService.java b/src/main/java/com/ruoyi/approve/service/FinReimbursementService.java
deleted file mode 100644
index c14b943..0000000
--- a/src/main/java/com/ruoyi/approve/service/FinReimbursementService.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.ruoyi.approve.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.approve.bean.dto.FinReimbursementDto;
-import com.ruoyi.approve.bean.vo.FinReimbursementVo;
-import com.ruoyi.approve.pojo.FinReimbursement;
-import com.baomidou.mybatisplus.extension.service.IService;
-
-import java.util.List;
-
-/**
- * <p>
- * 鎶ラ攢鍗曚富琛� 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:15
- */
-public interface FinReimbursementService extends IService<FinReimbursement> {
-
-    IPage<FinReimbursementVo> listPage(FinReimbursementDto finReimbursementDto, Page<FinReimbursementVo> page);
-
-    Boolean add(FinReimbursementDto finReimbursementDto);
-
-    FinReimbursementVo detail(Long id);
-
-    Boolean update(FinReimbursementDto finReimbursementDto);
-
-    Boolean delete(List<Long> ids);
-}
diff --git a/src/main/java/com/ruoyi/approve/service/FinReimbursementTravelService.java b/src/main/java/com/ruoyi/approve/service/FinReimbursementTravelService.java
deleted file mode 100644
index 0733d1b..0000000
--- a/src/main/java/com/ruoyi/approve/service/FinReimbursementTravelService.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.approve.service;
-
-import com.ruoyi.approve.pojo.FinReimbursementTravel;
-import com.baomidou.mybatisplus.extension.service.IService;
-
-/**
- * <p>
- * 宸梾鎶ラ攢鎵╁睍琛� 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:47
- */
-public interface FinReimbursementTravelService extends IService<FinReimbursementTravel> {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/KnowledgeBaseVectorService.java b/src/main/java/com/ruoyi/approve/service/KnowledgeBaseVectorService.java
deleted file mode 100644
index 10f2ca9..0000000
--- a/src/main/java/com/ruoyi/approve/service/KnowledgeBaseVectorService.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.ruoyi.approve.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.approve.dto.KnowledgeBaseVectorVO;
-import com.ruoyi.approve.pojo.KnowledgeBaseVector;
-
-import java.util.List;
-
-/**
- * 鐭ヨ瘑搴撴枃浠跺悜閲忚褰� Service
- */
-public interface KnowledgeBaseVectorService extends IService<KnowledgeBaseVector> {
-
-    /**
-     * 鏌ヨ鐭ヨ瘑搴撶殑鏂囦欢鍚戦噺鐘舵�佸垪琛�
-     */
-    List<KnowledgeBaseVectorVO> getVectorStatusByKnowledgeBaseId(Long knowledgeBaseId);
-
-    /**
-     * 鍒涘缓鍚戦噺璁板綍骞惰Е鍙戝紓姝ュ悜閲忓寲
-     */
-    KnowledgeBaseVector createVectorRecord(Long knowledgeBaseId, Long storageBlobId, String fileName, String fileType);
-
-    /**
-     * 鏇存柊鍚戦噺鐘舵��
-     */
-    void updateVectorStatus(Long id, Integer status, Integer chunkCount, String error);
-
-    /**
-     * 閲嶆柊澶勭悊鍚戦噺鍖�
-     */
-    void reprocessVector(Long id);
-
-    /**
-     * 鍒犻櫎鍚戦噺璁板綍鍙婄浉鍏冲悜閲忔暟鎹�
-     */
-    void deleteVector(Long id);
-
-    /**
-     * 鎵归噺鍒犻櫎鍚戦噺璁板綍
-     */
-    void deleteVectors(List<Long> ids);
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceNodeServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceNodeServiceImpl.java
deleted file mode 100644
index 9ea1963..0000000
--- a/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceNodeServiceImpl.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.approve.service.impl;
-
-import com.ruoyi.approve.pojo.ApprovalInstanceNode;
-import com.ruoyi.approve.mapper.ApprovalInstanceNodeMapper;
-import com.ruoyi.approve.service.ApprovalInstanceNodeService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import org.springframework.stereotype.Service;
-
-/**
- * <p>
- * 瀹℃壒鑺傜偣瀹炰緥琛� 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:27:54
- */
-@Service
-public class ApprovalInstanceNodeServiceImpl extends ServiceImpl<ApprovalInstanceNodeMapper, ApprovalInstanceNode> implements ApprovalInstanceNodeService {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
deleted file mode 100644
index 62d083d..0000000
--- a/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
+++ /dev/null
@@ -1,876 +0,0 @@
-package com.ruoyi.approve.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
-import com.ruoyi.approve.bean.vo.ApprovalInstanceVo;
-import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
-import com.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper;
-import com.ruoyi.approve.mapper.FinReimbursementMapper;
-import com.ruoyi.approve.pojo.*;
-import com.ruoyi.approve.service.*;
-import com.ruoyi.approve.utils.ApproveProcessConfigNodeUtils;
-import com.ruoyi.basic.enums.ApplicationTypeEnum;
-import com.ruoyi.basic.enums.RecordTypeEnum;
-import com.ruoyi.basic.utils.FileUtil;
-import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsMapper;
-import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeDeptMapper;
-import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeUserMapper;
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept;
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser;
-import com.ruoyi.common.enums.*;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.utils.OrderUtils;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.web.domain.R;
-import com.ruoyi.procurementrecord.utils.StockUtils;
-import com.ruoyi.project.system.domain.SysDept;
-import com.ruoyi.project.system.domain.SysUser;
-import com.ruoyi.project.system.mapper.SysDeptMapper;
-import com.ruoyi.project.system.mapper.SysUserDeptMapper;
-import com.ruoyi.project.system.mapper.SysUserMapper;
-import com.ruoyi.project.system.service.ISysNoticeService;
-import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
-import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.quality.utils.QualityInspectHelper;
-import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.mapper.SalesQuotationMapper;
-import com.ruoyi.sales.mapper.ShippingInfoMapper;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import com.ruoyi.sales.pojo.SalesQuotation;
-import com.ruoyi.sales.pojo.ShippingInfo;
-import com.ruoyi.staff.mapper.HolidayApplicationMapper;
-import com.ruoyi.staff.pojo.HolidayApplication;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.StringUtils;
-
-import java.time.LocalDateTime;
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * <p>
- * 瀹℃壒瀹炰緥鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @since 2026-05-18 03:27:46
- */
-@Service
-@RequiredArgsConstructor
-public class ApprovalInstanceServiceImpl extends ServiceImpl<ApprovalInstanceMapper, ApprovalInstance> implements ApprovalInstanceService {
-
-    private static final String ENTERPRISE_NEWS_STATUS_PUBLISHED = "PUBLISHED";
-    private static final String ENTERPRISE_NEWS_STATUS_REJECTED = "REJECTED";
-
-    private final ApprovalInstanceMapper approvalInstanceMapper;
-    private final ApproveProcessConfigNodeUtils approveProcessConfigNodeUtils;
-    private final ApprovalInstanceNodeService approvalInstanceNodeService;
-    private final ApprovalTaskService approvalTaskService;
-    private final ApprovalRecordService approvalRecordService;
-    private final ApprovalTemplateNodeService approvalTemplateNodeService;
-    private final FinReimbursementMapper finReimbursementMapper;
-    private final FileUtil fileUtil;
-    private final ISysNoticeService sysNoticeService;
-    private final PurchaseLedgerMapper purchaseLedgerMapper;
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-    private final StockUtils stockUtils;
-    private final SalesQuotationMapper salesQuotationMapper;
-    private final ShippingInfoMapper shippingInfoMapper;
-    private final QualityInspectHelper qualityInspectHelper;
-    private final EnterpriseNewsScopeUserMapper enterpriseNewsScopeUserMapper;
-    private final SysUserMapper sysUserMapper;
-    private final SysUserDeptMapper sysUserDeptMapper;
-    private final SysDeptMapper sysDeptMapper;
-    private final HolidayApplicationMapper holidayApplicationMapper;
-    private final EnterpriseNewsMapper enterpriseNewsMapper;
-    private final EnterpriseNewsScopeDeptMapper enterpriseNewsScopeDeptMapper;
-    private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper;
-
-    @Override
-    public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) {
-        IPage<ApprovalInstanceVo> approvalInstanceVoIPage = approvalInstanceMapper.listPage(page, approvalInstanceDto);
-
-        List<ApprovalInstanceVo> records = approvalInstanceVoIPage.getRecords();
-        if (records == null || records.isEmpty()) {
-            return R.ok(approvalInstanceVoIPage);
-        }
-        records.forEach(vo -> {
-            vo.setBusinessName(TypeEnums.getLabelByValue(vo.getBusinessType()));
-
-            // 鏍规嵁涓氬姟绫诲瀷鏌ヨ瀵瑰簲鐨勫崟鍙�
-            if (vo.getBusinessType() != null && vo.getBusinessId() != null) {
-                if (TypeEnums.PURCHASE_APPROVAL.getCode().equals(vo.getBusinessType())) {
-                    // 閲囪喘瀹℃壒 - 鏌ヨ閲囪喘鍗曞彿
-                    PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(vo.getBusinessId());
-                    if (purchaseLedger != null) {
-                        vo.setPurchaseContractNumber(purchaseLedger.getPurchaseContractNumber());
-                    }
-                } else if (TypeEnums.QUOTATION_APPROVAL.getCode().equals(vo.getBusinessType())) {
-                    // 鎶ヤ环瀹℃壒 - 鏌ヨ鎶ヤ环鍗曞彿
-                    SalesQuotation salesQuotation = salesQuotationMapper.selectById(vo.getBusinessId());
-                    if (salesQuotation != null) {
-                        vo.setQuotationNo(salesQuotation.getQuotationNo());
-                    }
-                } else if (TypeEnums.SHIPPING_APPROVAL.getCode().equals(vo.getBusinessType())) {
-                    // 鍙戣揣瀹℃壒 - 鏌ヨ鍙戣揣鍗曞彿
-                    ShippingInfo shippingInfo = shippingInfoMapper.selectById(vo.getBusinessId());
-                    if (shippingInfo != null) {
-                        vo.setShippingNo(shippingInfo.getShippingNo());
-                    }
-                }
-            }
-        });
-        Long currentUserId = SecurityUtils.getUserId();
-
-        List<Long> instanceIds = records.stream()
-                .map(ApprovalInstanceVo::getId)
-                .filter(id -> id != null)
-                .distinct()
-                .collect(Collectors.toList());
-
-        if (!instanceIds.isEmpty()) {
-            Map<Long, List<ApprovalRecord>> recordMap = approvalRecordService.list(
-                    Wrappers.<ApprovalRecord>lambdaQuery()
-                            .in(ApprovalRecord::getInstanceId, instanceIds)
-                            .eq(ApprovalRecord::getDeleted, 0)
-            ).stream().collect(Collectors.groupingBy(ApprovalRecord::getInstanceId));
-            Map<Long, List<ApprovalTask>> taskMap = approvalTaskService.list(
-                    Wrappers.<ApprovalTask>lambdaQuery()
-                            .in(ApprovalTask::getInstanceId, instanceIds)
-                            .eq(ApprovalTask::getDeleted, 0)
-            ).stream().collect(Collectors.groupingBy(ApprovalTask::getInstanceId));
-
-            for (ApprovalInstanceVo vo : records) {
-                vo.setIsApprove(approveProcessConfigNodeUtils.isCurrentApprover(vo.getId(), currentUserId));
-                vo.setRecords(recordMap.getOrDefault(vo.getId(), new ArrayList<>()));
-                vo.setTasks(taskMap.getOrDefault(vo.getId(), new ArrayList<>()));
-                vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.APPROVAL_INSTANCE, vo.getId()));
-            }
-
-        }
-        return R.ok(approvalInstanceVoIPage);
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Boolean add(ApprovalInstanceDto approvalInstanceDto) {
-        String instanceNo = OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no", approvalInstanceDto.getCreateTime() != null ? approvalInstanceDto.getCreateTime() : LocalDateTime.now());
-        approvalInstanceDto.setInstanceNo(instanceNo);
-        approvalInstanceDto.setStatus("PENDING");
-        approvalInstanceDto.setCurrentLevel(1);
-        boolean saved = this.save(approvalInstanceDto);
-        if (!saved) {
-            return false;
-        }
-        approveProcessConfigNodeUtils.createCurrentNodeAndTasks(approvalInstanceDto);
-        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, approvalInstanceDto.getId(), approvalInstanceDto.getStorageBlobDTOs());
-        sendApproveNotice(approvalInstanceDto, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId()));
-        return true;
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Boolean update(ApprovalInstanceDto approvalInstanceDto) {
-        if (approvalInstanceDto == null || approvalInstanceDto.getId() == null) {
-            return false;
-        }
-        // 鍒ゆ柇鏄惁鏈夋鍦ㄨ繘琛岀殑瀹℃壒浠诲姟锛屾湁鍒欎笉鍏佽淇敼
-        long pendingTaskCount = approvalTaskService.count(
-                Wrappers.<ApprovalTask>lambdaQuery()
-                        .eq(ApprovalTask::getInstanceId, approvalInstanceDto.getId())
-                        .eq(ApprovalTask::getTaskStatus, "PENDING")
-                        .eq(ApprovalTask::getDeleted, 0)
-        );
-        if (pendingTaskCount > 0) {
-            throw new ServiceException("璇ュ鎵瑰崟鏈夋鍦ㄨ繘琛岀殑瀹℃壒浠诲姟锛屼笉鍏佽淇敼");
-        }
-        boolean updated = this.updateById(approvalInstanceDto);
-        if (!updated) {
-            return false;
-        }
-        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, approvalInstanceDto.getId(), approvalInstanceDto.getStorageBlobDTOs());
-        return true;
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Boolean delete(List<Long> ids) {
-        if (ids == null || ids.isEmpty()) {
-            return false;
-        }
-        fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, ids);
-
-        int instanceRows = approvalInstanceMapper.update(
-                null,
-                Wrappers.<ApprovalInstance>lambdaUpdate()
-                        .in(ApprovalInstance::getId, ids)
-                        .eq(ApprovalInstance::getDeleted, 0)
-                        .set(ApprovalInstance::getDeleted, (byte) 1)
-        );
-
-        LambdaUpdateWrapper<ApprovalInstanceNode> nodeUpdateWrapper = Wrappers.lambdaUpdate();
-        nodeUpdateWrapper.in(ApprovalInstanceNode::getInstanceId, ids)
-                .eq(ApprovalInstanceNode::getDeleted, 0)
-                .set(ApprovalInstanceNode::getDeleted, (byte) 1);
-        approvalInstanceNodeService.update(nodeUpdateWrapper);
-
-        LambdaUpdateWrapper<ApprovalTask> taskUpdateWrapper = Wrappers.lambdaUpdate();
-        taskUpdateWrapper.in(ApprovalTask::getInstanceId, ids)
-                .eq(ApprovalTask::getDeleted, 0)
-                .set(ApprovalTask::getDeleted, (byte) 1);
-        approvalTaskService.update(taskUpdateWrapper);
-
-        LambdaUpdateWrapper<ApprovalRecord> recordUpdateWrapper = Wrappers.lambdaUpdate();
-        recordUpdateWrapper.in(ApprovalRecord::getInstanceId, ids)
-                .eq(ApprovalRecord::getDeleted, 0)
-                .set(ApprovalRecord::getDeleted, (byte) 1);
-        approvalRecordService.update(recordUpdateWrapper);
-
-        return instanceRows > 0;
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public R approve(ApprovalInstanceDto approvalInstanceDto) {
-        if (approvalInstanceDto == null || approvalInstanceDto.getId() == null) {
-            return R.fail("瀹℃壒瀹炰緥 ID 涓嶈兘涓虹┖");
-        }
-        String approveAction = normalizeApproveAction(approvalInstanceDto.getApproveAction());
-        if (approveAction == null) {
-            return R.fail("瀹℃壒鍔ㄤ綔鍙敮鎸� APPROVED 鎴� REJECTED");
-        }
-
-        ApprovalInstance instance = getPendingApprovalInstance(approvalInstanceDto.getId());
-        if (instance == null) {
-            return R.fail("瀹℃壒瀹炰緥涓嶅瓨鍦�");
-        }
-
-        ApprovalInstanceNode currentNode = approveProcessConfigNodeUtils.getCurrentNode(instance.getId());
-        if (currentNode == null) {
-            return R.fail("褰撳墠娌℃湁寰呭鐞嗙殑瀹℃壒鑺傜偣");
-        }
-
-        Long currentUserId = SecurityUtils.getUserId();
-        ApprovalTask currentTask = approveProcessConfigNodeUtils.getCurrentUserTask(instance.getId(), currentUserId);
-        if (currentTask == null) {
-            return R.fail("褰撳墠鐢ㄦ埛娌℃湁鍙鎵逛换鍔�");
-        }
-
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        String operatorName = loginUser.getUser() != null ? loginUser.getUser().getNickName() : SecurityUtils.getUsername();
-        LocalDateTime now = LocalDateTime.now();
-
-        if (!updateCurrentTask(approvalInstanceDto, approveAction, currentTask, now)) {
-            return R.fail("褰撳墠浠诲姟宸茶澶勭悊锛岃鍒锋柊鍚庨噸璇�");
-        }
-
-        saveApprovalRecord(
-                instance.getId(),
-                currentNode.getId(),
-                currentTask.getId(),
-                currentUserId,
-                operatorName,
-                approveAction,
-                approvalInstanceDto.getApproveComment()
-        );
-        //瀹℃壒鎷掔粷鐨勫鐞�
-        if ("REJECTED".equals(approveAction)) {
-            return rejectCurrentNode(instance, currentNode, now);
-        }
-        if (!approveProcessConfigNodeUtils.canProceedToNextLevel(instance.getId(), currentNode.getApproveType())) {
-            return R.ok("瀹℃壒鎴愬姛锛岀瓑寰呭叾浠栧鎵逛汉澶勭悊");
-        }
-
-        return approveAndMoveNext(instance, currentNode, approvalInstanceDto, now);
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public R autoApprove(Long instanceId) {
-        if (instanceId == null) {
-            return R.fail("瀹℃壒瀹炰緥 ID 涓嶈兘涓虹┖");
-        }
-
-        ApprovalInstance instance = getPendingApprovalInstance(instanceId);
-        if (instance == null) {
-            return R.fail("瀹℃壒瀹炰緥涓嶅瓨鍦�");
-        }
-        if ("REJECTED".equals(instance.getStatus())) {
-            return R.fail("瀹℃壒宸查┏鍥烇紝鏃犳硶鑷姩閫氳繃");
-        }
-        if ("APPROVED".equals(instance.getStatus())) {
-            return R.ok("瀹℃壒宸插畬鎴�");
-        }
-
-        ApprovalInstanceDto autoApproveDto = new ApprovalInstanceDto();
-        autoApproveDto.setId(instanceId);
-        autoApproveDto.setApproveComment("绯荤粺鑷姩瀹℃壒");
-
-        int loopCount = 0;
-        while (loopCount++ < 20) {
-            ApprovalInstance currentInstance = getPendingApprovalInstance(instanceId);
-            if (currentInstance == null) {
-                return R.fail("瀹℃壒瀹炰緥涓嶅瓨鍦�");
-            }
-            if ("APPROVED".equals(currentInstance.getStatus())) {
-                return R.ok("瀹℃壒宸插畬鎴�");
-            }
-            if ("REJECTED".equals(currentInstance.getStatus())) {
-                return R.fail("瀹℃壒宸查┏鍥烇紝鏃犳硶鑷姩閫氳繃");
-            }
-
-            ApprovalInstanceNode currentNode = approveProcessConfigNodeUtils.getCurrentNode(currentInstance.getId());
-            if (currentNode == null) {
-                currentInstance.setStatus("APPROVED");
-                currentInstance.setFinishTime(LocalDateTime.now());
-                this.updateById(currentInstance);
-                handleBusinessAfterApprovalFinished(currentInstance);
-                return R.ok("瀹℃壒宸插畬鎴�");
-            }
-
-            List<ApprovalTask> pendingTasks = approvalTaskService.list(
-                    Wrappers.<ApprovalTask>lambdaQuery()
-                            .eq(ApprovalTask::getInstanceId, currentInstance.getId())
-                            .eq(ApprovalTask::getNodeId, currentNode.getId())
-                            .eq(ApprovalTask::getTaskStatus, "PENDING")
-                            .eq(ApprovalTask::getDeleted, 0)
-            );
-
-            LocalDateTime now = LocalDateTime.now();
-            for (ApprovalTask currentTask : pendingTasks) {
-                if (!updateCurrentTask(autoApproveDto, "APPROVED", currentTask, now)) {
-                    return R.fail("褰撳墠浠诲姟宸茶澶勭悊锛岃鍒锋柊鍚庨噸璇�");
-                }
-                saveApprovalRecord(
-                        currentInstance.getId(),
-                        currentNode.getId(),
-                        currentTask.getId(),
-                        0L,
-                        "绯荤粺鑷姩瀹℃壒",
-                        "APPROVED",
-                        autoApproveDto.getApproveComment()
-                );
-            }
-
-            if (!approveProcessConfigNodeUtils.canProceedToNextLevel(currentInstance.getId(), currentNode.getApproveType())) {
-                return R.ok("瀹℃壒鎴愬姛锛岀瓑寰呭叾浠栧鎵逛汉澶勭悊");
-            }
-
-            R moveResult = moveToNextLevel(currentInstance, currentNode, autoApproveDto, now, false);
-            if (!R.isSuccess(moveResult)) {
-                return moveResult;
-            }
-        }
-
-        return R.fail("鑷姩瀹℃壒寰幆娆℃暟瓒呴檺");
-    }
-
-    private String normalizeApproveAction(String approveAction) {
-        if (!StringUtils.hasText(approveAction)) {
-            return null;
-        }
-        String normalizedAction = approveAction.trim().toUpperCase(Locale.ROOT);
-        return "APPROVED".equals(normalizedAction) || "REJECTED".equals(normalizedAction)
-                ? normalizedAction
-                : null;
-    }
-
-    private ApprovalInstance getPendingApprovalInstance(Long instanceId) {
-        return this.getOne(
-                new LambdaQueryWrapper<ApprovalInstance>()
-                        .eq(ApprovalInstance::getId, instanceId)
-                        .eq(ApprovalInstance::getDeleted, 0)
-                        .last("LIMIT 1")
-        );
-    }
-
-    private boolean updateCurrentTask(ApprovalInstanceDto approvalInstanceDto,
-                                      String approveAction,
-                                      ApprovalTask currentTask,
-                                      LocalDateTime now) {
-        // 浠呭厑璁稿緟瀹℃壒浠诲姟琚垚鍔熷鐞嗕竴娆★紝閬垮厤骞跺彂涓嬮噸澶嶅鎵规垚鍔熴��
-        return approvalTaskService.update(
-                Wrappers.<ApprovalTask>lambdaUpdate()
-                        .eq(ApprovalTask::getId, currentTask.getId())
-                        .eq(ApprovalTask::getTaskStatus, "PENDING")
-                        .eq(ApprovalTask::getDeleted, 0)
-                        .set(ApprovalTask::getTaskStatus, approveAction)
-                        .set(ApprovalTask::getComment, approvalInstanceDto.getApproveComment())
-                        .set(ApprovalTask::getApproveTime, now)
-                        .set(ApprovalTask::getIsRead, (byte) 1)
-        );
-    }
-
-    private R rejectCurrentNode(ApprovalInstance instance, ApprovalInstanceNode currentNode, LocalDateTime now) {
-        if (!updateCurrentNodeStatus(currentNode.getId(), "REJECTED", now)) {
-            return R.ok("褰撳墠鑺傜偣宸插鐞嗗畬鎴�");
-        }
-
-        closePendingTasks(instance.getId(), currentNode.getId());
-        instance.setStatus("REJECTED");
-        instance.setFinishTime(now);
-        this.updateById(instance);
-        // 缁熶竴澶勭悊涓氬姟鐘舵�佹洿鏂�
-        handleBusinessAfterApprovalFinished(instance);
-        return R.ok("瀹℃壒宸查┏鍥�");
-    }
-
-    private R approveAndMoveNext(ApprovalInstance instance,
-                                 ApprovalInstanceNode currentNode,
-                                 ApprovalInstanceDto approvalInstanceDto,
-                                 LocalDateTime now) {
-        return moveToNextLevel(instance, currentNode, approvalInstanceDto, now, true);
-    }
-
-    private R moveToNextLevel(ApprovalInstance instance,
-                              ApprovalInstanceNode currentNode,
-                              ApprovalInstanceDto approvalInstanceDto,
-                              LocalDateTime now,
-                              boolean notifyNextNode) {
-        if (!updateCurrentNodeStatus(currentNode.getId(), "APPROVED", now)) {
-            return R.ok("褰撳墠鑺傜偣宸插鐞嗗畬鎴�");
-        }
-
-        closePendingTasks(instance.getId(), currentNode.getId());
-
-        int nextLevel = currentNode.getLevelNo() + 1;
-        ApprovalInstanceNode nextInstanceNode = approvalInstanceNodeService.getOne(
-                new LambdaQueryWrapper<ApprovalInstanceNode>()
-                        .eq(ApprovalInstanceNode::getInstanceId, instance.getId())
-                        .eq(ApprovalInstanceNode::getLevelNo, nextLevel)
-                        .eq(ApprovalInstanceNode::getDeleted, 0)
-                        .orderByAsc(ApprovalInstanceNode::getId)
-                        .last("LIMIT 1")
-        );
-
-        if (nextInstanceNode != null) {
-            if (!activateNextInstanceNode(nextInstanceNode.getId(), now)) {
-                return R.ok("涓嬩竴瀹℃壒鑺傜偣宸茶婵�娲伙紝璇峰埛鏂板悗閲嶈瘯");
-            }
-            instance.setCurrentLevel(nextLevel);
-            instance.setStatus("PENDING");
-            this.updateById(instance);
-            if (notifyNextNode) {
-                List<ApprovalTask> nextTasks = approvalTaskService.list(
-                        Wrappers.<ApprovalTask>lambdaQuery()
-                                .eq(ApprovalTask::getInstanceId, instance.getId())
-                                .eq(ApprovalTask::getNodeId, nextInstanceNode.getId())
-                                .eq(ApprovalTask::getTaskStatus, "PENDING")
-                                .eq(ApprovalTask::getDeleted, 0)
-                );
-                sendApproveNotice(instance, nextTasks);
-            }
-            return R.ok("瀹℃壒鎴愬姛锛屽凡娴佽浆鍒颁笅涓�鑺傜偣");
-        }
-
-        ApprovalTemplateNode nextTemplateNode = approvalTemplateNodeService.getOne(
-                new LambdaQueryWrapper<ApprovalTemplateNode>()
-                        .eq(ApprovalTemplateNode::getTemplateId, instance.getTemplateId())
-                        .eq(ApprovalTemplateNode::getLevelNo, nextLevel)
-                        .orderByAsc(ApprovalTemplateNode::getId)
-                        .last("LIMIT 1")
-        );
-
-        if (nextTemplateNode == null) {
-            instance.setStatus("APPROVED");
-            instance.setFinishTime(now);
-            this.updateById(instance);
-            handleBusinessAfterApprovalFinished(instance);
-            return R.ok("瀹℃壒宸插畬鎴�");
-        }
-
-        instance.setCurrentLevel(nextLevel);
-        instance.setStatus("PENDING");
-        this.updateById(instance);
-        approveProcessConfigNodeUtils.createCurrentNodeAndTasks(instance, false);
-        if (notifyNextNode) {
-            sendApproveNotice(instance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId()));
-        }
-        return R.ok("瀹℃壒鎴愬姛锛屽凡娴佽浆鍒颁笅涓�鑺傜偣");
-    }
-
-    private boolean activateNextInstanceNode(Long nodeId, LocalDateTime now) {
-        return approvalInstanceNodeService.update(
-                Wrappers.<ApprovalInstanceNode>lambdaUpdate()
-                        .eq(ApprovalInstanceNode::getId, nodeId)
-                        .eq(ApprovalInstanceNode::getStatus, "WAITING")
-                        .eq(ApprovalInstanceNode::getDeleted, 0)
-                        .set(ApprovalInstanceNode::getStatus, "PENDING")
-                        .set(ApprovalInstanceNode::getStartTime, now)
-        );
-    }
-
-    private boolean updateCurrentNodeStatus(Long nodeId, String targetStatus, LocalDateTime now) {
-        // 浠呭厑璁镐竴涓姹傚皢褰撳墠鑺傜偣浠庡緟澶勭悊鎺ㄨ繘鍒扮洰鏍囩姸鎬侊紝閬垮厤閲嶅娴佽浆銆�
-        return approvalInstanceNodeService.update(
-                Wrappers.<ApprovalInstanceNode>lambdaUpdate()
-                        .eq(ApprovalInstanceNode::getId, nodeId)
-                        .eq(ApprovalInstanceNode::getStatus, "PENDING")
-                        .eq(ApprovalInstanceNode::getDeleted, 0)
-                        .set(ApprovalInstanceNode::getStatus, targetStatus)
-                        .set(ApprovalInstanceNode::getFinishTime, now)
-        );
-    }
-
-    private void handleBusinessAfterApprovalFinished(ApprovalInstance instance) {
-        String status = instance.getStatus();
-        Long businessType = instance.getBusinessType();
-        if (TypeEnums.PURCHASE_APPROVAL.getCode().equals(businessType)) {
-            handlePurchaseApprovalFinished(instance, status);
-            return;
-        }
-        if (TypeEnums.QUOTATION_APPROVAL.getCode().equals(businessType)) {
-            handleSalesQuotationApprovalFinished(instance, status);
-            return;
-        }
-        if (TypeEnums.SHIPPING_APPROVAL.getCode().equals(businessType)) {
-            handleShippingApprovalFinished(instance, status);
-            return;
-        }
-        if (TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode().equals(businessType)
-                || TypeEnums.EXPENSE_APPROVAL.getCode().equals(businessType)) {
-            handleReimbursementApprovalFinished(instance, status);
-            return;
-        }
-        // 椹冲洖瀵瑰簲鐨勪紒涓氭柊闂汇�佸姞鐝敵璇枫�佽鍋囩敵璇峰彲浠ラ噸鏂板啀鎻愪氦
-        if (TypeEnums.LEAVE_APPROVAL.getCode().equals(businessType)
-                || TypeEnums.OVERTIME_APPROVAL.getCode().equals(businessType)) {
-            handleHolidayApplicationApprovalFinished(instance, status);
-            return;
-        }
-        if (TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode().equals(businessType)) {
-            handleNewsApprovalFinished(instance, status);
-        }
-    }
-
-    private void handleReimbursementApprovalFinished(ApprovalInstance instance, String status) {
-        if (instance == null || instance.getBusinessId() == null) {
-            return;
-        }
-
-        FinReimbursement reimbursement = new FinReimbursement();
-        reimbursement.setId(instance.getBusinessId());
-        if ("APPROVED".equals(status)) {
-            reimbursement.setBillStatus("APPROVED");
-            reimbursement.setApprovedTime(instance.getFinishTime());
-        } else if ("REJECTED".equals(status)) {
-            reimbursement.setBillStatus("REJECTED");
-        } else if ("PENDING".equals(status)) {
-            reimbursement.setBillStatus("IN_APPROVAL");
-        } else {
-            return;
-        }
-        finReimbursementMapper.updateById(reimbursement);
-    }
-
-    private void handleNewsApprovalFinished(ApprovalInstance instance, String status) {
-        if (instance == null || instance.getBusinessId() == null) {
-            return;
-        }
-        EnterpriseNews enterpriseNews = new EnterpriseNews();
-        enterpriseNews.setId(instance.getBusinessId());
-        if ("APPROVED".equals(status)) {
-            enterpriseNews.setStatus(ENTERPRISE_NEWS_STATUS_PUBLISHED);
-            enterpriseNewsMapper.updateById(enterpriseNews);
-            sendEnterpriseNewsNotice(instance.getBusinessId());
-            return;
-        }
-        if ("REJECTED".equals(status)) {
-            enterpriseNews.setStatus(ENTERPRISE_NEWS_STATUS_REJECTED);
-            enterpriseNewsMapper.updateById(enterpriseNews);
-        }
-    }
-
-    private void handleHolidayApplicationApprovalFinished(ApprovalInstance instance, String status) {
-        if (instance == null || instance.getBusinessId() == null) {
-            return;
-        }
-        HolidayApplication holidayApplication = new HolidayApplication();
-        holidayApplication.setId(instance.getBusinessId());
-        if ("APPROVED".equals(status)) {
-            holidayApplication.setStatus("APPROVED");
-        } else if ("REJECTED".equals(status)) {
-            holidayApplication.setStatus("REJECTED");
-        } else if ("PENDING".equals(status)) {
-            holidayApplication.setStatus("PENDING");
-        } else {
-            return;
-        }
-        holidayApplicationMapper.updateById(holidayApplication);
-    }
-
-    private void handlePurchaseApprovalFinished(ApprovalInstance instance, String status) {
-        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(
-                new LambdaQueryWrapper<PurchaseLedger>()
-                        .eq(PurchaseLedger::getId, instance.getBusinessId())
-                        .last("limit 1")
-        );
-        if (purchaseLedger == null) {
-            return;
-        }
-
-        if ("APPROVED".equals(status)) {
-            purchaseLedger.setApprovalStatus(ApprovalStatusEnum.APPROVED.getCode());
-            List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(
-                    new QueryWrapper<SalesLedgerProduct>().lambda()
-                            .eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId())
-                            .eq(SalesLedgerProduct::getType, 2)
-            );
-            for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
-                if (salesLedgerProduct.getIsChecked()) {
-                    qualityInspectHelper.addQualityInspect(purchaseLedger, salesLedgerProduct);
-                } else {
-                    stockUtils.addStockWithBatchNo(
-                            salesLedgerProduct.getProductModelId(),
-                            salesLedgerProduct.getQuantity(),
-                            StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(),
-                            purchaseLedger.getId(),
-                            purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId()
-                    );
-                }
-            }
-        } else if ("REJECTED".equals(status)) {
-            purchaseLedger.setApprovalStatus(ApprovalStatusEnum.REJECTED.getCode());
-        } else if ("PENDING".equals(status)) {
-            purchaseLedger.setApprovalStatus(ApprovalStatusEnum.IN_PROGRESS.getCode());
-        }
-        purchaseLedgerMapper.updateById(purchaseLedger);
-    }
-
-    private void handleSalesQuotationApprovalFinished(ApprovalInstance instance, String status) {
-        SalesQuotation salesQuote = salesQuotationMapper.selectOne(
-                new LambdaQueryWrapper<SalesQuotation>()
-                        .eq(SalesQuotation::getId, instance.getBusinessId())
-                        .last("limit 1")
-        );
-        if (salesQuote == null) {
-            return;
-        }
-
-        if ("APPROVED".equals(status)) {
-            salesQuote.setStatus(SalesQuotationStatusEnum.APPROVED.getCode());
-        } else if ("REJECTED".equals(status)) {
-            salesQuote.setStatus(SalesQuotationStatusEnum.REJECTED.getCode());
-        } else if ("PENDING".equals(status)) {
-            salesQuote.setStatus(SalesQuotationStatusEnum.IN_PROGRESS.getCode());
-        }
-        salesQuotationMapper.updateById(salesQuote);
-    }
-
-    private void handleShippingApprovalFinished(ApprovalInstance instance, String status) {
-        ShippingInfo shippingInfo = shippingInfoMapper.selectOne(
-                new LambdaQueryWrapper<ShippingInfo>()
-                        .eq(ShippingInfo::getShippingNo, instance.getTitle())
-                        .orderByDesc(ShippingInfo::getCreateTime)
-                        .last("limit 1")
-        );
-        if (shippingInfo == null) {
-            return;
-        }
-
-        if ("APPROVED".equals(status)) {
-            shippingInfo.setStatus(ShippingStatusEnum.APPROVED.getCode());
-            shippingInfo.setShippingDate(new Date());
-            stockUtils.shipmentStatus(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), shippingInfo.getId());
-        } else if ("REJECTED".equals(status)) {
-            stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
-            shippingInfo.setStatus(ShippingStatusEnum.REJECTED.getCode());
-        } else if ("PENDING".equals(status)) {
-            shippingInfo.setStatus(ShippingStatusEnum.IN_PROGRESS.getCode());
-        }
-        shippingInfoMapper.updateById(shippingInfo);
-    }
-
-    private List<ApprovalTask> createNodeAndTasks(ApprovalInstance instance, ApprovalTemplateNode templateNode) {
-        List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverMapper.selectList(
-                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
-                        .eq(ApprovalTemplateNodeApprover::getTemplateId, instance.getTemplateId())
-                        .eq(ApprovalTemplateNodeApprover::getNodeId, templateNode.getId())
-                        .eq(ApprovalTemplateNodeApprover::getDeleted, 0L)
-                        .orderByAsc(ApprovalTemplateNodeApprover::getSortNo)
-        );
-        if (approvers == null || approvers.isEmpty()) {
-            throw new RuntimeException("涓嬩竴瀹℃壒鑺傜偣鏈厤缃鎵逛汉");
-        }
-
-        ApprovalInstanceNode instanceNode = new ApprovalInstanceNode();
-        instanceNode.setInstanceId(instance.getId());
-        instanceNode.setLevelNo(templateNode.getLevelNo());
-        instanceNode.setApproveType(templateNode.getApproveType());
-        instanceNode.setStatus("PENDING");
-        instanceNode.setStartTime(LocalDateTime.now());
-        instanceNode.setDeleted((byte) 0);
-        approvalInstanceNodeService.save(instanceNode);
-
-        List<ApprovalTask> taskList = new ArrayList<>(approvers.size());
-        for (ApprovalTemplateNodeApprover approver : approvers) {
-            ApprovalTask task = new ApprovalTask();
-            task.setInstanceId(instance.getId());
-            task.setNodeId(instanceNode.getId());
-            task.setLevelNo(instanceNode.getLevelNo());
-            task.setApproverId(approver.getApproverId());
-            task.setApproverName(approver.getApproverName());
-            task.setTaskStatus("PENDING");
-            task.setIsRead((byte) 0);
-            task.setDeleted((byte) 0);
-            taskList.add(task);
-        }
-        approvalTaskService.saveBatch(taskList);
-        return taskList;
-    }
-
-    private void sendApproveNotice(ApprovalInstance instance, List<ApprovalTask> tasks) {
-        if (instance == null || tasks == null || tasks.isEmpty()) {
-            return;
-        }
-
-        List<Long> approverIds = tasks.stream()
-                .map(ApprovalTask::getApproverId)
-                .filter(id -> id != null && id > 0)
-                .distinct()
-                .collect(Collectors.toList());
-        if (approverIds.isEmpty()) {
-            return;
-        }
-
-        String title = StringUtils.hasText(instance.getTemplateName()) ? instance.getTemplateName() : "瀹℃壒鎻愰啋";
-        String message = "瀹℃壒鍗曞彿 " + instance.getInstanceNo() + " 闇�瑕佹偍瀹℃壒";
-        String jumpPath = getJumpPathByBusinessType(instance.getBusinessType(), instance.getId());
-        sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath);
-    }
-
-    private String getJumpPathByBusinessType(Long businessType, Long instanceId) {
-        if (businessType == null) {
-            return "/collaborativeApproval/approve-list?id=" + instanceId;
-        }
-        if (TypeEnums.LEAVE_APPROVAL.getCode().equals(businessType)) {
-            return "/collaborativeApproval/AttendManage/leave-apply?id=" + instanceId;
-        }
-        if (TypeEnums.OVERTIME_APPROVAL.getCode().equals(businessType)) {
-            return "/collaborativeApproval/AttendManage/overtime-apply?id=" + instanceId;
-        }
-        if (TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode().equals(businessType)) {
-            return "/collaborativeApproval/ReimburseManage/travel-reimburse?id=" + instanceId;
-        }
-        if (TypeEnums.EXPENSE_APPROVAL.getCode().equals(businessType)) {
-            return "/collaborativeApproval/ReimburseManage/cost-reimburse?id=" + instanceId;
-        }
-        return "/collaborativeApproval/approve-list?id=" + instanceId;
-    }
-
-    private void sendEnterpriseNewsNotice(Long newsId) {
-        EnterpriseNews enterpriseNews = enterpriseNewsMapper.selectById(newsId);
-        if (enterpriseNews == null) {
-            return;
-        }
-        List<Long> userIds = getEnterpriseNewsNoticeUserIds(enterpriseNews);
-        if (userIds == null || userIds.isEmpty()) {
-            return;
-        }
-        String title = "浼佷笟鏂伴椈";
-        String message = "鎮ㄦ湁鏂扮殑浼佷笟鏂伴椈銆�" + enterpriseNews.getTitle() + "銆嬭鍙婃椂鏌ラ槄";
-        String jumpPath = "/officeProcessAutomation/EnterpriseNews?id=" + newsId;
-        sysNoticeService.simpleNoticeByUser(title, message, userIds, jumpPath);
-    }
-
-    private List<Long> getEnterpriseNewsNoticeUserIds(EnterpriseNews enterpriseNews) {
-        if (enterpriseNews == null || !org.springframework.util.StringUtils.hasText(enterpriseNews.getReadScope())) {
-            return Collections.emptyList();
-        }
-        String readScope = enterpriseNews.getReadScope().trim();
-        if ("all".equals(readScope)) {
-            return sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>()
-                            .select(SysUser::getUserId)
-                            .eq(SysUser::getDelFlag, "0"))
-                    .stream()
-                    .map(SysUser::getUserId)
-                    .filter(id -> id != null && id > 0)
-                    .distinct()
-                    .collect(Collectors.toList());
-        }
-        if ("dept".equals(readScope)) {
-            List<Long> deptIds = enterpriseNewsScopeDeptMapper.selectList(
-                            new LambdaQueryWrapper<EnterpriseNewsScopeDept>()
-                                    .eq(EnterpriseNewsScopeDept::getNewsId, enterpriseNews.getId()))
-                    .stream()
-                    .map(EnterpriseNewsScopeDept::getDeptId)
-                    .filter(id -> id != null && id > 0)
-                    .distinct()
-                    .collect(Collectors.toList());
-            if (deptIds.isEmpty()) {
-                return Collections.emptyList();
-            }
-            return sysUserDeptMapper.selectDistinctUserIdsByDeptIds(collectDeptIdsWithChildren(deptIds));
-        }
-        if ("custom".equals(readScope)) {
-            return enterpriseNewsScopeUserMapper.selectList(
-                            new LambdaQueryWrapper<EnterpriseNewsScopeUser>()
-                                    .eq(EnterpriseNewsScopeUser::getNewsId, enterpriseNews.getId()))
-                    .stream()
-                    .map(EnterpriseNewsScopeUser::getUserId)
-                    .filter(id -> id != null && id > 0)
-                    .distinct()
-                    .collect(Collectors.toList());
-        }
-        return Collections.emptyList();
-    }
-
-    private List<Long> collectDeptIdsWithChildren(List<Long> deptIds) {
-        Set<Long> allDeptIds = new LinkedHashSet<>();
-        for (Long deptId : deptIds) {
-            if (deptId == null) {
-                continue;
-            }
-            allDeptIds.add(deptId);
-            List<SysDept> children = sysDeptMapper.selectChildrenDeptById(deptId);
-            if (children != null && !children.isEmpty()) {
-                for (SysDept child : children) {
-                    if (child != null && child.getDeptId() != null) {
-                        allDeptIds.add(child.getDeptId());
-                    }
-                }
-            }
-        }
-        return new ArrayList<>(allDeptIds);
-    }
-
-    private void closePendingTasks(Long instanceId, Long nodeId) {
-        LambdaUpdateWrapper<ApprovalTask> updateWrapper = Wrappers.lambdaUpdate();
-        updateWrapper.eq(ApprovalTask::getInstanceId, instanceId)
-                .eq(ApprovalTask::getNodeId, nodeId)
-                .eq(ApprovalTask::getTaskStatus, "PENDING")
-                .eq(ApprovalTask::getDeleted, 0)
-                .set(ApprovalTask::getDeleted, (byte) 1);
-        approvalTaskService.update(updateWrapper);
-    }
-
-    private void saveApprovalRecord(Long instanceId,
-                                    Long nodeId,
-                                    Long taskId,
-                                    Long operatorId,
-                                    String operatorName,
-                                    String action,
-                                    String comment) {
-        ApprovalRecord record = new ApprovalRecord();
-        record.setInstanceId(instanceId);
-        record.setNodeId(nodeId);
-        record.setTaskId(taskId);
-        record.setOperatorId(operatorId);
-        record.setOperatorName(operatorName);
-        record.setAction(action);
-        record.setComment(comment);
-        record.setDeleted((byte) 0);
-        approvalRecordService.save(record);
-    }
-
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApprovalRecordServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApprovalRecordServiceImpl.java
deleted file mode 100644
index 50911e4..0000000
--- a/src/main/java/com/ruoyi/approve/service/impl/ApprovalRecordServiceImpl.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.approve.service.impl;
-
-import com.ruoyi.approve.pojo.ApprovalRecord;
-import com.ruoyi.approve.mapper.ApprovalRecordMapper;
-import com.ruoyi.approve.service.ApprovalRecordService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import org.springframework.stereotype.Service;
-
-/**
- * <p>
- * 瀹℃壒璁板綍琛� 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:28:21
- */
-@Service
-public class ApprovalRecordServiceImpl extends ServiceImpl<ApprovalRecordMapper, ApprovalRecord> implements ApprovalRecordService {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApprovalTaskServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApprovalTaskServiceImpl.java
deleted file mode 100644
index 14e10ca..0000000
--- a/src/main/java/com/ruoyi/approve/service/impl/ApprovalTaskServiceImpl.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.approve.service.impl;
-
-import com.ruoyi.approve.pojo.ApprovalTask;
-import com.ruoyi.approve.mapper.ApprovalTaskMapper;
-import com.ruoyi.approve.service.ApprovalTaskService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import org.springframework.stereotype.Service;
-
-/**
- * <p>
- * 瀹℃壒浠诲姟琛� 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 03:32:37
- */
-@Service
-public class ApprovalTaskServiceImpl extends ServiceImpl<ApprovalTaskMapper, ApprovalTask> implements ApprovalTaskService {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateNodeApproverServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateNodeApproverServiceImpl.java
deleted file mode 100644
index 0921c35..0000000
--- a/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateNodeApproverServiceImpl.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.approve.service.impl;
-
-import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
-import com.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper;
-import com.ruoyi.approve.service.ApprovalTemplateNodeApproverService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import org.springframework.stereotype.Service;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘鑺傜偣瀹℃壒浜鸿〃 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:30
- */
-@Service
-public class ApprovalTemplateNodeApproverServiceImpl extends ServiceImpl<ApprovalTemplateNodeApproverMapper, ApprovalTemplateNodeApprover> implements ApprovalTemplateNodeApproverService {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateNodeServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateNodeServiceImpl.java
deleted file mode 100644
index ca65a5f..0000000
--- a/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateNodeServiceImpl.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.ruoyi.approve.service.impl;
-
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeApproverDto;
-import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeDto;
-import com.ruoyi.approve.mapper.ApprovalTemplateNodeMapper;
-import com.ruoyi.approve.pojo.ApprovalTemplateNode;
-import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
-import com.ruoyi.approve.service.ApprovalTemplateNodeApproverService;
-import com.ruoyi.approve.service.ApprovalTemplateNodeService;
-import lombok.RequiredArgsConstructor;
-import org.springframework.beans.BeanUtils;
-import org.springframework.stereotype.Service;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘鑺傜偣琛� 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-18 11:20:19
- */
-@Service
-@RequiredArgsConstructor
-public class ApprovalTemplateNodeServiceImpl extends ServiceImpl<ApprovalTemplateNodeMapper, ApprovalTemplateNode> implements ApprovalTemplateNodeService {
-
-    private final ApprovalTemplateNodeMapper approvalTemplateNodeMapper;
-    private final ApprovalTemplateNodeApproverService approvalTemplateNodeApproverService;
-    @Override
-    public Boolean saveApprovalTemplateNode(Long templateId, List<ApprovalTemplateNodeDto> nodes) {
-        if (nodes == null || nodes.isEmpty()) {
-            throw new RuntimeException("鑺傜偣鍒楄〃涓嶈兘涓虹┖");
-        }
-
-        List<ApprovalTemplateNodeApprover> approverList = new ArrayList<>();
-
-        for (ApprovalTemplateNodeDto nodeDto : nodes) {
-            ApprovalTemplateNode node = new ApprovalTemplateNode();
-            BeanUtils.copyProperties(nodeDto, node);
-            node.setTemplateId(templateId);
-            approvalTemplateNodeMapper.insert(node);
-
-            List<ApprovalTemplateNodeApproverDto> approvers = nodeDto.getApprovers();
-            if (approvers == null || approvers.isEmpty()) {
-                throw new RuntimeException("鑺傜偣瀹℃壒浜轰笉鑳戒负绌�");
-            }
-            for (ApprovalTemplateNodeApproverDto approverDto : approvers) {
-                ApprovalTemplateNodeApprover approver = new ApprovalTemplateNodeApprover();
-                BeanUtils.copyProperties(approverDto, approver);
-                approver.setNodeId(node.getId());
-                approver.setTemplateId(templateId);
-                approver.setDeleted(0L);
-                approverList.add(approver);
-            }
-        }
-        approvalTemplateNodeApproverService.saveBatch(approverList);
-        return true;
-    }
-}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java
deleted file mode 100644
index 9a5f0b8..0000000
--- a/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java
+++ /dev/null
@@ -1,308 +0,0 @@
-package com.ruoyi.approve.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.approve.bean.dto.ApprovalTemplateDto;
-import com.ruoyi.approve.bean.vo.ApprovalTemplateNodeApproverVo;
-import com.ruoyi.approve.bean.vo.ApprovalTemplateNodeVo;
-import com.ruoyi.approve.bean.vo.ApprovalTemplateVo;
-import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
-import com.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper;
-import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
-import com.ruoyi.approve.pojo.ApprovalInstance;
-import com.ruoyi.approve.pojo.ApprovalTemplate;
-import com.ruoyi.approve.pojo.ApprovalTemplateNode;
-import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
-import com.ruoyi.approve.service.ApprovalTemplateNodeService;
-import com.ruoyi.approve.service.ApprovalTemplateService;
-import com.ruoyi.basic.dto.StorageBlobDTO;
-import com.ruoyi.basic.enums.ApplicationTypeEnum;
-import com.ruoyi.basic.enums.RecordTypeEnum;
-import com.ruoyi.basic.utils.FileUtil;
-import lombok.RequiredArgsConstructor;
-import org.springframework.beans.BeanUtils;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.CollectionUtils;
-
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * <p>
- * 瀹℃壒妯℃澘鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @since 2026-05-18 11:20:08
- */
-@Service
-@RequiredArgsConstructor
-public class ApprovalTemplateServiceImpl extends ServiceImpl<ApprovalTemplateMapper, ApprovalTemplate> implements ApprovalTemplateService {
-
-    private final ApprovalTemplateMapper approvalTemplateMapper;
-    private final ApprovalTemplateNodeService approvalTemplateNodeService;
-    private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper;
-    private final ApprovalInstanceMapper approvalInstanceMapper;
-    private final FileUtil fileUtil;
-
-    @Override
-    public IPage<ApprovalTemplateVo> listPage(Page<ApprovalTemplateVo> page, ApprovalTemplateDto approvalTemplateDto) {
-        IPage<ApprovalTemplateVo> approvalTemplateVoIPage = approvalTemplateMapper.listPage(page, approvalTemplateDto);
-        fillTemplateVoNodes(approvalTemplateVoIPage.getRecords());
-        return approvalTemplateVoIPage;
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Boolean saveApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto) {
-        approvalTemplateMapper.insert(approvalTemplateDto);
-        approvalTemplateNodeService.remove(
-                new LambdaQueryWrapper<ApprovalTemplateNode>()
-                        .eq(ApprovalTemplateNode::getTemplateId, approvalTemplateDto.getId())
-        );
-        approvalTemplateNodeApproverMapper.delete(
-                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
-                        .eq(ApprovalTemplateNodeApprover::getTemplateId, approvalTemplateDto.getId())
-        );
-        // 淇濆瓨闄勪欢
-        List<StorageBlobDTO> storageBlobDTOs = approvalTemplateDto.getStorageBlobDTOs();
-        if (!CollectionUtils.isEmpty(storageBlobDTOs)) {
-            fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_TEMPLATE, approvalTemplateDto.getId(), storageBlobDTOs);
-        }
-        return approvalTemplateNodeService.saveApprovalTemplateNode(
-                approvalTemplateDto.getId(),
-                approvalTemplateDto.getNodes()
-        );
-    }
-
-    @Override
-    public Boolean updateApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto) {
-        // 妫�鏌ユā鏉挎槸鍚﹁瀹℃壒瀹炰緥寮曠敤
-        if (isTemplateReferenced(approvalTemplateDto.getId())) {
-            throw new RuntimeException("璇ュ鎵规ā鏉垮凡琚鎵规祦绋嬪紩鐢紝鏃犳硶缂栬緫");
-        }
-        approvalTemplateMapper.updateById(approvalTemplateDto);
-        approvalTemplateNodeService.remove(
-                new LambdaQueryWrapper<ApprovalTemplateNode>()
-                        .eq(ApprovalTemplateNode::getTemplateId, approvalTemplateDto.getId())
-        );
-        approvalTemplateNodeApproverMapper.delete(
-                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
-                        .eq(ApprovalTemplateNodeApprover::getTemplateId, approvalTemplateDto.getId())
-        );
-        // 淇濆瓨闄勪欢锛堜細鍏堝垹闄ゆ棫闄勪欢锛�
-        List<StorageBlobDTO> storageBlobDTOs = approvalTemplateDto.getStorageBlobDTOs();
-        if (!CollectionUtils.isEmpty(storageBlobDTOs)) {
-            fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_TEMPLATE, approvalTemplateDto.getId(), storageBlobDTOs);
-        } else {
-            // 濡傛灉鍓嶇浼犵┖鏁扮粍锛屽垹闄ゆ棫闄勪欢
-            fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordId(
-                    ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_TEMPLATE, approvalTemplateDto.getId()
-            );
-        }
-        return approvalTemplateNodeService.saveApprovalTemplateNode(
-                approvalTemplateDto.getId(),
-                approvalTemplateDto.getNodes()
-        );
-    }
-
-    @Transactional(rollbackFor = Exception.class)
-    public Boolean delete(List<Long> ids) {
-        if (ids == null || ids.isEmpty()) {
-            return false;
-        }
-        // 妫�鏌ユā鏉挎槸鍚﹁瀹℃壒瀹炰緥寮曠敤
-        for (Long id : ids) {
-            if (isTemplateReferenced(id)) {
-                throw new RuntimeException("瀹℃壒妯℃澘锛圛D: " + id + "锛夊凡琚鎵规祦绋嬪紩鐢紝鏃犳硶鍒犻櫎");
-            }
-        }
-        ApprovalTemplate updateEntity = new ApprovalTemplate();
-        updateEntity.setDeleted(1);
-        LambdaUpdateWrapper<ApprovalTemplate> updateWrapper = Wrappers.lambdaUpdate();
-        updateWrapper.in(ApprovalTemplate::getId, ids)
-                .eq(ApprovalTemplate::getDeleted, 0);
-
-        int rows = approvalTemplateMapper.update(updateEntity, updateWrapper);
-        return rows == ids.size();
-    }
-
-    @Override
-    public List<ApprovalTemplateVo> listApprovalTemplateVo(Integer type) {
-        List<ApprovalTemplate> templateList = this.list(
-                new LambdaQueryWrapper<ApprovalTemplate>()
-                        .eq(ApprovalTemplate::getDeleted, 0)
-                        .eq(ApprovalTemplate::getEnabled, 1)
-                        .notIn(ApprovalTemplate::getBusinessType, List.of(5L, 6L, 7L))
-                        .orderByDesc(ApprovalTemplate::getTemplateType)
-                        .orderByDesc(ApprovalTemplate::getId)
-        );
-        if (CollUtil.isEmpty(templateList)) {
-            return Collections.emptyList();
-        }
-
-        List<ApprovalTemplateVo> templateVos = templateList.stream()
-                .map(template -> {
-                    ApprovalTemplateVo templateVo = new ApprovalTemplateVo();
-                    BeanUtils.copyProperties(template, templateVo);
-                    return templateVo;
-                })
-                .collect(Collectors.toList());
-        fillTemplateVoNodes(templateVos);
-        return templateVos;
-    }
-
-    @Override
-    public ApprovalTemplateVo getApprovalTemplateVoById(Long id) {
-        if (id == null) {
-            throw new IllegalArgumentException("鍙傛暟 id 涓嶈兘涓虹┖");
-        }
-
-        ApprovalTemplate template = this.getOne(
-                new LambdaQueryWrapper<ApprovalTemplate>()
-                        .eq(ApprovalTemplate::getId, id)
-                        .eq(ApprovalTemplate::getDeleted, 0)
-        );
-        if (template == null) {
-            throw new IllegalArgumentException("妯℃澘涓嶅瓨鍦�");
-        }
-
-        List<ApprovalTemplateNode> nodeList = approvalTemplateNodeService.list(
-                new LambdaQueryWrapper<ApprovalTemplateNode>()
-                        .eq(ApprovalTemplateNode::getTemplateId, id)
-                        .orderByAsc(ApprovalTemplateNode::getLevelNo)
-        );
-
-        List<ApprovalTemplateNodeApprover> approverList = approvalTemplateNodeApproverMapper.selectList(
-                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
-                        .eq(ApprovalTemplateNodeApprover::getTemplateId, id)
-                        .eq(ApprovalTemplateNodeApprover::getDeleted, 0L)
-        );
-
-        Map<Long, List<ApprovalTemplateNode>> nodeMap = nodeList.stream()
-                .collect(Collectors.groupingBy(ApprovalTemplateNode::getTemplateId));
-
-        Map<Long, List<ApprovalTemplateNodeApprover>> approverMap = approverList.stream()
-                .collect(Collectors.groupingBy(ApprovalTemplateNodeApprover::getNodeId));
-
-        return buildTemplateVo(template, nodeMap, approverMap);
-    }
-
-    /**
-     * 鎵归噺濉厖妯℃澘鑺傜偣鍙婅妭鐐瑰鎵逛汉锛岄伩鍏嶅惊鐜煡搴撱��
-     */
-    private void fillTemplateVoNodes(List<ApprovalTemplateVo> templateVos) {
-        if (CollUtil.isEmpty(templateVos)) {
-            return;
-        }
-
-        List<Long> templateIds = templateVos.stream()
-                .map(ApprovalTemplateVo::getId)
-                .collect(Collectors.toList());
-
-        List<ApprovalTemplateNode> nodeList = approvalTemplateNodeService.list(
-                new LambdaQueryWrapper<ApprovalTemplateNode>()
-                        .in(ApprovalTemplateNode::getTemplateId, templateIds)
-                        .orderByAsc(ApprovalTemplateNode::getLevelNo)
-        );
-
-        List<ApprovalTemplateNodeApprover> approverList = approvalTemplateNodeApproverMapper.selectList(
-                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
-                        .in(ApprovalTemplateNodeApprover::getTemplateId, templateIds)
-                        .eq(ApprovalTemplateNodeApprover::getDeleted, 0L)
-        );
-
-        Map<Long, List<ApprovalTemplateNode>> nodeMap = nodeList.stream()
-                .collect(Collectors.groupingBy(ApprovalTemplateNode::getTemplateId));
-
-        Map<Long, List<ApprovalTemplateNodeApprover>> approverMap = approverList.stream()
-                .collect(Collectors.groupingBy(ApprovalTemplateNodeApprover::getNodeId));
-
-        templateVos.forEach(templateVo -> templateVo.setNodes(
-                nodeMap.getOrDefault(templateVo.getId(), Collections.emptyList())
-                        .stream()
-                        .sorted(Comparator.comparing(
-                                ApprovalTemplateNode::getLevelNo,
-                                Comparator.nullsLast(Integer::compareTo)
-                        ))
-                        .map(node ->  buildNodeVo(node, approverMap))
-                        .collect(Collectors.toList())
-        ));
-    }
-
-    private ApprovalTemplateVo buildTemplateVo(ApprovalTemplate template,
-                                               Map<Long, List<ApprovalTemplateNode>> nodeMap,
-                                               Map<Long, List<ApprovalTemplateNodeApprover>> approverMap) {
-        ApprovalTemplateVo templateVo = new ApprovalTemplateVo();
-        BeanUtils.copyProperties(template, templateVo);
-
-        List<ApprovalTemplateNodeVo> nodeVos = nodeMap
-                .getOrDefault(template.getId(), Collections.emptyList())
-                .stream()
-                .sorted(Comparator.comparing(
-                        ApprovalTemplateNode::getLevelNo,
-                        Comparator.nullsLast(Integer::compareTo)
-                ))
-                .map(node -> buildNodeVo(node, approverMap))
-                .collect(Collectors.toList());
-
-        templateVo.setNodes(nodeVos);
-        // 鏌ヨ闄勪欢
-        templateVo.setStorageBlobDTOs(
-                fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(
-                        ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_TEMPLATE, template.getId()
-                )
-        );
-        return templateVo;
-    }
-
-    private ApprovalTemplateNodeVo buildNodeVo(ApprovalTemplateNode node,
-                                               Map<Long, List<ApprovalTemplateNodeApprover>> approverMap) {
-        ApprovalTemplateNodeVo nodeVo = new ApprovalTemplateNodeVo();
-        BeanUtils.copyProperties(node, nodeVo);
-
-        List<ApprovalTemplateNodeApproverVo> approverVos = approverMap
-                .getOrDefault(node.getId(), Collections.emptyList())
-                .stream()
-                .sorted(Comparator.comparing(
-                        ApprovalTemplateNodeApprover::getSortNo,
-                        Comparator.nullsLast(Integer::compareTo)
-                ))
-                .map(this::buildApproverVo)
-                .collect(Collectors.toList());
-
-        nodeVo.setApprovers(approverVos);
-        return nodeVo;
-    }
-
-    private ApprovalTemplateNodeApproverVo buildApproverVo(ApprovalTemplateNodeApprover approver) {
-        ApprovalTemplateNodeApproverVo approverVo = new ApprovalTemplateNodeApproverVo();
-        BeanUtils.copyProperties(approver, approverVo);
-        return approverVo;
-    }
-
-    /**
-     * 妫�鏌ュ鎵规ā鏉挎槸鍚﹁瀹℃壒瀹炰緥寮曠敤
-     * @param templateId 妯℃澘ID
-     * @return true 琛ㄧず琚紩鐢紝false 琛ㄧず鏈寮曠敤
-     */
-    private boolean isTemplateReferenced(Long templateId) {
-        if (templateId == null) {
-            return false;
-        }
-        Long count = approvalInstanceMapper.selectCount(
-                new LambdaQueryWrapper<ApprovalInstance>()
-                        .eq(ApprovalInstance::getTemplateId, templateId)
-                        .eq(ApprovalInstance::getDeleted, 0)
-        );
-        return count != null && count > 0;
-    }
-}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java b/src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java
deleted file mode 100644
index 8135c3a..0000000
--- a/src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java
+++ /dev/null
@@ -1,175 +0,0 @@
-package com.ruoyi.approve.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
-import com.ruoyi.procurementrecord.utils.StockUtils;
-import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
-import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.quality.mapper.QualityInspectMapper;
-import com.ruoyi.quality.mapper.QualityInspectParamMapper;
-import com.ruoyi.quality.mapper.QualityTestStandardMapper;
-import com.ruoyi.quality.mapper.QualityTestStandardParamMapper;
-import com.ruoyi.quality.pojo.QualityInspect;
-import com.ruoyi.quality.pojo.QualityInspectParam;
-import com.ruoyi.quality.pojo.QualityTestStandard;
-import com.ruoyi.quality.pojo.QualityTestStandardParam;
-import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.mapper.SalesQuotationMapper;
-import com.ruoyi.sales.mapper.ShippingInfoMapper;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import com.ruoyi.sales.pojo.SalesQuotation;
-import com.ruoyi.sales.pojo.ShippingInfo;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-
-import java.util.Date;
-import java.util.List;
-
-@Service
-@RequiredArgsConstructor
-public class ApproveBusinessStatusService {
-
-    private final PurchaseLedgerMapper purchaseLedgerMapper;
-    private final SalesQuotationMapper salesQuotationMapper;
-    private final ShippingInfoMapper shippingInfoMapper;
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-    private final StockUtils stockUtils;
-    private final QualityInspectMapper qualityInspectMapper;
-    private final QualityTestStandardMapper qualityTestStandardMapper;
-    private final QualityTestStandardParamMapper qualityTestStandardParamMapper;
-    private final QualityInspectParamMapper qualityInspectParamMapper;
-
-    /**
-     * 缁熶竴鍚屾瀹℃壒缁撴灉瀵瑰簲鐨勪笟鍔″崟鎹姸鎬併��
-     * status锛�1-瀹℃牳涓紝2-瀹℃牳瀹屾垚锛�3-瀹℃牳鏈�氳繃銆�
-     */
-    public void syncBusinessStatus(Integer approveType, String approveReason, Integer status) {
-        if (approveType == null || status == null || !StringUtils.hasText(approveReason)) {
-            return;
-        }
-        switch (approveType) {
-            case 5:
-                syncPurchaseStatus(approveReason, status);
-                break;
-            case 6:
-                syncSalesQuotationStatus(approveReason, status);
-                break;
-            case 7:
-                syncShippingStatus(approveReason, status);
-                break;
-            default:
-                break;
-        }
-    }
-
-    // 閲囪喘瀹℃壒閫氳繃鏃讹紝鎸変骇鍝佽川妫�閰嶇疆鍐冲畾鐢熸垚璐ㄦ鍗曟垨鐩存帴鍏ュ簱銆�
-    private void syncPurchaseStatus(String approveReason, Integer status) {
-        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
-                .eq(PurchaseLedger::getPurchaseContractNumber, approveReason)
-                .last("limit 1"));
-        if (purchaseLedger == null) {
-            return;
-        }
-        if (status.equals(2)) {
-            purchaseLedger.setApprovalStatus(3);
-            List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new QueryWrapper<SalesLedgerProduct>()
-                    .lambda().eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()).eq(SalesLedgerProduct::getType, 2));
-            for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
-                if (Boolean.TRUE.equals(salesLedgerProduct.getIsChecked())) {
-                    addQualityInspect(purchaseLedger, salesLedgerProduct);
-                } else {
-                    stockUtils.addStockWithBatchNo(
-                            salesLedgerProduct.getProductModelId(),
-                            salesLedgerProduct.getQuantity(),
-                            StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(),
-                            purchaseLedger.getId(),
-                            purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId());
-                }
-            }
-        } else if (status.equals(3)) {
-            purchaseLedger.setApprovalStatus(4);
-        } else if (status.equals(1)) {
-            purchaseLedger.setApprovalStatus(2);
-        } else {
-            return;
-        }
-        purchaseLedgerMapper.updateById(purchaseLedger);
-    }
-
-    // 鎶ヤ环瀹℃壒鐘舵�佸洖鍐欏埌閿�鍞姤浠峰崟鐘舵�併��
-    private void syncSalesQuotationStatus(String approveReason, Integer status) {
-        SalesQuotation salesQuote = salesQuotationMapper.selectOne(new LambdaQueryWrapper<SalesQuotation>()
-                .eq(SalesQuotation::getQuotationNo, approveReason)
-                .last("limit 1"));
-        if (salesQuote == null) {
-            return;
-        }
-        if (status.equals(2)) {
-            salesQuote.setStatus("閫氳繃");
-        } else if (status.equals(3)) {
-            salesQuote.setStatus("鎷掔粷");
-        } else if (status.equals(1)) {
-            salesQuote.setStatus("瀹℃牳涓�");
-        } else {
-            return;
-        }
-        salesQuotationMapper.updateById(salesQuote);
-    }
-
-    // 鍙戣揣瀹℃壒閫氳繃鏃跺悓姝ュ彂璐х姸鎬佸拰鍑哄簱瀹℃壒鐘舵�侊紱鎷掔粷鏃跺垹闄ゅ緟纭鍑哄簱璁板綍銆�
-    private void syncShippingStatus(String approveReason, Integer status) {
-        ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
-                .eq(ShippingInfo::getShippingNo, approveReason)
-                .orderByDesc(ShippingInfo::getCreateTime)
-                .last("limit 1"));
-        if (shippingInfo == null) {
-            return;
-        }
-        if (status.equals(2)) {
-            shippingInfo.setStatus("瀹℃牳閫氳繃");
-            shippingInfo.setShippingDate(new Date());
-            stockUtils.shipmentStatus(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), shippingInfo.getId());
-        } else if (status.equals(3)) {
-            stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
-            shippingInfo.setStatus("瀹℃牳鎷掔粷");
-        } else if (status.equals(1)) {
-            shippingInfo.setStatus("瀹℃牳涓�");
-        } else {
-            return;
-        }
-        shippingInfoMapper.updateById(shippingInfo);
-    }
-
-    // 鐢熸垚閲囪喘璐ㄦ鍗曪紝骞舵寜浜у搧璐ㄦ鏍囧噯鍒濆鍖栬川妫�鍙傛暟銆�
-    private void addQualityInspect(PurchaseLedger purchaseLedger, SalesLedgerProduct saleProduct) {
-        QualityInspect qualityInspect = new QualityInspect();
-        qualityInspect.setInspectType(0);
-        qualityInspect.setSupplier(purchaseLedger.getSupplierName());
-        qualityInspect.setPurchaseLedgerId(purchaseLedger.getId());
-        qualityInspect.setProductId(saleProduct.getProductId());
-        qualityInspect.setProductName(saleProduct.getProductCategory());
-        qualityInspect.setModel(saleProduct.getSpecificationModel());
-        qualityInspect.setProductModelId(saleProduct.getProductModelId());
-        qualityInspect.setUnit(saleProduct.getUnit());
-        qualityInspect.setQuantity(saleProduct.getQuantity());
-        qualityInspectMapper.insert(qualityInspect);
-        List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(saleProduct.getProductId(), 0, null);
-        if (qualityTestStandard.size() > 0) {
-            qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
-            qualityInspectMapper.updateById(qualityInspect);
-            qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
-                            .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId()))
-                    .forEach(qualityTestStandardParam -> {
-                        QualityInspectParam param = new QualityInspectParam();
-                        com.ruoyi.common.utils.bean.BeanUtils.copyProperties(qualityTestStandardParam, param);
-                        param.setId(null);
-                        param.setInspectId(qualityInspect.getId());
-                        qualityInspectParamMapper.insert(param);
-                    });
-        }
-    }
-}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementDetailServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementDetailServiceImpl.java
deleted file mode 100644
index 1897440..0000000
--- a/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementDetailServiceImpl.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.approve.service.impl;
-
-import com.ruoyi.approve.pojo.FinReimbursementDetail;
-import com.ruoyi.approve.mapper.FinReimbursementDetailMapper;
-import com.ruoyi.approve.service.FinReimbursementDetailService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import org.springframework.stereotype.Service;
-
-/**
- * <p>
- * 鎶ラ攢鍗曟槑缁嗚〃 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:38
- */
-@Service
-public class FinReimbursementDetailServiceImpl extends ServiceImpl<FinReimbursementDetailMapper, FinReimbursementDetail> implements FinReimbursementDetailService {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementServiceImpl.java
deleted file mode 100644
index a3d33f4..0000000
--- a/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementServiceImpl.java
+++ /dev/null
@@ -1,574 +0,0 @@
-package com.ruoyi.approve.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
-import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeApproverDto;
-import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeDto;
-import com.ruoyi.approve.bean.dto.FinReimbursementDto;
-import com.ruoyi.approve.bean.vo.FinReimbursementVo;
-import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
-import com.ruoyi.approve.mapper.FinReimbursementDetailMapper;
-import com.ruoyi.approve.mapper.FinReimbursementMapper;
-import com.ruoyi.approve.mapper.FinReimbursementTravelMapper;
-import com.ruoyi.approve.pojo.*;
-import com.ruoyi.basic.enums.ApplicationTypeEnum;
-import com.ruoyi.basic.enums.RecordTypeEnum;
-import com.ruoyi.basic.utils.FileUtil;
-import com.ruoyi.approve.service.*;
-import com.ruoyi.common.enums.TypeEnums;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.utils.OrderUtils;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.project.system.service.ISysNoticeService;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.StringUtils;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * <p>
- * 鎶ラ攢鍗曚富琛� 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:15
- */
-@Service
-@RequiredArgsConstructor
-public class FinReimbursementServiceImpl extends ServiceImpl<FinReimbursementMapper, FinReimbursement> implements FinReimbursementService {
-
-    private static final String BILL_STATUS_DRAFT = "DRAFT";
-    private static final String BILL_STATUS_IN_APPROVAL = "IN_APPROVAL";
-    private static final String NODE_STATUS_WAITING = "WAITING";
-
-    private final ApprovalInstanceMapper approvalInstanceMapper;
-    private final ApprovalInstanceService approvalInstanceService;
-    private final ApprovalInstanceNodeService approvalInstanceNodeService;
-    private final ApprovalTaskService approvalTaskService;
-    private final ApprovalRecordService approvalRecordService;
-    private final FinReimbursementMapper finReimbursementMapper;
-    private final FinReimbursementTravelMapper finReimbursementTravelMapper;
-    private final FinReimbursementDetailMapper finReimbursementDetailMapper;
-    private final FileUtil fileUtil;
-    private final ISysNoticeService sysNoticeService;
-    @Override
-    public IPage<FinReimbursementVo> listPage(FinReimbursementDto finReimbursementDto, Page<FinReimbursementVo> page) {
-        IPage<FinReimbursementVo> finReimbursementVoIPage = finReimbursementMapper.listPage(finReimbursementDto, page);
-        finReimbursementVoIPage.getRecords().forEach(vo -> {
-            vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.FIN_REIMBURSEMENT,  vo.getId()));
-        });
-
-        return finReimbursementVoIPage;
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Boolean add(FinReimbursementDto finReimbursementDto) {
-        String billStatus = validateAddParam(finReimbursementDto);
-
-        // 鐢熸垚鎶ラ攢鍗曞彿
-        String billNo = OrderUtils.countTodayByCreateTime(finReimbursementMapper, "BXD", "bill_no", finReimbursementDto.getCreateTime() != null ? finReimbursementDto.getCreateTime() : LocalDateTime.now());
-        List<FinReimbursementDetail> details = finReimbursementDto.getDetails();
-        BigDecimal totalAmount = details.stream()
-                .map(FinReimbursementDetail::getAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-        FinReimbursement reimbursement = buildReimbursement(finReimbursementDto, billNo, totalAmount, billStatus);
-        // 淇濆瓨鎶ラ攢鍗曚富琛�
-        boolean saved = this.save(reimbursement);
-        if (!saved || reimbursement.getId() == null) {
-            throw new ServiceException("鏂板鎶ラ攢鍗曞け璐�");
-        }
-        Long reimbursementId = reimbursement.getId();
-
-        // 淇濆瓨宸梾鎶ラ攢鎵╁睍淇℃伅锛堟姤閿�绫诲瀷涓哄樊鏃呮姤閿�鏃讹級
-        FinReimbursementTravel travel = finReimbursementDto.getTravel();
-        if (isTravelReimbursement(finReimbursementDto.getReimbursementType())) {
-            travel.setReimbursementId(reimbursementId);
-            int travelRows = finReimbursementTravelMapper.insert(travel);
-            if (travelRows != 1) {
-                throw new ServiceException("鏂板宸梾鎶ラ攢鎵╁睍淇℃伅澶辫触");
-            }
-        }
-
-        // 淇濆瓨鎶ラ攢鍗曟槑缁�
-        for (int i = 0; i < details.size(); i++) {
-            FinReimbursementDetail detail = details.get(i);
-            detail.setId(null);
-            detail.setReimbursementId(reimbursementId);
-            detail.setRowNo(i + 1);
-            int detailRows = finReimbursementDetailMapper.insert(detail);
-            if (detailRows != 1) {
-                throw new ServiceException("鏂板鎶ラ攢鍗曟槑缁嗗け璐�");
-            }
-        }
-
-        if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) {
-            startApproval(reimbursement, finReimbursementDto);
-        }
-        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.FIN_REIMBURSEMENT, reimbursementId, finReimbursementDto.getStorageBlobDTOs());
-        return true;
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Boolean update(FinReimbursementDto finReimbursementDto) {
-        String billStatus = validateUpdateParam(finReimbursementDto);
-
-        Long reimbursementId = finReimbursementDto.getId();
-        FinReimbursement existing = finReimbursementMapper.selectById(reimbursementId);
-        if (existing == null) {
-            throw new ServiceException("鎶ラ攢鍗曚笉瀛樺湪");
-        }
-
-        // 璁$畻鏄庣粏姹囨�婚噾棰�
-        List<FinReimbursementDetail> details = finReimbursementDto.getDetails();
-        BigDecimal totalAmount = details.stream()
-                .map(FinReimbursementDetail::getAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-        // 鏇存柊涓昏〃
-        FinReimbursement reimbursement = buildReimbursement(
-                finReimbursementDto,
-                existing.getBillNo(),
-                totalAmount,
-                billStatus
-        );
-        reimbursement.setId(reimbursementId);
-        int mainRows = finReimbursementMapper.updateById(reimbursement);
-        if (mainRows != 1) {
-            throw new ServiceException("鏇存柊鎶ラ攢鍗曚富琛ㄥけ璐�");
-        }
-
-        // 鏌ヨ鏁版嵁搴撲腑宸叉湁鐨勬槑缁�
-        List<FinReimbursementDetail> existingDetails = finReimbursementDetailMapper.selectList(
-                new LambdaQueryWrapper<FinReimbursementDetail>()
-                        .eq(FinReimbursementDetail::getReimbursementId, reimbursementId));
-        Set<Long> existingDetailIds = existingDetails.stream()
-                .map(FinReimbursementDetail::getId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-
-        // 鏂版槑缁嗕腑鏈塈D鐨� 鈫� 鏇存柊锛涙棤ID鐨� 鈫� 鏂板
-        Set<Long> submittedDetailIds = new HashSet<>();
-        for (int i = 0; i < details.size(); i++) {
-            FinReimbursementDetail detail = details.get(i);
-            detail.setReimbursementId(reimbursementId);
-            detail.setRowNo(i + 1);
-            if (detail.getId() != null && existingDetailIds.contains(detail.getId())) {
-                finReimbursementDetailMapper.updateById(detail);
-                submittedDetailIds.add(detail.getId());
-            } else {
-                detail.setId(null);
-                finReimbursementDetailMapper.insert(detail);
-            }
-        }
-
-        // 鏁版嵁搴撲腑宸叉湁浣嗘柊鏄庣粏涓病鏈夌殑 鈫� 鍒犻櫎
-        for (Long existingId : existingDetailIds) {
-            if (!submittedDetailIds.contains(existingId)) {
-                finReimbursementDetailMapper.deleteById(existingId);
-            }
-        }
-
-        // 宸梾鎵╁睍锛氭湁鍒欐洿鏂帮紝鏃犲垯鏂板
-        FinReimbursementTravel existingTravel = finReimbursementTravelMapper.selectOne(
-                new LambdaQueryWrapper<FinReimbursementTravel>()
-                        .eq(FinReimbursementTravel::getReimbursementId, reimbursementId)
-                        .last("LIMIT 1"));
-        FinReimbursementTravel travel = finReimbursementDto.getTravel();
-        if (isTravelReimbursement(finReimbursementDto.getReimbursementType()) && travel != null) {
-            travel.setReimbursementId(reimbursementId);
-            if (existingTravel != null) {
-                travel.setId(existingTravel.getId());
-                finReimbursementTravelMapper.updateById(travel);
-            } else {
-                travel.setId(null);
-                finReimbursementTravelMapper.insert(travel);
-            }
-        }
-
-        resetApprovalFlow(existing, reimbursementId);
-        if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) {
-            reimbursement.setApprovalInstanceId(null);
-            startApproval(reimbursement, finReimbursementDto);
-        }
-        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.FIN_REIMBURSEMENT, reimbursementId, finReimbursementDto.getStorageBlobDTOs());
-
-        return true;
-    }
-
-    @Override
-    public FinReimbursementVo detail(Long id) {
-        if (id == null ) {
-            throw new ServiceException("鎶ラ攢鍗旾D涓嶈兘涓虹┖");
-        }
-
-        FinReimbursement reimbursement = finReimbursementMapper.selectById(id);
-        if (reimbursement == null) {
-            throw new ServiceException("鎶ラ攢鍗曚笉瀛樺湪");
-        }
-
-        FinReimbursementVo vo = new FinReimbursementVo();
-        vo.setId(reimbursement.getId());
-        vo.setBillNo(reimbursement.getBillNo());
-        vo.setReimbursementType(reimbursement.getReimbursementType());
-        vo.setExpenseType(reimbursement.getExpenseType());
-        vo.setApplicantId(reimbursement.getApplicantId());
-        vo.setApplicantCode(reimbursement.getApplicantCode());
-        vo.setApplicantName(reimbursement.getApplicantName());
-        vo.setApplicantDeptId(reimbursement.getApplicantDeptId());
-        vo.setApplicantDeptName(reimbursement.getApplicantDeptName());
-        vo.setReason(reimbursement.getReason());
-        vo.setApplyAmount(reimbursement.getApplyAmount());
-        vo.setDetailTotalAmount(reimbursement.getDetailTotalAmount());
-        vo.setPayeeName(reimbursement.getPayeeName());
-        vo.setPayeeAccount(reimbursement.getPayeeAccount());
-        vo.setPayeeBank(reimbursement.getPayeeBank());
-        vo.setApprovalInstanceId(reimbursement.getApprovalInstanceId());
-        vo.setApproveProcessId(reimbursement.getApproveProcessId());
-        vo.setBillStatus(reimbursement.getBillStatus());
-        vo.setApprovedTime(reimbursement.getApprovedTime());
-        vo.setPaidTime(reimbursement.getPaidTime());
-        vo.setAccountExpenseId(reimbursement.getAccountExpenseId());
-        vo.setRemark(reimbursement.getRemark());
-        vo.setTenantId(reimbursement.getTenantId());
-        vo.setCreateUser(reimbursement.getCreateUser());
-        vo.setCreateTime(reimbursement.getCreateTime());
-        vo.setUpdateUser(reimbursement.getUpdateUser());
-        vo.setUpdateTime(reimbursement.getUpdateTime());
-        vo.setDeptId(reimbursement.getDeptId());
-        vo.setDeleted(reimbursement.getDeleted());
-
-        vo.setDetails(finReimbursementDetailMapper.selectList(
-                new LambdaQueryWrapper<FinReimbursementDetail>()
-                        .eq(FinReimbursementDetail::getReimbursementId, reimbursement.getId())
-                        .orderByAsc(FinReimbursementDetail::getRowNo)
-        ));
-
-        if (isTravelReimbursement(reimbursement.getReimbursementType())) {
-            vo.setTravel(finReimbursementTravelMapper.selectOne(
-                    new LambdaQueryWrapper<FinReimbursementTravel>()
-                            .eq(FinReimbursementTravel::getReimbursementId, reimbursement.getId())
-                            .last("LIMIT 1")
-            ));
-        }
-        vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.FIN_REIMBURSEMENT, reimbursement.getId()));
-        //瀹℃壒璁板綍杩斿洖
-        vo.setTasks(approvalTaskService.list(new LambdaQueryWrapper<ApprovalTask>().eq(ApprovalTask::getInstanceId, reimbursement.getApprovalInstanceId())));
-        vo.setRecords(approvalRecordService.list(new LambdaQueryWrapper<ApprovalRecord>().eq(ApprovalRecord::getInstanceId, reimbursement.getApprovalInstanceId())));
-        return vo;
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Boolean delete(List<Long> ids) {
-        if (ids == null || ids.isEmpty()) {
-            throw new ServiceException("鍒犻櫎澶辫触锛岃閫夋嫨瑕佸垹闄ょ殑鏁版嵁");
-        }
-        // 鏌ヨ鎶ラ攢鍗曞叧鑱旂殑瀹℃壒瀹炰緥ID
-        List<FinReimbursement> reimbursements = finReimbursementMapper.selectList(
-                new LambdaQueryWrapper<FinReimbursement>()
-                        .in(FinReimbursement::getId, ids)
-                        .isNotNull(FinReimbursement::getApprovalInstanceId)
-        );
-        List<Long> approvalInstanceIds = reimbursements.stream()
-                .map(FinReimbursement::getApprovalInstanceId)
-                .filter(Objects::nonNull)
-                .distinct()
-                .collect(Collectors.toList());
-
-        // 鍒犻櫎鍏宠仈鐨勫鎵硅褰�
-        if (!approvalInstanceIds.isEmpty()) {
-            approvalInstanceService.delete(approvalInstanceIds);
-        }
-
-        fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.FILE, RecordTypeEnum.FIN_REIMBURSEMENT, ids);
-        //鍏堝垹闄ゆ槑缁�
-        finReimbursementDetailMapper.delete(new LambdaQueryWrapper<FinReimbursementDetail>().in(FinReimbursementDetail::getReimbursementId, ids));
-        //鍒犻櫎宸梾
-        finReimbursementTravelMapper.delete(new LambdaQueryWrapper<FinReimbursementTravel>().in(FinReimbursementTravel::getReimbursementId, ids));
-        //鍒犻櫎涓昏〃
-        int rows = finReimbursementMapper.delete(new LambdaQueryWrapper<FinReimbursement>().in(FinReimbursement::getId, ids));
-        return rows == ids.size();
-    }
-
-    private String validateUpdateParam(FinReimbursementDto finReimbursementDto) {
-        if (finReimbursementDto == null || finReimbursementDto.getId() == null) {
-            throw new ServiceException("鎶ラ攢鍗旾D涓嶈兘涓虹┖");
-        }
-        if (finReimbursementDto.getReimbursementType() == null) {
-            throw new ServiceException("鎶ラ攢绫诲瀷涓嶈兘涓虹┖");
-        }
-        String billStatus = normalizeBillStatus(finReimbursementDto.getBillStatus());
-        if (billStatus == null) {
-            throw new ServiceException("鍗曟嵁鐘舵�佸彧鏀寔 DRAFT 鎴� IN_APPROVAL");
-        }
-        if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) {
-            validateApprovalNodes(finReimbursementDto.getNodes());
-        }
-        List<FinReimbursementDetail> details = finReimbursementDto.getDetails();
-        if (details == null || details.isEmpty()) {
-            throw new ServiceException("鎶ラ攢鍗曟槑缁嗕笉鑳戒负绌�");
-        }
-        for (FinReimbursementDetail detail : details) {
-            if (detail == null) {
-                throw new ServiceException("鎶ラ攢鍗曟槑缁嗕笉鑳戒负绌�");
-            }
-            if (detail.getAmount() == null || detail.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
-                throw new ServiceException("鎶ラ攢鍗曟槑缁嗛噾棰濆繀椤诲ぇ浜�0");
-            }
-        }
-        if (isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() == null) {
-            throw new ServiceException("宸梾鎶ラ攢蹇呴』濉啓宸梾鎵╁睍淇℃伅");
-        }
-        if (!isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() != null) {
-            throw new ServiceException("闈炲樊鏃呮姤閿�涓嶅厑璁稿~鍐欏樊鏃呮墿灞曚俊鎭�");
-        }
-        return billStatus;
-    }
-
-    private String validateAddParam(FinReimbursementDto finReimbursementDto) {
-        if (finReimbursementDto == null) {
-            throw new ServiceException("鎶ラ攢鍗曟暟鎹笉鑳戒负绌�");
-        }
-        if (finReimbursementDto.getReimbursementType() == null) {
-            throw new ServiceException("鎶ラ攢绫诲瀷涓嶈兘涓虹┖");
-        }
-        String billStatus = normalizeBillStatus(finReimbursementDto.getBillStatus());
-        if (billStatus == null) {
-            throw new ServiceException("鍗曟嵁鐘舵�佸彧鏀寔 DRAFT 鎴� IN_APPROVAL");
-        }
-        if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) {
-            validateApprovalNodes(finReimbursementDto.getNodes());
-        }
-        List<FinReimbursementDetail> details = finReimbursementDto.getDetails();
-        if (details == null || details.isEmpty()) {
-            throw new ServiceException("鎶ラ攢鍗曟槑缁嗕笉鑳戒负绌�");
-        }
-        for (FinReimbursementDetail detail : details) {
-            if (detail == null) {
-                throw new ServiceException("鎶ラ攢鍗曟槑缁嗕笉鑳戒负绌�");
-            }
-            if (detail.getAmount() == null || detail.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
-                throw new ServiceException("鎶ラ攢鍗曟槑缁嗛噾棰濆繀椤诲ぇ浜�0");
-            }
-        }
-        if (isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() == null) {
-            throw new ServiceException("宸梾鎶ラ攢蹇呴』濉啓宸梾鎵╁睍淇℃伅");
-        }
-        if (!isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() != null) {
-            throw new ServiceException("闈炲樊鏃呮姤閿�涓嶅厑璁稿~鍐欏樊鏃呮墿灞曚俊鎭�");
-        }
-        return billStatus;
-    }
-
-    private FinReimbursement buildReimbursement(FinReimbursementDto finReimbursementDto, String billNo, BigDecimal totalAmount, String billStatus) {
-        FinReimbursement reimbursement = new FinReimbursement();
-        reimbursement.setId(null);
-        reimbursement.setBillNo(billNo);
-        reimbursement.setReimbursementType(finReimbursementDto.getReimbursementType());
-        reimbursement.setExpenseType(finReimbursementDto.getExpenseType());
-        reimbursement.setApplicantId(finReimbursementDto.getApplicantId());
-        reimbursement.setApplicantCode(finReimbursementDto.getApplicantCode());
-        reimbursement.setApplicantName(finReimbursementDto.getApplicantName());
-        reimbursement.setApplicantDeptId(finReimbursementDto.getApplicantDeptId());
-        reimbursement.setApplicantDeptName(finReimbursementDto.getApplicantDeptName());
-        reimbursement.setReason(finReimbursementDto.getReason());
-        reimbursement.setApplyAmount(finReimbursementDto.getApplyAmount());
-        reimbursement.setDetailTotalAmount(totalAmount);
-        reimbursement.setPayeeName(finReimbursementDto.getPayeeName());
-        reimbursement.setPayeeAccount(finReimbursementDto.getPayeeAccount());
-        reimbursement.setPayeeBank(finReimbursementDto.getPayeeBank());
-        reimbursement.setRemark(finReimbursementDto.getRemark());
-        reimbursement.setTenantId(finReimbursementDto.getTenantId());
-        reimbursement.setApproveProcessId(null);
-        reimbursement.setBillStatus(billStatus);
-        return reimbursement;
-    }
-
-    private void startApproval(FinReimbursement reimbursement, FinReimbursementDto finReimbursementDto) {
-        Long businessType = resolveBusinessType(finReimbursementDto.getReimbursementType());
-        ApprovalInstanceDto approvalInstanceDto = new ApprovalInstanceDto();
-        approvalInstanceDto.setInstanceNo(OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no", approvalInstanceDto.getCreateTime() != null ? approvalInstanceDto.getCreateTime() : LocalDateTime.now()));
-        approvalInstanceDto.setBusinessId(reimbursement.getId());
-        approvalInstanceDto.setTemplateId(null);
-        approvalInstanceDto.setTemplateName(TypeEnums.getLabelByValue(businessType) + "瀹℃壒");
-        approvalInstanceDto.setBusinessType(businessType);
-        approvalInstanceDto.setTitle("鎶ラ攢鍗曞彿锛�" + reimbursement.getBillNo());
-        approvalInstanceDto.setApplicantId(reimbursement.getApplicantId() != null ? reimbursement.getApplicantId() : SecurityUtils.getUserId());
-        approvalInstanceDto.setApplicantName(reimbursement.getApplicantName() != null ? reimbursement.getApplicantName() : SecurityUtils.getLoginUser().getNickName());
-        approvalInstanceDto.setApplyTime(LocalDateTime.now());
-        approvalInstanceDto.setStatus("PENDING");
-        approvalInstanceDto.setCurrentLevel(1);
-
-        boolean approvalSaved = approvalInstanceService.save(approvalInstanceDto);
-        if (!approvalSaved || approvalInstanceDto.getId() == null) {
-            throw new ServiceException("鍙戣捣瀹℃壒澶辫触");
-        }
-        List<ApprovalTask> firstTasks = createApprovalNodes(approvalInstanceDto, finReimbursementDto.getNodes());
-        sendApproveNotice(approvalInstanceDto, firstTasks);
-
-        FinReimbursement update = new FinReimbursement();
-        update.setId(reimbursement.getId());
-        update.setApprovalInstanceId(approvalInstanceDto.getId());
-        update.setBillStatus(BILL_STATUS_IN_APPROVAL);
-        int rows = finReimbursementMapper.updateById(update);
-        if (rows != 1) {
-            throw new ServiceException("鍥炲~瀹℃壒瀹炰緥澶辫触");
-        }
-    }
-
-    private List<ApprovalTask> createApprovalNodes(ApprovalInstanceDto approvalInstanceDto, List<ApprovalTemplateNodeDto> nodes) {
-        List<ApprovalTask> firstTasks = Collections.emptyList();
-        for (int i = 0; i < nodes.size(); i++) {
-            ApprovalTemplateNodeDto nodeDto = nodes.get(i);
-            ApprovalInstanceNode instanceNode = new ApprovalInstanceNode();
-            instanceNode.setInstanceId(approvalInstanceDto.getId());
-            instanceNode.setLevelNo(nodeDto.getLevelNo());
-            instanceNode.setApproveType(nodeDto.getApproveType());
-            instanceNode.setStatus(i == 0 ? "PENDING" : NODE_STATUS_WAITING);
-            instanceNode.setStartTime(i == 0 ? LocalDateTime.now() : null);
-            instanceNode.setDeleted((byte) 0);
-            approvalInstanceNodeService.save(instanceNode);
-
-            List<ApprovalTask> tasks = nodeDto.getApprovers().stream().map(approver -> {
-                ApprovalTask task = new ApprovalTask();
-                task.setInstanceId(approvalInstanceDto.getId());
-                task.setNodeId(instanceNode.getId());
-                task.setLevelNo(instanceNode.getLevelNo());
-                task.setApproverId(approver.getApproverId());
-                task.setApproverName(approver.getApproverName());
-                task.setTaskStatus("PENDING");
-                task.setIsRead((byte) 0);
-                task.setDeleted((byte) 0);
-                return task;
-            }).collect(Collectors.toList());
-            approvalTaskService.saveBatch(tasks);
-
-            if (i == 0) {
-                firstTasks = tasks;
-                ApprovalRecord record = new ApprovalRecord();
-                record.setInstanceId(approvalInstanceDto.getId());
-                record.setNodeId(instanceNode.getId());
-                record.setOperatorId(approvalInstanceDto.getApplicantId());
-                record.setOperatorName(approvalInstanceDto.getApplicantName());
-                record.setAction("SUBMIT");
-                record.setComment("鍙戣捣瀹℃壒");
-                record.setDeleted((byte) 0);
-                approvalRecordService.save(record);
-            }
-        }
-        return firstTasks;
-    }
-
-    private void validateApprovalNodes(List<ApprovalTemplateNodeDto> nodes) {
-        if (nodes == null || nodes.isEmpty()) {
-            throw new ServiceException("鎻愪氦瀹℃壒鏃跺鎵硅妭鐐逛笉鑳戒负绌�");
-        }
-        for (int i = 0; i < nodes.size(); i++) {
-            ApprovalTemplateNodeDto node = nodes.get(i);
-            if (node == null) {
-                throw new ServiceException("瀹℃壒鑺傜偣涓嶈兘涓虹┖");
-            }
-            if (node.getLevelNo() == null) {
-                node.setLevelNo(i + 1);
-            }
-            if (!StringUtils.hasText(node.getApproveType())) {
-                throw new ServiceException("瀹℃壒鑺傜偣瀹℃壒鏂瑰紡涓嶈兘涓虹┖");
-            }
-            List<ApprovalTemplateNodeApproverDto> approvers = node.getApprovers();
-            if (approvers == null || approvers.isEmpty()) {
-                throw new ServiceException("瀹℃壒鑺傜偣瀹℃壒浜轰笉鑳戒负绌�");
-            }
-            for (ApprovalTemplateNodeApproverDto approver : approvers) {
-                if (approver == null || approver.getApproverId() == null) {
-                    throw new ServiceException("瀹℃壒浜轰笉鑳戒负绌�");
-                }
-            }
-        }
-    }
-
-    private void sendApproveNotice(ApprovalInstanceDto instance, List<ApprovalTask> tasks) {
-        if (instance == null || tasks == null || tasks.isEmpty()) {
-            return;
-        }
-        List<Long> approverIds = tasks.stream()
-                .map(ApprovalTask::getApproverId)
-                .filter(id -> id != null && id > 0)
-                .distinct()
-                .collect(Collectors.toList());
-        if (approverIds.isEmpty()) {
-            return;
-        }
-        String title = "鎶ラ攢瀹℃壒";
-        String message = "瀹℃壒鍗曞彿 " + instance.getInstanceNo() + " 闇�瑕佹偍瀹℃壒";
-        String jumpPath = getJumpPathByBusinessType(instance.getBusinessType(), instance.getId());
-        sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath);
-    }
-
-    private String getJumpPathByBusinessType(Long businessType, Long instanceId) {
-        if (TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode().equals(businessType)) {
-            return "/collaborativeApproval/ReimburseManage/travel-reimburse?id=" + instanceId;
-        }
-        if (TypeEnums.EXPENSE_APPROVAL.getCode().equals(businessType)) {
-            return "/collaborativeApproval/ReimburseManage/cost-reimburse?id=" + instanceId;
-        }
-        return "/approvalInstance?id=" + instanceId;
-    }
-
-    private void resetApprovalFlow(FinReimbursement existing, Long reimbursementId) {
-        if (existing == null || existing.getApprovalInstanceId() == null) {
-            return;
-        }
-        Long approvalInstanceId = existing.getApprovalInstanceId();
-        if (!"REJECTED".equals(existing.getBillStatus())) {
-            approvalInstanceService.delete(Collections.singletonList(approvalInstanceId));
-        }
-        clearApprovalBinding(reimbursementId);
-    }
-
-    private void clearApprovalBinding(Long reimbursementId) {
-        int rows = finReimbursementMapper.update(
-                null,
-                Wrappers.<FinReimbursement>lambdaUpdate()
-                        .eq(FinReimbursement::getId, reimbursementId)
-                        .set(FinReimbursement::getApprovalInstanceId, null)
-        );
-        if (rows != 1) {
-            throw new ServiceException("閲嶇疆瀹℃壒娴佺▼澶辫触");
-        }
-    }
-
-    private Long resolveBusinessType(Byte reimbursementType) {
-        return isTravelReimbursement(reimbursementType)
-                ? TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode()
-                : TypeEnums.EXPENSE_APPROVAL.getCode();
-    }
-
-    private String normalizeBillStatus(String billStatus) {
-        if (billStatus == null) {
-            return BILL_STATUS_DRAFT;
-        }
-        String normalized = billStatus.trim().toUpperCase();
-        if (BILL_STATUS_DRAFT.equals(normalized) || BILL_STATUS_IN_APPROVAL.equals(normalized)) {
-            return normalized;
-        }
-        return null;
-    }
-
-    private boolean isTravelReimbursement(Byte reimbursementType) {
-        return Byte.valueOf((byte) 1).equals(reimbursementType);
-    }
-}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementTravelServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementTravelServiceImpl.java
deleted file mode 100644
index 3329f9a..0000000
--- a/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementTravelServiceImpl.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.approve.service.impl;
-
-import com.ruoyi.approve.pojo.FinReimbursementTravel;
-import com.ruoyi.approve.mapper.FinReimbursementTravelMapper;
-import com.ruoyi.approve.service.FinReimbursementTravelService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import org.springframework.stereotype.Service;
-
-/**
- * <p>
- * 宸梾鎶ラ攢鎵╁睍琛� 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-21 09:56:47
- */
-@Service
-public class FinReimbursementTravelServiceImpl extends ServiceImpl<FinReimbursementTravelMapper, FinReimbursementTravel> implements FinReimbursementTravelService {
-
-}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/KnowledgeBaseVectorServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/KnowledgeBaseVectorServiceImpl.java
deleted file mode 100644
index 52bc0b5..0000000
--- a/src/main/java/com/ruoyi/approve/service/impl/KnowledgeBaseVectorServiceImpl.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package com.ruoyi.approve.service.impl;
-
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.approve.dto.KnowledgeBaseVectorVO;
-import com.ruoyi.approve.mapper.KnowledgeBaseVectorMapper;
-import com.ruoyi.approve.pojo.KnowledgeBase;
-import com.ruoyi.approve.pojo.KnowledgeBaseVector;
-import com.ruoyi.approve.service.KnowledgeBaseService;
-import com.ruoyi.approve.service.KnowledgeBaseVectorService;
-import com.ruoyi.ai.service.KnowledgeRagService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-
-/**
- * 鐭ヨ瘑搴撴枃浠跺悜閲忚褰� Service瀹炵幇
- */
-@Slf4j
-@Service
-public class KnowledgeBaseVectorServiceImpl extends ServiceImpl<KnowledgeBaseVectorMapper, KnowledgeBaseVector>
-        implements KnowledgeBaseVectorService {
-
-    private final KnowledgeBaseService knowledgeBaseService;
-    private final KnowledgeRagService knowledgeRagService;
-
-    public KnowledgeBaseVectorServiceImpl(
-            KnowledgeBaseService knowledgeBaseService,
-            @Lazy KnowledgeRagService knowledgeRagService) {
-        this.knowledgeBaseService = knowledgeBaseService;
-        this.knowledgeRagService = knowledgeRagService;
-    }
-
-    @Override
-    public List<KnowledgeBaseVectorVO> getVectorStatusByKnowledgeBaseId(Long knowledgeBaseId) {
-        return baseMapper.selectByKnowledgeBaseId(knowledgeBaseId);
-    }
-
-    @Override
-    public KnowledgeBaseVector createVectorRecord(Long knowledgeBaseId, Long storageBlobId,
-                                                   String fileName, String fileType) {
-        KnowledgeBase knowledgeBase = knowledgeBaseService.getById(knowledgeBaseId);
-        if (knowledgeBase == null) {
-            throw new RuntimeException("鐭ヨ瘑搴撲笉瀛樺湪: " + knowledgeBaseId);
-        }
-
-        KnowledgeBaseVector vector = new KnowledgeBaseVector();
-        vector.setKnowledgeBaseId(knowledgeBaseId);
-        vector.setStorageBlobId(storageBlobId);
-        vector.setFileName(fileName);
-        vector.setFileType(fileType);
-        vector.setVectorStatus(KnowledgeBaseVector.STATUS_PENDING);
-        vector.setNamespace("kb-" + knowledgeBaseId);
-        vector.setChunkCount(0);
-        save(vector);
-
-        // 寮傛瑙﹀彂鍚戦噺鍖栧鐞�
-        knowledgeRagService.processVectorAsync(vector.getId());
-
-        return vector;
-    }
-
-    @Override
-    public void updateVectorStatus(Long id, Integer status, Integer chunkCount, String error) {
-        KnowledgeBaseVector vector = getById(id);
-        if (vector == null) {
-            return;
-        }
-        vector.setVectorStatus(status);
-        if (chunkCount != null) {
-            vector.setChunkCount(chunkCount);
-        }
-        if (error != null) {
-            vector.setVectorError(error);
-        }
-        updateById(vector);
-
-        // 濡傛灉瀹屾垚锛屾洿鏂扮煡璇嗗簱缁熻
-        if (status == KnowledgeBaseVector.STATUS_COMPLETED) {
-            updateKnowledgeBaseStats(vector.getKnowledgeBaseId());
-        }
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void reprocessVector(Long id) {
-        KnowledgeBaseVector vector = getById(id);
-        if (vector == null) {
-            throw new RuntimeException("鍚戦噺璁板綍涓嶅瓨鍦�: " + id);
-        }
-        vector.setVectorStatus(KnowledgeBaseVector.STATUS_PENDING);
-        vector.setVectorError(null);
-        vector.setChunkCount(0);
-        updateById(vector);
-
-        // 寮傛閲嶆柊澶勭悊
-        knowledgeRagService.processVectorAsync(id);
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void deleteVector(Long id) {
-        KnowledgeBaseVector vector = getById(id);
-        if (vector == null) {
-            return;
-        }
-
-        // 鍒犻櫎鍚戦噺搴撲腑鐨勬暟鎹�
-        try {
-            knowledgeRagService.deleteEmbeddings(vector.getNamespace(), vector.getStorageBlobId());
-        } catch (Exception e) {
-            log.error("鍒犻櫎鍚戦噺搴撴暟鎹け璐�", e);
-        }
-
-        // 鍒犻櫎璁板綍
-        removeById(id);
-
-        // 鏇存柊鐭ヨ瘑搴撶粺璁�
-        updateKnowledgeBaseStats(vector.getKnowledgeBaseId());
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void deleteVectors(List<Long> ids) {
-        for (Long id : ids) {
-            deleteVector(id);
-        }
-    }
-
-    private void updateKnowledgeBaseStats(Long knowledgeBaseId) {
-        KnowledgeBase knowledgeBase = knowledgeBaseService.getById(knowledgeBaseId);
-        if (knowledgeBase == null) {
-            return;
-        }
-        int fileCount = baseMapper.countByKnowledgeBaseId(knowledgeBaseId);
-        int totalChunkCount = baseMapper.sumChunkCountByKnowledgeBaseId(knowledgeBaseId);
-        knowledgeBase.setFileCount(fileCount);
-        knowledgeBase.setTotalChunkCount(totalChunkCount);
-        knowledgeBaseService.updateById(knowledgeBase);
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/controller/EnterpriseNewsController.java b/src/main/java/com/ruoyi/collaborativeApproval/controller/EnterpriseNewsController.java
deleted file mode 100644
index 36f1e21..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/controller/EnterpriseNewsController.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.ruoyi.collaborativeApproval.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.collaborativeApproval.dto.EnterpriseNewsDto;
-import com.ruoyi.collaborativeApproval.service.EnterpriseNewsService;
-import com.ruoyi.collaborativeApproval.vo.EnterpriseNewsVo;
-import com.ruoyi.framework.aspectj.lang.annotation.Log;
-import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
-import com.ruoyi.framework.web.domain.R;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import lombok.AllArgsConstructor;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈琛� 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:50:59
- */
-@RestController
-@RequestMapping("/enterpriseNews")
-@Tag(name = "浼佷笟鏂伴椈琛�")
-@AllArgsConstructor
-public class EnterpriseNewsController {
-
-    private final EnterpriseNewsService enterpriseNewsService;
-
-    @Operation(summary = "鍒嗛〉鏌ヨ")
-    @GetMapping("/listPage")
-    @Log(title = "浼佷笟鏂伴椈鍒嗛〉鏌ヨ", businessType = BusinessType.OTHER)
-    public R listPage(Page<EnterpriseNewsVo>  page , EnterpriseNewsDto enterpriseNewsDto) {
-        return R.ok(enterpriseNewsService.listPage(page, enterpriseNewsDto));
-    }
-
-    @PostMapping("/save")
-    @Operation(summary = "淇濆瓨")
-    @Log(title = "淇濆瓨浼佷笟鏂伴椈", businessType = BusinessType.INSERT)
-    public R save(@RequestBody EnterpriseNewsDto enterpriseNewsDto) {
-        return R.ok(enterpriseNewsService.add(enterpriseNewsDto));
-    }
-
-    @PutMapping("/update")
-    @Operation(summary = "鏇存柊")
-    @Log(title = "鏇存柊浼佷笟鏂伴椈", businessType = BusinessType.UPDATE)
-    public R update(@RequestBody EnterpriseNewsDto enterpriseNewsDto) {
-        return R.ok(enterpriseNewsService.updateEnterpriseNewsDto(enterpriseNewsDto));
-    }
-
-    @DeleteMapping("/delete")
-    @Operation(summary = "鍒犻櫎")
-    @Log(title = "鍒犻櫎浼佷笟鏂伴椈", businessType = BusinessType.DELETE)
-    public R delete(@RequestBody List<Long> ids) {
-        return R.ok(enterpriseNewsService.delete(ids));
-    }
-
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/controller/EnterpriseNewsScopeDeptController.java b/src/main/java/com/ruoyi/collaborativeApproval/controller/EnterpriseNewsScopeDeptController.java
deleted file mode 100644
index 8c68d1a..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/controller/EnterpriseNewsScopeDeptController.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.collaborativeApproval.controller;
-
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈闃呰鑼冨洿閮ㄩ棬琛� 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:51:12
- */
-@RestController
-@RequestMapping("/enterpriseNewsScopeDept")
-public class EnterpriseNewsScopeDeptController {
-
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/controller/EnterpriseNewsScopeUserController.java b/src/main/java/com/ruoyi/collaborativeApproval/controller/EnterpriseNewsScopeUserController.java
deleted file mode 100644
index 7ceba13..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/controller/EnterpriseNewsScopeUserController.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.collaborativeApproval.controller;
-
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈闃呰鑼冨洿鐢ㄦ埛琛� 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:51:23
- */
-@RestController
-@RequestMapping("/enterpriseNewsScopeUser")
-public class EnterpriseNewsScopeUserController {
-
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/dto/EnterpriseNewsDto.java b/src/main/java/com/ruoyi/collaborativeApproval/dto/EnterpriseNewsDto.java
deleted file mode 100644
index 108cf66..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/dto/EnterpriseNewsDto.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.ruoyi.collaborativeApproval.dto;
-
-import com.ruoyi.basic.dto.StorageBlobDTO;
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class EnterpriseNewsDto extends EnterpriseNews {
-
-    private String createUserName;
-
-    private List<Long> deptIds;
-
-    private List<Long> userIds;
-
-    private Long templateId;
-    private String templateName;
-
-    private String createTimeStart;
-    private String createTimeEnd;
-
-    private List<StorageBlobDTO> storageBlobDTOs;
-
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/mapper/EnterpriseNewsMapper.java b/src/main/java/com/ruoyi/collaborativeApproval/mapper/EnterpriseNewsMapper.java
deleted file mode 100644
index 799ae82..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/mapper/EnterpriseNewsMapper.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.collaborativeApproval.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.collaborativeApproval.dto.EnterpriseNewsDto;
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
-import com.ruoyi.collaborativeApproval.vo.EnterpriseNewsVo;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈琛� Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:50:59
- */
-@Mapper
-public interface EnterpriseNewsMapper extends BaseMapper<EnterpriseNews> {
-
-    IPage<EnterpriseNewsVo> listPage(Page<EnterpriseNewsVo> page,@Param("enterpriseNewsDto") EnterpriseNewsDto enterpriseNewsDto);
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/mapper/EnterpriseNewsScopeDeptMapper.java b/src/main/java/com/ruoyi/collaborativeApproval/mapper/EnterpriseNewsScopeDeptMapper.java
deleted file mode 100644
index 5b4639f..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/mapper/EnterpriseNewsScopeDeptMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.collaborativeApproval.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈闃呰鑼冨洿閮ㄩ棬琛� Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:51:12
- */
-@Mapper
-public interface EnterpriseNewsScopeDeptMapper extends BaseMapper<EnterpriseNewsScopeDept> {
-
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/mapper/EnterpriseNewsScopeUserMapper.java b/src/main/java/com/ruoyi/collaborativeApproval/mapper/EnterpriseNewsScopeUserMapper.java
deleted file mode 100644
index ab9a64f..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/mapper/EnterpriseNewsScopeUserMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.collaborativeApproval.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈闃呰鑼冨洿鐢ㄦ埛琛� Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:51:23
- */
-@Mapper
-public interface EnterpriseNewsScopeUserMapper extends BaseMapper<EnterpriseNewsScopeUser> {
-
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/pojo/EnterpriseNews.java b/src/main/java/com/ruoyi/collaborativeApproval/pojo/EnterpriseNews.java
deleted file mode 100644
index f5e001b..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/pojo/EnterpriseNews.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.ruoyi.collaborativeApproval.pojo;
-
-import com.baomidou.mybatisplus.annotation.FieldFill;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.annotations.ApiModel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * 浼佷笟鏂伴椈琛�
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:50:59
- */
-@Getter
-@Setter
-@ToString
-@TableName("enterprise_news")
-@ApiModel(value = "EnterpriseNews瀵硅薄", description = "浼佷笟鏂伴椈琛�")
-public class EnterpriseNews implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    @Schema(description = "缂栧彿 ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    @Schema(description = "鏍囬 Title")
-    private String title;
-
-    @Schema(description = "鎽樿 Summary")
-    private String summary;
-
-    @Schema(description = "姝f枃 Content")
-    private String content;
-
-    @Schema(description = "鍒嗙被 Category")
-    private String category;
-
-    @Schema(description = "闃呰鑼冨洿 Read scope: all 鍏ㄥ憳, dept 閮ㄩ棬, custom 鑷畾涔�")
-    private String readScope;
-
-    @Schema(description = "鏄惁蹇呰 Required flag: 0 鍚�, 1 鏄�")
-    private Byte isRequired;
-
-    @Schema(description = "鐘舵�� Status: DRAFT 鑽夌, PENDING 寰呭鎵�, PUBLISHED 宸插彂甯�, REJECTED 椹冲洖, OFFLINE 宸蹭笅绾�")
-    private String status;
-
-    @Schema(description = "搴旇浜烘暟 Required read count")
-    private Integer requiredReadCount;
-
-    @Schema(description = "宸茶浜烘暟 Read count")
-    private Integer readCount;
-
-    @Schema(description = "鍒涘缓浜� Create user")
-    @TableField(fill = FieldFill.INSERT)
-    private Long createUser;
-
-    @Schema(description = "鍒涘缓鏃堕棿 Create time")
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss", iso = DateTimeFormat.ISO.DATE_TIME)
-    private LocalDateTime createTime;
-
-    @Schema(description = "鏇存柊浜� Update user")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Long updateUser;
-
-    @Schema(description = "鏇存柊鏃堕棿 Update time")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss", iso = DateTimeFormat.ISO.DATE_TIME)
-    private LocalDateTime updateTime;
-
-    @Schema(description = "閮ㄩ棬ID Dept ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/pojo/EnterpriseNewsScopeDept.java b/src/main/java/com/ruoyi/collaborativeApproval/pojo/EnterpriseNewsScopeDept.java
deleted file mode 100644
index 97ff9de..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/pojo/EnterpriseNewsScopeDept.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.ruoyi.collaborativeApproval.pojo;
-
-import com.baomidou.mybatisplus.annotation.FieldFill;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈闃呰鑼冨洿閮ㄩ棬琛�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:51:12
- */
-@Getter
-@Setter
-@ToString
-@TableName("enterprise_news_scope_dept")
-@ApiModel(value = "EnterpriseNewsScopeDept瀵硅薄", description = "浼佷笟鏂伴椈闃呰鑼冨洿閮ㄩ棬琛�")
-public class EnterpriseNewsScopeDept implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 缂栧彿
-     */
-    @ApiModelProperty("缂栧彿")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 浼佷笟鏂伴椈ID
-     */
-    @ApiModelProperty("浼佷笟鏂伴椈ID")
-    private Long newsId;
-
-    /**
-     * 閮ㄩ棬ID
-     */
-    @ApiModelProperty("閮ㄩ棬ID")
-    private Long deptId;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @ApiModelProperty("鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/pojo/EnterpriseNewsScopeUser.java b/src/main/java/com/ruoyi/collaborativeApproval/pojo/EnterpriseNewsScopeUser.java
deleted file mode 100644
index 9d43df2..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/pojo/EnterpriseNewsScopeUser.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.ruoyi.collaborativeApproval.pojo;
-
-import com.baomidou.mybatisplus.annotation.FieldFill;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈闃呰鑼冨洿鐢ㄦ埛琛�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:51:23
- */
-@Getter
-@Setter
-@ToString
-@TableName("enterprise_news_scope_user")
-@ApiModel(value = "EnterpriseNewsScopeUser瀵硅薄", description = "浼佷笟鏂伴椈闃呰鑼冨洿鐢ㄦ埛琛�")
-public class EnterpriseNewsScopeUser implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 缂栧彿
-     */
-    @ApiModelProperty("缂栧彿")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 浼佷笟鏂伴椈ID
-     */
-    @ApiModelProperty("浼佷笟鏂伴椈ID")
-    private Long newsId;
-
-    /**
-     * 鐢ㄦ埛ID
-     */
-    @ApiModelProperty("鐢ㄦ埛ID")
-    private Long userId;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @ApiModelProperty("鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/service/EnterpriseNewsScopeDeptService.java b/src/main/java/com/ruoyi/collaborativeApproval/service/EnterpriseNewsScopeDeptService.java
deleted file mode 100644
index b41a7d8..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/service/EnterpriseNewsScopeDeptService.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.collaborativeApproval.service;
-
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept;
-import com.baomidou.mybatisplus.extension.service.IService;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈闃呰鑼冨洿閮ㄩ棬琛� 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:51:12
- */
-public interface EnterpriseNewsScopeDeptService extends IService<EnterpriseNewsScopeDept> {
-
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/service/EnterpriseNewsScopeUserService.java b/src/main/java/com/ruoyi/collaborativeApproval/service/EnterpriseNewsScopeUserService.java
deleted file mode 100644
index 28ac6c7..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/service/EnterpriseNewsScopeUserService.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.collaborativeApproval.service;
-
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser;
-import com.baomidou.mybatisplus.extension.service.IService;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈闃呰鑼冨洿鐢ㄦ埛琛� 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:51:23
- */
-public interface EnterpriseNewsScopeUserService extends IService<EnterpriseNewsScopeUser> {
-
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/service/EnterpriseNewsService.java b/src/main/java/com/ruoyi/collaborativeApproval/service/EnterpriseNewsService.java
deleted file mode 100644
index 21e7e6c..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/service/EnterpriseNewsService.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.ruoyi.collaborativeApproval.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.collaborativeApproval.dto.EnterpriseNewsDto;
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.collaborativeApproval.vo.EnterpriseNewsVo;
-
-import java.util.List;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈琛� 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:50:59
- */
-public interface EnterpriseNewsService extends IService<EnterpriseNews> {
-
-    IPage<EnterpriseNewsVo> listPage(Page<EnterpriseNewsVo> page, EnterpriseNewsDto enterpriseNewsDto);
-
-    Boolean add(EnterpriseNewsDto enterpriseNewsDto);
-
-    Boolean updateEnterpriseNewsDto(EnterpriseNewsDto enterpriseNewsDto);
-
-    Boolean delete(List<Long> ids);
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsScopeDeptServiceImpl.java b/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsScopeDeptServiceImpl.java
deleted file mode 100644
index 22283c7..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsScopeDeptServiceImpl.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.collaborativeApproval.service.impl;
-
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept;
-import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeDeptMapper;
-import com.ruoyi.collaborativeApproval.service.EnterpriseNewsScopeDeptService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import org.springframework.stereotype.Service;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈闃呰鑼冨洿閮ㄩ棬琛� 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:51:12
- */
-@Service
-public class EnterpriseNewsScopeDeptServiceImpl extends ServiceImpl<EnterpriseNewsScopeDeptMapper, EnterpriseNewsScopeDept> implements EnterpriseNewsScopeDeptService {
-
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsScopeUserServiceImpl.java b/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsScopeUserServiceImpl.java
deleted file mode 100644
index db1521e..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsScopeUserServiceImpl.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.collaborativeApproval.service.impl;
-
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser;
-import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeUserMapper;
-import com.ruoyi.collaborativeApproval.service.EnterpriseNewsScopeUserService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import org.springframework.stereotype.Service;
-
-/**
- * <p>
- * 浼佷笟鏂伴椈闃呰鑼冨洿鐢ㄦ埛琛� 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:51:23
- */
-@Service
-public class EnterpriseNewsScopeUserServiceImpl extends ServiceImpl<EnterpriseNewsScopeUserMapper, EnterpriseNewsScopeUser> implements EnterpriseNewsScopeUserService {
-
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java b/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java
deleted file mode 100644
index daa1c89..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java
+++ /dev/null
@@ -1,409 +0,0 @@
-package com.ruoyi.collaborativeApproval.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
-import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
-import com.ruoyi.approve.pojo.ApprovalInstance;
-import com.ruoyi.approve.pojo.ApprovalTask;
-import com.ruoyi.approve.pojo.ApprovalTemplate;
-import com.ruoyi.approve.service.ApprovalInstanceService;
-import com.ruoyi.approve.utils.ApproveProcessConfigNodeUtils;
-import com.ruoyi.basic.enums.ApplicationTypeEnum;
-import com.ruoyi.basic.enums.RecordTypeEnum;
-import com.ruoyi.basic.utils.FileUtil;
-import com.ruoyi.collaborativeApproval.dto.EnterpriseNewsDto;
-import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsMapper;
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept;
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser;
-import com.ruoyi.collaborativeApproval.service.EnterpriseNewsScopeDeptService;
-import com.ruoyi.collaborativeApproval.service.EnterpriseNewsScopeUserService;
-import com.ruoyi.collaborativeApproval.service.EnterpriseNewsService;
-import com.ruoyi.collaborativeApproval.vo.EnterpriseNewsVo;
-import com.ruoyi.common.enums.TypeEnums;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.utils.OrderUtils;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.project.system.domain.SysDept;
-import com.ruoyi.project.system.domain.SysUser;
-import com.ruoyi.project.system.mapper.SysDeptMapper;
-import com.ruoyi.project.system.mapper.SysUserDeptMapper;
-import com.ruoyi.project.system.mapper.SysUserMapper;
-import com.ruoyi.project.system.service.ISysNoticeService;
-import lombok.RequiredArgsConstructor;
-import org.springframework.beans.BeanUtils;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * 浼佷笟鏂伴椈琛ㄦ湇鍔″疄鐜扮被
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-05-20 11:50:59
- */
-@Service
-@RequiredArgsConstructor
-public class EnterpriseNewsServiceImpl extends ServiceImpl<EnterpriseNewsMapper, EnterpriseNews> implements EnterpriseNewsService {
-
-    private static final String READ_SCOPE_ALL = "all";
-    private static final String READ_SCOPE_DEPT = "dept";
-    private static final String READ_SCOPE_CUSTOM = "custom";
-
-    private static final String STATUS_DRAFT = "DRAFT";
-    private static final String STATUS_PENDING = "PENDING";
-    private static final String STATUS_PUBLISHED = "PUBLISHED";
-    private static final String STATUS_REJECTED = "REJECTED";
-    private static final String STATUS_OFFLINE = "OFFLINE";
-
-    private final EnterpriseNewsMapper enterpriseNewsMapper;
-    private final EnterpriseNewsScopeDeptService enterpriseNewsScopeDeptService;
-    private final EnterpriseNewsScopeUserService enterpriseNewsScopeUserService;
-    private final SysUserMapper sysUserMapper;
-    private final SysDeptMapper sysDeptMapper;
-    private final SysUserDeptMapper sysUserDeptMapper;
-    private final ApprovalInstanceMapper approvalInstanceMapper;
-    private final ApprovalInstanceService approvalInstanceService;
-    private final ApprovalTemplateMapper approvalTemplateMapper;
-    private final ApproveProcessConfigNodeUtils approveProcessConfigNodeUtils;
-    private final ISysNoticeService sysNoticeService;
-    private final FileUtil fileUtil;
-
-    @Override
-    public IPage<EnterpriseNewsVo> listPage(Page<EnterpriseNewsVo> page, EnterpriseNewsDto enterpriseNewsDto) {
-        IPage<EnterpriseNewsVo> enterpriseNewsVoIPage = enterpriseNewsMapper.listPage(page, enterpriseNewsDto);
-        enterpriseNewsVoIPage.getRecords().forEach(enterpriseNewsVo -> {
-            enterpriseNewsVo.setStorageBlobDTOs(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.ENTERPRISE_NEWS, enterpriseNewsVo.getId()));
-        });
-        return enterpriseNewsVoIPage;
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Boolean add(EnterpriseNewsDto enterpriseNewsDto) {
-        validateForSave(enterpriseNewsDto);
-        String readScope = normalizeReadScope(enterpriseNewsDto.getReadScope());
-        List<Long> deptIds = distinctIds(enterpriseNewsDto.getDeptIds());
-        List<Long> userIds = distinctIds(enterpriseNewsDto.getUserIds());
-
-        EnterpriseNews enterpriseNews = new EnterpriseNews();
-        BeanUtils.copyProperties(enterpriseNewsDto, enterpriseNews);
-        enterpriseNews.setReadScope(readScope);
-        enterpriseNews.setIsRequired(enterpriseNewsDto.getIsRequired() == null ? (byte) 0 : enterpriseNewsDto.getIsRequired());
-        enterpriseNews.setStatus(normalizeStatus(enterpriseNewsDto.getStatus(), STATUS_DRAFT));
-        enterpriseNews.setReadCount(0);
-        enterpriseNews.setRequiredReadCount(calculateRequiredReadCount(readScope, deptIds, userIds));
-
-        Long[] loginDeptIds = SecurityUtils.getDeptId();
-        if (StringUtils.isNotEmpty(loginDeptIds)) {
-            enterpriseNews.setDeptId(loginDeptIds[0]);
-        }
-
-        if (!save(enterpriseNews) || enterpriseNews.getId() == null) {
-            throw new ServiceException("鏂板浼佷笟鏂伴椈澶辫触");
-        }
-
-        saveReadScopeRelations(enterpriseNews.getId(), readScope, deptIds, userIds);
-        if (STATUS_PENDING.equals(enterpriseNews.getStatus())) {
-            startEnterpriseNewsApproval(enterpriseNews, enterpriseNewsDto);
-        }
-        //娣诲姞闄勪欢
-        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.ENTERPRISE_NEWS, enterpriseNews.getId(), enterpriseNewsDto.getStorageBlobDTOs());
-        return true;
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Boolean updateEnterpriseNewsDto(EnterpriseNewsDto enterpriseNewsDto) {
-        if (enterpriseNewsDto == null || enterpriseNewsDto.getId() == null) {
-            throw new ServiceException("浼佷笟鏂伴椈ID涓嶈兘涓虹┖");
-        }
-
-        EnterpriseNews oldEnterpriseNews = getById(enterpriseNewsDto.getId());
-        if (oldEnterpriseNews == null) {
-            throw new ServiceException("浼佷笟鏂伴椈涓嶅瓨鍦�");
-        }
-        if (!STATUS_DRAFT.equals(oldEnterpriseNews.getStatus())
-                && !STATUS_REJECTED.equals(oldEnterpriseNews.getStatus())) {
-            throw new ServiceException("寰呭鎵规垨宸插彂甯冪殑浼佷笟鏂伴椈涓嶅厑璁镐慨鏀�");
-        }
-
-        validateForSave(enterpriseNewsDto);
-        String readScope = normalizeReadScope(enterpriseNewsDto.getReadScope());
-        List<Long> deptIds = distinctIds(enterpriseNewsDto.getDeptIds());
-        List<Long> userIds = distinctIds(enterpriseNewsDto.getUserIds());
-
-        EnterpriseNews enterpriseNews = new EnterpriseNews();
-        BeanUtils.copyProperties(enterpriseNewsDto, enterpriseNews);
-        enterpriseNews.setReadScope(readScope);
-        enterpriseNews.setIsRequired(enterpriseNewsDto.getIsRequired() == null ? oldEnterpriseNews.getIsRequired() : enterpriseNewsDto.getIsRequired());
-        enterpriseNews.setStatus(normalizeStatus(enterpriseNewsDto.getStatus(), oldEnterpriseNews.getStatus()));
-        enterpriseNews.setReadCount(oldEnterpriseNews.getReadCount());
-        enterpriseNews.setRequiredReadCount(calculateRequiredReadCount(readScope, deptIds, userIds));
-        enterpriseNews.setCreateUser(oldEnterpriseNews.getCreateUser());
-        enterpriseNews.setCreateTime(oldEnterpriseNews.getCreateTime());
-        enterpriseNews.setDeptId(oldEnterpriseNews.getDeptId());
-
-        if (!updateById(enterpriseNews)) {
-            throw new ServiceException("淇敼浼佷笟鏂伴椈澶辫触");
-        }
-
-        clearReadScopeRelations(enterpriseNews.getId());
-        saveReadScopeRelations(enterpriseNews.getId(), readScope, deptIds, userIds);
-        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.ENTERPRISE_NEWS, enterpriseNews.getId(), enterpriseNewsDto.getStorageBlobDTOs());
-        if (STATUS_PENDING.equals(enterpriseNews.getStatus())) {
-            resetEnterpriseNewsApprovalFlow(oldEnterpriseNews);
-            startEnterpriseNewsApproval(enterpriseNews, enterpriseNewsDto);
-        }
-        return true;
-    }
-
-    @Override
-    public Boolean delete(List<Long> ids) {
-        if (ids == null || ids.isEmpty()) {
-            return false;
-        }
-        if (!removeByIds(ids)) {
-            throw new ServiceException("鍒犻櫎浼佷笟鏂伴椈澶辫触");
-        }
-        ids.forEach(this::clearReadScopeRelations);
-        return true;
-    }
-
-    private void validateForSave(EnterpriseNewsDto enterpriseNewsDto) {
-        if (enterpriseNewsDto == null) {
-            throw new ServiceException("浼佷笟鏂伴椈鏁版嵁涓嶈兘涓虹┖");
-        }
-        if (StringUtils.isEmpty(enterpriseNewsDto.getTitle())) {
-            throw new ServiceException("鏍囬涓嶈兘涓虹┖");
-        }
-        if (StringUtils.isEmpty(enterpriseNewsDto.getContent())) {
-            throw new ServiceException("姝f枃涓嶈兘涓虹┖");
-        }
-
-        normalizeStatus(enterpriseNewsDto.getStatus(), STATUS_DRAFT);
-        String readScope = normalizeReadScope(enterpriseNewsDto.getReadScope());
-        List<Long> deptIds = distinctIds(enterpriseNewsDto.getDeptIds());
-        List<Long> userIds = distinctIds(enterpriseNewsDto.getUserIds());
-
-        if (READ_SCOPE_DEPT.equals(readScope) && StringUtils.isEmpty(deptIds)) {
-            throw new ServiceException("璇烽�夋嫨闃呰鑼冨洿閮ㄩ棬");
-        }
-        if (READ_SCOPE_CUSTOM.equals(readScope) && StringUtils.isEmpty(userIds)) {
-            throw new ServiceException("璇烽�夋嫨鑷畾涔夐槄璇讳汉鍛�");
-        }
-
-        validateDeptIds(deptIds);
-        validateUserIds(userIds);
-    }
-
-    private String normalizeReadScope(String readScope) {
-        String normalized = StringUtils.isEmpty(readScope) ? READ_SCOPE_ALL : readScope.trim();
-        if (!READ_SCOPE_ALL.equals(normalized)
-                && !READ_SCOPE_DEPT.equals(normalized)
-                && !READ_SCOPE_CUSTOM.equals(normalized)) {
-            throw new ServiceException("闃呰鑼冨洿涓嶅悎娉�");
-        }
-        return normalized;
-    }
-
-    private String normalizeStatus(String status, String defaultStatus) {
-        String normalized = StringUtils.isEmpty(status) ? defaultStatus : status.trim().toUpperCase();
-        if (!STATUS_DRAFT.equals(normalized)
-                && !STATUS_PENDING.equals(normalized)
-                && !STATUS_PUBLISHED.equals(normalized)
-                && !STATUS_REJECTED.equals(normalized)
-                && !STATUS_OFFLINE.equals(normalized)) {
-            throw new ServiceException("浼佷笟鏂伴椈鐘舵�佷笉鍚堟硶");
-        }
-        return normalized;
-    }
-
-    private void validateDeptIds(List<Long> deptIds) {
-        if (StringUtils.isEmpty(deptIds)) {
-            return;
-        }
-        for (Long deptId : deptIds) {
-            SysDept sysDept = sysDeptMapper.selectDeptById(deptId);
-            if (deptId == null || sysDept == null) {
-                throw new ServiceException("闃呰鑼冨洿閮ㄩ棬涓嶅瓨鍦�");
-            }
-        }
-    }
-
-    private void validateUserIds(List<Long> userIds) {
-        if (StringUtils.isEmpty(userIds)) {
-            return;
-        }
-        List<SysUser> users = sysUserMapper.selectUsersByIds(userIds);
-        if (users.size() != userIds.size()) {
-            throw new ServiceException("鑷畾涔夐槄璇讳汉鍛樺寘鍚棤鏁堢敤鎴�");
-        }
-    }
-
-    private Integer calculateRequiredReadCount(String readScope, List<Long> deptIds, List<Long> userIds) {
-        if (READ_SCOPE_ALL.equals(readScope)) {
-            Long count = sysUserMapper.selectCount(new LambdaQueryWrapper<SysUser>()
-                    .eq(SysUser::getDelFlag, "0"));
-            return count == null ? 0 : count.intValue();
-        }
-        if (READ_SCOPE_DEPT.equals(readScope)) {
-            List<Long> allDeptIds = collectDeptIdsWithChildren(deptIds);
-            if (StringUtils.isEmpty(allDeptIds)) {
-                return 0;
-            }
-            Long count = sysUserDeptMapper.countDistinctUserIdsByDeptIds(allDeptIds);
-            return count == null ? 0 : count.intValue();
-        }
-        return userIds.size();
-    }
-
-    private List<Long> collectDeptIdsWithChildren(List<Long> deptIds) {
-        Set<Long> allDeptIds = new LinkedHashSet<>();
-        for (Long deptId : deptIds) {
-            if (deptId == null) {
-                continue;
-            }
-            allDeptIds.add(deptId);
-            List<SysDept> children = sysDeptMapper.selectChildrenDeptById(deptId);
-            if (StringUtils.isNotEmpty(children)) {
-                for (SysDept child : children) {
-                    allDeptIds.add(child.getDeptId());
-                }
-            }
-        }
-        return new ArrayList<>(allDeptIds);
-    }
-
-    private void saveReadScopeRelations(Long newsId, String readScope, List<Long> deptIds, List<Long> userIds) {
-        if (READ_SCOPE_DEPT.equals(readScope)) {
-            List<EnterpriseNewsScopeDept> scopeDeptList = new ArrayList<>();
-            for (Long deptId : deptIds) {
-                EnterpriseNewsScopeDept scopeDept = new EnterpriseNewsScopeDept();
-                scopeDept.setNewsId(newsId);
-                scopeDept.setDeptId(deptId);
-                scopeDeptList.add(scopeDept);
-            }
-            if (StringUtils.isNotEmpty(scopeDeptList)) {
-                enterpriseNewsScopeDeptService.saveBatch(scopeDeptList);
-            }
-            return;
-        }
-
-        if (READ_SCOPE_CUSTOM.equals(readScope)) {
-            List<EnterpriseNewsScopeUser> scopeUserList = new ArrayList<>();
-            for (Long userId : userIds) {
-                EnterpriseNewsScopeUser scopeUser = new EnterpriseNewsScopeUser();
-                scopeUser.setNewsId(newsId);
-                scopeUser.setUserId(userId);
-                scopeUserList.add(scopeUser);
-            }
-            if (StringUtils.isNotEmpty(scopeUserList)) {
-                enterpriseNewsScopeUserService.saveBatch(scopeUserList);
-            }
-        }
-    }
-
-    private void clearReadScopeRelations(Long newsId) {
-        enterpriseNewsScopeDeptService.remove(new LambdaQueryWrapper<EnterpriseNewsScopeDept>()
-                .eq(EnterpriseNewsScopeDept::getNewsId, newsId));
-        enterpriseNewsScopeUserService.remove(new LambdaQueryWrapper<EnterpriseNewsScopeUser>()
-                .eq(EnterpriseNewsScopeUser::getNewsId, newsId));
-    }
-
-    private void resetEnterpriseNewsApprovalFlow(EnterpriseNews oldEnterpriseNews) {
-        if (oldEnterpriseNews == null || !STATUS_DRAFT.equals(oldEnterpriseNews.getStatus())) {
-            return;
-        }
-        List<Long> approvalInstanceIds = approvalInstanceMapper.selectList(new LambdaQueryWrapper<ApprovalInstance>()
-                        .eq(ApprovalInstance::getBusinessId, oldEnterpriseNews.getId())
-                        .eq(ApprovalInstance::getBusinessType, TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode())
-                        .eq(ApprovalInstance::getDeleted, (byte) 0))
-                .stream()
-                .map(ApprovalInstance::getId)
-                .filter(id -> id != null && id > 0)
-                .collect(Collectors.toList());
-        if (StringUtils.isEmpty(approvalInstanceIds)) {
-            return;
-        }
-        approvalInstanceService.delete(approvalInstanceIds);
-    }
-
-    private List<Long> distinctIds(List<Long> ids) {
-        if (StringUtils.isEmpty(ids)) {
-            return new ArrayList<>();
-        }
-        Set<Long> distinctSet = new LinkedHashSet<>();
-        for (Long id : ids) {
-            if (id != null) {
-                distinctSet.add(id);
-            }
-        }
-        return new ArrayList<>(distinctSet);
-    }
-
-    private void startEnterpriseNewsApproval(EnterpriseNews enterpriseNews, EnterpriseNewsDto enterpriseNewsDto) {
-        if (enterpriseNewsDto.getTemplateId() == null) {
-            throw new ServiceException("瀹℃壒妯℃澘涓嶈兘涓虹┖");
-        }
-
-        String templateName = enterpriseNewsDto.getTemplateName();
-        if (StringUtils.isEmpty(templateName)) {
-            ApprovalTemplate approvalTemplate = approvalTemplateMapper.selectById(enterpriseNewsDto.getTemplateId());
-            if (approvalTemplate == null) {
-                throw new ServiceException("瀹℃壒妯℃澘涓嶅瓨鍦�");
-            }
-            templateName = approvalTemplate.getTemplateName();
-        }
-
-        ApprovalInstance approvalInstance = new ApprovalInstance();
-        approvalInstance.setInstanceNo(OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no", enterpriseNews.getCreateTime() != null ? enterpriseNews.getCreateTime() : LocalDateTime.now()));
-        approvalInstance.setTemplateId(enterpriseNewsDto.getTemplateId());
-        approvalInstance.setTemplateName(templateName);
-        approvalInstance.setBusinessId(enterpriseNews.getId());
-        approvalInstance.setBusinessType(TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode());
-        approvalInstance.setTitle(enterpriseNews.getTitle());
-        approvalInstance.setStatus("PENDING");
-        approvalInstance.setCurrentLevel(1);
-        approvalInstance.setApplicantId(SecurityUtils.getUserId());
-        approvalInstance.setApplicantName(SecurityUtils.getLoginUser().getNickName());
-        approvalInstance.setApplyTime(LocalDateTime.now());
-        approvalInstance.setDeleted((byte) 0);
-        approvalInstance.setCreateUser(SecurityUtils.getUserId());
-        approvalInstance.setUpdateUser(SecurityUtils.getUserId());
-        approvalInstance.setDeptId(enterpriseNews.getDeptId());
-        approvalInstanceMapper.insert(approvalInstance);
-
-        approveProcessConfigNodeUtils.createCurrentNodeAndTasks(approvalInstance);
-        sendApproveNotice(approvalInstance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstance.getId()));
-    }
-
-    private void sendApproveNotice(ApprovalInstance instance, List<ApprovalTask> tasks) {
-        if (instance == null || tasks == null || tasks.isEmpty()) {
-            return;
-        }
-        List<Long> approverIds = tasks.stream()
-                .map(ApprovalTask::getApproverId)
-                .filter(id -> id != null && id > 0)
-                .distinct()
-                .collect(Collectors.toList());
-        if (approverIds.isEmpty()) {
-            return;
-        }
-
-        String title = StringUtils.isNotEmpty(instance.getTemplateName()) ? instance.getTemplateName() : "瀹℃壒鎻愰啋";
-        String message = "瀹℃壒鍗曞彿 " + instance.getInstanceNo() + " 闇�瑕佹偍瀹℃壒";
-        String jumpPath = "/collaborativeApproval/approve-list/?id=" + instance.getId();
-        sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath);
-    }
-}
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/vo/EnterpriseNewsVo.java b/src/main/java/com/ruoyi/collaborativeApproval/vo/EnterpriseNewsVo.java
deleted file mode 100644
index 66123b9..0000000
--- a/src/main/java/com/ruoyi/collaborativeApproval/vo/EnterpriseNewsVo.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.ruoyi.collaborativeApproval.vo;
-
-import com.ruoyi.basic.dto.StorageBlobVO;
-import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class EnterpriseNewsVo extends EnterpriseNews {
-
-    private String createUserName;
-
-    private List<StorageBlobVO> storageBlobDTOs;
-}
diff --git a/src/main/java/com/ruoyi/common/enums/ApprovalStatusEnum.java b/src/main/java/com/ruoyi/common/enums/ApprovalStatusEnum.java
deleted file mode 100644
index 8913ebd..0000000
--- a/src/main/java/com/ruoyi/common/enums/ApprovalStatusEnum.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.ruoyi.common.enums;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-/**
- * 瀹℃壒鐘舵�佹灇涓�
- */
-@Getter
-@AllArgsConstructor
-public enum ApprovalStatusEnum implements BaseEnum<Integer> {
-
-    DRAFT(0, "鑽夌"),
-    PENDING(1, "寰呭鎵�"),
-    IN_PROGRESS(2, "瀹℃壒涓�"),
-    APPROVED(3, "宸查�氳繃"),
-    REJECTED(4, "宸查┏鍥�");
-
-
-    private final Integer value;
-    private final String label;
-
-    @Override
-    public Integer getCode() {
-        return value;
-    }
-
-    @Override
-    public String getValue() {
-        return label;
-    }
-
-    public static ApprovalStatusEnum fromValue(Integer value) {
-        if (value == null) {
-            return null;
-        }
-        for (ApprovalStatusEnum status : values()) {
-            if (status.getCode().equals(value)) {
-                return status;
-            }
-        }
-        return null;
-    }
-
-    public static String getLabelByValue(Integer value) {
-        ApprovalStatusEnum statusEnum = fromValue(value);
-        return statusEnum != null ? statusEnum.getValue() : "鏈煡鐘舵��";
-    }
-}
diff --git a/src/main/java/com/ruoyi/common/enums/EnterpriseNewsStatusEnum.java b/src/main/java/com/ruoyi/common/enums/EnterpriseNewsStatusEnum.java
deleted file mode 100644
index 8e6e480..0000000
--- a/src/main/java/com/ruoyi/common/enums/EnterpriseNewsStatusEnum.java
+++ /dev/null
@@ -1,143 +0,0 @@
-package com.ruoyi.common.enums;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonValue;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-
-/**
- * 浼佷笟鏂伴椈鐘舵�佹灇涓剧被
- *
- * @author ruoyi
- * @date 2026-05-20
- */
-@Schema(description = "浼佷笟鏂伴椈鐘舵�佹灇涓�")
-public enum EnterpriseNewsStatusEnum implements BaseEnum<String> {
-
-    /**
-     * 鑽夌
-     */
-    @Schema(description = "鑽夌")
-    DRAFT("DRAFT", "鑽夌"),
-
-    /**
-     * 寰呭鎵�
-     */
-    @Schema(description = "寰呭鎵�")
-    PENDING("PENDING", "寰呭鎵�"),
-
-    /**
-     * 宸插彂甯�
-     */
-    @Schema(description = "宸插彂甯�")
-    PUBLISHED("PUBLISHED", "宸插彂甯�"),
-
-    /**
-     * 椹冲洖
-     */
-    @Schema(description = "椹冲洖")
-    REJECTED("REJECTED", "椹冲洖"),
-
-    /**
-     * 宸蹭笅绾�
-     */
-    @Schema(description = "宸蹭笅绾�")
-    OFFLINE("OFFLINE", "宸蹭笅绾�");
-
-    /**
-     * 鐘舵�佺爜
-     */
-    private final String code;
-
-    /**
-     * 鐘舵�佹弿杩�
-     * -- GETTER --
-     *  鑾峰彇鐘舵�佹弿杩�
-     *
-     * @return 鐘舵�佹弿杩�
-
-     */
-    @Getter
-    private final String description;
-
-    EnterpriseNewsStatusEnum(String code, String description) {
-        this.code = code;
-        this.description = description;
-    }
-
-    /**
-     * 鑾峰彇鐘舵�佺爜
-     *
-     * @return 鐘舵�佺爜
-     */
-    @JsonValue
-    public String getCode() {
-        return code;
-    }
-
-    @Override
-    public String getValue() {
-        return "";
-    }
-
-    /**
-     * 鏍规嵁鐘舵�佺爜鑾峰彇鏋氫妇
-     *
-     * @param code 鐘舵�佺爜
-     * @return 鏋氫妇鍊�
-     */
-    @JsonCreator
-    public static EnterpriseNewsStatusEnum getByCode(String code) {
-        for (EnterpriseNewsStatusEnum status : values()) {
-            if (status.code.equals(code)) {
-                return status;
-            }
-        }
-        throw new IllegalArgumentException("Invalid enterprise news status code: " + code);
-    }
-
-    /**
-     * 鍒ゆ柇鏄惁涓鸿崏绋跨姸鎬�
-     *
-     * @return 鏄惁涓鸿崏绋跨姸鎬�
-     */
-    public boolean isDraft() {
-        return DRAFT.equals(this);
-    }
-
-    /**
-     * 鍒ゆ柇鏄惁涓哄緟瀹℃壒鐘舵��
-     *
-     * @return 鏄惁涓哄緟瀹℃壒鐘舵��
-     */
-    public boolean isPending() {
-        return PENDING.equals(this);
-    }
-
-    /**
-     * 鍒ゆ柇鏄惁涓哄凡鍙戝竷鐘舵��
-     *
-     * @return 鏄惁涓哄凡鍙戝竷鐘舵��
-     */
-    public boolean isPublished() {
-        return PUBLISHED.equals(this);
-    }
-
-    /**
-     * 鍒ゆ柇鏄惁涓洪┏鍥炵姸鎬�
-     *
-     * @return 鏄惁涓洪┏鍥炵姸鎬�
-     */
-    public boolean isRejected() {
-        return REJECTED.equals(this);
-    }
-
-    /**
-     * 鍒ゆ柇鏄惁涓哄凡涓嬬嚎鐘舵��
-     *
-     * @return 鏄惁涓哄凡涓嬬嚎鐘舵��
-     */
-    public boolean isOffline() {
-        return OFFLINE.equals(this);
-    }
-}
diff --git a/src/main/java/com/ruoyi/common/enums/SalesQuotationStatusEnum.java b/src/main/java/com/ruoyi/common/enums/SalesQuotationStatusEnum.java
deleted file mode 100644
index 0789c26..0000000
--- a/src/main/java/com/ruoyi/common/enums/SalesQuotationStatusEnum.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.ruoyi.common.enums;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-/**
- * 閿�鍞姤浠风姸鎬佹灇涓�
- */
-@Getter
-@AllArgsConstructor
-public enum SalesQuotationStatusEnum implements BaseEnum<String> {
-
-    DRAFT("鑽夌", "鑽夌"),
-    PENDING("寰呭鎵�", "寰呭鎵�"),
-    IN_PROGRESS("瀹℃牳涓�", "瀹℃牳涓�"),
-    APPROVED("閫氳繃", "閫氳繃"),
-    REJECTED("鎷掔粷", "鎷掔粷");
-
-    private final String value;
-    private final String label;
-
-    @Override
-    public String getCode() {
-        return value;
-    }
-
-    @Override
-    public String getValue() {
-        return label;
-    }
-
-    public static SalesQuotationStatusEnum fromValue(String value) {
-        if (value == null) {
-            return null;
-        }
-        for (SalesQuotationStatusEnum status : values()) {
-            if (status.getCode().equals(value)) {
-                return status;
-            }
-        }
-        return null;
-    }
-}
diff --git a/src/main/java/com/ruoyi/common/enums/ShippingStatusEnum.java b/src/main/java/com/ruoyi/common/enums/ShippingStatusEnum.java
deleted file mode 100644
index e8155f2..0000000
--- a/src/main/java/com/ruoyi/common/enums/ShippingStatusEnum.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.ruoyi.common.enums;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-/**
- * 鍙戣揣瀹℃壒鐘舵�佹灇涓�
- */
-@Getter
-@AllArgsConstructor
-public enum ShippingStatusEnum implements BaseEnum<String> {
-
-    PENDING("寰呯‘璁�", "寰呯‘璁�"),
-    IN_PROGRESS("瀹℃牳涓�", "瀹℃牳涓�"),
-    APPROVED("瀹℃牳閫氳繃", "瀹℃牳閫氳繃"),
-    REJECTED("瀹℃牳鎷掔粷", "瀹℃牳鎷掔粷");
-
-    private final String value;
-    private final String label;
-
-    @Override
-    public String getCode() {
-        return value;
-    }
-
-    @Override
-    public String getValue() {
-        return label;
-    }
-
-    public static ShippingStatusEnum fromValue(String value) {
-        if (value == null) {
-            return null;
-        }
-        for (ShippingStatusEnum status : values()) {
-            if (status.getCode().equals(value)) {
-                return status;
-            }
-        }
-        return null;
-    }
-}
diff --git a/src/main/java/com/ruoyi/common/enums/TypeEnums.java b/src/main/java/com/ruoyi/common/enums/TypeEnums.java
deleted file mode 100644
index ba1c1f3..0000000
--- a/src/main/java/com/ruoyi/common/enums/TypeEnums.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.ruoyi.common.enums;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-@Getter
-@AllArgsConstructor
-public enum TypeEnums implements BaseEnum<Long> {
-
-    PUBLIC_OUT(1L, "鍏嚭绠$悊"),
-    LEAVE(2L, "璇峰亣绠$悊"),
-    BUSINESS_TRIP(3L, "鍑哄樊绠$悊"),
-    REIMBURSEMENT(4L, "鎶ラ攢绠$悊"),
-    PURCHASE_APPROVAL(5L, "閲囪喘瀹℃壒"),
-    QUOTATION_APPROVAL(6L, "鎶ヤ环瀹℃壒"),
-    SHIPPING_APPROVAL(7L, "鍙戣揣瀹℃壒"),
-    DANGEROUS_OPERATION(8L, "鍗遍櫓浣滀笟瀹℃壒"),
-    OFFICE_SUPPLIES(9L, "鍔炲叕鐢ㄥ搧瀹℃壒"),
-    REGULARIZATION_APPROVAL(10L, "杞瀹℃壒"),
-    TRANSFER_APPROVAL(11L, "璋冨姩瀹℃壒"),
-    RESIGNATION_APPROVAL(12L, "绂昏亴瀹℃壒"),
-    WORK_HANDOVER_APPROVAL(13L, "宸ヤ綔浜ゆ帴瀹℃壒"),
-    LEAVE_APPROVAL(14L, "璇峰亣瀹℃壒"),
-    OVERTIME_APPROVAL(15L, "鍔犵彮瀹℃壒"),
-    TRAVEL_REIMBURSEMENT_APPROVAL(16L, "鍑哄樊鎶ラ攢瀹℃壒"),
-    EXPENSE_APPROVAL(17L, "璐圭敤瀹℃壒"),
-    ENTERPRISE_NEWS_APPROVAL(18L, "浼佷笟鏂伴椈瀹℃壒");
-
-
-
-    private final Long value;
-    private final String label;
-
-    @Override
-    public Long getCode() {
-        return value;
-    }
-
-    @Override
-    public String getValue() {
-        return label;
-    }
-
-    /**
-     * 鏍规嵁鍊艰幏鍙栧搴旂殑鏋氫妇
-     * @param value 涓氬姟绫诲瀷鍊�
-     * @return 瀵瑰簲鐨勬灇涓撅紝鏈尮閰嶈繑鍥瀗ull
-     */
-    public static TypeEnums fromValue(Long value) {
-        if (value == null) {
-            return null;
-        }
-        for (TypeEnums type : values()) {
-            if (type.getCode().equals(value)) {
-                return type;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * 鏍规嵁鍊艰幏鍙栨弿杩�
-     * @param value 涓氬姟绫诲瀷鍊�
-     * @return 涓氬姟绫诲瀷鎻忚堪锛屾湭鍖归厤杩斿洖"鑷畾涔夊鎵�"
-     */
-    public static String getLabelByValue(Long value) {
-        TypeEnums typeEnum = fromValue(value);
-        return typeEnum != null ? typeEnum.getValue() : "鑷畾涔夊鎵�";
-    }
-}
diff --git a/src/main/java/com/ruoyi/mock/controller/DataCheckController.java b/src/main/java/com/ruoyi/mock/controller/DataCheckController.java
deleted file mode 100644
index e8c0b8d..0000000
--- a/src/main/java/com/ruoyi/mock/controller/DataCheckController.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.ruoyi.mock.controller;
-
-import com.ruoyi.framework.web.domain.R;
-import com.ruoyi.mock.dto.DataCheckRequest;
-import com.ruoyi.mock.dto.DataGenerateRequest;
-import com.ruoyi.mock.service.DataCheckService;
-import com.ruoyi.mock.service.DataGenerateService;
-import com.ruoyi.mock.vo.DataCheckResult;
-import com.ruoyi.mock.vo.DataCheckResult.CheckItem;
-import com.ruoyi.mock.vo.DataGenerateResult;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-@RequestMapping("/mock")
-@RequiredArgsConstructor
-@Tag(name = "鏁版嵁妯℃嫙")
-public class DataCheckController {
-
-    private final DataCheckService dataCheckService;
-    private final DataGenerateService dataGenerateService;
-
-    @PostMapping("/dataCheck")
-    @Operation(summary = "妫�娴嬪熀纭�鏁版嵁")
-    public R<DataCheckResult> dataCheck(@RequestBody DataCheckRequest request) {
-        DataCheckResult result = dataCheckService.check(request);
-        return R.ok(result);
-    }
-
-    @PostMapping("/generate")
-    @Operation(summary = "AI鐢熸垚妯℃嫙鏁版嵁")
-    public R<?> generate(@RequestBody DataGenerateRequest request) {
-        // 鍏堟牎楠屽熀纭�鏁版嵁
-        DataCheckRequest checkRequest = new DataCheckRequest();
-        checkRequest.setModules(request.getModules());
-        DataCheckResult checkResult = dataCheckService.check(checkRequest);
-
-        boolean allPassed = checkResult.getItems().stream().allMatch(CheckItem::isPassed);
-        if (!allPassed) {
-            DataGenerateResult failResult = new DataGenerateResult();
-            failResult.setStatus("CHECK_FAILED");
-            failResult.setCheckResult(checkResult);
-            return R.fail(failResult, "鍩虹鏁版嵁涓嶈冻锛岃鍏堣ˉ鍏呭悗鍐嶇敓鎴�");
-        }
-
-        DataGenerateResult result = dataGenerateService.generate(request);
-        return R.ok(result);
-    }
-}
diff --git a/src/main/java/com/ruoyi/mock/dto/DataCheckRequest.java b/src/main/java/com/ruoyi/mock/dto/DataCheckRequest.java
deleted file mode 100644
index 9e1d7db..0000000
--- a/src/main/java/com/ruoyi/mock/dto/DataCheckRequest.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.ruoyi.mock.dto;
-
-import lombok.Data;
-
-import java.util.List;
-
-/**
- * 鍩虹鏁版嵁妫�娴嬭姹�
- */
-@Data
-public class DataCheckRequest {
-
-    /** 闇�瑕佹娴嬬殑妯″潡: sales / purchase / quality */
-    private List<String> modules;
-}
diff --git a/src/main/java/com/ruoyi/mock/dto/DataGenerateRequest.java b/src/main/java/com/ruoyi/mock/dto/DataGenerateRequest.java
deleted file mode 100644
index 9f9522c..0000000
--- a/src/main/java/com/ruoyi/mock/dto/DataGenerateRequest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.ruoyi.mock.dto;
-
-import lombok.Data;
-
-import java.util.List;
-
-/**
- * AI鏁版嵁鐢熸垚璇锋眰
- */
-@Data
-public class DataGenerateRequest {
-
-    /** 瑕佺敓鎴愭暟鎹殑妯″潡: sales / purchase / quality / production / stock */
-    private List<String> modules;
-
-    /** 琛屼笟锛堝涓級锛屽: ["鏈烘鍒堕��", "椋熷搧鍔犲伐", "鐢靛瓙瑁呴厤"] */
-    private List<String> industries;
-
-    /** 姣忎釜瀹炰綋鐢熸垚鏁伴噺鐨勬渶灏忓�� */
-    private int countMin;
-
-    /** 姣忎釜瀹炰綋鐢熸垚鏁伴噺鐨勬渶澶у�� */
-    private int countMax;
-
-    /** 鏃堕棿鑼冨洿-寮�濮�, yyyy-MM-dd */
-    private String dateStart;
-
-    /** 鏃堕棿鑼冨洿-缁撴潫, yyyy-MM-dd */
-    private String dateEnd;
-
-    /** 鍏朵粬琛ュ厖鎻忚堪 */
-    private String additionalInfo;
-}
diff --git a/src/main/java/com/ruoyi/mock/prompt/MockDataPrompt.java b/src/main/java/com/ruoyi/mock/prompt/MockDataPrompt.java
deleted file mode 100644
index 2743445..0000000
--- a/src/main/java/com/ruoyi/mock/prompt/MockDataPrompt.java
+++ /dev/null
@@ -1,242 +0,0 @@
-package com.ruoyi.mock.prompt;
-
-import com.ruoyi.project.system.domain.SysUser;
-
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * 鍚勬ā鍧楃殑 AI Prompt 妯℃澘
- */
-public final class MockDataPrompt {
-
-    private MockDataPrompt() {}
-
-    public static String buildSystemPrompt() {
-        return """
-            浣犳槸涓�涓紒涓欵RP绯荤粺鐨勬暟鎹ā鎷熶笓瀹躲��
-
-            鏍稿績瑙勫垯锛堝繀椤讳弗鏍奸伒瀹堬級锛�
-            1. 杈撳嚭蹇呴』鏄函JSON鏁扮粍锛屼笉瑕佺敤markdown浠g爜鍧楀寘瑁癸紝涓嶈鏈変换浣曞叾浠栨枃瀛�
-            2. 姣忎釜JSON瀵硅薄蹇呴』鍖呭惈 "entity" 瀛楁锛屽�间负瀹炰綋绫诲瀷鍚�
-            3. 鏁版嵁鍐呭瑕佺鍚堟寚瀹氳涓氱殑鐗瑰緛
-            4. 閲戦銆佹暟閲忕瓑鏁板�煎瓧娈佃鍚堢悊
-            5. 鍚屼竴妯″潡鍐呯殑瀹炰綋涔嬮棿瑕佹湁寮曠敤鍏崇郴
-            6. 涓嶈浣跨敤emoji鎴栫壒娈妘nicode瀛楃
-            7. 鏈�閲嶈锛氭棩鏈熷彧浠�"鎸囧畾鏃堕棿鑼冨洿"涓彇锛岀粷瀵逛笉瑕佺敤鍏朵粬骞翠唤锛�
-            8. 浜哄憳瀛楁锛堝entryPerson銆乻alesman绛夛級蹇呴』浠�"绯荤粺鐢ㄦ埛鍒楄〃"涓�夊彇锛屾牴鎹鑹插拰閮ㄩ棬鍖归厤瀵瑰簲妯″潡锛屼笉瑕佺紪閫犱汉鍚嶏紒
-            """;
-    }
-
-    public static String buildUserMessage(List<String> modules, List<String> industries,
-                                           int countMin, int countMax,
-                                           String dateStart, String dateEnd,
-                                           String additionalInfo,
-                                           Map<Long, String> productModelIdToCategory,
-                                           List<SysUser> systemUsers,
-                                           List<String> existingCustomerNames,
-                                           List<String> existingSupplierNames) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("鎸囧畾琛屼笟: ").append(String.join("銆�", industries)).append("\n");
-        sb.append("姣忕瀹炰綋鐢熸垚: ").append(countMin).append("-").append(countMax).append(" 鏉n");
-        sb.append("鎸囧畾鏃堕棿鑼冨洿: ").append(dateStart).append(" 鍒� ").append(dateEnd);
-        sb.append("锛堟墍鏈夋棩鏈熷瓧娈靛繀椤诲湪杩欎釜鑼冨洿鍐咃紒绂佹浣跨敤2023銆�2024銆�2025绛変换浣曡秴鍑鸿寖鍥寸殑骞翠唤锛侊級\n");
-        if (additionalInfo != null && !additionalInfo.isBlank()) {
-            sb.append("琛ュ厖淇℃伅: ").append(additionalInfo).append("\n");
-        }
-        sb.append("\n");
-
-        // 鎸夐《绾т骇鍝佸垎绫伙紙鎴愬搧/鍘熸潗鏂�/鍗婃垚鍝侊級鍒嗙粍鍒楀嚭浜у搧瑙勬牸
-        Map<String, List<Map.Entry<Long, String>>> grouped = productModelIdToCategory.entrySet().stream()
-                .collect(Collectors.groupingBy(
-                        e -> categorize(e.getValue()),
-                        java.util.LinkedHashMap::new,
-                        Collectors.toList()));
-
-        sb.append("=== 浜у搧瑙勬牸鍒楄〃 ===\n");
-        for (Map.Entry<String, List<Map.Entry<Long, String>>> entry : grouped.entrySet()) {
-            String label = entry.getKey();
-            List<Map.Entry<Long, String>> items = entry.getValue();
-            sb.append("銆�").append(label).append("銆�: ");
-            sb.append(items.stream()
-                    .map(e -> e.getKey() + "(" + e.getValue() + ")")
-                    .collect(Collectors.joining(", "))).append("\n");
-        }
-        sb.append("閿�鍞彴璐︾殑productData鍙兘閫夈�愭垚鍝佺被銆戣鏍硷紝閲囪喘鍙拌处鍙兘閫夈�愬師鏉愭枡绫汇�戣鏍笺�俓n\n");
-
-        // 绯荤粺鐢ㄦ埛鍒楄〃锛堝惈瑙掕壊鍜岄儴闂級
-        sb.append("=== 绯荤粺鐢ㄦ埛鍒楄〃锛堜汉鍛樺瓧娈靛繀椤讳粠涓�夊彇锛屼笉瑕佺紪閫犱汉鍚嶏級===\n");
-        for (SysUser u : systemUsers) {
-            String roleNames = u.getRoleNames() != null && !u.getRoleNames().isBlank() ? u.getRoleNames() : "鏃犺鑹�";
-            String deptNames = u.getDeptNames() != null && !u.getDeptNames().isBlank() ? u.getDeptNames() : "鏃犻儴闂�";
-            sb.append(u.getNickName()).append("锛堣鑹�: ").append(roleNames).append(", 閮ㄩ棬: ").append(deptNames).append("锛塡n");
-        }
-        sb.append("閫夋嫨瑙勫垯锛歕n");
-        sb.append("- 閿�鍞ā鍧楃殑浜哄憳(entryPerson銆乻alesman)閫夎鑹叉垨閮ㄩ棬鍚玕"閿�鍞甛"鐨勭敤鎴穃n");
-        sb.append("- 閲囪喘妯″潡鐨勪汉鍛橀�夎鑹叉垨閮ㄩ棬鍚玕"閲囪喘\"鐨勭敤鎴穃n");
-        sb.append("- 鐢熶骇妯″潡鐨勪汉鍛橀�夎鑹叉垨閮ㄩ棬鍚玕"鐢熶骇\"鐨勭敤鎴穃n");
-        sb.append("- 璐ㄩ噺妯″潡鐨勪汉鍛橀�夎鑹叉垨閮ㄩ棬鍚玕"璐ㄩ噺\"鎴朶"璐ㄦ\"鐨勭敤鎴穃n");
-        sb.append("- 浠撳簱妯″潡鐨勪汉鍛橀�夎鑹叉垨閮ㄩ棬鍚玕"浠撳簱\"鎴朶"搴撳瓨\"鐨勭敤鎴穃n\n");
-
-        if (!existingCustomerNames.isEmpty()) {
-            sb.append("=== 宸叉湁瀹㈡埛锛堝彧鑳藉紩鐢紝涓嶈鐢熸垚鏂癱ustomer瀹炰綋锛�===\n");
-            sb.append(String.join("銆�", existingCustomerNames)).append("\n\n");
-        }
-        if (!existingSupplierNames.isEmpty()) {
-            sb.append("=== 宸叉湁渚涘簲鍟嗭紙鍙兘寮曠敤锛屼笉瑕佺敓鎴愭柊supplier瀹炰綋锛�===\n");
-            sb.append(String.join("銆�", existingSupplierNames)).append("\n\n");
-        }
-
-        sb.append("鏁版嵁妯″潡: ").append(String.join("銆�", modules)).append("\n\n");
-
-        if (modules.contains("sales")) {
-            sb.append(buildSalesPrompt(countMin, countMax, dateStart, dateEnd, existingCustomerNames));
-        }
-        if (modules.contains("purchase")) {
-            sb.append(buildPurchasePrompt(countMin, countMax, dateStart, dateEnd, existingSupplierNames));
-        }
-        if (modules.contains("quality")) {
-            sb.append(buildQualityPrompt(countMin, countMax, dateStart));
-        }
-        if (modules.contains("production")) {
-            sb.append(buildProductionPrompt(countMin, countMax, dateStart, dateEnd));
-        }
-        if (modules.contains("stock")) {
-            sb.append(buildStockPrompt(countMin, countMax, dateStart));
-        }
-
-        sb.append("\n璇风洿鎺ヨ緭鍑篔SON鏁扮粍:");
-        return sb.toString();
-    }
-
-    /**
-     * 灏嗛《绾т骇鍝佸悕绉版槧灏勪负鍒嗙被鏍囩
-     */
-    private static String categorize(String rootProductName) {
-        if (rootProductName == null) return "鍏朵粬绫�";
-        if (rootProductName.contains("鎴愬搧") || rootProductName.contains("浜ф垚鍝�")) return "鎴愬搧绫�-閿�鍞紭鍏堥�夎繖浜�";
-        if (rootProductName.contains("鍘熸枡") || rootProductName.contains("鍘熸潗鏂�") || rootProductName.contains("鏉愭枡")) return "鍘熸潗鏂欑被-閲囪喘浼樺厛閫夎繖浜�";
-        if (rootProductName.contains("鍗婃垚鍝�")) return "鍗婃垚鍝佺被";
-        return "鍏朵粬绫�";
-    }
-
-    private static String buildSalesPrompt(int min, int max, String dateStart, String dateEnd,
-                                            List<String> existingCustomerNames) {
-        String namesHint = existingCustomerNames.isEmpty() ? ""
-                : "customerName蹇呴』浠庝互涓嬪凡鏈夊鎴蜂腑閫夋嫨: " + String.join("銆�", existingCustomerNames) + "\n";
-        return """
-            閿�鍞ā鍧楁牸寮忥紙鎵�鏈夋棩鏈熷繀椤诲湪 %s ~ %s 鑼冨洿鍐咃級:
-            %s娉ㄦ剰锛氫笉瑕佺敓鎴恈ustomer瀹炰綋锛屽彧鐢熸垚salesLedger锛�
-            productData涓殑productModelId蹇呴』閫夈�愭垚鍝佺被銆戣鏍糏D锛�
-            entryPerson鍜宻alesman蹇呴』浠庣郴缁熺敤鎴峰垪琛ㄤ腑瑙掕壊鎴栭儴闂ㄥ惈"閿�鍞�"鐨勭敤鎴蜂腑閫夊彇锛�
-            {
-              "entity": "salesLedger",
-              "customerName": "寮曠敤涓婇潰鐢熸垚鐨勫鎴峰悕绉�",
-              "salesContractNo": "XS-YYYYMMDD-001",
-              "projectName": "XX椤圭洰",
-              "entryDate": "%s",
-              "entryPerson": "浠庣敤鎴峰垪琛ㄤ腑閫�",
-              "salesman": "浠庣敤鎴峰垪琛ㄤ腑閫�",
-              "contractAmount": 50000.00,
-              "paymentMethod": "鏈堢粨30澶�",
-              "executionDate": "%s",
-              "deliveryDate": "%s",
-              "type": 1,
-              "productData": [{
-                "productId": 1, "productModelId": 1, "quantity": 100,
-                "taxInclusiveUnitPrice": 500.00, "taxInclusiveTotalPrice": 50000.00,
-                "taxExclusiveTotalPrice": 44247.79, "taxRate": 13.00, "unit": "浠�", "type": 1
-              }]
-            }
-            salesContractNo涓璝YYYMMDD鏇挎崲涓篹ntryDate鐨勬棩鏈熴��%d-%d鏉°��
-            """.formatted(dateStart, dateEnd, namesHint, dateStart, dateStart, dateEnd, min, max);
-    }
-
-    private static String buildPurchasePrompt(int min, int max, String dateStart, String dateEnd,
-                                              List<String> existingSupplierNames) {
-        String namesHint = existingSupplierNames.isEmpty() ? ""
-                : "supplierName蹇呴』浠庝互涓嬪凡鏈変緵搴斿晢涓�夋嫨: " + String.join("銆�", existingSupplierNames) + "\n";
-        return """
-            閲囪喘妯″潡鏍煎紡锛堟墍鏈夋棩鏈熷繀椤诲湪 %s ~ %s 鑼冨洿鍐咃級:
-            %s娉ㄦ剰锛氫笉瑕佺敓鎴恠upplier瀹炰綋锛屽彧鐢熸垚purchaseLedger锛�
-            productData涓殑productModelId蹇呴』閫夈�愬師鏉愭枡绫汇�戣鏍糏D锛�
-            浜哄憳瀛楁蹇呴』浠庣郴缁熺敤鎴峰垪琛ㄤ腑瑙掕壊鎴栭儴闂ㄥ惈"閲囪喘"鐨勭敤鎴蜂腑閫夊彇锛�
-            {
-              "entity": "purchaseLedger",
-              "supplierName": "浠庡凡鏈変緵搴斿晢涓�夋嫨",
-              "purchaseContractNumber": "CG-YYYYMMDD-001",
-              "projectName": "XX閲囪喘椤圭洰",
-              "entryDate": "%s",
-              "contractAmount": 30000.00,
-              "paymentMethod": "璐у埌浠樻",
-              "executionDate": "%s",
-              "productData": [{
-                "productId": 1, "productModelId": 1, "quantity": 50,
-                "taxInclusiveUnitPrice": 600.00, "taxInclusiveTotalPrice": 30000.00,
-                "taxExclusiveTotalPrice": 26548.67, "taxRate": 13.00, "unit": "浠�", "type": 2
-              }]
-            }
-            purchaseContractNumber涓璝YYYMMDD鏇挎崲涓篹ntryDate鐨勬棩鏈熴��%d-%d鏉°��
-            """.formatted(dateStart, dateEnd, namesHint, dateStart, dateStart, min, max);
-    }
-
-    private static String buildQualityPrompt(int min, int max, String dateStart) {
-        return """
-            璐ㄩ噺妯″潡鏍煎紡:
-            {
-              "entity": "qualityTestStandard",
-              "standardNo": "QTS-YYYYMMDD-001",
-              "standardName": "XX浜у搧妫�楠屾爣鍑�",
-              "inspectType": 0,
-              "remark": "閫傜敤浜嶺X琛屼笟鐨勮川閲忔楠屾爣鍑�"
-            }
-            inspectType: 0=鍘熸潗鏂欐楠�, 1=杩囩▼妫�楠�, 2=鍑哄巶妫�楠屻�備笁绉嶇被鍨嬮兘瑕佽鐩栥��
-            standardNo涓璝YYYMMDD鏇挎崲涓� %s銆�%d-%d鏉°��
-            {
-              "entity": "qualityTestStandardBinding",
-              "productId": 1,
-              "testStandardId": 1
-            }
-            %d-%d鏉°��
-            """.formatted(dateStart.replace("-", ""), min, max, min, max);
-    }
-
-    private static String buildProductionPrompt(int min, int max, String dateStart, String dateEnd) {
-        return """
-            鐢熶骇妯″潡鏍煎紡锛堟墍鏈夋棩鏈熷繀椤诲湪 %s ~ %s 鑼冨洿鍐咃級:
-            {
-              "entity": "productionPlan",
-              "productModelId": 1,
-              "qtyRequired": 200,
-              "requiredDate": "%s",
-              "source": "閿�鍞�",
-              "promisedDeliveryDate": "%s",
-              "remark": "XX瀹㈡埛璁㈠崟闇�姹�"
-            }
-            {
-              "entity": "productionOrder",
-              "productModelId": 1,
-              "quantity": 200,
-              "planCompleteTime": "%s",
-              "remark": "鏍规嵁鐢熶骇璁″垝XX鐢熸垚"
-            }
-            source鍙��"閿�鍞�"鎴�"鍐呴儴"銆�%d-%d鏉°��
-            """.formatted(dateStart, dateEnd, dateStart, dateEnd, dateEnd, min, max);
-    }
-
-    private static String buildStockPrompt(int min, int max, String dateStart) {
-        return """
-            搴撳瓨妯″潡鏍煎紡:
-            {
-              "entity": "stockInventory",
-              "productModelId": 1,
-              "qualitity": 500,
-              "batchNo": "BATCH-YYYYMMDD-001",
-              "warnNum": 50,
-              "remark": "瀹夊叏搴撳瓨"
-            }
-            batchNo涓璝YYYMMDD鏇挎崲涓� %s銆�%d-%d鏉°��
-            """.formatted(dateStart.replace("-", ""), min, max);
-    }
-}
diff --git a/src/main/java/com/ruoyi/mock/service/DataCheckService.java b/src/main/java/com/ruoyi/mock/service/DataCheckService.java
deleted file mode 100644
index ac3b652..0000000
--- a/src/main/java/com/ruoyi/mock/service/DataCheckService.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.ruoyi.mock.service;
-
-import com.ruoyi.mock.dto.DataCheckRequest;
-import com.ruoyi.mock.vo.DataCheckResult;
-
-/**
- * 鍩虹鏁版嵁妫�娴嬫湇鍔�
- */
-public interface DataCheckService {
-
-    /**
-     * 妫�娴嬫寚瀹氭ā鍧楃殑鍩虹鏁版嵁鏄惁灏辩华
-     */
-    DataCheckResult check(DataCheckRequest request);
-}
diff --git a/src/main/java/com/ruoyi/mock/service/DataGenerateService.java b/src/main/java/com/ruoyi/mock/service/DataGenerateService.java
deleted file mode 100644
index 1b0b6b0..0000000
--- a/src/main/java/com/ruoyi/mock/service/DataGenerateService.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.ruoyi.mock.service;
-
-import com.ruoyi.mock.dto.DataGenerateRequest;
-import com.ruoyi.mock.vo.DataGenerateResult;
-
-/**
- * AI鏁版嵁鐢熸垚鏈嶅姟
- */
-public interface DataGenerateService {
-
-    /**
-     * 鏍规嵁璇锋眰鍙傛暟璋冪敤AI鐢熸垚妯℃嫙鏁版嵁骞跺垱寤�
-     */
-    DataGenerateResult generate(DataGenerateRequest request);
-}
diff --git a/src/main/java/com/ruoyi/mock/service/impl/DataCheckServiceImpl.java b/src/main/java/com/ruoyi/mock/service/impl/DataCheckServiceImpl.java
deleted file mode 100644
index 0fc4718..0000000
--- a/src/main/java/com/ruoyi/mock/service/impl/DataCheckServiceImpl.java
+++ /dev/null
@@ -1,282 +0,0 @@
-package com.ruoyi.mock.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.ruoyi.approve.pojo.ApprovalTemplate;
-import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
-import com.ruoyi.basic.mapper.CustomerMapper;
-import com.ruoyi.basic.mapper.ProductMapper;
-import com.ruoyi.basic.mapper.ProductModelMapper;
-import com.ruoyi.basic.mapper.SupplierManageMapper;
-import com.ruoyi.common.enums.TypeEnums;
-import com.ruoyi.mock.dto.DataCheckRequest;
-import com.ruoyi.mock.service.DataCheckService;
-import com.ruoyi.mock.vo.DataCheckResult;
-import com.ruoyi.mock.vo.DataCheckResult.CheckItem;
-import com.ruoyi.project.system.domain.SysUser;
-import com.ruoyi.project.system.mapper.SysUserMapper;
-import com.ruoyi.quality.mapper.QualityTestStandardBindingMapper;
-import com.ruoyi.quality.mapper.QualityTestStandardMapper;
-import com.ruoyi.technology.mapper.TechnologyBomMapper;
-import com.ruoyi.technology.mapper.TechnologyBomStructureMapper;
-import com.ruoyi.technology.mapper.TechnologyOperationMapper;
-import com.ruoyi.technology.mapper.TechnologyRoutingMapper;
-import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper;
-import com.ruoyi.technology.pojo.TechnologyBom;
-import com.ruoyi.technology.pojo.TechnologyBomStructure;
-import com.ruoyi.technology.pojo.TechnologyRouting;
-import com.ruoyi.technology.pojo.TechnologyRoutingOperation;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
-
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-@Service
-@RequiredArgsConstructor
-public class DataCheckServiceImpl implements DataCheckService {
-
-    private final ProductMapper productMapper;
-    private final ProductModelMapper productModelMapper;
-    private final CustomerMapper customerMapper;
-    private final SupplierManageMapper supplierManageMapper;
-    private final ApprovalTemplateMapper approvalTemplateMapper;
-    private final QualityTestStandardMapper qualityTestStandardMapper;
-    private final QualityTestStandardBindingMapper qualityTestStandardBindingMapper;
-    private final TechnologyRoutingMapper technologyRoutingMapper;
-    private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
-    private final TechnologyOperationMapper technologyOperationMapper;
-    private final TechnologyBomMapper technologyBomMapper;
-    private final TechnologyBomStructureMapper technologyBomStructureMapper;
-    private final SysUserMapper sysUserMapper;
-
-    @Override
-    public DataCheckResult check(DataCheckRequest request) {
-        List<String> modules = request.getModules();
-        if (modules == null) {
-            modules = List.of();
-        }
-
-        Map<String, CheckItem> itemMap = new LinkedHashMap<>();
-
-        if (!modules.isEmpty()) {
-            addProductCheck(itemMap);
-            addUserChecks(itemMap);
-        }
-
-        for (String module : modules) {
-            switch (module) {
-                case "sales" -> addSalesChecks(itemMap);
-                case "purchase" -> addPurchaseChecks(itemMap);
-                case "quality" -> addQualityChecks(itemMap);
-                case "production" -> addProductionChecks(itemMap);
-            }
-        }
-
-        List<CheckItem> items = new ArrayList<>(itemMap.values());
-
-        DataCheckResult result = new DataCheckResult();
-        result.setItems(items);
-        result.setTotalItems(items.size());
-        result.setPassedItems((int) items.stream().filter(CheckItem::isPassed).count());
-        return result;
-    }
-
-    private void addProductCheck(Map<String, CheckItem> itemMap) {
-        String key = "common:浜у搧鏁版嵁";
-        if (itemMap.containsKey(key)) {
-            return;
-        }
-        long count = productMapper.selectCount(null);
-        itemMap.put(key, buildItem("common", "浜у搧鏁版嵁", 1, (int) count,
-                "缂哄皯浜у搧鏁版嵁锛岃鍏堝湪銆愬熀纭�鏁版嵁-浜у搧绠$悊銆戜腑娣诲姞鑷冲皯1鏉′骇鍝�"));
-    }
-
-    private void addUserChecks(Map<String, CheckItem> itemMap) {
-        // 1. 绯荤粺鐢ㄦ埛
-        String userKey = "common:绯荤粺鐢ㄦ埛";
-        if (!itemMap.containsKey(userKey)) {
-            List<SysUser> users = sysUserMapper.selectUserListWithDetail();
-            itemMap.put(userKey, buildItem("common", "绯荤粺鐢ㄦ埛", 1, (int) users.size(),
-                    "缂哄皯绯荤粺鐢ㄦ埛锛岃鍏堝湪銆愮郴缁熺鐞�-鐢ㄦ埛绠$悊銆戜腑娣诲姞鐢ㄦ埛"));
-        }
-
-        // 2. 鏈夎鑹茬殑鐢ㄦ埛
-        String userWithRoleKey = "common:鐢ㄦ埛瑙掕壊閰嶇疆";
-        if (!itemMap.containsKey(userWithRoleKey)) {
-            List<SysUser> users = sysUserMapper.selectUserListWithDetail();
-            long withRole = users.stream().filter(u -> u.getRoleNames() != null && !u.getRoleNames().isBlank()).count();
-            itemMap.put(userWithRoleKey, buildItem("common", "鐢ㄦ埛瑙掕壊閰嶇疆", 1, (int) withRole,
-                    "娌℃湁鐢ㄦ埛鍒嗛厤瑙掕壊锛岃鍏堝湪銆愮郴缁熺鐞�-鐢ㄦ埛绠$悊銆戜腑涓虹敤鎴峰垎閰嶈鑹�"));
-        }
-
-        // 3. 鏈夐儴闂ㄧ殑鐢ㄦ埛
-        String userWithDeptKey = "common:鐢ㄦ埛閮ㄩ棬閰嶇疆";
-        if (!itemMap.containsKey(userWithDeptKey)) {
-            List<SysUser> users = sysUserMapper.selectUserListWithDetail();
-            long withDept = users.stream().filter(u -> u.getDeptNames() != null && !u.getDeptNames().isBlank()).count();
-            itemMap.put(userWithDeptKey, buildItem("common", "鐢ㄦ埛閮ㄩ棬閰嶇疆", 1, (int) withDept,
-                    "娌℃湁鐢ㄦ埛鍒嗛厤閮ㄩ棬锛岃鍏堝湪銆愮郴缁熺鐞�-鐢ㄦ埛绠$悊銆戜腑涓虹敤鎴峰垎閰嶉儴闂�"));
-        }
-    }
-
-    private void addSalesChecks(Map<String, CheckItem> itemMap) {
-        String customerKey = "sales:瀹㈡埛鏁版嵁";
-        if (!itemMap.containsKey(customerKey)) {
-            long count = customerMapper.selectCount(null);
-            itemMap.put(customerKey, buildItem("sales", "瀹㈡埛鏁版嵁", 1, (int) count,
-                    "缂哄皯瀹㈡埛鏁版嵁锛岃鍏堝湪銆愬熀纭�鏁版嵁-瀹㈡埛绠$悊銆戜腑娣诲姞鑷冲皯1鏉″鎴�"));
-        }
-
-        String quotationKey = "sales:鎶ヤ环瀹℃壒妯℃澘";
-        if (!itemMap.containsKey(quotationKey)) {
-            long count = approvalTemplateMapper.selectCount(
-                    new LambdaQueryWrapper<ApprovalTemplate>()
-                            .eq(ApprovalTemplate::getBusinessType, TypeEnums.QUOTATION_APPROVAL.getCode()));
-            itemMap.put(quotationKey, buildItem("sales", "鎶ヤ环瀹℃壒妯℃澘", 1, (int) count,
-                    "缂哄皯鎶ヤ环瀹℃壒妯℃澘锛岃鍏堝湪銆愮郴缁熺鐞�-瀹℃壒妯℃澘銆戜腑鍒涘缓鎶ヤ环瀹℃壒妯℃澘"));
-        }
-
-        String shippingKey = "sales:鍙戣揣瀹℃壒妯℃澘";
-        if (!itemMap.containsKey(shippingKey)) {
-            long count = approvalTemplateMapper.selectCount(
-                    new LambdaQueryWrapper<ApprovalTemplate>()
-                            .eq(ApprovalTemplate::getBusinessType, TypeEnums.SHIPPING_APPROVAL.getCode()));
-            itemMap.put(shippingKey, buildItem("sales", "鍙戣揣瀹℃壒妯℃澘", 1, (int) count,
-                    "缂哄皯鍙戣揣瀹℃壒妯℃澘锛岃鍏堝湪銆愮郴缁熺鐞�-瀹℃壒妯℃澘銆戜腑鍒涘缓鍙戣揣瀹℃壒妯℃澘"));
-        }
-    }
-
-    private void addPurchaseChecks(Map<String, CheckItem> itemMap) {
-        String supplierKey = "purchase:渚涘簲鍟嗘暟鎹�";
-        if (!itemMap.containsKey(supplierKey)) {
-            long count = supplierManageMapper.selectCount(null);
-            itemMap.put(supplierKey, buildItem("purchase", "渚涘簲鍟嗘暟鎹�", 1, (int) count,
-                    "缂哄皯渚涘簲鍟嗘暟鎹紝璇峰厛鍦ㄣ�愬熀纭�鏁版嵁-渚涘簲鍟嗙鐞嗐�戜腑娣诲姞鑷冲皯1鏉′緵搴斿晢"));
-        }
-
-        String tplKey = "purchase:閲囪喘瀹℃壒妯℃澘";
-        if (!itemMap.containsKey(tplKey)) {
-            long count = approvalTemplateMapper.selectCount(
-                    new LambdaQueryWrapper<ApprovalTemplate>()
-                            .eq(ApprovalTemplate::getBusinessType, TypeEnums.PURCHASE_APPROVAL.getCode()));
-            itemMap.put(tplKey, buildItem("purchase", "閲囪喘瀹℃壒妯℃澘", 1, (int) count,
-                    "缂哄皯閲囪喘瀹℃壒妯℃澘锛岃鍏堝湪銆愮郴缁熺鐞�-瀹℃壒妯℃澘銆戜腑鍒涘缓閲囪喘瀹℃壒妯℃澘"));
-        }
-    }
-
-    private void addQualityChecks(Map<String, CheckItem> itemMap) {
-        String standardKey = "quality:妫�娴嬫爣鍑�";
-        if (!itemMap.containsKey(standardKey)) {
-            long count = qualityTestStandardMapper.selectCount(null);
-            itemMap.put(standardKey, buildItem("quality", "妫�娴嬫爣鍑�", 1, (int) count,
-                    "缂哄皯妫�娴嬫爣鍑嗭紝璇峰厛鍦ㄣ�愯川閲忕鐞�-妫�娴嬫爣鍑嗐�戜腑鍒涘缓妫�娴嬫爣鍑�"));
-        }
-
-        String bindingKey = "quality:鎸囨爣缁戝畾";
-        if (!itemMap.containsKey(bindingKey)) {
-            long count = qualityTestStandardBindingMapper.selectCount(null);
-            itemMap.put(bindingKey, buildItem("quality", "鎸囨爣缁戝畾", 1, (int) count,
-                    "缂哄皯鎸囨爣缁戝畾锛岃鍏堝湪銆愯川閲忕鐞�-妫�娴嬫爣鍑嗙粦瀹氥�戜腑灏嗘娴嬫爣鍑嗕笌浜у搧缁戝畾"));
-        }
-    }
-
-    private void addProductionChecks(Map<String, CheckItem> itemMap) {
-        // 1. 浜у搧瑙勬牸
-        String modelKey = "production:浜у搧瑙勬牸";
-        if (!itemMap.containsKey(modelKey)) {
-            long count = productModelMapper.selectCount(null);
-            itemMap.put(modelKey, buildItem("production", "浜у搧瑙勬牸", 1, (int) count,
-                    "缂哄皯浜у搧瑙勬牸锛岃鍏堝湪銆愬熀纭�鏁版嵁-浜у搧绠$悊銆戜腑涓轰骇鍝佹坊鍔犺鏍煎瀷鍙�"));
-        }
-
-        // 2. 宸ュ簭
-        String operationKey = "production:宸ュ簭";
-        if (!itemMap.containsKey(operationKey)) {
-            long count = technologyOperationMapper.selectCount(null);
-            itemMap.put(operationKey, buildItem("production", "宸ュ簭", 1, (int) count,
-                    "缂哄皯宸ュ簭锛岃鍏堝湪銆愬伐鑹鸿璁�-宸ュ簭绠$悊銆戜腑鍒涘缓宸ュ簭"));
-        }
-
-        // 3. BOM
-        String bomKey = "production:BOM";
-        if (!itemMap.containsKey(bomKey)) {
-            long count = technologyBomMapper.selectCount(null);
-            itemMap.put(bomKey, buildItem("production", "BOM", 1, (int) count,
-                    "缂哄皯BOM锛岃鍏堝湪銆愬伐鑹鸿璁�-BOM绠$悊銆戜腑鍒涘缓BOM"));
-        }
-
-        // 4. BOM浜у搧缁撴瀯
-        String bomStructureKey = "production:BOM浜у搧缁撴瀯";
-        if (!itemMap.containsKey(bomStructureKey)) {
-            long count = technologyBomStructureMapper.selectCount(null);
-            itemMap.put(bomStructureKey, buildItem("production", "BOM浜у搧缁撴瀯", 1, (int) count,
-                    "缂哄皯BOM浜у搧缁撴瀯锛岃鍏堝湪銆愬伐鑹鸿璁�-BOM绠$悊銆戜腑涓築OM娣诲姞浜у搧缁撴瀯鑺傜偣"));
-        }
-
-        // 5. 宸ヨ壓璺嚎
-        String routingKey = "production:宸ヨ壓璺嚎";
-        if (!itemMap.containsKey(routingKey)) {
-            long count = technologyRoutingMapper.selectCount(null);
-            itemMap.put(routingKey, buildItem("production", "宸ヨ壓璺嚎", 1, (int) count,
-                    "缂哄皯宸ヨ壓璺嚎锛岃鍏堝湪銆愬伐鑹鸿璁�-宸ヨ壓璺嚎銆戜腑鍒涘缓宸ヨ壓璺嚎"));
-        }
-
-        // 6. 宸ヨ壓璺嚎宸ュ簭
-        String routingOpKey = "production:宸ヨ壓璺嚎宸ュ簭";
-        if (!itemMap.containsKey(routingOpKey)) {
-            long count = technologyRoutingOperationMapper.selectCount(null);
-            itemMap.put(routingOpKey, buildItem("production", "宸ヨ壓璺嚎宸ュ簭", 1, (int) count,
-                    "缂哄皯宸ヨ壓璺嚎宸ュ簭锛岃鍏堝湪銆愬伐鑹鸿璁�-宸ヨ壓璺嚎銆戜腑涓哄伐鑹鸿矾绾挎坊鍔犲伐搴�"));
-        }
-
-        // 7. 鍏宠仈鎬ф娴嬶細鏈変骇鍝佽鏍间絾鏃犲伐鑹鸿矾绾跨殑
-        String linkageKey = "production:浜у搧-宸ヨ壓璺嚎鍏宠仈";
-        if (!itemMap.containsKey(linkageKey)) {
-            long modelCount = productModelMapper.selectCount(null);
-            long routedCount = technologyRoutingMapper.selectCount(
-                    new LambdaQueryWrapper<TechnologyRouting>()
-                            .isNotNull(TechnologyRouting::getProductModelId)
-                            .gt(TechnologyRouting::getProductModelId, 0));
-            itemMap.put(linkageKey, buildItem("production", "浜у搧-宸ヨ壓璺嚎鍏宠仈",
-                    (int) Math.min(modelCount, 1), (int) routedCount,
-                    "閮ㄥ垎浜у搧瑙勬牸鏈叧鑱斿伐鑹鸿矾绾匡紝璇峰厛鍦ㄣ�愬伐鑹鸿璁�-宸ヨ壓璺嚎銆戜腑涓轰骇鍝佽鏍煎垱寤哄伐鑹鸿矾绾�"));
-        }
-
-        // 8. 鍏宠仈鎬ф娴嬶細鏈夊伐鑹鸿矾绾夸絾鏃犲伐搴忕殑
-        String routingOpLinkKey = "production:宸ヨ壓璺嚎-宸ュ簭鍏宠仈";
-        if (!itemMap.containsKey(routingOpLinkKey)) {
-            long routingCount = technologyRoutingMapper.selectCount(null);
-            long routedOpCount = technologyRoutingOperationMapper.selectCount(
-                    new LambdaQueryWrapper<TechnologyRoutingOperation>()
-                            .gt(TechnologyRoutingOperation::getTechnologyRoutingId, 0));
-            itemMap.put(routingOpLinkKey, buildItem("production", "宸ヨ壓璺嚎-宸ュ簭鍏宠仈",
-                    (int) Math.min(routingCount, 1), (int) routedOpCount,
-                    "閮ㄥ垎宸ヨ壓璺嚎鏈坊鍔犲伐搴忥紝璇峰厛鍦ㄣ�愬伐鑹鸿璁�-宸ヨ壓璺嚎銆戜腑涓哄伐鑹鸿矾绾挎坊鍔犲伐搴�"));
-        }
-
-        // 9. 鍏宠仈鎬ф娴嬶細鏈塀OM浣嗘棤浜у搧缁撴瀯鐨�
-        String bomStructureLinkKey = "production:BOM-浜у搧缁撴瀯鍏宠仈";
-        if (!itemMap.containsKey(bomStructureLinkKey)) {
-            long bomCount = technologyBomMapper.selectCount(null);
-            long structureCount = technologyBomStructureMapper.selectCount(
-                    new LambdaQueryWrapper<TechnologyBomStructure>()
-                            .gt(TechnologyBomStructure::getBomId, 0));
-            itemMap.put(bomStructureLinkKey, buildItem("production", "BOM-浜у搧缁撴瀯鍏宠仈",
-                    (int) Math.min(bomCount, 1), (int) structureCount,
-                    "閮ㄥ垎BOM鏈坊鍔犱骇鍝佺粨鏋勶紝璇峰厛鍦ㄣ�愬伐鑹鸿璁�-BOM绠$悊銆戜腑涓築OM娣诲姞浜у搧缁撴瀯鑺傜偣"));
-        }
-    }
-
-    private CheckItem buildItem(String module, String itemName, int minRequired, int currentCount, String failMessage) {
-        CheckItem item = new CheckItem();
-        item.setModule(module);
-        item.setItemName(itemName);
-        item.setMinRequired(minRequired);
-        item.setCurrentCount(currentCount);
-        item.setPassed(currentCount >= minRequired);
-        item.setMessage(item.isPassed() ? "閫氳繃" : failMessage);
-        return item;
-    }
-}
diff --git a/src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java b/src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java
deleted file mode 100644
index 92b7cb8..0000000
--- a/src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java
+++ /dev/null
@@ -1,1745 +0,0 @@
-package com.ruoyi.mock.service.impl;
-
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONArray;
-import com.alibaba.fastjson2.JSONObject;
-import com.ruoyi.ai.assistant.Assistant;
-import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
-import com.ruoyi.approve.mapper.ApprovalInstanceNodeMapper;
-import com.ruoyi.approve.mapper.ApprovalRecordMapper;
-import com.ruoyi.approve.mapper.ApprovalTaskMapper;
-import com.ruoyi.approve.pojo.ApprovalInstance;
-import com.ruoyi.approve.pojo.ApprovalInstanceNode;
-import com.ruoyi.approve.pojo.ApprovalRecord;
-import com.ruoyi.approve.pojo.ApprovalTask;
-import com.ruoyi.approve.service.ApprovalInstanceService;
-import com.ruoyi.basic.mapper.ProductMapper;
-import com.ruoyi.basic.mapper.ProductModelMapper;
-import com.ruoyi.basic.pojo.Customer;
-import com.ruoyi.basic.pojo.Product;
-import com.ruoyi.basic.pojo.ProductModel;
-import com.ruoyi.basic.pojo.SupplierManage;
-import com.ruoyi.basic.service.ICustomerService;
-import com.ruoyi.basic.service.ISupplierService;
-import com.ruoyi.common.enums.ReviewStatusEnum;
-import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
-import com.ruoyi.common.utils.OrderUtils;
-import com.ruoyi.mock.dto.DataGenerateRequest;
-import com.ruoyi.mock.prompt.MockDataPrompt;
-import com.ruoyi.mock.service.DataGenerateService;
-import com.ruoyi.mock.vo.DataGenerateResult;
-import com.ruoyi.mock.vo.DataGenerateResult.ModuleSummary;
-import com.ruoyi.procurementrecord.utils.StockUtils;
-import com.ruoyi.production.bean.dto.ProductionOrderPickDto;
-import com.ruoyi.production.bean.dto.ProductionPlanDto;
-import com.ruoyi.production.bean.dto.ProductionProductMainDto;
-import com.ruoyi.production.bean.vo.ProductionBomStructureVo;
-import com.ruoyi.production.mapper.*;
-import com.ruoyi.production.pojo.*;
-import com.ruoyi.production.service.ProductionOrderPickService;
-import com.ruoyi.production.service.ProductionOrderService;
-import com.ruoyi.production.service.ProductionPlanService;
-import com.ruoyi.production.service.ProductionProductMainService;
-import com.ruoyi.purchase.dto.PurchaseLedgerDto;
-import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.purchase.service.IPurchaseLedgerService;
-import com.ruoyi.project.system.domain.SysDept;
-import com.ruoyi.project.system.domain.SysUser;
-import com.ruoyi.project.system.mapper.SysDeptMapper;
-import com.ruoyi.project.system.mapper.SysUserDeptMapper;
-import com.ruoyi.project.system.mapper.SysUserMapper;
-import com.ruoyi.quality.mapper.QualityInspectMapper;
-import com.ruoyi.quality.pojo.QualityInspect;
-import com.ruoyi.quality.pojo.QualityTestStandard;
-import com.ruoyi.quality.pojo.QualityTestStandardBinding;
-import com.ruoyi.quality.service.IQualityInspectService;
-import com.ruoyi.quality.service.IQualityTestStandardService;
-import com.ruoyi.quality.service.QualityTestStandardBindingService;
-import com.ruoyi.sales.dto.SalesLedgerDto;
-import com.ruoyi.sales.dto.ShippingInfoDto;
-import com.ruoyi.sales.mapper.SalesLedgerMapper;
-import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.mapper.ShippingInfoMapper;
-import com.ruoyi.sales.mapper.ShippingProductDetailMapper;
-import com.ruoyi.sales.pojo.SalesLedger;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import com.ruoyi.sales.pojo.ShippingInfo;
-import com.ruoyi.sales.pojo.ShippingProductDetail;
-import com.ruoyi.sales.service.ISalesLedgerService;
-import com.ruoyi.sales.service.ShippingInfoService;
-import com.ruoyi.stock.mapper.StockInRecordMapper;
-import com.ruoyi.stock.mapper.StockInventoryMapper;
-import com.ruoyi.stock.mapper.StockOutRecordMapper;
-import com.ruoyi.stock.pojo.StockInventory;
-import com.ruoyi.stock.pojo.StockOutRecord;
-import com.ruoyi.stock.dto.StockInventoryDto;
-import com.ruoyi.stock.service.StockInRecordService;
-import com.ruoyi.stock.service.StockOutRecordService;
-import com.ruoyi.stock.service.StockInventoryService;
-import com.ruoyi.technology.mapper.TechnologyBomStructureMapper;
-import com.ruoyi.technology.mapper.TechnologyRoutingMapper;
-import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.ChronoUnit;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.stream.Collectors;
-
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class DataGenerateServiceImpl implements DataGenerateService {
-
-    private final Assistant assistant;
-    private final ProductMapper productMapper;
-    private final ProductModelMapper productModelMapper;
-
-    private final ICustomerService customerService;
-    private final ISalesLedgerService salesLedgerService;
-    private final ISupplierService supplierService;
-    private final IPurchaseLedgerService purchaseLedgerService;
-    private final IQualityTestStandardService qualityTestStandardService;
-    private final QualityTestStandardBindingService qualityTestStandardBindingService;
-    private final ProductionPlanService productionPlanService;
-    private final ProductionOrderService productionOrderService;
-    private final StockInventoryService stockInventoryService;
-
-    // 閲囪喘瀹屾暣娴佺▼闇�瑕佺殑service
-    private final ApprovalInstanceService approvalInstanceService;
-    private final ApprovalInstanceMapper approvalInstanceMapper;
-    private final ApprovalInstanceNodeMapper approvalInstanceNodeMapper;
-    private final ApprovalTaskMapper approvalTaskMapper;
-    private final ApprovalRecordMapper approvalRecordMapper;
-    private final IQualityInspectService qualityInspectService;
-    private final QualityInspectMapper qualityInspectMapper;
-    private final StockInRecordService stockInRecordService;
-    private final StockInRecordMapper stockInRecordMapper;
-
-    // 閿�鍞畬鏁存祦绋嬮渶瑕佺殑service/mapper
-    private final SalesLedgerMapper salesLedgerMapper;
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-    private final ProductionPlanMapper productionPlanMapper;
-    private final ProductionOrderMapper productionOrderMapper;
-    private final ProductionOperationTaskMapper productionOperationTaskMapper;
-    private final ProductionProductMainService productionProductMainService;
-    private final ShippingInfoService shippingInfoService;
-    private final ShippingInfoMapper shippingInfoMapper;
-    private final ShippingProductDetailMapper shippingProductDetailMapper;
-    private final StockUtils stockUtils;
-    private final StockOutRecordMapper stockOutRecordMapper;
-    private final StockOutRecordService stockOutRecordService;
-    private final StockInventoryMapper stockInventoryMapper;
-
-    // 宸ヨ壓鏁版嵁妫�娴�
-    private final TechnologyRoutingMapper technologyRoutingMapper;
-    private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
-    private final TechnologyBomStructureMapper technologyBomStructureMapper;
-
-    // 棰嗘枡
-    private final ProductionOrderPickService productionOrderPickService;
-    private final ProductionOrderBomMapper productionOrderBomMapper;
-    private final ProductionBomStructureMapper productionBomStructureMapper;
-
-    // 鐢ㄦ埛/瑙掕壊鏌ヨ
-    private final SysUserMapper sysUserMapper;
-    private final SysDeptMapper sysDeptMapper;
-    private final SysUserDeptMapper sysUserDeptMapper;
-
-    @Override
-    public DataGenerateResult generate(DataGenerateRequest request) {
-        DataGenerateResult result = new DataGenerateResult();
-        List<ModuleSummary> summaries = new ArrayList<>();
-        List<String> errors = new ArrayList<>();
-        int totalGenerated = 0;
-
-        try {
-            // 鏋勫缓浜у搧瑙勬牸鍒嗙被锛氶�氳繃Product鏍戞牴鑺傜偣鍒ゆ柇鎴愬搧/鍘熸潗鏂�
-            Map<Long, String> productModelIdToCategory = buildProductModelCategoryMap();
-            List<Long> productModelIds = new ArrayList<>(productModelIdToCategory.keySet());
-
-            // 鍔犺浇宸叉湁瀹㈡埛/渚涘簲鍟嗭紙涓嶆柊澧烇紝浣跨敤宸叉湁鏁版嵁锛�
-            Map<String, Long> customerNameToId = loadExistingCustomers();
-            Map<String, Long> supplierNameToId = loadExistingSuppliers();
-            List<String> existingCustomerNames = new ArrayList<>(customerNameToId.keySet());
-            List<String> existingSupplierNames = new ArrayList<>(supplierNameToId.keySet());
-
-            // 鍔犺浇绯荤粺鐢ㄦ埛淇℃伅锛堟樀绉般�佽鑹层�侀儴闂級
-            List<SysUser> systemUsers = loadSystemUsersWithDetail();
-
-            String systemPrompt = MockDataPrompt.buildSystemPrompt();
-            String userMessage = MockDataPrompt.buildUserMessage(
-                    request.getModules(), request.getIndustries(),
-                    request.getCountMin(), request.getCountMax(),
-                    request.getDateStart(), request.getDateEnd(),
-                    request.getAdditionalInfo(),
-                    productModelIdToCategory,
-                    systemUsers,
-                    existingCustomerNames, existingSupplierNames);
-
-            String fullPrompt = systemPrompt + "\n\n" + userMessage;
-            log.info("璋冪敤AI鐢熸垚妯℃嫙鏁版嵁, modules={}, industries={}", request.getModules(), request.getIndustries());
-            String llmResponse = assistant.chat(fullPrompt);
-            log.info("AI杩斿洖鏁版嵁闀垮害: {}", llmResponse != null ? llmResponse.length() : 0);
-
-            if (llmResponse == null || llmResponse.isBlank()) {
-                result.setStatus("FAILED");
-                errors.add("AI鏈繑鍥炰换浣曟暟鎹�");
-                result.setErrors(errors);
-                return result;
-            }
-
-            List<JSONObject> entities = parseJsonResponse(llmResponse);
-            if (entities.isEmpty()) {
-                result.setStatus("FAILED");
-                errors.add("鏃犳硶瑙f瀽AI杩斿洖鐨勬暟鎹�");
-                result.setErrors(errors);
-                return result;
-            }
-
-            // 淇AI鐢熸垚鐨勬棩鏈熷埌鎸囧畾鏃堕棿鑼冨洿鍐�
-            String dateStart = request.getDateStart();
-            String dateEnd = request.getDateEnd();
-            if (dateStart != null && dateEnd != null) {
-                fixDatesInRange(entities, dateStart, dateEnd);
-            }
-
-            Map<String, List<JSONObject>> grouped = entities.stream()
-                    .collect(Collectors.groupingBy(e -> e.getString("entity")));
-
-            // Tier 0: 鍩虹鏁版嵁锛堝鎴峰拰渚涘簲鍟嗕笉鑷姩鐢熸垚锛屼娇鐢ㄥ凡鏈夋暟鎹級
-            if (grouped.containsKey("qualityTestStandard")) {
-                ModuleSummary s = createQualityStandards(grouped.get("qualityTestStandard"));
-                summaries.add(s);
-                totalGenerated += s.getSuccessCount();
-            }
-
-            // Tier 1: 涓氬姟鍗曟嵁
-            if (grouped.containsKey("salesLedger")) {
-                ModuleSummary s = createSalesLedgers(grouped.get("salesLedger"), customerNameToId, request.getDateStart());
-                summaries.add(s);
-                totalGenerated += s.getSuccessCount();
-            }
-            if (grouped.containsKey("purchaseLedger")) {
-                ModuleSummary s = createPurchaseLedgers(grouped.get("purchaseLedger"), supplierNameToId,
-                        request.getAdditionalInfo(), request.getDateStart(), request.getDateEnd());
-                summaries.add(s);
-                totalGenerated += s.getSuccessCount();
-            }
-            if (grouped.containsKey("productionPlan")) {
-                ModuleSummary s = createProductionPlans(grouped.get("productionPlan"));
-                summaries.add(s);
-                totalGenerated += s.getSuccessCount();
-            }
-
-            // Tier 2
-            if (grouped.containsKey("productionOrder")) {
-                ModuleSummary s = createProductionOrders(grouped.get("productionOrder"));
-                summaries.add(s);
-                totalGenerated += s.getSuccessCount();
-            }
-            if (grouped.containsKey("qualityTestStandardBinding")) {
-                ModuleSummary s = createQualityBindings(grouped.get("qualityTestStandardBinding"));
-                summaries.add(s);
-                totalGenerated += s.getSuccessCount();
-            }
-            if (grouped.containsKey("stockInventory")) {
-                ModuleSummary s = createStockInventories(grouped.get("stockInventory"));
-                summaries.add(s);
-                totalGenerated += s.getSuccessCount();
-            }
-
-            result.setStatus(errors.isEmpty() ? "SUCCESS" : "PARTIAL");
-            result.setTotalGenerated(totalGenerated);
-            result.setModuleSummaries(summaries);
-            result.setErrors(errors);
-
-        } catch (Exception e) {
-            log.error("鏁版嵁鐢熸垚澶辫触", e);
-            result.setStatus("FAILED");
-            errors.add("鏁版嵁鐢熸垚寮傚父: " + e.getMessage());
-            result.setErrors(errors);
-        }
-
-        return result;
-    }
-
-    private List<JSONObject> parseJsonResponse(String response) {
-        try {
-            String trimmed = response.trim();
-            if (trimmed.startsWith("```")) {
-                int start = trimmed.indexOf("\n");
-                int end = trimmed.lastIndexOf("```");
-                if (start > 0 && end > start) {
-                    trimmed = trimmed.substring(start + 1, end).trim();
-                }
-            }
-            return JSON.parseArray(trimmed, JSONObject.class);
-        } catch (Exception e) {
-            log.warn("JSON瑙f瀽澶辫触锛屽皾璇曟彁鍙栨暟缁勭墖娈�: {}", e.getMessage());
-            int start = response.indexOf('[');
-            int end = response.lastIndexOf(']');
-            if (start >= 0 && end > start) {
-                return JSON.parseArray(response.substring(start, end + 1), JSONObject.class);
-            }
-            return List.of();
-        }
-    }
-
-    /**
-     * 淇AI鐢熸垚鐨勬棩鏈熷埌鎸囧畾鏃堕棿鑼冨洿鍐呫��
-     * 閬嶅巻鎵�鏈夊疄浣撶殑鎵�鏈夊瓧娈碉紝濡傛灉鍙戠幇鏃ユ湡瀛楃涓诧紙yyyy-MM-dd鏍煎紡锛夎秴鍑鸿寖鍥达紝鏇挎崲涓鸿寖鍥村唴鐨勯殢鏈烘棩鏈熴��
-     */
-    private void fixDatesInRange(List<JSONObject> entities, String dateStart, String dateEnd) {
-        LocalDate start;
-        LocalDate end;
-        try {
-            start = LocalDate.parse(dateStart);
-            end = LocalDate.parse(dateEnd);
-        } catch (Exception e) {
-            log.warn("鏃ユ湡鑼冨洿瑙f瀽澶辫触: {} ~ {}", dateStart, dateEnd);
-            return;
-        }
-        long daysBetween = ChronoUnit.DAYS.between(start, end);
-        if (daysBetween <= 0) {
-            daysBetween = 1;
-        }
-
-        // 鎵�鏈夊凡鐭ョ殑鏃ユ湡瀛楁鍚�
-        java.util.Set<String> dateFields = java.util.Set.of(
-                "entryDate", "executionDate", "deliveryDate", "requiredDate",
-                "promisedDeliveryDate", "planCompleteTime", "maintenanceTime",
-                "checkTime", "registerDate"
-        );
-
-        for (JSONObject entity : entities) {
-            for (String key : dateFields) {
-                String val = entity.getString(key);
-                if (val != null && val.matches("\\d{4}-\\d{2}-\\d{2}")) {
-                    try {
-                        LocalDate d = LocalDate.parse(val);
-                        if (d.isBefore(start) || d.isAfter(end)) {
-                            LocalDate fixed = start.plusDays(ThreadLocalRandom.current().nextLong(daysBetween + 1));
-                            entity.put(key, fixed.toString());
-                            log.debug("淇鏃ユ湡 {}: {} -> {}", key, val, fixed);
-                        }
-                    } catch (Exception ignored) {
-                    }
-                } else if (val != null && !val.matches("\\d{4}-\\d{2}-\\d{2}")) {
-                    // AI杩斿洖浜嗘棤鏁堟棩鏈熸牸寮忥紝鐩存帴鏇挎崲涓鸿寖鍥村唴鐨勯殢鏈烘棩鏈�
-                    LocalDate fixed = start.plusDays(ThreadLocalRandom.current().nextLong(daysBetween + 1));
-                    entity.put(key, fixed.toString());
-                    log.debug("淇鏃犳晥鏃ユ湡 {}: {} -> {}", key, val, fixed);
-                }
-            }
-            // 淇鍚堝悓缂栧彿涓殑鏃ユ湡: CG-20230601-001 -> CG-YYYYMMDD-001
-            for (String key : java.util.Set.of("purchaseContractNumber", "salesContractNo", "standardNo", "batchNo")) {
-                String val = entity.getString(key);
-                if (val != null && val.matches(".*\\d{8}.*")) {
-                    String datePart = val.replaceAll(".*?(\\d{8}).*", "$1");
-                    try {
-                        // 楠岃瘉鎻愬彇鍒扮殑鏄湁鏁堟棩鏈�
-                        String dateStr = datePart.substring(0, 4) + "-" + datePart.substring(4, 6) + "-" + datePart.substring(6, 8);
-                        LocalDate d = LocalDate.parse(dateStr);
-                        if (d.isBefore(start) || d.isAfter(end)) {
-                            LocalDate fixed = start.plusDays(ThreadLocalRandom.current().nextLong(daysBetween + 1));
-                            String newDatePart = fixed.format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE);
-                            String newVal = val.replace(datePart, newDatePart);
-                            entity.put(key, newVal);
-                            log.debug("淇缂栧彿 {}: {} -> {}", key, val, newVal);
-                        }
-                    } catch (Exception ignored) {
-                    }
-                }
-            }
-        }
-    }
-
-    // ---- Tier 0: 鍩虹鏁版嵁 ----
-
-    /**
-     * 浠庢暟鎹簱鍔犺浇宸叉湁瀹㈡埛鍚嶇О鈫扞D鏄犲皠
-     */
-    private Map<String, Long> loadExistingCustomers() {
-        Map<String, Long> map = new HashMap<>();
-        List<Customer> customers = customerService.list();
-        for (Customer c : customers) {
-            if (c.getCustomerName() != null) {
-                map.put(c.getCustomerName(), c.getId());
-            }
-        }
-        return map;
-    }
-
-    /**
-     * 浠庢暟鎹簱鍔犺浇宸叉湁渚涘簲鍟嗗悕绉扳啋ID鏄犲皠
-     */
-    private Map<String, Long> loadExistingSuppliers() {
-        Map<String, Long> map = new HashMap<>();
-        List<SupplierManage> suppliers = supplierService.list();
-        for (SupplierManage s : suppliers) {
-            if (s.getSupplierName() != null) {
-                map.put(s.getSupplierName(), s.getId());
-            }
-        }
-        return map;
-    }
-
-    /**
-     * 鍔犺浇绯荤粺鐢ㄦ埛淇℃伅锛堝惈瑙掕壊鍜岄儴闂ㄥ悕绉帮級
-     */
-    private List<SysUser> loadSystemUsersWithDetail() {
-        return sysUserMapper.selectUserListWithDetail();
-    }
-
-    /**
-     * 鏋勫缓浜у搧瑙勬牸ID鈫掗《绾т骇鍝佸垎绫诲悕绉扮殑鏄犲皠
-     * 閫氳繃Product鏍戝悜涓婃壘鍒版牴鑺傜偣锛屽垽鏂�"鎴愬搧"/"鍘熸潗鏂�"/"鍗婃垚鍝�"
-     */
-    private Map<Long, String> buildProductModelCategoryMap() {
-        // 鍔犺浇鎵�鏈塒roduct鑺傜偣
-        List<Product> allProducts = productMapper.selectList(null);
-        Map<Long, Product> productMap = allProducts.stream()
-                .collect(Collectors.toMap(Product::getId, p -> p, (a, b) -> a));
-
-        // 瀵规瘡涓狿roduct锛屾部parentId鍚戜笂鎵惧埌鏍硅妭鐐瑰悕绉�
-        Map<Long, String> productIdToRootName = new HashMap<>();
-        for (Product p : allProducts) {
-            if (productIdToRootName.containsKey(p.getId())) continue;
-            // 鍚戜笂閬嶅巻鎵炬牴
-            List<Long> chain = new ArrayList<>();
-            Long currentId = p.getId();
-            while (currentId != null) {
-                chain.add(currentId);
-                Product current = productMap.get(currentId);
-                if (current == null || current.getParentId() == null) break;
-                currentId = current.getParentId();
-            }
-            // 鏍硅妭鐐圭殑productName灏辨槸鍒嗙被鍚�
-            Product root = productMap.get(chain.get(chain.size() - 1));
-            String rootName = root != null ? root.getProductName() : "鍏朵粬";
-            for (Long id : chain) {
-                productIdToRootName.put(id, rootName);
-            }
-        }
-
-        // 瀵规瘡涓狿roductModel锛岄�氳繃productId鎵惧埌鍏舵墍灞炲垎绫�
-        List<ProductModel> allModels = productModelMapper.selectList(null);
-        Map<Long, String> result = new HashMap<>();
-        for (ProductModel m : allModels) {
-            String category = m.getProductId() != null
-                    ? productIdToRootName.getOrDefault(m.getProductId(), "鍏朵粬")
-                    : "鍏朵粬";
-            result.put(m.getId(), category);
-        }
-        return result;
-    }
-
-    private ModuleSummary createCustomers(List<JSONObject> items, Map<String, Long> nameToId) {
-        int success = 0, fail = 0;
-        for (JSONObject item : items) {
-            try {
-                Customer c = new Customer();
-                c.setCustomerName(item.getString("customerName"));
-                c.setCustomerType(item.getString("customerType"));
-                c.setContactPerson(item.getString("contactPerson"));
-                c.setContactPhone(item.getString("contactPhone"));
-                c.setCompanyAddress(item.getString("companyAddress"));
-                c.setCompanyPhone(item.getString("companyPhone"));
-                c.setTaxpayerIdentificationNumber(item.getString("taxpayerIdentificationNumber"));
-                c.setMaintainer(item.getString("maintainer"));
-                if (item.containsKey("maintenanceTime")) {
-                    String mtStr = item.getString("maintenanceTime");
-                    if (mtStr != null && mtStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
-                        c.setMaintenanceTime(java.sql.Date.valueOf(mtStr));
-                    }
-                } else {
-                    c.setMaintenanceTime(new java.sql.Date(System.currentTimeMillis()));
-                }
-                if (item.containsKey("bankAccount")) {
-                    c.setBankAccount(item.getString("bankAccount"));
-                }
-                if (item.containsKey("basicBankAccount")) {
-                    c.setBasicBankAccount(item.getString("basicBankAccount"));
-                }
-                if (item.containsKey("bankCode")) {
-                    c.setBankCode(item.getString("bankCode"));
-                }
-                customerService.insertCustomer(c);
-                if (c.getId() != null) {
-                    nameToId.put(c.getCustomerName(), c.getId());
-                }
-                success++;
-            } catch (Exception e) {
-                log.warn("鍒涘缓瀹㈡埛澶辫触: {}", e.getMessage());
-                fail++;
-            }
-        }
-        return summary("sales", "瀹㈡埛", items.size(), success, fail);
-    }
-
-    private ModuleSummary createSuppliers(List<JSONObject> items, Map<String, Long> nameToId) {
-        int success = 0, fail = 0;
-        for (JSONObject item : items) {
-            try {
-                SupplierManage s = new SupplierManage();
-                s.setSupplierName(item.getString("supplierName"));
-                s.setSupplierType(item.getString("supplierType"));
-                s.setContactUserName(item.getString("contactUserName"));
-                s.setContactUserPhone(item.getString("contactUserPhone"));
-                s.setCompanyAddress(item.getString("companyAddress"));
-                s.setCompanyPhone(item.getString("companyPhone"));
-                s.setTaxpayerIdentificationNum(item.getString("taxpayerIdentificationNum"));
-                s.setBankAccountName(item.getString("bankAccountName"));
-                s.setBankAccountNum(item.getString("bankAccountNum"));
-                if (item.containsKey("isWhite")) {
-                    s.setIsWhite(item.getInteger("isWhite"));
-                }
-                supplierService.saveSupplier(s);
-                if (s.getId() != null) {
-                    nameToId.put(s.getSupplierName(), s.getId());
-                }
-                success++;
-            } catch (Exception e) {
-                log.warn("鍒涘缓渚涘簲鍟嗗け璐�: {}", e.getMessage());
-                fail++;
-            }
-        }
-        return summary("purchase", "渚涘簲鍟�", items.size(), success, fail);
-    }
-
-    private ModuleSummary createQualityStandards(List<JSONObject> items) {
-        int success = 0, fail = 0;
-        for (JSONObject item : items) {
-            try {
-                QualityTestStandard std = new QualityTestStandard();
-                std.setStandardNo(item.getString("standardNo"));
-                std.setStandardName(item.getString("standardName"));
-                std.setInspectType(item.getInteger("inspectType"));
-                std.setRemark(item.getString("remark"));
-                qualityTestStandardService.save(std);
-                success++;
-            } catch (Exception e) {
-                log.warn("鍒涘缓妫�娴嬫爣鍑嗗け璐�: {}", e.getMessage());
-                fail++;
-            }
-        }
-        return summary("quality", "妫�娴嬫爣鍑�", items.size(), success, fail);
-    }
-
-    // ---- Tier 1: 涓氬姟鍗曟嵁 ----
-
-    private ModuleSummary createSalesLedgers(List<JSONObject> items, Map<String, Long> customerNameToId, String dateStart) {
-        int success = 0, fail = 0;
-        for (JSONObject item : items) {
-            try {
-                String customerName = item.getString("customerName");
-                Long customerId = customerNameToId.get(customerName);
-
-                SalesLedgerDto dto = new SalesLedgerDto();
-                dto.setCustomerId(customerId);
-                dto.setCustomerName(customerName);
-                dto.setProjectName(item.getString("projectName"));
-                dto.setSalesman(item.getString("salesman"));
-                dto.setPaymentMethod(item.getString("paymentMethod"));
-                dto.setType(item.getInteger("type"));
-
-                // 褰曞叆浜猴細浼樺厛鐢ˋI杩斿洖鐨勶紝鍚﹀垯浠�"閿�鍞�"瑙掕壊/閮ㄩ棬闅忔満閫�
-                String entryPerson = item.getString("entryPerson");
-                if (entryPerson == null || entryPerson.isBlank()) {
-                    SysUser salesUser = randomUserByKeyword("閿�鍞�");
-                    entryPerson = salesUser != null ? salesUser.getNickName() : "绯荤粺";
-                }
-                dto.setEntryPerson(entryPerson);
-
-                // 涓氬姟鍛橈細浼樺厛鐢ˋI杩斿洖鐨勶紝鍚﹀垯浠�"閿�鍞�"瑙掕壊/閮ㄩ棬闅忔満閫�
-                String salesman = dto.getSalesman();
-                if (salesman == null || salesman.isBlank()) {
-                    SysUser salesUser = randomUserByKeyword("閿�鍞�");
-                    salesman = salesUser != null ? salesUser.getNickName() : "绯荤粺";
-                    dto.setSalesman(salesman);
-                }
-                // customerId涓簄ull浼氬鑷�"瀹㈡埛涓嶅瓨鍦�"寮傚父锛岃烦杩�
-                if (customerId == null) {
-                    log.warn("璺宠繃閿�鍞彴璐︼紝瀹㈡埛[{}]涓嶅瓨鍦�", customerName);
-                    fail++;
-                    continue;
-                }
-                LocalDate entryDate = null;
-                if (item.containsKey("entryDate")) {
-                    String entryDateStr = item.getString("entryDate");
-                    if (entryDateStr != null && entryDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
-                        entryDate = LocalDate.parse(entryDateStr);
-                        dto.setEntryDate(java.sql.Date.valueOf(entryDateStr));
-                    } else {
-                        dto.setEntryDate(java.sql.Date.valueOf(dateStart));
-                    }
-                }
-                if (item.containsKey("executionDate")) {
-                    String execDateStr = item.getString("executionDate");
-                    if (execDateStr != null && execDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
-                        dto.setExecutionDate(LocalDate.parse(execDateStr));
-                    } else {
-                        dto.setExecutionDate(LocalDate.parse(dateStart));
-                    }
-                }
-                if (item.containsKey("deliveryDate")) {
-                    String delDateStr = item.getString("deliveryDate");
-                    if (delDateStr != null && delDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
-                        dto.setDeliveryDate(LocalDate.parse(delDateStr));
-                    } else {
-                        dto.setDeliveryDate(LocalDate.parse(dateStart));
-                    }
-                }
-                JSONArray productData = item.getJSONArray("productData");
-                boolean hasProduction = false;
-                if (productData != null) {
-                    List<SalesLedgerProduct> products = new ArrayList<>();
-                    for (int i = 0; i < productData.size(); i++) {
-                        JSONObject pd = productData.getJSONObject(i);
-                        SalesLedgerProduct slp = new SalesLedgerProduct();
-                        slp.setProductId(pd.getLong("productId"));
-                        slp.setProductModelId(pd.getLong("productModelId"));
-                        slp.setQuantity(pd.getBigDecimal("quantity"));
-                        slp.setTaxInclusiveUnitPrice(pd.getBigDecimal("taxInclusiveUnitPrice"));
-                        slp.setTaxInclusiveTotalPrice(pd.getBigDecimal("taxInclusiveTotalPrice"));
-                        slp.setTaxRate(pd.getBigDecimal("taxRate"));
-                        slp.setUnit(pd.getString("unit"));
-                        slp.setType(pd.getInteger("type"));
-                        if (pd.containsKey("taxExclusiveTotalPrice")) {
-                            slp.setTaxExclusiveTotalPrice(pd.getBigDecimal("taxExclusiveTotalPrice"));
-                        } else if (pd.getBigDecimal("taxInclusiveTotalPrice") != null && pd.getBigDecimal("taxRate") != null) {
-                            slp.setTaxExclusiveTotalPrice(
-                                pd.getBigDecimal("taxInclusiveTotalPrice").divide(
-                                    BigDecimal.ONE.add(pd.getBigDecimal("taxRate").divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP)),
-                                    2, RoundingMode.HALF_UP));
-                        } else {
-                            slp.setTaxExclusiveTotalPrice(BigDecimal.ZERO);
-                        }
-                        slp.setIsProduction(true);
-                        products.add(slp);
-                        hasProduction = true;
-                    }
-                    dto.setProductData(products);
-                }
-                salesLedgerService.addOrUpdateSalesLedger(dto);
-                // addOrUpdateSalesLedger鍐呴儴浼氳嚜鍔ㄧ敓鎴愬悎鍚屽彿骞秈nsert锛屼絾dto涓婃病鏈夊洖鍐�
-                // 鐩存帴鐢╠to鐨別ntryDate鍜宑ustomerId鏌ユ渶鏂板垱寤虹殑璁板綍
-                SalesLedger savedLedger = salesLedgerMapper.selectOne(
-                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SalesLedger>()
-                                .eq(SalesLedger::getCustomerId, dto.getCustomerId())
-                                .orderByDesc(SalesLedger::getId)
-                                .last("limit 1"));
-                if (savedLedger != null && hasProduction) {
-                    processSalesFullFlow(savedLedger, entryDate);
-                }
-                success++;
-            } catch (Exception e) {
-                log.warn("鍒涘缓閿�鍞彴璐﹀け璐�: {}", e.getMessage(), e);
-                fail++;
-            }
-        }
-        return summary("sales", "閿�鍞彴璐�", items.size(), success, fail);
-    }
-
-    // ==================== 閿�鍞畬鏁存祦绋� ====================
-
-    /**
-     * 閿�鍞畬鏁存祦绋�: 鐢熶骇璁″垝鍚堝苟涓嬪彂 鈫� 棰嗘枡 鈫� 鎶ュ伐 鈫� 璐ㄦ(鍙��) 鈫� 鍏ュ簱 鈫� 鍙戣揣 鈫� 鍑哄簱
-     * 鏃堕棿浠ラ攢鍞綍鍏ユ棩鏈熶负鍩哄噯锛屽悇鐜妭閫掓帹0-3澶�
-     */
-    private void processSalesFullFlow(SalesLedger salesLedger, LocalDate entryDate) {
-        try {
-            LocalDate baseDate = entryDate != null ? entryDate : LocalDate.now();
-
-            // 1. 鏌ヨ閿�鍞彴璐︿骇鍝侊紙鍚敓浜ц鍒掞級
-            List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SalesLedgerProduct>()
-                            .eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId())
-                            .eq(SalesLedgerProduct::getIsProduction, true));
-            if (products.isEmpty()) {
-                log.info("閿�鍞彴璐{}]鏃犻渶鐢熶骇锛岃烦杩囩敓浜ф祦绋�", salesLedger.getSalesContractNo());
-                return;
-            }
-
-            // 妫�鏌ヤ骇鍝佹槸鍚﹀叿澶囧畬鏁寸殑宸ヨ壓鏁版嵁锛堝伐鑹鸿矾绾裤�佸伐搴忋�丅OM锛�
-            List<Long> missingTechProductIds = checkTechnologyDataReadiness(products);
-            if (!missingTechProductIds.isEmpty()) {
-                log.warn("閿�鍞彴璐{}]浠ヤ笅浜у搧缂哄皯宸ヨ壓鏁版嵁锛堝伐鑹鸿矾绾�/宸ュ簭/BOM锛夛紝璺宠繃鐢熶骇娴佺▼: {}",
-                        salesLedger.getSalesContractNo(), missingTechProductIds);
-                return;
-            }
-
-            // 2. 鐢熶骇璁″垝鍚堝苟涓嬪彂 鈫� 鐢熶骇璁㈠崟
-            LocalDate planDate = baseDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
-            processProductionCombine(salesLedger, planDate);
-
-            // 3. 棰嗘枡锛堢墿鏂欎笉瓒宠嚜鍔ㄥ叆搴撳悗鍐嶉锛�
-            LocalDate pickDate = planDate.plusDays(ThreadLocalRandom.current().nextInt(0, 3));
-            processMaterialPick(salesLedger, pickDate);
-
-            // 4. 鐢熶骇鎶ュ伐
-            LocalDate reportDate = pickDate.plusDays(ThreadLocalRandom.current().nextInt(1, 4));
-            processProductionReport(salesLedger, reportDate);
-
-            // 5. 璐ㄦ鎻愪氦 + 鍏ュ簱瀹℃壒
-            LocalDate qualityDate = reportDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
-            processSalesQualityAndStockIn(salesLedger, qualityDate);
-
-            // 6. 鍙戣揣 + 鍙戣揣瀹℃壒 + 鍑哄簱瀹℃壒
-            LocalDate shipDate = qualityDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
-            processSalesShipping(salesLedger, shipDate);
-
-            log.info("閿�鍞彴璐{}]瀹屾暣娴佺▼澶勭悊瀹屾瘯", salesLedger.getSalesContractNo());
-        } catch (Exception e) {
-            log.warn("閿�鍞畬鏁存祦绋嬪鐞嗗け璐{}]: {}", salesLedger.getSalesContractNo(), e.getMessage());
-        }
-    }
-
-    /**
-     * 鏌ヨ瑙掕壊鎴栭儴闂ㄥ惈鎸囧畾鍏抽敭瀛楃殑鐢ㄦ埛锛岄殢鏈鸿繑鍥炰竴涓�
-     */
-    private SysUser randomUserByKeyword(String keyword) {
-        try {
-            List<Long> userIds = new ArrayList<>(sysUserMapper.getUserByRole(keyword));
-
-            List<SysDept> depts = sysDeptMapper.selectList(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SysDept>()
-                            .like(SysDept::getDeptName, keyword)
-                            .eq(SysDept::getDelFlag, "0")
-                            .eq(SysDept::getStatus, "0"));
-            if (!depts.isEmpty()) {
-                List<Long> deptIds = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
-                List<Long> deptUserIds = sysUserDeptMapper.selectDistinctUserIdsByDeptIds(deptIds);
-                userIds.addAll(deptUserIds);
-            }
-
-            if (userIds.isEmpty()) {
-                return null;
-            }
-            List<Long> distinctIds = userIds.stream().distinct().collect(Collectors.toList());
-            Long randomId = distinctIds.get(ThreadLocalRandom.current().nextInt(distinctIds.size()));
-            return sysUserMapper.selectUserById(randomId);
-        } catch (Exception e) {
-            log.warn("鏌ヨ[{}]瑙掕壊/閮ㄩ棬鐢ㄦ埛澶辫触: {}", keyword, e.getMessage());
-            return null;
-        }
-    }
-
-    /**
-     * 鏌ヨ瑙掕壊鎴栭儴闂ㄥ惈"鐢熶骇"鐨勭敤鎴凤紝闅忔満杩斿洖涓�涓�
-     */
-    private SysUser randomProductionUser() {
-        return randomUserByKeyword("鐢熶骇");
-    }
-
-    /**
-     * 妫�鏌ヤ骇鍝佹槸鍚﹀叿澶囧畬鏁寸殑宸ヨ壓鏁版嵁锛堝伐鑹鸿矾绾裤�佸伐搴忋�丅OM锛�
-     * @return 缂哄皯宸ヨ壓鏁版嵁鐨勪骇鍝佽鏍糏D鍒楄〃锛堢┖鍒楄〃琛ㄧず鍏ㄩ儴灏辩华锛�
-     */
-    private List<Long> checkTechnologyDataReadiness(List<SalesLedgerProduct> products) {
-        List<Long> missingIds = new ArrayList<>();
-        for (SalesLedgerProduct slp : products) {
-            Long productModelId = slp.getProductModelId();
-            if (productModelId == null) continue;
-
-            // 1. 妫�鏌ュ伐鑹鸿矾绾�
-            List<com.ruoyi.technology.pojo.TechnologyRouting> routings =
-                    technologyRoutingMapper.selectList(
-                            new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.technology.pojo.TechnologyRouting>()
-                                    .eq(com.ruoyi.technology.pojo.TechnologyRouting::getProductModelId, productModelId));
-            if (routings.isEmpty()) {
-                log.warn("浜у搧瑙勬牸[{}]缂哄皯宸ヨ壓璺嚎", productModelId);
-                missingIds.add(productModelId);
-                continue;
-            }
-            Long routingId = routings.get(0).getId();
-
-            // 2. 妫�鏌ュ伐鑹鸿矾绾挎槸鍚︽湁鍏宠仈宸ュ簭
-            List<com.ruoyi.technology.pojo.TechnologyRoutingOperation> routingOps =
-                    technologyRoutingOperationMapper.selectList(
-                            new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.technology.pojo.TechnologyRoutingOperation>()
-                                    .eq(com.ruoyi.technology.pojo.TechnologyRoutingOperation::getTechnologyRoutingId, routingId));
-            if (routingOps.isEmpty()) {
-                log.warn("浜у搧瑙勬牸[{}]宸ヨ壓璺嚎[{}]缂哄皯宸ュ簭", productModelId, routingId);
-                missingIds.add(productModelId);
-                continue;
-            }
-
-            // 3. 妫�鏌OM锛堝彲閫変絾鏈夋洿濂斤級
-            com.ruoyi.technology.pojo.TechnologyRouting routing = routings.get(0);
-            if (routing.getBomId() != null) {
-                List<com.ruoyi.technology.pojo.TechnologyBomStructure> bomStructures =
-                        technologyBomStructureMapper.selectList(
-                                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.technology.pojo.TechnologyBomStructure>()
-                                        .eq(com.ruoyi.technology.pojo.TechnologyBomStructure::getBomId, routing.getBomId()));
-                if (bomStructures.isEmpty()) {
-                    log.warn("浜у搧瑙勬牸[{}]BOM[{}]缂哄皯浜у搧缁撴瀯", productModelId, routing.getBomId());
-                    missingIds.add(productModelId);
-                }
-            }
-        }
-        return missingIds;
-    }
-
-    /**
-     * 鐢熶骇璁″垝鍚堝苟涓嬪彂 鈫� 鐢熶骇璁㈠崟锛堟寜productModelId鍒嗙粍锛屽悓鍨嬪彿鍚堝苟涓嬪彂锛�
-     */
-    private void processProductionCombine(SalesLedger salesLedger, LocalDate planDate) {
-        try {
-            List<ProductionPlan> plans = productionPlanMapper.selectList(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionPlan>()
-                            .eq(ProductionPlan::getSalesLedgerId, salesLedger.getId())
-                            .and(w -> w.eq(ProductionPlan::getStatus, 0).or().isNull(ProductionPlan::getStatus)));
-            if (plans.isEmpty()) {
-                log.info("閿�鍞彴璐{}]鏃犲緟涓嬪彂鐢熶骇璁″垝", salesLedger.getSalesContractNo());
-                return;
-            }
-
-            // 鎸塸roductModelId鍒嗙粍锛屽悓鍨嬪彿鎵嶈兘鍚堝苟涓嬪彂锛沺roductModelId涓簄ull鐨勫崟鐙�愪釜涓嬪彂
-            Map<Long, List<ProductionPlan>> grouped = plans.stream()
-                    .filter(p -> p.getProductModelId() != null)
-                    .collect(Collectors.groupingBy(ProductionPlan::getProductModelId));
-
-            for (Map.Entry<Long, List<ProductionPlan>> entry : grouped.entrySet()) {
-                try {
-                    List<ProductionPlan> sameModelPlans = entry.getValue();
-                    BigDecimal totalQty = sameModelPlans.stream()
-                            .map(p -> Optional.ofNullable(p.getQtyRequired()).orElse(BigDecimal.ZERO))
-                            .reduce(BigDecimal.ZERO, BigDecimal::add);
-                    ProductionPlanDto combineDto = new ProductionPlanDto();
-                    combineDto.setIds(sameModelPlans.stream().map(ProductionPlan::getId).collect(Collectors.toList()));
-                    combineDto.setTotalAssignedQuantity(totalQty);
-                    combineDto.setPlanCompleteTime(planDate.plusDays(ThreadLocalRandom.current().nextInt(3, 7)));
-                    productionPlanService.combine(combineDto);
-
-                    // 淇鐢熶骇璁㈠崟鐨刾lanCompleteTime
-                    List<ProductionOrder> orders = productionOrderMapper.selectList(
-                            new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionOrder>()
-                                    .like(ProductionOrder::getProductionPlanIds, String.valueOf(sameModelPlans.get(0).getId())));
-                    for (ProductionOrder order : orders) {
-                        order.setPlanCompleteTime(planDate.plusDays(ThreadLocalRandom.current().nextInt(3, 7)));
-                        order.setStartTime(planDate.atStartOfDay());
-                        productionOrderMapper.updateById(order);
-                    }
-                    log.info("閿�鍞彴璐{}]鐢熶骇璁″垝涓嬪彂鎴愬姛, productModelId={}, 璁″垝鏁�: {}",
-                            salesLedger.getSalesContractNo(), entry.getKey(), sameModelPlans.size());
-                } catch (Exception e) {
-                    log.warn("閿�鍞彴璐{}]鐢熶骇璁″垝涓嬪彂澶辫触, productModelId={}: {}",
-                            salesLedger.getSalesContractNo(), entry.getKey(), e.getMessage());
-                }
-            }
-        } catch (Exception e) {
-            log.warn("鐢熶骇璁″垝涓嬪彂澶辫触[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage());
-        }
-    }
-
-    /**
-     * 棰嗘枡: 鏌ヨ鐢熶骇璁㈠崟鐨凚OM棰嗘枡娓呭崟锛屾鏌ュ簱瀛橈紝涓嶈冻鍒欏厛鑷姩鍏ュ簱瀹℃壒鍚庡啀棰嗘枡
-     */
-    private void processMaterialPick(SalesLedger salesLedger, LocalDate pickDate) {
-        try {
-            List<ProductionOrder> orders = findOrdersForSalesLedger(salesLedger);
-            if (orders.isEmpty()) {
-                log.info("閿�鍞彴璐{}]鏃犵敓浜ц鍗曪紝璺宠繃棰嗘枡", salesLedger.getSalesContractNo());
-                return;
-            }
-
-            for (ProductionOrder order : orders) {
-                try {
-                    // 鏌ヨ璁㈠崟BOM棰嗘枡娓呭崟
-                    List<com.ruoyi.production.bean.vo.ProductionOrderPickVo> pickList = productionOrderService.pick(order.getId());
-                    if (pickList == null || pickList.isEmpty()) {
-                        log.info("鐢熶骇璁㈠崟[{}]鏃犻鏂欐竻鍗�", order.getId());
-                        continue;
-                    }
-
-                    // 妫�鏌ュ簱瀛樹笉瓒崇殑鐗╂枡锛屽厛鑷姩鍏ュ簱
-                    ensureMaterialStock(pickList, pickDate);
-
-                    // 閲嶆柊鑾峰彇棰嗘枡娓呭崟锛堝叆搴撳悗鎵瑰彿鍜屽簱瀛橀噺宸叉洿鏂帮級
-                    pickList = productionOrderService.pick(order.getId());
-                    if (pickList == null || pickList.isEmpty()) {
-                        log.info("鐢熶骇璁㈠崟[{}]閲嶆柊鑾峰彇棰嗘枡娓呭崟涓虹┖", order.getId());
-                        continue;
-                    }
-
-                    // 鎵ц棰嗘枡
-                    List<ProductionOrderPickDto> pickDtoList = new ArrayList<>();
-                    for (com.ruoyi.production.bean.vo.ProductionOrderPickVo pickVo : pickList) {
-                        ProductionOrderPickDto pickDto = new ProductionOrderPickDto();
-                        pickDto.setProductionOrderId(order.getId());
-                        pickDto.setProductModelId(pickVo.getProductModelId());
-                        pickDto.setPickQuantity(pickVo.getDemandedQuantity());
-                        pickDto.setPickType((byte) 1);
-                        pickDto.setOperationName(pickVo.getOperationName());
-                        pickDto.setTechnologyOperationId(pickVo.getTechnologyOperationId());
-                        pickDto.setDemandedQuantity(pickVo.getDemandedQuantity());
-                        pickDto.setBom(pickVo.getBom());
-                        // 璁剧疆鎵瑰彿锛堢敤鏇存柊鍚庣殑鎵瑰彿鍒楄〃锛�
-                        if (pickVo.getBatchNoList() != null && !pickVo.getBatchNoList().isEmpty()) {
-                            pickDto.setBatchNoList(pickVo.getBatchNoList());
-                            pickDto.setBatchNo(pickVo.getBatchNoList().get(0));
-                        }
-                        pickDtoList.add(pickDto);
-                    }
-
-                    if (!pickDtoList.isEmpty()) {
-                        ProductionOrderPickDto batchDto = new ProductionOrderPickDto();
-                        batchDto.setPickList(pickDtoList);
-                        productionOrderPickService.savePick(batchDto);
-                        log.info("鐢熶骇璁㈠崟[{}]棰嗘枡鎴愬姛, 棰嗘枡椤规暟: {}", order.getId(), pickDtoList.size());
-                    }
-                } catch (Exception e) {
-                    log.warn("鐢熶骇璁㈠崟[{}]棰嗘枡澶辫触: {}", order.getId(), e.getMessage());
-                }
-            }
-        } catch (Exception e) {
-            log.warn("棰嗘枡娴佺▼澶辫触[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage());
-        }
-    }
-
-    /**
-     * 纭繚鐗╂枡搴撳瓨鍏呰冻锛屼笉瓒冲垯鍏堣嚜鍔ㄥ叆搴撳鎵�
-     */
-    private void ensureMaterialStock(List<com.ruoyi.production.bean.vo.ProductionOrderPickVo> pickList, LocalDate pickDate) {
-        LocalDateTime pickDateTime = pickDate.atTime(9, 0, 0).plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
-        String pickDateStr = pickDate.format(DateTimeFormatter.BASIC_ISO_DATE);
-
-        for (com.ruoyi.production.bean.vo.ProductionOrderPickVo pickVo : pickList) {
-            BigDecimal demanded = pickVo.getDemandedQuantity() != null ? pickVo.getDemandedQuantity() : BigDecimal.ZERO;
-            BigDecimal stockQty = pickVo.getStockQuantity() != null ? pickVo.getStockQuantity() : BigDecimal.ZERO;
-            BigDecimal shortage = demanded.subtract(stockQty);
-
-            if (shortage.compareTo(BigDecimal.ZERO) <= 0) {
-                continue; // 搴撳瓨鍏呰冻
-            }
-
-            // 搴撳瓨涓嶈冻锛岃嚜鍔ㄥ叆搴撹ˉ鍏�
-            try {
-                StockInventoryDto dto = new StockInventoryDto();
-                dto.setProductModelId(pickVo.getProductModelId());
-                dto.setQualitity(shortage);
-                dto.setRecordType(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_IN.getCode());
-                dto.setRecordId(0L);
-                stockInventoryService.addStockInRecordOnly(dto);
-
-                // 鏌ユ壘鍒氬垱寤虹殑鍏ュ簱璁板綍
-                List<com.ruoyi.stock.pojo.StockInRecord> records = stockInRecordService.list(
-                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>()
-                                .eq(com.ruoyi.stock.pojo.StockInRecord::getProductModelId, pickVo.getProductModelId())
-                                .eq(com.ruoyi.stock.pojo.StockInRecord::getApprovalStatus, 0)
-                                .orderByDesc(com.ruoyi.stock.pojo.StockInRecord::getId)
-                                .last("limit 1"));
-                if (!records.isEmpty()) {
-                    com.ruoyi.stock.pojo.StockInRecord record = records.get(0);
-                    record.setCreateTime(pickDateTime);
-                    record.setBatchNo(fixBatchNoDate(record.getBatchNo(), pickDateStr));
-                    record.setInboundBatches(fixBatchNoDate(record.getInboundBatches(), pickDateStr));
-                    stockInRecordMapper.updateById(record);
-                    // 瀹℃壒閫氳繃
-                    stockInRecordService.batchApprove(List.of(record.getId()), ReviewStatusEnum.APPROVED.getCode());
-                    log.info("鐗╂枡[{}]鑷姩鍏ュ簱瀹℃壒瀹屾垚, 鍏ュ簱鏁伴噺: {}", pickVo.getProductModelId(), shortage);
-                }
-            } catch (Exception e) {
-                log.warn("鐗╂枡[{}]鑷姩鍏ュ簱澶辫触: {}", pickVo.getProductModelId(), e.getMessage());
-            }
-        }
-    }
-
-    /**
-     * 鐢熶骇鎶ュ伐: 閬嶅巻宸ュ崟閫愪釜鎶ュ伐锛屼粠鐢熶骇瑙掕壊鐢ㄦ埛涓殢鏈洪�夊彇鎶ュ伐浜�
-     */
-    private void processProductionReport(SalesLedger salesLedger, LocalDate reportDate) {
-        try {
-            List<ProductionOrder> orders = findOrdersForSalesLedger(salesLedger);
-            if (orders.isEmpty()) {
-                log.info("閿�鍞彴璐{}]鏃犵敓浜ц鍗�", salesLedger.getSalesContractNo());
-                return;
-            }
-
-            for (ProductionOrder order : orders) {
-                List<ProductionOperationTask> tasks = productionOperationTaskMapper.selectList(
-                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionOperationTask>()
-                                .eq(ProductionOperationTask::getProductionOrderId, order.getId())
-                                .orderByAsc(ProductionOperationTask::getId));
-                for (ProductionOperationTask task : tasks) {
-                    if (task.getStatus() != null && task.getStatus() >= 3) continue;
-
-                    // 姣忔鎶ュ伐闅忔満閫変竴涓敓浜х敤鎴�
-                    SysUser productionUser = randomProductionUser();
-                    Long userId = productionUser != null ? productionUser.getUserId() : 1L;
-                    String userName = productionUser != null ? productionUser.getNickName() : "绯荤粺";
-
-                    // 鎶ュ伐
-                    ProductionProductMainDto reportDto = new ProductionProductMainDto();
-                    reportDto.setProductionOperationTaskId(task.getId());
-                    reportDto.setQuantity(task.getPlanQuantity());
-                    reportDto.setScrapQty(BigDecimal.ZERO);
-                    reportDto.setUserId(userId);
-                    reportDto.setUserName(userName);
-                    productionProductMainService.addProductMain(reportDto);
-
-                    // 淇鎶ュ伐鏃堕棿锛堥噸鏂颁粠DB璇诲彇锛岄伩鍏嶈鐩朼ddProductMain鏇存柊鐨刢ompleteQuantity锛�
-                    fixProductionReportTimes(task.getId(), reportDate);
-                }
-                // 淇鐢熶骇璁㈠崟鏃堕棿锛堥噸鏂颁粠DB璇诲彇锛岄伩鍏嶈鐩朼ddProductMain鏇存柊鐨刢ompleteQuantity锛�
-                fixProductionOrderTimes(order.getId(), reportDate);
-            }
-            log.info("閿�鍞彴璐{}]鐢熶骇鎶ュ伐瀹屾垚, 璁㈠崟鏁�: {}", salesLedger.getSalesContractNo(), orders.size());
-        } catch (Exception e) {
-            log.warn("鐢熶骇鎶ュ伐澶辫触[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage());
-        }
-    }
-
-    /**
-     * 鏌ユ壘閿�鍞彴璐﹀叧鑱旂殑鐢熶骇璁㈠崟
-     */
-    private List<ProductionOrder> findOrdersForSalesLedger(SalesLedger salesLedger) {
-        List<ProductionOrder> orders = new ArrayList<>();
-        List<ProductionPlan> plans = productionPlanMapper.selectList(
-                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionPlan>()
-                        .eq(ProductionPlan::getSalesLedgerId, salesLedger.getId()));
-        for (ProductionPlan plan : plans) {
-            List<ProductionOrder> po = productionOrderMapper.selectList(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionOrder>()
-                            .like(ProductionOrder::getProductionPlanIds, String.valueOf(plan.getId())));
-            orders.addAll(po);
-        }
-        // 鍘婚噸
-        return orders.stream()
-                .collect(Collectors.toMap(ProductionOrder::getId, o -> o, (a, b) -> a))
-                .values().stream().collect(Collectors.toList());
-    }
-
-    /**
-     * 淇鐢熶骇鎶ュ伐鐩稿叧鏃堕棿锛堥噸鏂颁粠DB璇诲彇task锛岄伩鍏嶈鐩朼ddProductMain宸叉洿鏂扮殑completeQuantity锛�
-     */
-    private void fixProductionReportTimes(Long taskId, LocalDate reportDate) {
-        try {
-            ProductionOperationTask freshTask = productionOperationTaskMapper.selectById(taskId);
-            if (freshTask != null) {
-                freshTask.setActualStartTime(reportDate);
-                freshTask.setActualEndTime(reportDate);
-                freshTask.setStatus(4);
-                productionOperationTaskMapper.updateById(freshTask);
-            }
-        } catch (Exception e) {
-            log.warn("淇鐢熶骇鎶ュ伐鏃堕棿澶辫触: {}", e.getMessage());
-        }
-    }
-
-    /**
-     * 淇鐢熶骇璁㈠崟鏃堕棿锛堥噸鏂颁粠DB璇诲彇order锛岄伩鍏嶈鐩朼ddProductMain宸叉洿鏂扮殑completeQuantity锛�
-     */
-    private void fixProductionOrderTimes(Long orderId, LocalDate reportDate) {
-        try {
-            ProductionOrder freshOrder = productionOrderMapper.selectById(orderId);
-            if (freshOrder != null) {
-                freshOrder.setStartTime(reportDate.minusDays(1).atStartOfDay());
-                freshOrder.setEndTime(reportDate.plusDays(1).atStartOfDay());
-                freshOrder.setStatus(3);
-                productionOrderMapper.updateById(freshOrder);
-            }
-        } catch (Exception e) {
-            log.warn("淇鐢熶骇璁㈠崟鏃堕棿澶辫触: {}", e.getMessage());
-        }
-    }
-
-    /**
-     * 閿�鍞川妫�鎻愪氦 + 鍏ュ簱瀹℃壒
-     */
-    private void processSalesQualityAndStockIn(SalesLedger salesLedger, LocalDate qualityDate) {
-        try {
-            LocalDateTime qualityDateTime = qualityDate.atTime(9, 0, 0)
-                    .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
-
-            // 鏌ユ墍鏈夋湭鎻愪氦鐨勮川妫�鍗曪紙inspectType=1杩囩▼妫�楠�, 2=鍑哄巶妫�楠岋紝鐢辩敓浜ф姤宸ョ敓鎴愶級
-            List<QualityInspect> allUnsubmitted = qualityInspectService.list(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QualityInspect>()
-                            .eq(QualityInspect::getInspectState, 0)
-                            .in(QualityInspect::getInspectType, java.util.Arrays.asList(1, 2)));
-            for (QualityInspect qi : allUnsubmitted) {
-                qualityInspectService.autoSubmit(qi.getId());
-                qi.setCreateTime(qualityDateTime);
-                qualityInspectMapper.updateById(qi);
-            }
-            log.info("閿�鍞彴璐{}]璐ㄦ鎻愪氦瀹屾垚, 璐ㄦ鍗曟暟: {}", salesLedger.getSalesContractNo(), allUnsubmitted.size());
-
-            // 鍏ュ簱瀹℃壒锛氬鎵规墍鏈夊緟瀹℃壒鐨勫叆搴撹褰�
-            LocalDate stockDate = qualityDate.plusDays(ThreadLocalRandom.current().nextInt(0, 3));
-            LocalDateTime stockDateTime = stockDate.atTime(9, 0, 0)
-                    .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
-            String stockDateStr = stockDate.format(DateTimeFormatter.BASIC_ISO_DATE);
-            List<com.ruoyi.stock.pojo.StockInRecord> stockRecords = stockInRecordService.list(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>()
-                            .eq(com.ruoyi.stock.pojo.StockInRecord::getApprovalStatus, 0));
-            List<Long> recordIds = stockRecords.stream()
-                    .map(com.ruoyi.stock.pojo.StockInRecord::getId)
-                    .collect(Collectors.toList());
-            if (!recordIds.isEmpty()) {
-                for (com.ruoyi.stock.pojo.StockInRecord sr : stockRecords) {
-                    sr.setCreateTime(stockDateTime);
-                    sr.setBatchNo(fixBatchNoDate(sr.getBatchNo(), stockDateStr));
-                    sr.setInboundBatches(fixBatchNoDate(sr.getInboundBatches(), stockDateStr));
-                    stockInRecordMapper.updateById(sr);
-                }
-                stockInRecordService.batchApprove(recordIds, ReviewStatusEnum.APPROVED.getCode());
-                for (com.ruoyi.stock.pojo.StockInRecord sr : stockRecords) {
-                    StockInventory si = stockInventoryMapper.selectOne(
-                            new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StockInventory>()
-                                    .eq(StockInventory::getProductModelId, sr.getProductModelId())
-                                    .eq(StockInventory::getBatchNo, sr.getBatchNo()));
-                    if (si != null) {
-                        si.setBatchNo(fixBatchNoDate(si.getBatchNo(), stockDateStr));
-                        stockInventoryMapper.updateById(si);
-                    }
-                }
-                log.info("閿�鍞彴璐{}]鍏ュ簱瀹℃壒瀹屾垚, 鍏ュ簱璁板綍鏁�: {}", salesLedger.getSalesContractNo(), recordIds.size());
-            }
-        } catch (Exception e) {
-            log.warn("閿�鍞川妫�鍏ュ簱澶辫触[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage());
-        }
-    }
-
-    /**
-     * 鍙戣揣 + 鍙戣揣瀹℃壒閫氳繃 + 鍑哄簱瀹℃壒
-     */
-    private void processSalesShipping(SalesLedger salesLedger, LocalDate shipDate) {
-        try {
-            LocalDateTime shipDateTime = shipDate.atTime(9, 0, 0)
-                    .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
-            String shipDateStr = shipDate.format(DateTimeFormatter.BASIC_ISO_DATE);
-
-            // 鏌ユ壘鏈夊簱瀛樼殑浜у搧瑙勬牸
-            List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SalesLedgerProduct>()
-                            .eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId()));
-
-            List<ShippingProductDetail> details = new ArrayList<>();
-            for (SalesLedgerProduct slp : products) {
-                StockInventory si = stockInventoryMapper.selectOne(
-                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StockInventory>()
-                                .eq(StockInventory::getProductModelId, slp.getProductModelId())
-                                .gt(StockInventory::getQualitity, BigDecimal.ZERO)
-                                .orderByDesc(StockInventory::getId)
-                                .last("limit 1"));
-                if (si != null) {
-                    ShippingProductDetail detail = new ShippingProductDetail();
-                    detail.setStockInventoryId(si.getId());
-                    detail.setProductModelId(slp.getProductModelId());
-                    detail.setBatchNo(si.getBatchNo());
-                    detail.setQuantity(slp.getQuantity());
-                    details.add(detail);
-                }
-            }
-            if (details.isEmpty()) {
-                log.info("閿�鍞彴璐{}]鏃犲彲鐢ㄥ簱瀛橈紝璺宠繃鍙戣揣", salesLedger.getSalesContractNo());
-                return;
-            }
-
-            // 鍒涘缓鍙戣揣鍗�
-            ShippingInfoDto shipDto = new ShippingInfoDto();
-            shipDto.setSalesLedgerId(salesLedger.getId());
-            shipDto.setSalesLedgerProductId(products.get(0).getId());
-            shipDto.setCreateTime(shipDateTime);
-            shipDto.setBatchNoDetailList(details);
-            shippingInfoService.addReq(shipDto);
-
-            // 鎵惧埌鍙戣揣鍗曞拰瀹℃壒瀹炰緥
-            ShippingInfo shippingInfo = shippingInfoMapper.selectOne(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ShippingInfo>()
-                            .eq(ShippingInfo::getShippingNo, shipDto.getShippingNo())
-                            .last("limit 1"));
-            if (shippingInfo != null) {
-                shippingInfo.setCreateTime(shipDateTime);
-                shippingInfo.setShippingDate(java.sql.Date.valueOf(shipDate));
-                // 鏍规嵁瀹㈡埛鍦板潃鐢熸垚鍙戣揣杞︾墝鍙�
-                shippingInfo.setShippingCarNumber(generateCarNumber(salesLedger.getCustomerName()));
-                shippingInfoMapper.updateById(shippingInfo);
-
-                // 鍙戣揣瀹℃壒鑷姩閫氳繃
-                ApprovalInstance shipApproval = approvalInstanceMapper.selectOne(
-                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalInstance>()
-                                .eq(ApprovalInstance::getBusinessId, shippingInfo.getId())
-                                .eq(ApprovalInstance::getBusinessType, 7L)
-                                .eq(ApprovalInstance::getDeleted, 0)
-                                .orderByDesc(ApprovalInstance::getId)
-                                .last("limit 1"));
-                if (shipApproval != null) {
-                    LocalDate shipApproveDate = shipDate.plusDays(ThreadLocalRandom.current().nextInt(0, 3));
-                    LocalDateTime shipApproveDateTime = shipApproveDate.atTime(9, 0, 0)
-                            .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
-                    approvalInstanceService.autoApprove(shipApproval.getId());
-                    fixApprovalTimes(shipApproval.getId(), shipApproveDateTime);
-
-                    shippingInfo.setStatus("宸插彂璐�");
-                    shippingInfo.setShippingDate(java.sql.Date.valueOf(shipApproveDate));
-                    shippingInfoMapper.updateById(shippingInfo);
-                }
-
-                // 鍑哄簱瀹℃壒
-                LocalDate outDate = shipDate.plusDays(ThreadLocalRandom.current().nextInt(0, 3));
-                LocalDateTime outDateTime = outDate.atTime(9, 0, 0)
-                        .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
-                String outDateStr = outDate.format(DateTimeFormatter.BASIC_ISO_DATE);
-                List<StockOutRecord> outRecords = stockOutRecordMapper.selectList(
-                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StockOutRecord>()
-                                .eq(StockOutRecord::getRecordId, shippingInfo.getId())
-                                .eq(StockOutRecord::getRecordType,
-                                        String.valueOf(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode())));
-                List<Long> outIds = new ArrayList<>();
-                for (StockOutRecord sr : outRecords) {
-                    if (sr.getApprovalStatus() == null || sr.getApprovalStatus() == 0 || sr.getApprovalStatus() == 3) {
-                        sr.setCreateTime(outDateTime);
-                        sr.setOutboundBatches(fixBatchNoDate(sr.getOutboundBatches(), outDateStr));
-                        sr.setBatchNo(fixBatchNoDate(sr.getBatchNo(), outDateStr));
-                        stockOutRecordMapper.updateById(sr);
-                        outIds.add(sr.getId());
-                    }
-                }
-                if (!outIds.isEmpty()) {
-                    // 鍑哄簱瀹℃壒閫氳繃锛堣蛋姝e紡瀹℃壒娴佺▼锛屽唴閮ㄤ細鎵e噺搴撳瓨锛�
-                    stockOutRecordService.batchApprove(outIds, ReviewStatusEnum.APPROVED.getCode());
-                    log.info("閿�鍞彴璐{}]鍑哄簱瀹℃壒瀹屾垚, 鍑哄簱璁板綍鏁�: {}",
-                            salesLedger.getSalesContractNo(), outIds.size());
-                }
-            }
-            log.info("閿�鍞彴璐{}]鍙戣揣娴佺▼瀹屾垚", salesLedger.getSalesContractNo());
-        } catch (Exception e) {
-            log.warn("閿�鍞彂璐ф祦绋嬪け璐{}]: {}", salesLedger.getSalesContractNo(), e.getMessage());
-        }
-    }
-
-    private ModuleSummary createPurchaseLedgers(List<JSONObject> items, Map<String, Long> supplierNameToId,
-                                                 String additionalInfo, String dateStart, String dateEnd) {
-        // 鏄惁闇�瑕佽川妫�锛屼粠琛ュ厖淇℃伅鍒ゆ柇锛岄粯璁や笉闇�瑕�
-        boolean needQualityInspect = additionalInfo != null
-                && (additionalInfo.contains("璐ㄦ") || additionalInfo.contains("闇�瑕佹楠�"));
-        int success = 0, fail = 0;
-        for (JSONObject item : items) {
-            try {
-                String supplierName = item.getString("supplierName");
-                Long supplierId = supplierNameToId.get(supplierName);
-
-                PurchaseLedgerDto dto = new PurchaseLedgerDto();
-                dto.setSupplierId(supplierId);
-                dto.setSupplierName(supplierName);
-                dto.setPurchaseContractNumber(item.getString("purchaseContractNumber"));
-                dto.setProjectName(item.getString("projectName"));
-                dto.setContractAmount(item.getBigDecimal("contractAmount"));
-                dto.setPaymentMethod(item.getString("paymentMethod"));
-
-                String entryDateStr = item.getString("entryDate");
-                LocalDate entryDate = null;
-                if (item.containsKey("entryDate") && entryDateStr != null && entryDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
-                    entryDate = LocalDate.parse(entryDateStr);
-                    dto.setEntryDate(java.sql.Date.valueOf(entryDateStr));
-                } else {
-                    dto.setEntryDate(java.sql.Date.valueOf(dateStart));
-                }
-                if (item.containsKey("executionDate")) {
-                    String execDateStr = item.getString("executionDate");
-                    if (execDateStr != null && execDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
-                        dto.setExecutionDate(java.sql.Date.valueOf(execDateStr));
-                    } else {
-                        dto.setExecutionDate(java.sql.Date.valueOf(dateStart));
-                    }
-                }
-                JSONArray productData = item.getJSONArray("productData");
-                if (productData != null) {
-                    List<SalesLedgerProduct> products = new ArrayList<>();
-                    for (int i = 0; i < productData.size(); i++) {
-                        JSONObject pd = productData.getJSONObject(i);
-                        SalesLedgerProduct slp = new SalesLedgerProduct();
-                        slp.setProductId(pd.getLong("productId"));
-                        slp.setProductModelId(pd.getLong("productModelId"));
-                        slp.setQuantity(pd.getBigDecimal("quantity"));
-                        slp.setTaxInclusiveUnitPrice(pd.getBigDecimal("taxInclusiveUnitPrice"));
-                        slp.setTaxInclusiveTotalPrice(pd.getBigDecimal("taxInclusiveTotalPrice"));
-                        slp.setTaxRate(pd.getBigDecimal("taxRate"));
-                        slp.setUnit(pd.getString("unit"));
-                        slp.setType(2);
-                        // 鏄惁璐ㄦ锛氫粠琛ュ厖淇℃伅鍒ゆ柇锛岄粯璁や笉闇�瑕�
-                        slp.setIsChecked(needQualityInspect);
-                        if (pd.containsKey("taxExclusiveTotalPrice")) {
-                            slp.setTaxExclusiveTotalPrice(pd.getBigDecimal("taxExclusiveTotalPrice"));
-                        } else if (pd.getBigDecimal("taxInclusiveTotalPrice") != null && pd.getBigDecimal("taxRate") != null) {
-                            slp.setTaxExclusiveTotalPrice(
-                                pd.getBigDecimal("taxInclusiveTotalPrice").divide(
-                                    BigDecimal.ONE.add(pd.getBigDecimal("taxRate").divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP)),
-                                    2, RoundingMode.HALF_UP));
-                        } else {
-                            slp.setTaxExclusiveTotalPrice(BigDecimal.ZERO);
-                        }
-                        products.add(slp);
-                    }
-                    dto.setProductData(products);
-                }
-                purchaseLedgerService.addOrEditPurchase(dto);
-                // 閫氳繃鍚堝悓鍙锋壘鍒板垰鍒涘缓鐨勯噰璐彴璐�
-                PurchaseLedger savedLedger = purchaseLedgerService.getOne(
-                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<PurchaseLedger>()
-                                .eq(PurchaseLedger::getPurchaseContractNumber, dto.getPurchaseContractNumber())
-                                .last("limit 1"));
-                if (savedLedger != null) {
-                    // 璧板畬鏁存祦绋嬶細瀹℃牳閫氳繃 鈫� 璐ㄦ(鍙��) 鈫� 鍏ュ簱 + 鍏ュ簱瀹℃牳閫氳繃
-                    processPurchaseFullFlow(savedLedger, needQualityInspect, entryDate, dateEnd);
-                }
-                success++;
-            } catch (Exception e) {
-                log.warn("鍒涘缓閲囪喘鍙拌处澶辫触: {}", e.getMessage(), e);
-                fail++;
-            }
-        }
-        return summary("purchase", "閲囪喘鍙拌处", items.size(), success, fail);
-    }
-
-    /**
-     * 閲囪喘瀹屾暣娴佺▼: 瀹℃牳閫氳繃 鈫� 璐ㄦ(鍙��) 鈫� 鍏ュ簱瀹℃牳閫氳繃
-     * 鍚勭幆鑺傛椂闂翠互閲囪喘褰曞叆鏃ユ湡涓哄熀鍑嗭紝鍋跺皵鎺ㄨ繜1-3澶�
-     */
-    private void processPurchaseFullFlow(PurchaseLedger purchaseLedger, boolean needQualityInspect,
-                                          LocalDate entryDate, String dateEnd) {
-        try {
-            // 鍩哄噯鏃ユ湡锛氶噰璐綍鍏ユ棩鏈燂紝涓虹┖鍒欑敤褰撳ぉ
-            LocalDate baseDate = entryDate != null ? entryDate : LocalDate.now();
-            // 瀹℃壒鏃堕棿锛氬熀浜庡綍鍏ユ棩鏈燂紝闅忔満鎺�0-3澶�
-            LocalDate approveDate = baseDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
-            LocalDateTime approveDateTime = approveDate.atTime(9, 0, 0)
-                    .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
-
-            // 1. 瀹℃壒鑷姩閫氳繃
-            ApprovalInstance approvalInstance = approvalInstanceMapper.selectOne(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalInstance>()
-                            .eq(ApprovalInstance::getBusinessId, purchaseLedger.getId())
-                            .eq(ApprovalInstance::getBusinessType, 5L)
-                            .eq(ApprovalInstance::getDeleted, 0)
-                            .orderByDesc(ApprovalInstance::getId)
-                            .last("limit 1"));
-            if (approvalInstance != null) {
-                approvalInstanceService.autoApprove(approvalInstance.getId());
-                // 淇瀹℃壒鐩稿叧鏃堕棿涓洪噰璐綍鍏ユ棩鏈熻寖鍥�
-                fixApprovalTimes(approvalInstance.getId(), approveDateTime);
-                log.info("閲囪喘鍙拌处[{}]瀹℃壒閫氳繃, 瀹℃壒鏃ユ湡: {}", purchaseLedger.getPurchaseContractNumber(), approveDate);
-            }
-
-            // 2. 璐ㄦ娴佺▼锛堝鏋滈渶瑕佽川妫�锛�
-            if (needQualityInspect) {
-                // 璐ㄦ鏃堕棿锛氬鎵逛箣鍚庡啀鎺�0-3澶�
-                LocalDate inspectDate = approveDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
-                processQualityInspect(purchaseLedger, inspectDate);
-            }
-
-            // 3. 鍏ュ簱瀹℃壒閫氳繃
-            // 鍏ュ簱鏃堕棿锛氳川妫�鏃堕棿锛堟湁璐ㄦ锛夋垨瀹℃壒鏃堕棿涔嬪悗鍐嶆帹0-3澶�
-            LocalDate stockBaseDate = needQualityInspect
-                    ? approveDate.plusDays(ThreadLocalRandom.current().nextInt(1, 4))
-                    : approveDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
-            processStockInApprove(purchaseLedger, stockBaseDate);
-
-        } catch (Exception e) {
-            log.warn("閲囪喘瀹屾暣娴佺▼澶勭悊澶辫触[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage());
-        }
-    }
-
-    /**
-     * 淇瀹℃壒瀹炰緥鍙婂叧鑱旇妭鐐广�佷换鍔°�佽褰曠殑鏃堕棿
-     */
-    private void fixApprovalTimes(Long instanceId, LocalDateTime dateTime) {
-        try {
-            // 鏇存柊瀹℃壒瀹炰緥鐨刦inishTime鍜宑reateTime
-            ApprovalInstance instance = approvalInstanceMapper.selectById(instanceId);
-            if (instance != null) {
-                instance.setFinishTime(dateTime);
-                instance.setCreateTime(dateTime.minusHours(1));
-                approvalInstanceMapper.updateById(instance);
-            }
-
-            // 鏇存柊瀹℃壒瀹炰緥鑺傜偣鐨刦inishTime
-            List<ApprovalInstanceNode> nodes = approvalInstanceNodeMapper.selectList(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalInstanceNode>()
-                            .eq(ApprovalInstanceNode::getInstanceId, instanceId));
-            for (ApprovalInstanceNode node : nodes) {
-                node.setFinishTime(dateTime);
-                node.setCreateTime(dateTime.minusHours(1));
-                approvalInstanceNodeMapper.updateById(node);
-            }
-
-            // 鏇存柊瀹℃壒浠诲姟鐨刢reateTime
-            List<ApprovalTask> tasks = approvalTaskMapper.selectList(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalTask>()
-                            .eq(ApprovalTask::getInstanceId, instanceId));
-            for (ApprovalTask task : tasks) {
-                task.setCreateTime(dateTime.minusMinutes(30));
-                approvalTaskMapper.updateById(task);
-            }
-
-            // 鏇存柊瀹℃壒璁板綍鐨刢reateTime
-            List<ApprovalRecord> records = approvalRecordMapper.selectList(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalRecord>()
-                            .eq(ApprovalRecord::getInstanceId, instanceId));
-            for (ApprovalRecord record : records) {
-                record.setCreateTime(dateTime.minusMinutes(10));
-                approvalRecordMapper.updateById(record);
-            }
-        } catch (Exception e) {
-            log.warn("淇瀹℃壒鏃堕棿澶辫触: {}", e.getMessage());
-        }
-    }
-
-    /**
-     * 璐ㄦ: 鎵惧埌閲囪喘鍏宠仈鐨勮川妫�鍗曪紝鑷姩鎻愪氦涓哄悎鏍�
-     */
-    private void processQualityInspect(PurchaseLedger purchaseLedger, LocalDate inspectDate) {
-        try {
-            LocalDateTime inspectDateTime = inspectDate.atTime(9, 0, 0)
-                    .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
-            List<QualityInspect> inspectList = qualityInspectService.list(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QualityInspect>()
-                            .eq(QualityInspect::getPurchaseLedgerId, purchaseLedger.getId()));
-            for (QualityInspect qi : inspectList) {
-                if (qi.getInspectState() == null || qi.getInspectState() == 0) {
-                    qualityInspectService.autoSubmit(qi.getId());
-                    // 淇璐ㄦ鏃堕棿
-                    qi.setCreateTime(inspectDateTime);
-                    qualityInspectMapper.updateById(qi);
-                    log.info("閲囪喘鍙拌处[{}]璐ㄦ鍗昜{}]鑷姩鎻愪氦鍚堟牸, 璐ㄦ鏃ユ湡: {}",
-                            purchaseLedger.getPurchaseContractNumber(), qi.getId(), inspectDate);
-                }
-            }
-        } catch (Exception e) {
-            log.warn("璐ㄦ娴佺▼澶勭悊澶辫触[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage());
-        }
-    }
-
-    /**
-     * 鍏ュ簱瀹℃牳: 鎵惧埌鍏ュ簱璁板綍骞跺鎵归�氳繃锛屽苟淇鏃堕棿涓庢壒鍙锋棩鏈�
-     */
-    private void processStockInApprove(PurchaseLedger purchaseLedger, LocalDate stockDate) {
-        try {
-            LocalDateTime stockDateTime = stockDate.atTime(9, 0, 0)
-                    .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
-            String stockDateStr = stockDate.format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE);
-
-            List<com.ruoyi.stock.pojo.StockInRecord> stockRecords = stockInRecordService.list(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>()
-                            .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordId, purchaseLedger.getId())
-                            .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordType,
-                                    String.valueOf(com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode())));
-            if (stockRecords.isEmpty()) {
-                stockRecords = stockInRecordService.list(
-                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>()
-                                .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordId, purchaseLedger.getId())
-                                .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordType,
-                                        String.valueOf(com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode())));
-            }
-            for (QualityInspect qi : qualityInspectService.list(
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QualityInspect>()
-                            .eq(QualityInspect::getPurchaseLedgerId, purchaseLedger.getId()))) {
-                List<com.ruoyi.stock.pojo.StockInRecord> qiRecords = stockInRecordService.list(
-                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>()
-                                .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordId, qi.getId()));
-                stockRecords.addAll(qiRecords);
-            }
-            stockRecords = stockRecords.stream()
-                    .collect(Collectors.toMap(com.ruoyi.stock.pojo.StockInRecord::getId, r -> r, (a, b) -> a))
-                    .values().stream().collect(Collectors.toList());
-
-            if (!stockRecords.isEmpty()) {
-                List<Long> recordIds = stockRecords.stream()
-                        .filter(r -> r.getApprovalStatus() == null || r.getApprovalStatus() == 0)
-                        .map(com.ruoyi.stock.pojo.StockInRecord::getId)
-                        .collect(Collectors.toList());
-                if (!recordIds.isEmpty()) {
-                    // 鍏堜慨姝e叆搴撹褰曠殑createTime鍜屾壒鍙锋棩鏈燂紙batchApprove鍐呴儴浼氱敤batchNo鍒涘缓StockInventory锛�
-                    for (Long recordId : recordIds) {
-                        com.ruoyi.stock.pojo.StockInRecord sr = stockInRecordMapper.selectById(recordId);
-                        if (sr != null) {
-                            sr.setCreateTime(stockDateTime);
-                            sr.setBatchNo(fixBatchNoDate(sr.getBatchNo(), stockDateStr));
-                            String s = OrderUtils.countTodayByCreateTime(stockInRecordMapper, "RK", "inbound_batches", stockDateTime);
-                            sr.setInboundBatches(s);
-                            stockInRecordMapper.updateById(sr);
-                        }
-                    }
-                    stockInRecordService.batchApprove(recordIds, ReviewStatusEnum.APPROVED.getCode());
-                    log.info("閲囪喘鍙拌处[{}]鍏ュ簱瀹℃壒閫氳繃, 鍏ュ簱鏃ユ湡: {}, 鍏ュ簱璁板綍鏁�: {}",
-                            purchaseLedger.getPurchaseContractNumber(), stockDate, recordIds.size());
-                }
-            }
-        } catch (Exception e) {
-            log.warn("鍏ュ簱瀹℃壒澶辫触[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage());
-        }
-    }
-
-    /**
-     * 鏇挎崲鎵瑰彿涓殑鏃ユ湡閮ㄥ垎锛坹yyyMMdd 鈫� 鎸囧畾鏃ユ湡锛�
-     */
-    /**
-     * 鏍规嵁瀹㈡埛鍚嶇О鏌ュ湴鍧�锛屾帹鏂渷浠界畝绉扮敓鎴愯溅鐗屽彿
-     * 鏍煎紡: 鐪佷唤绠�绉� + 瀛楁瘝 + 5浣嶉殢鏈烘暟瀛楀瓧姣�, 濡� 鑻廇12345
-     */
-    private String generateCarNumber(String customerName) {
-        // 鐪佷唤绠�绉板埌鍩庡競瀛楁瘝鐨勫父瑙佹槧灏�
-        Map<String, String[]> provinceCityMap = new HashMap<>();
-        provinceCityMap.put("浜�", new String[]{"A", "B", "C", "E", "F", "G"});
-        provinceCityMap.put("娌�", new String[]{"A", "B", "D", "E", "F"});
-        provinceCityMap.put("绮�", new String[]{"A", "B", "E", "F", "G", "H", "J", "K"});
-        provinceCityMap.put("鑻�", new String[]{"A", "B", "E", "F", "G", "H", "J", "K", "L", "M"});
-        provinceCityMap.put("娴�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L"});
-        provinceCityMap.put("椴�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "Y"});
-        provinceCityMap.put("璞�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "U"});
-        provinceCityMap.put("宸�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"});
-        provinceCityMap.put("娓�", new String[]{"A", "B", "C", "D"});
-        provinceCityMap.put("閯�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S"});
-        provinceCityMap.put("婀�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "S"});
-        provinceCityMap.put("闂�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K"});
-        provinceCityMap.put("璧�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M"});
-        provinceCityMap.put("鐨�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R", "S"});
-        provinceCityMap.put("鍐�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "R", "T"});
-        provinceCityMap.put("杈�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P"});
-        provinceCityMap.put("鍚�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K"});
-        provinceCityMap.put("榛�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R"});
-        provinceCityMap.put("鏅�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M"});
-        provinceCityMap.put("闄�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "V"});
-        provinceCityMap.put("妗�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R"});
-        provinceCityMap.put("浜�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S"});
-        provinceCityMap.put("璐�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J"});
-        provinceCityMap.put("鐢�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P"});
-        provinceCityMap.put("鐞�", new String[]{"A", "B", "C", "D", "E", "F"});
-        provinceCityMap.put("瀹�", new String[]{"A", "B", "C", "D", "E"});
-        provinceCityMap.put("闈�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H"});
-        provinceCityMap.put("钘�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J"});
-        provinceCityMap.put("钂�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M"});
-        provinceCityMap.put("鏂�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R"});
-        provinceCityMap.put("娲�", new String[]{"A", "B", "C", "E", "F", "G", "H", "J", "K", "L", "M", "N", "Q", "R"});
-
-        // 鍦板潃鍏抽敭璇嶅埌鐪佷唤绠�绉扮殑鏄犲皠
-        Map<String, String> addressToProvince = new HashMap<>();
-        addressToProvince.put("鍖椾含", "浜�"); addressToProvince.put("涓婃捣", "娌�");
-        addressToProvince.put("骞垮窞", "绮�"); addressToProvince.put("娣卞湷", "绮�");
-        addressToProvince.put("涓滆帪", "绮�"); addressToProvince.put("浣涘北", "绮�");
-        addressToProvince.put("鍗椾含", "鑻�"); addressToProvince.put("鑻忓窞", "鑻�");
-        addressToProvince.put("鏃犻敗", "鑻�"); addressToProvince.put("鍗楅��", "鑻�");
-        addressToProvince.put("甯稿窞", "鑻�"); addressToProvince.put("寰愬窞", "鑻�");
-        addressToProvince.put("鏉窞", "娴�"); addressToProvince.put("瀹佹尝", "娴�");
-        addressToProvince.put("娓╁窞", "娴�"); addressToProvince.put("鍢夊叴", "娴�");
-        addressToProvince.put("娴庡崡", "椴�"); addressToProvince.put("闈掑矝", "椴�");
-        addressToProvince.put("閮戝窞", "璞�"); addressToProvince.put("鎴愰兘", "宸�");
-        addressToProvince.put("閲嶅簡", "娓�"); addressToProvince.put("姝︽眽", "閯�");
-        addressToProvince.put("闀挎矙", "婀�"); addressToProvince.put("绂忓窞", "闂�");
-        addressToProvince.put("鍘﹂棬", "闂�"); addressToProvince.put("鍗楁槍", "璧�");
-        addressToProvince.put("鍚堣偉", "鐨�"); addressToProvince.put("鐭冲搴�", "鍐�");
-        addressToProvince.put("娌堥槼", "杈�"); addressToProvince.put("澶ц繛", "杈�");
-        addressToProvince.put("闀挎槬", "鍚�"); addressToProvince.put("鍝堝皵婊�", "榛�");
-        addressToProvince.put("澶師", "鏅�"); addressToProvince.put("瑗垮畨", "闄�");
-        addressToProvince.put("鍗楀畞", "妗�"); addressToProvince.put("鏄嗘槑", "浜�");
-        addressToProvince.put("璐甸槼", "璐�"); addressToProvince.put("鍏板窞", "鐢�");
-        addressToProvince.put("娴峰彛", "鐞�"); addressToProvince.put("閾跺窛", "瀹�");
-        addressToProvince.put("瑗垮畞", "闈�"); addressToProvince.put("鎷夎惃", "钘�");
-        addressToProvince.put("鍛煎拰娴╃壒", "钂�"); addressToProvince.put("涔岄瞾鏈ㄩ綈", "鏂�");
-        addressToProvince.put("澶╂触", "娲�");
-        // 鐪佸悕鏄犲皠
-        addressToProvince.put("姹熻嫃", "鑻�"); addressToProvince.put("娴欐睙", "娴�");
-        addressToProvince.put("灞变笢", "椴�"); addressToProvince.put("娌冲崡", "璞�");
-        addressToProvince.put("鍥涘窛", "宸�"); addressToProvince.put("婀栧寳", "閯�");
-        addressToProvince.put("婀栧崡", "婀�"); addressToProvince.put("绂忓缓", "闂�");
-        addressToProvince.put("姹熻タ", "璧�"); addressToProvince.put("瀹夊窘", "鐨�");
-        addressToProvince.put("娌冲寳", "鍐�"); addressToProvince.put("杈藉畞", "杈�");
-        addressToProvince.put("鍚夋灄", "鍚�"); addressToProvince.put("榛戦緳姹�", "榛�");
-        addressToProvince.put("灞辫タ", "鏅�"); addressToProvince.put("闄曡タ", "闄�");
-        addressToProvince.put("骞夸笢", "绮�"); addressToProvince.put("骞胯タ", "妗�");
-        addressToProvince.put("浜戝崡", "浜�"); addressToProvince.put("璐靛窞", "璐�");
-        addressToProvince.put("鐢樿們", "鐢�"); addressToProvince.put("娴峰崡", "鐞�");
-        addressToProvince.put("瀹佸", "瀹�"); addressToProvince.put("闈掓捣", "闈�");
-        addressToProvince.put("瑗胯棌", "钘�"); addressToProvince.put("鍐呰挋鍙�", "钂�");
-        addressToProvince.put("鏂扮枂", "鏂�");
-
-        String province = "鑻�"; // 榛樿姹熻嫃
-        // 灏濊瘯浠庡鎴峰湴鍧�鎺ㄦ柇鐪佷唤
-        if (customerName != null) {
-            try {
-                Customer customer = customerService.getOne(
-                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Customer>()
-                                .eq(Customer::getCustomerName, customerName)
-                                .last("limit 1"));
-                if (customer != null && customer.getCompanyAddress() != null) {
-                    String addr = customer.getCompanyAddress();
-                    for (Map.Entry<String, String> e : addressToProvince.entrySet()) {
-                        if (addr.contains(e.getKey())) {
-                            province = e.getValue();
-                            break;
-                        }
-                    }
-                }
-            } catch (Exception e) {
-                log.debug("鏌ュ鎴峰湴鍧�澶辫触: {}", e.getMessage());
-            }
-        }
-
-        // 鐢熸垚杞︾墝鍙�: 鐪佷唤绠�绉� + 鍩庡競瀛楁瘝 + 5浣嶉殢鏈哄瓧绗�(鏁板瓧+澶у啓瀛楁瘝)
-        String[] cities = provinceCityMap.getOrDefault(province, new String[]{"A", "B", "C"});
-        String city = cities[ThreadLocalRandom.current().nextInt(cities.length)];
-        String chars = "ABCDEFGHJKLMNPQRSTUVWXYZ0123456789";
-        StringBuilder suffix = new StringBuilder();
-        for (int i = 0; i < 5; i++) {
-            suffix.append(chars.charAt(ThreadLocalRandom.current().nextInt(chars.length())));
-        }
-        return province + city + suffix;
-    }
-
-    private String fixBatchNoDate(String batchNo, String newDate) {
-        if (batchNo == null || batchNo.length() < 8) {
-            return batchNo;
-        }
-        // 鎵瑰彿鏍煎紡: yyyyMMdd-浜у搧缂栫爜-NNN
-        String prefix = batchNo.substring(0, 8);
-        if (prefix.matches("\\d{8}")) {
-            return newDate + batchNo.substring(8);
-        }
-        return batchNo;
-    }
-
-    private ModuleSummary createProductionPlans(List<JSONObject> items) {
-        int success = 0, fail = 0;
-        List<ProductionPlan> createdPlans = new ArrayList<>();
-        for (JSONObject item : items) {
-            try {
-                ProductionPlan plan = new ProductionPlan();
-                plan.setProductModelId(item.getLong("productModelId"));
-                plan.setQtyRequired(item.getBigDecimal("qtyRequired"));
-                plan.setSource(item.getString("source"));
-                plan.setRemark(item.getString("remark"));
-                if (item.containsKey("requiredDate")) {
-                    String dateStr = item.getString("requiredDate");
-                    if (dateStr != null && dateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
-                        plan.setRequiredDate(LocalDate.parse(dateStr));
-                    }
-                }
-                if (item.containsKey("promisedDeliveryDate")) {
-                    String dateStr = item.getString("promisedDeliveryDate");
-                    if (dateStr != null && dateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
-                        plan.setPromisedDeliveryDate(LocalDate.parse(dateStr));
-                    }
-                }
-                productionPlanService.save(plan);
-                createdPlans.add(plan);
-                success++;
-            } catch (Exception e) {
-                log.warn("鍒涘缓鐢熶骇璁″垝澶辫触: {}", e.getMessage());
-                fail++;
-            }
-        }
-
-        // 鎸塸roductModelId鍒嗙粍锛岃嚜鍔ㄥ悎骞朵笅鍙�
-        Map<Long, List<ProductionPlan>> grouped = createdPlans.stream()
-                .filter(p -> p.getProductModelId() != null)
-                .collect(Collectors.groupingBy(ProductionPlan::getProductModelId));
-        for (Map.Entry<Long, List<ProductionPlan>> entry : grouped.entrySet()) {
-            try {
-                List<Long> planIds = entry.getValue().stream().map(ProductionPlan::getId).collect(Collectors.toList());
-                BigDecimal totalQty = entry.getValue().stream()
-                        .map(ProductionPlan::getQtyRequired)
-                        .reduce(BigDecimal.ZERO, BigDecimal::add);
-                ProductionPlanDto combineDto = new ProductionPlanDto();
-                combineDto.setIds(planIds);
-                combineDto.setTotalAssignedQuantity(totalQty);
-                combineDto.setPlanCompleteTime(LocalDate.now().plusDays(ThreadLocalRandom.current().nextInt(3, 10)));
-                productionPlanService.combine(combineDto);
-                log.info("鐢熶骇璁″垝鑷姩涓嬪彂鎴愬姛, productModelId={}, 璁″垝鏁�: {}, 涓嬪彂鏁伴噺: {}",
-                        entry.getKey(), planIds.size(), totalQty);
-            } catch (Exception e) {
-                log.warn("鐢熶骇璁″垝鑷姩涓嬪彂澶辫触, productModelId={}: {}", entry.getKey(), e.getMessage());
-            }
-        }
-
-        return summary("production", "鐢熶骇璁″垝", items.size(), success, fail);
-    }
-
-    // ---- Tier 2: 鍚庣画鍗曟嵁 ----
-
-    private ModuleSummary createProductionOrders(List<JSONObject> items) {
-        int success = 0, fail = 0;
-        for (JSONObject item : items) {
-            try {
-                ProductionOrder order = new ProductionOrder();
-                order.setProductModelId(item.getLong("productModelId"));
-                order.setQuantity(item.getBigDecimal("quantity"));
-                if (item.containsKey("planCompleteTime")) {
-                    String dateStr = item.getString("planCompleteTime");
-                    if (dateStr != null && dateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
-                        order.setPlanCompleteTime(LocalDate.parse(dateStr));
-                    }
-                }
-                productionOrderService.saveProductionOrder(order);
-                success++;
-            } catch (Exception e) {
-                log.warn("鍒涘缓鐢熶骇璁㈠崟澶辫触: {}", e.getMessage());
-                fail++;
-            }
-        }
-        return summary("production", "鐢熶骇璁㈠崟", items.size(), success, fail);
-    }
-
-    private ModuleSummary createQualityBindings(List<JSONObject> items) {
-        int success = 0, fail = 0;
-        for (JSONObject item : items) {
-            try {
-                QualityTestStandardBinding binding = new QualityTestStandardBinding();
-                binding.setProductId(item.getLong("productId"));
-                binding.setTestStandardId(item.getInteger("testStandardId"));
-                qualityTestStandardBindingService.add(List.of(binding));
-                success++;
-            } catch (Exception e) {
-                log.warn("鍒涘缓鎸囨爣缁戝畾澶辫触: {}", e.getMessage());
-                fail++;
-            }
-        }
-        return summary("quality", "鎸囨爣缁戝畾", items.size(), success, fail);
-    }
-
-    private ModuleSummary createStockInventories(List<JSONObject> items) {
-        int success = 0, fail = 0;
-        for (JSONObject item : items) {
-            try {
-                StockInventoryDto dto = new StockInventoryDto();
-                dto.setProductModelId(item.getLong("productModelId"));
-                dto.setQualitity(item.getBigDecimal("qualitity"));
-                dto.setBatchNo(item.getString("batchNo"));
-                dto.setWarnNum(item.getBigDecimal("warnNum"));
-                dto.setRemark(item.getString("remark"));
-                stockInventoryService.addstockInventory(dto);
-                success++;
-            } catch (Exception e) {
-                log.warn("鍒涘缓搴撳瓨璁板綍澶辫触: {}", e.getMessage());
-                fail++;
-            }
-        }
-        return summary("stock", "搴撳瓨璁板綍", items.size(), success, fail);
-    }
-
-    private ModuleSummary summary(String module, String entityName, int total, int success, int fail) {
-        ModuleSummary s = new ModuleSummary();
-        s.setModule(module);
-        s.setEntityName(entityName);
-        s.setGeneratedCount(total);
-        s.setSuccessCount(success);
-        s.setFailCount(fail);
-        return s;
-    }
-}
diff --git a/src/main/java/com/ruoyi/mock/vo/DataCheckResult.java b/src/main/java/com/ruoyi/mock/vo/DataCheckResult.java
deleted file mode 100644
index ed48b72..0000000
--- a/src/main/java/com/ruoyi/mock/vo/DataCheckResult.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.ruoyi.mock.vo;
-
-import lombok.Data;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 鍩虹鏁版嵁妫�娴嬬粨鏋�
- */
-@Data
-public class DataCheckResult {
-
-    /** 妫�娴嬮」鎬绘暟 */
-    private int totalItems;
-    /** 宸查�氳繃鐨勬娴嬮」鏁伴噺 */
-    private int passedItems;
-    /** 妫�娴嬫槑缁� */
-    private List<CheckItem> items = new ArrayList<>();
-
-    @Data
-    public static class CheckItem {
-        /** 妯″潡锛歴ales / purchase / quality / common */
-        private String module;
-        /** 妫�娴嬮」鍚嶇О */
-        private String itemName;
-        /** 鎵�闇�鏈�浣庢暟閲� */
-        private int minRequired;
-        /** 褰撳墠瀹為檯鏁伴噺 */
-        private int currentCount;
-        /** 鏄惁閫氳繃 */
-        private boolean passed;
-        /** 鎻愮ず淇℃伅 */
-        private String message;
-    }
-}
diff --git a/src/main/java/com/ruoyi/mock/vo/DataGenerateResult.java b/src/main/java/com/ruoyi/mock/vo/DataGenerateResult.java
deleted file mode 100644
index e4487fc..0000000
--- a/src/main/java/com/ruoyi/mock/vo/DataGenerateResult.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.ruoyi.mock.vo;
-
-import lombok.Data;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * AI鏁版嵁鐢熸垚缁撴灉
- */
-@Data
-public class DataGenerateResult {
-
-    /** 鐢熸垚鐘舵��: SUCCESS / PARTIAL / FAILED */
-    private String status;
-
-    /** 鎬昏鐢熸垚鏉℃暟 */
-    private int totalGenerated;
-
-    /** 鍚勬ā鍧楃敓鎴愭憳瑕� */
-    private List<ModuleSummary> moduleSummaries = new ArrayList<>();
-
-    /** 閿欒淇℃伅锛堝鏈夛級 */
-    private List<String> errors = new ArrayList<>();
-
-    /** 鍩虹鏁版嵁妫�娴嬬粨鏋滐紙鍓嶇疆鏍¢獙鏈�氳繃鏃惰繑鍥烇級 */
-    private DataCheckResult checkResult;
-
-    @Data
-    public static class ModuleSummary {
-        private String module;
-        private String entityName;
-        private int generatedCount;
-        private int successCount;
-        private int failCount;
-    }
-}
diff --git a/src/main/java/com/ruoyi/quality/utils/QualityInspectHelper.java b/src/main/java/com/ruoyi/quality/utils/QualityInspectHelper.java
deleted file mode 100644
index 766515a..0000000
--- a/src/main/java/com/ruoyi/quality/utils/QualityInspectHelper.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.ruoyi.quality.utils;
-
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.ruoyi.common.utils.bean.BeanUtils;
-import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.quality.mapper.QualityInspectMapper;
-import com.ruoyi.quality.mapper.QualityInspectParamMapper;
-import com.ruoyi.quality.mapper.QualityTestStandardMapper;
-import com.ruoyi.quality.mapper.QualityTestStandardParamMapper;
-import com.ruoyi.quality.pojo.QualityInspect;
-import com.ruoyi.quality.pojo.QualityInspectParam;
-import com.ruoyi.quality.pojo.QualityTestStandard;
-import com.ruoyi.quality.pojo.QualityTestStandardParam;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-
-/**
- * 璐ㄦ鍗曞垱寤哄伐鍏风被
- */
-@Component
-@RequiredArgsConstructor
-public class QualityInspectHelper {
-
-    private final QualityInspectMapper qualityInspectMapper;
-    private final QualityTestStandardMapper qualityTestStandardMapper;
-    private final QualityTestStandardParamMapper qualityTestStandardParamMapper;
-    private final QualityInspectParamMapper qualityInspectParamMapper;
-
-    /**
-     * 鍒涘缓璐ㄦ鍗�
-     * @param purchaseLedger 閲囪喘鍙拌处
-     * @param saleProduct 閲囪喘浜у搧
-     */
-    public void addQualityInspect(PurchaseLedger purchaseLedger, SalesLedgerProduct saleProduct) {
-        QualityInspect qualityInspect = new QualityInspect();
-        qualityInspect.setInspectType(0);
-        qualityInspect.setSupplier(purchaseLedger.getSupplierName());
-        qualityInspect.setPurchaseLedgerId(purchaseLedger.getId());
-        qualityInspect.setProductId(saleProduct.getProductId());
-        qualityInspect.setProductName(saleProduct.getProductCategory());
-        qualityInspect.setModel(saleProduct.getSpecificationModel());
-        qualityInspect.setProductModelId(saleProduct.getProductModelId());
-        qualityInspect.setUnit(saleProduct.getUnit());
-        qualityInspect.setQuantity(saleProduct.getQuantity());
-        qualityInspectMapper.insert(qualityInspect);
-
-        List<QualityTestStandard> qualityTestStandardList = qualityTestStandardMapper
-                .getQualityTestStandardByProductId(saleProduct.getProductId(), 0, null);
-
-        if (qualityTestStandardList.isEmpty()) {
-            return;
-        }
-
-        QualityTestStandard firstStandard = qualityTestStandardList.get(0);
-        qualityInspect.setTestStandardId(firstStandard.getId());
-        qualityInspectMapper.updateById(qualityInspect);
-
-        List<QualityTestStandardParam> standardParams = qualityTestStandardParamMapper.selectList(
-                Wrappers.<QualityTestStandardParam>lambdaQuery()
-                        .eq(QualityTestStandardParam::getTestStandardId, firstStandard.getId()));
-
-        for (QualityTestStandardParam standardParam : standardParams) {
-            QualityInspectParam param = new QualityInspectParam();
-            BeanUtils.copyProperties(standardParam, param);
-            param.setId(null);
-            param.setInspectId(qualityInspect.getId());
-            qualityInspectParamMapper.insert(param);
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/staff/dto/StaffSalaryCalculateDto.java b/src/main/java/com/ruoyi/staff/dto/StaffSalaryCalculateDto.java
deleted file mode 100644
index ef0a50e..0000000
--- a/src/main/java/com/ruoyi/staff/dto/StaffSalaryCalculateDto.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.staff.dto;
-
-import com.ruoyi.staff.pojo.StaffSalaryDetail;
-import lombok.Data;
-
-/**
- * 鍗曚釜鍛樺伐宸ヨ祫閲嶇畻鍙傛暟
- */
-@Data
-public class StaffSalaryCalculateDto extends StaffSalaryDetail {
-
-    /**
-     * 宸ヨ祫鏈堜唤锛屾牸寮� yyyy-MM
-     */
-    private String salaryMonth;
-}
diff --git a/src/main/java/com/ruoyi/staff/excel/StaffSalaryExportData.java b/src/main/java/com/ruoyi/staff/excel/StaffSalaryExportData.java
deleted file mode 100644
index c1f2725..0000000
--- a/src/main/java/com/ruoyi/staff/excel/StaffSalaryExportData.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.ruoyi.staff.excel;
-
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * 鍛樺伐钖祫瀵煎嚭鏁版嵁
- */
-@Data
-public class StaffSalaryExportData {
-
-    @Excel(name = "宸ヨ祫鏈堜唤")
-    private String salaryMonth;
-
-    @Excel(name = "宸ヨ祫涓婚")
-    private String salaryTitle;
-
-    @Excel(name = "鍛樺伐濮撳悕")
-    private String staffName;
-
-    @Excel(name = "閮ㄩ棬鍚嶇О")
-    private String deptName;
-
-    @Excel(name = "鍩烘湰宸ヨ祫")
-    private BigDecimal basicSalary;
-
-    @Excel(name = "璁′欢宸ヨ祫")
-    private BigDecimal pieceSalary;
-
-    @Excel(name = "璁℃椂宸ヨ祫")
-    private BigDecimal hourlySalary;
-
-    @Excel(name = "鍏朵粬鏀跺叆")
-    private BigDecimal otherIncome;
-
-    @Excel(name = "绀句繚涓汉")
-    private BigDecimal socialPersonal;
-
-    @Excel(name = "鍏Н閲戜釜浜�")
-    private BigDecimal fundPersonal;
-
-    @Excel(name = "鍏朵粬鏀嚭")
-    private BigDecimal otherDeduct;
-
-    @Excel(name = "绀句繚琛ョ即")
-    private BigDecimal socialSupplementAmount;
-
-    @Excel(name = "宸ヨ祫涓◣")
-    private BigDecimal salaryTax;
-
-    @Excel(name = "搴斿彂宸ヨ祫")
-    private BigDecimal grossSalary;
-
-    @Excel(name = "搴旀墸宸ヨ祫")
-    private BigDecimal deductSalary;
-
-    @Excel(name = "瀹炲彂宸ヨ祫")
-    private BigDecimal netSalary;
-
-    @Excel(name = "澶囨敞")
-    private String remark;
-}
diff --git a/src/main/java/com/ruoyi/staff/init/DataInitializer.java b/src/main/java/com/ruoyi/staff/init/DataInitializer.java
deleted file mode 100644
index 1432d2e..0000000
--- a/src/main/java/com/ruoyi/staff/init/DataInitializer.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.ruoyi.staff.init;
-
-import com.ruoyi.staff.mapper.PersonalAttendanceLocationConfigMapper;
-import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.ApplicationArguments;
-import org.springframework.boot.ApplicationRunner;
-import org.springframework.stereotype.Component;
-
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class DataInitializer implements ApplicationRunner {
-
-    private final PersonalAttendanceLocationConfigMapper configMapper;
-
-    @Override
-    public void run(ApplicationArguments args) {
-        initLeaveConfig();
-    }
-
-    private void initLeaveConfig() {
-        PersonalAttendanceLocationConfig config = configMapper.selectById(999);
-        if (config == null) {
-            config = new PersonalAttendanceLocationConfig();
-            config.setId(999);
-            config.setShift("璇峰亣");
-            configMapper.insert(config);
-            log.info("宸插垵濮嬪寲璇峰亣鐝閰嶇疆(id=999)");
-        }
-    }
-}
diff --git a/src/main/resources/mapper/approve/ApprovalInstanceMapper.xml b/src/main/resources/mapper/approve/ApprovalInstanceMapper.xml
deleted file mode 100644
index f3720c2..0000000
--- a/src/main/resources/mapper/approve/ApprovalInstanceMapper.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.approve.mapper.ApprovalInstanceMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalInstance">
-        <id column="id" property="id" />
-        <result column="instance_no" property="instanceNo" />
-        <result column="template_id" property="templateId" />
-        <result column="template_name" property="templateName" />
-        <result column="business_id" property="businessId" />
-        <result column="business_type" property="businessType" />
-        <result column="title" property="title" />
-        <result column="status" property="status" />
-        <result column="current_level" property="currentLevel" />
-        <result column="applicant_id" property="applicantId" />
-        <result column="applicant_name" property="applicantName" />
-        <result column="apply_time" property="applyTime" />
-        <result column="finish_time" property="finishTime" />
-        <result column="create_user" property="createUser" />
-        <result column="create_time" property="createTime" />
-        <result column="update_user" property="updateUser" />
-        <result column="update_time" property="updateTime" />
-        <result column="deleted" property="deleted" />
-    </resultMap>
-    <select id="listPage" resultType="com.ruoyi.approve.bean.vo.ApprovalInstanceVo">
-        select ai.*,su.nick_name as create_user_name from
-        approval_instance ai
-        left join sys_user su on ai.create_user = su.user_id
-        <where>
-            deleted = 0
-            <if test="ew.id != null">
-                and ai.id = #{ew.id}
-            </if>
-            <if test="ew.instanceNo != null">
-                and ai.instance_no like concat('%',#{ew.instanceNo},'%')
-            </if>
-            <if test="ew.templateName != null">
-                and ai.template_name like concat('%',#{ew.templateName},'%')
-            </if>
-            <if test="ew.templateId != null ">
-                and ai. template_id = #{ew.templateId}
-            </if>
-            <if test="ew.businessType != null ">
-                and ai.business_type = #{ew.businessType}
-            </if>
-            <if test="ew.createTimeStart != null and ew.createTimeEnd != null">
-                and ai.apply_time &gt;= #{ew.createTimeStart}
-                and ai.apply_time &lt;= #{ew.createTimeEnd}
-            </if>
-            <if test="ew.status != null">
-                and ai.status = #{ew.status}
-            </if>
-            <if test="ew.applicantName != null and ew.applicantName !=''">
-                and ai.applicant_name = #{ew.applicantName}
-            </if>
-        </where>
-        order by ai.create_time desc
-    </select>
-
-</mapper>
diff --git a/src/main/resources/mapper/approve/ApprovalInstanceNodeMapper.xml b/src/main/resources/mapper/approve/ApprovalInstanceNodeMapper.xml
deleted file mode 100644
index 560271b..0000000
--- a/src/main/resources/mapper/approve/ApprovalInstanceNodeMapper.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.approve.mapper.ApprovalInstanceNodeMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalInstanceNode">
-        <id column="id" property="id" />
-        <result column="instance_id" property="instanceId" />
-        <result column="level_no" property="levelNo" />
-        <result column="approve_type" property="approveType" />
-        <result column="status" property="status" />
-        <result column="start_time" property="startTime" />
-        <result column="finish_time" property="finishTime" />
-        <result column="create_user" property="createUser" />
-        <result column="create_time" property="createTime" />
-        <result column="update_user" property="updateUser" />
-        <result column="update_time" property="updateTime" />
-        <result column="deleted" property="deleted" />
-    </resultMap>
-
-</mapper>
diff --git a/src/main/resources/mapper/approve/ApprovalRecordMapper.xml b/src/main/resources/mapper/approve/ApprovalRecordMapper.xml
deleted file mode 100644
index db40692..0000000
--- a/src/main/resources/mapper/approve/ApprovalRecordMapper.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.approve.mapper.ApprovalRecordMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalRecord">
-        <id column="id" property="id" />
-        <result column="instance_id" property="instanceId" />
-        <result column="node_id" property="nodeId" />
-        <result column="task_id" property="taskId" />
-        <result column="operator_id" property="operatorId" />
-        <result column="operator_name" property="operatorName" />
-        <result column="action" property="action" />
-        <result column="comment" property="comment" />
-        <result column="create_user" property="createUser" />
-        <result column="create_time" property="createTime" />
-        <result column="deleted" property="deleted" />
-    </resultMap>
-
-</mapper>
diff --git a/src/main/resources/mapper/approve/ApprovalTaskMapper.xml b/src/main/resources/mapper/approve/ApprovalTaskMapper.xml
deleted file mode 100644
index c079440..0000000
--- a/src/main/resources/mapper/approve/ApprovalTaskMapper.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.approve.mapper.ApprovalTaskMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalTask">
-        <id column="id" property="id" />
-        <result column="instance_id" property="instanceId" />
-        <result column="node_id" property="nodeId" />
-        <result column="level_no" property="levelNo" />
-        <result column="approver_id" property="approverId" />
-        <result column="approver_name" property="approverName" />
-        <result column="task_status" property="taskStatus" />
-        <result column="approve_time" property="approveTime" />
-        <result column="comment" property="comment" />
-        <result column="is_read" property="isRead" />
-        <result column="create_user" property="createUser" />
-        <result column="create_time" property="createTime" />
-        <result column="update_user" property="updateUser" />
-        <result column="update_time" property="updateTime" />
-        <result column="deleted" property="deleted" />
-    </resultMap>
-
-</mapper>
diff --git a/src/main/resources/mapper/approve/ApprovalTemplateMapper.xml b/src/main/resources/mapper/approve/ApprovalTemplateMapper.xml
deleted file mode 100644
index a48432b..0000000
--- a/src/main/resources/mapper/approve/ApprovalTemplateMapper.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.approve.mapper.ApprovalTemplateMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalTemplate">
-        <id column="id" property="id" />
-        <result column="template_name" property="templateName" />
-        <result column="enabled" property="enabled" />
-        <result column="description" property="description" />
-        <result column="deleted" property="deleted" />
-        <result column="dept_id" property="deptId" />
-    </resultMap>
-    <select id="listPage" resultType="com.ruoyi.approve.bean.vo.ApprovalTemplateVo">
-        select at.*,su.nick_name as create_user_name  from
-        approval_template at
-        left join sys_user su on at.create_user = su.user_id
-        <where>
-            deleted = 0
-            <if test="ew.templateName != null">
-                and template_name like concat('%',#{ew.templateName},'%')
-            </if>
-            <if test="ew.templateType != null">
-                and template_type = #{ew.templateType}
-            </if>
-            <if test="ew.enabled != null">
-                and enabled = #{ew.enabled}
-            </if>
-        </where>
-        order by at.id desc
-    </select>
-
-</mapper>
diff --git a/src/main/resources/mapper/approve/ApprovalTemplateNodeApproverMapper.xml b/src/main/resources/mapper/approve/ApprovalTemplateNodeApproverMapper.xml
deleted file mode 100644
index dac42cc..0000000
--- a/src/main/resources/mapper/approve/ApprovalTemplateNodeApproverMapper.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover">
-        <id column="id" property="id" />
-        <result column="node_id" property="nodeId" />
-        <result column="template_id" property="templateId" />
-        <result column="approver_id" property="approverId" />
-        <result column="approver_name" property="approverName" />
-        <result column="sort_no" property="sortNo" />
-        <result column="created_time" property="createdTime" />
-    </resultMap>
-
-</mapper>
diff --git a/src/main/resources/mapper/approve/ApprovalTemplateNodeMapper.xml b/src/main/resources/mapper/approve/ApprovalTemplateNodeMapper.xml
deleted file mode 100644
index 7956787..0000000
--- a/src/main/resources/mapper/approve/ApprovalTemplateNodeMapper.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.approve.mapper.ApprovalTemplateNodeMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalTemplateNode">
-        <id column="id" property="id" />
-        <result column="template_id" property="templateId" />
-        <result column="level_no" property="levelNo" />
-        <result column="approve_type" property="approveType" />
-        <result column="created_time" property="createdTime" />
-        <result column="updated_time" property="updatedTime" />
-    </resultMap>
-
-</mapper>
diff --git a/src/main/resources/mapper/approve/FinReimbursementDetailMapper.xml b/src/main/resources/mapper/approve/FinReimbursementDetailMapper.xml
deleted file mode 100644
index f8a67bb..0000000
--- a/src/main/resources/mapper/approve/FinReimbursementDetailMapper.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.approve.mapper.FinReimbursementDetailMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.FinReimbursementDetail">
-        <id column="id" property="id" />
-        <result column="reimbursement_id" property="reimbursementId" />
-        <result column="row_no" property="rowNo" />
-        <result column="invoice_date" property="invoiceDate" />
-        <result column="expense_category" property="expenseCategory" />
-        <result column="amount" property="amount" />
-        <result column="description" property="description" />
-        <result column="invoice_no" property="invoiceNo" />
-        <result column="invoice_type" property="invoiceType" />
-        <result column="invoice_amount" property="invoiceAmount" />
-        <result column="tax_rate" property="taxRate" />
-        <result column="tax_amount" property="taxAmount" />
-        <result column="remark" property="remark" />
-        <result column="tenant_id" property="tenantId" />
-        <result column="create_user" property="createUser" />
-        <result column="create_time" property="createTime" />
-        <result column="update_user" property="updateUser" />
-        <result column="update_time" property="updateTime" />
-        <result column="dept_id" property="deptId" />
-        <result column="deleted" property="deleted" />
-    </resultMap>
-
-</mapper>
diff --git a/src/main/resources/mapper/approve/FinReimbursementMapper.xml b/src/main/resources/mapper/approve/FinReimbursementMapper.xml
deleted file mode 100644
index 6b4931c..0000000
--- a/src/main/resources/mapper/approve/FinReimbursementMapper.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.approve.mapper.FinReimbursementMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.FinReimbursement">
-        <id column="id" property="id" />
-        <result column="bill_no" property="billNo" />
-        <result column="reimbursement_type" property="reimbursementType" />
-        <result column="expense_type" property="expenseType" />
-        <result column="applicant_id" property="applicantId" />
-        <result column="applicant_code" property="applicantCode" />
-        <result column="applicant_name" property="applicantName" />
-        <result column="applicant_dept_id" property="applicantDeptId" />
-        <result column="applicant_dept_name" property="applicantDeptName" />
-        <result column="reason" property="reason" />
-        <result column="apply_amount" property="applyAmount" />
-        <result column="detail_total_amount" property="detailTotalAmount" />
-        <result column="payee_name" property="payeeName" />
-        <result column="payee_account" property="payeeAccount" />
-        <result column="payee_bank" property="payeeBank" />
-        <result column="approval_instance_id" property="approvalInstanceId" />
-        <result column="approve_process_id" property="approveProcessId" />
-        <result column="bill_status" property="billStatus" />
-        <result column="approved_time" property="approvedTime" />
-        <result column="paid_time" property="paidTime" />
-        <result column="account_expense_id" property="accountExpenseId" />
-        <result column="remark" property="remark" />
-        <result column="tenant_id" property="tenantId" />
-        <result column="create_user" property="createUser" />
-        <result column="create_time" property="createTime" />
-        <result column="update_user" property="updateUser" />
-        <result column="update_time" property="updateTime" />
-        <result column="dept_id" property="deptId" />
-        <result column="deleted" property="deleted" />
-    </resultMap>
-    <select id="listPage" resultType="com.ruoyi.approve.bean.vo.FinReimbursementVo">
-        select fin_reimbursement.*,
-        fin_reimbursement_travel.start_time ,
-        fin_reimbursement_travel.end_time
-               from
-                fin_reimbursement
-            left join fin_reimbursement_travel on fin_reimbursement.id = fin_reimbursement_travel.reimbursement_id
-        <where>
-            <if test="ew.billNo != null and ew.billNo != ''">
-                bill_no like concat('%',#{ew.billNo},'%')
-            </if>
-            <if test="ew.applicantName != null and ew.applicantName != ''">
-                and applicant_name like concat('%',#{ew.applicantName},'%')
-            </if>
-            <if test="ew.applicantCode != null and ew.applicantCode != ''">
-                and applicant_code like concat('%',#{ew.applicantCode},'%')
-            </if>
-            <if test="ew.createTimeStart != null and ew.createTimeStart !='' and ew.createTimeEnd != null and ew.createTimeEnd != ''">
-                and create_time &gt;= #{ew.createTimeStart}
-                and create_time &lt;= #{ew.createTimeEnd}
-            </if>
-        </where>
-        order by create_time desc
-    </select>
-
-</mapper>
diff --git a/src/main/resources/mapper/approve/FinReimbursementTravelMapper.xml b/src/main/resources/mapper/approve/FinReimbursementTravelMapper.xml
deleted file mode 100644
index dc42863..0000000
--- a/src/main/resources/mapper/approve/FinReimbursementTravelMapper.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.approve.mapper.FinReimbursementTravelMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.FinReimbursementTravel">
-        <id column="id" property="id" />
-        <result column="reimbursement_id" property="reimbursementId" />
-        <result column="start_time" property="startTime" />
-        <result column="end_time" property="endTime" />
-        <result column="travel_days" property="travelDays" />
-        <result column="departure_city" property="departureCity" />
-        <result column="destination_city" property="destinationCity" />
-        <result column="hotel_standard" property="hotelStandard" />
-        <result column="lodging_days" property="lodgingDays" />
-        <result column="meal_allowance" property="mealAllowance" />
-        <result column="transport_allowance" property="transportAllowance" />
-        <result column="lodging_limit" property="lodgingLimit" />
-        <result column="standard_tag" property="standardTag" />
-        <result column="within_standard" property="withinStandard" />
-        <result column="tenant_id" property="tenantId" />
-        <result column="create_user" property="createUser" />
-        <result column="create_time" property="createTime" />
-        <result column="update_user" property="updateUser" />
-        <result column="update_time" property="updateTime" />
-        <result column="dept_id" property="deptId" />
-    </resultMap>
-
-</mapper>
diff --git a/src/main/resources/mapper/collaborativeApproval/EnterpriseNewsMapper.xml b/src/main/resources/mapper/collaborativeApproval/EnterpriseNewsMapper.xml
deleted file mode 100644
index 830a858..0000000
--- a/src/main/resources/mapper/collaborativeApproval/EnterpriseNewsMapper.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.collaborativeApproval.pojo.EnterpriseNews">
-        <id column="id" property="id" />
-        <result column="title" property="title" />
-        <result column="summary" property="summary" />
-        <result column="content" property="content" />
-        <result column="category" property="category" />
-        <result column="read_scope" property="readScope" />
-        <result column="is_required" property="isRequired" />
-        <result column="status" property="status" />
-        <result column="required_read_count" property="requiredReadCount" />
-        <result column="read_count" property="readCount" />
-        <result column="create_user" property="createUser" />
-        <result column="create_time" property="createTime" />
-        <result column="update_user" property="updateUser" />
-        <result column="update_time" property="updateTime" />
-        <result column="dept_id" property="deptId" />
-    </resultMap>
-    <select id="listPage" resultType="com.ruoyi.collaborativeApproval.vo.EnterpriseNewsVo">
-        select en.*, u.nick_name as create_user_name from
-        enterprise_news en
-        left join sys_user u on en.create_user = u.user_id
-        <where>
-            <if test="enterpriseNewsDto.title != null and enterpriseNewsDto.title != ''">
-                and en.title like concat('%',#{enterpriseNewsDto.title},'%')
-            </if>
-            <if test="enterpriseNewsDto.category != null and enterpriseNewsDto.category != ''">
-                and en.category = #{enterpriseNewsDto.category}
-            </if>
-            <if test="enterpriseNewsDto.status != null ">
-                and en.status = #{enterpriseNewsDto.status}
-            </if>
-            <if test="enterpriseNewsDto.createUser != null and enterpriseNewsDto.createUser != ''">
-                and en.create_user = #{enterpriseNewsDto.createUser}
-            </if>
-            <if test="enterpriseNewsDto.createTimeStart != null and enterpriseNewsDto.createTimeEnd != null">
-                and en.create_time between #{enterpriseNewsDto.createTimeStart} and #{enterpriseNewsDto.createTimeEnd}
-            </if>
-        </where>
-        order by en.create_time desc
-    </select>
-
-</mapper>
diff --git a/src/main/resources/mapper/collaborativeApproval/EnterpriseNewsScopeDeptMapper.xml b/src/main/resources/mapper/collaborativeApproval/EnterpriseNewsScopeDeptMapper.xml
deleted file mode 100644
index 0b13f67..0000000
--- a/src/main/resources/mapper/collaborativeApproval/EnterpriseNewsScopeDeptMapper.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeDeptMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept">
-        <id column="id" property="id" />
-        <result column="news_id" property="newsId" />
-        <result column="dept_id" property="deptId" />
-        <result column="create_time" property="createTime" />
-    </resultMap>
-
-</mapper>
diff --git a/src/main/resources/mapper/collaborativeApproval/EnterpriseNewsScopeUserMapper.xml b/src/main/resources/mapper/collaborativeApproval/EnterpriseNewsScopeUserMapper.xml
deleted file mode 100644
index 7f4ac4b..0000000
--- a/src/main/resources/mapper/collaborativeApproval/EnterpriseNewsScopeUserMapper.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeUserMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser">
-        <id column="id" property="id" />
-        <result column="news_id" property="newsId" />
-        <result column="user_id" property="userId" />
-        <result column="create_time" property="createTime" />
-    </resultMap>
-
-</mapper>

--
Gitblit v1.9.3