From 9d66bfbfcda297f628e6a857e343f98422f4534a Mon Sep 17 00:00:00 2001
From: liyong <18434998025@163.com>
Date: 星期五, 22 五月 2026 09:32:28 +0800
Subject: [PATCH] Merge remote-tracking branch 'refs/remotes/origin/dev_New_pro' into dev_New_pro_OA

---
 src/main/java/com/ruoyi/ai/assistant/ApproveTodoIntentExecutor.java                             |  199 
 src/main/java/com/ruoyi/project/system/controller/SysMenuController.java                        |  270 
 src/main/java/com/ruoyi/account/controller/financial/AccountSubjectController.java              |    8 
 src/main/java/com/ruoyi/purchase/vo/SupplierTransactionsVo.java                                 |   30 
 src/main/java/com/ruoyi/ai/controller/SalesAiController.java                                    |  141 
 src/main/resources/mapper/basic/ProductModelMapper.xml                                          |    1 
 src/main/java/com/ruoyi/warehouse/mapper/DocumentationFileMapper.java                           |    3 
 doc/financial-ai-front-integration.md                                                           |  192 
 src/main/resources/application-dev.yml                                                          |    3 
 src/main/java/com/ruoyi/account/service/purchase/AccountPaymentApplicationService.java          |   33 
 src/main/java/com/ruoyi/quality/controller/QualityReportController.java                         |   34 
 src/main/java/com/ruoyi/project/common/CaptchaController.java                                   |  196 
 src/main/java/com/ruoyi/ai/tools/ApproveTodoTools.java                                          |   17 
 src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java                                    |    3 
 src/main/resources/mapper/procurementrecord/ReturnManagementMapper.xml                          |    5 
 src/main/java/com/ruoyi/account/controller/sales/AccountSalesInvoiceController.java             |   72 
 src/main/java/com/ruoyi/account/service/sales/AccountSalesService.java                          |   10 
 src/main/java/com/ruoyi/account/service/financial/AccountPurchaseService.java                   |   10 
 src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java         |   17 
 src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java                    |   45 
 src/main/java/com/ruoyi/account/controller/sales/AccountSalesCollectionController.java          |   79 
 src/main/java/com/ruoyi/account/bean/vo/financial/AccountSubjectVo.java                         |    4 
 src/main/java/com/ruoyi/account/bean/vo/purchase/AccountPurchasePaymentVo.java                  |   34 
 src/main/java/com/ruoyi/account/controller/AccountStatementController.java                      |   71 
 src/main/java/com/ruoyi/project/system/controller/SysConfigController.java                      |  254 
 src/main/java/com/ruoyi/project/monitor/controller/ServerController.java                        |   54 
 src/main/java/com/ruoyi/account/controller/sales/AccountInvoiceApplicationController.java       |   86 
 src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java              |   35 
 src/main/java/com/ruoyi/basic/mapper/SupplierManageMapper.java                                  |    6 
 src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml                                  |    2 
 src/main/java/com/ruoyi/account/bean/dto/purchase/PurchaseInboundDto.java                       |   10 
 src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java                                        |  311 
 src/main/resources/mapper/account/purchase/AccountPaymentApplicationMapper.xml                  |   98 
 src/main/java/com/ruoyi/project/monitor/controller/CacheController.java                         |  222 
 src/main/java/com/ruoyi/sales/service/ISalesLedgerProductService.java                           |    7 
 src/main/resources/financial-agent-prompt.txt                                                   |   11 
 src/main/java/com/ruoyi/account/pojo/purchase/AccountPurchaseInvoice.java                       |  168 
 src/main/resources/mapper/account/sales/AccountSalesInvoiceMapper.xml                           |   47 
 src/main/java/com/ruoyi/account/bean/dto/purchase/AccountPaymentApplicationDto.java             |   34 
 src/main/java/com/ruoyi/account/bean/vo/sales/AccountInvoiceApplicationVo.java                  |   23 
 src/main/java/com/ruoyi/purchase/mapper/PurchaseLedgerMapper.java                               |    3 
 src/main/java/com/ruoyi/project/system/controller/SysRoleController.java                        |  510 
 src/main/java/com/ruoyi/account/bean/vo/sales/SalesReturnVo.java                                |    2 
 src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java                 |  166 
 src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java                                         |    5 
 src/main/resources/sales-agent-prompt.txt                                                       |    9 
 doc/20260520_首页生产看板性能优化前端变更文档.md                                                                |  107 
 src/main/java/com/ruoyi/quality/controller/QualityInspectController.java                        |   48 
 src/main/java/com/ruoyi/account/mapper/purchase/AccountPaymentApplicationMapper.java            |   32 
 src/main/java/com/ruoyi/ai/controller/XiaozhiController.java                                    |   42 
 src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java          |    3 
 src/main/java/com/ruoyi/warehouse/service/DocumentationFileService.java                         |    3 
 src/main/java/com/ruoyi/ai/config/SalesAgentConfig.java                                         |   21 
 src/main/java/com/ruoyi/staff/service/impl/StaffSalaryMainServiceImpl.java                      |   20 
 src/main/java/com/ruoyi/procurementrecord/controller/ReturnManagementController.java            |   14 
 src/main/java/com/ruoyi/purchase/vo/SupplierTransactionsDetailsVo.java                          |   33 
 src/main/java/com/ruoyi/account/bean/dto/purchase/AccountPurchaseInvoiceDto.java                |   32 
 src/main/java/com/ruoyi/ai/assistant/SalesIntentExecutor.java                                   |  270 
 src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java                                         |   14 
 src/main/java/com/ruoyi/account/mapper/AccountStatementMapper.java                              |   25 
 src/main/resources/mapper/account/AccountStatementMapper.xml                                    |   43 
 src/main/java/com/ruoyi/account/bean/dto/sales/AccountSalesCollectionDto.java                   |   34 
 src/main/java/com/ruoyi/account/mapper/sales/AccountSalesInvoiceMapper.java                     |   24 
 src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java                                  |    4 
 src/main/java/com/ruoyi/purchase/mapper/PurchaseReturnOrdersMapper.java                         |    4 
 src/main/resources/manufacturing-agent-prompt.txt                                               |    2 
 src/main/java/com/ruoyi/account/pojo/purchase/AccountPurchasePayment.java                       |  127 
 src/main/java/com/ruoyi/account/mapper/financial/AccountSubjectMapper.java                      |    4 
 src/main/java/com/ruoyi/account/service/impl/financial/FinVoucherServiceImpl.java               |    4 
 src/main/java/com/ruoyi/account/service/sales/AccountInvoiceApplicationService.java             |   33 
 src/main/java/com/ruoyi/sales/vo/CustomerTransactionsDetailsVo.java                             |   33 
 src/main/java/com/ruoyi/ai/tools/FinancialAgentTools.java                                       | 2226 ++++++
 doc/20260518_销售助手前端联调文档.md                                                                      |  188 
 src/main/java/com/ruoyi/account/bean/dto/financial/AccountSubjectImportDto.java                 |    2 
 src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java                    |  240 
 src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java                                           | 1633 +++++
 src/main/java/com/ruoyi/basic/pojo/ProductModel.java                                            |    6 
 src/main/java/com/ruoyi/account/bean/vo/sales/SalesOutboundVo.java                              |    9 
 src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java                                         |    3 
 src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java                             |   12 
 src/main/resources/mapper/stock/StockOutRecordMapper.xml                                        |   12 
 src/main/java/com/ruoyi/account/bean/dto/purchase/PurchaseReturnDto.java                        |   10 
 src/main/java/com/ruoyi/CodeGenerator.java                                                      |    6 
 src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java                       |   12 
 src/main/java/com/ruoyi/procurementrecord/mapper/ReturnManagementMapper.java                    |    4 
 src/main/java/com/ruoyi/warehouse/controller/DocumentationFileController.java                   |    3 
 src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java                            |   21 
 src/main/resources/mapper/account/sales/AccountInvoiceApplicationMapper.xml                     |   73 
 src/main/java/com/ruoyi/account/pojo/AccountStatementDetails.java                               |  115 
 src/main/java/com/ruoyi/account/service/AccountStatementDetailsService.java                     |   16 
 src/main/java/com/ruoyi/ai/assistant/PurchaseIntentExecutor.java                                |  249 
 src/main/java/com/ruoyi/account/service/AccountStatementService.java                            |   32 
 src/main/java/com/ruoyi/account/bean/dto/sales/AccountSalesInvoiceDto.java                      |   33 
 src/main/java/com/ruoyi/account/controller/purchase/AccounPurchaseController.java               |   12 
 src/main/java/com/ruoyi/account/service/impl/sales/AccountInvoiceApplicationServiceImpl.java    |   97 
 src/main/java/com/ruoyi/sales/pojo/SalesLedger.java                                             |   26 
 src/main/java/com/ruoyi/purchase/controller/PurchaseReturnOrdersController.java                 |   14 
 src/main/resources/mapper/purchase/PurchaseReturnOrdersMapper.xml                               |    5 
 src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java                   |   25 
 src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java                                   |    4 
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java                          |   93 
 src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java                       |   27 
 src/main/java/com/ruoyi/ai/service/PurchaseAiService.java                                       |   88 
 src/main/java/com/ruoyi/account/controller/purchase/AccountPaymentApplicationController.java    |   86 
 src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java                                        |   22 
 src/main/java/com/ruoyi/account/bean/vo/sales/AccountSalesCollectionVo.java                     |   26 
 src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java                                     |   15 
 src/main/resources/mapper/stock/StockInventoryMapper.xml                                        |    6 
 src/main/java/com/ruoyi/account/service/sales/AccountSalesCollectionService.java                |   33 
 src/main/java/com/ruoyi/basic/service/ICustomerService.java                                     |   18 
 src/main/java/com/ruoyi/account/service/impl/purchase/AccountPaymentApplicationServiceImpl.java |   96 
 src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java       |   96 
 src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java          |    2 
 src/main/resources/mapper/account/financial/AccountSubjectMapper.xml                            |    4 
 src/main/java/com/ruoyi/account/mapper/sales/AccountSalesCollectionMapper.java                  |   35 
 src/main/java/com/ruoyi/account/service/impl/AccountStatementServiceImpl.java                   |  298 
 src/main/java/com/ruoyi/ai/assistant/SalesAgent.java                                            |   22 
 src/main/java/com/ruoyi/account/service/sales/AccountSalesInvoiceService.java                   |   28 
 src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java                          |  508 
 src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesInvoiceServiceImpl.java          |   53 
 src/main/java/com/ruoyi/account/pojo/AccountStatement.java                                      |  127 
 src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml                                     |   44 
 src/main/java/com/ruoyi/account/bean/dto/StatementAccountDto.java                               |   35 
 src/main/java/com/ruoyi/project/monitor/controller/SysJobController.java                        |  372 
 src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java                             |   12 
 src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java                                  |  171 
 src/main/java/com/ruoyi/account/service/purchase/AccountPurchaseInvoiceService.java             |   31 
 src/main/resources/mapper/sales/SalesLedgerProductMapper.xml                                    |   81 
 src/main/java/com/ruoyi/account/pojo/sales/AccountSalesCollection.java                          |  127 
 src/main/java/com/ruoyi/account/mapper/AccountStatementDetailsMapper.java                       |   18 
 src/main/java/com/ruoyi/project/system/controller/SysRegisterController.java                    |   66 
 doc/20260522_财务升级AI模块前端变更联调文档.md                                                                |  150 
 src/main/java/com/ruoyi/account/controller/sales/AccountSalesController.java                    |   12 
 src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java                   |   57 
 src/main/java/com/ruoyi/project/system/controller/SysProfileController.java                     |  266 
 src/main/java/com/ruoyi/account/service/purchase/AccountSubjectService.java                     |    8 
 src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java                        |   24 
 src/main/java/com/ruoyi/sales/excel/InvoiceLedgerExcelDto.java                                  |    7 
 src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java                         |   16 
 src/main/java/com/ruoyi/account/bean/dto/sales/SalesOutboundDto.java                            |   10 
 src/main/java/com/ruoyi/account/bean/vo/purchase/PurchaseReturnVo.java                          |    2 
 src/main/java/com/ruoyi/ai/controller/FinancialAiController.java                                |  112 
 src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java                               |  137 
 src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java                              |    5 
 src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java                    |  264 
 src/main/java/com/ruoyi/account/pojo/purchase/AccountPaymentApplication.java                    |  141 
 src/main/resources/mapper/basic/SupplierManageMapper.xml                                        |   92 
 src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java                                      |   78 
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java                   |   79 
 doc/20260521_首页HomeController接口升级前端变更文档.md                                                      |  113 
 src/main/resources/mapper/account/purchase/AccountPurchaseInvoiceMapper.xml                     |   86 
 src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java                      |   29 
 src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java                                      |    3 
 src/main/java/com/ruoyi/ai/assistant/FinancialIntentExecutor.java                               |  246 
 src/main/resources/purchase-agent-prompt.txt                                                    |    9 
 src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java                      |  192 
 src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java                                    |    3 
 src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchaseInvoiceMapper.java               |   29 
 src/main/java/com/ruoyi/basic/service/ISupplierService.java                                     |   21 
 src/main/java/com/ruoyi/account/bean/vo/purchase/AccountPurchaseInvoiceVo.java                  |   19 
 src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java                     |    9 
 src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java    |   90 
 src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java                                        |    4 
 src/main/resources/mapper/basic/CustomerMapper.xml                                              |   84 
 src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java                            |    3 
 src/main/java/com/ruoyi/account/bean/dto/purchase/AccountPurchasePaymentDto.java                |   34 
 src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java                    |   56 
 src/main/java/com/ruoyi/project/system/controller/SysLoginController.java                       |  310 
 src/main/java/com/ruoyi/project/system/controller/SysDeptController.java                        |  268 
 src/main/java/com/ruoyi/sales/dto/SalesLedgerImportDto.java                                     |    4 
 src/main/java/com/ruoyi/project/system/controller/SysUserController.java                        |  584 
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java |  152 
 src/main/java/com/ruoyi/sales/vo/CustomerTransactionsVo.java                                    |   30 
 src/main/java/com/ruoyi/technology/service/impl/TechnologyRoutingServiceImpl.java               |   11 
 src/main/resources/approve-todo-agent-prompt.txt                                                |    2 
 src/main/resources/static/销售台账导入模板.xlsx                                                         |    0 
 src/main/java/com/ruoyi/account/service/impl/AccountStatementDetailsServiceImpl.java            |   20 
 src/main/java/com/ruoyi/account/service/purchase/AccountPurchasePaymentService.java             |   30 
 src/main/java/com/ruoyi/project/monitor/controller/SysOperlogController.java                    |  140 
 src/main/java/com/ruoyi/account/pojo/sales/AccountInvoiceApplication.java                       |  138 
 src/main/resources/mapper/stock/StockInRecordMapper.xml                                         |   13 
 src/main/java/com/ruoyi/account/pojo/financial/AccountSubject.java                              |    6 
 src/main/java/com/ruoyi/quality/pojo/QualityInspect.java                                        |   10 
 src/main/resources/mapper/production/ProductionOperationTaskMapper.xml                          |    3 
 src/main/java/com/ruoyi/ai/config/FinancialAgentConfig.java                                     |   20 
 src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java            |   27 
 src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java                     |    3 
 src/main/java/com/ruoyi/ai/assistant/FinancialAgent.java                                        |   22 
 src/main/java/com/ruoyi/account/bean/dto/financial/AccountSubjectDto.java                       |    4 
 src/main/java/com/ruoyi/project/monitor/controller/SysJobLogController.java                     |  186 
 src/main/java/com/ruoyi/account/service/impl/financial/AccountSubjectServiceImpl.java           |   14 
 src/main/java/com/ruoyi/home/controller/HomeController.java                                     |  586 +
 src/main/java/com/ruoyi/account/bean/dto/sales/SalesReturnDto.java                              |   10 
 src/main/java/com/ruoyi/account/mapper/sales/AccountInvoiceApplicationMapper.java               |   32 
 src/main/java/com/ruoyi/account/bean/vo/StatementAccountVo.java                                 |   25 
 src/main/java/com/ruoyi/account/bean/dto/sales/AccountInvoiceApplicationDto.java                |   34 
 src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchaseInvoiceServiceImpl.java    |   59 
 src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java                             |   79 
 src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java                 |  140 
 doc/20260521_采购智能体优化前端变更文档.md                                                                   |   85 
 src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java                     |   51 
 src/main/java/com/ruoyi/account/bean/vo/purchase/AccountPaymentApplicationVo.java               |   23 
 src/main/java/com/ruoyi/sales/dto/SalesLedgerProductImportDto.java                              |    7 
 src/main/java/com/ruoyi/account/pojo/sales/AccountSalesInvoice.java                             |  168 
 src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java                                       |    8 
 src/main/java/com/ruoyi/account/controller/purchase/AccountPurchasePaymentController.java       |   71 
 src/main/java/com/ruoyi/account/bean/vo/purchase/PurchaseInboundVo.java                         |    6 
 src/main/resources/mapper/account/purchase/AccountPurchasePaymentMapper.xml                     |   57 
 src/main/java/com/ruoyi/account/controller/purchase/AccountPurchaseInvoiceController.java       |   79 
 src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchaseServiceImpl.java           |   12 
 src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java                            |   12 
 src/main/java/com/ruoyi/project/system/controller/SysPostController.java                        |  266 
 src/main/java/com/ruoyi/account/bean/vo/sales/AccountSalesInvoiceVo.java                        |   19 
 src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java                                        |    1 
 src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml                        |  101 
 doc/20260520_首页生产看板前端联调文档.md                                                                    |  160 
 src/main/resources/mapper/production/ProductionOrderMapper.xml                                  |   81 
 /dev/null                                                                                       |  454 -
 src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesServiceImpl.java                 |   12 
 src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java              |   33 
 src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchasePaymentMapper.java               |   29 
 221 files changed, 14,863 insertions(+), 4,568 deletions(-)

diff --git "a/doc/20260518_\351\224\200\345\224\256\345\212\251\346\211\213\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/doc/20260518_\351\224\200\345\224\256\345\212\251\346\211\213\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..d0c6e40
--- /dev/null
+++ "b/doc/20260518_\351\224\200\345\224\256\345\212\251\346\211\213\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,188 @@
+# 閿�鍞姪鎵嬪墠绔仈璋冩枃妗o紙`/sales-ai`锛�
+> 鏇存柊鏃堕棿锛�2026-05-18  
+> 閫傜敤妯″潡锛氬鎴锋。妗堬紙绉佹捣/鍏捣锛夈�侀攢鍞姤浠枫�侀攢鍞彴璐︺�侀攢鍞��璐с�佸鎴峰線鏉ャ�佸彂璐у彴璐︺�佹寚鏍囩粺璁�  
+> 閲嶇偣鑳藉姏锛氬鎴锋祦澶遍闄╁垎鏋愩�佸洖娆句笌鎶ヤ环绛栫暐寤鸿
+
+## 1. 鎺ュ彛鎬昏
+
+1. 娴佸紡瀵硅瘽锛歚POST /sales-ai/chat`
+2. 浼氳瘽鍒楄〃锛歚GET /sales-ai/history/sessions`
+3. 浼氳瘽娑堟伅锛歚GET /sales-ai/history/messages/{memoryId}`
+4. 鍒犻櫎浼氳瘽锛歚DELETE /sales-ai/history/{memoryId}`
+
+璇存槑锛�
+- `/chat` 杩斿洖 `text/stream;charset=utf-8`锛圫SE 鏂囨湰娴侊級銆�
+- 鍛戒腑宸ュ叿鏃讹紝鏈�缁堝唴瀹逛负 **JSON 瀛楃涓�**锛堥潪 `AjaxResult`锛夈��
+- 鏈懡涓伐鍏锋椂锛岃繑鍥炴櫘閫氫腑鏂囨枃鏈��
+
+## 2. 瀵硅瘽鎺ュ彛
+
+### 2.1 璇锋眰
+
+```http
+POST /sales-ai/chat
+Content-Type: application/json
+```
+
+```json
+{
+  "memoryId": "sales-ai-001",
+  "message": "甯垜鍋氬鎴锋祦澶遍闄╁垎鏋愶紝杩�90澶╋紝鍓�10鏉�"
+}
+```
+
+瀛楁璇存槑锛�
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+| --- | --- | --- | --- |
+| `memoryId` | string | 鏄� | 浼氳瘽 ID锛屽墠绔敓鎴愬苟澶嶇敤 |
+| `message` | string | 鏄� | 鐢ㄦ埛杈撳叆 |
+
+### 2.2 杩斿洖澶勭悊
+
+鍓嶇寤鸿娴佺▼锛�
+1. 鍏堟寜娴佹嫾鎺ュ畬鏁存枃鏈� `fullText`銆�
+2. 灏濊瘯 `JSON.parse(fullText)`锛�
+   - 鎴愬姛锛氭寜 `type` 璺敱鍒扮粨鏋勫寲缁勪欢銆�
+   - 澶辫触锛氭寜鏅�氳亰澶╂枃鏈睍绀恒��
+
+## 3. 缁撴瀯鍖栧搷搴斿崗璁�
+
+### 3.1 閫氱敤缁撴瀯
+
+```json
+{
+  "success": true,
+  "type": "sales_dashboard",
+  "description": "宸茶繑鍥為攢鍞寚鏍囩粺璁�",
+  "summary": {},
+  "data": {},
+  "charts": {}
+}
+```
+
+### 3.2 `type` 鏋氫妇
+
+| type | 鍦烘櫙 |
+| --- | --- |
+| `sales_customer_profile_list` | 瀹㈡埛妗f锛堢娴�/鍏捣锛� |
+| `sales_quotation_list` | 閿�鍞姤浠� |
+| `sales_ledger_list` | 閿�鍞彴璐� |
+| `sales_return_list` | 閿�鍞��璐� |
+| `sales_customer_interaction_list` | 瀹㈡埛寰�鏉ワ紙鍥炴锛� |
+| `sales_shipping_list` | 鍙戣揣鍙拌处 |
+| `sales_dashboard` | 鎸囨爣缁熻 |
+| `sales_customer_churn_risk` | 瀹㈡埛娴佸け椋庨櫓鍒嗘瀽 |
+| `sales_collection_quote_strategy` | 鍥炴涓庢姤浠风瓥鐣ュ缓璁� |
+
+## 4. 鑿滃崟鑳藉姏鏄犲皠锛堝搴旇惀閿�绠$悊锛�
+
+1. 瀹㈡埛妗f锛堢娴凤級锛氱ず渚嬫彁闂� `鏌ヨ绉佹捣瀹㈡埛妗f鍓�10鏉
+2. 瀹㈡埛妗f锛堝叕娴凤級锛氱ず渚嬫彁闂� `鏌ヨ鍏捣瀹㈡埛妗f`
+3. 閿�鍞姤浠凤細绀轰緥鎻愰棶 `鏌ヨ鏈湀閿�鍞姤浠穈
+4. 閿�鍞彴璐︼細绀轰緥鎻愰棶 `鏌ヨ鏈湀閿�鍞彴璐
+5. 閿�鍞��璐э細绀轰緥鎻愰棶 `鏌ヨ杩�30澶╅攢鍞��璐
+6. 瀹㈡埛寰�鏉ワ細绀轰緥鎻愰棶 `鏌ヨ杩�30澶╁鎴峰洖娆惧線鏉
+7. 鍙戣揣鍙拌处锛氱ず渚嬫彁闂� `鏌ヨ鏈湀鍙戣揣鍙拌处`
+8. 鎸囨爣缁熻锛氱ず渚嬫彁闂� `鏌ョ湅閿�鍞寚鏍囩粺璁
+
+## 5. 閲嶇偣鑳藉姏鑱旇皟
+
+### 5.1 瀹㈡埛娴佸け椋庨櫓鍒嗘瀽锛坄sales_customer_churn_risk`锛�
+
+鏁版嵁浣嶇疆锛�
+- 鍒楄〃锛歚data.items`
+- 姹囨�伙細`summary.highRiskCount / mediumRiskCount / lowRiskCount`
+- 鍥捐〃锛歚charts.riskLevelPieOption`銆乣charts.riskScoreBarOption`
+
+鍗曢」甯哥敤瀛楁锛�
+- `customerName`
+- `riskLevel`锛坄high`/`medium`/`low`锛�
+- `riskScore`锛�0-100锛�
+- `pendingAmount`
+- `pendingRate`
+- `daysSinceLastOrder`
+- `riskReasons`锛堝瓧绗︿覆鏁扮粍锛�
+
+### 5.2 鍥炴涓庢姤浠风瓥鐣ュ缓璁紙`sales_collection_quote_strategy`锛�
+
+鏁版嵁浣嶇疆锛�
+- 绛栫暐鍗★細`data.items`
+- 姹囨�伙細`summary.highPriorityCount / mediumPriorityCount / lowPriorityCount`
+- 鍥捐〃锛歚charts.pendingAmountBarOption`銆乣charts.priorityPieOption`
+
+鍗曢」甯哥敤瀛楁锛�
+- `customerName`
+- `priority`锛坄high`/`medium`/`low`锛�
+- `pendingAmount`
+- `quoteConversionRate`
+- `collectionStrategy`
+- `quotationStrategy`
+- `nextAction`
+
+## 6. 鎸囨爣缁熻鑱旇皟锛坄sales_dashboard`锛�
+
+鍏抽敭瀛楁锛�
+- `summary.contractAmountTotal`
+- `summary.receivedAmountTotal`
+- `summary.pendingAmountTotal`
+- `summary.shipRate`
+
+鍥捐〃瀛楁锛堝彲鐩存帴缁� ECharts锛夛細
+- `charts.amountBarOption`
+- `charts.shippingPieOption`
+- `charts.customerTopBarOption`
+- `charts.contractTrendLineOption`
+
+闄勫姞鏁版嵁锛�
+- `data.topCustomers`
+- `data.contractTrend`
+
+## 7. 浼氳瘽鍘嗗彶鎺ュ彛
+
+### 7.1 浼氳瘽鍒楄〃
+
+```http
+GET /sales-ai/history/sessions
+```
+
+杩斿洖 `AjaxResult.data` 瀛楁锛�
+- `memoryId`
+- `title`
+- `lastMessage`
+- `messageCount`
+- `lastChatTime`
+
+### 7.2 浼氳瘽娑堟伅
+
+```http
+GET /sales-ai/history/messages/{memoryId}
+```
+
+杩斿洖 `AjaxResult.data` 瀛楁锛�
+- `role`锛歚user` / `assistant` / `system` / `tool`
+- `content`
+- `filePaths`锛堝綋鍓嶉攢鍞姪鎵嬫湭浣跨敤鏂囦欢鍒嗘瀽锛屽彲蹇界暐锛�
+
+### 7.3 鍒犻櫎浼氳瘽
+
+```http
+DELETE /sales-ai/history/{memoryId}
+```
+
+杩斿洖鏍囧噯 `AjaxResult`銆�
+
+## 8. 鍓嶇鎺ュ叆绾︽潫
+
+1. 鏂板鍔╂墜閰嶇疆鏃讹紝`assistantRegistry` 蹇呴』娉ㄥ唽 `sales`锛堟垨浣犳柟绾﹀畾 key锛夛紝骞舵寚鍚� `apiBase = /sales-ai`銆�
+2. 缁撴瀯鍖栨覆鏌撳繀椤诲熀浜� `type` 鍒嗗彂锛屼笉瑕佷粎闈犲叧閿瘝銆�
+3. 鑱婂ぉ娓叉煋闇�淇濈暀鈥滄枃鏈厹搴曗�濓紝閬垮厤 JSON 瑙f瀽澶辫触鏃堕〉闈㈢┖鐧姐��
+4. 涓氬姟灞曠ず瀛楁寤鸿涓枃鍖栵紝涓嶇洿鎺ュ睍绀鸿嫳鏂囧瓧娈� key銆�
+
+## 9. 鑱旇皟楠屾敹娓呭崟
+
+1. 鑳芥甯告祦寮忔帴鏀� `/sales-ai/chat` 鍝嶅簲骞舵嫾鎺ユ枃鏈��
+2. 鑳芥寜 `type` 姝g‘娓叉煋 9 绫荤粨鏋勫寲缁撴灉銆�
+3. 鑳芥纭睍绀衡�滃鎴锋祦澶遍闄╁垎鏋愨�濆拰鈥滃洖娆句笌鎶ヤ环绛栫暐寤鸿鈥濅袱涓噸鐐瑰満鏅��
+4. 浼氳瘽鍒楄〃銆佷細璇濇秷鎭�佸垹闄や細璇濆叏閾捐矾鍙敤銆�
+5. `memoryId` 澶嶇敤鍚庡彲鍥炵湅鍘嗗彶锛屼笉浼氫覆浼氳瘽銆�
diff --git "a/doc/20260520_\351\246\226\351\241\265\347\224\237\344\272\247\347\234\213\346\235\277\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/doc/20260520_\351\246\226\351\241\265\347\224\237\344\272\247\347\234\213\346\235\277\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..aaa6055
--- /dev/null
+++ "b/doc/20260520_\351\246\226\351\241\265\347\224\237\344\272\247\347\234\213\346\235\277\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,160 @@
+# 棣栭〉鐢熶骇鐪嬫澘鍓嶇鑱旇皟鏂囨。
+
+鏇存柊鏃堕棿锛�2026-05-20  
+妯″潡锛歚/home`锛堥椤碉級
+
+## 1. 鎺ュ彛娓呭崟
+
+1. `GET /home/productionOverview`锛氱敓浜ф�昏  
+2. `GET /home/productionRealtimeBoard`锛氱敓浜у疄鏃剁湅鏉�  
+3. `GET /home/productionOrderProgress`锛氱敓浜ц鍗曡繘搴�  
+4. `GET /home/todayProductionPlan`锛氫粖鏃ョ敓浜ц鍒�
+
+鎵�鏈夋帴鍙g粺涓�杩斿洖 `AjaxResult`锛�
+
+```json
+{
+  "code": 200,
+  "msg": "鎿嶄綔鎴愬姛",
+  "data": {}
+}
+```
+
+## 2. 鐢熶骇鎬昏
+
+### 2.1 璇锋眰
+
+```http
+GET /home/productionOverview
+```
+
+### 2.2 杩斿洖 `data`
+
+```json
+{
+  "totalOutput": 1280.00,
+  "totalScrap": 25.00,
+  "yieldRate": 98.08
+}
+```
+
+瀛楁璇存槑锛�
+
+- `totalOutput`锛氱疮璁′骇鍑猴紙浠讹紝鍚堟牸鏁帮級
+- `totalScrap`锛氱疮璁℃姤搴燂紙浠讹級
+- `yieldRate`锛氳壇鐜囷紙0-100锛屽墠绔睍绀烘椂鍙嫾鎺� `%`锛�
+
+## 3. 鐢熶骇瀹炴椂鐪嬫澘
+
+### 3.1 璇锋眰
+
+```http
+GET /home/productionRealtimeBoard
+```
+
+### 3.2 杩斿洖 `data`
+
+```json
+{
+  "deviceOee": {
+    "value": 74.00,
+    "compareYesterday": 2.50
+  },
+  "orderAchievementRate": {
+    "value": 81.30,
+    "compareYesterday": -1.20
+  },
+  "defectRate": {
+    "value": 1.40,
+    "compareYesterday": 0.30
+  }
+}
+```
+
+瀛楁璇存槑锛�
+
+- `value`锛氬綋鏃ユ寚鏍囧�硷紙0-100锛�
+- `compareYesterday`锛氳緝鏄ㄦ棩鍙樺寲鍊硷紙鍙鍙礋锛涘墠绔寜姝h礋鍐冲畾绠ご鏂瑰悜鍜岄鑹诧級
+
+## 4. 鐢熶骇璁㈠崟杩涘害
+
+### 4.1 璇锋眰
+
+```http
+GET /home/productionOrderProgress?tab=all&pageNum=1&pageSize=10
+```
+
+鍙傛暟锛�
+
+- `tab`锛歚all` / `inProgress` / `completed` / `paused`
+- `pageNum`锛氶〉鐮侊紙榛樿 `1`锛�
+- `pageSize`锛氭瘡椤垫潯鏁帮紙榛樿 `10`锛屾渶澶� `50`锛�
+
+### 4.2 杩斿洖 `data`
+
+```json
+{
+  "tab": "all",
+  "total": 24,
+  "pageNum": 1,
+  "pageSize": 10,
+  "inProgressCount": 6,
+  "completedCount": 12,
+  "pausedCount": 2,
+  "records": [
+    {
+      "orderNo": "MO-20260518-001",
+      "productName": "鏅鸿兘鎺у埗鍣�",
+      "plannedQuantity": 1000.00,
+      "completedQuantity": 860.00,
+      "completionRate": 86.00,
+      "dueDate": "2026-05-20",
+      "status": 2,
+      "statusLabel": "杩涜涓�"
+    }
+  ]
+}
+```
+
+瀛楁璇存槑锛�
+
+- `completionRate`锛氬畬鎴愮巼锛�0-100锛�
+- `status`锛氬悗绔姸鎬佺爜锛坄1`寰呭紑濮嬶紝`2`杩涜涓紝`3`宸插畬鎴愶紝`4`宸叉殏鍋滐級
+- `statusLabel`锛氱姸鎬佷腑鏂囧睍绀哄��
+
+## 5. 浠婃棩鐢熶骇璁″垝
+
+### 5.1 璇锋眰
+
+```http
+GET /home/todayProductionPlan?limit=4
+```
+
+鍙傛暟锛�
+
+- `limit`锛氳繑鍥炴潯鏁帮紙榛樿 `4`锛屾渶澶� `20`锛�
+
+### 5.2 杩斿洖 `data`
+
+```json
+{
+  "total": 9,
+  "records": [
+    {
+      "orderNo": "MO-20260518-004",
+      "productName": "缁撴瀯浠禔",
+      "plannedQuantity": 1200.00,
+      "dueDate": "2026-05-15",
+      "status": 2,
+      "statusLabel": "杩涜涓�"
+    }
+  ]
+}
+```
+
+## 6. 鍓嶇灞曠ず绾﹀畾
+
+- 鐧惧垎姣斿瓧娈电粺涓�鏄暟鍊硷紙濡� `74.00`锛夛紝鍓嶇鑷鎷兼帴 `%`銆�
+- 鎵�鏈夋暟鍊间繚鐣欎袱浣嶅皬鏁般��
+- `dueDate` 鍙兘涓� `null`锛屽墠绔渶鍏滃簳灞曠ず锛堝 `--`锛夈��
+- `compareYesterday` 姝h礋閮藉彲鑳藉嚭鐜帮紝寤鸿鎸� `>0` 涓婂崌銆乣<0` 涓嬮檷銆乣=0` 鎸佸钩澶勭悊銆�
diff --git "a/doc/20260520_\351\246\226\351\241\265\347\224\237\344\272\247\347\234\213\346\235\277\346\200\247\350\203\275\344\274\230\345\214\226\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md" "b/doc/20260520_\351\246\226\351\241\265\347\224\237\344\272\247\347\234\213\346\235\277\346\200\247\350\203\275\344\274\230\345\214\226\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..730dbf1
--- /dev/null
+++ "b/doc/20260520_\351\246\226\351\241\265\347\224\237\344\272\247\347\234\213\346\235\277\346\200\247\350\203\275\344\274\230\345\214\226\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
@@ -0,0 +1,107 @@
+# 棣栭〉鐢熶骇鐪嬫澘鎬ц兘浼樺寲鍓嶇鍙樻洿鏂囨。
+
+鏇存柊鏃堕棿锛�2026-05-20  
+閫傜敤椤甸潰锛氶椤�  
+娑夊強鍖哄潡锛�
+
+1. 鐢熶骇璁㈠崟杩涘害
+2. 浠婃棩鐢熶骇璁″垝
+
+## 1. 鏈浼樺寲鐩爣
+
+閽堝澶ф暟鎹噺鍦烘櫙锛堣鍗曟暟閲忓銆佺敓浜у巻鍙查暱锛変紭鍖栨煡璇㈡�ц兘锛岄檷浣庨椤垫帴鍙e搷搴旀椂闂村拰鍐呭瓨鍗犵敤銆�
+
+## 2. 娑夊強鎺ュ彛
+
+1. `GET /home/productionOrderProgress`
+2. `GET /home/todayProductionPlan`
+
+## 3. 鍓嶇鏄惁闇�瑕佹敼浠g爜
+
+缁撹锛�**鏃犲己鍒舵敼鍔紝鎺ュ彛鍏ュ弬涓庤繑鍥炵粨鏋勪繚鎸佸吋瀹�**銆�  
+浣犵幇鏈夐〉闈㈠彲浠ョ洿鎺ヨ仈璋冿紝涓嶉渶瑕佹敼瀛楁鏄犲皠銆�
+
+## 4. 鎺ュ彛璇存槑锛堜繚鎸佷笉鍙橈級
+
+### 4.1 鐢熶骇璁㈠崟杩涘害
+
+璇锋眰锛�
+
+```http
+GET /home/productionOrderProgress?tab=all&pageNum=1&pageSize=10
+```
+
+鍙傛暟锛�
+
+- `tab`锛歚all` / `inProgress` / `completed` / `paused`
+- `pageNum`锛氶〉鐮侊紝榛樿 `1`
+- `pageSize`锛氭瘡椤垫潯鏁帮紝榛樿 `10`锛屾渶澶� `50`
+
+杩斿洖 `data`锛堢粨鏋勪笉鍙橈級锛�
+
+```json
+{
+  "tab": "all",
+  "total": 1200,
+  "pageNum": 1,
+  "pageSize": 10,
+  "inProgressCount": 180,
+  "completedCount": 900,
+  "pausedCount": 20,
+  "records": [
+    {
+      "orderNo": "MO-20260518-001",
+      "productName": "鏅鸿兘鎺у埗鍣�",
+      "plannedQuantity": 1000.00,
+      "completedQuantity": 860.00,
+      "completionRate": 86.00,
+      "dueDate": "2026-05-20",
+      "status": 2,
+      "statusLabel": "杩涜涓�"
+    }
+  ]
+}
+```
+
+### 4.2 浠婃棩鐢熶骇璁″垝
+
+璇锋眰锛�
+
+```http
+GET /home/todayProductionPlan?limit=4
+```
+
+鍙傛暟锛�
+
+- `limit`锛氳繑鍥炴潯鏁帮紝榛樿 `4`锛屾渶澶� `20`
+
+杩斿洖 `data`锛堢粨鏋勪笉鍙橈級锛�
+
+```json
+{
+  "total": 230,
+  "records": [
+    {
+      "orderNo": "MO-20260518-004",
+      "productName": "缁撴瀯浠禔",
+      "plannedQuantity": 1200.00,
+      "dueDate": "2026-05-15",
+      "status": 2,
+      "statusLabel": "杩涜涓�"
+    }
+  ]
+}
+```
+
+## 5. 鍚庣浼樺寲鐐癸紙渚涘墠绔煡鎮夛級
+
+1. 璁㈠崟杩涘害涓庝粖鏃ヨ鍒掓敼涓鸿交閲� SQL锛屼粎鏌ヨ棣栭〉蹇呴渶瀛楁銆�  
+2. 鍘绘帀浜嗛椤垫煡璇㈣矾寰勪腑涓嶅繀瑕佺殑澶у叧鑱斻�佸浘鐗囧~鍏呭拰瀵硅薄瑁呴厤銆�  
+3. 鐘舵�佺粺璁℃敼涓烘暟鎹簱鑱氬悎璁℃暟锛屼笉鍐嶉�愭潯鎷夊彇璁$畻銆�  
+4. 鍒嗛〉涓庢潯鏁颁笂闄愪繚鐣欙紙`pageSize <= 50`, `limit <= 20`锛夈��
+
+## 6. 鍓嶇寤鸿
+
+1. 鍒囨崲 `tab` 鏃朵繚鐣欑幇鏈夎皟鐢ㄦ柟寮忓嵆鍙��  
+2. `dueDate` 鍙兘涓虹┖锛岀户缁寜 `--` 鍏滃簳灞曠ず銆�  
+3. 鐧惧垎姣斿瓧娈典粛涓烘暟鍊硷紝鍓嶇缁х画杩藉姞 `%` 灞曠ず銆�
diff --git "a/doc/20260521_\351\207\207\350\264\255\346\231\272\350\203\275\344\275\223\344\274\230\345\214\226\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md" "b/doc/20260521_\351\207\207\350\264\255\346\231\272\350\203\275\344\275\223\344\274\230\345\214\226\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..58089e8
--- /dev/null
+++ "b/doc/20260521_\351\207\207\350\264\255\346\231\272\350\203\275\344\275\223\344\274\230\345\214\226\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
@@ -0,0 +1,85 @@
+# 閲囪喘鏅鸿兘浣撲紭鍖栧墠绔彉鏇存枃妗�
+
+## 1. 鍙樻洿鑳屾櫙
+
+鏈閽堝閲囪喘鏅鸿兘浣撳仛浜嗗榻愪紭鍖栵紙鍙傝�冮攢鍞�/瀹℃壒/鍒堕�犳櫤鑳戒綋锛夛細
+
+1. 鎻愬崌 `quickPrompts` 鍛戒腑绋冲畾鎬с��
+2. 澧炲己鐩稿鏃堕棿璇嗗埆锛堜粖澶�/鏄ㄥぉ/鏈懆/涓婂懆/鏈湀/涓婃湀/浠婂勾/鍘诲勾/杩慛澶╃瓑锛夈��
+3. 澧炲姞涓氬姟鎰忓浘鏈瘑鍒椂鐨勭粨鏋勫寲鍏滃簳鍝嶅簲锛岄伩鍏嶇紪閫犳暟鎹��
+4. 琛ュ厖寰呬粯娆炬煡璇㈢殑姹囨�诲瓧娈碉紝渚夸簬鍓嶇鐩存帴娓叉煋缁熻鍗$墖銆�
+
+## 2. 鎺ュ彛褰卞搷姒傝
+
+| 鎺ュ彛 | 鏂规硶 | 鏄惁鏀硅矾寰� | 鏄惁鏀瑰叆鍙� | 鏄惁鏀硅繑鍥炵粨鏋� |
+| --- | --- | --- | --- | --- |
+| `/purchase-ai/chat` | POST(SSE) | 鍚� | 鍚� | 鏄紙鏂板鍏滃簳 JSON 绫诲瀷锛� |
+| `/purchase-ai/analyze-files` | POST(SSE) | 鍚� | 鍚� | 鍚︼紙浠呭唴閮ㄦ彁绀鸿瘝澧炲己锛� |
+
+## 3. 鏂板鍏滃簳鍝嶅簲锛堥噸鐐癸級
+
+褰撶敤鎴锋槑鏄惧湪闂噰璐笟鍔★紝浣嗘潯浠朵笉鍏呭垎涓旀湭鍛戒腑鍙墽琛屾剰鍥炬椂锛宍/purchase-ai/chat` 浼氱洿鎺ヨ繑鍥炵粨鏋勫寲 JSON锛堣�屼笉鏄嚜鐢辨枃鏈級锛�
+
+```json
+{
+  "success": false,
+  "type": "purchase_intent_not_recognized",
+  "description": "鏈瘑鍒埌鍙墽琛岀殑閲囪喘鏌ヨ鏉′欢銆備负淇濊瘉缁撴灉鍑嗙‘锛屽綋鍓嶄笉浼氭帹娴嬫垨缂栭�犳暟鎹紝璇疯ˉ鍏呮槑纭椂闂磋寖鍥淬�佷緵搴斿晢銆侀噰璐悎鍚屽彿鎴栫墿鏂欏悗鍐嶆煡璇€��",
+  "summary": {},
+  "data": {
+    "quickPrompts": [
+      "鏈湀閲囪喘閲戦鎺掑悕鍓嶅崄鐨勭墿鏂欐湁鍝簺锛�",
+      "鍝簺閲囪喘璁㈠崟杩樻湭鍏ュ簱锛�",
+      "鏈�杩�7澶╀緵搴斿晢鍒拌揣寮傚父鏈夊摢浜涳紵",
+      "甯垜缁熻寰呬粯娆鹃噰璐崟锛�",
+      "鍒楀嚭鏈湀閲囪喘閫�璐ф儏鍐�"
+    ]
+  },
+  "charts": {}
+}
+```
+
+鍓嶇澶勭悊寤鸿锛�
+
+1. 褰� `type === "purchase_intent_not_recognized"` 鏃讹紝灞曠ず `description`銆�
+2. 璇诲彇 `data.quickPrompts` 浣滀负蹇嵎鎻愰棶鎸夐挳锛堝彲鐩存帴鍥炲~杈撳叆妗嗭級銆�
+
+## 4. 寰呬粯娆捐繑鍥炴柊澧炴眹鎬诲瓧娈�
+
+鎺ュ彛绫诲瀷锛歚type = "purchase_pending_payment_list"`  
+浣嶇疆锛歚summary`
+
+鏂板瀛楁锛�
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+| --- | --- | --- |
+| pendingOrderCount | number | 寰呬粯娆捐鍗曟暟 |
+| totalContractAmount | number | 寰呬粯娆捐鍗曞悎鍚屾�婚 |
+| totalPaidAmount | number | 宸蹭粯娆炬�婚 |
+| totalPendingAmount | number | 寰呬粯娆炬�婚 |
+
+璇存槑锛氬師鏈夊瓧娈典粛淇濈暀锛堝吋瀹癸級锛屾湰娆′负澧為噺瀛楁锛屼笉鐮村潖鐜版湁娓叉煋銆�
+
+## 5. 鏃堕棿鍙e緞浼樺寲
+
+閲囪喘鏅鸿兘浣撶幇鍦ㄧ粺涓�鎸変腑鍥芥椂鍖哄姩鎬佹棩鏈熸崲绠楃浉瀵规椂闂达紝鏀寔锛�
+
+- 浠婂ぉ銆佹槰澶�
+- 鏈懆銆佷笂鍛�
+- 鏈湀銆佷笂鏈�
+- 浠婂勾銆佸幓骞�
+- 杩慛澶�/鍛�/鏈�/骞淬�佽繎鍗婂勾銆佽繎鍗婁釜鏈�
+
+鍓嶇鏃犻渶鏀逛紶鍙傦紝浣嗗睍绀烘椂闂磋寖鍥存椂璇蜂互鍚庣杩斿洖 `summary.startDate/endDate/timeRange` 涓哄噯銆�
+
+## 6. 鍓嶇鑱旇皟妫�鏌ユ竻鍗�
+
+1. `chat` 娴佸紡缁撴灉鎷兼帴鍚庯紝浼樺厛鎸� JSON 瑙f瀽銆�
+2. 瑕嗙洊鏂扮被鍨� `purchase_intent_not_recognized` 鐨� UI 澶勭悊銆�
+3. 寰呬粯娆鹃〉闈㈣鍙栧苟灞曠ず `summary.totalPendingAmount` 绛夋柊澧炲瓧娈点��
+4. 楠岃瘉浠ヤ笅蹇嵎闂鍙ǔ瀹氳繑鍥炵粨鏋勫寲缁撴灉锛�
+   - 鏈湀閲囪喘閲戦鎺掑悕鍓嶅崄鐨勭墿鏂欐湁鍝簺锛�
+   - 鍝簺閲囪喘璁㈠崟杩樻湭鍏ュ簱锛�
+   - 鏈�杩�7澶╀緵搴斿晢鍒拌揣寮傚父鏈夊摢浜涳紵
+   - 甯垜缁熻寰呬粯娆鹃噰璐崟锛�
+   - 鍒楀嚭鏈湀閲囪喘閫�璐ф儏鍐�
diff --git "a/doc/20260521_\351\246\226\351\241\265HomeController\346\216\245\345\217\243\345\215\207\347\272\247\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md" "b/doc/20260521_\351\246\226\351\241\265HomeController\346\216\245\345\217\243\345\215\207\347\272\247\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..008660f
--- /dev/null
+++ "b/doc/20260521_\351\246\226\351\241\265HomeController\346\216\245\345\217\243\345\215\207\347\272\247\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
@@ -0,0 +1,113 @@
+# 棣栭〉 HomeController 鎺ュ彛鍗囩骇鍓嶇鍙樻洿鏂囨。
+
+鏇存柊鏃堕棿锛�2026-05-21  
+閫傜敤妯″潡锛氶椤碉紙`/home`锛�
+
+## 1. 鍙樻洿姒傝
+
+鏈涓� **鍏煎寮忓崌绾�**锛屾棫璋冪敤鏂瑰紡浠嶅彲鐢ㄣ��  
+閲嶇偣鏄粰鐢熶骇鐪嬫澘鎺ュ彛澧炲姞鏇存槑纭殑绛涢�夊弬鏁帮紝渚夸簬鍓嶇鎸夋棩鏈熷拰鐘舵�佹煡璇€��
+
+娑夊強鎺ュ彛锛�
+
+1. `GET /home/productionOrderProgress`
+2. `GET /home/todayProductionPlan`
+
+## 2. 鍙傛暟鍙樻洿
+
+### 2.1 鐢熶骇璁㈠崟杩涘害 `GET /home/productionOrderProgress`
+
+鏃у弬鏁帮紙浠嶅吋瀹癸級锛�
+
+- `tab`锛歚all` / `inProgress` / `completed` / `paused`
+- `pageNum`锛氶粯璁� `1`
+- `pageSize`锛氶粯璁� `10`锛屾渶澶� `50`
+
+鏂板鍙傛暟锛�
+
+- `status`锛堝彲閫夛級锛氱姸鎬佺瓫閫夛紝浼樺厛绾ч珮浜� `tab`  
+  鍙�夊�硷細`all` / `waiting` / `inProgress` / `completed` / `paused` / `1` / `2` / `3` / `4`
+- `bizDate`锛堝彲閫夛級锛氫笟鍔℃棩鏈熺瓫閫夛紝鏍煎紡 `yyyy-MM-dd`锛堟寜璁㈠崟鍒涘缓鏃堕棿杩囨护锛�
+
+鍙傛暟浼樺厛绾э細
+
+1. 濡傛灉浼犱簡 `status`锛屽悗绔紭鍏堟寜 `status` 瑙f瀽锛�
+2. 鏈紶 `status` 鏃讹紝娌跨敤鍘熸湁 `tab` 琛屼负锛�
+3. `status` 鎴� `bizDate` 鏍煎紡閿欒鏃惰繑鍥炲け璐ヤ俊鎭��
+
+璇锋眰绀轰緥锛�
+
+```http
+GET /home/productionOrderProgress?status=completed&bizDate=2026-05-20&pageNum=1&pageSize=10
+```
+
+### 2.2 浠婃棩鐢熶骇璁″垝 `GET /home/todayProductionPlan`
+
+鏃у弬鏁帮紙浠嶅吋瀹癸級锛�
+
+- `limit`锛氶粯璁� `4`锛屾渶澶� `20`
+
+鏂板鍙傛暟锛�
+
+- `planDate`锛堝彲閫夛級锛氳鍒掓棩鏈熺瓫閫夛紝鏍煎紡 `yyyy-MM-dd`锛堟寜 `plan_complete_time` 杩囨护锛�
+
+璇锋眰绀轰緥锛�
+
+```http
+GET /home/todayProductionPlan?limit=6&planDate=2026-05-21
+```
+
+## 3. 杩斿洖缁撴瀯鍙樻洿
+
+### 3.1 `productionOrderProgress` 杩斿洖鏂板瀛楁
+
+鏂板锛�
+
+- `status`锛氭爣鍑嗗寲鐘舵�佸洖鏄撅紙`all` / `waiting` / `inProgress` / `completed` / `paused`锛�
+- `bizDate`锛氭棩鏈熺瓫閫夊洖鏄撅紙鏈紶鏃朵负 `null`锛�
+- `waitingCount`锛氬緟寮�濮嬭鍗曟暟閲�
+
+鍏煎淇濈暀锛�
+
+- `tab` 瀛楁缁х画杩斿洖锛堣�侀〉闈㈡棤闇�鏀瑰姩鍙户缁娇鐢級
+
+杩斿洖绀轰緥锛�
+
+```json
+{
+  "tab": "completed",
+  "status": "completed",
+  "bizDate": "2026-05-20",
+  "total": 24,
+  "pageNum": 1,
+  "pageSize": 10,
+  "waitingCount": 3,
+  "inProgressCount": 6,
+  "completedCount": 12,
+  "pausedCount": 2,
+  "records": []
+}
+```
+
+### 3.2 `todayProductionPlan` 杩斿洖鏂板瀛楁
+
+鏂板锛�
+
+- `planDate`锛氭棩鏈熺瓫閫夊洖鏄撅紙鏈紶鏃朵负 `null`锛�
+
+杩斿洖绀轰緥锛�
+
+```json
+{
+  "planDate": "2026-05-21",
+  "total": 9,
+  "records": []
+}
+```
+
+## 4. 鍓嶇鏀归�犲缓璁�
+
+1. 鏂伴〉闈㈠缓璁紭鍏堜紶 `status`锛岄�愭鏇夸唬 `tab`銆�
+2. 闇�瑕佹寜鏃ユ湡澶嶇洏鐪嬫澘鏃讹紝浣跨敤 `bizDate` / `planDate`銆�
+3. 鑰侀〉闈㈠彲涓嶆敼锛岀户缁部鐢ㄥ師鍙傛暟涔熻兘姝e父鑱旇皟銆�
+
diff --git "a/doc/20260522_\350\264\242\345\212\241\345\215\207\347\272\247AI\346\250\241\345\235\227\345\211\215\347\253\257\345\217\230\346\233\264\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/doc/20260522_\350\264\242\345\212\241\345\215\207\347\272\247AI\346\250\241\345\235\227\345\211\215\347\253\257\345\217\230\346\233\264\350\201\224\350\260\203\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..e011374
--- /dev/null
+++ "b/doc/20260522_\350\264\242\345\212\241\345\215\207\347\272\247AI\346\250\241\345\235\227\345\211\215\347\253\257\345\217\230\346\233\264\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,150 @@
+# 璐㈠姟妯″潡鍗囩骇鍚� AI 妯″潡鍓嶇鍙樻洿鑱旇皟鏂囨。锛堥噰璐�/閿�鍞�/鐢熶骇/寰呭姙锛�
+
+鏇存柊鏃ユ湡锛�2026-05-22  
+閫傜敤鑼冨洿锛歚/sales-ai`銆乣/purchase-ai`銆乣/manufacturing-ai`銆乣/xiaozhi`锛堝鎵瑰緟鍔烇級
+
+## 1. 鍙樻洿鎬昏
+
+| 妯″潡 | 瀵瑰鎺ュ彛 | 鏄惁闇�瑕佸墠绔敼閫� | 缁撹 |
+| --- | --- | --- | --- |
+| 閿�鍞� AI | `POST /sales-ai/chat` | 鏄� | 璐㈠姟鍙e緞鍒囨崲鍒版柊鏀舵妯″瀷锛岄儴鍒� `type` 鐨勫瓧娈佃涔夊彉鍖� |
+| 閲囪喘 AI | `POST /purchase-ai/chat` | 鏄� | 浠樻/鍙戠エ/寰呬粯娆捐绠楀垏鎹㈠埌鏂拌储鍔¢摼璺紝缁熻鍊间粠鍗犱綅鏀逛负鐪熷疄鍊� |
+| 鐢熶骇 AI | `POST /manufacturing-ai/chat` | 鍚� | 宸叉牳鏌ワ紝鏃犳棫璐㈠姟閫昏緫渚濊禆锛屾棤瀛楁鍙樻洿 |
+| 寰呭姙 AI | `POST /xiaozhi/chat` | 鍚� | 宸叉牳鏌ワ紝鏃犳棫璐㈠姟閫昏緫渚濊禆锛屾棤瀛楁鍙樻洿 |
+
+## 2. 閿�鍞� AI 鍙樻洿锛坄/sales-ai/chat`锛�
+
+### 2.1 `type = sales_return_list`锛堥攢鍞��娆�/鍥炴璁板綍锛�
+
+褰撳墠杩斿洖鏁版嵁鏉ユ簮缁熶竴涓烘柊璐㈠姟琛� `account_sales_collection`锛屼笉鍐嶈蛋鏃ф敹娆鹃��璐ч�昏緫銆�
+
+`data.items[]` 鍏抽敭瀛楁锛�
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+| --- | --- | --- |
+| id | number | 鏀舵璁板綍ID |
+| refundId | string | 鏄犲皠 `collectionNumber`锛屽墠绔彲缁х画浣滀负鈥滈��娆�/鍥炴鍗曞彿鈥濆睍绀� |
+| collectionNumber | string | 鏀舵鍗曞彿 |
+| paymentMethod | string | 鏀舵鏂瑰紡 |
+| actualAmount | number | 鏀舵閲戦锛堜笌 `collectionAmount` 鍚屽�硷級 |
+| collectionAmount | number | 鏀舵閲戦锛堟帹鑽愪富灞曠ず瀛楁锛� |
+| customerId | number | 瀹㈡埛ID |
+| remark | string | 澶囨敞 |
+| createTime | string | 鏀舵鏃ユ湡锛坹yyy-MM-dd锛� |
+
+`summary` 澧為噺鍏虫敞锛�
+- `returnAmount`锛氭椂闂磋寖鍥村唴閲戦姹囨�伙紙鎸� `collectionAmount` 缁熻锛�
+
+### 2.2 `type = sales_customer_interaction_list`锛堝鎴峰線鏉ワ級
+
+褰撳墠杩斿洖鍩轰簬鏂伴摼璺細
+`account_sales_collection.stock_out_record_ids -> stock_out_record(record_type=13) -> shipping_info -> sales_ledger`
+
+杩斿洖绾﹀畾锛�
+- 鏃犳暟鎹椂锛歚description = "no_customer_interactions"`
+- 鏈夋暟鎹椂锛歚description = "ok"`
+
+`summary` 鍏抽敭瀛楁锛�
+- `totalReceiptAmount`
+- `customerCount`
+
+`data.items[]` 鍏抽敭瀛楁锛�
+- `salesLedgerId`
+- `salesContractNo`
+- `customerName`
+- `projectName`
+- `receiptPaymentDate`
+- `receiptPaymentAmount`
+- `receiptPaymentType`
+- `collectionNumber`
+- `registrant`
+- `remark`
+
+### 2.3 `type = sales_ledger_list`锛堥攢鍞彴璐︼級
+
+瀛楁缁撴瀯涓嶅彉锛屼絾閲戦鍙e緞宸插垏鎹細
+- `receivedAmount` 鐢辨柊鏀舵妯″瀷姹囨�诲緱鍒帮紱
+- `pendingAmount = max(0, invoicedAmount - receivedAmount)`锛�
+- 鑻ユ敹娆捐褰曟湭鏄惧紡鍏宠仈鍙拌处锛屽垯鎸夊鎴风淮搴﹀厹搴曞綊闆嗐��
+
+鍓嶇鏀归�犲缓璁細
+- 涓嶆敼瀛楁鍚嶏紱
+- 閲嶇偣鍥炲綊鈥滃凡鏀堕噾棰�/寰呭洖娆鹃噾棰濃�濇槸鍚︿笌璐㈠姟鍙拌处涓�鑷淬��
+
+## 3. 閲囪喘 AI 鍙樻洿锛坄/purchase-ai/chat`锛�
+
+### 3.1 `type = purchase_stats`锛堥噰璐粺璁★級
+
+浠ヤ笅瀛楁宸蹭粠鍗犱綅鍊兼敼涓虹湡瀹炵粺璁″�硷細
+- `summary.paymentCount`
+- `summary.invoiceCount`
+- `summary.paymentAmount`
+- `summary.invoiceAmount`
+
+鍙戠エ閲戦鍙e緞锛�
+- 浼樺厛 `taxInclusivePrice`
+- 鑻ヤ负绌�/0锛屽垯浣跨敤 `taxExclusivelPrice + taxPrice`
+
+### 3.2 `type = purchase_pending_payment_list`锛堝緟浠樻閲囪喘鍗曪級
+
+鏍稿績璁$畻宸插垏鎹㈠埌鏂拌储鍔¢摼璺細
+
+`account_purchase_payment -> account_payment_application -> stock_in_record -> (purchase_ledger / quality_inspect) -> purchase_ledger_id`
+
+鏄犲皠瑙勫垯锛�
+1. `stock_in_record.record_type = 7`锛歚record_id` 鐩存帴瑙嗕负 `purchase_ledger_id`
+2. `stock_in_record.record_type = 10`锛氶�氳繃 `quality_inspect.id = record_id` 鍙� `quality_inspect.purchase_ledger_id`
+
+閲戦瀛楁鍙e緞锛�
+- `paidAmount`锛氭柊閾捐矾绱宸蹭粯娆鹃噾棰�
+- `pendingAmount = contractAmount - paidAmount`锛�<=0 鐨勮褰曚笉杩斿洖锛�
+
+`summary` 鍏抽敭瀛楁锛堝潎涓虹湡瀹炲�硷級锛�
+- `pendingOrderCount`
+- `totalContractAmount`
+- `totalPaidAmount`
+- `totalPendingAmount`
+
+### 3.3 鏁版嵁娓呮礂淇
+
+宸蹭慨澶� `record_type` 甯︾┖鏍煎鑷寸殑鏄犲皠涓㈠け闂锛堝悗绔粺涓� `trim()` 鍚庡啀鍒ゆ柇 `7/10`锛夈��
+
+## 4. 鐢熶骇 AI / 寰呭姙 AI 鏍告煡缁撹
+
+宸叉牳鏌ヤ互涓嬫ā鍧椾唬鐮侊紝鏈彂鐜版棫璐㈠姟閫昏緫鑰﹀悎鐐癸細
+- `ManufacturingAgentTools`锛堢敓浜э級
+- `ApproveTodoTools`锛堝緟鍔炲鎵癸級
+
+缁撹锛�
+- 瀵瑰 `type` 涓庡瓧娈电粨鏋勬棤鍙樻洿锛�
+- 鍓嶇鏃犻渶鍋氬吋瀹规敼閫狅紝浠呴渶鍋氫竴娆″洖褰掗獙璇併��
+
+## 5. 鍓嶇鑱旇皟瑕佺偣
+
+1. `/sales-ai/chat`銆乣/purchase-ai/chat` 缁х画鎸� SSE 鏂囨湰娴佹嫾鎺ュ悗鍋� JSON 瑙f瀽銆�  
+2. 鎸� `type` 璺敱娓叉煋锛屼笉瑕佷粎渚濊禆 `description` 鏂囨銆�  
+3. `sales_customer_interaction_list` 闇�鍏煎 `description` 鏋氫妇锛歚ok` / `no_customer_interactions`銆�  
+4. `sales_return_list` 閲戦灞曠ず缁熶竴鐢� `collectionAmount`锛坄actualAmount` 淇濈暀鍏煎锛夈��  
+5. `purchase_pending_payment_list` 鐨勬眹鎬诲崱鐗囪鐩存帴璇诲彇 `summary.totalPendingAmount` 绛夊瓧娈碉紝涓嶅啀鍓嶇浜屾浼扮畻銆�  
+
+## 6. 鍥炲綊娓呭崟锛堝缓璁級
+
+### 閿�鍞�
+1. 鎻愰棶锛氣�滆繎30澶╁摢涓鍗曞洖娆炬渶灏戔��  
+   - 鏍¢獙 `sales_ledger_list` 鐨� `receivedAmount/pendingAmount`銆�  
+2. 鎻愰棶锛氣�滄煡璇㈡湰鏈堥攢鍞��娆锯��  
+   - 鏍¢獙 `sales_return_list` 鐨� `collectionNumber/collectionAmount/returnAmount`銆�  
+3. 鎻愰棶锛氣�滄煡璇㈡湰鏈堝鎴峰線鏉モ��  
+   - 鏍¢獙 `sales_customer_interaction_list` 鐨� `totalReceiptAmount/customerCount`銆�  
+
+### 閲囪喘
+1. 鎻愰棶锛氣�滅粺璁℃湰鏈堥噰璐暟鎹��  
+   - 鏍¢獙 `purchase_stats` 鐨� `paymentCount/invoiceCount/paymentAmount/invoiceAmount` 闈炲浐瀹�0銆�  
+2. 鎻愰棶锛氣�滃垪鍑哄緟浠樻閲囪喘鍗曗��  
+   - 鏍¢獙 `purchase_pending_payment_list` 鐨� `paidAmount/pendingAmount` 涓庤储鍔″疄闄呬竴鑷淬��  
+
+### 鐢熶骇/寰呭姙
+1. 鐢熶骇鎻愰棶锛氣�滄煡璇㈡湰鍛ㄨ澶囩淮淇褰曗��  
+2. 寰呭姙鎻愰棶锛氣�滄煡璇㈡垜鐨勫緟瀹℃壒鍒楄〃鈥�  
+   - 鏍¢獙杩斿洖缁撴瀯涓庡崌绾у墠涓�鑷达紙鏃犲瓧娈电牬鍧忥級銆�
+
diff --git a/doc/financial-ai-front-integration.md b/doc/financial-ai-front-integration.md
new file mode 100644
index 0000000..f632c78
--- /dev/null
+++ b/doc/financial-ai-front-integration.md
@@ -0,0 +1,192 @@
+# 璐㈠姟鏅鸿兘浣撳墠绔仈璋冩枃妗�
+
+## 1. 妯″潡璇存槑
+
+璐㈠姟鏅鸿兘浣撳悗绔凡鏂板缁熶竴鍏ュ彛 `financial-ai`锛岀敤浜庝笟璐竴浣撳寲鍒嗘瀽锛岃鐩栵細
+
+- 鏅鸿兘鎴愭湰鏍哥畻
+- 璁㈠崟鍒╂鼎鍒嗘瀽
+- 搴撳瓨璧勯噾鍒嗘瀽
+- 搴旀敹搴斾粯涓庣幇閲戞祦棰勬祴
+- 缁忚惀寮傚父棰勮
+- AI 缁忚惀椹鹃┒鑸�
+- 鏃ユ姤/鍛ㄦ姤鑷姩鐢熸垚
+- 璐㈠姟鐭ヨ瘑妫�绱紙杞婚噺 RAG 涓婁笅鏂囷級
+
+鎺ュ彛閲囩敤 **SSE 娴佸紡杈撳嚭**锛屽伐鍏峰懡涓椂杩斿洖缁撴瀯鍖� JSON 瀛楃涓层��
+
+## 2. 鎺ュ彛娓呭崟
+
+### 2.1 瀵硅瘽鎺ュ彛锛圫SE锛�
+
+- `POST /financial-ai/chat`
+- `Content-Type: application/json`
+- `Accept: text/stream;charset=utf-8`
+
+璇锋眰浣擄細
+
+```json
+{
+  "memoryId": "finance-uuid-001",
+  "message": "鏌ヨ杩�30澶╀簭鎹熻鍗�"
+}
+```
+
+瀛楁璇存槑锛�
+
+- `memoryId`锛氫細璇濆敮涓�鏍囪瘑锛堝墠绔敓鎴� UUID锛屽崟浼氳瘽澶嶇敤锛�
+- `message`锛氳嚜鐒惰瑷�闂
+
+---
+
+### 2.2 浼氳瘽鍒楄〃
+
+- `GET /financial-ai/history/sessions`
+
+---
+
+### 2.3 浼氳瘽娑堟伅
+
+- `GET /financial-ai/history/messages/{memoryId}`
+
+---
+
+### 2.4 鍒犻櫎浼氳瘽
+
+- `DELETE /financial-ai/history/{memoryId}`
+
+## 3. SSE 杩斿洖澶勭悊瑙勮寖
+
+### 3.1 杩斿洖褰㈡��
+
+- 鏅�氶棶绛旓細娴佸紡鏂囨湰鐗囨
+- 宸ュ叿鍛戒腑锛氬畬鏁� JSON 瀛楃涓诧紙閫氬父涓�娆℃�ц緭鍑猴紝涔熷彲鑳藉垎鐗囷級
+
+鍓嶇寤鸿澶勭悊娴佺▼锛�
+
+1. 灏� SSE 鍒嗙墖鎸夐『搴忔嫾鎺ユ垚 `rawText`
+2. 瀵� `rawText` 灏濊瘯 `JSON.parse`
+3. 鑻ュ彲瑙f瀽锛屾寜 `type` 鍒嗗彂娓叉煋鍥捐〃/琛ㄦ牸
+4. 鑻ヤ笉鍙В鏋愶紝鎸夋櫘閫氭枃鏈睍绀�
+
+### 3.2 缁撴瀯鍖� JSON 閫氱敤鏍煎紡
+
+```json
+{
+  "success": true,
+  "type": "financial_order_profit_analysis",
+  "description": "宸插畬鎴愯鍗曞埄娑﹀垎鏋�",
+  "summary": {},
+  "data": {},
+  "charts": {}
+}
+```
+
+瀛楁璇存槑锛�
+
+- `type`锛氱粨鏋滅被鍨嬶紙鍓嶇娓叉煋鍒嗗彂閿級
+- `summary`锛氬ご閮ㄦ寚鏍�
+- `data`锛氳〃鏍兼槑缁�/寤鸿鍒楄〃
+- `charts`锛欵Charts `option` 鏁版嵁
+
+## 4. type 涓庡墠绔〉闈㈡槧灏�
+
+寤鸿鎸� `type` 寤虹珛娓叉煋绛栫暐锛�
+
+- `financial_cost_accounting`锛氭垚鏈牳绠楅〉
+- `financial_order_profit_analysis`锛氳鍗曞埄娑﹂〉
+- `financial_inventory_capital_analysis`锛氬簱瀛樿祫閲戦〉
+- `financial_cashflow_forecast`锛氱幇閲戞祦椤�
+- `financial_business_anomaly_warning`锛氶闄╅璀﹂〉
+- `financial_business_cockpit`锛氱粡钀ラ┚椹惰埍
+- `financial_operation_report`锛氭棩鎶ュ懆鎶ラ〉
+- `financial_rag_knowledge`锛氱煡璇嗘绱�/鍙e緞璇存槑鍗$墖
+
+## 5. 鍏抽敭鏁版嵁瀛楁锛堣仈璋冮噸鐐癸級
+
+### 5.1 鎴愭湰/鍒╂鼎绫�
+
+- `data.orders[]`锛�
+  - `salesContractNo`
+  - `customerName`
+  - `revenue`
+  - `materialCost`
+  - `laborCost`
+  - `depreciationCost`
+  - `scrapCost`
+  - `totalCost`
+  - `profit`
+  - `profitRate`
+  - `riskLevel`
+  - `reasons`
+  - `suggestion`
+
+### 5.2 搴撳瓨璧勯噾绫�
+
+- `data.items[]`锛�
+  - `productName`
+  - `model`
+  - `quantity`
+  - `inventoryValue`
+  - `stagnantDays`
+  - `overstock`
+  - `riskLevel`
+
+### 5.3 鐜伴噾娴佺被
+
+- `data.actualMonthly[]` / `data.forecastMonthly[]`锛�
+  - `month`
+  - `income`
+  - `expense`
+  - `netFlow`
+- `data.receivableRiskTop[]` / `data.payablePressureTop[]`
+
+### 5.4 寮傚父棰勮绫�
+
+- `data.items[]`锛�
+  - `riskLevel`
+  - `type`
+  - `message`
+  - `detail`
+
+### 5.5 鎶ュ憡绫�
+
+- `data.headline`
+- `data.conclusions[]`
+- `data.riskSuggestions[]`
+- `data.orderProfitTop[]`
+
+## 6. 鍥捐〃鑱旇皟瑙勮寖
+
+`charts` 鍐呭瓧娈靛潎涓� ECharts `option`锛屽彲鐩存帴鍠傜粰鍥捐〃缁勪欢銆�
+
+甯歌瀛楁锛�
+
+- 鏌辩姸鍥撅細`orderProfitBarOption` / `processCostBarOption` / `inventoryValueTopOption`
+- 楗煎浘锛歚costCompositionPieOption` / `inventoryAgingPieOption` / `anomalyLevelPieOption`
+- 瓒嬪娍鍥撅細`cashFlowTrendOption`
+- 浠〃鐩橈細`fundGapGaugeOption` / `inventoryTurnoverGauge`
+
+## 7. 鎺ㄨ崘鍓嶇闂彞锛堝洖褰掓祴璇曪級
+
+1. `鏌ョ湅鏈湀缁忚惀椹鹃┒鑸盽
+2. `鏌ヨ杩�30澶╀簭鎹熻鍗昤
+3. `鍒嗘瀽杩�30澶╁簱瀛樿祫閲戝崰鐢╜
+4. `棰勬祴鏈潵3涓湀鐜伴噾娴乣
+5. `鐢熸垚鏈懆缁忚惀鍛ㄦ姤`
+6. `涓轰粈涔堝埄娑︿笅闄峘
+7. `鍝釜瀹㈡埛鏈�璧氶挶`
+8. `鍝釜宸ュ簭鎴愭湰鏈�楂榒
+
+## 8. 寮傚父涓庡厹搴曞鐞�
+
+- `memoryId` 涓虹┖锛氳繑鍥炴枃鏈� `memoryId涓嶈兘涓虹┖`
+- `message` 涓虹┖锛氳繑鍥炴枃鏈� `message涓嶈兘涓虹┖`
+- 鏃犳暟鎹満鏅細`success=true` 涓� `data.items=[]`锛屽墠绔寜绌烘�佸睍绀�
+- 闈� JSON 娴佽繑鍥烇細鎸夋櫘閫氳亰澶╂枃鏈睍绀�
+
+## 9. 鑱旇皟寤鸿
+
+1. 鍏堝仛 `type` 鍒嗗彂鍣紙淇濊瘉鎵�鏈夌粨鏋勫寲缁撴灉鍙惤鍦帮級
+2. 鍐嶅仛鎽樿鍗$墖锛坄summary`锛�+ 琛ㄦ牸锛坄data`锛�+ 鍥捐〃锛坄charts`锛�
+3. 鏈�鍚庤ˉ浼氳瘽鍘嗗彶涓庡垹闄よ兘鍔涳紝褰㈡垚瀹屾暣瀵硅瘽闂幆
diff --git a/src/main/java/com/ruoyi/CodeGenerator.java b/src/main/java/com/ruoyi/CodeGenerator.java
index 721245b..e9f7110 100644
--- a/src/main/java/com/ruoyi/CodeGenerator.java
+++ b/src/main/java/com/ruoyi/CodeGenerator.java
@@ -20,11 +20,11 @@
 // 婕旂ず渚嬪瓙锛屾墽琛� main 鏂规硶鎺у埗鍙拌緭鍏ユā鍧楄〃鍚嶅洖杞﹁嚜鍔ㄧ敓鎴愬搴旈」鐩洰褰曚腑
 public class CodeGenerator {
 
-    public static String database_url = "jdbc:mysql://localhost:3300/product-inventory-management-new-pro";
+    public static String database_url = "jdbc:mysql://localhost:3306/product-inventory-management-new-pro";
     public static String database_username = "root";
-    public static String database_password= "root";
+    public static String database_password= "123456";
     public static String author = "鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃";
-    public static String model = "sales"; // 妯″潡
+    public static String model = "account"; // 妯″潡
     public static String setParent = "com.ruoyi."+ model; // 鍖呰矾寰�
     public static String tablePrefix = ""; // 璁剧疆杩囨护琛ㄥ墠缂�
     public static void main(String[] args) {
diff --git a/src/main/java/com/ruoyi/account/bean/dto/StatementAccountDto.java b/src/main/java/com/ruoyi/account/bean/dto/StatementAccountDto.java
new file mode 100644
index 0000000..52b6513
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/StatementAccountDto.java
@@ -0,0 +1,35 @@
+package com.ruoyi.account.bean.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+@Data
+@Schema(name = "StatementAccountDto", description = "璐㈠姟绠$悊--鐢熸垚瀵硅处鍗�(浼犲弬)")
+public class StatementAccountDto {
+
+    //涓氬姟绫诲瀷(1搴旀敹瀵硅处;2搴斾粯瀵硅处)
+    @Schema(name = "accountType", description = "涓氬姟绫诲瀷(1搴旀敹瀵硅处;2搴斾粯瀵硅处)")
+    private Integer accountType;
+
+    //閫夋嫨鐨勫鎴�(搴旀敹鏄鎴�,搴斾粯鏄緵搴斿晢supplierId)
+    @Schema(name = "customerId", description = "瀹㈡埛ID")
+    private Long customerId;
+
+    //瀵硅处鏈堜唤yyyy-MM
+    @Schema(name = "statementMonth", description = "瀵硅处鏈堜唤")
+    private String statementMonth;
+
+    @Schema(description = "寮�濮嬫棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startDate;
+
+    @Schema(description = "缁撴潫鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endDate;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/AccountSubjectDto.java b/src/main/java/com/ruoyi/account/bean/dto/financial/AccountSubjectDto.java
similarity index 60%
rename from src/main/java/com/ruoyi/account/bean/dto/AccountSubjectDto.java
rename to src/main/java/com/ruoyi/account/bean/dto/financial/AccountSubjectDto.java
index e26844d..4d55666 100644
--- a/src/main/java/com/ruoyi/account/bean/dto/AccountSubjectDto.java
+++ b/src/main/java/com/ruoyi/account/bean/dto/financial/AccountSubjectDto.java
@@ -1,6 +1,6 @@
-package com.ruoyi.account.bean.dto;
+package com.ruoyi.account.bean.dto.financial;
 
-import com.ruoyi.account.pojo.AccountSubject;
+import com.ruoyi.account.pojo.financial.AccountSubject;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
diff --git a/src/main/java/com/ruoyi/account/bean/dto/AccountSubjectImportDto.java b/src/main/java/com/ruoyi/account/bean/dto/financial/AccountSubjectImportDto.java
similarity index 94%
rename from src/main/java/com/ruoyi/account/bean/dto/AccountSubjectImportDto.java
rename to src/main/java/com/ruoyi/account/bean/dto/financial/AccountSubjectImportDto.java
index 28c8ab9..7ea5225 100644
--- a/src/main/java/com/ruoyi/account/bean/dto/AccountSubjectImportDto.java
+++ b/src/main/java/com/ruoyi/account/bean/dto/financial/AccountSubjectImportDto.java
@@ -1,4 +1,4 @@
-package com.ruoyi.account.bean.dto;
+package com.ruoyi.account.bean.dto.financial;
 
 import com.ruoyi.framework.aspectj.lang.annotation.Excel;
 import io.swagger.v3.oas.annotations.media.Schema;
diff --git a/src/main/java/com/ruoyi/account/bean/dto/purchase/AccountPaymentApplicationDto.java b/src/main/java/com/ruoyi/account/bean/dto/purchase/AccountPaymentApplicationDto.java
new file mode 100644
index 0000000..dfe0562
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/purchase/AccountPaymentApplicationDto.java
@@ -0,0 +1,34 @@
+package com.ruoyi.account.bean.dto.purchase;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+@Data
+@Schema(name = "AccountPaymentApplicationDto", description = "璐㈠姟绠$悊--浠樻鐢宠鍙拌处(浼犲弬)")
+public class AccountPaymentApplicationDto {
+
+    @Schema(description = "渚涘簲鍟咺D")
+    private Integer supplierId;
+
+    @Schema(description = "鐢宠鍗曞彿")
+    private String invoiceApplicationNo;
+
+    @Schema(description = "瀹℃牳鐘舵��:0寰呭鏍�1瀹℃牳閫氳繃2瀹℃牳涓嶉�氳繃")
+    private Integer status;
+
+    @Schema(description = "寮�濮嬫棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startDate;
+
+    @Schema(description = "缁撴潫鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endDate;
+
+
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/purchase/AccountPurchaseInvoiceDto.java b/src/main/java/com/ruoyi/account/bean/dto/purchase/AccountPurchaseInvoiceDto.java
new file mode 100644
index 0000000..3a799eb
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/purchase/AccountPurchaseInvoiceDto.java
@@ -0,0 +1,32 @@
+package com.ruoyi.account.bean.dto.purchase;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+@Data
+@Schema(name = "AccountPurchaseInvoiceDto", description = "璐㈠姟绠$悊--杩涢」鍙戠エ鍙拌处(浼犲弬)")
+public class AccountPurchaseInvoiceDto {
+
+    @Schema(description = "渚涘簲鍟咺D")
+    private Integer supplierId;
+
+    @Schema(description = "鍙戠エ鍙风爜")
+    private String invoiceNumber;
+
+    @Schema(description = "寮�濮嬫棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startDate;
+
+    @Schema(description = "缁撴潫鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endDate;
+
+    @Schema(description = "鐘舵��")
+    private Integer status;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/purchase/AccountPurchasePaymentDto.java b/src/main/java/com/ruoyi/account/bean/dto/purchase/AccountPurchasePaymentDto.java
new file mode 100644
index 0000000..f01d241
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/purchase/AccountPurchasePaymentDto.java
@@ -0,0 +1,34 @@
+package com.ruoyi.account.bean.dto.purchase;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+@Data
+@Schema(name = "AccountPurchasePaymentDto", description = "璐㈠姟绠$悊--浠樻鍗曞彴璐�(浼犲弬)")
+public class AccountPurchasePaymentDto {
+
+    @Schema(description = "渚涘簲鍟咺D")
+    private Integer supplierId;
+
+    @Schema(description = "浠樻鍗曞彿")
+    private String paymentNumber;
+
+    @Schema(description = "浠樻鏂瑰紡")
+    private String paymentMethod;
+
+    @Schema(description = "寮�濮嬫棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startDate;
+
+    @Schema(description = "缁撴潫鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endDate;
+
+
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/PurchaseInboundDto.java b/src/main/java/com/ruoyi/account/bean/dto/purchase/PurchaseInboundDto.java
similarity index 81%
rename from src/main/java/com/ruoyi/account/bean/dto/PurchaseInboundDto.java
rename to src/main/java/com/ruoyi/account/bean/dto/purchase/PurchaseInboundDto.java
index 757e6b4..cec0719 100644
--- a/src/main/java/com/ruoyi/account/bean/dto/PurchaseInboundDto.java
+++ b/src/main/java/com/ruoyi/account/bean/dto/purchase/PurchaseInboundDto.java
@@ -1,11 +1,11 @@
-package com.ruoyi.account.bean.dto;
+package com.ruoyi.account.bean.dto.purchase;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
-import java.util.Date;
+import java.time.LocalDate;
 
 @Data
 @Schema(name = "PurchaseInboundDto", description = "璐㈠姟绠$悊--閲囪喘鍏ュ簱鍙拌处(浼犲弬)")
@@ -14,16 +14,18 @@
     @Schema(description = "鍏ュ簱鍗曞彿")
     private String inboundBatches;
 
+    private Long supplierId;
+
     @Schema(description = "渚涘簲鍟�")
     private String supplierName;
 
     @Schema(description = "寮�濮嬫棩鏈�")
     @JsonFormat(pattern = "yyyy-MM-dd")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private Date startDate;
+    private LocalDate startDate;
 
     @Schema(description = "缁撴潫鏃ユ湡")
     @JsonFormat(pattern = "yyyy-MM-dd")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private Date endDate;
+    private LocalDate endDate;
 }
diff --git a/src/main/java/com/ruoyi/account/bean/dto/PurchaseReturnDto.java b/src/main/java/com/ruoyi/account/bean/dto/purchase/PurchaseReturnDto.java
similarity index 81%
rename from src/main/java/com/ruoyi/account/bean/dto/PurchaseReturnDto.java
rename to src/main/java/com/ruoyi/account/bean/dto/purchase/PurchaseReturnDto.java
index c238990..eb6adec 100644
--- a/src/main/java/com/ruoyi/account/bean/dto/PurchaseReturnDto.java
+++ b/src/main/java/com/ruoyi/account/bean/dto/purchase/PurchaseReturnDto.java
@@ -1,11 +1,11 @@
-package com.ruoyi.account.bean.dto;
+package com.ruoyi.account.bean.dto.purchase;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
-import java.util.Date;
+import java.time.LocalDate;
 
 @Data
 @Schema(name = "PurchaseReturnDto", description = "璐㈠姟绠$悊--閲囪喘閫�璐у彴璐�(浼犲弬)")
@@ -14,16 +14,18 @@
     @Schema(description = "閫�璐у崟鍙�")
     private String returnNo;
 
+    private Long supplierId;
+
     @Schema(description = "渚涘簲鍟�")
     private String supplierName;
 
     @Schema(description = "寮�濮嬫棩鏈�")
     @JsonFormat(pattern = "yyyy-MM-dd")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private Date startDate;
+    private LocalDate startDate;
 
     @Schema(description = "缁撴潫鏃ユ湡")
     @JsonFormat(pattern = "yyyy-MM-dd")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private Date endDate;
+    private LocalDate endDate;
 }
diff --git a/src/main/java/com/ruoyi/account/bean/dto/sales/AccountInvoiceApplicationDto.java b/src/main/java/com/ruoyi/account/bean/dto/sales/AccountInvoiceApplicationDto.java
new file mode 100644
index 0000000..d7917f3
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/sales/AccountInvoiceApplicationDto.java
@@ -0,0 +1,34 @@
+package com.ruoyi.account.bean.dto.sales;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+@Data
+@Schema(name = "AccountInvoiceApplicationDto", description = "璐㈠姟绠$悊--寮�绁ㄧ敵璇峰彴璐�(浼犲弬)")
+public class AccountInvoiceApplicationDto  {
+
+    @Schema(description = "瀹㈡埛ID")
+    private Integer customerId;
+
+    @Schema(description = "鐢宠鍗曞彿")
+    private String invoiceApplicationNo;
+
+    @Schema(description = "瀹℃牳鐘舵��:0寰呭鏍�1瀹℃牳閫氳繃2瀹℃牳涓嶉�氳繃")
+    private Integer status;
+
+    @Schema(description = "寮�濮嬫棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startDate;
+
+    @Schema(description = "缁撴潫鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endDate;
+
+
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/sales/AccountSalesCollectionDto.java b/src/main/java/com/ruoyi/account/bean/dto/sales/AccountSalesCollectionDto.java
new file mode 100644
index 0000000..ec3c042
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/sales/AccountSalesCollectionDto.java
@@ -0,0 +1,34 @@
+package com.ruoyi.account.bean.dto.sales;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+@Data
+@Schema(name = "AccountSalesCollectionDto", description = "璐㈠姟绠$悊--鏀舵鍗曞彴璐�(浼犲弬)")
+public class AccountSalesCollectionDto {
+
+    @Schema(description = "瀹㈡埛ID")
+    private Integer customerId;
+
+    @Schema(description = "鏀舵鍗曞彿")
+    private String collectionNumber;
+
+    @Schema(description = "鏀舵鏂瑰紡")
+    private String collectionMethod;
+
+    @Schema(description = "寮�濮嬫棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startDate;
+
+    @Schema(description = "缁撴潫鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endDate;
+
+
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/sales/AccountSalesInvoiceDto.java b/src/main/java/com/ruoyi/account/bean/dto/sales/AccountSalesInvoiceDto.java
new file mode 100644
index 0000000..4774edb
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/sales/AccountSalesInvoiceDto.java
@@ -0,0 +1,33 @@
+package com.ruoyi.account.bean.dto.sales;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+@Data
+@Schema(name = "AccountSalesInvoiceDto", description = "璐㈠姟绠$悊--閿�椤瑰彂绁ㄥ彴璐�(浼犲弬)")
+public class AccountSalesInvoiceDto {
+
+    @Schema(description = "瀹㈡埛ID")
+    private Integer customerId;
+
+    @Schema(description = "鍙戠エ鍙风爜")
+    private String invoiceNumber;
+
+    @Schema(description = "寮�濮嬫棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startDate;
+
+    @Schema(description = "缁撴潫鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endDate;
+
+    @Schema(description = "鐘舵��")
+    private Integer status;
+
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/SalesOutboundDto.java b/src/main/java/com/ruoyi/account/bean/dto/sales/SalesOutboundDto.java
similarity index 81%
rename from src/main/java/com/ruoyi/account/bean/dto/SalesOutboundDto.java
rename to src/main/java/com/ruoyi/account/bean/dto/sales/SalesOutboundDto.java
index 33bc1b9..b8c9cc6 100644
--- a/src/main/java/com/ruoyi/account/bean/dto/SalesOutboundDto.java
+++ b/src/main/java/com/ruoyi/account/bean/dto/sales/SalesOutboundDto.java
@@ -1,11 +1,11 @@
-package com.ruoyi.account.bean.dto;
+package com.ruoyi.account.bean.dto.sales;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
-import java.util.Date;
+import java.time.LocalDate;
 
 @Data
 @Schema(name = "SalesOutboundDto", description = "璐㈠姟绠$悊--閿�鍞嚭搴撳彴璐�(浼犲弬)")
@@ -14,16 +14,18 @@
     @Schema(description = "鍑哄簱鍗曞彿")
     private String outboundBatches;
 
+    private Long customerId;
+
     @Schema(description = "瀹㈡埛鍚嶇О")
     private String customerName;
 
     @Schema(description = "寮�濮嬫棩鏈�")
     @JsonFormat(pattern = "yyyy-MM-dd")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private Date startDate;
+    private LocalDate startDate;
 
     @Schema(description = "缁撴潫鏃ユ湡")
     @JsonFormat(pattern = "yyyy-MM-dd")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private Date endDate;
+    private LocalDate endDate;
 }
diff --git a/src/main/java/com/ruoyi/account/bean/dto/SalesReturnDto.java b/src/main/java/com/ruoyi/account/bean/dto/sales/SalesReturnDto.java
similarity index 81%
rename from src/main/java/com/ruoyi/account/bean/dto/SalesReturnDto.java
rename to src/main/java/com/ruoyi/account/bean/dto/sales/SalesReturnDto.java
index b7ebae2..5a239ae 100644
--- a/src/main/java/com/ruoyi/account/bean/dto/SalesReturnDto.java
+++ b/src/main/java/com/ruoyi/account/bean/dto/sales/SalesReturnDto.java
@@ -1,11 +1,11 @@
-package com.ruoyi.account.bean.dto;
+package com.ruoyi.account.bean.dto.sales;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
-import java.util.Date;
+import java.time.LocalDate;
 
 @Data
 @Schema(name = "SalesReturnDto", description = "璐㈠姟绠$悊--閿�鍞��璐у彴璐�(浼犲弬)")
@@ -14,16 +14,18 @@
     @Schema(description = "閫�璐у崟鍙�")
     private String returnNo;
 
+    private Long customerId;
+
     @Schema(description = "瀹㈡埛鍚嶇О")
     private String customerName;
 
     @Schema(description = "寮�濮嬫棩鏈�")
     @JsonFormat(pattern = "yyyy-MM-dd")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private Date startDate;
+    private LocalDate startDate;
 
     @Schema(description = "缁撴潫鏃ユ湡")
     @JsonFormat(pattern = "yyyy-MM-dd")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private Date endDate;
+    private LocalDate endDate;
 }
diff --git a/src/main/java/com/ruoyi/account/bean/vo/StatementAccountVo.java b/src/main/java/com/ruoyi/account/bean/vo/StatementAccountVo.java
new file mode 100644
index 0000000..4dd073c
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/StatementAccountVo.java
@@ -0,0 +1,25 @@
+package com.ruoyi.account.bean.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.ruoyi.account.pojo.AccountStatement;
+import com.ruoyi.account.pojo.AccountStatementDetails;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Schema(name = "StatementAccountVo", description = "璐㈠姟绠$悊--瀵硅处鍗曡鎯�(杩斿洖)")
+@ExcelIgnoreUnannotated
+public class StatementAccountVo extends AccountStatement {
+
+    //瀹㈡埛鍚嶇О(搴旀敹鏄鎴�,搴斾粯鏄緵搴斿晢)
+    @Schema(description = "瀹㈡埛鍚嶇О")
+    @Excel(name = "瀹㈡埛鍚嶇О")
+    private String customerName;
+
+    //瀵硅处鏄庣粏
+    @Schema(description = "瀵硅处鏄庣粏")
+    private List<AccountStatementDetails> accountStatementDetails;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/vo/AccountSubjectVo.java b/src/main/java/com/ruoyi/account/bean/vo/financial/AccountSubjectVo.java
similarity index 76%
rename from src/main/java/com/ruoyi/account/bean/vo/AccountSubjectVo.java
rename to src/main/java/com/ruoyi/account/bean/vo/financial/AccountSubjectVo.java
index c6bb078..106eb17 100644
--- a/src/main/java/com/ruoyi/account/bean/vo/AccountSubjectVo.java
+++ b/src/main/java/com/ruoyi/account/bean/vo/financial/AccountSubjectVo.java
@@ -1,6 +1,6 @@
-package com.ruoyi.account.bean.vo;
+package com.ruoyi.account.bean.vo.financial;
 
-import com.ruoyi.account.pojo.AccountSubject;
+import com.ruoyi.account.pojo.financial.AccountSubject;
 import lombok.Data;
 
 import java.util.ArrayList;
diff --git a/src/main/java/com/ruoyi/account/bean/vo/purchase/AccountPaymentApplicationVo.java b/src/main/java/com/ruoyi/account/bean/vo/purchase/AccountPaymentApplicationVo.java
new file mode 100644
index 0000000..26cae0e
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/purchase/AccountPaymentApplicationVo.java
@@ -0,0 +1,23 @@
+package com.ruoyi.account.bean.vo.purchase;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.ruoyi.account.pojo.purchase.AccountPaymentApplication;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(name = "AccountPaymentApplicationVo", description = "璐㈠姟绠$悊--浠樻鐢宠鍙拌处(杩斿洖)")
+@ExcelIgnoreUnannotated
+public class AccountPaymentApplicationVo extends AccountPaymentApplication {
+
+    @Schema(description = "渚涘簲鍟嗗悕绉�")
+    @Excel(name = "渚涘簲鍟嗗悕绉�")
+    private String supplierName;
+
+    @Schema(description = "鍏ュ簱鍗曞彿")
+    @Excel(name = "鍏ュ簱鍗曞彿")
+    private String inboundBatches;
+
+
+}
diff --git a/src/main/java/com/ruoyi/account/bean/vo/purchase/AccountPurchaseInvoiceVo.java b/src/main/java/com/ruoyi/account/bean/vo/purchase/AccountPurchaseInvoiceVo.java
new file mode 100644
index 0000000..9d753b2
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/purchase/AccountPurchaseInvoiceVo.java
@@ -0,0 +1,19 @@
+package com.ruoyi.account.bean.vo.purchase;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.ruoyi.account.pojo.purchase.AccountPurchaseInvoice;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(name = "AccountPurchaseInvoiceVo", description = "璐㈠姟绠$悊--杩涢」鍙戠エ鍙拌处(杩斿洖)")
+@ExcelIgnoreUnannotated
+public class AccountPurchaseInvoiceVo extends AccountPurchaseInvoice {
+
+    @Schema(description = "渚涘簲鍟嗗悕绉�")
+    @Excel(name = "渚涘簲鍟嗗悕绉�")
+    private String supplierName;
+
+
+}
diff --git a/src/main/java/com/ruoyi/account/bean/vo/purchase/AccountPurchasePaymentVo.java b/src/main/java/com/ruoyi/account/bean/vo/purchase/AccountPurchasePaymentVo.java
new file mode 100644
index 0000000..367e17a
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/purchase/AccountPurchasePaymentVo.java
@@ -0,0 +1,34 @@
+package com.ruoyi.account.bean.vo.purchase;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(name = "AccountPurchasePaymentVo", description = "璐㈠姟绠$悊--浠樻鍗曞彴璐�(杩斿洖)")
+@ExcelIgnoreUnannotated
+public class AccountPurchasePaymentVo extends AccountPurchasePayment {
+
+    @Schema(description = "渚涘簲鍟嗗悕绉�")
+    @Excel(name = "渚涘簲鍟嗗悕绉�")
+    private String supplierName;
+
+    @Schema(description = "浠樻鐢宠鍗曞彿")
+    @Excel(name = "浠樻鐢宠鍗曞彿")
+    private String invoiceApplicationNo;
+
+    @Schema(description = "寮�鎴疯")
+    @Excel(name = "寮�鎴疯")
+    private String bankAccountName;
+
+    @Schema(description = "閾惰璐﹀彿")
+    @Excel(name = "閾惰璐﹀彿")
+    private String bankAccountNum;
+
+    @Schema(description = "鏄惁鐢熸垚浜嗗璐﹀崟")
+    private boolean isAccountStatemen;
+
+
+}
diff --git a/src/main/java/com/ruoyi/account/bean/vo/PurchaseInboundVo.java b/src/main/java/com/ruoyi/account/bean/vo/purchase/PurchaseInboundVo.java
similarity index 92%
rename from src/main/java/com/ruoyi/account/bean/vo/PurchaseInboundVo.java
rename to src/main/java/com/ruoyi/account/bean/vo/purchase/PurchaseInboundVo.java
index 934502a..48831e1 100644
--- a/src/main/java/com/ruoyi/account/bean/vo/PurchaseInboundVo.java
+++ b/src/main/java/com/ruoyi/account/bean/vo/purchase/PurchaseInboundVo.java
@@ -1,4 +1,4 @@
-package com.ruoyi.account.bean.vo;
+package com.ruoyi.account.bean.vo.purchase;
 
 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.fasterxml.jackson.annotation.JsonFormat;
@@ -7,7 +7,7 @@
 import lombok.Data;
 
 import java.math.BigDecimal;
-import java.util.Date;
+import java.time.LocalDate;
 
 @Data
 @Schema(name = "PurchaseInboundVo", description = "璐㈠姟绠$悊--閲囪喘鍏ュ簱鍙拌处(杩斿洖)")
@@ -28,7 +28,7 @@
     @Schema(description = "鍏ュ簱鏃ユ湡")
     @Excel(name = "鍏ュ簱鏃ユ湡")
     @JsonFormat(pattern = "yyyy-MM-dd")
-    private Date InboundDate;
+    private LocalDate InboundDate;
 
     @Schema(description = "浜у搧鍚嶇О")
     @Excel(name = "浜у搧鍚嶇О")
diff --git a/src/main/java/com/ruoyi/account/bean/vo/PurchaseReturnVo.java b/src/main/java/com/ruoyi/account/bean/vo/purchase/PurchaseReturnVo.java
similarity index 96%
rename from src/main/java/com/ruoyi/account/bean/vo/PurchaseReturnVo.java
rename to src/main/java/com/ruoyi/account/bean/vo/purchase/PurchaseReturnVo.java
index e912993..82a90a3 100644
--- a/src/main/java/com/ruoyi/account/bean/vo/PurchaseReturnVo.java
+++ b/src/main/java/com/ruoyi/account/bean/vo/purchase/PurchaseReturnVo.java
@@ -1,4 +1,4 @@
-package com.ruoyi.account.bean.vo;
+package com.ruoyi.account.bean.vo.purchase;
 
 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.fasterxml.jackson.annotation.JsonFormat;
diff --git a/src/main/java/com/ruoyi/account/bean/vo/sales/AccountInvoiceApplicationVo.java b/src/main/java/com/ruoyi/account/bean/vo/sales/AccountInvoiceApplicationVo.java
new file mode 100644
index 0000000..55bf22b
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/sales/AccountInvoiceApplicationVo.java
@@ -0,0 +1,23 @@
+package com.ruoyi.account.bean.vo.sales;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.ruoyi.account.pojo.sales.AccountInvoiceApplication;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(name = "AccountInvoiceApplicationVo", description = "璐㈠姟绠$悊--寮�绁ㄧ敵璇峰彴璐�(杩斿洖)")
+@ExcelIgnoreUnannotated
+public class AccountInvoiceApplicationVo extends AccountInvoiceApplication {
+
+    @Schema(description = "瀹㈡埛鍚嶇О")
+    @Excel(name = "瀹㈡埛鍚嶇О")
+    private String customerName;
+
+    @Schema(description = "鍑哄簱鍗曞彿")
+    @Excel(name = "鍑哄簱鍗曞彿")
+    private String outboundBatches;
+
+
+}
diff --git a/src/main/java/com/ruoyi/account/bean/vo/sales/AccountSalesCollectionVo.java b/src/main/java/com/ruoyi/account/bean/vo/sales/AccountSalesCollectionVo.java
new file mode 100644
index 0000000..bde5fe0
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/sales/AccountSalesCollectionVo.java
@@ -0,0 +1,26 @@
+package com.ruoyi.account.bean.vo.sales;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.ruoyi.account.pojo.sales.AccountSalesCollection;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(name = "AccountSalesCollectionVo", description = "璐㈠姟绠$悊--鏀舵鍗曞彴璐�(杩斿洖)")
+@ExcelIgnoreUnannotated
+public class AccountSalesCollectionVo extends AccountSalesCollection {
+
+    @Schema(description = "瀹㈡埛鍚嶇О")
+    @Excel(name = "瀹㈡埛鍚嶇О")
+    private String customerName;
+
+    @Schema(description = "鍑哄簱鍗曞彿")
+    @Excel(name = "鍑哄簱鍗曞彿")
+    private String outboundBatches;
+
+    @Schema(description = "鏄惁鐢熸垚浜嗗璐﹀崟")
+    private boolean isAccountStatemen;
+
+
+}
diff --git a/src/main/java/com/ruoyi/account/bean/vo/sales/AccountSalesInvoiceVo.java b/src/main/java/com/ruoyi/account/bean/vo/sales/AccountSalesInvoiceVo.java
new file mode 100644
index 0000000..1dfd4e3
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/sales/AccountSalesInvoiceVo.java
@@ -0,0 +1,19 @@
+package com.ruoyi.account.bean.vo.sales;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.ruoyi.account.pojo.sales.AccountSalesInvoice;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(name = "AccountSalesInvoiceVo", description = "璐㈠姟绠$悊--閿�椤瑰彂绁ㄥ彴璐�(杩斿洖)")
+@ExcelIgnoreUnannotated
+public class AccountSalesInvoiceVo extends AccountSalesInvoice {
+
+    @Schema(description = "瀹㈡埛鍚嶇О")
+    @Excel(name = "瀹㈡埛鍚嶇О")
+    private String customerName;
+
+
+}
diff --git a/src/main/java/com/ruoyi/account/bean/vo/SalesOutboundVo.java b/src/main/java/com/ruoyi/account/bean/vo/sales/SalesOutboundVo.java
similarity index 88%
rename from src/main/java/com/ruoyi/account/bean/vo/SalesOutboundVo.java
rename to src/main/java/com/ruoyi/account/bean/vo/sales/SalesOutboundVo.java
index 5ccdb5b..13c1b27 100644
--- a/src/main/java/com/ruoyi/account/bean/vo/SalesOutboundVo.java
+++ b/src/main/java/com/ruoyi/account/bean/vo/sales/SalesOutboundVo.java
@@ -1,4 +1,4 @@
-package com.ruoyi.account.bean.vo;
+package com.ruoyi.account.bean.vo.sales;
 
 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.fasterxml.jackson.annotation.JsonFormat;
@@ -7,7 +7,7 @@
 import lombok.Data;
 
 import java.math.BigDecimal;
-import java.util.Date;
+import java.time.LocalDate;
 
 @Data
 @Schema(name = "SalesOutboundVo", description = "璐㈠姟绠$悊--閿�鍞嚭搴撳彴璐�(杩斿洖)")
@@ -28,7 +28,7 @@
     @Schema(description = "鍑哄簱鏃ユ湡")
     @Excel(name = "鍑哄簱鏃ユ湡")
     @JsonFormat(pattern = "yyyy-MM-dd")
-    private Date shippingDate;
+    private LocalDate shippingDate;
 
     @Schema(description = "浜у搧鍚嶇О")
     @Excel(name = "浜у搧鍚嶇О")
@@ -42,6 +42,9 @@
     @Excel(name = "閲戦")
     private BigDecimal outboundAmount;
 
+    @Schema(description = "绋庣巼")
+    private BigDecimal taxRate;
+
     @Schema(description = "鍙戣揣缂栧彿")
     @Excel(name = "鍙戣揣缂栧彿")
     private String shippingNo;
diff --git a/src/main/java/com/ruoyi/account/bean/vo/SalesReturnVo.java b/src/main/java/com/ruoyi/account/bean/vo/sales/SalesReturnVo.java
similarity index 96%
rename from src/main/java/com/ruoyi/account/bean/vo/SalesReturnVo.java
rename to src/main/java/com/ruoyi/account/bean/vo/sales/SalesReturnVo.java
index c425737..980d7f8 100644
--- a/src/main/java/com/ruoyi/account/bean/vo/SalesReturnVo.java
+++ b/src/main/java/com/ruoyi/account/bean/vo/sales/SalesReturnVo.java
@@ -1,4 +1,4 @@
-package com.ruoyi.account.bean.vo;
+package com.ruoyi.account.bean.vo.sales;
 
 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.fasterxml.jackson.annotation.JsonFormat;
diff --git a/src/main/java/com/ruoyi/account/controller/AccountExpenseController.java b/src/main/java/com/ruoyi/account/controller/AccountExpenseController.java
deleted file mode 100644
index 9d49919..0000000
--- a/src/main/java/com/ruoyi/account/controller/AccountExpenseController.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package com.ruoyi.account.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.bean.dto.ReportDateDto;
-import com.ruoyi.account.pojo.AccountExpense;
-import com.ruoyi.account.service.AccountExpenseService;
-import com.ruoyi.account.service.AccountIncomeService;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.dto.DateQueryDto;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Operation;
-import jakarta.annotation.Resource;
-import org.springframework.util.CollectionUtils;
-import org.springframework.web.bind.annotation.*;
-
-import jakarta.servlet.http.HttpServletResponse;
-import java.util.Date;
-import java.util.List;
-
-/**
- * 璐㈠姟绠$悊--鏀嚭绠$悊
- */
-@RestController
-@RequestMapping("/account/accountExpense")
-@Tag(name = "璐㈠姟绠$悊--鏀嚭绠$悊")
-public class AccountExpenseController {
-
-    @Resource
-    private AccountExpenseService accountExpenseService;
-
-    @Resource
-    private AccountIncomeService accountIncomeService;
-
-
-    /**
-     * 鏂板
-     * @param accountExpense
-     * @return
-     */
-    @PostMapping("/add")
-    @Operation(summary = "鏂板")
-    public AjaxResult add(@RequestBody AccountExpense accountExpense) {
-        accountExpense.setInputTime(new Date());
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        accountExpense.setInputUser(loginUser.getNickName());
-        return AjaxResult.success(accountExpenseService.save(accountExpense));
-    }
-
-    /**
-     * 鍒犻櫎
-     * @param ids
-     * @return
-     */
-    @DeleteMapping("/del")
-    @Operation(summary = "鍒犻櫎")
-    public AjaxResult delQualityInspect(@RequestBody List<Integer> ids) {
-        if(CollectionUtils.isEmpty(ids)){
-            return AjaxResult.error("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
-        }
-        //鍒犻櫎妫�楠屽崟
-        return AjaxResult.success(accountExpenseService.removeBatchByIds(ids));
-    }
-
-    /**
-     * 淇敼
-     * @param accountExpense
-     * @return
-     */
-    @PostMapping("/update")
-    @Operation(summary = "淇敼")
-    public AjaxResult update(@RequestBody AccountExpense accountExpense) {
-        return AjaxResult.success(accountExpenseService.updateById(accountExpense));
-    }
-
-    /**
-     *鍒嗛〉鏌ヨ
-     * @param page
-     * @param accountExpense
-     * @return
-     */
-    @GetMapping("/listPage")
-    @Operation(summary = "鍒嗛〉鏌ヨ")
-    public AjaxResult accountExpenseListPage(Page page, AccountExpense accountExpense) {
-        return AjaxResult.success(accountExpenseService.accountExpenseListPage(page, accountExpense));
-    }
-
-    /**
-     * 璇︽儏
-     * @param id
-     * @return
-     */
-    @GetMapping("/{id}")
-    @Operation(summary = "璇︽儏")
-    public AjaxResult accountExpenseDetail(@PathVariable("id") Integer id) {
-        return AjaxResult.success(accountExpenseService.getById(id));
-    }
-
-    /**
-     * 瀵煎嚭
-     * @param response
-     * @param accountExpense
-     */
-    @PostMapping("/export")
-    @Operation(summary = "瀵煎嚭")
-    public void accountExpenseExport(HttpServletResponse response,AccountExpense accountExpense) {
-        accountExpenseService.accountExpenseExport(response, accountExpense);
-    }
-
-    /**
-     * 璐㈠姟鎶ヨ〃鍥捐〃鏌ヨ
-     * @param dateQueryDto
-     * @return
-     */
-    @GetMapping("/report/forms")
-    @Operation(summary = "璐㈠姟鎶ヨ〃鍥捐〃鏌ヨ")
-    public AjaxResult report(DateQueryDto dateQueryDto) {
-        return AjaxResult.success(accountExpenseService.report(dateQueryDto));
-    }
-
-    /**
-     * 璐㈠姟鎶ヨ〃-璐㈠姟鍒嗘瀽
-     * @return
-     */
-    @GetMapping("/report/analysis")
-    @Operation(summary = "璐㈠姟鎶ヨ〃-璐㈠姟鍒嗘瀽")
-    public AjaxResult analysis() {
-        return AjaxResult.success(accountExpenseService.analysis());
-    }
-
-    /**
-     * 璐㈠姟鎶ヨ〃鍥捐〃鏀跺叆骞村害鏌ヨ
-     * @param
-     * @return
-     */
-    @GetMapping("/report/income")
-    @Operation(summary = "璐㈠姟鎶ヨ〃鍥捐〃鏀跺叆骞村害鏌ヨ")
-    public AjaxResult reportIncome(ReportDateDto reportDateDto) {
-        return AjaxResult.success(accountIncomeService.reportIncome(reportDateDto));
-    }
-
-    /**
-     * 璐㈠姟鎶ヨ〃鍥捐〃鏀嚭骞村害鏌ヨ
-     * @param
-     * @return
-     */
-    @GetMapping("/report/expense")
-    @Operation(summary = "璐㈠姟鎶ヨ〃鍥捐〃鏀嚭骞村害鏌ヨ")
-    public AjaxResult reportExpense(ReportDateDto reportDateDto) {
-        return AjaxResult.success(accountExpenseService.reportExpense(reportDateDto));
-    }
-
-
-}
diff --git a/src/main/java/com/ruoyi/account/controller/AccountFileController.java b/src/main/java/com/ruoyi/account/controller/AccountFileController.java
deleted file mode 100644
index 42c20d1..0000000
--- a/src/main/java/com/ruoyi/account/controller/AccountFileController.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.ruoyi.account.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.pojo.AccountFile;
-import com.ruoyi.account.service.AccountFileService;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.quality.pojo.QualityInspectFile;
-import com.ruoyi.quality.service.IQualityInspectFileService;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Operation;
-import org.springframework.util.CollectionUtils;
-import org.springframework.web.bind.annotation.*;
-
-import jakarta.annotation.Resource;
-import java.util.List;
-
-/**
- * 璐㈠姟闄勪欢
- */
-@RestController
-@RequestMapping("/account/accountFile")
-@Tag(name = "璐㈠姟闄勪欢")
-public class AccountFileController {
-
-
-    @Resource
-    private AccountFileService accountFileService;
-
-
-    /**
-     * 鏂板
-     * @param accountFile
-     * @return
-     */
-    @PostMapping("/add")
-    @Operation(summary = "鏂板")
-    public AjaxResult add(@RequestBody AccountFile accountFile) {
-        return AjaxResult.success(accountFileService.save(accountFile));
-    }
-
-    /**
-     * 鍒犻櫎
-     * @param ids
-     * @return
-     */
-    @DeleteMapping("/del")
-    @Operation(summary = "鍒犻櫎")
-    public AjaxResult delAccountFile(@RequestBody List<Integer> ids) {
-        if(CollectionUtils.isEmpty(ids)){
-            return AjaxResult.error("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
-        }
-        //鍒犻櫎妫�楠岄檮浠�
-        return AjaxResult.success(accountFileService.removeBatchByIds(ids));
-    }
-
-    /**
-     *鍒嗛〉鏌ヨ
-     * @param page
-     * @param accountFile
-     * @return
-     */
-    @GetMapping("/listPage")
-    @Operation(summary = "鍒嗛〉鏌ヨ")
-    public AjaxResult accountFileListPage(Page page, AccountFile accountFile) {
-        return AjaxResult.success(accountFileService.accountFileListPage(page, accountFile));
-    }
-
-
-
-
-}
diff --git a/src/main/java/com/ruoyi/account/controller/AccountIncomeController.java b/src/main/java/com/ruoyi/account/controller/AccountIncomeController.java
deleted file mode 100644
index 690e75a..0000000
--- a/src/main/java/com/ruoyi/account/controller/AccountIncomeController.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package com.ruoyi.account.controller;
-
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.pojo.AccountIncome;
-import com.ruoyi.account.service.AccountFileService;
-import com.ruoyi.account.service.AccountIncomeService;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.quality.pojo.QualityInspect;
-import com.ruoyi.quality.pojo.QualityInspectFile;
-import com.ruoyi.quality.pojo.QualityInspectParam;
-import com.ruoyi.quality.service.IQualityInspectFileService;
-import com.ruoyi.quality.service.IQualityInspectParamService;
-import com.ruoyi.quality.service.IQualityInspectService;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Operation;
-import org.springframework.util.CollectionUtils;
-import org.springframework.web.bind.annotation.*;
-
-import jakarta.annotation.Resource;
-import jakarta.servlet.http.HttpServletResponse;
-import java.util.Date;
-import java.util.List;
-
-/**
- * 璐㈠姟绠$悊--鏀跺叆绠$悊
- */
-@RestController
-@RequestMapping("/account/accountIncome")
-@Tag(name = "璐㈠姟绠$悊--鏀跺叆绠$悊")
-public class AccountIncomeController {
-
-    @Resource
-    private AccountIncomeService accountIncomeService;
-
-
-    /**
-     * 鏂板
-     * @param accountIncome
-     * @return
-     */
-    @PostMapping("/add")
-    @Operation(summary = "鏂板")
-    public AjaxResult add(@RequestBody AccountIncome accountIncome) {
-        accountIncome.setInputTime(new Date());
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        accountIncome.setInputUser(loginUser.getNickName());
-        return AjaxResult.success(accountIncomeService.save(accountIncome));
-    }
-
-    /**
-     * 鍒犻櫎
-     * @param ids
-     * @return
-     */
-    @DeleteMapping("/del")
-    @Operation(summary = "鍒犻櫎")
-    public AjaxResult delQualityInspect(@RequestBody List<Integer> ids) {
-        if(CollectionUtils.isEmpty(ids)){
-            return AjaxResult.error("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
-        }
-        //鍒犻櫎妫�楠屽崟
-        return AjaxResult.success(accountIncomeService.removeBatchByIds(ids));
-    }
-
-    /**
-     * 淇敼
-     * @param accountIncome
-     * @return
-     */
-    @PostMapping("/update")
-    @Operation(summary = "淇敼")
-    public AjaxResult update(@RequestBody AccountIncome accountIncome) {
-        return AjaxResult.success(accountIncomeService.updateById(accountIncome));
-    }
-
-    /**
-     *鍒嗛〉鏌ヨ
-     * @param page
-     * @param accountIncome
-     * @return
-     */
-    @GetMapping("/listPage")
-    @Operation(summary = "鍒嗛〉鏌ヨ")
-    public AjaxResult accountIncomeListPage(Page page, AccountIncome accountIncome) {
-        return AjaxResult.success(accountIncomeService.accountIncomeListPage(page, accountIncome));
-    }
-
-    /**
-     * 璇︽儏
-     * @param id
-     * @return
-     */
-    @GetMapping("/{id}")
-    @Operation(summary = "璇︽儏")
-    public AjaxResult accountIncomeDetail(@PathVariable("id") Integer id) {
-        return AjaxResult.success(accountIncomeService.getById(id));
-    }
-
-    /**
-     * 瀵煎嚭
-     * @param response
-     * @param accountIncome
-     */
-    @PostMapping("/export")
-    @Operation(summary = "瀵煎嚭")
-    public void accountIncomeExport(HttpServletResponse response,AccountIncome accountIncome) {
-        accountIncomeService.accountIncomeExport(response, accountIncome);
-    }
-
-
-}
diff --git a/src/main/java/com/ruoyi/account/controller/AccountStatementController.java b/src/main/java/com/ruoyi/account/controller/AccountStatementController.java
new file mode 100644
index 0000000..b53f457
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/controller/AccountStatementController.java
@@ -0,0 +1,71 @@
+package com.ruoyi.account.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.StatementAccountDto;
+import com.ruoyi.account.bean.vo.StatementAccountVo;
+import com.ruoyi.account.service.AccountStatementService;
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+
+/**
+ * <p>
+ *  鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 09:42:47
+ */
+@RestController
+@RequestMapping("/accountStatement")
+@RequiredArgsConstructor
+@Tag(name = "璐㈠姟绠$悊-瀵硅处鍗�")
+public class AccountStatementController {
+
+    private final AccountStatementService accountStatementService;
+
+    @GetMapping("/getAccountStatementDetailsByMonth")
+    @Log(title = "鏍规嵁瀹㈡埛鍜屾湀浠芥煡璇㈠璐﹀崟鏄庣粏", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--鏍规嵁瀹㈡埛鍜屾湀浠芥煡璇㈠璐﹀崟鏄庣粏")
+    public R getAccountStatementDetailsByMonth(StatementAccountDto statementAccountDto) {
+        return R.ok(accountStatementService.getAccountStatementDetailsByMonth(statementAccountDto));
+    }
+
+    @PostMapping("/addAccountStatement")
+    @Log(title = "鏂板瀵硅处鍗�", businessType = BusinessType.INSERT)
+    @Operation(summary = "璐㈠姟绠$悊--鏂板瀵硅处鍗�")
+    public R addAccountStatement(@RequestBody StatementAccountVo statementAccountVo) {
+        return R.ok(accountStatementService.addAccountStatement(statementAccountVo));
+    }
+
+    @DeleteMapping("/deleteAccountStatement")
+    @Log(title = "鍒犻櫎瀵硅处鍗�", businessType = BusinessType.DELETE)
+    @Operation(summary = "璐㈠姟绠$悊--鍒犻櫎瀵硅处鍗�")
+    public R deleteAccountStatement(@RequestParam("ids") Long[] ids) {
+        return R.ok(accountStatementService.deleteAccountStatement(Arrays.asList(ids)));
+    }
+
+    @GetMapping("/listPageAccountStatement")
+    @Log(title = "瀵硅处鍗曞彴璐�", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--瀵硅处鍗曞彴璐�")
+    public R<IPage<StatementAccountVo>> listPageAccountStatement(Page page, StatementAccountDto statementAccountDto) {
+        IPage<StatementAccountVo> listPage = accountStatementService.listPageAccountStatement(page,statementAccountDto);
+        return R.ok(listPage);
+    }
+
+    @PostMapping("/exportAccountStatement")
+    @Operation(summary = "瀵煎嚭瀵硅处鍗曟枃浠�")
+    @Log(title = "瀵煎嚭瀵硅处鍗曟枃浠�", businessType = BusinessType.EXPORT)
+    public void exportAccountStatement(HttpServletResponse response, StatementAccountDto statementAccountDto) {
+        accountStatementService.exportAccountStatement(response,statementAccountDto);
+    }
+
+}
diff --git a/src/main/java/com/ruoyi/account/controller/BorrowInfoController.java b/src/main/java/com/ruoyi/account/controller/BorrowInfoController.java
deleted file mode 100644
index 7620c19..0000000
--- a/src/main/java/com/ruoyi/account/controller/BorrowInfoController.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.ruoyi.account.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.pojo.BorrowInfo;
-import com.ruoyi.account.service.BorrowInfoService;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.framework.aspectj.lang.annotation.Log;
-import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Operation;
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.*;
-
-import jakarta.servlet.http.HttpServletResponse;
-import java.util.List;
-
-/**
- * <p>
- * 鍊熸淇℃伅琛� 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-01-15 02:57:29
- */
-@Tag(name = "鍊熸淇℃伅琛�")
-@RestController
-@RequestMapping("/borrowInfo")
-@AllArgsConstructor
-public class BorrowInfoController {
-
-    private BorrowInfoService borrowInfoService;
-
-    @GetMapping("/listPage")
-    @Operation(summary = "鍒嗛〉鏌ヨ")
-    public AjaxResult listPage(Page page, BorrowInfo borrowInfo) {
-        return borrowInfoService.listPage(page,borrowInfo);
-    }
-
-    /**
-     * 鏂板
-     */
-    @PostMapping("/add")
-    @Transactional(rollbackFor = Exception.class)
-    @Log(title = "鏂板鍊熸淇℃伅", businessType = BusinessType.INSERT)
-    public AjaxResult add(@RequestBody BorrowInfo borrowInfo) {
-        return borrowInfoService.add(borrowInfo);
-    }
-
-    /**
-     * 淇敼
-     */
-    @PostMapping("/update")
-    @Transactional(rollbackFor = Exception.class)
-    @Log(title = "淇敼鍊熸淇℃伅", businessType = BusinessType.UPDATE)
-    public AjaxResult updateBorrowInfo(@RequestBody BorrowInfo borrowInfo) {
-        return borrowInfoService.updateBorrowInfo(borrowInfo);
-    }
-
-
-    /**
-     * 鍒犻櫎
-     */
-    @DeleteMapping("/delete")
-    @Transactional(rollbackFor = Exception.class)
-    @Log(title = "鍒犻櫎鍊熸淇℃伅", businessType = BusinessType.DELETE)
-    public AjaxResult delete(@RequestBody List<Long> ids) {
-        return borrowInfoService.delete(ids);
-    }
-
-    /**
-     * 瀵煎嚭
-     */
-    @PostMapping("/export")
-    @Operation(summary = "瀵煎嚭鍊熸淇℃伅")
-    public void export(HttpServletResponse response, BorrowInfo borrowInfo) {
-        List<BorrowInfo> list = borrowInfoService.list();
-        ExcelUtil<BorrowInfo> util = new ExcelUtil<>(BorrowInfo.class);
-        util.exportExcel(response,list, "鍊熸淇℃伅鏁版嵁");
-    }
-
-
-}
diff --git a/src/main/java/com/ruoyi/account/controller/AccountSubjectController.java b/src/main/java/com/ruoyi/account/controller/financial/AccountSubjectController.java
similarity index 91%
rename from src/main/java/com/ruoyi/account/controller/AccountSubjectController.java
rename to src/main/java/com/ruoyi/account/controller/financial/AccountSubjectController.java
index 38dd0ce..19d333d 100644
--- a/src/main/java/com/ruoyi/account/controller/AccountSubjectController.java
+++ b/src/main/java/com/ruoyi/account/controller/financial/AccountSubjectController.java
@@ -1,10 +1,10 @@
-package com.ruoyi.account.controller;
+package com.ruoyi.account.controller.financial;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.bean.dto.AccountSubjectDto;
-import com.ruoyi.account.bean.vo.AccountSubjectVo;
-import com.ruoyi.account.service.AccountSubjectService;
+import com.ruoyi.account.bean.dto.financial.AccountSubjectDto;
+import com.ruoyi.account.bean.vo.financial.AccountSubjectVo;
+import com.ruoyi.account.service.purchase.AccountSubjectService;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.domain.R;
diff --git a/src/main/java/com/ruoyi/account/controller/AccounPurchaseController.java b/src/main/java/com/ruoyi/account/controller/purchase/AccounPurchaseController.java
similarity index 88%
rename from src/main/java/com/ruoyi/account/controller/AccounPurchaseController.java
rename to src/main/java/com/ruoyi/account/controller/purchase/AccounPurchaseController.java
index d1993ea..283e8fb 100644
--- a/src/main/java/com/ruoyi/account/controller/AccounPurchaseController.java
+++ b/src/main/java/com/ruoyi/account/controller/purchase/AccounPurchaseController.java
@@ -1,12 +1,12 @@
-package com.ruoyi.account.controller;
+package com.ruoyi.account.controller.purchase;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.bean.dto.PurchaseInboundDto;
-import com.ruoyi.account.bean.dto.PurchaseReturnDto;
-import com.ruoyi.account.bean.vo.PurchaseInboundVo;
-import com.ruoyi.account.bean.vo.PurchaseReturnVo;
-import com.ruoyi.account.service.AccountPurchaseService;
+import com.ruoyi.account.bean.dto.purchase.PurchaseInboundDto;
+import com.ruoyi.account.bean.dto.purchase.PurchaseReturnDto;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseReturnVo;
+import com.ruoyi.account.service.financial.AccountPurchaseService;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.domain.R;
diff --git a/src/main/java/com/ruoyi/account/controller/purchase/AccountPaymentApplicationController.java b/src/main/java/com/ruoyi/account/controller/purchase/AccountPaymentApplicationController.java
new file mode 100644
index 0000000..423d0ef
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/controller/purchase/AccountPaymentApplicationController.java
@@ -0,0 +1,86 @@
+package com.ruoyi.account.controller.purchase;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.purchase.AccountPaymentApplicationDto;
+import com.ruoyi.account.bean.vo.purchase.AccountPaymentApplicationVo;
+import com.ruoyi.account.pojo.purchase.AccountPaymentApplication;
+import com.ruoyi.account.service.purchase.AccountPaymentApplicationService;
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--浠樻鐢宠 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 03:44:22
+ */
+@RestController
+@RequestMapping("/accountPaymentApplication")
+@Tag(name = "璐㈠姟绠$悊--浠樻鐢宠")
+@RequiredArgsConstructor
+public class AccountPaymentApplicationController {
+
+    private final AccountPaymentApplicationService accountPaymentApplicationService;
+
+    @GetMapping("/listPageAccountPaymentApplication")
+    @Log(title = "浠樻鐢宠鍙拌处", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--浠樻鐢宠鍙拌处")
+    public R<IPage<AccountPaymentApplicationVo>> listPageAccountPaymentApplication(Page page, AccountPaymentApplicationDto accountPaymentApplicationDto) {
+        IPage<AccountPaymentApplicationVo> listPage = accountPaymentApplicationService.listPageAccountPaymentApplication(page,accountPaymentApplicationDto);
+        return R.ok(listPage);
+    }
+
+    @GetMapping("/getInboundBatchesBySupplier")
+    @Log(title = "鏍规嵁渚涘簲鍟嗘煡璇㈠叆搴撳崟鍙�(浠樻鐢宠)", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--鏍规嵁渚涘簲鍟嗘煡璇㈠叆搴撳崟鍙�(浠樻鐢宠)")
+    public R getInboundBatchesBySupplier(Integer supplierId) {
+        return R.ok(accountPaymentApplicationService.getInboundBatchesBySupplier(supplierId));
+    }
+
+    @PostMapping("/addAccountPaymentApplication")
+    @Log(title = "鏂板浠樻鐢宠", businessType = BusinessType.INSERT)
+    @Operation(summary = "璐㈠姟绠$悊--鏂板浠樻鐢宠")
+    public R addAccountPaymentApplication(@RequestBody AccountPaymentApplication accountPaymentApplication) {
+        return R.ok(accountPaymentApplicationService.addAccountPaymentApplication(accountPaymentApplication));
+    }
+
+    @PutMapping("/updateAccountPaymentApplication")
+    @Log(title = "淇敼浠樻鐢宠", businessType = BusinessType.UPDATE)
+    @Operation(summary = "璐㈠姟绠$悊--淇敼浠樻鐢宠")
+    public R updateAccountPaymentApplication(@RequestBody AccountPaymentApplication accountPaymentApplication) {
+        return R.ok(accountPaymentApplicationService.updateById(accountPaymentApplication));
+    }
+
+    @PutMapping("/auditAccountPaymentApplication")
+    @Log(title = "瀹℃牳浠樻鐢宠", businessType = BusinessType.UPDATE)
+    @Operation(summary = "璐㈠姟绠$悊--瀹℃牳浠樻鐢宠")
+    public R auditAccountPaymentApplication(@RequestBody AccountPaymentApplication accountPaymentApplication) {
+        return R.ok(accountPaymentApplicationService.updateById(accountPaymentApplication));
+    }
+
+    @DeleteMapping("/deleteAccountPaymentApplication")
+    @Log(title = "鍒犻櫎浠樻鐢宠", businessType = BusinessType.DELETE)
+    @Operation(summary = "璐㈠姟绠$悊--鍒犻櫎浠樻鐢宠")
+    public R deleteAccountPaymentApplication(@RequestParam("ids") Long[] ids) {
+        return R.ok(accountPaymentApplicationService.deleteAccountPaymentApplication(Arrays.asList(ids)));
+    }
+
+    @PostMapping("/exportAccountPaymentApplication")
+    @Operation(summary = "瀵煎嚭浠樻鐢宠鏂囦欢")
+    @Log(title = "瀵煎嚭浠樻鐢宠鏂囦欢", businessType = BusinessType.EXPORT)
+    public void exportAccountPaymentApplication(HttpServletResponse response, AccountPaymentApplicationDto accountPaymentApplicationDto) {
+        accountPaymentApplicationService.exportAccountPaymentApplication(response,accountPaymentApplicationDto);
+    }
+
+}
diff --git a/src/main/java/com/ruoyi/account/controller/purchase/AccountPurchaseInvoiceController.java b/src/main/java/com/ruoyi/account/controller/purchase/AccountPurchaseInvoiceController.java
new file mode 100644
index 0000000..c755aad
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/controller/purchase/AccountPurchaseInvoiceController.java
@@ -0,0 +1,79 @@
+package com.ruoyi.account.controller.purchase;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.purchase.AccountPurchaseInvoiceDto;
+import com.ruoyi.account.bean.vo.purchase.AccountPurchaseInvoiceVo;
+import com.ruoyi.account.pojo.purchase.AccountPurchaseInvoice;
+import com.ruoyi.account.service.purchase.AccountPurchaseInvoiceService;
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--杩涢」鍙戠エ 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 03:06:17
+ */
+@RestController
+@RequestMapping("/accountPurchaseInvoice")
+@Tag(name = "璐㈠姟绠$悊--杩涢」鍙戠エ")
+@RequiredArgsConstructor
+public class AccountPurchaseInvoiceController {
+
+    private final AccountPurchaseInvoiceService accountPurchaseInvoiceService;
+
+    @GetMapping("/listPageAccountPurchaseInvoice")
+    @Log(title = "杩涢」鍙戠エ鍙拌处", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--杩涢」鍙戠エ鍙拌处")
+    public R<IPage<AccountPurchaseInvoiceVo>> listPageAccountPurchaseInvoice(Page page, AccountPurchaseInvoiceDto accountPurchaseInvoiceDto) {
+        IPage<AccountPurchaseInvoiceVo> listPage = accountPurchaseInvoiceService.listPageAccountPurchaseInvoice(page,accountPurchaseInvoiceDto);
+        return R.ok(listPage);
+    }
+
+    @GetMapping("/getInboundBatchesBySupplier")
+    @Log(title = "鏍规嵁渚涘簲鍟嗘煡璇㈠叆搴撳崟鍙�(杩涢」鍙戠エ)", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--鏍规嵁渚涘簲鍟嗘煡璇㈠叆搴撳崟鍙�(杩涢」鍙戠エ)")
+    public R getInboundBatchesBySupplier(Integer supplierId) {
+        return R.ok(accountPurchaseInvoiceService.getInboundBatchesBySupplier(supplierId));
+    }
+
+    @PostMapping("/addAccountPurchaseInvoice")
+    @Log(title = "鏂板杩涢」鍙戠エ", businessType = BusinessType.INSERT)
+    @Operation(summary = "璐㈠姟绠$悊--鏂板杩涢」鍙戠エ")
+    public R addAccountPurchaseInvoice(@RequestBody AccountPurchaseInvoice accountPurchaseInvoice) {
+        return R.ok(accountPurchaseInvoiceService.save(accountPurchaseInvoice));
+    }
+
+    @PutMapping("/cancelAccountPurchaseInvoice")
+    @Log(title = "浣滃簾杩涢」鍙戠エ", businessType = BusinessType.INSERT)
+    @Operation(summary = "璐㈠姟绠$悊--浣滃簾閿�椤瑰彂绁�")
+    public R cancelAccountPurchaseInvoice(@RequestBody AccountPurchaseInvoice accountPurchaseInvoice) {
+        return R.ok(accountPurchaseInvoiceService.updateById(accountPurchaseInvoice));
+    }
+
+    @DeleteMapping("/deleteAccountPurchaseInvoice")
+    @Log(title = "鍒犻櫎杩涢」鍙戠エ", businessType = BusinessType.DELETE)
+    @Operation(summary = "璐㈠姟绠$悊--鍒犻櫎杩涢」鍙戠エ")
+    public R deleteAccountPurchaseInvoice(@RequestParam("ids") Long[] ids) {
+        return R.ok(accountPurchaseInvoiceService.deleteAccountPurchaseInvoice(Arrays.asList(ids)));
+    }
+
+    @PostMapping("/exportAccountPurchaseInvoice")
+    @Operation(summary = "瀵煎嚭杩涢」鍙戠エ鏂囦欢")
+    @Log(title = "瀵煎嚭杩涢」鍙戠エ鏂囦欢", businessType = BusinessType.EXPORT)
+    public void exportAccountPurchaseInvoice(HttpServletResponse response, AccountPurchaseInvoiceDto accountPurchaseInvoiceDto) {
+        accountPurchaseInvoiceService.exportAccountPurchaseInvoice(response,accountPurchaseInvoiceDto);
+    }
+
+}
diff --git a/src/main/java/com/ruoyi/account/controller/purchase/AccountPurchasePaymentController.java b/src/main/java/com/ruoyi/account/controller/purchase/AccountPurchasePaymentController.java
new file mode 100644
index 0000000..c73e547
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/controller/purchase/AccountPurchasePaymentController.java
@@ -0,0 +1,71 @@
+package com.ruoyi.account.controller.purchase;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.purchase.AccountPurchasePaymentDto;
+import com.ruoyi.account.bean.vo.purchase.AccountPurchasePaymentVo;
+import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
+import com.ruoyi.account.service.purchase.AccountPurchasePaymentService;
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--浠樻鍗� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 04:14:51
+ */
+@RestController
+@RequestMapping("/accountPurchasePayment")
+@Tag(name = "璐㈠姟绠$悊--浠樻鍗�")
+@RequiredArgsConstructor
+public class AccountPurchasePaymentController {
+
+    private final AccountPurchasePaymentService accountPurchasePaymentService;
+
+    @GetMapping("/listPageAccountPurchasePayment")
+    @Log(title = "浠樻鍗曞彴璐�", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--浠樻鍗曞彴璐�")
+    public R<IPage<AccountPurchasePaymentVo>> listPageAccountPurchasePayment(Page page, AccountPurchasePaymentDto accountPurchasePaymentDto) {
+        IPage<AccountPurchasePaymentVo> listPage = accountPurchasePaymentService.listPageAccountPurchasePayment(page,accountPurchasePaymentDto);
+        return R.ok(listPage);
+    }
+
+    @PostMapping("/addAccountPurchasePayment")
+    @Log(title = "鏂板浠樻鍗�", businessType = BusinessType.INSERT)
+    @Operation(summary = "璐㈠姟绠$悊--鏂板浠樻鍗�")
+    public R addAccountPurchasePayment(@RequestBody AccountPurchasePayment accountPurchasePayment) {
+        return R.ok(accountPurchasePaymentService.addAccountPurchasePayment(accountPurchasePayment));
+    }
+
+    @PutMapping("/updateAccountPurchasePayment")
+    @Log(title = "缂栬緫浠樻鍗�", businessType = BusinessType.UPDATE)
+    @Operation(summary = "璐㈠姟绠$悊--缂栬緫浠樻鍗�")
+    public R updateAccountPurchasePayment(@RequestBody AccountPurchasePayment accountPurchasePayment) {
+        return R.ok(accountPurchasePaymentService.updateById(accountPurchasePayment));
+    }
+
+    @DeleteMapping("/deleteAccountPurchasePayment")
+    @Log(title = "鍒犻櫎浠樻鍗�", businessType = BusinessType.DELETE)
+    @Operation(summary = "璐㈠姟绠$悊--鍒犻櫎浠樻鍗�")
+    public R deleteAccountPurchasePayment(@RequestParam("ids") Long[] ids) {
+        return R.ok(accountPurchasePaymentService.deleteAccountPurchasePayment(Arrays.asList(ids)));
+    }
+
+    @PostMapping("/exportAccountPurchasePayment")
+    @Operation(summary = "瀵煎嚭浠樻鍗曟枃浠�")
+    @Log(title = "瀵煎嚭浠樻鍗曟枃浠�", businessType = BusinessType.EXPORT)
+    public void exportAccountPurchasePayment(HttpServletResponse response, AccountPurchasePaymentDto accountPurchasePaymentDto) {
+        accountPurchasePaymentService.exportAccountPurchasePayment(response,accountPurchasePaymentDto);
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/controller/sales/AccountInvoiceApplicationController.java b/src/main/java/com/ruoyi/account/controller/sales/AccountInvoiceApplicationController.java
new file mode 100644
index 0000000..00b490f
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/controller/sales/AccountInvoiceApplicationController.java
@@ -0,0 +1,86 @@
+package com.ruoyi.account.controller.sales;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.sales.AccountInvoiceApplicationDto;
+import com.ruoyi.account.bean.vo.sales.AccountInvoiceApplicationVo;
+import com.ruoyi.account.pojo.sales.AccountInvoiceApplication;
+import com.ruoyi.account.service.sales.AccountInvoiceApplicationService;
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--寮�绁ㄧ敵璇� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 01:38:32
+ */
+@RestController
+@RequestMapping("/accountInvoiceApplication")
+@Tag(name = "璐㈠姟绠$悊--寮�绁ㄧ敵璇�")
+@RequiredArgsConstructor
+public class AccountInvoiceApplicationController {
+
+    private final AccountInvoiceApplicationService accountInvoiceApplicationService;
+
+    @GetMapping("/listPageAccountInvoiceApplication")
+    @Log(title = "寮�绁ㄧ敵璇峰彴璐�", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--寮�绁ㄧ敵璇峰彴璐�")
+    public R<IPage<AccountInvoiceApplicationVo>> listPageAccountInvoiceApplication(Page page, AccountInvoiceApplicationDto accountInvoiceApplicationDto) {
+        IPage<AccountInvoiceApplicationVo> listPage = accountInvoiceApplicationService.listPageAccountInvoiceApplication(page,accountInvoiceApplicationDto);
+        return R.ok(listPage);
+    }
+
+    @GetMapping("/getOutboundBatchesByCustomer")
+    @Log(title = "鏍规嵁瀹㈡埛鏌ヨ鍑哄簱鍗曞彿(寮�绁ㄧ敵璇�)", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--鏍规嵁瀹㈡埛鏌ヨ鍑哄簱鍗曞彿(寮�绁ㄧ敵璇�)")
+    public R getOutboundBatchesByCustomer(Integer customerId) {
+        return R.ok(accountInvoiceApplicationService.getOutboundBatchesByCustomer(customerId));
+    }
+
+    @PostMapping("/addAccountInvoiceApplication")
+    @Log(title = "鏂板寮�绁ㄧ敵璇�", businessType = BusinessType.INSERT)
+    @Operation(summary = "璐㈠姟绠$悊--鏂板寮�绁ㄧ敵璇�")
+    public R addAccountInvoiceApplication(@RequestBody AccountInvoiceApplication accountInvoiceApplication) {
+        return R.ok(accountInvoiceApplicationService.addAccountInvoiceApplication(accountInvoiceApplication));
+    }
+
+    @PutMapping("/updateAccountInvoiceApplication")
+    @Log(title = "淇敼寮�绁ㄧ敵璇�", businessType = BusinessType.UPDATE)
+    @Operation(summary = "璐㈠姟绠$悊--淇敼寮�绁ㄧ敵璇�")
+    public R updateAccountInvoiceApplication(@RequestBody AccountInvoiceApplication accountInvoiceApplication) {
+        return R.ok(accountInvoiceApplicationService.updateById(accountInvoiceApplication));
+    }
+
+    @PutMapping("/auditAccountInvoiceApplication")
+    @Log(title = "瀹℃牳寮�绁ㄧ敵璇�", businessType = BusinessType.UPDATE)
+    @Operation(summary = "璐㈠姟绠$悊--瀹℃牳寮�绁ㄧ敵璇�")
+    public R auditAccountInvoiceApplication(@RequestBody AccountInvoiceApplication accountInvoiceApplication) {
+        return R.ok(accountInvoiceApplicationService.updateById(accountInvoiceApplication));
+    }
+
+    @DeleteMapping("/deleteAccountInvoiceApplication")
+    @Log(title = "鍒犻櫎寮�绁ㄧ敵璇�", businessType = BusinessType.DELETE)
+    @Operation(summary = "璐㈠姟绠$悊--鍒犻櫎寮�绁ㄧ敵璇�")
+    public R deleteAccountInvoiceApplication(@RequestParam("ids") Long[] ids) {
+        return R.ok(accountInvoiceApplicationService.deleteAccountInvoiceApplication(Arrays.asList(ids)));
+    }
+
+    @PostMapping("/exportAccountInvoiceApplication")
+    @Operation(summary = "瀵煎嚭寮�绁ㄧ敵璇锋枃浠�")
+    @Log(title = "瀵煎嚭寮�绁ㄧ敵璇锋枃浠�", businessType = BusinessType.EXPORT)
+    public void exportAccountInvoiceApplication(HttpServletResponse response, AccountInvoiceApplicationDto accountInvoiceApplicationDto) {
+        accountInvoiceApplicationService.exportAccountInvoiceApplication(response,accountInvoiceApplicationDto);
+    }
+
+}
diff --git a/src/main/java/com/ruoyi/account/controller/sales/AccountSalesCollectionController.java b/src/main/java/com/ruoyi/account/controller/sales/AccountSalesCollectionController.java
new file mode 100644
index 0000000..6ab1f2a
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/controller/sales/AccountSalesCollectionController.java
@@ -0,0 +1,79 @@
+package com.ruoyi.account.controller.sales;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.sales.AccountSalesCollectionDto;
+import com.ruoyi.account.bean.vo.sales.AccountSalesCollectionVo;
+import com.ruoyi.account.pojo.sales.AccountSalesCollection;
+import com.ruoyi.account.service.sales.AccountSalesCollectionService;
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--鏀舵鍗� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 03:49:56
+ */
+@RestController
+@RequestMapping("/accountSalesCollection")
+@Tag(name = "璐㈠姟绠$悊--鏀舵鍗�")
+@RequiredArgsConstructor
+public class AccountSalesCollectionController {
+
+    private final AccountSalesCollectionService accountSalesCollectionService;
+
+    @GetMapping("/listPageAccountSalesCollection")
+    @Log(title = "鏀舵鍗曞彴璐�", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--鏀舵鍗曞彴璐�")
+    public R<IPage<AccountSalesCollectionVo>> listPageAccountSalesCollection(Page page, AccountSalesCollectionDto accountSalesCollectionDto) {
+        IPage<AccountSalesCollectionVo> listPage = accountSalesCollectionService.listPageAccountSalesCollection(page,accountSalesCollectionDto);
+        return R.ok(listPage);
+    }
+
+    @GetMapping("/getOutboundBatchesByCustomer")
+    @Log(title = "鏍规嵁瀹㈡埛鏌ヨ鍑哄簱鍗曞彿(鏀舵鍗�)", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--鏍规嵁瀹㈡埛鏌ヨ鍑哄簱鍗曞彿(鏀舵鍗�)")
+    public R getOutboundBatchesByCustomer(Integer customerId) {
+        return R.ok(accountSalesCollectionService.getOutboundBatchesByCustomer(customerId));
+    }
+
+    @PostMapping("/addAccountSalesCollection")
+    @Log(title = "鏂板鏀舵鍗�", businessType = BusinessType.INSERT)
+    @Operation(summary = "璐㈠姟绠$悊--鏂板鏀舵鍗�")
+    public R addAccountSalesCollection(@RequestBody AccountSalesCollection accountSalesCollection) {
+        return R.ok(accountSalesCollectionService.addAccountSalesCollection(accountSalesCollection));
+    }
+
+    @PutMapping("/updateAccountSalesCollection")
+    @Log(title = "缂栬緫鏀舵鍗�", businessType = BusinessType.UPDATE)
+    @Operation(summary = "璐㈠姟绠$悊--缂栬緫鏀舵鍗�")
+    public R updateAccountSalesCollection(@RequestBody AccountSalesCollection accountSalesCollection) {
+        return R.ok(accountSalesCollectionService.updateById(accountSalesCollection));
+    }
+
+    @DeleteMapping("/deleteAccountSalesCollection")
+    @Log(title = "鍒犻櫎鏀舵鍗�", businessType = BusinessType.DELETE)
+    @Operation(summary = "璐㈠姟绠$悊--鍒犻櫎鏀舵鍗�")
+    public R deleteAccountSalesCollection(@RequestParam("ids") Long[] ids) {
+        return R.ok(accountSalesCollectionService.deleteAccountSalesCollection(Arrays.asList(ids)));
+    }
+
+    @PostMapping("/exportAccountSalesCollection")
+    @Operation(summary = "瀵煎嚭鏀舵鍗曟枃浠�")
+    @Log(title = "瀵煎嚭鏀舵鍗曟枃浠�", businessType = BusinessType.EXPORT)
+    public void exportAccountSalesCollection(HttpServletResponse response, AccountSalesCollectionDto accountSalesCollectionDto) {
+        accountSalesCollectionService.exportAccountSalesCollection(response,accountSalesCollectionDto);
+    }
+
+}
diff --git a/src/main/java/com/ruoyi/account/controller/AccountSalesController.java b/src/main/java/com/ruoyi/account/controller/sales/AccountSalesController.java
similarity index 88%
rename from src/main/java/com/ruoyi/account/controller/AccountSalesController.java
rename to src/main/java/com/ruoyi/account/controller/sales/AccountSalesController.java
index bca90db..25d8096 100644
--- a/src/main/java/com/ruoyi/account/controller/AccountSalesController.java
+++ b/src/main/java/com/ruoyi/account/controller/sales/AccountSalesController.java
@@ -1,12 +1,12 @@
-package com.ruoyi.account.controller;
+package com.ruoyi.account.controller.sales;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.bean.dto.SalesOutboundDto;
-import com.ruoyi.account.bean.dto.SalesReturnDto;
-import com.ruoyi.account.bean.vo.SalesOutboundVo;
-import com.ruoyi.account.bean.vo.SalesReturnVo;
-import com.ruoyi.account.service.AccountSalesService;
+import com.ruoyi.account.bean.dto.sales.SalesOutboundDto;
+import com.ruoyi.account.bean.dto.sales.SalesReturnDto;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.bean.vo.sales.SalesReturnVo;
+import com.ruoyi.account.service.sales.AccountSalesService;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.domain.R;
diff --git a/src/main/java/com/ruoyi/account/controller/sales/AccountSalesInvoiceController.java b/src/main/java/com/ruoyi/account/controller/sales/AccountSalesInvoiceController.java
new file mode 100644
index 0000000..05c13b0
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/controller/sales/AccountSalesInvoiceController.java
@@ -0,0 +1,72 @@
+package com.ruoyi.account.controller.sales;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.sales.AccountSalesInvoiceDto;
+import com.ruoyi.account.bean.vo.sales.AccountSalesInvoiceVo;
+import com.ruoyi.account.pojo.sales.AccountSalesInvoice;
+import com.ruoyi.account.service.sales.AccountSalesInvoiceService;
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--閿�椤瑰彂绁� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 03:10:20
+ */
+@RestController
+@RequestMapping("/accountSalesInvoice")
+@Tag(name = "璐㈠姟绠$悊--閿�椤瑰彂绁�")
+@RequiredArgsConstructor
+public class AccountSalesInvoiceController {
+
+    private final AccountSalesInvoiceService accountSalesInvoiceService;
+
+    @GetMapping("/listPageAccountSalesInvoice")
+    @Log(title = "閿�椤瑰彂绁ㄥ彴璐�", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--閿�椤瑰彂绁ㄥ彴璐�")
+    public R<IPage<AccountSalesInvoiceVo>> listPageAccountSalesInvoice(Page page, AccountSalesInvoiceDto accountSalesInvoiceDto) {
+        IPage<AccountSalesInvoiceVo> listPage = accountSalesInvoiceService.listPageAccountSalesInvoice(page,accountSalesInvoiceDto);
+        return R.ok(listPage);
+    }
+
+    @PostMapping("/addAccountSalesInvoice")
+    @Log(title = "鏂板閿�椤瑰彂绁�", businessType = BusinessType.INSERT)
+    @Operation(summary = "璐㈠姟绠$悊--鏂板閿�椤瑰彂绁�")
+    public R addAccountSalesInvoice(@RequestBody AccountSalesInvoice accountSalesInvoice) {
+        return R.ok(accountSalesInvoiceService.save(accountSalesInvoice));
+    }
+
+    @PutMapping("/cancelAccountSalesInvoice")
+    @Log(title = "浣滃簾閿�椤瑰彂绁�", businessType = BusinessType.INSERT)
+    @Operation(summary = "璐㈠姟绠$悊--浣滃簾閿�椤瑰彂绁�")
+    public R cancelAccountSalesInvoice(@RequestBody AccountSalesInvoice accountSalesInvoice) {
+        return R.ok(accountSalesInvoiceService.updateById(accountSalesInvoice));
+    }
+
+    @DeleteMapping("/deleteAccountSalesInvoice")
+    @Log(title = "鍒犻櫎閿�椤瑰彂绁�", businessType = BusinessType.DELETE)
+    @Operation(summary = "璐㈠姟绠$悊--鍒犻櫎閿�椤瑰彂绁�")
+    public R deleteAccountSalesInvoice(@RequestParam("ids") Long[] ids) {
+        return R.ok(accountSalesInvoiceService.deleteAccountSalesInvoice(Arrays.asList(ids)));
+    }
+
+    @PostMapping("/exportAccountSalesInvoice")
+    @Operation(summary = "瀵煎嚭閿�椤瑰彂绁ㄦ枃浠�")
+    @Log(title = "瀵煎嚭閿�椤瑰彂绁ㄦ枃浠�", businessType = BusinessType.EXPORT)
+    public void exportAccountSalesInvoice(HttpServletResponse response, AccountSalesInvoiceDto accountSalesInvoiceDto) {
+        accountSalesInvoiceService.exportAccountSalesInvoice(response,accountSalesInvoiceDto);
+    }
+
+}
diff --git a/src/main/java/com/ruoyi/account/mapper/AccountExpenseMapper.java b/src/main/java/com/ruoyi/account/mapper/AccountExpenseMapper.java
deleted file mode 100644
index 4876e7b..0000000
--- a/src/main/java/com/ruoyi/account/mapper/AccountExpenseMapper.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.ruoyi.account.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.account.bean.dto.AccountDto;
-import com.ruoyi.account.bean.dto.AccountDto2;
-import com.ruoyi.account.pojo.AccountExpense;
-import com.ruoyi.account.pojo.AccountIncome;
-import com.ruoyi.dto.DateQueryDto;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-import com.ruoyi.home.dto.IncomeExpenseAnalysisDto;
-
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
-
-@Mapper
-public interface AccountExpenseMapper extends BaseMapper<AccountExpense> {
-    IPage<AccountExpense> accountExpenseListPage(Page page, @Param("accountExpense") AccountExpense accountExpense);
-
-    List<AccountExpense> accountExpenseExport(@Param("accountExpense") AccountExpense accountExpense);
-
-
-    List<AccountDto2> report(@Param("dateQueryDto") DateQueryDto dateQueryDto);
-    BigDecimal report1(@Param("dateQueryDto") DateQueryDto dateQueryDto, @Param("dictValue") String dictValue);
-
-    List<IncomeExpenseAnalysisDto> selectAccountExpenseStats(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("dateFormat") String dateFormat);
-
-    List<com.ruoyi.dto.MapDto> selectExpenseComposition(@Param("startDate") String startDate, @Param("endDate") String endDate);
-}
diff --git a/src/main/java/com/ruoyi/account/mapper/AccountFileMapper.java b/src/main/java/com/ruoyi/account/mapper/AccountFileMapper.java
deleted file mode 100644
index d5b55be..0000000
--- a/src/main/java/com/ruoyi/account/mapper/AccountFileMapper.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.ruoyi.account.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.account.pojo.AccountFile;
-import com.ruoyi.quality.pojo.QualityInspectFile;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-
-@Mapper
-public interface AccountFileMapper extends BaseMapper<AccountFile> {
-
-    IPage<AccountFile> accountFileListPage(Page page, @Param("accountFile") AccountFile accountFile);
-}
diff --git a/src/main/java/com/ruoyi/account/mapper/AccountIncomeMapper.java b/src/main/java/com/ruoyi/account/mapper/AccountIncomeMapper.java
deleted file mode 100644
index 9bb3f3a..0000000
--- a/src/main/java/com/ruoyi/account/mapper/AccountIncomeMapper.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.ruoyi.account.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.account.bean.dto.AccountDto2;
-import com.ruoyi.account.pojo.AccountFile;
-import com.ruoyi.account.pojo.AccountIncome;
-import com.ruoyi.dto.DateQueryDto;
-import com.ruoyi.home.dto.IncomeExpenseAnalysisDto;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
-
-@Mapper
-public interface AccountIncomeMapper extends BaseMapper<AccountIncome> {
-
-    IPage<AccountIncome> accountIncomeListPage(Page page, @Param("accountIncome") AccountIncome accountIncome);
-
-    List<AccountIncome> accountIncomeExport(@Param("accountIncome") AccountIncome accountIncome);
-
-    List<AccountDto2> report(@Param("dateQueryDto") DateQueryDto dateQueryDto);
-    BigDecimal report1(@Param("dateQueryDto") DateQueryDto dateQueryDto, @Param("dictValue") String dictValue);
-
-    List<IncomeExpenseAnalysisDto> selectIncomeStats(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("dateFormat") String dateFormat);
-
-}
diff --git a/src/main/java/com/ruoyi/account/mapper/AccountStatementDetailsMapper.java b/src/main/java/com/ruoyi/account/mapper/AccountStatementDetailsMapper.java
new file mode 100644
index 0000000..7b6e72f
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/mapper/AccountStatementDetailsMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.account.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.account.pojo.AccountStatementDetails;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--瀵硅处鍗曟槑缁� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 10:12:42
+ */
+@Mapper
+public interface AccountStatementDetailsMapper extends BaseMapper<AccountStatementDetails> {
+
+}
diff --git a/src/main/java/com/ruoyi/account/mapper/AccountStatementMapper.java b/src/main/java/com/ruoyi/account/mapper/AccountStatementMapper.java
new file mode 100644
index 0000000..307cf1a
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/mapper/AccountStatementMapper.java
@@ -0,0 +1,25 @@
+package com.ruoyi.account.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.account.bean.dto.StatementAccountDto;
+import com.ruoyi.account.bean.vo.StatementAccountVo;
+import com.ruoyi.account.pojo.AccountStatement;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * <p>
+ *  Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 09:42:47
+ */
+@Mapper
+public interface AccountStatementMapper extends BaseMapper<AccountStatement> {
+
+
+    IPage<StatementAccountVo> listPageAccountStatement(Page page, @Param("req") StatementAccountDto statementAccountDto);
+}
diff --git a/src/main/java/com/ruoyi/account/mapper/BorrowInfoMapper.java b/src/main/java/com/ruoyi/account/mapper/BorrowInfoMapper.java
deleted file mode 100644
index bcac543..0000000
--- a/src/main/java/com/ruoyi/account/mapper/BorrowInfoMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.account.mapper;
-
-import com.ruoyi.account.pojo.BorrowInfo;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * <p>
- * 鍊熸淇℃伅琛� Mapper 鎺ュ彛
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-01-15 02:57:29
- */
-@Mapper
-public interface BorrowInfoMapper extends BaseMapper<BorrowInfo> {
-
-}
diff --git a/src/main/java/com/ruoyi/account/mapper/AccountSubjectMapper.java b/src/main/java/com/ruoyi/account/mapper/financial/AccountSubjectMapper.java
similarity index 82%
rename from src/main/java/com/ruoyi/account/mapper/AccountSubjectMapper.java
rename to src/main/java/com/ruoyi/account/mapper/financial/AccountSubjectMapper.java
index 46a4968..a5dd4fc 100644
--- a/src/main/java/com/ruoyi/account/mapper/AccountSubjectMapper.java
+++ b/src/main/java/com/ruoyi/account/mapper/financial/AccountSubjectMapper.java
@@ -1,7 +1,7 @@
-package com.ruoyi.account.mapper;
+package com.ruoyi.account.mapper.financial;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.account.pojo.AccountSubject;
+import com.ruoyi.account.pojo.financial.AccountSubject;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
diff --git a/src/main/java/com/ruoyi/account/mapper/purchase/AccountPaymentApplicationMapper.java b/src/main/java/com/ruoyi/account/mapper/purchase/AccountPaymentApplicationMapper.java
new file mode 100644
index 0000000..f6d90f9
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/mapper/purchase/AccountPaymentApplicationMapper.java
@@ -0,0 +1,32 @@
+package com.ruoyi.account.mapper.purchase;
+
+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.account.bean.dto.purchase.AccountPaymentApplicationDto;
+import com.ruoyi.account.bean.vo.purchase.AccountPaymentApplicationVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.pojo.purchase.AccountPaymentApplication;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--浠樻鐢宠 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 03:44:22
+ */
+@Mapper
+public interface AccountPaymentApplicationMapper extends BaseMapper<AccountPaymentApplication> {
+
+    IPage<AccountPaymentApplicationVo> listPageAccountPaymentApplication(Page page, @Param("req") AccountPaymentApplicationDto accountPaymentApplicationDto);
+
+    List<PurchaseInboundVo> getInboundBatchesBySupplier(@Param("supplierId") Integer supplierId);
+
+    //鍒ゆ柇璇ュ嚭搴撹褰曟槸鍚︽湁寮�绁ㄧ敵璇�
+    boolean existsByStockInRecordId(@Param("stockInRecordIds") List<Long> stockInRecordIds);
+}
diff --git a/src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchaseInvoiceMapper.java b/src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchaseInvoiceMapper.java
new file mode 100644
index 0000000..bd8e25a
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchaseInvoiceMapper.java
@@ -0,0 +1,29 @@
+package com.ruoyi.account.mapper.purchase;
+
+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.account.bean.dto.purchase.AccountPurchaseInvoiceDto;
+import com.ruoyi.account.bean.vo.purchase.AccountPurchaseInvoiceVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.pojo.purchase.AccountPurchaseInvoice;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--杩涢」鍙戠エ Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 03:06:17
+ */
+@Mapper
+public interface AccountPurchaseInvoiceMapper extends BaseMapper<AccountPurchaseInvoice> {
+
+    IPage<AccountPurchaseInvoiceVo> listPageAccountPurchaseInvoice(Page page, @Param("req") AccountPurchaseInvoiceDto accountPurchaseInvoiceDto);
+
+    List<PurchaseInboundVo> getInboundBatchesBySupplier(@Param("supplierId") Integer supplierId);
+}
diff --git a/src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchasePaymentMapper.java b/src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchasePaymentMapper.java
new file mode 100644
index 0000000..f687c74
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchasePaymentMapper.java
@@ -0,0 +1,29 @@
+package com.ruoyi.account.mapper.purchase;
+
+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.account.bean.dto.purchase.AccountPurchasePaymentDto;
+import com.ruoyi.account.bean.vo.purchase.AccountPurchasePaymentVo;
+import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
+import com.ruoyi.home.dto.IncomeExpenseAnalysisDto;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--浠樻鍗� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 04:14:51
+ */
+@Mapper
+public interface AccountPurchasePaymentMapper extends BaseMapper<AccountPurchasePayment> {
+
+    IPage<AccountPurchasePaymentVo> listPageAccountPurchasePayment(Page page, @Param("req") AccountPurchasePaymentDto accountPurchasePaymentDto);
+
+    List<IncomeExpenseAnalysisDto> selectPayment(@Param("startStr") String startStr, @Param("endStr") String endStr, @Param("dateFormat") String dateFormat);
+}
diff --git a/src/main/java/com/ruoyi/account/mapper/sales/AccountInvoiceApplicationMapper.java b/src/main/java/com/ruoyi/account/mapper/sales/AccountInvoiceApplicationMapper.java
new file mode 100644
index 0000000..463f178
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/mapper/sales/AccountInvoiceApplicationMapper.java
@@ -0,0 +1,32 @@
+package com.ruoyi.account.mapper.sales;
+
+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.account.bean.dto.sales.AccountInvoiceApplicationDto;
+import com.ruoyi.account.bean.vo.sales.AccountInvoiceApplicationVo;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.pojo.sales.AccountInvoiceApplication;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--寮�绁ㄧ敵璇� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 01:38:32
+ */
+@Mapper
+public interface AccountInvoiceApplicationMapper extends BaseMapper<AccountInvoiceApplication> {
+
+    IPage<AccountInvoiceApplicationVo> listPageAccountInvoiceApplication(Page page, @Param("req") AccountInvoiceApplicationDto accountInvoiceApplicationDto);
+
+    List<SalesOutboundVo> getOutboundBatchesByCustomer(@Param("customerId") Integer customerId);
+
+    //鍒ゆ柇璇ュ嚭搴撹褰曟槸鍚︽湁寮�绁ㄧ敵璇�
+    boolean existsByStockOutRecordId(@Param("stockOutRecordIds") List<Long> stockOutRecordIds);
+}
diff --git a/src/main/java/com/ruoyi/account/mapper/sales/AccountSalesCollectionMapper.java b/src/main/java/com/ruoyi/account/mapper/sales/AccountSalesCollectionMapper.java
new file mode 100644
index 0000000..2f1cf6e
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/mapper/sales/AccountSalesCollectionMapper.java
@@ -0,0 +1,35 @@
+package com.ruoyi.account.mapper.sales;
+
+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.account.bean.dto.sales.AccountSalesCollectionDto;
+import com.ruoyi.account.bean.vo.sales.AccountSalesCollectionVo;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.pojo.sales.AccountSalesCollection;
+import com.ruoyi.home.dto.IncomeExpenseAnalysisDto;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--鏀舵鍗� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 03:49:56
+ */
+@Mapper
+public interface AccountSalesCollectionMapper extends BaseMapper<AccountSalesCollection> {
+
+    IPage<AccountSalesCollectionVo> listPageAccountSalesCollection(Page page, @Param("req") AccountSalesCollectionDto accountSalesCollectionDto);
+
+    //鍒ゆ柇璇ュ嚭搴撹褰曟槸鍚︽湁鏀舵鍗�
+    boolean existsByStockOutRecordId(@Param("stockOutRecordIds") List<Long> stockOutRecordIds);
+
+    List<SalesOutboundVo> getOutboundBatchesByCustomer(@Param("customerId") Integer customerId);
+
+    List<IncomeExpenseAnalysisDto> selectIncomeStats(@Param("startStr") String startStr, @Param("endStr") String endStr, @Param("dateFormat") String dateFormat);
+}
diff --git a/src/main/java/com/ruoyi/account/mapper/sales/AccountSalesInvoiceMapper.java b/src/main/java/com/ruoyi/account/mapper/sales/AccountSalesInvoiceMapper.java
new file mode 100644
index 0000000..ea88e8f
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/mapper/sales/AccountSalesInvoiceMapper.java
@@ -0,0 +1,24 @@
+package com.ruoyi.account.mapper.sales;
+
+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.account.bean.dto.sales.AccountSalesInvoiceDto;
+import com.ruoyi.account.bean.vo.sales.AccountSalesInvoiceVo;
+import com.ruoyi.account.pojo.sales.AccountSalesInvoice;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--閿�椤瑰彂绁� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 03:10:20
+ */
+@Mapper
+public interface AccountSalesInvoiceMapper extends BaseMapper<AccountSalesInvoice> {
+
+    IPage<AccountSalesInvoiceVo> listPageAccountSalesInvoice(Page page, @Param("req") AccountSalesInvoiceDto accountSalesInvoiceDto);
+}
diff --git a/src/main/java/com/ruoyi/account/pojo/AccountExpense.java b/src/main/java/com/ruoyi/account/pojo/AccountExpense.java
deleted file mode 100644
index dcb6b4b..0000000
--- a/src/main/java/com/ruoyi/account/pojo/AccountExpense.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.ruoyi.account.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.dto.DateQueryDto;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import jakarta.validation.constraints.NotBlank;
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-import java.util.Date;
-
-/**
- * 璐㈠姟绠$悊--鏀嚭绠$悊
- * account_expense
- */
-@TableName(value = "account_expense")
-@Data
-public class AccountExpense extends DateQueryDto implements Serializable {
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 搴忓彿
-     */
-    @TableId(type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 涓氬姟id
-     */
-    private Long businessId;
-
-    /**
-     * 涓氬姟绫诲瀷 1-浠樻 2-杩樻 3-钖祫鍙戞斁
-     */
-    private Integer businessType;
-
-    /**
-     * 鏀嚭鏃ユ湡
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "鏀嚭鏃ユ湡", width = 30, dateFormat = "yyyy-MM-dd")
-    private Date expenseDate;
-
-    /**
-     * 鏀嚭绫诲瀷(鍔炲叕鐢ㄥ搧锛屽憳宸ュ伐璧勶紝宸梾璐癸紝璁惧璐圭敤锛屾潵绁ㄤ粯娆撅紝鍏朵粬)
-     */
-    @Excel(name = "鏀嚭绫诲瀷",readConverterExp = "0=鍔炲叕鐢ㄥ搧,1=鍛樺伐宸ヨ祫,2=宸梾璐�,3=璁惧璐圭敤,4=鏉ョエ浠樻,5=鍏朵粬")
-    @NotBlank(message = "鏀嚭绫诲瀷涓嶈兘涓虹┖!!")
-    private String expenseType;
-
-    /**
-     * 渚涘簲鍟嗗悕绉�
-     */
-    @Excel(name = "渚涘簲鍟嗗悕绉�")
-    private String supplierName;
-
-    /**
-     * 鏀嚭閲戦
-     */
-    @Excel(name = "鏀嚭閲戦")
-    private BigDecimal expenseMoney;
-
-    /**
-     * 鏀嚭鎻忚堪
-     */
-    @Excel(name = "鏀嚭鎻忚堪")
-    private String expenseDescribed;
-
-    /**
-     * 浠樻鏂瑰紡(鐜伴噾锛屾敮绁紝閾惰杞处锛屽叾浠�)
-     */
-    @Excel(name = "浠樻鏂瑰紡",readConverterExp = "0=鐜伴噾,1=鏀エ,2=閾惰杞处,3=鍏朵粬")
-    private String expenseMethod;
-
-    /**
-     * 鍙戠エ鍙风爜
-     */
-    @Excel(name = "鍙戠エ鍙风爜")
-    private String invoiceNumber;
-
-    /**
-     * 澶囨敞
-     */
-    @Excel(name = "澶囨敞")
-    private String note;
-
-    /**
-     * 褰曞叆浜哄憳
-     */
-    @Excel(name = "褰曞叆浜哄憳")
-    private String inputUser;
-
-    /**
-     * 褰曞叆鏃堕棿
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "褰曞叆鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd")
-    private Date inputTime;
-
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    @Schema(description = "鍒涘缓鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @Schema(description = "淇敼鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    @Schema(description = "淇敼鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-
-    @Schema(description = "绉熸埛ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/account/pojo/AccountFile.java b/src/main/java/com/ruoyi/account/pojo/AccountFile.java
deleted file mode 100644
index b22ab91..0000000
--- a/src/main/java/com/ruoyi/account/pojo/AccountFile.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.ruoyi.account.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import jakarta.validation.constraints.NotBlank;
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * 璐㈠姟绠$悊--闄勪欢
- * account_file
- */
-@TableName(value = "account_file")
-@Data
-public class AccountFile implements Serializable {
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 搴忓彿
-     */
-    @TableId(type = IdType.AUTO)
-    private Long id;
-
-    @Schema(description = "鏂囦欢鍚嶇О")
-    private String name;
-
-    @Schema(description = "鏂囦欢璺緞")
-    private String url;
-
-    @Schema(description = "鏂囦欢澶у皬")
-    private int fileSize;
-
-    @Schema(description = "璐㈠姟ID")
-    @NotBlank(message = "璐㈠姟id涓嶈兘涓虹┖!")
-    private Long accountId;
-
-    /**
-     * 绫诲瀷(鏀跺叆/鏀嚭)
-     */
-    @Schema(description = "绫诲瀷(鏀跺叆/鏀嚭)")
-    private String accountType;
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    @Schema(description = "淇敼鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    @Schema(description = "鍒涘缓鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @Schema(description = "淇敼鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-
-    @Schema(description = "绉熸埛ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/account/pojo/AccountIncome.java b/src/main/java/com/ruoyi/account/pojo/AccountIncome.java
deleted file mode 100644
index d6ce79c..0000000
--- a/src/main/java/com/ruoyi/account/pojo/AccountIncome.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package com.ruoyi.account.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.dto.DateQueryDto;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import jakarta.validation.constraints.NotBlank;
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-import java.util.Date;
-import java.util.List;
-
-/**
- * 璐㈠姟绠$悊--鏀跺叆绠$悊
- * account_income
- */
-@TableName(value = "account_income")
-@Data
-public class AccountIncome extends DateQueryDto implements Serializable {
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 搴忓彿
-     */
-    @TableId(type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 涓氬姟id
-     */
-    private Long businessId;
-
-    /**
-     * 涓氬姟绫诲瀷 1-鍥炴 2-鍊熸
-     */
-    private Integer businessType;
-
-    /**
-     * 鏀跺叆鏃ユ湡
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "鏀跺叆鏃ユ湡", width = 30, dateFormat = "yyyy-MM-dd")
-    private Date incomeDate;
-
-    /**
-     * 鏀跺叆绫诲瀷(閿�鍞敹鍏ワ紝鏈嶅姟鏀跺叆锛屽叾浠栨敹鍏�)
-     */
-    @Excel(name = "鏀跺叆绫诲瀷", readConverterExp = "0=閿�鍞敹鍏�,1=鏈嶅姟鏀跺叆,2=鍏朵粬鏀跺叆,3=鍥炴鏀跺叆")
-    @NotBlank(message = "鏀跺叆绫诲瀷涓嶈兘涓虹┖!!")
-    private String incomeType;
-
-    /**
-     * 瀹㈡埛鍚嶇О
-     */
-    @Excel(name = "瀹㈡埛鍚嶇О")
-    private String customerName;
-
-    /**
-     * 鏀跺叆閲戦
-     */
-    @Excel(name = "鏀跺叆閲戦")
-    private BigDecimal incomeMoney;
-
-    /**
-     * 鏀跺叆鎻忚堪
-     */
-    @Excel(name = "鏀跺叆鎻忚堪")
-    private String incomeDescribed;
-
-    /**
-     * 鏀舵鏂瑰紡(鐜伴噾锛屾敮绁紝閾惰杞处锛屽叾浠�)
-     */
-    @Excel(name = "鏀舵鏂瑰紡", readConverterExp = "0=鐜伴噾,1=鏀エ,2=閾惰杞处,3=鍏朵粬")
-    private String incomeMethod;
-
-    /**
-     * 鏀舵鏂瑰紡鏍囩
-     */
-    @TableField(exist = false)
-    private String incomeMethodLabel;
-
-    /**
-     * payment_methods 瀛楀吀缂栫爜闆嗗悎锛坆usiness_type 涓虹┖鏃讹級
-     */
-    @TableField(exist = false)
-    private List<String> paymentMethodList;
-
-    /**
-     * receipt_payment_type 瀛楀吀缂栫爜闆嗗悎锛坆usiness_type=1鏃讹級
-     */
-    @TableField(exist = false)
-    private List<String> receiptPaymentMethodList;
-
-    /**
-     * 鍙戠エ鍙风爜
-     */
-    @Excel(name = "鍙戠エ鍙风爜")
-    private String invoiceNumber;
-
-    /**
-     * 澶囨敞
-     */
-    @Excel(name = "澶囨敞")
-    private String note;
-
-    /**
-     * 褰曞叆浜哄憳
-     */
-    @Excel(name = "褰曞叆浜哄憳")
-    private String inputUser;
-
-    /**
-     * 褰曞叆鏃堕棿
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "褰曞叆鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd")
-    private Date inputTime;
-
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    @Schema(description = "鍒涘缓鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @Schema(description = "淇敼鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    @Schema(description = "淇敼鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-
-    @Schema(description = "绉熸埛ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/account/pojo/AccountStatement.java b/src/main/java/com/ruoyi/account/pojo/AccountStatement.java
new file mode 100644
index 0000000..20d2495
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/pojo/AccountStatement.java
@@ -0,0 +1,127 @@
+package com.ruoyi.account.pojo;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+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.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 09:42:47
+ */
+@Getter
+@Setter
+@ToString
+@TableName("account_statement")
+@ApiModel(value = "AccountStatement瀵硅薄", description = "璐㈠姟绠$悊--瀵硅处鍗�")
+public class AccountStatement implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 瀹㈡埛id(搴旀敹鏄鎴穋ustomer,搴斾粯鏄緵搴斿晢supplier)
+     */
+    @ApiModelProperty("瀹㈡埛id")
+    private Integer customerId;
+
+    /**
+     * 瀵硅处鏈堜唤(yyyy-MM)
+     */
+    @ApiModelProperty("瀵硅处鏈堜唤(yyyy-MM)")
+    @Excel(name = "瀵硅处鏈堜唤")
+    private String statementMonth;
+
+    /**
+     * 涓氬姟绫诲瀷(1搴旀敹瀵硅处;2搴斾粯瀵硅处)
+     */
+    @ApiModelProperty("涓氬姟绫诲瀷(1搴旀敹瀵硅处;2搴斾粯瀵硅处)")
+    @Excel(name = "涓氬姟绫诲瀷",readConverterExp = "1=搴旀敹瀵硅处,2=搴斾粯瀵硅处")
+    private Integer accountType;
+
+    /**
+     * 瀵硅处鍗曞彿
+     */
+    @ApiModelProperty("瀵硅处鍗曞彿")
+    @Excel(name = "瀵硅处鍗曞彿")
+    private String statementNumber;
+
+    /**
+     * 鏈熷垵浣欓
+     */
+    @ApiModelProperty("鏈熷垵浣欓")
+    @Excel(name = "鏈熷垵浣欓")
+    private BigDecimal openingBalance;
+
+    /**
+     * 鏈湡搴旀敹/搴斾粯
+     */
+    @ApiModelProperty("鏈湡搴旀敹/搴斾粯")
+    @Excel(name = "鏈湡搴旀敹/搴斾粯")
+    private BigDecimal currentPlan;
+
+    /**
+     * 鏈湡鏀舵/浠樻
+     */
+    @ApiModelProperty("鏈湡鏀舵/浠樻")
+    @Excel(name = "鏈湡鏀舵/浠樻")
+    private BigDecimal currentActually;
+
+    /**
+     * 鏈熸湯浣欓
+     */
+    @ApiModelProperty("鏈熸湯浣欓")
+    @Excel(name = "鏈熸湯浣欓")
+    private BigDecimal closingBalance;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime createTime;
+
+    /**
+     * 淇敼浜�
+     */
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    /**
+     * 淇敼鏃堕棿
+     */
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime updateTime;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    @ApiModelProperty("閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+}
diff --git a/src/main/java/com/ruoyi/account/pojo/AccountStatementDetails.java b/src/main/java/com/ruoyi/account/pojo/AccountStatementDetails.java
new file mode 100644
index 0000000..016a099
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/pojo/AccountStatementDetails.java
@@ -0,0 +1,115 @@
+package com.ruoyi.account.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.annotations.ApiModelProperty;
+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.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--瀵硅处鍗曟槑缁�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 10:12:42
+ */
+@Getter
+@Setter
+@ToString
+@TableName("account_statement_details")
+@ApiModel(value = "AccountStatementDetails瀵硅薄", description = "璐㈠姟绠$悊--瀵硅处鍗曟槑缁�")
+public class AccountStatementDetails implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 鍏宠仈瀵硅处鍗昳d
+     */
+    @ApiModelProperty("鍏宠仈瀵硅处鍗昳d")
+    private Integer accountStatementId;
+
+    /**
+     * 鏁版嵁鏃ユ湡
+     */
+    @ApiModelProperty("鏁版嵁鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate occurrenceDate;
+
+    /**
+     * 鍗曟嵁缂栧彿
+     */
+    @ApiModelProperty("鍗曟嵁缂栧彿")
+    private String receiptNumber;
+
+    /**
+     * 鏁版嵁绫诲瀷(1鍑哄簱;2鍏ュ簱;3鏀舵;4浠樻;5閫�璐�)
+     */
+    @ApiModelProperty("鏁版嵁绫诲瀷(1鍑哄簱;2鍏ュ簱;3鏀舵;4浠樻;5閫�璐�)")
+    private Integer type;
+
+    /**
+     * 閲戦
+     */
+    @ApiModelProperty("閲戦")
+    private BigDecimal amount;
+
+    /**
+     * 澶囨敞
+     */
+    @ApiModelProperty("澶囨敞")
+    private String remark;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime createTime;
+
+    /**
+     * 淇敼浜�
+     */
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    /**
+     * 淇敼鏃堕棿
+     */
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime updateTime;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    @ApiModelProperty("閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+}
diff --git a/src/main/java/com/ruoyi/account/pojo/BorrowInfo.java b/src/main/java/com/ruoyi/account/pojo/BorrowInfo.java
deleted file mode 100644
index 8e4d809..0000000
--- a/src/main/java/com/ruoyi/account/pojo/BorrowInfo.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.ruoyi.account.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 java.io.Serializable;
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.dto.DateQueryDto;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-import org.springframework.format.annotation.DateTimeFormat;
-
-/**
- * <p>
- * 鍊熸淇℃伅琛�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-01-15 02:57:29
- */
-@Getter
-@Setter
-@TableName("borrow_info")
-@Schema(name = "BorrowInfo瀵硅薄", description = "鍊熸淇℃伅琛�")
-public class BorrowInfo extends DateQueryDto implements Serializable{
-
-    private static final long serialVersionUID = 1L;
-
-    @Schema(description = "鍊熸璁板綍涓婚敭ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    @Schema(description = "鍊熸浜哄鍚�")
-    @Excel(name = "鍊熸浜哄鍚�")
-    private String borrowerName;
-
-    @Schema(description = "鍊熸閲戦锛堝厓锛�")
-    @Excel(name = "鍊熸閲戦锛堝厓锛�")
-    private BigDecimal borrowAmount;
-
-    @Schema(description = "鍊熸鍒╃巼锛堝锛�5.85 浠h〃5.85%锛�")
-    @Excel(name = "鍊熸鍒╃巼")
-    private BigDecimal interestRate;
-
-    @Schema(description = "鍊熸鏃ユ湡")
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "鍊熸鏃ユ湡", width = 30, dateFormat = "yyyy-MM-dd")
-    private LocalDate borrowDate;
-
-    @Schema(description = "瀹為檯杩樻鏃ユ湡锛堣繕娆惧悗濉厖锛�")
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "瀹為檯杩樻鏃ユ湡", width = 30, dateFormat = "yyyy-MM-dd")
-    private LocalDate repayDate;
-
-    @Schema(description = "鍊熸鐘舵�侊細1=寰呰繕娆撅紝2=宸茶繕娆�")
-    @Excel(name = "鍊熸鐘舵��", readConverterExp = "1=寰呰繕娆�,2=宸茶繕娆�")
-    private Integer status;
-
-    @Schema(description = "澶囨敞锛堝�熸璇存槑锛�")
-    @Excel(name = "澶囨敞")
-    private String remark;
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    @Schema(description = "鍒涘缓鑰匢D")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @Schema(description = "淇敼鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    @Schema(description = "淇敼鑰匢D")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-
-    @Schema(description = "绉熸埛id")
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/account/pojo/AccountSubject.java b/src/main/java/com/ruoyi/account/pojo/financial/AccountSubject.java
similarity index 95%
rename from src/main/java/com/ruoyi/account/pojo/AccountSubject.java
rename to src/main/java/com/ruoyi/account/pojo/financial/AccountSubject.java
index 9616324..2548a9c 100644
--- a/src/main/java/com/ruoyi/account/pojo/AccountSubject.java
+++ b/src/main/java/com/ruoyi/account/pojo/financial/AccountSubject.java
@@ -1,4 +1,4 @@
-package com.ruoyi.account.pojo;
+package com.ruoyi.account.pojo.financial;
 
 import com.baomidou.mybatisplus.annotation.FieldFill;
 import com.baomidou.mybatisplus.annotation.IdType;
@@ -85,7 +85,7 @@
      */
     @ApiModelProperty("鍒涘缓浜�")
     @TableField(fill = FieldFill.INSERT)
-    private String createUser;
+    private Integer createUser;
 
     /**
      * 鍒涘缓鏃堕棿
@@ -99,7 +99,7 @@
      */
     @ApiModelProperty("淇敼浜�")
     @TableField(fill = FieldFill.INSERT_UPDATE)
-    private String updateUser;
+    private Integer updateUser;
 
     /**
      * 淇敼鏃堕棿
diff --git a/src/main/java/com/ruoyi/account/pojo/purchase/AccountPaymentApplication.java b/src/main/java/com/ruoyi/account/pojo/purchase/AccountPaymentApplication.java
new file mode 100644
index 0000000..9a01df7
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/pojo/purchase/AccountPaymentApplication.java
@@ -0,0 +1,141 @@
+package com.ruoyi.account.pojo.purchase;
+
+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 com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+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.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--浠樻鐢宠
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 03:44:22
+ */
+@Getter
+@Setter
+@ToString
+@TableName("account_payment_application")
+@ApiModel(value = "AccountPaymentApplication瀵硅薄", description = "璐㈠姟绠$悊--浠樻鐢宠")
+public class AccountPaymentApplication implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime createTime;
+
+    /**
+     * 淇敼浜�
+     */
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    /**
+     * 淇敼鏃堕棿
+     */
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime updateTime;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    @ApiModelProperty("閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+
+    /**
+     * 渚涘簲鍟唅d
+     */
+    @ApiModelProperty("渚涘簲鍟唅d")
+    private Integer supplierId;
+
+    /**
+     * 鍏宠仈鍏ュ簱鍗昳d(澶氶��)
+     */
+    @ApiModelProperty("鍏宠仈鍏ュ簱鍗昳d(澶氶��)")
+    private String stockInRecordIds;
+
+    /**
+     * 浠樻鐢宠鍗曞彿
+     */
+    @ApiModelProperty("浠樻鐢宠鍗曞彿")
+    @Excel(name = "浠樻鐢宠鍗曞彿")
+    private String invoiceApplicationNo;
+
+    /**
+     * 浠樻鏂瑰紡
+     */
+    @ApiModelProperty("浠樻鏂瑰紡")
+    @Excel(name = "浠樻鏂瑰紡")
+    private String paymentMethod;
+
+    /**
+     * 浠樻浜嬬敱
+     */
+    @ApiModelProperty("浠樻浜嬬敱")
+    @Excel(name = "浠樻浜嬬敱")
+    private String paymentContent;
+
+    /**
+     * 鐢宠鏃ユ湡
+     */
+    @ApiModelProperty("鐢宠鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "鐢宠鏃ユ湡")
+    private LocalDate applyDate;
+
+    /**
+     * 澶囨敞
+     */
+    @ApiModelProperty("澶囨敞")
+    @Excel(name = "澶囨敞")
+    private String remark;
+
+    /**
+     * 瀹℃牳鐘舵��:0寰呭鏍�1瀹℃牳閫氳繃2瀹℃牳涓嶉�氳繃
+     */
+    @ApiModelProperty("瀹℃牳鐘舵��:0寰呭鏍�1瀹℃牳閫氳繃2瀹℃牳涓嶉�氳繃")
+    @Excel(name = "瀹℃牳鐘舵��",readConverterExp = "0=寰呭鏍�,1=瀹℃牳閫氳繃,2=瀹℃牳涓嶉�氳繃")
+    private Integer status;
+
+    /**
+     * 浠樻閲戦
+     */
+    @ApiModelProperty("浠樻閲戦")
+    @Excel(name = "浠樻閲戦")
+    private BigDecimal paymentAmount;
+}
diff --git a/src/main/java/com/ruoyi/account/pojo/purchase/AccountPurchaseInvoice.java b/src/main/java/com/ruoyi/account/pojo/purchase/AccountPurchaseInvoice.java
new file mode 100644
index 0000000..c71ecd0
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/pojo/purchase/AccountPurchaseInvoice.java
@@ -0,0 +1,168 @@
+package com.ruoyi.account.pojo.purchase;
+
+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 com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+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.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--杩涢」鍙戠エ
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 03:06:17
+ */
+@Getter
+@Setter
+@ToString
+@TableName("account_purchase_invoice")
+@ApiModel(value = "AccountPurchaseInvoice瀵硅薄", description = "璐㈠姟绠$悊--杩涢」鍙戠エ")
+public class AccountPurchaseInvoice implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime createTime;
+
+    /**
+     * 淇敼浜�
+     */
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    /**
+     * 淇敼鏃堕棿
+     */
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime updateTime;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    @ApiModelProperty("閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+
+    /**
+     * 鍙戠エ鍙风爜
+     */
+    @ApiModelProperty("鍙戠エ鍙风爜")
+    @Excel(name = "鍙戠エ鍙风爜")
+    private String invoiceNumber;
+
+    /**
+     * 绋庣巼
+     */
+    @ApiModelProperty("绋庣巼")
+    @Excel(name = "绋庣巼")
+    private Integer taxRate;
+
+    /**
+     * 鍙戠エ绫诲瀷
+     */
+    @ApiModelProperty("鍙戠エ绫诲瀷")
+    @Excel(name = "鍙戠エ绫诲瀷")
+    private String invoiceType;
+
+    /**
+     * 寮�绁ㄦ棩鏈�
+     */
+    @ApiModelProperty("寮�绁ㄦ棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "寮�绁ㄦ棩鏈�")
+    private LocalDate issueDate;
+
+    /**
+     * 閲戦(涓嶅惈绋�)
+     */
+    @ApiModelProperty("閲戦(涓嶅惈绋�)")
+    @Excel(name = "閲戦(涓嶅惈绋�)")
+    private BigDecimal taxExclusivelPrice;
+
+    /**
+     * 绋庨
+     */
+    @ApiModelProperty("绋庨")
+    @Excel(name = "绋庨")
+    private BigDecimal taxPrice;
+
+    /**
+     * 浠风◣鍚堣
+     */
+    @ApiModelProperty("浠风◣鍚堣")
+    @Excel(name = "浠风◣鍚堣")
+    private BigDecimal taxInclusivePrice;
+
+    /**
+     * 澶囨敞
+     */
+    @ApiModelProperty("澶囨敞")
+    @Excel(name = "澶囨敞")
+    private String remark;
+
+    /**
+     * 鍙戠エ鍐呭
+     */
+    @ApiModelProperty("鍙戠エ鍐呭")
+    @Excel(name = "鍙戠エ鍐呭")
+    private String invoiceContent;
+
+    /**
+     * 渚涘簲鍟唅d
+     */
+    @ApiModelProperty("渚涘簲鍟唅d")
+    private Integer supplierId;
+
+    /**
+     * 鍏宠仈涓婁紶鐨勫彂绁ㄩ檮浠秈d
+     */
+    @ApiModelProperty("鍏宠仈涓婁紶鐨勫彂绁ㄩ檮浠秈d")
+    private Integer storageAttachmentId;
+
+    /**
+     * 鍏宠仈鍏ュ簱鍗昳d(澶氶��)
+     */
+    @ApiModelProperty("鍏宠仈鍏ュ簱鍗昳d(澶氶��)")
+    private String stockInRecordIds;
+
+    /**
+     * 鐘舵�� 0鍚敤 1绂佺敤
+     */
+    @ApiModelProperty("鐘舵�� 0鍚敤 1绂佺敤")
+    @Excel(name = "鐘舵��", readConverterExp = "0=姝e父,1=浣滃簾")
+    private Integer status;
+}
diff --git a/src/main/java/com/ruoyi/account/pojo/purchase/AccountPurchasePayment.java b/src/main/java/com/ruoyi/account/pojo/purchase/AccountPurchasePayment.java
new file mode 100644
index 0000000..7fc2d4e
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/pojo/purchase/AccountPurchasePayment.java
@@ -0,0 +1,127 @@
+package com.ruoyi.account.pojo.purchase;
+
+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 com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+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.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--浠樻鍗�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 04:14:51
+ */
+@Getter
+@Setter
+@ToString
+@TableName("account_purchase_payment")
+@ApiModel(value = "AccountPurchasePayment瀵硅薄", description = "璐㈠姟绠$悊--浠樻鍗�")
+public class AccountPurchasePayment implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 鍏宠仈浠樻鐢宠id
+     */
+    @ApiModelProperty("鍏宠仈浠樻鐢宠id")
+    private Integer accountPaymentApplicationId;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime createTime;
+
+    /**
+     * 淇敼浜�
+     */
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    /**
+     * 淇敼鏃堕棿
+     */
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime updateTime;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    @ApiModelProperty("閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+
+    /**
+     * 渚涘簲鍟唅d
+     */
+    @ApiModelProperty("渚涘簲鍟唅d")
+    private Integer supplierId;
+
+    /**
+     * 浠樻鏃ユ湡
+     */
+    @ApiModelProperty("浠樻鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "浠樻鏃ユ湡")
+    private LocalDate paymentDate;
+
+    /**
+     * 浠樻鏂瑰紡
+     */
+    @ApiModelProperty("浠樻鏂瑰紡")
+    @Excel(name = "浠樻鏂瑰紡",dictType = "checkout_payment")
+    private String paymentMethod;
+
+    /**
+     * 浠樻閲戦
+     */
+    @ApiModelProperty("浠樻閲戦")
+    @Excel(name = "浠樻閲戦")
+    private BigDecimal paymentAmount;
+
+    /**
+     * 浠樻鍗曞彿
+     */
+    @ApiModelProperty("浠樻鍗曞彿")
+    @Excel(name = "浠樻鍗曞彿")
+    private String paymentNumber;
+
+    /**
+     * 澶囨敞
+     */
+    @ApiModelProperty("澶囨敞")
+    @Excel(name = "澶囨敞")
+    private String remark;
+}
diff --git a/src/main/java/com/ruoyi/account/pojo/sales/AccountInvoiceApplication.java b/src/main/java/com/ruoyi/account/pojo/sales/AccountInvoiceApplication.java
new file mode 100644
index 0000000..ed4b72a
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/pojo/sales/AccountInvoiceApplication.java
@@ -0,0 +1,138 @@
+package com.ruoyi.account.pojo.sales;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+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.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--寮�绁ㄧ敵璇�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 01:38:32
+ */
+@Getter
+@Setter
+@ToString
+@TableName("account_invoice_application")
+@ApiModel(value = "AccountInvoiceApplication瀵硅薄", description = "璐㈠姟绠$悊--寮�绁ㄧ敵璇�")
+public class AccountInvoiceApplication implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime createTime;
+
+    /**
+     * 淇敼浜�
+     */
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    /**
+     * 淇敼鏃堕棿
+     */
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime updateTime;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    @ApiModelProperty("閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+
+    /**
+     * 瀹㈡埛id
+     */
+    @ApiModelProperty("瀹㈡埛id")
+    private Integer customerId;
+
+    /**
+     * 鍏宠仈鍑哄簱鍗昳d(澶氶��)
+     */
+    @ApiModelProperty("鍏宠仈鍑哄簱鍗昳d(澶氶��)")
+    private String stockOutRecordIds;
+
+    /**
+     * 寮�绁ㄧ敵璇峰崟鍙�
+     */
+    @ApiModelProperty("寮�绁ㄧ敵璇峰崟鍙�")
+    @Excel(name = "寮�绁ㄧ敵璇峰崟鍙�")
+    private String invoiceApplicationNo;
+
+    /**
+     * 鍙戠エ绫诲瀷
+     */
+    @ApiModelProperty("鍙戠エ绫诲瀷")
+    @Excel(name = "鍙戠エ绫诲瀷")
+    private String invoiceType;
+
+    /**
+     * 鐢宠鏃ユ湡
+     */
+    @ApiModelProperty("鐢宠鏃ユ湡")
+    @Excel(name = "鐢宠鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate applyDate;
+
+    /**
+     * 鍙戠エ鍐呭
+     */
+    @ApiModelProperty("鍙戠エ鍐呭")
+    @Excel(name = "鍙戠エ鍐呭")
+    private String invoiceContent;
+
+    /**
+     * 澶囨敞
+     */
+    @ApiModelProperty("澶囨敞")
+    @Excel(name = "澶囨敞")
+    private String remark;
+
+    /**
+     * 瀹℃牳鐘舵��:0寰呭鏍�1瀹℃牳閫氳繃2瀹℃牳涓嶉�氳繃
+     */
+    @ApiModelProperty("瀹℃牳鐘舵��:0寰呭鏍�1瀹℃牳閫氳繃2瀹℃牳涓嶉�氳繃")
+    @Excel(name = "瀹℃牳鐘舵��",readConverterExp = "0=寰呭鏍�,1=瀹℃牳閫氳繃,2=瀹℃牳涓嶉�氳繃")
+    private Integer status;
+
+    @ApiModelProperty("寮�绁ㄩ噾棰�")
+    @Excel(name = "寮�绁ㄩ噾棰�")
+    private BigDecimal invoiceAmount;
+
+    @ApiModelProperty("绋庣巼")
+    @Excel(name = "绋庣巼")
+    private BigDecimal taxRate;
+}
diff --git a/src/main/java/com/ruoyi/account/pojo/sales/AccountSalesCollection.java b/src/main/java/com/ruoyi/account/pojo/sales/AccountSalesCollection.java
new file mode 100644
index 0000000..40ea9a8
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/pojo/sales/AccountSalesCollection.java
@@ -0,0 +1,127 @@
+package com.ruoyi.account.pojo.sales;
+
+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 com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+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.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--鏀舵鍗�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 03:49:56
+ */
+@Getter
+@Setter
+@ToString
+@TableName("account_sales_collection")
+@ApiModel(value = "AccountSalesCollection瀵硅薄", description = "璐㈠姟绠$悊--鏀舵鍗�")
+public class AccountSalesCollection implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 鍏宠仈鍑哄簱鍗昳d(澶氶��)
+     */
+    @ApiModelProperty("鍏宠仈鍑哄簱鍗昳d(澶氶��)")
+    private String stockOutRecordIds;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime createTime;
+
+    /**
+     * 淇敼浜�
+     */
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    /**
+     * 淇敼鏃堕棿
+     */
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime updateTime;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    @ApiModelProperty("閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+
+    /**
+     * 瀹㈡埛id
+     */
+    @ApiModelProperty("瀹㈡埛id")
+    private Integer customerId;
+
+    /**
+     * 鏀舵鏃ユ湡
+     */
+    @ApiModelProperty("鏀舵鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "鏀舵鏃ユ湡")
+    private LocalDate collectionDate;
+
+    /**
+     * 鏀舵閲戦
+     */
+    @ApiModelProperty("鏀舵閲戦")
+    @Excel(name = "鏀舵閲戦")
+    private BigDecimal collectionAmount;
+
+    /**
+     * 鏀舵鏂瑰紡
+     */
+    @ApiModelProperty("鏀舵鏂瑰紡")
+    @Excel(name = "鏀舵鏂瑰紡",dictType = "payment_methods")
+    private String collectionMethod;
+
+    /**
+     * 鏀舵鍗曞彿
+     */
+    @ApiModelProperty("鏀舵鍗曞彿")
+    @Excel(name = "鏀舵鍗曞彿")
+    private String collectionNumber;
+
+    /**
+     * 澶囨敞
+     */
+    @ApiModelProperty("澶囨敞")
+    @Excel(name = "澶囨敞")
+    private String remark;
+}
diff --git a/src/main/java/com/ruoyi/account/pojo/sales/AccountSalesInvoice.java b/src/main/java/com/ruoyi/account/pojo/sales/AccountSalesInvoice.java
new file mode 100644
index 0000000..7551cb3
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/pojo/sales/AccountSalesInvoice.java
@@ -0,0 +1,168 @@
+package com.ruoyi.account.pojo.sales;
+
+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 com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+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.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--閿�椤瑰彂绁�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 03:10:20
+ */
+@Getter
+@Setter
+@ToString
+@TableName("account_sales_invoice")
+@ApiModel(value = "AccountSalesInvoice瀵硅薄", description = "璐㈠姟绠$悊--閿�椤瑰彂绁�")
+public class AccountSalesInvoice implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 鍏宠仈寮�绁ㄧ敵璇穒d
+     */
+    @ApiModelProperty("鍏宠仈寮�绁ㄧ敵璇穒d")
+    private Integer accountInvoiceApplicationId;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime createTime;
+
+    /**
+     * 淇敼浜�
+     */
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    /**
+     * 淇敼鏃堕棿
+     */
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime updateTime;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    @ApiModelProperty("閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+
+    /**
+     * 鍙戠エ鍙风爜
+     */
+    @ApiModelProperty("鍙戠エ鍙风爜")
+    @Excel(name = "鍙戠エ鍙风爜")
+    private String invoiceNumber;
+
+    /**
+     * 绋庣巼
+     */
+    @ApiModelProperty("绋庣巼")
+    @Excel(name = "绋庣巼")
+    private BigDecimal taxRate;
+
+    /**
+     * 鍙戠エ绫诲瀷
+     */
+    @ApiModelProperty("鍙戠エ绫诲瀷")
+    @Excel(name = "鍙戠エ绫诲瀷")
+    private String invoiceType;
+
+    /**
+     * 寮�绁ㄦ棩鏈�
+     */
+    @ApiModelProperty("寮�绁ㄦ棩鏈�")
+    @Excel(name = "寮�绁ㄦ棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate issueDate;
+
+    /**
+     * 閲戦(涓嶅惈绋�)
+     */
+    @ApiModelProperty("閲戦(涓嶅惈绋�)")
+    @Excel(name = "閲戦(涓嶅惈绋�)")
+    private BigDecimal taxExclusivelPrice;
+
+    /**
+     * 绋庨
+     */
+    @ApiModelProperty("绋庨")
+    @Excel(name = "绋庨")
+    private BigDecimal taxPrice;
+
+    /**
+     * 浠风◣鍚堣
+     */
+    @ApiModelProperty("浠风◣鍚堣")
+    @Excel(name = "浠风◣鍚堣")
+    private BigDecimal taxInclusivePrice;
+
+    /**
+     * 澶囨敞
+     */
+    @ApiModelProperty("澶囨敞")
+    @Excel(name = "澶囨敞")
+    private String remark;
+
+    /**
+     * 鍙戠エ鍐呭
+     */
+    @ApiModelProperty("鍙戠エ鍐呭")
+    @Excel(name = "鍙戠エ鍐呭")
+    private String invoiceContent;
+
+    /**
+     * 瀹㈡埛id
+     */
+    @ApiModelProperty("瀹㈡埛id")
+    private Integer customerId;
+
+    /**
+     * 鍏宠仈涓婁紶鐨勫彂绁ㄩ檮浠秈d
+     */
+    @ApiModelProperty("鍏宠仈涓婁紶鐨勫彂绁ㄩ檮浠秈d")
+    private Integer storageAttachmentId;
+
+    /**
+     * 鐘舵�� 0鍚敤 1绂佺敤
+     */
+    @ApiModelProperty("鐘舵�� 0鍚敤 1绂佺敤")
+    @Excel(name = "鐘舵��", readConverterExp = "0=姝e父,1=浣滃簾")
+    private Integer status;
+}
diff --git a/src/main/java/com/ruoyi/account/service/AccountExpenseService.java b/src/main/java/com/ruoyi/account/service/AccountExpenseService.java
deleted file mode 100644
index b070485..0000000
--- a/src/main/java/com/ruoyi/account/service/AccountExpenseService.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.ruoyi.account.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.account.bean.dto.AccountDto;
-import com.ruoyi.account.bean.dto.AccountDto2;
-import com.ruoyi.account.bean.dto.AccountDto3;
-import com.ruoyi.account.bean.dto.ReportDateDto;
-import com.ruoyi.account.pojo.AccountExpense;
-import com.ruoyi.account.pojo.AccountIncome;
-import com.ruoyi.dto.DateQueryDto;
-
-import jakarta.servlet.http.HttpServletResponse;
-import java.util.List;
-import java.util.Map;
-
-public interface AccountExpenseService extends IService<AccountExpense> {
-
-    IPage<AccountExpense> accountExpenseListPage(Page page, AccountExpense accountExpense);
-
-    void accountExpenseExport(HttpServletResponse response, AccountExpense accountExpense);
-
-    AccountDto report(DateQueryDto dateQueryDto);
-
-    List<AccountDto3> reportExpense(ReportDateDto reportDateDto);
-
-    Map<String,List<String>> analysis();
-
-    AccountExpense getByInvoiceNumber(String purchaseContractNumber);
-
-    List<AccountExpense> getByInvoiceNumberList(String purchaseContractNumber);
-}
diff --git a/src/main/java/com/ruoyi/account/service/AccountFileService.java b/src/main/java/com/ruoyi/account/service/AccountFileService.java
deleted file mode 100644
index fe24512..0000000
--- a/src/main/java/com/ruoyi/account/service/AccountFileService.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.ruoyi.account.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.account.pojo.AccountFile;
-import com.ruoyi.quality.pojo.QualityInspectFile;
-
-public interface AccountFileService extends IService<AccountFile> {
-
-
-    IPage<AccountFile> accountFileListPage(Page page, AccountFile accountFile);
-}
diff --git a/src/main/java/com/ruoyi/account/service/AccountIncomeService.java b/src/main/java/com/ruoyi/account/service/AccountIncomeService.java
deleted file mode 100644
index 1f5d684..0000000
--- a/src/main/java/com/ruoyi/account/service/AccountIncomeService.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.ruoyi.account.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.account.bean.dto.AccountDto2;
-import com.ruoyi.account.bean.dto.AccountDto3;
-import com.ruoyi.account.bean.dto.ReportDateDto;
-import com.ruoyi.account.pojo.AccountIncome;
-
-import jakarta.servlet.http.HttpServletResponse;
-import java.util.List;
-
-public interface AccountIncomeService extends IService<AccountIncome> {
-
-
-    IPage<AccountIncome> accountIncomeListPage(Page page, AccountIncome accountIncome);
-
-    void accountIncomeExport(HttpServletResponse response, AccountIncome accountIncome);
-
-    List<AccountDto3> reportIncome(ReportDateDto reportDateDto);
-
-    AccountIncome getByInvoiceNumber(String purchaseContractNumber);
-
-    List<AccountIncome> getByInvoiceNumberList(String purchaseContractNumber);
-}
diff --git a/src/main/java/com/ruoyi/account/service/AccountStatementDetailsService.java b/src/main/java/com/ruoyi/account/service/AccountStatementDetailsService.java
new file mode 100644
index 0000000..c9a4928
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/AccountStatementDetailsService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.account.service;
+
+import com.ruoyi.account.pojo.AccountStatementDetails;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--瀵硅处鍗曟槑缁� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 10:12:42
+ */
+public interface AccountStatementDetailsService extends IService<AccountStatementDetails> {
+
+}
diff --git a/src/main/java/com/ruoyi/account/service/AccountStatementService.java b/src/main/java/com/ruoyi/account/service/AccountStatementService.java
new file mode 100644
index 0000000..a0bc218
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/AccountStatementService.java
@@ -0,0 +1,32 @@
+package com.ruoyi.account.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.account.bean.dto.StatementAccountDto;
+import com.ruoyi.account.bean.vo.StatementAccountVo;
+import com.ruoyi.account.pojo.AccountStatement;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.util.List;
+
+/**
+ * <p>
+ *  鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 09:42:47
+ */
+public interface AccountStatementService extends IService<AccountStatement> {
+
+    StatementAccountVo getAccountStatementDetailsByMonth(StatementAccountDto statementAccountDto);
+
+    boolean addAccountStatement(StatementAccountVo statementAccountVo);
+
+    boolean deleteAccountStatement(List<Long> ids);
+
+    IPage<StatementAccountVo> listPageAccountStatement(Page page, StatementAccountDto statementAccountDto);
+
+    void exportAccountStatement(HttpServletResponse response, StatementAccountDto statementAccountDto);
+}
diff --git a/src/main/java/com/ruoyi/account/service/BorrowInfoService.java b/src/main/java/com/ruoyi/account/service/BorrowInfoService.java
deleted file mode 100644
index eb1c83b..0000000
--- a/src/main/java/com/ruoyi/account/service/BorrowInfoService.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.ruoyi.account.service;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.pojo.BorrowInfo;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.framework.web.domain.AjaxResult;
-
-import java.util.List;
-
-/**
- * <p>
- * 鍊熸淇℃伅琛� 鏈嶅姟绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-01-15 02:57:29
- */
-public interface BorrowInfoService extends IService<BorrowInfo> {
-
-    AjaxResult listPage(Page page, BorrowInfo borrowInfo);
-
-    AjaxResult add(BorrowInfo borrowInfo);
-
-    AjaxResult updateBorrowInfo(BorrowInfo borrowInfo);
-
-    AjaxResult delete(List<Long> ids);
-}
diff --git a/src/main/java/com/ruoyi/account/service/AccountPurchaseService.java b/src/main/java/com/ruoyi/account/service/financial/AccountPurchaseService.java
similarity index 72%
rename from src/main/java/com/ruoyi/account/service/AccountPurchaseService.java
rename to src/main/java/com/ruoyi/account/service/financial/AccountPurchaseService.java
index 386f921..b7a6cfd 100644
--- a/src/main/java/com/ruoyi/account/service/AccountPurchaseService.java
+++ b/src/main/java/com/ruoyi/account/service/financial/AccountPurchaseService.java
@@ -1,11 +1,11 @@
-package com.ruoyi.account.service;
+package com.ruoyi.account.service.financial;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.bean.dto.PurchaseInboundDto;
-import com.ruoyi.account.bean.dto.PurchaseReturnDto;
-import com.ruoyi.account.bean.vo.PurchaseInboundVo;
-import com.ruoyi.account.bean.vo.PurchaseReturnVo;
+import com.ruoyi.account.bean.dto.purchase.PurchaseInboundDto;
+import com.ruoyi.account.bean.dto.purchase.PurchaseReturnDto;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseReturnVo;
 import jakarta.servlet.http.HttpServletResponse;
 
 /**
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountExpenseServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/AccountExpenseServiceImpl.java
deleted file mode 100644
index 9d392a2..0000000
--- a/src/main/java/com/ruoyi/account/service/impl/AccountExpenseServiceImpl.java
+++ /dev/null
@@ -1,233 +0,0 @@
-package com.ruoyi.account.service.impl;
-
-
-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.account.bean.dto.AccountDto;
-import com.ruoyi.account.bean.dto.AccountDto2;
-import com.ruoyi.account.bean.dto.AccountDto3;
-import com.ruoyi.account.bean.dto.ReportDateDto;
-import com.ruoyi.account.mapper.AccountExpenseMapper;
-import com.ruoyi.account.mapper.AccountIncomeMapper;
-import com.ruoyi.account.pojo.AccountExpense;
-import com.ruoyi.account.pojo.AccountIncome;
-import com.ruoyi.account.service.AccountExpenseService;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.dto.DateQueryDto;
-import com.ruoyi.project.system.domain.SysDictData;
-import com.ruoyi.project.system.mapper.SysDictDataMapper;
-import lombok.AllArgsConstructor;
-import org.springframework.stereotype.Service;
-
-import jakarta.servlet.http.HttpServletResponse;
-import java.math.BigDecimal;
-import java.time.DayOfWeek;
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.*;
-import java.util.stream.Collectors;
-
-@AllArgsConstructor
-@Service
-public class AccountExpenseServiceImpl extends ServiceImpl<AccountExpenseMapper, AccountExpense> implements AccountExpenseService {
-
-    private AccountExpenseMapper accountExpenseMapper;
-
-    private AccountIncomeMapper accountIncomeMapper;
-
-    private SysDictDataMapper sysDictDataMapper;
-
-
-    //鍒嗛〉鏌ヨ
-    @Override
-    public IPage<AccountExpense> accountExpenseListPage(Page page, AccountExpense accountExpense) {
-        return accountExpenseMapper.accountExpenseListPage(page,accountExpense);
-    }
-
-    //瀵煎嚭
-    @Override
-    public void accountExpenseExport(HttpServletResponse response, AccountExpense accountExpense) {
-        List<AccountExpense> accountExpenses =accountExpenseMapper.accountExpenseExport(accountExpense);
-        ExcelUtil<AccountExpense> util = new ExcelUtil<AccountExpense>(AccountExpense.class);
-        util.exportExcel(response, accountExpenses, "鏀嚭绠$悊瀵煎嚭");
-    }
-
-    //璐㈠姟鎶ヨ〃鍥捐〃
-    @Override
-    public AccountDto report(DateQueryDto dateQueryDto) {
-        AccountDto accountDto = new AccountDto();
-        //鑾峰彇璇ユ鏃堕棿鍐呯殑鎵�鏈夋敹鍏�
-        List<AccountDto2> accountIncomes =accountIncomeMapper.report(dateQueryDto);
-
-        Long incomeNumber = accountIncomeMapper.selectCount(Wrappers.<AccountIncome>lambdaQuery()
-                .between(AccountIncome::getIncomeDate, dateQueryDto.getEntryDateStart(), dateQueryDto.getEntryDateEnd()));
-        accountDto.setIncomeNumber(incomeNumber);
-        BigDecimal totalIncome = accountIncomes.stream().map(AccountDto2::getAccount).reduce(BigDecimal.ZERO, BigDecimal::add);
-        accountDto.setTotalIncome(totalIncome);
-        accountIncomes.stream().forEach(accountDto2 -> {
-            accountDto2.setProportion(accountDto2.getAccount().divide(totalIncome,2,BigDecimal.ROUND_HALF_UP));
-        });
-        accountDto.setIncomeType(accountIncomes);
-        //鑾峰彇璇ユ鏃堕棿鍐呯殑鎵�鏈夋敮鍑�
-        List<AccountDto2> accountExpenses =accountExpenseMapper.report(dateQueryDto);
-        accountDto.setExpenseType(accountExpenses);
-        Long expenseNumber = accountExpenseMapper.selectCount(Wrappers.<AccountExpense>lambdaQuery()
-                .between(AccountExpense::getExpenseDate, dateQueryDto.getEntryDateStart(), dateQueryDto.getEntryDateEnd()));
-        accountDto.setExpenseNumber(expenseNumber);
-        BigDecimal totalExpense = accountExpenses.stream().map(AccountDto2::getAccount).reduce(BigDecimal.ZERO, BigDecimal::add);
-        accountDto.setTotalExpense(totalExpense);
-        accountExpenses.stream().forEach(accountDto2 -> {
-            accountDto2.setProportion(accountDto2.getAccount().divide(totalExpense,2,BigDecimal.ROUND_HALF_UP));
-        });
-        accountDto.setExpenseType(accountExpenses);
-        //鍑�鏀跺叆
-        BigDecimal netRevenue = totalIncome.subtract(totalExpense);
-        accountDto.setNetRevenue(netRevenue);
-        return accountDto;
-    }
-
-    //璐㈠姟鎶ヨ〃骞存煡璇�
-    @Override
-    public  List<AccountDto3> reportExpense(ReportDateDto reportDateDto) {
-        List<AccountDto3> accountDto3s = new ArrayList<>();
-        //鍏堟煡璇㈡敹鍏ョ被鍨嬫湁鍝簺
-        List<SysDictData> incomeTypes = sysDictDataMapper.selectDictDataByType("expense_types");
-        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-//        int currentYear = LocalDate.now().getYear(); // 鑾峰彇褰撳墠骞翠唤锛堝2025锛�
-        for (SysDictData incomeType : incomeTypes) {
-            AccountDto3 accountDto3 = new AccountDto3();
-            accountDto3.setTypeName(incomeType.getDictLabel());//绫诲瀷
-            List<BigDecimal> account=new ArrayList<>();
-            LocalDate startDate = reportDateDto.getEntryDateStart();
-            LocalDate endDate = reportDateDto.getEntryDateEnd();
-
-            // 鍒濆鍖栧惊鐜彉閲忎负璧峰鏃ユ湡
-            LocalDate currentDate = startDate;
-
-            // 寰幆锛氬綋鍓嶆棩鏈熶笉瓒呰繃缁撴潫鏃ユ湡鏃剁户缁�
-            while (!currentDate.isAfter(endDate)) {
-                // 褰撴湀绗竴澶�
-                LocalDate firstDay = currentDate.withDayOfMonth(1);
-                DateQueryDto dateQueryDto = new DateQueryDto();
-                dateQueryDto.setEntryDateStart(firstDay.format(formatter));
-
-                // 褰撴湀鏈�鍚庝竴澶�
-                LocalDate lastDay = firstDay.plusMonths(1).minusDays(1);
-                dateQueryDto.setEntryDateEnd(lastDay.format(formatter));
-
-                // 绱姞鏁版嵁
-                account.add(accountExpenseMapper.report1(dateQueryDto, incomeType.getDictValue()));
-
-                // 鏈堜唤鍔犱竴锛堣嚜鍔ㄥ鐞嗚法骞达紝姣斿12鏈堝姞1涓湀浼氬彉鎴愪笅涓�骞�1鏈堬級
-                currentDate = currentDate.plusMonths(1);
-            }
-            accountDto3.setAccount(account);//绫诲瀷
-            accountDto3s.add(accountDto3);
-        }
-        return accountDto3s;
-    }
-
-    @Override
-    public Map<String, List<String>> analysis() {
-        // 鑾峰彇鏈�杩戝洓涓湀锛堝綋鍓嶆湀 + 鍓�3涓湀锛夌殑鏃堕棿鑼冨洿
-        LocalDate today = LocalDate.now();
-        DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM"); // 骞存湀鏍煎紡鍖栧櫒
-        Map<String, List<String>> result = new HashMap<>();
-        List<String> months = new ArrayList<>(); // 瀛樺偍骞存湀锛堝 2025-12銆�2025-11锛�
-        List<String> totalIncomeList = new ArrayList<>(); // 姣忔湀鎬绘敹鍏�
-        List<String> totalExpenseList = new ArrayList<>(); // 姣忔湀鎬绘敮鍑�
-        List<String> netIncomeList = new ArrayList<>(); // 姣忔湀鍑�鏀跺叆锛堟敹鍏�-鏀嚭锛�
-
-        // 姝ラ1锛氳绠楄繎4涓湀鐨勫勾鏈堝垪琛紙褰撳墠鏈堛�佸墠1鏈堛�佸墠2鏈堛�佸墠3鏈堬級
-        List<String> targetMonths = new ArrayList<>();
-        for (int i = 0; i < 4; i++) {
-            LocalDate currentMonth = today.minusMonths(i);
-            String monthStr = currentMonth.format(monthFormatter);
-            targetMonths.add(monthStr);
-        }
-        // 鍙嶈浆鍒楄〃锛岀‘淇濋『搴忎负銆屽墠3鏈� 鈫� 褰撳墠鏈堛�嶏紙鍙�夛紝鎸夐渶姹傝皟鏁撮『搴忥級
-        Collections.reverse(targetMonths);
-
-        // 姝ラ2锛氫竴娆℃�ф煡璇㈣繎4涓湀鎵�鏈夋敹鍏ユ暟鎹紝鎸夆�滃勾鏈堚�濆垎缁勬眹鎬�
-        LocalDate fourMonthsAgo = today.minusMonths(3).withDayOfMonth(1); // 杩�4涓湀璧峰鏃ワ紙鍓�3鏈�1鍙凤級
-        LocalDate currentMonthEnd = today.withDayOfMonth(today.lengthOfMonth()); // 褰撳墠鏈堢粨鏉熸棩
-        ZoneId zoneId = ZoneId.of("Asia/Shanghai");
-        // 鏌ヨ杩�4涓湀鎵�鏈夋敹鍏�
-        List<AccountIncome> allIncomes = accountIncomeMapper.selectList(
-                Wrappers.<AccountIncome>lambdaQuery()
-                        .ge(AccountIncome::getIncomeDate, fourMonthsAgo.toString()) // 澶т簬绛変簬璧峰鏃�
-                        .le(AccountIncome::getIncomeDate, currentMonthEnd.toString()) // 灏忎簬绛変簬缁撴潫鏃�
-        );
-
-        // 鏀跺叆鎸夆�滃勾鏈堚�濆垎缁勬眹鎬伙紙key锛氬勾鏈堝瓧绗︿覆锛寁alue锛氬綋鏈堟�绘敹鍏ワ級
-        Map<String, BigDecimal> monthlyIncomeMap = allIncomes.stream()
-                .filter(income -> income.getIncomeMoney() != null) // 杩囨护绌洪噾棰�
-                .collect(Collectors.groupingBy(
-                        income -> {
-                            // 灏嗚緭鍏ユ椂闂达紙瀛楃涓诧級杞崲涓篖ocalDate锛屽啀鏍煎紡鍖栦负骞存湀
-                            LocalDate inputDate = income.getIncomeDate().toInstant().atZone(zoneId).toLocalDate();
-                            return inputDate.format(monthFormatter);
-                        },
-                        Collectors.reducing(BigDecimal.ZERO, AccountIncome::getIncomeMoney, BigDecimal::add)
-                ));
-
-        // 姝ラ3锛氫竴娆℃�ф煡璇㈣繎4涓湀鎵�鏈夋敮鍑烘暟鎹紝鎸夆�滃勾鏈堚�濆垎缁勬眹鎬�
-        List<AccountExpense> allExpenses = accountExpenseMapper.selectList(
-                Wrappers.<AccountExpense>lambdaQuery()
-                        .ge(AccountExpense::getExpenseDate, fourMonthsAgo.toString())
-                        .le(AccountExpense::getExpenseDate, currentMonthEnd.toString())
-        );
-
-        // 鏀嚭鎸夆�滃勾鏈堚�濆垎缁勬眹鎬�
-        Map<String, BigDecimal> monthlyExpenseMap = allExpenses.stream()
-                .filter(expense -> expense.getExpenseMoney() != null) // 杩囨护绌洪噾棰�
-                .collect(Collectors.groupingBy(
-                        expense -> {
-                            LocalDate inputDate = expense.getExpenseDate().toInstant().atZone(zoneId).toLocalDate();
-                            return inputDate.format(monthFormatter);
-                        },
-                        Collectors.reducing(BigDecimal.ZERO, AccountExpense::getExpenseMoney, BigDecimal::add)
-                ));
-
-        // 姝ラ4锛氬惊鐜�4涓洰鏍囨湀浠斤紝濉厖缁熻鏁版嵁锛堟棤鏁版嵁鏃堕粯璁や负0锛�
-        for (String month : targetMonths) {
-            // 褰撴湀鎬绘敹鍏ワ紙鏃犳暟鎹垯涓�0锛�
-            BigDecimal totalIncome = monthlyIncomeMap.getOrDefault(month, BigDecimal.ZERO);
-            // 褰撴湀鎬绘敮鍑猴紙鏃犳暟鎹垯涓�0锛�
-            BigDecimal totalExpense = monthlyExpenseMap.getOrDefault(month, BigDecimal.ZERO);
-            // 褰撴湀鍑�鏀跺叆锛堟敹鍏� - 鏀嚭锛�
-            BigDecimal netIncome = totalIncome.subtract(totalExpense);
-
-            // 濉厖鍒楄〃
-            months.add(month);
-            totalIncomeList.add(totalIncome.toString());
-            totalExpenseList.add(totalExpense.toString());
-            netIncomeList.add(netIncome.toString());
-        }
-
-        // 缁勮缁撴灉
-        result.put("days", months); // 骞存湀锛堝 ["2025-09", "2025-10", "2025-11", "2025-12"]锛�
-        result.put("totalIncome", totalIncomeList); // 瀵瑰簲鏈堜唤鎬绘敹鍏�
-        result.put("totalExpense", totalExpenseList); // 瀵瑰簲鏈堜唤鎬绘敮鍑�
-        result.put("netIncome", netIncomeList); // 瀵瑰簲鏈堜唤鍑�鏀跺叆
-
-        return result;
-    }
-
-    @Override
-    public AccountExpense getByInvoiceNumber(String purchaseContractNumber) {
-        return accountExpenseMapper.selectOne(Wrappers.<AccountExpense>lambdaQuery()
-                .eq(AccountExpense::getInvoiceNumber, purchaseContractNumber));
-    }
-
-    @Override
-    public List<AccountExpense> getByInvoiceNumberList(String purchaseContractNumber) {
-        return accountExpenseMapper.selectList(Wrappers.<AccountExpense>lambdaQuery()
-                .eq(AccountExpense::getInvoiceNumber, purchaseContractNumber));
-    }
-
-
-}
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountFileServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/AccountFileServiceImpl.java
deleted file mode 100644
index b1e8f84..0000000
--- a/src/main/java/com/ruoyi/account/service/impl/AccountFileServiceImpl.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.ruoyi.account.service.impl;
-
-
-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.account.mapper.AccountFileMapper;
-import com.ruoyi.account.pojo.AccountFile;
-import com.ruoyi.account.service.AccountFileService;
-import com.ruoyi.quality.mapper.QualityInspectFileMapper;
-import com.ruoyi.quality.pojo.QualityInspectFile;
-import com.ruoyi.quality.service.IQualityInspectFileService;
-import lombok.AllArgsConstructor;
-import org.springframework.stereotype.Service;
-
-@AllArgsConstructor
-@Service
-public class AccountFileServiceImpl extends ServiceImpl<AccountFileMapper, AccountFile> implements AccountFileService {
-
-    private AccountFileMapper accountFileMapper;
-
-
-    @Override
-    public IPage<AccountFile> accountFileListPage(Page page, AccountFile accountFile) {
-        return accountFileMapper.accountFileListPage(page,accountFile);
-    }
-}
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountIncomeServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/AccountIncomeServiceImpl.java
deleted file mode 100644
index e760a2d..0000000
--- a/src/main/java/com/ruoyi/account/service/impl/AccountIncomeServiceImpl.java
+++ /dev/null
@@ -1,136 +0,0 @@
-package com.ruoyi.account.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.account.bean.dto.AccountDto3;
-import com.ruoyi.account.bean.dto.ReportDateDto;
-import com.ruoyi.account.mapper.AccountIncomeMapper;
-import com.ruoyi.account.pojo.AccountIncome;
-import com.ruoyi.account.service.AccountIncomeService;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.dto.DateQueryDto;
-import com.ruoyi.project.system.domain.SysDictData;
-import com.ruoyi.project.system.mapper.SysDictDataMapper;
-import lombok.AllArgsConstructor;
-import org.springframework.stereotype.Service;
-
-import jakarta.servlet.http.HttpServletResponse;
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-@AllArgsConstructor
-@Service
-public class AccountIncomeServiceImpl extends ServiceImpl<AccountIncomeMapper, AccountIncome> implements AccountIncomeService {
-
-    private AccountIncomeMapper accountIncomeMapper;
-
-    private SysDictDataMapper sysDictDataMapper;
-
-
-    //鍒嗛〉鏌ヨ
-    @Override
-    public IPage<AccountIncome> accountIncomeListPage(Page page, AccountIncome accountIncome) {
-        resolveIncomeMethodLabelFilter(accountIncome);
-        return accountIncomeMapper.accountIncomeListPage(page,accountIncome);
-    }
-
-    private void resolveIncomeMethodLabelFilter(AccountIncome accountIncome) {
-        if (accountIncome == null) {
-            return;
-        }
-        if (accountIncome.getIncomeMethodLabel() == null || accountIncome.getIncomeMethodLabel().trim().isEmpty()) {
-            return;
-        }
-        String targetLabel = accountIncome.getIncomeMethodLabel().trim();
-        List<String> paymentMethodList = selectDictValuesByLabel("payment_methods", targetLabel);
-        List<String> receiptPaymentMethodList = selectDictValuesByLabel("receipt_payment_type", targetLabel);
-        if (paymentMethodList.isEmpty()) {
-            paymentMethodList = Collections.singletonList("__NO_MATCH__");
-        }
-        if (receiptPaymentMethodList.isEmpty()) {
-            receiptPaymentMethodList = Collections.singletonList("__NO_MATCH__");
-        }
-        accountIncome.setPaymentMethodList(paymentMethodList);
-        accountIncome.setReceiptPaymentMethodList(receiptPaymentMethodList);
-        accountIncome.setIncomeMethod(null);
-    }
-
-    private List<String> selectDictValuesByLabel(String dictType, String label) {
-        return sysDictDataMapper.selectDictDataByType(dictType).stream()
-                .filter(item -> label.equals(item.getDictLabel()))
-                .map(SysDictData::getDictValue)
-                .filter(v -> v != null && !v.trim().isEmpty())
-                .distinct()
-                .collect(Collectors.toList());
-    }
-
-    //瀵煎嚭
-    @Override
-    public void accountIncomeExport(HttpServletResponse response, AccountIncome accountIncome) {
-        List<AccountIncome> accountIncomes =accountIncomeMapper.accountIncomeExport(accountIncome);
-        ExcelUtil<AccountIncome> util = new ExcelUtil<AccountIncome>(AccountIncome.class);
-        util.exportExcel(response, accountIncomes, "鏀跺叆绠$悊瀵煎嚭");
-    }
-
-    //璐㈠姟鎶ヨ〃骞存煡璇�
-    @Override
-    public List<AccountDto3> reportIncome(ReportDateDto reportDateDto) {
-        List<AccountDto3> accountDto3s = new ArrayList<>();
-        //鍏堟煡璇㈡敹鍏ョ被鍨嬫湁鍝簺
-        List<SysDictData> incomeTypes = sysDictDataMapper.selectDictDataByType("income_types");
-        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-//        int currentYear = LocalDate.now().getYear(); // 鑾峰彇褰撳墠骞翠唤锛堝2025锛�
-        for (SysDictData incomeType : incomeTypes) {
-            AccountDto3 accountDto3 = new AccountDto3();
-            accountDto3.setTypeName(incomeType.getDictLabel());//绫诲瀷
-            List<BigDecimal> account=new ArrayList<>();
-            LocalDate startDate = reportDateDto.getEntryDateStart();
-            LocalDate endDate = reportDateDto.getEntryDateEnd();
-
-            // 鍒濆鍖栧惊鐜彉閲忎负璧峰鏃ユ湡
-            LocalDate currentDate = startDate;
-
-            // 寰幆锛氬綋鍓嶆棩鏈熶笉瓒呰繃缁撴潫鏃ユ湡鏃剁户缁�
-            while (!currentDate.isAfter(endDate)) {
-                // 褰撴湀绗竴澶�
-                LocalDate firstDay = currentDate.withDayOfMonth(1);
-                DateQueryDto dateQueryDto = new DateQueryDto();
-                dateQueryDto.setEntryDateStart(firstDay.format(formatter));
-
-                // 褰撴湀鏈�鍚庝竴澶�
-                LocalDate lastDay = firstDay.plusMonths(1).minusDays(1);
-                dateQueryDto.setEntryDateEnd(lastDay.format(formatter));
-
-                // 绱姞鏁版嵁
-                account.add(accountIncomeMapper.report1(dateQueryDto, incomeType.getDictValue()));
-
-                // 鏈堜唤鍔犱竴锛堣嚜鍔ㄥ鐞嗚法骞达紝姣斿12鏈堝姞1涓湀浼氬彉鎴愪笅涓�骞�1鏈堬級
-                currentDate = currentDate.plusMonths(1);
-            }
-            accountDto3.setAccount(account);//绫诲瀷
-            accountDto3s.add(accountDto3);
-        }
-        return accountDto3s;
-    }
-
-    @Override
-    public AccountIncome getByInvoiceNumber(String purchaseContractNumber) {
-        AccountIncome accountIncome = accountIncomeMapper.selectOne(new LambdaQueryWrapper<AccountIncome>()
-                .eq(AccountIncome::getInvoiceNumber, purchaseContractNumber));
-        return accountIncome;
-    }
-
-    @Override
-    public List<AccountIncome> getByInvoiceNumberList(String purchaseContractNumber) {
-        return accountIncomeMapper.selectList(new LambdaQueryWrapper<AccountIncome>()
-                .eq(AccountIncome::getInvoiceNumber, purchaseContractNumber));
-    }
-}
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountStatementDetailsServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/AccountStatementDetailsServiceImpl.java
new file mode 100644
index 0000000..6d1ba1c
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/AccountStatementDetailsServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.account.service.impl;
+
+import com.ruoyi.account.pojo.AccountStatementDetails;
+import com.ruoyi.account.mapper.AccountStatementDetailsMapper;
+import com.ruoyi.account.service.AccountStatementDetailsService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--瀵硅处鍗曟槑缁� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 10:12:42
+ */
+@Service
+public class AccountStatementDetailsServiceImpl extends ServiceImpl<AccountStatementDetailsMapper, AccountStatementDetails> implements AccountStatementDetailsService {
+
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountStatementServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/AccountStatementServiceImpl.java
new file mode 100644
index 0000000..411d595
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/AccountStatementServiceImpl.java
@@ -0,0 +1,298 @@
+package com.ruoyi.account.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+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.account.bean.dto.StatementAccountDto;
+import com.ruoyi.account.bean.dto.purchase.PurchaseInboundDto;
+import com.ruoyi.account.bean.dto.purchase.PurchaseReturnDto;
+import com.ruoyi.account.bean.dto.sales.SalesOutboundDto;
+import com.ruoyi.account.bean.dto.sales.SalesReturnDto;
+import com.ruoyi.account.bean.vo.StatementAccountVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseReturnVo;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.bean.vo.sales.SalesReturnVo;
+import com.ruoyi.account.mapper.AccountStatementDetailsMapper;
+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.AccountStatementDetails;
+import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
+import com.ruoyi.account.pojo.sales.AccountSalesCollection;
+import com.ruoyi.account.service.AccountStatementService;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.bean.BeanUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.procurementrecord.mapper.ReturnManagementMapper;
+import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper;
+import com.ruoyi.stock.mapper.StockInRecordMapper;
+import com.ruoyi.stock.mapper.StockOutRecordMapper;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.YearMonth;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * <p>
+ *  鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 09:42:47
+ */
+@Service
+@RequiredArgsConstructor
+@Transactional(rollbackFor = Exception.class)
+public class AccountStatementServiceImpl extends ServiceImpl<AccountStatementMapper, AccountStatement> implements AccountStatementService {
+
+    private final AccountStatementMapper accountStatementMapper;
+    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
+    private final StockOutRecordMapper stockOutRecordMapper;
+    private final StockInRecordMapper stockInRecordMapper;
+    private final ReturnManagementMapper returnManagementMapper;
+    private final AccountStatementDetailsMapper accountStatementDetailsMapper;
+    private final AccountPurchasePaymentMapper accountPurchasePaymentMapper;
+    private final PurchaseReturnOrdersMapper purchaseReturnOrdersMapper;
+    private static final DateTimeFormatter CODE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyMMdd");
+
+    @Override
+    public StatementAccountVo getAccountStatementDetailsByMonth(StatementAccountDto statementAccountDto) {
+        //瀵硅处鏈堜唤杞崲鎴愬紑濮嬫棩鏈熷拰缁撴潫鏃ユ湡鍖洪棿
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
+        YearMonth yearMonth = YearMonth.parse(statementAccountDto.getStatementMonth(), formatter);
+        statementAccountDto.setStartDate(yearMonth.atDay(1));
+        statementAccountDto.setEndDate(yearMonth.atEndOfMonth());
+        if (statementAccountDto.getAccountType() == 1){
+            //搴旀敹瀵硅处--Customer
+            return getAccountStatementDetailsByCustomerAndMonth(statementAccountDto);
+        }else {
+            //搴斾粯瀵硅处--SupplierManage
+            return getAccountStatementDetailsBySupplierAndMonth(statementAccountDto);
+        }
+    }
+
+    @Override
+    public boolean addAccountStatement(StatementAccountVo statementAccountVo) {
+        //鍚屼竴瀹㈡埛鎴栬�呭悓涓�渚涘簲鍟�,涓�涓湀浠藉彧鑳芥湁涓�涓璐﹀崟
+        List<AccountStatement> accountStatements = accountStatementMapper.selectList(Wrappers.<AccountStatement>lambdaQuery()
+                .eq(AccountStatement::getStatementMonth, statementAccountVo.getStatementMonth())
+                .eq(AccountStatement::getAccountType, statementAccountVo.getAccountType())
+                .eq(AccountStatement::getCustomerId, statementAccountVo.getCustomerId()));
+        if (CollectionUtils.isNotEmpty(accountStatements)){
+            throw new ServiceException("鍚屼竴瀹㈡埛鎴栬�呭悓涓�渚涘簲鍟�,涓�涓湀浠藉彧鑳芥湁涓�涓璐﹀崟");
+        }
+        AccountStatement accountStatement = new AccountStatement();
+        BeanUtils.copyProperties(statementAccountVo, accountStatement);
+        accountStatement.setStatementNumber(genStatementAccountNo());
+        boolean save = save(accountStatement);
+        statementAccountVo.getAccountStatementDetails().stream().forEach(accountStatementDetails -> {
+            accountStatementDetails.setAccountStatementId(accountStatement.getId());
+            //娣诲姞瀵硅处鍗曟槑缁�
+            accountStatementDetailsMapper.insert(accountStatementDetails);
+        });
+        return save;
+    }
+
+    @Override
+    public boolean deleteAccountStatement(List<Long> ids) {
+        //鍒犻櫎瀵硅处鍗曟槑缁�
+        accountStatementDetailsMapper.delete(Wrappers.<AccountStatementDetails>lambdaQuery().in(AccountStatementDetails::getAccountStatementId, ids));
+        return removeByIds(ids);
+    }
+
+    @Override
+    public IPage<StatementAccountVo> listPageAccountStatement(Page page, StatementAccountDto statementAccountDto) {
+        return accountStatementMapper.listPageAccountStatement(page, statementAccountDto);
+    }
+
+    @Override
+    public void exportAccountStatement(HttpServletResponse response, StatementAccountDto statementAccountDto) {
+        List<StatementAccountVo> list = accountStatementMapper.listPageAccountStatement(new Page(1,-1),statementAccountDto).getRecords();
+        ExcelUtil<StatementAccountVo> util = new ExcelUtil<>(StatementAccountVo.class);
+        util.exportExcel(response, list , "瀵硅处鍗�");
+    }
+
+    //鏍规嵁瀹㈡埛鍜屾湀浠借幏鍙栧璐﹁鎯�(閿�鍞�)
+    private StatementAccountVo getAccountStatementDetailsByCustomerAndMonth(StatementAccountDto statementAccountDto) {
+        StatementAccountVo statementAccountVo = new StatementAccountVo();
+        statementAccountVo.setAccountType(1);//搴旀敹瀵硅处
+        List<AccountStatementDetails> accountStatementDetailsList = new ArrayList<>();
+        /*鏌ヨ鍑哄簱鏄庣粏*/
+        SalesOutboundDto salesOutboundDto = new SalesOutboundDto();
+        salesOutboundDto.setCustomerId(statementAccountDto.getCustomerId());
+        salesOutboundDto.setStartDate(statementAccountDto.getStartDate());
+        salesOutboundDto.setEndDate(statementAccountDto.getEndDate());
+        List<SalesOutboundVo> salesOutboundVos = stockOutRecordMapper.listPageAccountSales(new Page(1, -1), salesOutboundDto).getRecords();
+        salesOutboundVos.stream().forEach(salesOutboundVo -> {
+            AccountStatementDetails accountStatementDetails = new AccountStatementDetails();
+            //鏁版嵁鏃ユ湡=鍑哄簱鏃ユ湡
+            accountStatementDetails.setOccurrenceDate(salesOutboundVo.getShippingDate());
+            //鍗曟嵁缂栧彿=鍑哄簱鍗曞彿
+            accountStatementDetails.setReceiptNumber(salesOutboundVo.getOutboundBatches());
+            //绫诲瀷=鍑哄簱
+            accountStatementDetails.setType(1);
+            //閲戦=鍑哄簱閲戦
+            accountStatementDetails.setAmount(salesOutboundVo.getOutboundAmount());
+            //澶囨敞
+            accountStatementDetails.setRemark("浜у搧閿�鍞嚭搴擄紝浜у搧锛�"+salesOutboundVo.getProductName());
+            accountStatementDetailsList.add(accountStatementDetails);
+        });
+        /*鏌ヨ鏀舵鏄庣粏*/
+        List<AccountSalesCollection> accountSalesCollections = accountSalesCollectionMapper.selectList(Wrappers.<AccountSalesCollection>lambdaQuery()
+                .eq(AccountSalesCollection::getCustomerId, statementAccountDto.getCustomerId())
+                .between(AccountSalesCollection::getCollectionDate, statementAccountDto.getStartDate(), statementAccountDto.getEndDate()));
+        accountSalesCollections.stream().forEach(accountSalesCollection -> {
+            AccountStatementDetails accountStatementDetails = new AccountStatementDetails();
+            //鏁版嵁鏃ユ湡=鏀舵鏃ユ湡
+            accountStatementDetails.setOccurrenceDate(accountSalesCollection.getCollectionDate());
+            //鍗曟嵁缂栧彿=鏀舵鍗曞彿
+            accountStatementDetails.setReceiptNumber(accountSalesCollection.getCollectionNumber());
+            //绫诲瀷=鏀舵
+            accountStatementDetails.setType(3);
+            //閲戦=鏀舵閲戦
+            accountStatementDetails.setAmount(accountSalesCollection.getCollectionAmount());
+            //澶囨敞
+            accountStatementDetails.setRemark("瀹㈡埛鍥炴锛屽娉細"+accountSalesCollection.getRemark());
+            accountStatementDetailsList.add(accountStatementDetails);
+        });
+        /*鏌ヨ閫�璐ф槑缁�*/
+        SalesReturnDto salesReturnDto = new SalesReturnDto();
+        salesReturnDto.setCustomerId(statementAccountDto.getCustomerId());
+        salesReturnDto.setStartDate(statementAccountDto.getStartDate());
+        salesReturnDto.setEndDate(statementAccountDto.getEndDate());
+        List<SalesReturnVo> salesReturnVos = returnManagementMapper.listPageAccountSalesReturn(new Page(1, -1), salesReturnDto).getRecords();
+        salesReturnVos.stream().forEach(salesReturnVo -> {
+            AccountStatementDetails accountStatementDetails = new AccountStatementDetails();
+            //鏁版嵁鏃ユ湡=閫�璐ф棩鏈�
+            accountStatementDetails.setOccurrenceDate(salesReturnVo.getMakeTime().toLocalDate());
+            //鍗曟嵁缂栧彿=閫�璐у崟鍙�
+            accountStatementDetails.setReceiptNumber(salesReturnVo.getReturnNo());
+            //绫诲瀷=閫�璐�
+            accountStatementDetails.setType(5);
+            //閲戦=閫�娆鹃噾棰�
+            accountStatementDetails.setAmount(salesReturnVo.getRefundAmount());
+            //澶囨敞
+            accountStatementDetails.setRemark("浜у搧閫�璐э紝鍘熷洜锛�"+salesReturnVo.getReturnReason());
+            accountStatementDetailsList.add(accountStatementDetails);
+        });
+        //鏈熷垵浣欓=涓婁釜鏈堢殑鏈熸湯浣欓
+        statementAccountVo.setOpeningBalance(BigDecimal.ZERO);
+        List<AccountStatement> accountStatements = accountStatementMapper.selectList(Wrappers.<AccountStatement>lambdaQuery()
+                .eq(AccountStatement::getAccountType, 1)
+                .eq(AccountStatement::getCustomerId, statementAccountDto.getCustomerId())
+                .eq(AccountStatement::getStatementMonth,
+                        YearMonth.parse(statementAccountDto.getStatementMonth()).minusMonths(1).toString()));
+        if (CollectionUtils.isNotEmpty(accountStatements)){
+            statementAccountVo.setOpeningBalance(accountStatements.get(accountStatements.size() - 1).getClosingBalance());
+        }
+        //鏈湡搴旀敹=鍑哄簱-閫�璐ч噾棰濈疮璁�
+        statementAccountVo.setCurrentPlan(salesOutboundVos.stream().map(SalesOutboundVo::getOutboundAmount).reduce(BigDecimal.ZERO, BigDecimal::add)
+                .subtract(salesReturnVos.stream().map(SalesReturnVo::getRefundAmount).reduce(BigDecimal.ZERO, BigDecimal::add)));
+        //鏈湡鏀舵=鏀舵閲戦绱
+        statementAccountVo.setCurrentActually(accountSalesCollections.stream().map(AccountSalesCollection::getCollectionAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
+        //鏈熸湯浣欓=鏈熷垵+搴旀敹-鏀舵
+        statementAccountVo.setClosingBalance(statementAccountVo.getOpeningBalance().add(statementAccountVo.getCurrentPlan()).subtract(statementAccountVo.getCurrentActually()));
+        statementAccountVo.setAccountStatementDetails(accountStatementDetailsList);
+        return statementAccountVo;
+    }
+
+    //鏍规嵁渚涘簲鍟嗗拰鏈堜唤鑾峰彇瀵硅处璇︽儏(閲囪喘)
+    private StatementAccountVo getAccountStatementDetailsBySupplierAndMonth(StatementAccountDto statementAccountDto) {
+        StatementAccountVo statementAccountVo = new StatementAccountVo();
+        statementAccountVo.setAccountType(2);//搴斾粯瀵硅处
+        List<AccountStatementDetails> accountStatementDetailsList = new ArrayList<>();
+        /*鏌ヨ鍏ュ簱鏄庣粏*/
+        PurchaseInboundDto purchaseInboundDto = new PurchaseInboundDto();
+        purchaseInboundDto.setSupplierId(statementAccountDto.getCustomerId());
+        purchaseInboundDto.setStartDate(statementAccountDto.getStartDate());
+        purchaseInboundDto.setEndDate(statementAccountDto.getEndDate());
+        List<PurchaseInboundVo> purchaseInboundVos = stockInRecordMapper.listPageAccountPurchase(new Page(1, -1), purchaseInboundDto).getRecords();
+        purchaseInboundVos.stream().forEach(purchaseInboundVo -> {
+            AccountStatementDetails accountStatementDetails = new AccountStatementDetails();
+            //鏁版嵁鏃ユ湡=鍏ュ簱鏃ユ湡
+            accountStatementDetails.setOccurrenceDate(purchaseInboundVo.getInboundDate());
+            //鍗曟嵁缂栧彿=鍏ュ簱鍗曞彿
+            accountStatementDetails.setReceiptNumber(purchaseInboundVo.getInboundBatches());
+            //绫诲瀷=鍏ュ簱
+            accountStatementDetails.setType(2);
+            //閲戦=鍏ュ簱閲戦
+            accountStatementDetails.setAmount(purchaseInboundVo.getInboundAmount());
+            //澶囨敞
+            accountStatementDetails.setRemark("浜у搧閲囪喘鍏ュ簱锛屼骇鍝侊細"+purchaseInboundVo.getProductName());
+            accountStatementDetailsList.add(accountStatementDetails);
+        });
+        /*鏌ヨ浠樻鏄庣粏*/
+        List<AccountPurchasePayment> accountPurchasePayments = accountPurchasePaymentMapper.selectList(Wrappers.<AccountPurchasePayment>lambdaQuery()
+                .eq(AccountPurchasePayment::getSupplierId, statementAccountDto.getCustomerId())
+                .between(AccountPurchasePayment::getPaymentDate, statementAccountDto.getStartDate(), statementAccountDto.getEndDate()));
+        accountPurchasePayments.stream().forEach(accountPurchasePayment -> {
+            AccountStatementDetails accountStatementDetails = new AccountStatementDetails();
+            //鏁版嵁鏃ユ湡=浠樻鏃ユ湡
+            accountStatementDetails.setOccurrenceDate(accountPurchasePayment.getPaymentDate());
+            //鍗曟嵁缂栧彿=浠樻鍗曞彿
+            accountStatementDetails.setReceiptNumber(accountPurchasePayment.getPaymentNumber());
+            //绫诲瀷=浠樻
+            accountStatementDetails.setType(4);
+            //閲戦=浠樻閲戦
+            accountStatementDetails.setAmount(accountPurchasePayment.getPaymentAmount());
+            //澶囨敞
+            accountStatementDetails.setRemark("鏀粯璐ф锛屽娉細"+accountPurchasePayment.getRemark());
+            accountStatementDetailsList.add(accountStatementDetails);
+        });
+        /*鏌ヨ閫�璐ф槑缁�*/
+        PurchaseReturnDto purchaseReturnDto = new PurchaseReturnDto();
+        purchaseReturnDto.setSupplierId(statementAccountDto.getCustomerId());
+        purchaseReturnDto.setStartDate(statementAccountDto.getStartDate());
+        purchaseReturnDto.setEndDate(statementAccountDto.getEndDate());
+        List<PurchaseReturnVo> purchaseReturnVos = purchaseReturnOrdersMapper.listPageAccountPurchaseReturn(new Page(1, -1), purchaseReturnDto).getRecords();
+        purchaseReturnVos.stream().forEach(purchaseReturnVo -> {
+            AccountStatementDetails accountStatementDetails = new AccountStatementDetails();
+            //鏁版嵁鏃ユ湡=閫�璐ф棩鏈�
+            accountStatementDetails.setOccurrenceDate(purchaseReturnVo.getPreparedAt().toLocalDate());
+            //鍗曟嵁缂栧彿=閫�璐у崟鍙�
+            accountStatementDetails.setReceiptNumber(purchaseReturnVo.getReturnNo());
+            //绫诲瀷=閫�璐�
+            accountStatementDetails.setType(5);
+            //閲戦=閫�娆鹃噾棰�
+            accountStatementDetails.setAmount(purchaseReturnVo.getTotalAmount());
+            //澶囨敞
+            accountStatementDetails.setRemark("浜у搧閫�璐э紝閫�璐ф柟寮忥細"+purchaseReturnVo.getReturnType());
+            accountStatementDetailsList.add(accountStatementDetails);
+        });
+        //鏈熷垵浣欓=涓婁釜鏈堢殑鏈熸湯浣欓
+        statementAccountVo.setOpeningBalance(BigDecimal.ZERO);
+        List<AccountStatement> accountStatements = accountStatementMapper.selectList(Wrappers.<AccountStatement>lambdaQuery()
+                .eq(AccountStatement::getAccountType, 2)
+                .eq(AccountStatement::getCustomerId, statementAccountDto.getCustomerId())
+                .eq(AccountStatement::getStatementMonth,
+                        YearMonth.parse(statementAccountDto.getStatementMonth()).minusMonths(1).toString()));
+        if (CollectionUtils.isNotEmpty(accountStatements)){
+            statementAccountVo.setOpeningBalance(accountStatements.get(accountStatements.size() - 1).getClosingBalance());
+        }
+        //鏈湡搴斾粯=鍏ュ簱-閫�璐ч噾棰濈疮璁�
+        statementAccountVo.setCurrentPlan(purchaseInboundVos.stream().map(PurchaseInboundVo::getInboundAmount).reduce(BigDecimal.ZERO, BigDecimal::add)
+                .subtract(purchaseReturnVos.stream().map(PurchaseReturnVo::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add)));
+        //鏈湡浠樻=浠樻閲戦绱
+        statementAccountVo.setCurrentActually(accountPurchasePayments.stream().map(AccountPurchasePayment::getPaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
+        //鏈熸湯浣欓=鏈熷垵+搴旀敹-鏀舵
+        statementAccountVo.setClosingBalance(statementAccountVo.getOpeningBalance().add(statementAccountVo.getCurrentPlan()).subtract(statementAccountVo.getCurrentActually()));
+        statementAccountVo.setAccountStatementDetails(accountStatementDetailsList);
+        return statementAccountVo;
+    }
+
+    private String genStatementAccountNo() {
+        return "DZ" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10);
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java
index ab38285..01f5687 100644
--- a/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java
+++ b/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java
@@ -6,8 +6,6 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.account.bean.dto.DeviceTypeDetail;
 import com.ruoyi.account.bean.dto.DeviceTypeDistributionVO;
-import com.ruoyi.account.mapper.BorrowInfoMapper;
-import com.ruoyi.account.pojo.BorrowInfo;
 import com.ruoyi.device.mapper.DeviceLedgerMapper;
 import com.ruoyi.device.pojo.DeviceLedger;
 import com.ruoyi.framework.web.domain.AjaxResult;
@@ -38,7 +36,6 @@
 public class AccountingServiceImpl {
 
     private final DeviceLedgerMapper deviceLedgerMapper;
-    private final BorrowInfoMapper borrowInfoMapper;
     private final CustomStorageMapper customStorageMapper;
     private final ProcurementRecordMapper procurementRecordMapper;
     private final ProcurementRecordOutMapper procurementRecordOutMapper;
@@ -75,17 +72,8 @@
             map.put("netValue",reduce.subtract(total));
         }
         // 璐熷��
-        LambdaQueryWrapper<BorrowInfo> borrowInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        borrowInfoLambdaQueryWrapper.like(BorrowInfo::getCreateTime,year)
-                .eq(BorrowInfo::getStatus,1);
-        List<BorrowInfo> borrowInfos = borrowInfoMapper.selectList(borrowInfoLambdaQueryWrapper);
-        if(CollectionUtils.isNotEmpty(borrowInfos)){
-            BigDecimal reduce = borrowInfos.stream()
-                    .map(BorrowInfo::getBorrowAmount)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-            map.put("debt",reduce);
-        }
+        map.put("debt",BigDecimal.ZERO);
+
         // 搴撳瓨璧勪骇
         LambdaQueryWrapper<ProcurementRecordStorage> procurementRecordStorageLambdaQueryWrapper = new LambdaQueryWrapper<>();
         procurementRecordStorageLambdaQueryWrapper.like(ProcurementRecordStorage::getCreateTime,year);
diff --git a/src/main/java/com/ruoyi/account/service/impl/BorrowInfoServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/BorrowInfoServiceImpl.java
deleted file mode 100644
index 773799d..0000000
--- a/src/main/java/com/ruoyi/account/service/impl/BorrowInfoServiceImpl.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package com.ruoyi.account.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.account.mapper.BorrowInfoMapper;
-import com.ruoyi.account.pojo.AccountExpense;
-import com.ruoyi.account.pojo.AccountIncome;
-import com.ruoyi.account.pojo.BorrowInfo;
-import com.ruoyi.account.service.AccountExpenseService;
-import com.ruoyi.account.service.AccountIncomeService;
-import com.ruoyi.account.service.BorrowInfoService;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-
-/**
- * <p>
- * 鍊熸淇℃伅琛� 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
- * @since 2026-01-15 02:57:29
- */
-@Service
-@Slf4j
-@RequiredArgsConstructor
-public class BorrowInfoServiceImpl extends ServiceImpl<BorrowInfoMapper, BorrowInfo> implements BorrowInfoService {
-
-    private final BorrowInfoMapper borrowInfoMapper;
-    private final AccountIncomeService accountIncomeService;
-    private final AccountExpenseService accountExpenseService;
-
-    @Override
-    public AjaxResult listPage(Page page, BorrowInfo borrowInfo) {
-        LambdaQueryWrapper<BorrowInfo> borrowInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        if(borrowInfo != null){
-            if(StringUtils.isNotEmpty(borrowInfo.getEntryDateStart()) && StringUtils.isNotEmpty(borrowInfo.getEntryDateEnd())){
-                borrowInfoLambdaQueryWrapper.ge(BorrowInfo::getBorrowDate, borrowInfo.getEntryDateStart());
-                borrowInfoLambdaQueryWrapper.le(BorrowInfo::getBorrowDate, borrowInfo.getEntryDateEnd());
-            }
-            if(borrowInfo.getStatus() != null){
-                borrowInfoLambdaQueryWrapper.eq(BorrowInfo::getStatus, borrowInfo.getStatus());
-            }
-            if(StringUtils.isNotEmpty(borrowInfo.getBorrowerName())){
-                borrowInfoLambdaQueryWrapper.like(BorrowInfo::getBorrowerName, borrowInfo.getBorrowerName());
-            }
-        }
-        return AjaxResult.success(borrowInfoMapper.selectPage(page, borrowInfoLambdaQueryWrapper));
-    }
-
-    @Override
-    public AjaxResult add(BorrowInfo borrowInfo) {
-        int insert = borrowInfoMapper.insert(borrowInfo);
-        if(insert > 0){
-            // 娣诲姞鎴愬姛锛岃繘鍏ユ敹鍏ョ鐞�
-            AccountIncome accountIncome = new AccountIncome();
-            accountIncome.setBusinessId(borrowInfo.getId());
-            accountIncome.setBusinessType(2);
-            accountIncome.setIncomeDate(DateUtils.toDate(borrowInfo.getBorrowDate()));
-            accountIncome.setIncomeType("2");
-            accountIncome.setIncomeMoney(borrowInfo.getBorrowAmount());
-            accountIncome.setIncomeDescribed("鍊熸");
-            accountIncome.setIncomeMethod("3");
-            accountIncome.setInputTime(DateUtils.getNowDate());
-            accountIncome.setInputUser(borrowInfo.getBorrowerName());
-            accountIncomeService.save(accountIncome);
-            return AjaxResult.success("娣诲姞鎴愬姛");
-        }
-        return AjaxResult.success("娣诲姞澶辫触");
-    }
-
-    @Override
-    public AjaxResult updateBorrowInfo(BorrowInfo borrowInfo) {
-        int update = borrowInfoMapper.updateById(borrowInfo);
-        if(update > 0){
-            // 淇敼鎴愬姛锛屼慨鏀规敹鍏ョ鐞�
-            AccountIncome one = accountIncomeService.getOne(new LambdaQueryWrapper<AccountIncome>()
-                    .eq(AccountIncome::getBusinessId, borrowInfo.getId())
-                    .eq(AccountIncome::getBusinessType, 2)
-                    .last("limit 1"));
-            if(one != null){
-                one.setIncomeMoney(borrowInfo.getBorrowAmount());
-                accountIncomeService.updateById(one);
-            }
-            // 鏄惁涓鸿繕娆�
-            if(borrowInfo.getStatus() != null && borrowInfo.getStatus() == 2){
-                // 鏂板鏀嚭璁板綍
-                AccountExpense accountExpense = new AccountExpense();
-                accountExpense.setBusinessId(borrowInfo.getId());
-                accountExpense.setBusinessType(2);
-                accountExpense.setExpenseDate(DateUtils.toDate(borrowInfo.getRepayDate()));
-                accountExpense.setExpenseType("5");
-                accountExpense.setExpenseMoney(borrowInfo.getBorrowAmount());
-                accountExpense.setExpenseDescribed("杩樻");
-                accountExpense.setExpenseMethod("3");
-                accountExpense.setInputTime(DateUtils.getNowDate());
-                accountExpense.setInputUser(borrowInfo.getBorrowerName());
-                accountExpenseService.save(accountExpense);
-            }
-            return AjaxResult.success("淇敼鎴愬姛");
-        }
-        return  AjaxResult.success("淇敼澶辫触");
-    }
-
-    @Override
-    public AjaxResult delete(List<Long> ids) {
-        int delete = borrowInfoMapper.deleteBatchIds(ids);
-        if(delete > 0){
-            // 鍒犻櫎鎴愬姛锛屽垹闄ゆ敹鍏ョ鐞�
-            accountIncomeService.remove(new LambdaQueryWrapper<AccountIncome>()
-                    .in(AccountIncome::getBusinessId, ids)
-                    .eq(AccountIncome::getBusinessType, 2));
-            // 鍒犻櫎鏀嚭绠$悊
-            accountExpenseService.remove(new LambdaQueryWrapper<AccountExpense>()
-                    .in(AccountExpense::getBusinessId, ids)
-                    .eq(AccountExpense::getBusinessType, 2));
-            return AjaxResult.success("鍒犻櫎鎴愬姛");
-        }
-        return  AjaxResult.success("鍒犻櫎澶辫触");
-    }
-}
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountSubjectServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/financial/AccountSubjectServiceImpl.java
similarity index 97%
rename from src/main/java/com/ruoyi/account/service/impl/AccountSubjectServiceImpl.java
rename to src/main/java/com/ruoyi/account/service/impl/financial/AccountSubjectServiceImpl.java
index 37bf64b..a6c4149 100644
--- a/src/main/java/com/ruoyi/account/service/impl/AccountSubjectServiceImpl.java
+++ b/src/main/java/com/ruoyi/account/service/impl/financial/AccountSubjectServiceImpl.java
@@ -1,15 +1,15 @@
-package com.ruoyi.account.service.impl;
+package com.ruoyi.account.service.impl.financial;
 
 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.account.bean.dto.AccountSubjectDto;
-import com.ruoyi.account.bean.dto.AccountSubjectImportDto;
-import com.ruoyi.account.bean.vo.AccountSubjectVo;
-import com.ruoyi.account.mapper.AccountSubjectMapper;
-import com.ruoyi.account.pojo.AccountSubject;
-import com.ruoyi.account.service.AccountSubjectService;
+import com.ruoyi.account.bean.dto.financial.AccountSubjectDto;
+import com.ruoyi.account.bean.dto.financial.AccountSubjectImportDto;
+import com.ruoyi.account.bean.vo.financial.AccountSubjectVo;
+import com.ruoyi.account.mapper.financial.AccountSubjectMapper;
+import com.ruoyi.account.pojo.financial.AccountSubject;
+import com.ruoyi.account.service.purchase.AccountSubjectService;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
diff --git a/src/main/java/com/ruoyi/account/service/impl/financial/FinVoucherServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/financial/FinVoucherServiceImpl.java
index b7548ef..6859b52 100644
--- a/src/main/java/com/ruoyi/account/service/impl/financial/FinVoucherServiceImpl.java
+++ b/src/main/java/com/ruoyi/account/service/impl/financial/FinVoucherServiceImpl.java
@@ -8,10 +8,10 @@
 import com.ruoyi.account.bean.dto.financial.FinVoucherEntryDto;
 import com.ruoyi.account.bean.dto.financial.FinVoucherPageDto;
 import com.ruoyi.account.bean.vo.financial.FinVoucherDetailVo;
-import com.ruoyi.account.mapper.AccountSubjectMapper;
+import com.ruoyi.account.mapper.financial.AccountSubjectMapper;
 import com.ruoyi.account.mapper.financial.FinVoucherEntryMapper;
 import com.ruoyi.account.mapper.financial.FinVoucherMapper;
-import com.ruoyi.account.pojo.AccountSubject;
+import com.ruoyi.account.pojo.financial.AccountSubject;
 import com.ruoyi.account.pojo.financial.FinVoucher;
 import com.ruoyi.account.pojo.financial.FinVoucherEntry;
 import com.ruoyi.account.service.financial.FinVoucherService;
diff --git a/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPaymentApplicationServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPaymentApplicationServiceImpl.java
new file mode 100644
index 0000000..9eecc49
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPaymentApplicationServiceImpl.java
@@ -0,0 +1,96 @@
+package com.ruoyi.account.service.impl.purchase;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+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.account.bean.dto.purchase.AccountPaymentApplicationDto;
+import com.ruoyi.account.bean.vo.purchase.AccountPaymentApplicationVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.mapper.purchase.AccountPaymentApplicationMapper;
+import com.ruoyi.account.mapper.purchase.AccountPurchasePaymentMapper;
+import com.ruoyi.account.pojo.purchase.AccountPaymentApplication;
+import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
+import com.ruoyi.account.service.purchase.AccountPaymentApplicationService;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--浠樻鐢宠 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 03:44:22
+ */
+@Service
+@RequiredArgsConstructor
+public class AccountPaymentApplicationServiceImpl extends ServiceImpl<AccountPaymentApplicationMapper, AccountPaymentApplication> implements AccountPaymentApplicationService {
+
+    private final AccountPaymentApplicationMapper accountPaymentApplicationMapper;
+    private final AccountPurchasePaymentMapper accountPurchasePaymentMapper;
+    private static final DateTimeFormatter CODE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyMMddHHmmss");
+
+    @Override
+    public IPage<AccountPaymentApplicationVo> listPageAccountPaymentApplication(Page page, AccountPaymentApplicationDto accountPaymentApplicationDto) {
+        return accountPaymentApplicationMapper.listPageAccountPaymentApplication(page, accountPaymentApplicationDto);
+    }
+
+    @Override
+    public List<PurchaseInboundVo> getInboundBatchesBySupplier(Integer supplierId) {
+        return accountPaymentApplicationMapper.getInboundBatchesBySupplier(supplierId);
+    }
+
+    @Override
+    public boolean addAccountPaymentApplication(AccountPaymentApplication accountPaymentApplication) {
+        if (StringUtils.isEmpty(accountPaymentApplication.getInvoiceApplicationNo())) {
+            accountPaymentApplication.setInvoiceApplicationNo(genPaymentApplicationNo());
+        }
+        String stockInRecordIds= accountPaymentApplication.getStockInRecordIds();
+        if (stockInRecordIds != null && !stockInRecordIds.isEmpty()) {
+            List<Long> ids = Arrays.stream(stockInRecordIds.split(","))
+                    .map(Long::valueOf)
+                    .toList();
+            if (accountPaymentApplicationMapper.existsByStockInRecordId(ids)){
+                throw new ServiceException("瀛樺湪閲嶅鐨勫叆搴撳崟");
+            }
+        }
+        return save(accountPaymentApplication);
+    }
+
+    @Override
+    public boolean deleteAccountPaymentApplication(List<Long> ids) {
+        if (ids == null || ids.isEmpty()) {
+            throw new ServiceException("鍒犻櫎澶辫触锛岃閫夋嫨瑕佸垹闄ょ殑鏁版嵁");
+        }
+        //鍒ゆ柇鏄惁宸茬粡鏈夊搴旂殑浠樻鍗�,濡傛灉鏈夊垯鏃犳硶鍒犻櫎
+        List<AccountPurchasePayment> accountPurchasePayments = accountPurchasePaymentMapper.selectList(Wrappers.<AccountPurchasePayment>lambdaQuery().in(AccountPurchasePayment::getAccountPaymentApplicationId, ids));
+        if (CollectionUtils.isNotEmpty(accountPurchasePayments)){
+            throw new ServiceException("鍒犻櫎澶辫触锛屽凡缁忔湁鍏宠仈鐨勪粯娆惧崟");
+        }
+        //鍒犻櫎寮�绁ㄧ敵璇�
+        return removeBatchByIds(ids);
+    }
+
+    @Override
+    public void exportAccountPaymentApplication(HttpServletResponse response, AccountPaymentApplicationDto accountPaymentApplicationDto) {
+        List<AccountPaymentApplicationVo> list = accountPaymentApplicationMapper.listPageAccountPaymentApplication(new Page(1,-1),accountPaymentApplicationDto).getRecords();
+        ExcelUtil<AccountPaymentApplicationVo> util = new ExcelUtil<>(AccountPaymentApplicationVo.class);
+        util.exportExcel(response, list , "浠樻鐢宠");
+    }
+
+    private String genPaymentApplicationNo() {
+        return "FK" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10);
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchaseInvoiceServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchaseInvoiceServiceImpl.java
new file mode 100644
index 0000000..5ca2efe
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchaseInvoiceServiceImpl.java
@@ -0,0 +1,59 @@
+package com.ruoyi.account.service.impl.purchase;
+
+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.account.bean.dto.purchase.AccountPurchaseInvoiceDto;
+import com.ruoyi.account.bean.vo.purchase.AccountPurchaseInvoiceVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.mapper.purchase.AccountPurchaseInvoiceMapper;
+import com.ruoyi.account.pojo.purchase.AccountPurchaseInvoice;
+import com.ruoyi.account.service.purchase.AccountPurchaseInvoiceService;
+import com.ruoyi.basic.mapper.StorageAttachmentMapper;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--杩涢」鍙戠エ 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 03:06:17
+ */
+@Service
+@RequiredArgsConstructor
+public class AccountPurchaseInvoiceServiceImpl extends ServiceImpl<AccountPurchaseInvoiceMapper, AccountPurchaseInvoice> implements AccountPurchaseInvoiceService {
+
+    private final AccountPurchaseInvoiceMapper accountPurchaseInvoiceMapper;
+    private final StorageAttachmentMapper storageAttachmentMapper;
+
+    @Override
+    public IPage<AccountPurchaseInvoiceVo> listPageAccountPurchaseInvoice(Page page, AccountPurchaseInvoiceDto accountPurchaseInvoiceDto) {
+        return accountPurchaseInvoiceMapper.listPageAccountPurchaseInvoice(page, accountPurchaseInvoiceDto);
+    }
+
+    @Override
+    public boolean deleteAccountPurchaseInvoice(List<Long> ids) {
+        List<AccountPurchaseInvoice> accountPurchaseInvoices = accountPurchaseInvoiceMapper.selectByIds(ids);
+        //鍒犻櫎闄勪欢
+        storageAttachmentMapper.deleteBatchIds(accountPurchaseInvoices.stream().map(AccountPurchaseInvoice::getStorageAttachmentId).toList());
+        return removeBatchByIds(ids);
+    }
+
+    @Override
+    public void exportAccountPurchaseInvoice(HttpServletResponse response, AccountPurchaseInvoiceDto accountPurchaseInvoiceDto) {
+        List<AccountPurchaseInvoiceVo> list = accountPurchaseInvoiceMapper.listPageAccountPurchaseInvoice(new Page(1,-1),accountPurchaseInvoiceDto).getRecords();
+        ExcelUtil<AccountPurchaseInvoiceVo> util = new ExcelUtil<>(AccountPurchaseInvoiceVo.class);
+        util.exportExcel(response, list , "杩涢」鍙戠エ");
+    }
+
+    @Override
+    public List<PurchaseInboundVo> getInboundBatchesBySupplier(Integer supplierId) {
+        return accountPurchaseInvoiceMapper.getInboundBatchesBySupplier(supplierId);
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java
new file mode 100644
index 0000000..b9953a0
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java
@@ -0,0 +1,90 @@
+package com.ruoyi.account.service.impl.purchase;
+
+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.github.xiaoymin.knife4j.core.util.CollectionUtils;
+import com.ruoyi.account.bean.dto.purchase.AccountPurchasePaymentDto;
+import com.ruoyi.account.bean.vo.purchase.AccountPurchasePaymentVo;
+import com.ruoyi.account.mapper.AccountStatementDetailsMapper;
+import com.ruoyi.account.mapper.purchase.AccountPaymentApplicationMapper;
+import com.ruoyi.account.mapper.purchase.AccountPurchasePaymentMapper;
+import com.ruoyi.account.pojo.AccountStatementDetails;
+import com.ruoyi.account.pojo.purchase.AccountPaymentApplication;
+import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
+import com.ruoyi.account.service.purchase.AccountPurchasePaymentService;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--浠樻鍗� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 04:14:51
+ */
+@Service
+@RequiredArgsConstructor
+public class AccountPurchasePaymentServiceImpl extends ServiceImpl<AccountPurchasePaymentMapper, AccountPurchasePayment> implements AccountPurchasePaymentService {
+
+    private static final DateTimeFormatter CODE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyMMddHHmmss");
+    private final AccountPurchasePaymentMapper accountPurchasePaymentMapper;
+    private final AccountStatementDetailsMapper accountStatementDetailsMapper;
+    private final AccountPaymentApplicationMapper accountPaymentApplicationMapper;
+
+    @Override
+    public IPage<AccountPurchasePaymentVo> listPageAccountPurchasePayment(Page page, AccountPurchasePaymentDto accountPurchasePaymentDto) {
+        return accountPurchasePaymentMapper.listPageAccountPurchasePayment(page, accountPurchasePaymentDto);
+    }
+
+    @Override
+    public boolean addAccountPurchasePayment(AccountPurchasePayment accountPurchasePayment) {
+        if (StringUtils.isEmpty(accountPurchasePayment.getPaymentNumber())) {
+            accountPurchasePayment.setPaymentNumber(genAccountPurchasePaymentNo());
+        }
+        //鏍¢獙绱浠樻閲戦涓嶈兘瓒呰繃鐢宠閲戦
+        AccountPaymentApplication accountPaymentApplication = accountPaymentApplicationMapper.selectById(accountPurchasePayment.getAccountPaymentApplicationId());
+        List<AccountPurchasePayment> accountPurchasePayments = accountPurchasePaymentMapper.selectList(Wrappers.<AccountPurchasePayment>lambdaQuery().eq(AccountPurchasePayment::getAccountPaymentApplicationId, accountPurchasePayment.getAccountPaymentApplicationId()));
+        BigDecimal totalPaymentAmount = accountPurchasePayments.stream().map(AccountPurchasePayment::getPaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
+        if (accountPaymentApplication.getPaymentAmount().compareTo(totalPaymentAmount) < 0) {
+            throw new ServiceException("绱浠樻閲戦涓嶈兘瓒呰繃鐢宠閲戦");
+        }
+        return save(accountPurchasePayment);
+    }
+
+    @Override
+    public void exportAccountPurchasePayment(HttpServletResponse response, AccountPurchasePaymentDto accountPurchasePaymentDto) {
+        List<AccountPurchasePaymentVo> list = accountPurchasePaymentMapper.listPageAccountPurchasePayment(new Page(1,-1),accountPurchasePaymentDto).getRecords();
+        ExcelUtil<AccountPurchasePaymentVo> util = new ExcelUtil<>(AccountPurchasePaymentVo.class);
+        util.exportExcel(response, list , "浠樻鍗�");
+    }
+
+    @Override
+    public boolean deleteAccountPurchasePayment(List<Long> ids) {
+        //濡傛灉璇ヤ粯娆惧崟宸茬粡鐢熸垚瀵硅处鍗曞垯鏃犳硶鍒犻櫎
+        List<AccountPurchasePayment> accountPurchasePayments = accountPurchasePaymentMapper.selectByIds(ids);
+        List<String> strings = accountPurchasePayments.stream().map(AccountPurchasePayment::getPaymentNumber).toList();
+        List<AccountStatementDetails> accountStatementDetails = accountStatementDetailsMapper.selectList(Wrappers.<AccountStatementDetails>lambdaQuery()
+                .in(AccountStatementDetails::getReceiptNumber, strings));
+        if (CollectionUtils.isNotEmpty(accountStatementDetails)){
+            throw new ServiceException("璇ヤ粯娆惧崟宸茬粡鐢熸垚瀵硅处鍗曪紝鏃犳硶鍒犻櫎");
+        }
+        return removeByIds(ids);
+    }
+
+    private String genAccountPurchasePaymentNo() {
+        return "SK" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10);
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountPurchaseServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchaseServiceImpl.java
similarity index 85%
rename from src/main/java/com/ruoyi/account/service/impl/AccountPurchaseServiceImpl.java
rename to src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchaseServiceImpl.java
index 747f6cf..9547d05 100644
--- a/src/main/java/com/ruoyi/account/service/impl/AccountPurchaseServiceImpl.java
+++ b/src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchaseServiceImpl.java
@@ -1,12 +1,12 @@
-package com.ruoyi.account.service.impl;
+package com.ruoyi.account.service.impl.purchase;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.bean.dto.PurchaseInboundDto;
-import com.ruoyi.account.bean.dto.PurchaseReturnDto;
-import com.ruoyi.account.bean.vo.PurchaseInboundVo;
-import com.ruoyi.account.bean.vo.PurchaseReturnVo;
-import com.ruoyi.account.service.AccountPurchaseService;
+import com.ruoyi.account.bean.dto.purchase.PurchaseInboundDto;
+import com.ruoyi.account.bean.dto.purchase.PurchaseReturnDto;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseReturnVo;
+import com.ruoyi.account.service.financial.AccountPurchaseService;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper;
 import com.ruoyi.stock.mapper.StockInRecordMapper;
diff --git a/src/main/java/com/ruoyi/account/service/impl/sales/AccountInvoiceApplicationServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/sales/AccountInvoiceApplicationServiceImpl.java
new file mode 100644
index 0000000..74cec42
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/sales/AccountInvoiceApplicationServiceImpl.java
@@ -0,0 +1,97 @@
+package com.ruoyi.account.service.impl.sales;
+
+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.account.bean.dto.sales.AccountInvoiceApplicationDto;
+import com.ruoyi.account.bean.vo.sales.AccountInvoiceApplicationVo;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.mapper.sales.AccountInvoiceApplicationMapper;
+import com.ruoyi.account.mapper.sales.AccountSalesInvoiceMapper;
+import com.ruoyi.account.pojo.sales.AccountInvoiceApplication;
+import com.ruoyi.account.pojo.sales.AccountSalesInvoice;
+import com.ruoyi.account.service.sales.AccountInvoiceApplicationService;
+import com.ruoyi.basic.mapper.StorageAttachmentMapper;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--寮�绁ㄧ敵璇� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 01:38:32
+ */
+@Service
+@RequiredArgsConstructor
+public class AccountInvoiceApplicationServiceImpl extends ServiceImpl<AccountInvoiceApplicationMapper, AccountInvoiceApplication> implements AccountInvoiceApplicationService {
+
+    private final AccountInvoiceApplicationMapper accountInvoiceApplicationMapper;
+    private final AccountSalesInvoiceMapper accountSalesInvoiceMapper;
+    private final StorageAttachmentMapper storageAttachmentMapper;
+    private static final DateTimeFormatter CODE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyMMddHHmmss");
+
+    @Override
+    public IPage<AccountInvoiceApplicationVo> listPageAccountInvoiceApplication(Page page, AccountInvoiceApplicationDto accountInvoiceApplicationDto) {
+        return accountInvoiceApplicationMapper.listPageAccountInvoiceApplication(page, accountInvoiceApplicationDto);
+    }
+
+    @Override
+    public List<SalesOutboundVo> getOutboundBatchesByCustomer(Integer customerId) {
+        return accountInvoiceApplicationMapper.getOutboundBatchesByCustomer(customerId);
+    }
+
+    @Override
+    public boolean addAccountInvoiceApplication(AccountInvoiceApplication accountInvoiceApplication) {
+        if (StringUtils.isEmpty(accountInvoiceApplication.getInvoiceApplicationNo())) {
+            accountInvoiceApplication.setInvoiceApplicationNo(genInvoiceApplicationNo());
+        }
+        String stockOutRecordIds = accountInvoiceApplication.getStockOutRecordIds();
+        if (stockOutRecordIds != null && !stockOutRecordIds.isEmpty()) {
+            List<Long> ids = Arrays.stream(stockOutRecordIds.split(","))
+                    .map(Long::valueOf)
+                    .toList();
+            if (accountInvoiceApplicationMapper.existsByStockOutRecordId(ids)){
+                throw new ServiceException("瀛樺湪閲嶅鐨勫嚭搴撳崟");
+            }
+        }
+        return save(accountInvoiceApplication);
+    }
+
+    @Override
+    public void exportAccountInvoiceApplication(HttpServletResponse response, AccountInvoiceApplicationDto accountInvoiceApplicationDto) {
+        List<AccountInvoiceApplicationVo> list = accountInvoiceApplicationMapper.listPageAccountInvoiceApplication(new Page(1,-1),accountInvoiceApplicationDto).getRecords();
+        ExcelUtil<AccountInvoiceApplicationVo> util = new ExcelUtil<>(AccountInvoiceApplicationVo.class);
+        util.exportExcel(response, list , "寮�绁ㄧ敵璇�");
+    }
+
+    @Override
+    public boolean deleteAccountInvoiceApplication(List<Long> ids) {
+        if (ids == null || ids.isEmpty()) {
+            throw new ServiceException("鍒犻櫎澶辫触锛岃閫夋嫨瑕佸垹闄ょ殑鏁版嵁");
+        }
+        //鍒犻櫎鐩稿叧闄勪欢
+        List<AccountSalesInvoice> accountSalesInvoices = accountSalesInvoiceMapper.selectList(Wrappers.<AccountSalesInvoice>lambdaQuery().in(AccountSalesInvoice::getAccountInvoiceApplicationId,ids));
+        storageAttachmentMapper.deleteBatchIds(accountSalesInvoices.stream().map(AccountSalesInvoice::getStorageAttachmentId).toList());
+        //鍒犻櫎鐩稿叧鐨勯攢椤瑰彂绁�
+        accountSalesInvoiceMapper.delete(Wrappers.<AccountSalesInvoice>lambdaQuery().in(AccountSalesInvoice::getAccountInvoiceApplicationId,ids));
+        //鍒犻櫎寮�绁ㄧ敵璇�
+        return removeBatchByIds(ids);
+    }
+
+    private String genInvoiceApplicationNo() {
+        return "KP" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10);
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java
new file mode 100644
index 0000000..5f328bc
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java
@@ -0,0 +1,96 @@
+package com.ruoyi.account.service.impl.sales;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+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.account.bean.dto.sales.AccountSalesCollectionDto;
+import com.ruoyi.account.bean.vo.sales.AccountSalesCollectionVo;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.mapper.AccountStatementDetailsMapper;
+import com.ruoyi.account.mapper.sales.AccountSalesCollectionMapper;
+import com.ruoyi.account.pojo.AccountStatementDetails;
+import com.ruoyi.account.pojo.sales.AccountSalesCollection;
+import com.ruoyi.account.service.sales.AccountSalesCollectionService;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--鏀舵鍗� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 03:49:56
+ */
+@Service
+@RequiredArgsConstructor
+public class AccountSalesCollectionServiceImpl extends ServiceImpl<AccountSalesCollectionMapper, AccountSalesCollection> implements AccountSalesCollectionService {
+
+    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
+    private final AccountStatementDetailsMapper accountStatementDetailsMapper;
+    private static final DateTimeFormatter CODE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyMMddHHmmss");
+
+
+    @Override
+    public IPage<AccountSalesCollectionVo> listPageAccountSalesCollection(Page page, AccountSalesCollectionDto accountSalesCollectionDto) {
+        return accountSalesCollectionMapper.listPageAccountSalesCollection(page, accountSalesCollectionDto);
+    }
+
+    @Override
+    public boolean addAccountSalesCollection(AccountSalesCollection accountSalesCollection) {
+        if (StringUtils.isEmpty(accountSalesCollection.getCollectionNumber())) {
+            accountSalesCollection.setCollectionNumber(genAccountSalesCollectionNo());
+        }
+        String stockOutRecordIds = accountSalesCollection.getStockOutRecordIds();
+        if (stockOutRecordIds != null && !stockOutRecordIds.isEmpty()) {
+            List<Long> ids = Arrays.stream(stockOutRecordIds.split(","))
+                    .map(Long::valueOf)
+                    .toList();
+            if (accountSalesCollectionMapper.existsByStockOutRecordId(ids)){
+                throw new ServiceException("瀛樺湪閲嶅鐨勫嚭搴撳崟");
+            }
+        }
+        return save(accountSalesCollection);
+    }
+
+    @Override
+    public void exportAccountSalesCollection(HttpServletResponse response, AccountSalesCollectionDto accountSalesCollectionDto) {
+        List<AccountSalesCollectionVo> list = accountSalesCollectionMapper.listPageAccountSalesCollection(new Page(1,-1),accountSalesCollectionDto).getRecords();
+        ExcelUtil<AccountSalesCollectionVo> util = new ExcelUtil<>(AccountSalesCollectionVo.class);
+        util.exportExcel(response, list , "鏀舵鍗�");
+    }
+
+    @Override
+    public boolean deleteAccountSalesCollection(List<Long> ids) {
+        //濡傛灉璇ユ敹娆惧崟宸茬粡鐢熸垚瀵硅处鍗曞垯鏃犳硶鍒犻櫎
+        List<AccountSalesCollection> accountSalesCollections = accountSalesCollectionMapper.selectByIds(ids);
+        List<String> strings = accountSalesCollections.stream().map(AccountSalesCollection::getCollectionNumber).toList();
+        List<AccountStatementDetails> accountStatementDetails = accountStatementDetailsMapper.selectList(Wrappers.<AccountStatementDetails>lambdaQuery()
+                .in(AccountStatementDetails::getReceiptNumber, strings));
+        if (CollectionUtils.isNotEmpty(accountStatementDetails)){
+            throw new ServiceException("璇ユ敹娆惧崟宸茬粡鐢熸垚瀵硅处鍗曪紝鏃犳硶鍒犻櫎");
+        }
+        return removeByIds(ids);
+    }
+
+    @Override
+    public List<SalesOutboundVo> getOutboundBatchesByCustomer(Integer customerId) {
+        return accountSalesCollectionMapper.getOutboundBatchesByCustomer(customerId);
+    }
+
+    private String genAccountSalesCollectionNo() {
+        return "SK" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10);
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesInvoiceServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesInvoiceServiceImpl.java
new file mode 100644
index 0000000..b2fe7e3
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesInvoiceServiceImpl.java
@@ -0,0 +1,53 @@
+package com.ruoyi.account.service.impl.sales;
+
+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.account.bean.dto.sales.AccountSalesInvoiceDto;
+import com.ruoyi.account.bean.vo.sales.AccountSalesInvoiceVo;
+import com.ruoyi.account.mapper.sales.AccountSalesInvoiceMapper;
+import com.ruoyi.account.pojo.sales.AccountSalesInvoice;
+import com.ruoyi.account.service.sales.AccountSalesInvoiceService;
+import com.ruoyi.basic.mapper.StorageAttachmentMapper;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--閿�椤瑰彂绁� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 03:10:20
+ */
+@Service
+@RequiredArgsConstructor
+public class AccountSalesInvoiceServiceImpl extends ServiceImpl<AccountSalesInvoiceMapper, AccountSalesInvoice> implements AccountSalesInvoiceService {
+
+    private final AccountSalesInvoiceMapper accountSalesInvoiceMapper;
+    private final StorageAttachmentMapper storageAttachmentMapper;
+
+    @Override
+    public IPage<AccountSalesInvoiceVo> listPageAccountSalesInvoice(Page page, AccountSalesInvoiceDto accountSalesInvoiceDto) {
+        return accountSalesInvoiceMapper.listPageAccountSalesInvoice(page, accountSalesInvoiceDto);
+    }
+
+    @Override
+    public void exportAccountSalesInvoice(HttpServletResponse response, AccountSalesInvoiceDto accountSalesInvoiceDto) {
+        List<AccountSalesInvoiceVo> list = accountSalesInvoiceMapper.listPageAccountSalesInvoice(new Page(1,-1),accountSalesInvoiceDto).getRecords();
+        ExcelUtil<AccountSalesInvoiceVo> util = new ExcelUtil<>(AccountSalesInvoiceVo.class);
+        util.exportExcel(response, list , "閿�椤瑰彂绁�");
+    }
+
+    @Override
+    public boolean deleteAccountSalesInvoice(List<Long> ids) {
+        List<AccountSalesInvoice> accountSalesInvoices = accountSalesInvoiceMapper.selectByIds(ids);
+        //鍒犻櫎闄勪欢
+        storageAttachmentMapper.deleteBatchIds(accountSalesInvoices.stream().map(AccountSalesInvoice::getStorageAttachmentId).toList());
+        return removeBatchByIds(ids);
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountSalesServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesServiceImpl.java
similarity index 85%
rename from src/main/java/com/ruoyi/account/service/impl/AccountSalesServiceImpl.java
rename to src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesServiceImpl.java
index ddf4a57..814d294 100644
--- a/src/main/java/com/ruoyi/account/service/impl/AccountSalesServiceImpl.java
+++ b/src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesServiceImpl.java
@@ -1,12 +1,12 @@
-package com.ruoyi.account.service.impl;
+package com.ruoyi.account.service.impl.sales;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.bean.dto.SalesOutboundDto;
-import com.ruoyi.account.bean.dto.SalesReturnDto;
-import com.ruoyi.account.bean.vo.SalesOutboundVo;
-import com.ruoyi.account.bean.vo.SalesReturnVo;
-import com.ruoyi.account.service.AccountSalesService;
+import com.ruoyi.account.bean.dto.sales.SalesOutboundDto;
+import com.ruoyi.account.bean.dto.sales.SalesReturnDto;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.bean.vo.sales.SalesReturnVo;
+import com.ruoyi.account.service.sales.AccountSalesService;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.procurementrecord.mapper.ReturnManagementMapper;
 import com.ruoyi.stock.mapper.StockOutRecordMapper;
diff --git a/src/main/java/com/ruoyi/account/service/purchase/AccountPaymentApplicationService.java b/src/main/java/com/ruoyi/account/service/purchase/AccountPaymentApplicationService.java
new file mode 100644
index 0000000..c2c5c66
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/purchase/AccountPaymentApplicationService.java
@@ -0,0 +1,33 @@
+package com.ruoyi.account.service.purchase;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.account.bean.dto.purchase.AccountPaymentApplicationDto;
+import com.ruoyi.account.bean.vo.purchase.AccountPaymentApplicationVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.pojo.purchase.AccountPaymentApplication;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--浠樻鐢宠 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 03:44:22
+ */
+public interface AccountPaymentApplicationService extends IService<AccountPaymentApplication> {
+
+    IPage<AccountPaymentApplicationVo> listPageAccountPaymentApplication(Page page, AccountPaymentApplicationDto accountPaymentApplicationDto);
+
+    List<PurchaseInboundVo> getInboundBatchesBySupplier(Integer supplierId);
+
+    boolean addAccountPaymentApplication(AccountPaymentApplication accountPaymentApplication);
+
+    boolean deleteAccountPaymentApplication(List<Long> ids);
+
+    void exportAccountPaymentApplication(HttpServletResponse response, AccountPaymentApplicationDto accountPaymentApplicationDto);
+}
diff --git a/src/main/java/com/ruoyi/account/service/purchase/AccountPurchaseInvoiceService.java b/src/main/java/com/ruoyi/account/service/purchase/AccountPurchaseInvoiceService.java
new file mode 100644
index 0000000..d799c5e
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/purchase/AccountPurchaseInvoiceService.java
@@ -0,0 +1,31 @@
+package com.ruoyi.account.service.purchase;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.purchase.AccountPurchaseInvoiceDto;
+import com.ruoyi.account.bean.vo.purchase.AccountPurchaseInvoiceVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.pojo.purchase.AccountPurchaseInvoice;
+import com.baomidou.mybatisplus.extension.service.IService;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--杩涢」鍙戠エ 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 03:06:17
+ */
+public interface AccountPurchaseInvoiceService extends IService<AccountPurchaseInvoice> {
+
+    IPage<AccountPurchaseInvoiceVo> listPageAccountPurchaseInvoice(Page page, AccountPurchaseInvoiceDto accountPurchaseInvoiceDto);
+
+    boolean deleteAccountPurchaseInvoice(List<Long> ids);
+
+    void exportAccountPurchaseInvoice(HttpServletResponse response, AccountPurchaseInvoiceDto accountPurchaseInvoiceDto);
+
+    List<PurchaseInboundVo> getInboundBatchesBySupplier(Integer supplierId);
+}
diff --git a/src/main/java/com/ruoyi/account/service/purchase/AccountPurchasePaymentService.java b/src/main/java/com/ruoyi/account/service/purchase/AccountPurchasePaymentService.java
new file mode 100644
index 0000000..018a497
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/purchase/AccountPurchasePaymentService.java
@@ -0,0 +1,30 @@
+package com.ruoyi.account.service.purchase;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.purchase.AccountPurchasePaymentDto;
+import com.ruoyi.account.bean.vo.purchase.AccountPurchasePaymentVo;
+import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
+import com.baomidou.mybatisplus.extension.service.IService;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--浠樻鍗� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-19 04:14:51
+ */
+public interface AccountPurchasePaymentService extends IService<AccountPurchasePayment> {
+
+    IPage<AccountPurchasePaymentVo> listPageAccountPurchasePayment(Page page, AccountPurchasePaymentDto accountPurchasePaymentDto);
+
+    boolean addAccountPurchasePayment(AccountPurchasePayment accountPurchasePayment);
+
+    void exportAccountPurchasePayment(HttpServletResponse response, AccountPurchasePaymentDto accountPurchasePaymentDto);
+
+    boolean deleteAccountPurchasePayment(List<Long> ids);
+}
diff --git a/src/main/java/com/ruoyi/account/service/AccountSubjectService.java b/src/main/java/com/ruoyi/account/service/purchase/AccountSubjectService.java
similarity index 78%
rename from src/main/java/com/ruoyi/account/service/AccountSubjectService.java
rename to src/main/java/com/ruoyi/account/service/purchase/AccountSubjectService.java
index bcbc57c..51d44ec 100644
--- a/src/main/java/com/ruoyi/account/service/AccountSubjectService.java
+++ b/src/main/java/com/ruoyi/account/service/purchase/AccountSubjectService.java
@@ -1,10 +1,10 @@
-package com.ruoyi.account.service;
+package com.ruoyi.account.service.purchase;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.bean.dto.AccountSubjectDto;
-import com.ruoyi.account.bean.vo.AccountSubjectVo;
-import com.ruoyi.account.pojo.AccountSubject;
+import com.ruoyi.account.bean.dto.financial.AccountSubjectDto;
+import com.ruoyi.account.bean.vo.financial.AccountSubjectVo;
+import com.ruoyi.account.pojo.financial.AccountSubject;
 import com.baomidou.mybatisplus.extension.service.IService;
 import jakarta.servlet.http.HttpServletResponse;
 
diff --git a/src/main/java/com/ruoyi/account/service/sales/AccountInvoiceApplicationService.java b/src/main/java/com/ruoyi/account/service/sales/AccountInvoiceApplicationService.java
new file mode 100644
index 0000000..7f55ba5
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/sales/AccountInvoiceApplicationService.java
@@ -0,0 +1,33 @@
+package com.ruoyi.account.service.sales;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.account.bean.dto.sales.AccountInvoiceApplicationDto;
+import com.ruoyi.account.bean.vo.sales.AccountInvoiceApplicationVo;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.pojo.sales.AccountInvoiceApplication;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--寮�绁ㄧ敵璇� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 01:38:32
+ */
+public interface AccountInvoiceApplicationService extends IService<AccountInvoiceApplication> {
+
+    IPage<AccountInvoiceApplicationVo> listPageAccountInvoiceApplication(Page page, AccountInvoiceApplicationDto accountInvoiceApplicationDto);
+
+    List<SalesOutboundVo> getOutboundBatchesByCustomer(Integer customerId);
+
+    boolean addAccountInvoiceApplication(AccountInvoiceApplication accountInvoiceApplication);
+
+    void exportAccountInvoiceApplication(HttpServletResponse response, AccountInvoiceApplicationDto accountInvoiceApplicationDto);
+
+    boolean deleteAccountInvoiceApplication(List<Long> ids);
+}
diff --git a/src/main/java/com/ruoyi/account/service/sales/AccountSalesCollectionService.java b/src/main/java/com/ruoyi/account/service/sales/AccountSalesCollectionService.java
new file mode 100644
index 0000000..d5172fb
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/sales/AccountSalesCollectionService.java
@@ -0,0 +1,33 @@
+package com.ruoyi.account.service.sales;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.sales.AccountSalesCollectionDto;
+import com.ruoyi.account.bean.vo.sales.AccountSalesCollectionVo;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.pojo.sales.AccountSalesCollection;
+import com.baomidou.mybatisplus.extension.service.IService;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--鏀舵鍗� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 03:49:56
+ */
+public interface AccountSalesCollectionService extends IService<AccountSalesCollection> {
+
+    IPage<AccountSalesCollectionVo> listPageAccountSalesCollection(Page page, AccountSalesCollectionDto accountSalesCollectionDto);
+
+    boolean addAccountSalesCollection(AccountSalesCollection accountSalesCollection);
+
+    void exportAccountSalesCollection(HttpServletResponse response, AccountSalesCollectionDto accountSalesCollectionDto);
+
+    boolean deleteAccountSalesCollection(List<Long> ids);
+
+    List<SalesOutboundVo> getOutboundBatchesByCustomer(Integer customerId);
+}
diff --git a/src/main/java/com/ruoyi/account/service/sales/AccountSalesInvoiceService.java b/src/main/java/com/ruoyi/account/service/sales/AccountSalesInvoiceService.java
new file mode 100644
index 0000000..1809177
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/sales/AccountSalesInvoiceService.java
@@ -0,0 +1,28 @@
+package com.ruoyi.account.service.sales;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.sales.AccountSalesInvoiceDto;
+import com.ruoyi.account.bean.vo.sales.AccountSalesInvoiceVo;
+import com.ruoyi.account.pojo.sales.AccountSalesInvoice;
+import com.baomidou.mybatisplus.extension.service.IService;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊--閿�椤瑰彂绁� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-18 03:10:20
+ */
+public interface AccountSalesInvoiceService extends IService<AccountSalesInvoice> {
+
+    IPage<AccountSalesInvoiceVo> listPageAccountSalesInvoice(Page page, AccountSalesInvoiceDto accountSalesInvoiceDto);
+
+    void exportAccountSalesInvoice(HttpServletResponse response, AccountSalesInvoiceDto accountSalesInvoiceDto);
+
+    boolean deleteAccountSalesInvoice(List<Long> ids);
+}
diff --git a/src/main/java/com/ruoyi/account/service/AccountSalesService.java b/src/main/java/com/ruoyi/account/service/sales/AccountSalesService.java
similarity index 73%
rename from src/main/java/com/ruoyi/account/service/AccountSalesService.java
rename to src/main/java/com/ruoyi/account/service/sales/AccountSalesService.java
index 7db5416..82f606c 100644
--- a/src/main/java/com/ruoyi/account/service/AccountSalesService.java
+++ b/src/main/java/com/ruoyi/account/service/sales/AccountSalesService.java
@@ -1,11 +1,11 @@
-package com.ruoyi.account.service;
+package com.ruoyi.account.service.sales;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.bean.dto.SalesOutboundDto;
-import com.ruoyi.account.bean.dto.SalesReturnDto;
-import com.ruoyi.account.bean.vo.SalesOutboundVo;
-import com.ruoyi.account.bean.vo.SalesReturnVo;
+import com.ruoyi.account.bean.dto.sales.SalesOutboundDto;
+import com.ruoyi.account.bean.dto.sales.SalesReturnDto;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.bean.vo.sales.SalesReturnVo;
 import jakarta.servlet.http.HttpServletResponse;
 
 /**
diff --git a/src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java b/src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java
index 3b37909..bad0e0a 100644
--- a/src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java
+++ b/src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java
@@ -3,6 +3,7 @@
 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;
 
@@ -16,5 +17,5 @@
 public interface ApproveTodoAgent {
 
     @SystemMessage(fromResource = "approve-todo-agent-prompt.txt")
-    Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage);
+    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
index 9f8499d..8d8ad45 100644
--- a/src/main/java/com/ruoyi/ai/assistant/ApproveTodoIntentExecutor.java
+++ b/src/main/java/com/ruoyi/ai/assistant/ApproveTodoIntentExecutor.java
@@ -14,8 +14,9 @@
 @Component
 public class ApproveTodoIntentExecutor {
 
-    private static final Pattern APPROVE_ID_PATTERN = Pattern.compile("\\b[A-Za-z]*\\d{8,}\\b");
-    private static final Pattern LIMIT_PATTERN = Pattern.compile("(鍓峾鏈�杩�)?(\\d{1,2})鏉�");
+    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+(澶﹟鍛▅涓湀|鏈坾骞�)");
@@ -34,54 +35,63 @@
         }
 
         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,
-                    extractStartDate(text),
-                    extractEndDate(text),
-                    extractTimeRange(text)
+                    startDate,
+                    endDate,
+                    timeRange
             );
         }
         if (containsAny(text, "娴佽浆", "杩涘害", "鑺傜偣", "鏃ュ織", "鍗″湪", "鍗″埌", "褰撳墠瀹℃壒浜�", "澶勭悊璁板綍")) {
-            return StringUtils.hasText(approveId)
+            return hasApproveId
                     ? approveTodoTools.getTodoProgress(memoryId, approveId)
                     : missingApproveId("todo_progress", "鏌ヨ瀹℃壒杩涘害闇�瑕佹彁渚涙祦绋嬬紪鍙枫��");
         }
         if (containsAny(text, "璇︽儏", "鏄庣粏") && !containsAny(text, "鍒楄〃")) {
-            return StringUtils.hasText(approveId)
+            return hasApproveId
                     ? approveTodoTools.getTodoDetail(memoryId, approveId)
                     : missingApproveId("todo_detail", "鏌ヨ瀹℃壒璇︽儏闇�瑕佹彁渚涙祦绋嬬紪鍙枫��");
         }
         if (containsAny(text, "鍙栨秷瀹℃牳", "鎾ら攢瀹℃牳", "鍥為��瀹℃牳", "鎾ら攢瀹℃壒", "鎾ゅ洖瀹℃壒")
                 || (containsAny(text, "鎾ら攢", "鎾ゅ洖") && containsAny(text, "瀹℃壒鎿嶄綔", "瀹℃牳鎿嶄綔"))) {
-            return StringUtils.hasText(approveId)
-                    ? approveTodoTools.cancelReviewTodo(memoryId, approveId, firstNonBlank(extractTail(text, "鍘熷洜"), extractTail(text, "澶囨敞")))
+            return hasApproveId
+                    ? approveTodoTools.cancelReviewTodo(memoryId, approveId, extractRemark(text))
                     : missingApproveId("cancel_review_action", "鍙栨秷瀹℃牳闇�瑕佹彁渚涙祦绋嬬紪鍙枫��");
         }
         if (containsAny(text, "鍒犻櫎", "绉婚櫎")) {
-            return StringUtils.hasText(approveId)
+            return hasApproveId
                     ? approveTodoTools.deleteTodo(memoryId, approveId)
                     : missingApproveId("delete_action", "鍒犻櫎瀹℃壒鍗曢渶瑕佹彁渚涙祦绋嬬紪鍙枫��");
         }
         if (containsAny(text, "椹冲洖", "鎷掔粷")) {
-            return StringUtils.hasText(approveId)
-                    ? approveTodoTools.reviewTodo(memoryId, approveId, "reject", firstNonBlank(extractTail(text, "鍘熷洜"), extractTail(text, "澶囨敞")))
+            return hasApproveId
+                    ? approveTodoTools.reviewTodo(memoryId, approveId, "reject", extractRemark(text))
                     : missingApproveId("review_action", "椹冲洖瀹℃壒闇�瑕佹彁渚涙祦绋嬬紪鍙枫��");
         }
         if (containsAny(text, "瀹℃牳閫氳繃", "瀹℃壒閫氳繃", "閫氳繃瀹℃壒", "鍚屾剰瀹℃壒", "瀹℃壒鍚屾剰")) {
-            return StringUtils.hasText(approveId)
-                    ? approveTodoTools.reviewTodo(memoryId, approveId, "approve", extractTail(text, "澶囨敞"))
+            return hasApproveId
+                    ? approveTodoTools.reviewTodo(memoryId, approveId, "approve", extractRemark(text))
                     : missingApproveId("review_action", "瀹℃壒閫氳繃闇�瑕佹彁渚涙祦绋嬬紪鍙枫��");
         }
-        if (StringUtils.hasText(approveId)
+        if (hasApproveId
                 && containsAny(text, "閫氳繃", "鍚屾剰")
                 && !containsAny(text, "鏈�氳繃", "閫氳繃鐜�", "瀹℃壒閫氳繃鐜�", "瀹℃牳閫氳繃鐜�")) {
-            return approveTodoTools.reviewTodo(memoryId, approveId, "approve", extractTail(text, "澶囨敞"));
+            return approveTodoTools.reviewTodo(memoryId, approveId, "approve", extractRemark(text));
         }
         if (containsAny(text, "淇敼", "鏇存柊", "鍙樻洿")) {
-            return StringUtils.hasText(approveId)
+            return hasApproveId
                     ? approveTodoTools.updateTodo(
                     memoryId,
                     approveId,
@@ -101,7 +111,82 @@
                     extractApproveType(text),
                     extractKeyword(text),
                     extractLimit(text),
-                    extractScope(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;
     }
@@ -130,6 +215,10 @@
     }
 
     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;
     }
@@ -196,6 +285,8 @@
                 .replace("鍗曟嵁", "")
                 .replace("寰呭姙", "")
                 .replace("鍒楄〃", "")
+                .replace("娴佺▼缂栧彿", "")
+                .replace("娴佺▼鍙�", "")
                 .replace("鍓�10鏉�", "")
                 .replace("鏈�杩�10鏉�", "")
                 .trim();
@@ -203,7 +294,7 @@
     }
 
     private String extractValue(String text, String fieldName) {
-        Pattern pattern = Pattern.compile(fieldName + "(鏀逛负|淇敼涓簗鏄�)[:锛歖?[\\s]*([^,锛屻�傦紱;\\s]+)");
+        Pattern pattern = Pattern.compile(fieldName + "(鏀逛负|淇敼涓簗涓簗鏄�)[:锛歖?[\\s]*([^,锛屻�傦紱;\\s]+)");
         Matcher matcher = pattern.matcher(text);
         return matcher.find() ? matcher.group(2) : null;
     }
@@ -250,7 +341,7 @@
         if (!text.contains(fieldName)) {
             return null;
         }
-        Matcher matcher = Pattern.compile(fieldName + "(鏀逛负|淇敼涓簗鏄�)[:锛歖?[\\s]*(\\d{1,2})").matcher(text);
+        Matcher matcher = Pattern.compile(fieldName + "(鏀逛负|淇敼涓簗涓簗鏄�)[:锛歖?[\\s]*(\\d{1,2})").matcher(text);
         return matcher.find() ? Integer.parseInt(matcher.group(2)) : null;
     }
 
@@ -264,21 +355,85 @@
     }
 
     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() ? matcher.group(2).trim() : null;
+        return matcher.find() ? cleanContent(matcher.group(2)) : null;
     }
 
     private String extractScope(String text) {
         if (containsAny(text, "鎴戝彂璧�", "鎴戞彁浜�", "鎴戠敵璇�", "鐢宠浜烘槸鎴�")) {
             return "applicant";
         }
-        if (containsAny(text, "寰呮垜瀹℃壒", "寰呮垜瀹℃牳", "鎴戝鐞�", "鎴戝鎵�", "褰撳墠寰呮垜", "闇�瑕佹垜澶勭悊")) {
+        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;
     }
diff --git a/src/main/java/com/ruoyi/ai/assistant/FinancialAgent.java b/src/main/java/com/ruoyi/ai/assistant/FinancialAgent.java
new file mode 100644
index 0000000..875b98d
--- /dev/null
+++ b/src/main/java/com/ruoyi/ai/assistant/FinancialAgent.java
@@ -0,0 +1,22 @@
+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
new file mode 100644
index 0000000..c1f349c
--- /dev/null
+++ b/src/main/java/com/ruoyi/ai/assistant/FinancialIntentExecutor.java
@@ -0,0 +1,246 @@
+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 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, limit);
+        }
+        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)) {
+            DateRange range = monthRange();
+            return financialAgentTools.getBusinessCockpit(memoryId, range.startDate(), range.endDate(), range.label());
+        }
+        if ("鏌ヨ杩�30澶╀簭鎹熻鍗�".equals(normalized) || "鍝釜璁㈠崟浜忔崯".equals(normalized)) {
+            DateRange range = recentDaysRange(30);
+            return financialAgentTools.analyzeOrderProfit(memoryId, range.startDate(), range.endDate(), range.label(), null, 20);
+        }
+        if ("鐢熸垚鏈懆缁忚惀鍛ㄦ姤".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, 20);
+        }
+        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(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, 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(2));
+            return recentDaysRange(days);
+        }
+        return new DateRange(null, null, "杩�30澶�");
+    }
+
+    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, "杩�30澶�");
+        }
+        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(" ", "")
+                .trim();
+    }
+
+    private String extractKeyword(String text) {
+        String cleaned = text
+                .replace("鏌ヨ", "")
+                .replace("鏌ョ湅", "")
+                .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/ManufacturingAgent.java b/src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java
index f0e8cf7..0d16703 100644
--- a/src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java
+++ b/src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java
@@ -3,6 +3,7 @@
 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;
 
@@ -17,5 +18,5 @@
 public interface ManufacturingAgent {
 
     @SystemMessage(fromResource = "manufacturing-agent-prompt.txt")
-    Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage);
+    Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage, @V("currentDate") String currentDate);
 }
diff --git a/src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java b/src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java
index 6a4ff4e..421261d 100644
--- a/src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java
+++ b/src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java
@@ -3,6 +3,7 @@
 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;
 
@@ -17,5 +18,5 @@
 public interface PurchaseAgent {
 
     @SystemMessage(fromResource = "purchase-agent-prompt.txt")
-    Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage);
+    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
index 5991fc3..c04915e 100644
--- a/src/main/java/com/ruoyi/ai/assistant/PurchaseIntentExecutor.java
+++ b/src/main/java/com/ruoyi/ai/assistant/PurchaseIntentExecutor.java
@@ -4,6 +4,9 @@
 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;
 
@@ -11,8 +14,12 @@
 public class PurchaseIntentExecutor {
 
     private static final Pattern ID_PATTERN = Pattern.compile("\\b\\d{1,12}\\b");
-    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 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;
 
@@ -25,71 +32,63 @@
             return null;
         }
         String text = message.trim();
+        String quickPromptResponse = tryExecuteQuickPrompt(memoryId, text);
+        if (StringUtils.hasText(quickPromptResponse)) {
+            return quickPromptResponse;
+        }
 
-        if (containsAny(text, "鎺掕", "鎺掑悕", "鍓嶅嚑", "鍓嶄簲", "鍓嶅崄") && containsAny(text, "鐗╂枡", "浜у搧", "鍘熸潗鏂�", "閲囪喘閲戦", "閲戦")) {
-            return purchaseAgentTools.rankPurchaseMaterials(
-                    memoryId,
-                    extractStartDate(text),
-                    extractEndDate(text),
-                    text,
-                    extractLimit(text)
-            );
+        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,
-                    extractStartDate(text),
-                    extractEndDate(text),
-                    extractKeyword(text),
-                    extractLimit(text)
-            );
+            return purchaseAgentTools.listUnstockedPurchaseOrders(memoryId, startDate, endDate, keyword, limit);
         }
         if (containsAny(text, "鍒拌揣寮傚父", "鍒拌揣鏈夊紓甯�", "寮傚父鍒拌揣", "鍒拌揣闂", "渚涘簲鍟嗗埌璐у紓甯�")) {
-            return purchaseAgentTools.listArrivalExceptions(
-                    memoryId,
-                    extractStartDate(text),
-                    extractEndDate(text),
-                    text,
-                    extractLimit(text)
-            );
+            return purchaseAgentTools.listArrivalExceptions(memoryId, startDate, endDate, text, limit);
         }
         if (containsAny(text, "寰呬粯娆�", "鏈粯娆�", "鏈粯娓�", "寰呮敮浠�", "搴斾粯")) {
-            return purchaseAgentTools.listPendingPaymentOrders(
-                    memoryId,
-                    extractStartDate(text),
-                    extractEndDate(text),
-                    extractKeyword(text),
-                    extractLimit(text)
-            );
+            return purchaseAgentTools.listPendingPaymentOrders(memoryId, startDate, endDate, keyword, limit);
         }
         if (containsAny(text, "閫�璐�", "閫�鏂�", "鎷掓敹")) {
-            return purchaseAgentTools.listPurchaseReturns(
-                    memoryId,
-                    extractStartDate(text),
-                    extractEndDate(text),
-                    extractKeyword(text),
-                    extractLimit(text)
-            );
+            return purchaseAgentTools.listPurchaseReturns(memoryId, startDate, endDate, keyword, limit);
         }
         if (isStatsIntent(text)) {
-            return purchaseAgentTools.getPurchaseStats(
-                    memoryId,
-                    extractStartDate(text),
-                    extractEndDate(text),
-                    text
-            );
+            return purchaseAgentTools.getPurchaseStats(memoryId, startDate, endDate, text);
         }
-        if (containsAny(text, "璇︽儏", "鏄庣粏") && extractId(text) != null) {
-            return purchaseAgentTools.getPurchaseLedgerDetail(memoryId, extractId(text));
+
+        Long ledgerId = extractId(text);
+        if (containsAny(text, "璇︽儏", "鏄庣粏") && ledgerId != null) {
+            return purchaseAgentTools.getPurchaseLedgerDetail(memoryId, ledgerId);
         }
         if (containsAny(text, "鍙拌处", "閲囪喘鍗�", "閲囪喘璁㈠崟", "璁㈠崟", "鍚堝悓", "鍒楄〃", "鏌ヨ")) {
-            return purchaseAgentTools.listPurchaseLedgers(
-                    memoryId,
-                    extractKeyword(text),
-                    extractStartDate(text),
-                    extractEndDate(text),
-                    extractLimit(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;
     }
@@ -100,8 +99,10 @@
         }
         boolean queryWord = containsAny(text, "鏌ヨ", "鏌ョ湅", "鐪嬩笅", "鐪嬬湅", "鑾峰彇");
         boolean dataWord = containsAny(text, "鏁版嵁", "閲戦", "鏁伴噺", "鍚堝悓棰�", "浠樻棰�", "鍙戠エ棰�");
-        boolean timeWord = containsAny(text, "浠婂ぉ", "鏈懆", "鏈湀", "涓婃湀", "浠婂勾", "鍘诲勾", "杩戝崐骞�", "鏈�杩戝崐涓湀", "鍗婁釜鏈�")
-                || DATE_PATTERN.matcher(text).find();
+        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;
     }
 
@@ -127,23 +128,125 @@
         return matcher.find() ? Integer.parseInt(matcher.group(2)) : 10;
     }
 
-    private String extractStartDate(String text) {
+    private DateRange extractDateRange(String text) {
         Matcher matcher = DATE_PATTERN.matcher(text);
-        return matcher.find() ? matcher.group() : null;
+        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 String extractEndDate(String text) {
-        Matcher matcher = DATE_PATTERN.matcher(text);
-        if (!matcher.find()) {
+    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;
         }
-        return matcher.find() ? matcher.group() : 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("閲囪喘璁㈠崟", "")
@@ -153,9 +256,33 @@
                 .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
new file mode 100644
index 0000000..e2f9a81
--- /dev/null
+++ b/src/main/java/com/ruoyi/ai/assistant/SalesAgent.java
@@ -0,0 +1,22 @@
+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
new file mode 100644
index 0000000..4388a3c
--- /dev/null
+++ b/src/main/java/com/ruoyi/ai/assistant/SalesIntentExecutor.java
@@ -0,0 +1,270 @@
+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/config/FinancialAgentConfig.java b/src/main/java/com/ruoyi/ai/config/FinancialAgentConfig.java
new file mode 100644
index 0000000..0706e74
--- /dev/null
+++ b/src/main/java/com/ruoyi/ai/config/FinancialAgentConfig.java
@@ -0,0 +1,20 @@
+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/SalesAgentConfig.java b/src/main/java/com/ruoyi/ai/config/SalesAgentConfig.java
new file mode 100644
index 0000000..aed3104
--- /dev/null
+++ b/src/main/java/com/ruoyi/ai/config/SalesAgentConfig.java
@@ -0,0 +1,21 @@
+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/controller/FinancialAiController.java b/src/main/java/com/ruoyi/ai/controller/FinancialAiController.java
new file mode 100644
index 0000000..2a3089d
--- /dev/null
+++ b/src/main/java/com/ruoyi/ai/controller/FinancialAiController.java
@@ -0,0 +1,112 @@
+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);
+        }
+
+        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);
+    }
+}
diff --git a/src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java b/src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java
index cb7c0ba..87eb418 100644
--- a/src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java
+++ b/src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java
@@ -24,12 +24,18 @@
 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;
@@ -76,7 +82,7 @@
             return Flux.just(directResponse);
         }
 
-        return manufacturingAgent.chat(memoryId, userMessage)
+        return manufacturingAgent.chat(memoryId, userMessage, currentDateForPrompt())
                 .doOnComplete(() -> aiChatSessionService.refreshSessionStats(memoryId, loginUser))
                 .doOnError(ex -> aiChatSessionService.refreshSessionStats(memoryId, loginUser));
     }
@@ -99,4 +105,8 @@
         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/SalesAiController.java b/src/main/java/com/ruoyi/ai/controller/SalesAiController.java
new file mode 100644
index 0000000..0c92ad6
--- /dev/null
+++ b/src/main/java/com/ruoyi/ai/controller/SalesAiController.java
@@ -0,0 +1,141 @@
+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
index eac43b2..82d088c 100644
--- a/src/main/java/com/ruoyi/ai/controller/XiaozhiController.java
+++ b/src/main/java/com/ruoyi/ai/controller/XiaozhiController.java
@@ -29,6 +29,9 @@
 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;
@@ -39,6 +42,8 @@
 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;
@@ -90,7 +95,17 @@
             return Flux.just(directResponse);
         }
 
-        return approveTodoAgent.chat(memoryId, userMessage)
+        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));
     }
@@ -159,4 +174,29 @@
         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/service/PurchaseAiService.java b/src/main/java/com/ruoyi/ai/service/PurchaseAiService.java
index 0f24d64..cbc936c 100644
--- a/src/main/java/com/ruoyi/ai/service/PurchaseAiService.java
+++ b/src/main/java/com/ruoyi/ai/service/PurchaseAiService.java
@@ -1,5 +1,6 @@
 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;
@@ -20,8 +21,6 @@
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.purchase.dto.PurchaseLedgerDto;
 import com.ruoyi.purchase.dto.PurchaseReturnOrderDto;
-import com.ruoyi.purchase.pojo.PaymentRegistration;
-import com.ruoyi.purchase.service.IPaymentRegistrationService;
 import com.ruoyi.purchase.service.IPurchaseLedgerService;
 import com.ruoyi.purchase.service.PurchaseReturnOrdersService;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
@@ -48,7 +47,6 @@
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.Base64;
-import java.util.Arrays;
 import java.time.LocalDate;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
@@ -71,6 +69,8 @@
     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;
@@ -80,7 +80,6 @@
     private final AiFileTextExtractor aiFileTextExtractor;
     private final ObjectMapper objectMapper;
     private final IPurchaseLedgerService purchaseLedgerService;
-    private final IPaymentRegistrationService paymentRegistrationService;
     private final PurchaseReturnOrdersService purchaseReturnOrdersService;
     private final StorageBlobService storageBlobService;
     private final SupplierManageMapper supplierManageMapper;
@@ -94,7 +93,6 @@
                                 AiFileTextExtractor aiFileTextExtractor,
                                  ObjectMapper objectMapper,
                                  IPurchaseLedgerService purchaseLedgerService,
-                                 IPaymentRegistrationService paymentRegistrationService,
                                  PurchaseReturnOrdersService purchaseReturnOrdersService,
                                  StorageBlobService storageBlobService,
                                  SupplierManageMapper supplierManageMapper,
@@ -107,7 +105,6 @@
         this.aiFileTextExtractor = aiFileTextExtractor;
         this.objectMapper = objectMapper;
         this.purchaseLedgerService = purchaseLedgerService;
-        this.paymentRegistrationService = paymentRegistrationService;
         this.purchaseReturnOrdersService = purchaseReturnOrdersService;
         this.storageBlobService = storageBlobService;
         this.supplierManageMapper = supplierManageMapper;
@@ -138,7 +135,17 @@
             return Flux.just(directResponse);
         }
 
-        return purchaseAgent.chat(memoryId, userMessage)
+        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));
     }
@@ -200,10 +207,10 @@
                     .doOnError(ex -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser));
         }
 
-        return Flux.defer(() -> purchaseAgent.chat(finalMemoryId, userPrompt))
+        return Flux.defer(() -> purchaseAgent.chat(finalMemoryId, userPrompt, currentDateForPrompt()))
                 .onErrorResume(NoSuchElementException.class, ex -> {
                     mongoChatMemoryStore.deleteMessages(finalMemoryId);
-                    return purchaseAgent.chat(finalMemoryId, userPrompt);
+                    return purchaseAgent.chat(finalMemoryId, userPrompt, currentDateForPrompt());
                 })
                 .doOnComplete(() -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser))
                 .doOnError(ex -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser));
@@ -221,7 +228,6 @@
             String businessType = request.getBusinessType().trim();
             return switch (businessType) {
                 case "purchase_ledger" -> processPurchaseLedger(request.getPayload());
-                case "payment_registration" -> processPaymentRegistration(request.getPayload());
                 case "purchase_return_order" -> processPurchaseReturnOrder(request.getPayload());
                 default -> AjaxResult.error("鏆備笉鏀寔璇ヤ笟鍔$被鍨�: " + businessType);
             };
@@ -471,6 +477,51 @@
         };
     }
 
+    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 """
                 浣犳槸閲囪喘涓氬姟鏂囦欢鍒嗘瀽鍔╂墜銆傝涓ユ牸鏍规嵁鐢ㄦ埛涓婁紶鐨勫涓枃浠跺拰鐢ㄦ埛瑕佹眰鎻愬彇閲囪喘涓氬姟鏁版嵁銆�
@@ -482,7 +533,7 @@
                 1. 鍙緭鍑哄悎娉� JSON锛屼笉瑕� Markdown锛屼笉瑕侀澶栬В閲娿��
                 2. JSON 椤跺眰瀛楁鍥哄畾涓�:
                    - success: boolean
-                   - businessType: purchase_ledger | payment_registration | purchase_return_order | unknown
+                   - businessType: purchase_ledger  | purchase_return_order | unknown
                    - action: confirm_required
                    - description: 涓枃璇存槑
                    - confidence: 0鍒�1鐨勫皬鏁�
@@ -507,7 +558,7 @@
                      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 浣跨敤 payment_registration锛宲ayload.records 涓轰粯娆剧櫥璁版暟缁勶紝瀛楁灏介噺鍖呭惈 purchaseLedgerId銆乻alesLedgerProductId銆乧urrentPaymentAmount銆乸aymentMethod銆乸aymentDate銆�
+                4. 濡傛灉鍙垽鏂负浠樻鐧昏锛宐usinessType 浣跨敤 payload.records 涓轰粯娆剧櫥璁版暟缁勶紝瀛楁灏介噺鍖呭惈 purchaseLedgerId銆乻alesLedgerProductId銆乧urrentPaymentAmount銆乸aymentMethod銆乸aymentDate銆�
                 5. 濡傛灉鍙垽鏂负閲囪喘閫�璐э紝businessType 浣跨敤 purchase_return_order锛宲ayload 鎸� PurchaseReturnOrderDto 缁勭粐锛屾槑缁嗘斁 purchaseReturnOrderProductsDtos銆�
                 6. 缂哄皯涓氬姟澶勭悊蹇呴』瀛楁鏃讹紝涓嶈缂栭�� ID锛屾妸瀛楁鏀惧叆 missingFields锛屽苟浠嶈繑鍥炲彲纭鐨勮崏绋挎暟鎹��
                 7. 鎵�鏈変腑鏂囧唴瀹圭洿鎺ヤ繚鐣欙紝涓嶈杞箟鎴� Unicode銆�
@@ -1008,19 +1059,6 @@
         }
         dto.setSupplierId(supplier.getId());
         return null;
-    }
-
-    private AjaxResult processPaymentRegistration(Map<String, Object> payload) {
-        Object recordsValue = payload.get("records");
-        List<PaymentRegistration> records;
-        if (recordsValue == null) {
-            records = Collections.singletonList(objectMapper.convertValue(payload, PaymentRegistration.class));
-        } else {
-            records = objectMapper.convertValue(recordsValue, new TypeReference<List<PaymentRegistration>>() {
-            });
-        }
-        int result = paymentRegistrationService.insertPaymentRegistration(records);
-        return AjaxResult.success("浠樻鐧昏宸插鐞�", result);
     }
 
     private AjaxResult processPurchaseReturnOrder(Map<String, Object> payload) {
diff --git a/src/main/java/com/ruoyi/ai/tools/ApproveTodoTools.java b/src/main/java/com/ruoyi/ai/tools/ApproveTodoTools.java
index cd3e933..fec0c21 100644
--- a/src/main/java/com/ruoyi/ai/tools/ApproveTodoTools.java
+++ b/src/main/java/com/ruoyi/ai/tools/ApproveTodoTools.java
@@ -76,12 +76,17 @@
                             @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 = "鏌ヨ鑼冨洿锛屽彲閫夊�硷細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);
@@ -120,6 +125,11 @@
             }
         }
 
+        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));
 
@@ -156,7 +166,10 @@
                         "statusFilter", StringUtils.hasText(status) ? status : "all",
                         "approveType", approveType == null ? "" : approveType,
                         "keyword", keyword == null ? "" : keyword,
-                        "scope", normalizedScope
+                        "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());
diff --git a/src/main/java/com/ruoyi/ai/tools/FinancialAgentTools.java b/src/main/java/com/ruoyi/ai/tools/FinancialAgentTools.java
new file mode 100644
index 0000000..900242b
--- /dev/null
+++ b/src/main/java/com/ruoyi/ai/tools/FinancialAgentTools.java
@@ -0,0 +1,2226 @@
+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.65");
+
+    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);
+        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", range.start().toString());
+        summary.put("endDate", range.end().toString());
+        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);
+        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(new BigDecimal("0.08")) < 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", range.start().toString());
+        summary.put("endDate", range.end().toString());
+        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", range.start().toString());
+        summary.put("endDate", range.end().toString());
+        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", range.start().toString());
+        summary.put("endDate", range.end().toString());
+        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", range.start().toString());
+        summary.put("endDate", range.end().toString());
+        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(new BigDecimal("1000000")) > 0) {
+            riskSuggestions.add(riskSuggestion("鍥炴椋庨櫓", "涓�", "瀵瑰簲鏀禩OP瀹㈡埛寤虹珛鍛ㄥ害鍥炴璁″垝锛屽苟璁剧疆棰勮闃堝�笺��"));
+        }
+        if (inventoryValue.compareTo(new BigDecimal("3000000")) > 0) {
+            riskSuggestions.add(riskSuggestion("搴撳瓨椋庨櫓", "涓�", "瀵归珮閲戦鍛嗘粸搴撳瓨鎵ц闄嶄环銆佹浛浠e拰鐢熶骇娑堣�楃瓥鐣ャ��"));
+        }
+
+        Map<String, Object> summary = new LinkedHashMap<>();
+        summary.put("reportType", type);
+        summary.put("timeRange", range.label());
+        summary.put("startDate", range.start().toString());
+        summary.put("endDate", range.end().toString());
+        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)
+                .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);
+        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())
+                .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())
+                .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())
+                .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));
+        }
+        wrapper.ge(SalesLedger::getEntryDate, toDate(range.start()))
+                .lt(SalesLedger::getEntryDate, toExclusiveEndDate(range.end()))
+                .orderByDesc(SalesLedger::getEntryDate, SalesLedger::getId)
+                .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);
+        }
+        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);
+        wrapper.ge(AccountSalesCollection::getCollectionDate, range.start())
+                .le(AccountSalesCollection::getCollectionDate, range.end())
+                .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);
+        wrapper.ge(AccountPurchasePayment::getPaymentDate, range.start())
+                .le(AccountPurchasePayment::getPaymentDate, range.end())
+                .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<>();
+        YearMonth startMonth = YearMonth.from(range.start());
+        YearMonth endMonth = YearMonth.from(range.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 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;
+            }
+        }
+        return revenue.multiply(DEFAULT_FALLBACK_MATERIAL_COST_RATE);
+    }
+
+    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) {
+        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)) {
+            if ("浠婂ぉ".equals(defaultLabel)) {
+                return new DateRange(today, today, "浠婂ぉ");
+            }
+            if ("鏈懆".equals(defaultLabel)) {
+                LocalDate start = today.minusDays(today.getDayOfWeek().getValue() - 1L);
+                return new DateRange(start, today, "鏈懆");
+            }
+            if ("鏈湀".equals(defaultLabel)) {
+                return new DateRange(today.withDayOfMonth(1), today, "鏈湀");
+            }
+            if ("杩�90澶�".equals(defaultLabel)) {
+                return new DateRange(today.minusDays(89), today, "杩�90澶�");
+            }
+            return new DateRange(today.minusDays(29), today, defaultLabel);
+        }
+
+        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(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(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", range.start().toString());
+        summary.put("endDate", range.end().toString());
+        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 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/PurchaseAgentTools.java b/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
index 17b6868..bdd1f1f 100644
--- a/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
+++ b/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
@@ -2,23 +2,29 @@
 
 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.purchase.mapper.InvoicePurchaseMapper;
-import com.ruoyi.purchase.mapper.PaymentRegistrationMapper;
-import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
-import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper;
-import com.ruoyi.purchase.pojo.InvoicePurchase;
-import com.ruoyi.purchase.pojo.PaymentRegistration;
-import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.purchase.pojo.PurchaseReturnOrders;
 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;
@@ -27,48 +33,52 @@
 
 import java.math.BigDecimal;
 import java.time.LocalDate;
-import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
-import java.util.Date;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Comparator;
+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 PaymentRegistrationMapper paymentRegistrationMapper;
-    private final InvoicePurchaseMapper invoicePurchaseMapper;
     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,
-                              PaymentRegistrationMapper paymentRegistrationMapper,
-                              InvoicePurchaseMapper invoicePurchaseMapper,
                               PurchaseReturnOrdersMapper purchaseReturnOrdersMapper,
                               SalesLedgerProductMapper salesLedgerProductMapper,
                               ProcurementRecordMapper procurementRecordMapper,
                               InboundManagementMapper inboundManagementMapper,
+                              AccountPurchasePaymentMapper accountPurchasePaymentMapper,
+                              AccountPaymentApplicationMapper accountPaymentApplicationMapper,
+                              AccountPurchaseInvoiceMapper accountPurchaseInvoiceMapper,
+                              StockInRecordMapper stockInRecordMapper,
+                              QualityInspectMapper qualityInspectMapper,
                               AiSessionUserContext aiSessionUserContext) {
         this.purchaseLedgerMapper = purchaseLedgerMapper;
-        this.paymentRegistrationMapper = paymentRegistrationMapper;
-        this.invoicePurchaseMapper = invoicePurchaseMapper;
         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;
     }
 
@@ -130,8 +140,8 @@
         DateRange range = resolveDateRange(startDate, endDate, timeRange);
 
         List<PurchaseLedger> ledgers = queryLedgers(loginUser, range);
-        List<PaymentRegistration> payments = queryPayments(loginUser, range);
-        List<InvoicePurchase> invoices = queryInvoices(loginUser, range);
+        List<AccountPurchasePayment> payments = queryPayments(loginUser, range);
+        List<AccountPurchaseInvoice> invoices = queryInvoices(loginUser, range);
         List<PurchaseReturnOrders> returns = queryReturns(loginUser, range);
 
         BigDecimal contractAmount = ledgers.stream()
@@ -139,11 +149,11 @@
                 .filter(Objects::nonNull)
                 .reduce(BigDecimal.ZERO, BigDecimal::add);
         BigDecimal paymentAmount = payments.stream()
-                .map(PaymentRegistration::getCurrentPaymentAmount)
+                .map(AccountPurchasePayment::getPaymentAmount)
                 .filter(Objects::nonNull)
                 .reduce(BigDecimal.ZERO, BigDecimal::add);
         BigDecimal invoiceAmount = invoices.stream()
-                .map(InvoicePurchase::getInvoiceAmount)
+                .map(this::invoiceAmountOf)
                 .filter(Objects::nonNull)
                 .reduce(BigDecimal.ZERO, BigDecimal::add);
         BigDecimal returnAmount = returns.stream()
@@ -279,15 +289,37 @@
                                            @P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
         LoginUser loginUser = currentLoginUser(memoryId);
         DateRange range = resolveDateRange(startDate, endDate, null);
-        List<Map<String, Object>> items = queryLedgers(loginUser, range).stream()
+        List<PurchaseLedger> matchedLedgers = queryLedgers(loginUser, range).stream()
                 .filter(ledger -> matchLedgerKeyword(ledger, keyword))
-                .map(ledger -> toPendingPaymentItem(loginUser, ledger))
+                .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", "宸茶繑鍥炲緟浠樻閲囪喘鍗曘��",
-                rangeSummary(range, items.size()), Map.of("items", items), Map.of());
+                summary, Map.of("items", items), Map.of());
     }
 
     @Tool(name = "鏌ヨ閲囪喘閫�璐ф儏鍐�", value = "鎸夋椂闂磋寖鍥存煡璇㈤噰璐��璐у崟鍒楄〃鍜岄��璐ч噾棰濄��")
@@ -406,27 +438,58 @@
         return map;
     }
 
-    private Map<String, Object> toPendingPaymentItem(LoginUser loginUser, PurchaseLedger ledger) {
+    private Map<String, Object> toPendingPaymentItem(PurchaseLedger ledger, BigDecimal paidAmount) {
         BigDecimal contractAmount = defaultDecimal(ledger.getContractAmount());
-        BigDecimal paidAmount = sumPaymentAmount(loginUser, ledger.getId());
-        BigDecimal pendingAmount = contractAmount.subtract(paidAmount);
+        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", paidAmount);
+        item.put("paidAmount", safePaidAmount);
         item.put("pendingAmount", pendingAmount);
         return item;
     }
 
-    private BigDecimal sumPaymentAmount(LoginUser loginUser, Long purchaseLedgerId) {
-        LambdaQueryWrapper<PaymentRegistration> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), PaymentRegistration::getTenantId);
-        wrapper.eq(PaymentRegistration::getPurchaseLedgerId, purchaseLedgerId);
-        return defaultList(paymentRegistrationMapper.selectList(wrapper)).stream()
-                .map(PaymentRegistration::getCurrentPaymentAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
+    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) {
@@ -446,21 +509,141 @@
         return value == null ? BigDecimal.ZERO : value;
     }
 
-    private List<PaymentRegistration> queryPayments(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<PaymentRegistration> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), PaymentRegistration::getTenantId);
-        wrapper.ge(PaymentRegistration::getPaymentDate, toDate(range.start()))
-                .lt(PaymentRegistration::getPaymentDate, toExclusiveEndDate(range.end()));
-        return defaultList(paymentRegistrationMapper.selectList(wrapper));
+    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 List<InvoicePurchase> queryInvoices(LoginUser loginUser, DateRange range) {
-        LambdaQueryWrapper<InvoicePurchase> wrapper = new LambdaQueryWrapper<>();
-        applyTenantFilter(wrapper, loginUser.getTenantId(), InvoicePurchase::getTenantId);
-        wrapper.ge(InvoicePurchase::getIssueDate, range.start())
-                .le(InvoicePurchase::getIssueDate, range.end());
-        return defaultList(invoicePurchaseMapper.selectList(wrapper));
+    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<>();
@@ -484,7 +667,7 @@
     }
 
     private DateRange resolveDateRange(String startDate, String endDate, String timeRange) {
-        LocalDate today = LocalDate.now();
+        LocalDate today = LocalDate.now(CHINA_ZONE_ID);
         LocalDate start = parseLocalDate(startDate);
         LocalDate end = parseLocalDate(endDate);
         if (start != null || end != null) {
@@ -501,6 +684,22 @@
             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, "浠婂勾");
         }
@@ -538,7 +737,11 @@
         if (!StringUtils.hasText(text)) {
             return null;
         }
-        return LocalDate.parse(text.trim(), DATE_FMT);
+        try {
+            return LocalDate.parse(text.trim(), DATE_FMT);
+        } catch (Exception ignored) {
+            return null;
+        }
     }
 
     private Date toDate(LocalDate localDate) {
diff --git a/src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java b/src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java
new file mode 100644
index 0000000..0f7e586
--- /dev/null
+++ b/src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java
@@ -0,0 +1,1633 @@
+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/basic/enums/RecordTypeEnum.java b/src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java
index 6613d3e..506a9d8 100644
--- a/src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java
+++ b/src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java
@@ -57,11 +57,8 @@
     SALES_QUOTATION("sales_quotation"),
     SALES_LEDGER_PRODUCT("sales_ledger_product"),
     PURCHASE_LEDGER_FILE("purchase_ledger_file"),
-    RECEIPT_PAYMENT("receipt_payment"),
     PAYMENT_SHIPPING("payment_shipping"),
-    INVOICE_REGISTRATION_PRODUCT("invoice_registration_product"),
     LOSS("loss"),
-    INVOICE_REGISTRATION("invoice_registration"),
     INVOICE_LEDGER_FILE("invoice_ledger_file"),
     INVOICE_LEDGER("invoice_ledger"),
     COMMON_FILE("common_file"),
@@ -86,15 +83,11 @@
     QUALITY_INSPECT_PARAM("quality_inspect_param"),
     QUALITY_INSPECT("quality_inspect"),
     // Purchase
-    TICKET_REGISTRATION("ticket_registration"),
     PURCHASE_RETURN_ORDER_PRODUCTS("purchase_return_order_products"),
     PURCHASE_RETURN_ORDERS("purchase_return_orders"),
     SALES_LEDGER_PRODUCT_TEMPLATE("sales_ledger_product_template"),
     PURCHASE_LEDGER("purchase_ledger"),
     PURCHASE_LEDGER_TEMPLATE("purchase_ledger_template"),
-    PRODUCT_RECORD("product_record"),
-    PAYMENT_REGISTRATION("payment_registration"),
-    INVOICE_PURCHASE("invoice_purchase"),
     // Project Management
     SHIPPING_ADDRESS("shipping_address"),
     ROLES("roles"),
@@ -199,8 +192,6 @@
     AFTER_SALES_SERVICE_FILE("after_sales_service_file"),
     AFTER_SALES_NEAR_EXPIRY("after_sales_near_expiry"),
     // Account
-    ACCOUNT_INCOME("account_income"),
-    BORROW_INFO("borrow_info"),
     SALES_REFUND_AMOUNT_ORDER("sales_refund_amount_order"),
     SALES_RECEIPT_RETURN("sales_receipt_return"),
     ACCOUNT_EXPENSE("account_expense"),
@@ -208,8 +199,9 @@
     FIN_VOUCHER("fin_voucher"),
     ACCOUNT_FILE("account_file"),
     ENTERPRISE_NEWS("enterprise_news"),
-    APPROVAL_INSTANCE("approval_instance");
-
+    APPROVAL_INSTANCE("approval_instance"),
+    ACCOUNT_INVOICE_APPLICATION("account_invoice_application"),
+    ACCOUNT_PURCHASE_INVOICE("account_purchase_invoice");
 
     private final String type;
     RecordTypeEnum(String type) { this.type = type; }
diff --git a/src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java b/src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java
index 2605737..f871b91 100644
--- a/src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java
+++ b/src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java
@@ -6,6 +6,8 @@
 import com.ruoyi.basic.dto.CustomerDto;
 import com.ruoyi.basic.pojo.Customer;
 import com.ruoyi.basic.vo.CustomerVo;
+import com.ruoyi.sales.vo.CustomerTransactionsDetailsVo;
+import com.ruoyi.sales.vo.CustomerTransactionsVo;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -13,7 +15,7 @@
 
 /**
  * 瀹㈡埛妗fMapper鎺ュ彛
- * 
+ *
  * @author ruoyi
  * @date 2025-05-07
  */
@@ -22,7 +24,7 @@
 {
     /**
      * 鏌ヨ瀹㈡埛妗f
-     * 
+     *
      * @param id 瀹㈡埛妗f涓婚敭
      * @return 瀹㈡埛妗f
      */
@@ -30,7 +32,7 @@
 
     /**
      * 鏌ヨ瀹㈡埛妗f鍒楄〃
-     * 
+     *
      * @param customer 瀹㈡埛妗f
      * @return 瀹㈡埛妗f闆嗗悎
      */
@@ -38,7 +40,7 @@
 
     /**
      * 鏂板瀹㈡埛妗f
-     * 
+     *
      * @param customer 瀹㈡埛妗f
      * @return 缁撴灉
      */
@@ -46,7 +48,7 @@
 
     /**
      * 淇敼瀹㈡埛妗f
-     * 
+     *
      * @param customer 瀹㈡埛妗f
      * @return 缁撴灉
      */
@@ -54,7 +56,7 @@
 
     /**
      * 鍒犻櫎瀹㈡埛妗f
-     * 
+     *
      * @param id 瀹㈡埛妗f涓婚敭
      * @return 缁撴灉
      */
@@ -62,7 +64,7 @@
 
     /**
      * 鎵归噺鍒犻櫎瀹㈡埛妗f
-     * 
+     *
      * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
      * @return 缁撴灉
      */
@@ -71,4 +73,8 @@
     IPage<CustomerVo> listPage(Page<CustomerDto> page, @Param("c") CustomerDto customer, @Param("loginUserId") Long loginUserId);
 
     List<CustomerVo> list(@Param("c") CustomerDto customer, @Param("loginUserId") Long loginUserId);
-}
\ No newline at end of file
+
+    IPage<CustomerTransactionsVo> customewTransactions(Page page, @Param("customerName") String customerName);
+
+    IPage<CustomerTransactionsDetailsVo> customewTransactionsDetails(Page page, @Param("customerId") Long customerId);
+}
diff --git a/src/main/java/com/ruoyi/basic/mapper/SupplierManageMapper.java b/src/main/java/com/ruoyi/basic/mapper/SupplierManageMapper.java
index 1ba05a6..beea9c3 100644
--- a/src/main/java/com/ruoyi/basic/mapper/SupplierManageMapper.java
+++ b/src/main/java/com/ruoyi/basic/mapper/SupplierManageMapper.java
@@ -6,6 +6,8 @@
 import com.ruoyi.basic.dto.SupplierManageDto;
 import com.ruoyi.basic.excel.SupplierManageExcelDto;
 import com.ruoyi.basic.pojo.SupplierManage;
+import com.ruoyi.purchase.vo.SupplierTransactionsDetailsVo;
+import com.ruoyi.purchase.vo.SupplierTransactionsVo;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -17,4 +19,8 @@
     IPage<SupplierManage> supplierListPage(Page page, @Param("supplierManageDto") SupplierManageDto supplierManageDto);
 
     List<SupplierManageExcelDto> supplierExportList(@Param("supplierManageDto") SupplierManageDto supplierManageDto);
+
+    IPage<SupplierTransactionsVo> supplierTransactions(Page page, @Param("supplierName") String supplierName);
+
+    IPage<SupplierTransactionsDetailsVo> supplierTransactionsDetails(Page page, @Param("supplierId") Long supplierId);
 }
diff --git a/src/main/java/com/ruoyi/basic/pojo/ProductModel.java b/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
index 8c0dc07..dc7201c 100644
--- a/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
+++ b/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
@@ -46,12 +46,6 @@
     @Excel(name = "鍗曚綅")
     private String unit;
 
-    /**
-     * 鐢熶骇鐐掓満
-     */
-    @Excel(name = "鐢熶骇鐐掓満")
-    private String speculativeTradingName;
-
     @Schema(description = "绉熸埛ID")
     @TableField(fill = FieldFill.INSERT)
     private Long tenantId;
diff --git a/src/main/java/com/ruoyi/basic/service/ICustomerService.java b/src/main/java/com/ruoyi/basic/service/ICustomerService.java
index b725216..27e4739 100644
--- a/src/main/java/com/ruoyi/basic/service/ICustomerService.java
+++ b/src/main/java/com/ruoyi/basic/service/ICustomerService.java
@@ -7,6 +7,8 @@
 import com.ruoyi.basic.pojo.Customer;
 import com.ruoyi.basic.vo.CustomerVo;
 import com.ruoyi.framework.web.domain.R;
+import com.ruoyi.sales.vo.CustomerTransactionsDetailsVo;
+import com.ruoyi.sales.vo.CustomerTransactionsVo;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.util.List;
@@ -93,4 +95,20 @@
     void together(CustomerDto customerDto);
 
     Boolean back(Long id);
+
+    /**
+     * 鏌ヨ瀹㈡埛寰�鏉ュ垪琛�
+     * @param page
+     * @param customerName
+     * @return
+     */
+    IPage<CustomerTransactionsVo> customewTransactions(Page page, String customerName);
+
+    /**
+     * 鏌ヨ瀹㈡埛寰�鏉ユ槑缁嗗垪琛�
+     * @param page
+     * @param customerId
+     * @return
+     */
+    IPage<CustomerTransactionsDetailsVo> customewTransactionsDetails(Page page, Long customerId);
 }
diff --git a/src/main/java/com/ruoyi/basic/service/ISupplierService.java b/src/main/java/com/ruoyi/basic/service/ISupplierService.java
index b54c2ad..ce6d832 100644
--- a/src/main/java/com/ruoyi/basic/service/ISupplierService.java
+++ b/src/main/java/com/ruoyi/basic/service/ISupplierService.java
@@ -5,10 +5,11 @@
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ruoyi.basic.dto.SupplierManageDto;
 import com.ruoyi.basic.pojo.SupplierManage;
-import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.purchase.vo.SupplierTransactionsDetailsVo;
+import com.ruoyi.purchase.vo.SupplierTransactionsVo;
+import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.web.multipart.MultipartFile;
 
-import jakarta.servlet.http.HttpServletResponse;
 import java.util.List;
 
 public interface ISupplierService extends IService<SupplierManage> {
@@ -57,4 +58,20 @@
     void supplierExport(HttpServletResponse response, SupplierManageDto supplierManageDto);
 
     Boolean importData(MultipartFile file);
+
+    /**
+     * 渚涘簲鍟嗗線鏉�
+     * @param page
+     * @param supplierName
+     * @return
+     */
+    IPage<SupplierTransactionsVo> supplierTransactions(Page page, String supplierName);
+
+    /**
+     * 渚涘簲鍟嗗線鏉ヨ鎯�
+     * @param page
+     * @param supplierId
+     * @return
+     */
+    IPage<SupplierTransactionsDetailsVo> supplierTransactionsDetails(Page page, Long supplierId);
 }
diff --git a/src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java b/src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
index 09c2a46..eef85aa 100644
--- a/src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
+++ b/src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
@@ -23,6 +23,8 @@
 import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.sales.mapper.SalesLedgerMapper;
 import com.ruoyi.sales.pojo.SalesLedger;
+import com.ruoyi.sales.vo.CustomerTransactionsDetailsVo;
+import com.ruoyi.sales.vo.CustomerTransactionsVo;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
@@ -379,6 +381,16 @@
         return this.updateById(customer);
     }
 
+    @Override
+    public IPage<CustomerTransactionsVo> customewTransactions(Page page, String customerName) {
+        return customerMapper.customewTransactions(page, customerName);
+    }
+
+    @Override
+    public IPage<CustomerTransactionsDetailsVo> customewTransactionsDetails(Page page, Long customerId) {
+        return customerMapper.customewTransactionsDetails(page, customerId);
+    }
+
     /**
      * 涓嬪垝绾垮懡鍚嶈浆椹煎嘲鍛藉悕
      */
diff --git a/src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java b/src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java
index 6adaf2a..613bde2 100644
--- a/src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java
+++ b/src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java
@@ -14,6 +14,8 @@
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
+import com.ruoyi.purchase.vo.SupplierTransactionsDetailsVo;
+import com.ruoyi.purchase.vo.SupplierTransactionsVo;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
 import org.springframework.beans.BeanUtils;
@@ -130,4 +132,14 @@
         }
         return false;
     }
+
+    @Override
+    public IPage<SupplierTransactionsVo> supplierTransactions(Page page, String supplierName) {
+        return supplierMapper.supplierTransactions(page,supplierName);
+    }
+
+    @Override
+    public IPage<SupplierTransactionsDetailsVo> supplierTransactionsDetails(Page page, Long supplierId) {
+        return supplierMapper.supplierTransactionsDetails(page,supplierId);
+    }
 }
diff --git a/src/main/java/com/ruoyi/home/controller/HomeController.java b/src/main/java/com/ruoyi/home/controller/HomeController.java
index 41ae224..7878d28 100644
--- a/src/main/java/com/ruoyi/home/controller/HomeController.java
+++ b/src/main/java/com/ruoyi/home/controller/HomeController.java
@@ -1,14 +1,21 @@
 package com.ruoyi.home.controller;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.approve.pojo.ApproveProcess;
+import com.ruoyi.device.mapper.DeviceLedgerMapper;
+import com.ruoyi.device.mapper.DeviceRepairMapper;
+import com.ruoyi.device.pojo.DeviceRepair;
 import com.ruoyi.dto.MapDto;
 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.AjaxResult;
+import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.home.annotation.DefaultType;
 import com.ruoyi.home.dto.*;
 import com.ruoyi.home.service.HomeService;
+import com.ruoyi.production.mapper.ProductionOrderMapper;
+import com.ruoyi.production.mapper.ProductionProductOutputMapper;
+import com.ruoyi.production.pojo.ProductionOrder;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.Operation;
 import lombok.AllArgsConstructor;
@@ -17,9 +24,21 @@
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.text.ParseException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+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.*;
 
 /**
  * @author :yys
@@ -32,293 +51,698 @@
 public class HomeController extends BaseController {
 
     private final HomeService homeService;
+    private final ProductionOrderMapper productionOrderMapper;
+    private final ProductionProductOutputMapper productionProductOutputMapper;
+    private final DeviceLedgerMapper deviceLedgerMapper;
+    private final DeviceRepairMapper deviceRepairMapper;
+
+    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+    private static final Integer ORDER_STATUS_WAIT = 1;
+    private static final Integer ORDER_STATUS_RUNNING = 2;
+    private static final Integer ORDER_STATUS_COMPLETED = 3;
+    private static final Integer ORDER_STATUS_PAUSED = 4;
 
     /********************************************************鍩虹绫�*****************************************************/
     @GetMapping("/todos")
     @Log(title = "寰呭姙浜嬮」", businessType = BusinessType.OTHER)
     @Operation(summary = "寰呭姙浜嬮」")
-    public AjaxResult todos(ApproveProcess req) throws ParseException {
+    public R todos() throws ParseException {
         List<ApproveProcess> approveProcessList = homeService.todos();
-        return AjaxResult.success(approveProcessList);
+        return R.ok(approveProcessList);
     }
 
     @GetMapping("/approveAndDeviceTodos")
     @Operation(summary = "瀹℃壒鍗忓悓锛岃澶囨姤淇緟鍔炰簨椤�")
-    public AjaxResult approveAndDeviceTodos(){
+    public R approveAndDeviceTodos(){
         Map<String, Object> map = homeService.approveAndDeviceTodos();
-        return AjaxResult.success(map);
+        return R.ok(map);
     }
 
     @GetMapping("/noticesCount")
     @Operation(summary = "鏈繃鏈熺殑鍏憡鏁伴噺")
-    public AjaxResult noticesCount(){
+    public R noticesCount(){
         Long count = homeService.noticesCount();
-        return AjaxResult.success(count);
+        return R.ok(count);
     }
 
     @GetMapping("/deptStaffDistribution")
     @Operation(summary = "鍚勯儴闂ㄤ汉鍛樺垎甯�")
-    public AjaxResult deptStaffDistribution() {
+    public R deptStaffDistribution() {
         DeptStaffDistributionDto dto = homeService.deptStaffDistribution();
-        return AjaxResult.success(dto);
+        return R.ok(dto);
     }
 
     @GetMapping("/summaryStatistics")
     @Operation(summary = "鍛樺伐-瀹㈡埛-渚涘簲鍟嗘�绘暟")
-    public AjaxResult summaryStatistics() {
+    public R summaryStatistics() {
         HomeSummaryDto homeSummaryDto = homeService.summaryStatistics();
-        return AjaxResult.success(homeSummaryDto);
+        return R.ok(homeSummaryDto);
     }
 
     /********************************************************钀ラ攢閲囪喘绫�**************************************************/
     @GetMapping("/supplierPurchaseRanking")
     @Operation(summary = "渚涘簲鍟嗛噰璐帓鍚�")
-    public AjaxResult supplierPurchaseRanking(@DefaultType Integer type) {
+    public R supplierPurchaseRanking(@DefaultType Integer type) {
         List<SupplierPurchaseRankingDto> list = homeService.supplierPurchaseRanking(type);
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/customerRevenueAnalysis")
     @Operation(summary = "瀹㈡埛钀ユ敹璐$尞鏁板�煎垎鏋�")
-    public AjaxResult customerRevenueAnalysis(Long customerId, @DefaultType Integer type) {
+    public R customerRevenueAnalysis(Long customerId, @DefaultType Integer type) {
         CustomerRevenueAnalysisDto dto = homeService.customerRevenueAnalysis(customerId, type);
-        return AjaxResult.success(dto);
+        return R.ok(dto);
     }
 
     @GetMapping("/customerContributionRanking")
     @Operation(summary = "瀹㈡埛閲戦璐$尞鎺掑悕")
-    public AjaxResult customerContributionRanking(@DefaultType Integer type) {
+    public R customerContributionRanking(@DefaultType Integer type) {
         List<CustomerContributionRankingDto> list = homeService.customerContributionRanking(type);
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/productSalesAnalysis")
     @Operation(summary = "鍚勪骇鍝侀攢鍞噾棰濆垎鏋�")
-    public AjaxResult productSalesAnalysis() {
+    public R productSalesAnalysis() {
         List<MapDto> list = homeService.productSalesAnalysis();
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/rawMaterialPurchaseAmountRatio")
     @Operation(summary = "鍘熸潗鏂欓噰璐噾棰濆崰姣�")
-    public AjaxResult rawMaterialPurchaseAmountRatio(){
+    public R rawMaterialPurchaseAmountRatio(){
         List<MapDto> list = homeService.rawMaterialPurchaseAmountRatio();
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/business")
     @Log(title = "閿�鍞�-閲囪喘-搴撳瓨鏁版嵁", businessType = BusinessType.OTHER)
     @Operation(summary = "閿�鍞�-閲囪喘-搴撳瓨鏁版嵁")
-    public AjaxResult business(HomeBusinessDto req) {
+    public R business() {
         HomeBusinessDto homeBusinessDto = homeService.business();
-        return AjaxResult.success(homeBusinessDto);
+        return R.ok(homeBusinessDto);
     }
 
     @GetMapping("/analysisCustomerContractAmounts")
     @Log(title = "瀹㈡埛鍚堝悓閲戦鍒嗘瀽", businessType = BusinessType.OTHER)
     @Operation(summary = "瀹㈡埛鍚堝悓閲戦鍒嗘瀽")
-    public AjaxResult analysisCustomerContractAmounts(AnalysisCustomerContractAmountsDto req) {
+    public R analysisCustomerContractAmounts() {
         AnalysisCustomerContractAmountsDto analysisCustomerContractAmounts = homeService.analysisCustomerContractAmounts();
-        return AjaxResult.success(analysisCustomerContractAmounts);
+        return R.ok(analysisCustomerContractAmounts);
     }
 
     /********************************************************鐢熶骇绫�*****************************************************/
     @GetMapping("/inputOutputAnalysis")
     @Operation(summary = "鎶曞叆浜у嚭鍒嗘瀽")
-    public AjaxResult inputOutputAnalysis(@DefaultType Integer type){
+    public R inputOutputAnalysis(@DefaultType Integer type){
       List<InputOutputAnalysisDto> list = homeService.inputOutputAnalysis(type);
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/processOutputAnalysis")
     @Operation(summary = "宸ュ簭浜у嚭鍒嗘瀽")
-    public AjaxResult processOutputAnalysis(@DefaultType Integer type){
+    public R processOutputAnalysis(@DefaultType Integer type){
         List<MapDto> list = homeService.processOutputAnalysis(type);
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/workOrderEfficiencyAnalysis")
     @Operation(summary = "宸ュ崟鎵ц鏁堢巼鍒嗘瀽")
-    public AjaxResult workOrderEfficiencyAnalysis(@DefaultType Integer type){
+    public R workOrderEfficiencyAnalysis(@DefaultType Integer type){
         List<WorkOrderEfficiencyDto> list = homeService.workOrderEfficiencyAnalysis(type);
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/productionAccountingAnalysis")
     @Operation(summary = "鐢熶骇鏍哥畻鍒嗘瀽")
-    public AjaxResult productionAccountingAnalysis(@DefaultType Integer type){
+    public R productionAccountingAnalysis(@DefaultType Integer type){
         List<ProductionAccountingDto> list   = homeService.productionAccountingAnalysis(type);
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/orderCount")
     @Operation(summary = "璁㈠崟鏁�")
-    public AjaxResult orderCount(){
-        return AjaxResult.success(homeService.orderCount());
+    public R orderCount(){
+        return R.ok(homeService.orderCount());
     }
 
     @GetMapping("/progressStatistics")
     @Operation(summary = "鍚勭敓浜ц鍗曠殑瀹屾垚杩涘害缁熻")
-    public AjaxResult progressStatistics(){
+    public R progressStatistics(){
         ProductionProgressDto productionProgressDto = homeService.productionProgress();
-        return AjaxResult.success(productionProgressDto);
+        return R.ok(productionProgressDto);
     }
 
     @GetMapping("/workInProcessTurnover")
     @Operation(summary = "鍦ㄥ埗鍝佸懆杞儏鍐�")
-    public AjaxResult workInProcessTurnover(){
+    public R workInProcessTurnover(){
         ProductionTurnoverDto productionTurnoverDto = homeService.workInProcessTurnover();
-        return AjaxResult.success(productionTurnoverDto);
+        return R.ok(productionTurnoverDto);
     }
 
     @GetMapping("/processDataProductionStatistics")
     @Operation(summary = "宸ュ簭鏁版嵁鐢熶骇缁熻鏁版嵁")
-    public AjaxResult processDataProductionStatistics(@DefaultType Integer type,@RequestParam(required = false) List<Long> processIds) {
+    public R processDataProductionStatistics(@DefaultType Integer type,@RequestParam(required = false) List<Long> processIds) {
         List<processDataProductionStatisticsDto> list = homeService.processDataProductionStatistics(type, processIds);
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     /********************************************************璐ㄩ噺绫�*****************************************************/
+    @GetMapping("/productionOverview")
+    @Operation(summary = "Production Overview")
+    public R productionOverview() {
+        LocalDate today = LocalDate.now();
+        Map<String, BigDecimal> totalStats = loadOutputStats(LocalDate.of(2000, 1, 1), today.plusDays(1));
+        BigDecimal totalOutput = totalStats.get("quantity");
+        BigDecimal totalScrap = totalStats.get("scrapQty");
+        BigDecimal yieldRate = calcRate(totalOutput, totalOutput.add(totalScrap));
+
+        Map<String, Object> result = new LinkedHashMap<>();
+        result.put("totalOutput", scale(totalOutput));
+        result.put("totalScrap", scale(totalScrap));
+        result.put("yieldRate", scale(yieldRate));
+        return R.ok(result);
+    }
+
+    @GetMapping("/productionRealtimeBoard")
+    @Operation(summary = "Production Realtime Board")
+    public R productionRealtimeBoard() {
+        LocalDate today = LocalDate.now();
+        LocalDate yesterday = today.minusDays(1);
+
+        BigDecimal todayDeviceOee = calcDeviceOee(today);
+        BigDecimal yesterdayDeviceOee = calcDeviceOee(yesterday);
+
+        BigDecimal todayOrderAchievementRate = calcOrderAchievementRate(today);
+        BigDecimal yesterdayOrderAchievementRate = calcOrderAchievementRate(yesterday);
+
+        BigDecimal todayDefectRate = calcDefectRate(today);
+        BigDecimal yesterdayDefectRate = calcDefectRate(yesterday);
+
+        Map<String, Object> result = new LinkedHashMap<>();
+        result.put("deviceOee", buildRealtimeMetric(todayDeviceOee, todayDeviceOee.subtract(yesterdayDeviceOee)));
+        result.put("orderAchievementRate", buildRealtimeMetric(todayOrderAchievementRate, todayOrderAchievementRate.subtract(yesterdayOrderAchievementRate)));
+        result.put("defectRate", buildRealtimeMetric(todayDefectRate, todayDefectRate.subtract(yesterdayDefectRate)));
+        return R.ok(result);
+    }
+
+    @GetMapping("/productionOrderProgress")
+    @Operation(summary = "Production Order Progress")
+    public R productionOrderProgress(@RequestParam(defaultValue = "all") String tab,
+                                     @RequestParam(required = false) String status,
+                                     @RequestParam(required = false) String bizDate,
+                                     @RequestParam(defaultValue = "1") Long pageNum,
+                                     @RequestParam(defaultValue = "10") Long pageSize) {
+        LocalDate queryDate = parseDateOrNull(bizDate);
+        if (!isBlank(bizDate) && queryDate == null) {
+            return R.fail("bizDate鏍煎紡閿欒锛岃浣跨敤yyyy-MM-dd");
+        }
+        Integer statusFromParam = parseOrderStatus(status);
+        if (!isBlank(status) && statusFromParam == null && !"all".equalsIgnoreCase(status.trim())) {
+            return R.fail("status鍙傛暟涓嶅悎娉曪紝鍙�夊�硷細all/waiting/inProgress/completed/paused 鎴� 1/2/3/4");
+        }
+        Integer queryStatus = resolveOrderStatus(status, tab);
+
+        long safePageNum = pageNum == null || pageNum < 1 ? 1 : pageNum;
+        long safePageSize = pageSize == null || pageSize < 1 ? 10 : Math.min(pageSize, 50);
+        long offset = (safePageNum - 1) * safePageSize;
+        LocalDateTime startTime = queryDate == null ? null : queryDate.atStartOfDay();
+        LocalDateTime endTime = queryDate == null ? null : queryDate.plusDays(1).atStartOfDay();
+
+        List<Map<String, Object>> rawRows = productionOrderMapper.selectHomeOrderProgressPage(queryStatus, offset, safePageSize, startTime, endTime);
+        List<Map<String, Object>> records = new ArrayList<>();
+        if (rawRows != null) {
+            for (Map<String, Object> rawRow : rawRows) {
+                records.add(buildOrderProgressRow(rawRow));
+            }
+        }
+
+        long waitingCount = 0L;
+        long inProgressCount = 0L;
+        long completedCount = 0L;
+        long pausedCount = 0L;
+        List<Map<String, Object>> statusCountRows = productionOrderMapper.countHomeOrderProgressByStatus(startTime, endTime);
+        if (statusCountRows != null) {
+            for (Map<String, Object> countRow : statusCountRows) {
+                Integer statusKey = toInteger(countRow.get("status"));
+                long cnt = toLong(countRow.get("cnt"));
+                if (Objects.equals(statusKey, ORDER_STATUS_WAIT)) {
+                    waitingCount = cnt;
+                } else if (Objects.equals(statusKey, ORDER_STATUS_RUNNING)) {
+                    inProgressCount = cnt;
+                } else if (Objects.equals(statusKey, ORDER_STATUS_COMPLETED)) {
+                    completedCount = cnt;
+                } else if (Objects.equals(statusKey, ORDER_STATUS_PAUSED)) {
+                    pausedCount = cnt;
+                }
+            }
+        }
+
+        Map<String, Object> result = new LinkedHashMap<>();
+        result.put("tab", mapOrderTab(queryStatus));
+        result.put("status", mapOrderStatus(queryStatus));
+        result.put("bizDate", queryDate == null ? null : queryDate.format(DATE_FORMATTER));
+        result.put("total", toLong(productionOrderMapper.countHomeOrderProgress(queryStatus, startTime, endTime)));
+        result.put("pageNum", safePageNum);
+        result.put("pageSize", safePageSize);
+        result.put("waitingCount", waitingCount);
+        result.put("inProgressCount", inProgressCount);
+        result.put("completedCount", completedCount);
+        result.put("pausedCount", pausedCount);
+        result.put("records", records);
+        return R.ok(result);
+    }
+
+    @GetMapping("/todayProductionPlan")
+    @Operation(summary = "Today Production Plan")
+    public R todayProductionPlan(@RequestParam(defaultValue = "4") Long limit,
+                                 @RequestParam(required = false) String planDate) {
+        LocalDate queryDate = parseDateOrNull(planDate);
+        if (!isBlank(planDate) && queryDate == null) {
+            return R.fail("planDate鏍煎紡閿欒锛岃浣跨敤yyyy-MM-dd");
+        }
+
+        long safeLimit = limit == null || limit < 1 ? 4 : Math.min(limit, 20);
+        LocalDateTime planStart = queryDate == null ? null : queryDate.atStartOfDay();
+        LocalDateTime planEnd = queryDate == null ? null : queryDate.plusDays(1).atStartOfDay();
+        List<Map<String, Object>> records = new ArrayList<>();
+        List<Map<String, Object>> rawRows = productionOrderMapper.selectHomeTodayProductionPlan(safeLimit, planStart, planEnd);
+        if (rawRows != null) {
+            for (Map<String, Object> rawRow : rawRows) {
+                Map<String, Object> row = new LinkedHashMap<>();
+                Integer rowStatus = toInteger(rawRow.get("status"));
+                row.put("orderNo", rawRow.get("orderNo"));
+                row.put("productName", rawRow.get("productName"));
+                row.put("plannedQuantity", scale(toBigDecimal(rawRow.get("plannedQuantity"))));
+                row.put("dueDate", rawRow.get("dueDate"));
+                row.put("status", rowStatus);
+                row.put("statusLabel", mapOrderStatusLabel(rowStatus));
+                records.add(row);
+            }
+        }
+
+        Map<String, Object> result = new LinkedHashMap<>();
+        result.put("planDate", queryDate == null ? null : queryDate.format(DATE_FORMATTER));
+        result.put("total", toLong(productionOrderMapper.countHomeTodayProductionPlan(planStart, planEnd)));
+        result.put("records", records);
+        return R.ok(result);
+    }
+
     @GetMapping("/rawMaterialDetection")
     @Operation(summary = "鍘熸潗鏂欐娴�")
-    public AjaxResult rawMaterialDetection(@DefaultType Integer type){
-        return AjaxResult.success(homeService.rawMaterialDetection(type));
+    public R rawMaterialDetection(@DefaultType Integer type){
+        return R.ok(homeService.rawMaterialDetection(type));
     }
 
     @GetMapping("/processDetection")
     @Operation(summary = "杩囩▼妫�娴�")
-    public AjaxResult processDetection(@DefaultType Integer type){
-        return AjaxResult.success(homeService.processDetection(type));
+    public R processDetection(@DefaultType Integer type){
+        return R.ok(homeService.processDetection(type));
     }
 
     @GetMapping("/factoryDetection")
     @Operation(summary = "鎴愬搧鍑哄巶妫�娴�")
-    public AjaxResult factoryDetection(@DefaultType Integer type){
-        return AjaxResult.success(homeService.factoryDetection(type));
+    public R factoryDetection(@DefaultType Integer type){
+        return R.ok(homeService.factoryDetection(type));
     }
 
     @GetMapping("/qualityInspectionCount")
     @Operation(summary = "璐ㄩ噺妫�楠屾暟閲�")
-    public AjaxResult qualityInspectionCount(){
+    public R qualityInspectionCount(){
         QualityInspectionCountDto qualityInspectionCountDto = homeService.qualityInspectionCount();
-        return AjaxResult.success(qualityInspectionCountDto);
+        return R.ok(qualityInspectionCountDto);
     }
 
     @GetMapping("/nonComplianceWarning")
     @Operation(summary = "涓嶅悎鏍奸璀�")
-    public AjaxResult nonComplianceWarning(){
+    public R nonComplianceWarning(){
         NonComplianceWarningDto nonComplianceWarningDto = homeService.nonComplianceWarning();
-        return AjaxResult.success(nonComplianceWarningDto);
+        return R.ok(nonComplianceWarningDto);
     }
 
     @GetMapping("/completedInspectionCount")
     @Operation(summary = "瀹屾垚妫�楠屾暟")
-    public AjaxResult completedInspectionCount(){
+    public R completedInspectionCount(){
         List<CompletedInspectionCountDto> list = homeService.completedInspectionCount();
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/unqualifiedProductRanking")
     @Operation(summary = "涓嶅悎鏍间骇鍝佹帓鍚�")
-    public AjaxResult unqualifiedProductRanking(){
+    public R unqualifiedProductRanking(){
         List<UnqualifiedProductRankDto> list = homeService.unqualifiedProductRanking();
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/unqualifiedProductProcessingAnalysis")
     @Operation(summary = "涓嶅悎鏍兼鍝佸鐞嗗垎鏋�")
-    public AjaxResult unqualifiedProductProcessingAnalysis(){
+    public R unqualifiedProductProcessingAnalysis(){
         List<MapDto> list = homeService.unqualifiedProductProcessingAnalysis();
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/qualityStatistics")
     @Log(title = "璐ㄩ噺鍒嗘瀽", businessType = BusinessType.OTHER)
     @Operation(summary = "璐ㄩ噺鍒嗘瀽")
-    public AjaxResult qualityStatistics(QualityStatisticsDto req) {
+    public R qualityStatistics() {
         QualityStatisticsDto qualityStatisticsDto = homeService.qualityStatistics();
-        return AjaxResult.success(qualityStatisticsDto);
+        return R.ok(qualityStatisticsDto);
     }
 
     @GetMapping("/qualityInspectionStatistics")
     @Operation(summary = "璐ㄩ噺缁熻")
-    public AjaxResult qualityInspectionStatistics(@DefaultType Integer type) {
+    public R qualityInspectionStatistics(@DefaultType Integer type) {
        QualityStatisticsDto  dto = homeService.qualityInspectionStatistics(type);
-        return AjaxResult.success(dto);
+        return R.ok(dto);
     }
 
     /********************************************************璐㈠姟绫�*****************************************************/
     @GetMapping("/incomeExpenseAnalysis")
     @Operation(summary = "鏀敹瀵规瘮鍒嗘瀽")
-    public AjaxResult incomeExpenseAnalysis(@DefaultType Integer type) {
+    public R incomeExpenseAnalysis(@DefaultType Integer type) {
         List<Map<String, Object>> result = homeService.incomeExpenseAnalysis(type);
-        return AjaxResult.success(result);
+        return R.ok(result);
     }
 
     @GetMapping("/profitTrendAnalysis")
     @Operation(summary = "鍒╂鼎瓒嬪娍鍒嗘瀽")
-    public AjaxResult profitTrendAnalysis(){
+    public R profitTrendAnalysis(){
         List<MapDto> list = homeService.profitTrendAnalysis();
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/expenseCompositionAnalysis")
     @Operation(summary = "鏋勬垚鍒嗘瀽")
-    public AjaxResult expenseCompositionAnalysis(@DefaultType Integer type) {
+    public R expenseCompositionAnalysis(@DefaultType Integer type) {
         List<MapDto> list = homeService.expenseCompositionAnalysis(type);
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/monthlyIncome")
     @Operation(summary = "鏈堝害鏀跺叆")
-    public AjaxResult monthlyIncome(){
+    public R monthlyIncome(){
         MonthlyIncomeDto dto = homeService.monthlyIncome();
-        return AjaxResult.success(dto);
+        return R.ok(dto);
     }
 
     @GetMapping("/monthlyExpenditure")
     @Operation(summary = "鏈堝害鏀嚭")
-    public AjaxResult monthlyExpenditure(){
+    public R monthlyExpenditure(){
         MonthlyExpenditureDto dto = homeService.monthlyExpenditure();
-        return AjaxResult.success(dto);
+        return R.ok(dto);
     }
 
     @GetMapping("/statisticsReceivablePayable")
     @Log(title = "搴旀敹搴斾粯缁熻", businessType = BusinessType.OTHER)
     @Operation(summary = "搴旀敹搴斾粯缁熻")
-    public AjaxResult statisticsReceivablePayable(StatisticsReceivablePayableDto req, @DefaultType Integer type ) {
+    public R statisticsReceivablePayable(@DefaultType Integer type ) {
         StatisticsReceivablePayableDto statisticsReceivablePayable = homeService.statisticsReceivablePayable(type);
-        return AjaxResult.success(statisticsReceivablePayable);
+        return R.ok(statisticsReceivablePayable);
     }
 
     /********************************************************浠撳偍绫�*****************************************************/
 
     @GetMapping("/productCategoryDistribution")
     @Operation(summary = "浜у搧澶х被鍒嗗竷")
-    public AjaxResult productCategoryDistribution() {
+    public R productCategoryDistribution() {
         ProductCategoryDistributionDto dto = homeService.productCategoryDistribution();
-        return AjaxResult.success(dto);
+        return R.ok(dto);
     }
 
     @GetMapping("/salesPurchaseStorageProductCount")
     @Operation(summary = "閿�鍞�-閲囪喘-鍌ㄥ瓨浜у搧鏁�")
-    public AjaxResult salesPurchaseStorageProductCount(){
+    public R salesPurchaseStorageProductCount(){
         List<MapDto> list = homeService.salesPurchaseStorageProductCount();
-        return AjaxResult.success(list);
+        return R.ok(list);
     }
 
     @GetMapping("/productInOutAnalysis")
     @Operation(summary = "浜у搧鍑哄叆搴撳垎鏋�")
-    public AjaxResult productInOutAnalysis(@DefaultType Integer type){
+    public R productInOutAnalysis(@DefaultType Integer type){
         List<Map<String, Object>> result = homeService.productInOutAnalysis(type);
-        return AjaxResult.success(result);
+        return R.ok(result);
     }
 
     @GetMapping("/productTurnoverDays")
     @Operation(summary = "浜у搧鍛ㄨ浆澶╂暟")
-    public AjaxResult productTurnoverDays(){
+    public R productTurnoverDays(){
         List<MapDto> list = homeService.productTurnoverDays();
-        return AjaxResult.success(list);
+        return R.ok(list);
+    }
+
+    private Map<String, Object> buildOrderProgressRow(Map<String, Object> rawRow) {
+        Map<String, Object> row = new LinkedHashMap<>();
+        Integer rowStatus = toInteger(rawRow.get("status"));
+        row.put("orderNo", rawRow.get("orderNo"));
+        row.put("productName", rawRow.get("productName"));
+        row.put("plannedQuantity", scale(toBigDecimal(rawRow.get("plannedQuantity"))));
+        row.put("completedQuantity", scale(toBigDecimal(rawRow.get("completedQuantity"))));
+        row.put("completionRate", scale(toBigDecimal(rawRow.get("completionRate"))));
+        row.put("dueDate", rawRow.get("dueDate"));
+        row.put("status", rowStatus);
+        row.put("statusLabel", mapOrderStatusLabel(rowStatus));
+        return row;
+    }
+
+    private Integer resolveOrderStatus(String status, String tab) {
+        if (!isBlank(status)) {
+            return parseOrderStatus(status);
+        }
+        return parseOrderStatus(tab);
+    }
+
+    private Integer parseOrderStatus(String rawStatus) {
+        if (isBlank(rawStatus)) {
+            return null;
+        }
+        String normalized = rawStatus.trim().toLowerCase();
+        if ("all".equals(normalized)) {
+            return null;
+        }
+        if ("1".equals(normalized) || "waiting".equals(normalized) || "wait".equals(normalized)) {
+            return ORDER_STATUS_WAIT;
+        }
+        if ("2".equals(normalized) || "inprogress".equals(normalized) || "running".equals(normalized)) {
+            return ORDER_STATUS_RUNNING;
+        }
+        if ("3".equals(normalized) || "completed".equals(normalized)) {
+            return ORDER_STATUS_COMPLETED;
+        }
+        if ("4".equals(normalized) || "paused".equals(normalized)) {
+            return ORDER_STATUS_PAUSED;
+        }
+        return null;
+    }
+
+    private String mapOrderTab(Integer status) {
+        if (Objects.equals(status, ORDER_STATUS_RUNNING)) {
+            return "inProgress";
+        }
+        if (Objects.equals(status, ORDER_STATUS_COMPLETED)) {
+            return "completed";
+        }
+        if (Objects.equals(status, ORDER_STATUS_PAUSED)) {
+            return "paused";
+        }
+        if (Objects.equals(status, ORDER_STATUS_WAIT)) {
+            return "waiting";
+        }
+        return "all";
+    }
+
+    private String mapOrderStatus(Integer status) {
+        if (Objects.equals(status, ORDER_STATUS_WAIT)) {
+            return "waiting";
+        }
+        if (Objects.equals(status, ORDER_STATUS_RUNNING)) {
+            return "inProgress";
+        }
+        if (Objects.equals(status, ORDER_STATUS_COMPLETED)) {
+            return "completed";
+        }
+        if (Objects.equals(status, ORDER_STATUS_PAUSED)) {
+            return "paused";
+        }
+        return "all";
+    }
+
+    private String mapOrderStatusLabel(Integer status) {
+        if (Objects.equals(status, ORDER_STATUS_WAIT)) {
+            return "寰呭紑濮�";
+        }
+        if (Objects.equals(status, ORDER_STATUS_RUNNING)) {
+            return "杩涜涓�";
+        }
+        if (Objects.equals(status, ORDER_STATUS_COMPLETED)) {
+            return "宸插畬鎴�";
+        }
+        if (Objects.equals(status, ORDER_STATUS_PAUSED)) {
+            return "宸叉殏鍋�";
+        }
+        return "鏈煡";
+    }
+
+    private Map<String, BigDecimal> loadOutputStats(LocalDate startDate, LocalDate endDateExclusive) {
+        String start = startDate.atStartOfDay().format(DATE_TIME_FORMATTER);
+        String end = endDateExclusive.atStartOfDay().format(DATE_TIME_FORMATTER);
+
+        BigDecimal quantity = BigDecimal.ZERO;
+        BigDecimal scrapQty = BigDecimal.ZERO;
+        List<Map<String, Object>> rows = productionProductOutputMapper.selectDailyOutputStats(start, end);
+        if (rows != null) {
+            for (Map<String, Object> row : rows) {
+                quantity = quantity.add(toBigDecimal(row.get("quantity")));
+                scrapQty = scrapQty.add(toBigDecimal(row.get("scrapQty")));
+            }
+        }
+
+        Map<String, BigDecimal> stats = new LinkedHashMap<>();
+        stats.put("quantity", quantity);
+        stats.put("scrapQty", scrapQty);
+        return stats;
+    }
+
+    private BigDecimal calcDeviceOee(LocalDate day) {
+        long totalDeviceCount = deviceLedgerMapper.selectCount(new LambdaQueryWrapper<>());
+        if (totalDeviceCount <= 0) {
+            return BigDecimal.ZERO;
+        }
+
+        Date start = Date.from(day.atStartOfDay(ZoneId.systemDefault()).toInstant());
+        Date end = Date.from(day.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
+
+        List<DeviceRepair> repairList = deviceRepairMapper.selectList(new LambdaQueryWrapper<DeviceRepair>()
+                .select(DeviceRepair::getDeviceLedgerId)
+                .ge(DeviceRepair::getRepairTime, start)
+                .lt(DeviceRepair::getRepairTime, end)
+                .in(DeviceRepair::getStatus, 0, 3));
+
+        long repairingDeviceCount = repairList == null ? 0 : repairList.stream()
+                .map(DeviceRepair::getDeviceLedgerId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .count();
+
+        long availableDeviceCount = Math.max(totalDeviceCount - repairingDeviceCount, 0);
+        return new BigDecimal(availableDeviceCount)
+                .multiply(new BigDecimal("100"))
+                .divide(new BigDecimal(totalDeviceCount), 2, RoundingMode.HALF_UP);
+    }
+
+    private BigDecimal calcOrderAchievementRate(LocalDate day) {
+        List<ProductionOrder> orderList = productionOrderMapper.selectList(new LambdaQueryWrapper<ProductionOrder>()
+                .select(ProductionOrder::getQuantity, ProductionOrder::getCompleteQuantity)
+                .ge(ProductionOrder::getCreateTime, day.atStartOfDay())
+                .lt(ProductionOrder::getCreateTime, day.plusDays(1).atStartOfDay())
+                .ne(ProductionOrder::getStatus, ORDER_STATUS_PAUSED));
+
+        BigDecimal totalQuantity = BigDecimal.ZERO;
+        BigDecimal totalCompleteQuantity = BigDecimal.ZERO;
+        if (orderList != null) {
+            for (ProductionOrder order : orderList) {
+                totalQuantity = totalQuantity.add(zeroIfNull(order.getQuantity()));
+                totalCompleteQuantity = totalCompleteQuantity.add(zeroIfNull(order.getCompleteQuantity()));
+            }
+        }
+        return calcRate(totalCompleteQuantity, totalQuantity);
+    }
+
+    private BigDecimal calcDefectRate(LocalDate day) {
+        Map<String, BigDecimal> stats = loadOutputStats(day, day.plusDays(1));
+        BigDecimal quantity = stats.get("quantity");
+        BigDecimal scrapQty = stats.get("scrapQty");
+        return calcRate(scrapQty, quantity.add(scrapQty));
+    }
+
+    private Map<String, Object> buildRealtimeMetric(BigDecimal value, BigDecimal change) {
+        Map<String, Object> metric = new LinkedHashMap<>();
+        metric.put("value", scale(value));
+        metric.put("compareYesterday", scale(change));
+        return metric;
+    }
+
+    private BigDecimal calcRate(BigDecimal numerator, BigDecimal denominator) {
+        if (denominator == null || denominator.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+        return zeroIfNull(numerator)
+                .multiply(new BigDecimal("100"))
+                .divide(denominator, 2, RoundingMode.HALF_UP);
+    }
+
+    private BigDecimal toBigDecimal(Object value) {
+        if (value == null) {
+            return BigDecimal.ZERO;
+        }
+        if (value instanceof BigDecimal) {
+            return (BigDecimal) value;
+        }
+        if (value instanceof Number) {
+            return BigDecimal.valueOf(((Number) value).doubleValue());
+        }
+        try {
+            return new BigDecimal(String.valueOf(value));
+        } catch (Exception ex) {
+            return BigDecimal.ZERO;
+        }
+    }
+
+    private Integer toInteger(Object value) {
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Integer) {
+            return (Integer) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).intValue();
+        }
+        try {
+            return Integer.valueOf(String.valueOf(value));
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    private long toLong(Object value) {
+        if (value == null) {
+            return 0L;
+        }
+        if (value instanceof Long) {
+            return (Long) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).longValue();
+        }
+        try {
+            return Long.parseLong(String.valueOf(value));
+        } catch (Exception ex) {
+            return 0L;
+        }
+    }
+
+    private LocalDate parseDateOrNull(String rawDate) {
+        if (isBlank(rawDate)) {
+            return null;
+        }
+        try {
+            return LocalDate.parse(rawDate.trim(), DATE_FORMATTER);
+        } catch (DateTimeParseException ex) {
+            return null;
+        }
+    }
+
+    private boolean isBlank(String value) {
+        return value == null || value.trim().isEmpty();
+    }
+
+    private BigDecimal zeroIfNull(BigDecimal value) {
+        return value == null ? BigDecimal.ZERO : value;
+    }
+
+    private BigDecimal scale(BigDecimal value) {
+        return zeroIfNull(value).setScale(2, RoundingMode.HALF_UP);
     }
 
 }
diff --git a/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java b/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
index e01927c..a17c012 100644
--- a/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
+++ b/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -3,9 +3,8 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
-import com.ruoyi.account.mapper.AccountExpenseMapper;
-import com.ruoyi.account.mapper.AccountIncomeMapper;
-import com.ruoyi.account.pojo.AccountExpense;
+import com.ruoyi.account.mapper.purchase.AccountPurchasePaymentMapper;
+import com.ruoyi.account.mapper.sales.AccountSalesCollectionMapper;
 import com.ruoyi.approve.mapper.ApproveProcessMapper;
 import com.ruoyi.approve.pojo.ApproveProcess;
 import com.ruoyi.basic.mapper.CustomerMapper;
@@ -30,18 +29,14 @@
 import com.ruoyi.production.mapper.*;
 import com.ruoyi.project.system.domain.SysDept;
 import com.ruoyi.project.system.mapper.SysDeptMapper;
-import com.ruoyi.purchase.mapper.PaymentRegistrationMapper;
 import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
-import com.ruoyi.purchase.pojo.PaymentRegistration;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
 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.sales.mapper.ReceiptPaymentMapper;
 import com.ruoyi.sales.mapper.SalesLedgerMapper;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.pojo.ReceiptPayment;
 import com.ruoyi.sales.pojo.SalesLedger;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.staff.mapper.StaffOnJobMapper;
@@ -83,10 +78,6 @@
 
     private final ApproveProcessMapper approveProcessMapper;
 
-    private final ReceiptPaymentMapper receiptPaymentMapper;
-
-    private final PaymentRegistrationMapper paymentRegistrationMapper;
-
     private final SysDeptMapper sysDeptMapper;
 
     private final NoticeMapper noticeMapper;
@@ -111,9 +102,8 @@
 
     private final ProductionOperationTaskMapper productionOperationTaskMapper;
 
-    private final AccountExpenseMapper accountExpenseMapper;
-
-    private final AccountIncomeMapper accountIncomeMapper;
+    private final AccountPurchasePaymentMapper accountPurchasePaymentMapper;
+    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
 
     private final ProductionAccountMapper productionAccountMapper;
 
@@ -141,12 +131,8 @@
                             salesLedgers.stream().map(SalesLedger::getId).collect(Collectors.toList()));
             List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper
                     .selectList(salesLedgerProductMapperLambdaQueryWrapper);
-            // 鏈紑绁ㄩ噾棰�
-            BigDecimal noInvoiceAmountTotal = salesLedgerProducts.stream().map(SalesLedgerProduct::getNoInvoiceAmount)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
             homeBusinessDto.setMonthSaleMoney(contractAmount.setScale(2, RoundingMode.HALF_UP).toString());
-            homeBusinessDto.setMonthSaleHaveMoney(noInvoiceAmountTotal.setScale(2, RoundingMode.HALF_UP).toString());
+            homeBusinessDto.setMonthSaleHaveMoney(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP).toString());
         }
         // 鍒涘缓LambdaQueryWrapper
         LambdaQueryWrapper<PurchaseLedger> queryWrapper = new LambdaQueryWrapper<>();
@@ -169,14 +155,8 @@
                     .filter(Objects::nonNull)
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
 
-            //  寰呬粯娆炬�婚噾棰�
-            BigDecimal unReceiptPaymentAmount = salesLedgerProductsCopy.stream()
-                    .map(SalesLedgerProduct::getPendingTicketsTotal)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-
             homeBusinessDto.setMonthPurchaseMoney(receiveAmount.setScale(2, RoundingMode.HALF_UP).toString());
-            homeBusinessDto.setMonthPurchaseHaveMoney(unReceiptPaymentAmount.setScale(2, RoundingMode.HALF_UP).toString());
+            homeBusinessDto.setMonthPurchaseHaveMoney(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP).toString());
         }
         // 缁熻搴撳瓨
         BigDecimal stockQuantityTotal = stockInventoryMapper.selectTotal();
@@ -414,6 +394,7 @@
      */
     @Override
     public StatisticsReceivablePayableDto statisticsReceivablePayable(Integer type) {
+        StatisticsReceivablePayableDto statisticsReceivablePayableDto = new StatisticsReceivablePayableDto();
         LocalDate today = LocalDate.now();
         LocalDate startDate = null;
         LocalDate endDate = null;
@@ -440,48 +421,14 @@
                 break;
         }
         // 搴旀敹
-        List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>()
-                // .ge(SalesLedger::getEntryDate, startDate)
-                // .lt(SalesLedger::getEntryDate, endDate)
-        );
-        // BigDecimal receivableMoney =
-        // salesLedgers.stream().map(SalesLedger::getContractAmount).reduce(BigDecimal.ZERO,
-        // BigDecimal::add);
-        BigDecimal receivableMoney = sumAmount(salesLedgers, SalesLedger::getContractAmount);
+
         // 搴斾粯
-        List<PurchaseLedger> procurementRecords = purchaseLedgerMapper
-                .selectList(new LambdaQueryWrapper<PurchaseLedger>()
-                        // .ge(PurchaseLedger::getEntryDate, startDate)
-                        // .lt(PurchaseLedger::getEntryDate, endDate)
-                );
-        // BigDecimal payableMoney =
-        // procurementRecords.stream().map(PurchaseLedger::getContractAmount).reduce(BigDecimal.ZERO,
-        // BigDecimal::add);
-        BigDecimal payableMoney = sumAmount(procurementRecords, PurchaseLedger::getContractAmount);
+
         // 棰勬敹
-        List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(new LambdaQueryWrapper<ReceiptPayment>()
-                // .ge(ReceiptPayment::getReceiptPaymentDate, startDate)
-                // .lt(ReceiptPayment::getReceiptPaymentDate, endDate)
-        );
-        // BigDecimal advanceMoney =
-        // receiptPayments.stream().map(ReceiptPayment::getReceiptPaymentAmount).reduce(BigDecimal.ZERO,
-        // BigDecimal::add);
-        BigDecimal advanceMoney = sumAmount(receiptPayments, ReceiptPayment::getReceiptPaymentAmount);
+
         // 棰勪粯
-        List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper
-                .selectList(new LambdaQueryWrapper<PaymentRegistration>()
-                        // .ge(PaymentRegistration::getPaymentDate, startDate)
-                        // .lt(PaymentRegistration::getPaymentDate, endDate)
-                );
-        // BigDecimal prepayMoney =
-        // paymentRegistrations.stream().map(PaymentRegistration::getCurrentPaymentAmount).reduce(BigDecimal.ZERO,
-        // BigDecimal::add);
-        BigDecimal prepayMoney = sumAmount(paymentRegistrations, PaymentRegistration::getCurrentPaymentAmount);
-        StatisticsReceivablePayableDto statisticsReceivablePayableDto = new StatisticsReceivablePayableDto();
-        statisticsReceivablePayableDto.setPayableMoney(payableMoney.subtract(prepayMoney));
-        statisticsReceivablePayableDto.setReceivableMoney(receivableMoney.subtract(advanceMoney));
-        statisticsReceivablePayableDto.setAdvanceMoney(advanceMoney);
-        statisticsReceivablePayableDto.setPrepayMoney(prepayMoney);
+
+
 
         return statisticsReceivablePayableDto;
     }
@@ -1164,13 +1111,9 @@
         String endStr = endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 
         // 2. 鏌ヨ鏁版嵁
-        List<IncomeExpenseAnalysisDto> incomeList = accountIncomeMapper.selectIncomeStats(startStr, endStr, dateFormat);
+        List<IncomeExpenseAnalysisDto> incomeList = accountSalesCollectionMapper.selectIncomeStats(startStr, endStr, dateFormat);
+        List<IncomeExpenseAnalysisDto> expenseList = accountPurchasePaymentMapper.selectPayment(startStr, endStr, dateFormat);
 
-        // List<IncomeExpenseAnalysisDto> purchaseList =
-        // purchaseLedgerMapper.selectPurchaseStats(startStr, endStr, dateFormat);
-
-        List<IncomeExpenseAnalysisDto> expenseList = accountExpenseMapper.selectAccountExpenseStats(startStr, endStr,
-                dateFormat);
 
         // 3. 杞� Map锛堣嚜鍔ㄥ悎骞讹級
         Map<String, BigDecimal> incomeMap = incomeList.stream()
@@ -1179,11 +1122,7 @@
                         IncomeExpenseAnalysisDto::getAmount,
                         BigDecimal::add));
 
-        // Map<String, BigDecimal> purchaseMap = purchaseList.stream()
-        // .collect(Collectors.toMap(
-        // IncomeExpenseAnalysisDto::getDateStr,
-        // IncomeExpenseAnalysisDto::getAmount,
-        // BigDecimal::add));
+
 
         Map<String, BigDecimal> expenseMap = expenseList.stream()
                 .collect(Collectors.toMap(
@@ -1197,18 +1136,12 @@
         for (String dateStr : xAxis) {
             Map<String, Object> item = new HashMap<>();
             item.put("date", dateStr);
-
             // 鏀跺叆
             BigDecimal income = incomeMap.getOrDefault(dateStr, BigDecimal.ZERO);
             item.put("income", income.setScale(2, RoundingMode.HALF_UP));
-
-            // 鏀嚭 = 閲囪喘 + 璐㈠姟鏀嚭
-            // BigDecimal purchase = purchaseMap.getOrDefault(dateStr, BigDecimal.ZERO);
+            // 鏀嚭
             BigDecimal expense = expenseMap.getOrDefault(dateStr, BigDecimal.ZERO);
-            // BigDecimal totalExpense = purchase.add(expense);
-            BigDecimal totalExpense = expense;
-
-            item.put("expense", totalExpense.setScale(2, RoundingMode.HALF_UP));
+            item.put("expense", expense.setScale(2, RoundingMode.HALF_UP));
 
             result.add(item);
         }
@@ -1235,8 +1168,8 @@
         String startStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
         String endStr = endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 
-        List<IncomeExpenseAnalysisDto> incomeList = accountIncomeMapper.selectIncomeStats(startStr, endStr, dateFormat);
-        List<IncomeExpenseAnalysisDto> expenseList = accountExpenseMapper.selectAccountExpenseStats(startStr, endStr, dateFormat);
+        List<IncomeExpenseAnalysisDto> incomeList = accountSalesCollectionMapper.selectIncomeStats(startStr, endStr, dateFormat);
+        List<IncomeExpenseAnalysisDto> expenseList = accountPurchasePaymentMapper.selectPayment(startStr, endStr, dateFormat);
 
         Map<String, BigDecimal> incomeMap = incomeList.stream().collect(Collectors
                 .toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
@@ -1272,11 +1205,6 @@
             rawMaterialDto.setName("鍘熸潗鏂�");
             rawMaterialDto.setValue(rawMaterialAmount != null ? rawMaterialAmount.toString() : "0");
             result.add(rawMaterialDto);
-
-            List<MapDto> expenseList = accountExpenseMapper.selectExpenseComposition(null, null);
-            if (expenseList != null) {
-                result.addAll(expenseList);
-            }
         }
 
         BigDecimal total = BigDecimal.ZERO;
@@ -1327,34 +1255,6 @@
             return dto;
         }
 
-        BigDecimal collected = products.stream()
-                .map(SalesLedgerProduct::getInvoiceTotal)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        dto.setMonthlyIncome(collected);
-
-        BigDecimal overdue = products.stream()
-                .map(SalesLedgerProduct::getPendingInvoiceTotal)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        dto.setOverdueNum(overdue);
-
-        BigDecimal total = collected.add(overdue);
-
-        if (total.compareTo(BigDecimal.ZERO) > 0) {
-            String collectionRate = collected.divide(total, 4, RoundingMode.HALF_UP)
-                    .multiply(new BigDecimal("100"))
-                    .setScale(2, RoundingMode.HALF_UP)
-                    .toString();
-            dto.setCollectionRate(collectionRate);
-
-            String overdueRate = overdue.divide(total, 4, RoundingMode.HALF_UP)
-                    .multiply(new BigDecimal("100"))
-                    .setScale(2, RoundingMode.HALF_UP)
-                    .toString();
-            dto.setOverdueRate(overdueRate);
-        }
-
         return dto;
     }
 
@@ -1386,38 +1286,14 @@
                 if (p.getTaxInclusiveTotalPrice() != null) {
                     rawMaterialCost = rawMaterialCost.add(p.getTaxInclusiveTotalPrice());
                 }
-
-                if (p.getTicketsTotal() != null) {
-                    paidAmount = paidAmount.add(p.getTicketsTotal());
-                }
-
-                if (p.getPendingTicketsTotal() != null) {
-                    pendingAmount = pendingAmount.add(p.getPendingTicketsTotal());
-                }
             }
         }
 
         // 鍏朵粬璐圭敤
-        LambdaQueryWrapper<AccountExpense> expenseWrapper = new LambdaQueryWrapper<>();
-        expenseWrapper.ge(AccountExpense::getExpenseDate,
-                java.sql.Date.valueOf(currentMonth.atDay(1)));
-        expenseWrapper.le(AccountExpense::getExpenseDate,
-                java.sql.Date.valueOf(currentMonth.atEndOfMonth()));
 
-        List<AccountExpense> expenses = accountExpenseMapper.selectList(expenseWrapper);
-
-        BigDecimal otherExpense = BigDecimal.ZERO;
-        if (!CollectionUtils.isEmpty(expenses)) {
-            for (AccountExpense e : expenses) {
-                if (e.getExpenseMoney() != null) {
-                    otherExpense = otherExpense.add(e.getExpenseMoney());
-                }
-            }
-        }
 
         // 鏈堝害鎬绘敮鍑�
-        // BigDecimal monthlyExpenditure = rawMaterialCost.add(otherExpense);
-        BigDecimal monthlyExpenditure = otherExpense;
+        BigDecimal monthlyExpenditure = BigDecimal.ZERO;
         dto.setMonthlyExpenditure(monthlyExpenditure);
 
         // 宸蹭粯娆� 梅锛堝凡浠樻 + 寰呬粯娆撅級
@@ -1440,13 +1316,6 @@
         List<SalesLedgerProduct> salesProducts = salesLedgerProductMapper.selectList(salesWrapper);
 
         BigDecimal revenue = BigDecimal.ZERO;
-        if (!CollectionUtils.isEmpty(salesProducts)) {
-            for (SalesLedgerProduct s : salesProducts) {
-                if (s.getInvoiceAmount() != null) {
-                    revenue = revenue.add(s.getInvoiceAmount());
-                }
-            }
-        }
 
         // 姣涘埄娑� & 鍒╂鼎鐜�
         if (revenue.compareTo(BigDecimal.ZERO) > 0) {
diff --git a/src/main/java/com/ruoyi/procurementrecord/controller/ReturnManagementController.java b/src/main/java/com/ruoyi/procurementrecord/controller/ReturnManagementController.java
index b3f31b9..6387006 100644
--- a/src/main/java/com/ruoyi/procurementrecord/controller/ReturnManagementController.java
+++ b/src/main/java/com/ruoyi/procurementrecord/controller/ReturnManagementController.java
@@ -3,11 +3,16 @@
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.pojo.AccountStatementDetails;
+import com.ruoyi.account.service.AccountStatementDetailsService;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.framework.web.controller.BaseController;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.procurementrecord.bean.dto.ReturnManagementDto;
 import com.ruoyi.procurementrecord.bean.vo.ShippingInfoVo;
+import com.ruoyi.procurementrecord.pojo.ReturnManagement;
 import com.ruoyi.procurementrecord.pojo.ReturnSaleProduct;
 import com.ruoyi.procurementrecord.service.ReturnManagementService;
 import com.ruoyi.procurementrecord.service.ReturnSaleProductService;
@@ -31,6 +36,7 @@
 
     private ReturnManagementService returnManagementService;
     private ReturnSaleProductService returnSaleProductService;
+    private final AccountStatementDetailsService accountStatementDetailsService;
 
     @GetMapping("/listPage")
     @Operation(summary = "閿�鍞��璐�-鏌ヨ")
@@ -67,6 +73,14 @@
     @Transactional(rollbackFor = Exception.class)
     public AjaxResult del(@RequestBody List<Long> ids) {
         if (CollectionUtils.isEmpty(ids)) return error("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
+        //濡傛灉璇ラ攢鍞��璐у凡缁忕敓鎴愬璐﹀崟鍒欐棤娉曞垹闄�
+        List<ReturnManagement> returnManagements = returnManagementService.listByIds(ids);
+        List<String> strings = returnManagements.stream().map(ReturnManagement::getReturnNo).toList();
+        List<AccountStatementDetails> accountStatementDetails = accountStatementDetailsService.list(Wrappers.<AccountStatementDetails>lambdaQuery()
+                .in(AccountStatementDetails::getReceiptNumber, strings));
+        if (CollectionUtils.isNotEmpty(accountStatementDetails)){
+            throw new ServiceException("璇ラ攢鍞��璐у崟宸茬粡鐢熸垚瀵硅处鍗曪紝鏃犳硶鍒犻櫎");
+        }
         returnSaleProductService.remove(new QueryWrapper<ReturnSaleProduct>()
                 .lambda()
                 .in(ReturnSaleProduct::getReturnManagementId, ids));
diff --git a/src/main/java/com/ruoyi/procurementrecord/mapper/ReturnManagementMapper.java b/src/main/java/com/ruoyi/procurementrecord/mapper/ReturnManagementMapper.java
index 815559c..e0eae1a 100644
--- a/src/main/java/com/ruoyi/procurementrecord/mapper/ReturnManagementMapper.java
+++ b/src/main/java/com/ruoyi/procurementrecord/mapper/ReturnManagementMapper.java
@@ -3,8 +3,8 @@
 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.account.bean.dto.SalesReturnDto;
-import com.ruoyi.account.bean.vo.SalesReturnVo;
+import com.ruoyi.account.bean.dto.sales.SalesReturnDto;
+import com.ruoyi.account.bean.vo.sales.SalesReturnVo;
 import com.ruoyi.procurementrecord.bean.dto.ReturnManagementDto;
 import com.ruoyi.procurementrecord.pojo.ReturnManagement;
 import org.apache.ibatis.annotations.Param;
diff --git a/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java b/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java
index b4701f6..5834e65 100644
--- a/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java
+++ b/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java
@@ -4,8 +4,6 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.account.bean.dto.SalesRefundAmountOrderDto;
-import com.ruoyi.account.mapper.AccountExpenseMapper;
-import com.ruoyi.account.pojo.AccountExpense;
 import com.ruoyi.account.service.SalesRefundAmountOrderService;
 import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
 import com.ruoyi.common.utils.OrderUtils;
@@ -31,7 +29,6 @@
 import org.springframework.util.ObjectUtils;
 
 import java.math.BigDecimal;
-import java.util.Date;
 import java.util.List;
 
 /**
@@ -49,7 +46,6 @@
     private final SalesLedgerMapper salesLedgerMapper;
     private final SalesRefundAmountOrderService salesRefundAmountOrderService;
     private final StockUtils stockUtils;
-    private final AccountExpenseMapper accountExpenseMapper;
 
     @Override
     public IPage<ReturnManagementDto> listPage(Page page, ReturnManagementDto returnManagement) {
@@ -127,19 +123,6 @@
         salesRefundAmountOrder.setNotRefundedAmount(salesRefundAmountOrder.getRefundedAmount());
         // 鍒嗘壒閫�娆�
 //        salesRefundAmountOrderService.addSalesRefundAmountOrderDto(salesRefundAmountOrder);
-        // 鍜岃储鍔¤仈鍔紝鏂板鏀嚭
-        AccountExpense accountExpense = new AccountExpense();
-        accountExpense.setBusinessType(3);
-        accountExpense.setExpenseMoney(byId.getRefundAmount());
-        accountExpense.setBusinessId(byId.getId());
-        accountExpense.setExpenseDate(new Date());
-        accountExpense.setExpenseMethod("3");
-        accountExpense.setExpenseType("5");
-        accountExpense.setExpenseDescribed("閿�鍞��璐ч��娆�");
-        accountExpense.setNote(byId.getReturnReason());
-        accountExpense.setInputUser(SecurityUtils.getLoginUser().getNickName());
-        accountExpense.setInputTime(new Date());
-        accountExpenseMapper.insert(accountExpense);
         return true;
     }
 
diff --git a/src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java b/src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java
index 965cbf3..8a75dcd 100644
--- a/src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java
+++ b/src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java
@@ -44,4 +44,7 @@
     @Schema(description = "缁撴潫鏃ユ湡")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
     private LocalDate endDate;
+
+    @Schema(description = "鏄惁鐢熶骇")
+    private Integer isProduction;
 }
diff --git a/src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java b/src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java
index e52df0c..cec7ca5 100644
--- a/src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java
+++ b/src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java
@@ -12,6 +12,7 @@
 
 import java.time.LocalDateTime;
 import java.util.List;
+import java.util.Map;
 
 /**
  * <p>
@@ -39,4 +40,24 @@
 
     Integer countPending(@Param("startDate") String startDate, @Param("endDate") String endDate);
 
+    List<Map<String, Object>> selectHomeOrderProgressPage(@Param("status") Integer status,
+                                                          @Param("offset") Long offset,
+                                                          @Param("size") Long size,
+                                                          @Param("startTime") LocalDateTime startTime,
+                                                          @Param("endTime") LocalDateTime endTime);
+
+    Long countHomeOrderProgress(@Param("status") Integer status,
+                                @Param("startTime") LocalDateTime startTime,
+                                @Param("endTime") LocalDateTime endTime);
+
+    List<Map<String, Object>> countHomeOrderProgressByStatus(@Param("startTime") LocalDateTime startTime,
+                                                              @Param("endTime") LocalDateTime endTime);
+
+    List<Map<String, Object>> selectHomeTodayProductionPlan(@Param("size") Long size,
+                                                             @Param("planStart") LocalDateTime planStart,
+                                                             @Param("planEnd") LocalDateTime planEnd);
+
+    Long countHomeTodayProductionPlan(@Param("planStart") LocalDateTime planStart,
+                                      @Param("planEnd") LocalDateTime planEnd);
+
 }
diff --git a/src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java b/src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java
index eb2c07e..61cf73c 100644
--- a/src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java
+++ b/src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java
@@ -8,6 +8,8 @@
 
     R addRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
 
+    R updateRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
+
     R deleteRouteItem(Long id);
 
     int sortRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
index 31cdc79..c6256a8 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -23,6 +23,7 @@
 import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
 import com.ruoyi.production.pojo.ProductionProductMain;
 import com.ruoyi.production.service.ProductionBomStructureService;
+import com.ruoyi.production.util.TaskPlanQuantityUtil;
 import com.ruoyi.technology.mapper.TechnologyOperationMapper;
 import com.ruoyi.technology.mapper.TechnologyOperationParamMapper;
 import com.ruoyi.technology.mapper.TechnologyParamMapper;
@@ -262,7 +263,7 @@
                 .filter(item -> item != null && item.getId() != null)
                 .collect(Collectors.toMap(ProductionOrderRoutingOperation::getId, item -> item, (left, right) -> left));
         // Keep task plan quantities aligned with the same order BOM snapshot demand used during snapshot creation.
-        Map<String, BigDecimal> demandedQuantityMap = buildOperationDemandedQuantityMap(structureList, rootProductModelId);
+        Map<String, BigDecimal> demandedQuantityMap = TaskPlanQuantityUtil.buildOperationDemandedQuantityMap(structureList, rootProductModelId);
         for (ProductionOperationTask task : taskList) {
             if (task == null || task.getId() == null || task.getProductionOrderRoutingOperationId() == null) {
                 continue;
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
index 502384d..75d0696 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
@@ -4,21 +4,15 @@
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.framework.web.domain.R;
-import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
-import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
-import com.ruoyi.production.mapper.ProductionOrderRoutingOperationParamMapper;
-import com.ruoyi.production.mapper.ProductionProductMainMapper;
-import com.ruoyi.production.pojo.ProductionOperationTask;
-import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
-import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
-import com.ruoyi.production.pojo.ProductionProductMain;
+import com.ruoyi.production.mapper.*;
+import com.ruoyi.production.util.TaskPlanQuantityUtil;
+import com.ruoyi.technology.mapper.*;
+import com.ruoyi.production.pojo.*;
 import com.ruoyi.production.service.ProductionOrderRoutingOperationService;
 import com.ruoyi.production.service.ProductionProductMainService;
-import com.ruoyi.technology.mapper.TechnologyOperationParamMapper;
-import com.ruoyi.technology.mapper.TechnologyParamMapper;
-import com.ruoyi.technology.pojo.TechnologyOperationParam;
-import com.ruoyi.technology.pojo.TechnologyParam;
+import com.ruoyi.technology.pojo.*;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -26,8 +20,7 @@
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
 
 @Service
 @Transactional(rollbackFor = Exception.class)
@@ -42,6 +35,11 @@
     private final TechnologyOperationParamMapper technologyOperationParamMapper;
     private final TechnologyParamMapper technologyParamMapper;
     private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
+    private final ProductionOrderMapper productionOrderMapper;
+    private final ProductionOrderRoutingMapper productionOrderRoutingMapper;
+    private final ProductionOrderBomMapper productionOrderBomMapper;
+    private final ProductionBomStructureMapper productionBomStructureMapper;
+    private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
 
     @Override
     public R addRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
@@ -102,6 +100,109 @@
             productionOperationTaskMapper.insert(productionOperationTask);
         }
         return R.ok();
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public R updateRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
+        Long operationId = productionOrderRoutingOperation.getId();
+
+        // 鏇存柊宸ヨ壓璺嚎宸ュ簭
+        productionOrderRoutingOperationMapper.updateById(productionOrderRoutingOperation);
+
+        // 閲嶆柊鏌ヨ瀹屾暣璁板綍锛堝墠绔彲鑳芥病鏈変紶閫掓墍鏈夊瓧娈碉紝濡� productionOrderId锛�
+        ProductionOrderRoutingOperation updatedOperation = productionOrderRoutingOperationMapper.selectById(operationId);
+        if (updatedOperation == null) {
+            throw new ServiceException("宸ヨ壓璺嚎宸ュ簭涓嶅瓨鍦�");
+        }
+
+        // 鏌ヨ鏄惁瀛樺湪宸ュ崟
+        ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectOne(
+                new LambdaQueryWrapper<ProductionOperationTask>()
+                        .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, operationId)
+                        .last("limit 1"));
+
+        // 鏍规嵁鏄惁闇�瑕佺敓浜ц繘琛屽鐞�
+        Boolean isProduction = updatedOperation.getIsProduction();
+
+        if (Boolean.TRUE.equals(isProduction)) {
+            // 闇�瑕佺敓浜э細妫�鏌ュ伐鍗曟槸鍚﹀瓨鍦紝涓嶅瓨鍦ㄥ垯鐢熸垚
+            if (productionOperationTask == null) {
+                ProductionOperationTask task = new ProductionOperationTask();
+                task.setProductionOrderRoutingOperationId(updatedOperation.getId());
+                task.setProductionOrderId(updatedOperation.getProductionOrderId());
+                // 鑾峰彇鐢熶骇璁㈠崟
+                ProductionOrder productionOrder = productionOrderMapper.selectById(updatedOperation.getProductionOrderId());
+                if (productionOrder == null) {
+                    throw new ServiceException("鐢熶骇璁㈠崟涓嶅瓨鍦�");
+                }
+
+                // 鑾峰彇璁㈠崟BOM
+                ProductionOrderBom orderBom = productionOrderBomMapper.selectOne(
+                        Wrappers.<ProductionOrderBom>lambdaQuery()
+                                .eq(ProductionOrderBom::getProductionOrderId, productionOrder.getId()));
+
+                // 纭畾鏍逛骇鍝佽鏍糏D
+                Long rootProductModelId = orderBom != null && orderBom.getProductModelId() != null
+                        ? orderBom.getProductModelId()
+                        : productionOrder.getProductModelId();
+
+                // 鑾峰彇BOM缁撴瀯鍒楄〃
+                List<ProductionBomStructure> orderBomStructureList = orderBom == null || orderBom.getId() == null
+                        ? Collections.emptyList()
+                        : productionBomStructureMapper.selectList(
+                        Wrappers.<ProductionBomStructure>lambdaQuery()
+                                .eq(ProductionBomStructure::getProductionOrderBomId, orderBom.getId())
+                                .orderByAsc(ProductionBomStructure::getId));
+
+                // 鏋勫缓宸ュ簭闇�姹傞噺鏄犲皠
+                Map<String, BigDecimal> operationDemandedQuantityMap =
+                        TaskPlanQuantityUtil.buildOperationDemandedQuantityMap(orderBomStructureList, rootProductModelId);
+
+                // 鑾峰彇宸ヨ壓璺嚎宸ュ簭锛堢敤浜庤绠楄鍒掓暟閲忥級
+                TechnologyRoutingOperation sourceOperation = technologyRoutingOperationMapper.selectById(
+                        updatedOperation.getTechnologyRoutingOperationId());
+                // 灏嗗師鏉ョ殑绉佹湁鏂规硶鏇挎崲涓鸿皟鐢ㄥ伐鍏风被
+                BigDecimal planQuantity = TaskPlanQuantityUtil.resolveTaskPlanQuantity(
+                        sourceOperation,
+                        operationDemandedQuantityMap,
+                        productionOrder,
+                        rootProductModelId);
+                task.setPlanQuantity(planQuantity);
+                task.setCompleteQuantity(BigDecimal.ZERO);
+                task.setWorkOrderNo(generateNextTaskNo());
+                task.setStatus(2);
+                productionOperationTaskMapper.insert(task);
+            }
+        } else {
+            // 涓嶉渶瑕佺敓浜э細妫�鏌ュ伐鍗曟槸鍚﹀瓨鍦�
+            if (productionOperationTask != null) {
+                validateTaskCanRemove(productionOperationTask);
+                // 娌℃湁鎶ュ伐锛屽垯鍒犻櫎宸ュ崟
+                productionOperationTaskMapper.deleteById(productionOperationTask.getId());
+            }
+        }
+
+        return R.ok();
+    }
+
+    private void validateTaskCanRemove(ProductionOperationTask task) {
+        if (task == null || task.getId() == null) {
+            return;
+        }
+        if (defaultDecimal(task.getCompleteQuantity()).compareTo(BigDecimal.ZERO) > 0) {
+            throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ簭蹇収");
+        }
+        long reportCount = productionProductMainMapper.selectCount(
+                Wrappers.<ProductionProductMain>lambdaQuery()
+                        .eq(ProductionProductMain::getProductionOperationTaskId, task.getId()));
+        if (reportCount > 0) {
+            throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ崟");
+        }
+    }
+
+    private BigDecimal defaultDecimal(BigDecimal value) {
+        return value == null ? BigDecimal.ZERO : value;
     }
 
     @Override
@@ -183,10 +284,23 @@
         return 0;
     }
 
-    @Override
-    public Boolean updateRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
-        //鏍规嵁鏄惁鐢熶骇鍒ゆ柇鏄惁闇�瑕佸垹闄ゅ搴旂殑宸ュ崟
-
-        return null;
+    private String generateNextTaskNo() {
+        // 鐢熸垚涓嬩竴涓敓浜у伐鍗曞彿
+        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+        String prefix = "GD" + datePrefix;
+        ProductionOperationTask lastTask = productionOperationTaskMapper.selectOne(
+                Wrappers.<ProductionOperationTask>lambdaQuery()
+                        .likeRight(ProductionOperationTask::getWorkOrderNo, prefix)
+                        .orderByDesc(ProductionOperationTask::getWorkOrderNo)
+                        .last("limit 1"));
+        int sequence = 1;
+        if (lastTask != null && lastTask.getWorkOrderNo() != null && lastTask.getWorkOrderNo().startsWith(prefix)) {
+            try {
+                sequence = Integer.parseInt(lastTask.getWorkOrderNo().substring(prefix.length())) + 1;
+            } catch (NumberFormatException ignored) {
+                sequence = 1;
+            }
+        }
+        return prefix + String.format("%03d", sequence);
     }
 }
diff --git a/src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java b/src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java
new file mode 100644
index 0000000..e82d7e4
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java
@@ -0,0 +1,137 @@
+package com.ruoyi.production.util;
+
+import com.ruoyi.production.pojo.ProductionBomStructure;
+import com.ruoyi.production.pojo.ProductionOrder;
+import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
+import com.ruoyi.technology.pojo.TechnologyRoutingOperation;
+import lombok.experimental.UtilityClass;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 宸ュ崟璁″垝鏁伴噺璁$畻宸ュ叿绫�
+ */
+@UtilityClass
+public class TaskPlanQuantityUtil {
+
+    /**
+     * 璁$畻宸ュ崟璁″垝鏁伴噺锛堜娇鐢� TechnologyRoutingOperation锛�
+     */
+    public BigDecimal resolveTaskPlanQuantity(TechnologyRoutingOperation sourceOperation,
+                                              Map<String, BigDecimal> operationDemandedQuantityMap,
+                                              ProductionOrder productionOrder,
+                                              Long rootProductModelId) {
+        if (sourceOperation == null || operationDemandedQuantityMap == null || operationDemandedQuantityMap.isEmpty()) {
+            return defaultDecimal(productionOrder == null ? null : productionOrder.getQuantity());
+        }
+        Long outputProductModelId = sourceOperation.getProductModelId() != null
+                ? sourceOperation.getProductModelId()
+                : rootProductModelId;
+        String key = buildOperationDemandedQuantityKey(sourceOperation.getTechnologyOperationId(), outputProductModelId);
+        BigDecimal planQuantity = operationDemandedQuantityMap.get(key);
+        return planQuantity != null ? planQuantity : defaultDecimal(productionOrder == null ? null : productionOrder.getQuantity());
+    }
+
+    /**
+     * 璁$畻宸ュ崟璁″垝鏁伴噺锛堜娇鐢� ProductionOrderRoutingOperation锛�
+     */
+    public BigDecimal resolveTaskPlanQuantity(ProductionOrderRoutingOperation routingOperation,
+                                              Map<String, BigDecimal> demandedQuantityMap,
+                                              BigDecimal orderQuantity,
+                                              Long rootProductModelId) {
+        if (routingOperation == null || demandedQuantityMap == null || demandedQuantityMap.isEmpty()) {
+            return orderQuantity;
+        }
+        Long outputProductModelId = routingOperation.getProductModelId() != null
+                ? routingOperation.getProductModelId()
+                : rootProductModelId;
+        String key = buildOperationDemandedQuantityKey(routingOperation.getTechnologyOperationId(), outputProductModelId);
+        BigDecimal planQuantity = demandedQuantityMap.get(key);
+        return planQuantity != null ? planQuantity : orderQuantity;
+    }
+
+    /**
+     * 鏋勫缓宸ュ簭闇�姹傞噺鏄犲皠琛�
+     */
+    public Map<String, BigDecimal> buildOperationDemandedQuantityMap(List<ProductionBomStructure> bomStructures, Long rootProductModelId) {
+        if (bomStructures == null || bomStructures.isEmpty()) {
+            return Collections.emptyMap();
+        }
+        Map<Long, ProductionBomStructure> structureById = new HashMap<>();
+        for (ProductionBomStructure item : bomStructures) {
+            if (item != null && item.getId() != null) {
+                structureById.put(item.getId(), item);
+            }
+        }
+        Map<String, BigDecimal> demandedQuantityMap = new HashMap<>();
+        Set<String> mergedOutputNodeKeySet = new HashSet<>();
+        for (ProductionBomStructure bomStructure : bomStructures) {
+            if (bomStructure == null || bomStructure.getTechnologyOperationId() == null) {
+                continue;
+            }
+            ProductionBomStructure outputNode = resolveOperationOutputNode(bomStructure, structureById);
+            Long outputProductModelId = resolveOutputProductModelId(outputNode, rootProductModelId);
+            if (outputProductModelId == null) {
+                continue;
+            }
+            String mergedOutputNodeKey = buildOperationOutputNodeKey(bomStructure.getTechnologyOperationId(),
+                    outputNode == null ? null : outputNode.getId(), outputProductModelId);
+            if (!mergedOutputNodeKeySet.add(mergedOutputNodeKey)) {
+                continue;
+            }
+            BigDecimal demandedQuantity = defaultDecimal(outputNode == null ? null : outputNode.getDemandedQuantity());
+            String key = buildOperationDemandedQuantityKey(bomStructure.getTechnologyOperationId(), outputProductModelId);
+            demandedQuantityMap.merge(key, demandedQuantity, BigDecimal::add);
+        }
+        return demandedQuantityMap;
+    }
+
+    /**
+     * 鏋勫缓宸ュ簭闇�姹傞噺key
+     */
+    public String buildOperationDemandedQuantityKey(Long operationId, Long outputProductModelId) {
+        return String.valueOf(operationId) + "#" + String.valueOf(outputProductModelId);
+    }
+
+    /**
+     * 鏋勫缓杈撳嚭鑺傜偣key
+     */
+    public String buildOperationOutputNodeKey(Long operationId, Long outputNodeId, Long outputProductModelId) {
+        return String.valueOf(operationId) + "#" + String.valueOf(outputNodeId) + "#" + String.valueOf(outputProductModelId);
+    }
+
+    /**
+     * 瑙f瀽宸ュ簭杈撳嚭鑺傜偣
+     */
+    public ProductionBomStructure resolveOperationOutputNode(ProductionBomStructure bomStructure,
+                                                             Map<Long, ProductionBomStructure> structureById) {
+        if (bomStructure == null) {
+            return null;
+        }
+        if (bomStructure.getParentId() == null) {
+            return bomStructure;
+        }
+        ProductionBomStructure parent = structureById.get(bomStructure.getParentId());
+        return parent != null ? parent : bomStructure;
+    }
+
+    /**
+     * 瑙f瀽杈撳嚭浜у搧瑙勬牸ID
+     */
+    public Long resolveOutputProductModelId(ProductionBomStructure outputNode, Long rootProductModelId) {
+        if (outputNode == null) {
+            return rootProductModelId;
+        }
+        return outputNode.getProductModelId() != null ? outputNode.getProductModelId() : rootProductModelId;
+    }
+
+    /**
+     * 榛樿BigDecimal鍊�
+     */
+    public BigDecimal defaultDecimal(BigDecimal value) {
+        return value == null ? BigDecimal.ZERO : value;
+    }
+
+}
diff --git a/src/main/java/com/ruoyi/project/common/CaptchaController.java b/src/main/java/com/ruoyi/project/common/CaptchaController.java
index 40255cb..5966fb5 100644
--- a/src/main/java/com/ruoyi/project/common/CaptchaController.java
+++ b/src/main/java/com/ruoyi/project/common/CaptchaController.java
@@ -1,98 +1,98 @@
-package com.ruoyi.project.common;
-
-import com.google.code.kaptcha.Producer;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.utils.sign.Base64;
-import com.ruoyi.common.utils.uuid.IdUtils;
-import com.ruoyi.framework.redis.RedisCache;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.project.system.service.ISysConfigService;
-import jakarta.annotation.Resource;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.RequiredArgsConstructor;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.util.FastByteArrayOutputStream;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-
-/**
- * 楠岃瘉鐮佹搷浣滃鐞�
- * 
- * @author ruoyi
- */
-@RestController
-@RequiredArgsConstructor
-public class CaptchaController
-{
-    @Resource(name = "captchaProducer")
-    private Producer captchaProducer;
-
-    @Resource(name = "captchaProducerMath")
-    private Producer captchaProducerMath;
-
-    private final RedisCache redisCache;
-    
-    // 楠岃瘉鐮佺被鍨�
-    @Value("${ruoyi.captchaType}")
-    private String captchaType;
-    
-    private final ISysConfigService configService;
-
-    /**
-     * 鐢熸垚楠岃瘉鐮�
-     */
-    @GetMapping("/captchaImage")
-    public AjaxResult getCode(HttpServletResponse response) throws IOException
-    {
-        AjaxResult ajax = AjaxResult.success();
-        boolean captchaEnabled = configService.selectCaptchaEnabled();
-        ajax.put("captchaEnabled", captchaEnabled);
-        if (!captchaEnabled)
-        {
-            return ajax;
-        }
-
-        // 淇濆瓨楠岃瘉鐮佷俊鎭�
-        String uuid = IdUtils.simpleUUID();
-        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
-
-        String capStr = null, code = null;
-        BufferedImage image = null;
-
-        // 鐢熸垚楠岃瘉鐮�
-        if ("math".equals(captchaType))
-        {
-            String capText = captchaProducerMath.createText();
-            capStr = capText.substring(0, capText.lastIndexOf("@"));
-            code = capText.substring(capText.lastIndexOf("@") + 1);
-            image = captchaProducerMath.createImage(capStr);
-        }
-        else if ("char".equals(captchaType))
-        {
-            capStr = code = captchaProducer.createText();
-            image = captchaProducer.createImage(capStr);
-        }
-
-        redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
-        // 杞崲娴佷俊鎭啓鍑�
-        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
-        try
-        {
-            ImageIO.write(image, "jpg", os);
-        }
-        catch (IOException e)
-        {
-            return AjaxResult.error(e.getMessage());
-        }
-
-        ajax.put("uuid", uuid);
-        ajax.put("img", Base64.encode(os.toByteArray()));
-        return ajax;
-    }
-}
+package com.ruoyi.project.common;
+
+import com.google.code.kaptcha.Producer;
+import com.ruoyi.common.constant.CacheConstants;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.utils.sign.Base64;
+import com.ruoyi.common.utils.uuid.IdUtils;
+import com.ruoyi.framework.redis.RedisCache;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.project.system.service.ISysConfigService;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.util.FastByteArrayOutputStream;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 楠岃瘉鐮佹搷浣滃鐞�
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequiredArgsConstructor
+public class CaptchaController
+{
+    @Resource(name = "captchaProducer")
+    private Producer captchaProducer;
+
+    @Resource(name = "captchaProducerMath")
+    private Producer captchaProducerMath;
+
+    private final RedisCache redisCache;
+    
+    // 楠岃瘉鐮佺被鍨�
+    @Value("${ruoyi.captchaType}")
+    private String captchaType;
+    
+    private final ISysConfigService configService;
+
+    /**
+     * 鐢熸垚楠岃瘉鐮�
+     */
+    @GetMapping("/captchaImage")
+    public AjaxResult getCode(HttpServletResponse response) throws IOException
+    {
+        AjaxResult ajax = AjaxResult.success();
+        boolean captchaEnabled = configService.selectCaptchaEnabled();
+        ajax.put("captchaEnabled", captchaEnabled);
+        if (!captchaEnabled)
+        {
+            return ajax;
+        }
+
+        // 淇濆瓨楠岃瘉鐮佷俊鎭�
+        String uuid = IdUtils.simpleUUID();
+        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
+
+        String capStr = null, code = null;
+        BufferedImage image = null;
+
+        // 鐢熸垚楠岃瘉鐮�
+        if ("math".equals(captchaType))
+        {
+            String capText = captchaProducerMath.createText();
+            capStr = capText.substring(0, capText.lastIndexOf("@"));
+            code = capText.substring(capText.lastIndexOf("@") + 1);
+            image = captchaProducerMath.createImage(capStr);
+        }
+        else if ("char".equals(captchaType))
+        {
+            capStr = code = captchaProducer.createText();
+            image = captchaProducer.createImage(capStr);
+        }
+
+        redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
+        // 杞崲娴佷俊鎭啓鍑�
+        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
+        try
+        {
+            ImageIO.write(image, "jpg", os);
+        }
+        catch (IOException e)
+        {
+            return AjaxResult.error(e.getMessage());
+        }
+
+        ajax.put("uuid", uuid);
+        ajax.put("img", Base64.encode(os.toByteArray()));
+        return ajax;
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/monitor/controller/CacheController.java b/src/main/java/com/ruoyi/project/monitor/controller/CacheController.java
index 63fe76b..ac29662 100644
--- a/src/main/java/com/ruoyi/project/monitor/controller/CacheController.java
+++ b/src/main/java/com/ruoyi/project/monitor/controller/CacheController.java
@@ -1,111 +1,111 @@
-package com.ruoyi.project.monitor.controller;
-
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.project.monitor.domain.SysCache;
-import lombok.AllArgsConstructor;
-import org.springframework.data.redis.core.RedisCallback;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.*;
-
-/**
- * 缂撳瓨鐩戞帶
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/cache")
-@AllArgsConstructor
-public class CacheController
-{
-    private RedisTemplate<String, String> redisTemplate;
-
-    private final static List<SysCache> caches = new ArrayList<SysCache>();
-    {
-        caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "鐢ㄦ埛淇℃伅"));
-        caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "閰嶇疆淇℃伅"));
-        caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "鏁版嵁瀛楀吀"));
-        caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "楠岃瘉鐮�"));
-        caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "闃查噸鎻愪氦"));
-        caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "闄愭祦澶勭悊"));
-        caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "瀵嗙爜閿欒娆℃暟"));
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @GetMapping()
-    public AjaxResult getInfo() throws Exception
-    {
-        Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
-        Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
-        Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());
-
-        Map<String, Object> result = new HashMap<>(3);
-        result.put("info", info);
-        result.put("dbSize", dbSize);
-
-        List<Map<String, String>> pieList = new ArrayList<>();
-        commandStats.stringPropertyNames().forEach(key -> {
-            Map<String, String> data = new HashMap<>(2);
-            String property = commandStats.getProperty(key);
-            data.put("name", StringUtils.removeStart(key, "cmdstat_"));
-            data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
-            pieList.add(data);
-        });
-        result.put("commandStats", pieList);
-        return AjaxResult.success(result);
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @GetMapping("/getNames")
-    public AjaxResult cache()
-    {
-        return AjaxResult.success(caches);
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @GetMapping("/getKeys/{cacheName}")
-    public AjaxResult getCacheKeys(@PathVariable String cacheName)
-    {
-        Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
-        return AjaxResult.success(new TreeSet<>(cacheKeys));
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @GetMapping("/getValue/{cacheName}/{cacheKey}")
-    public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
-    {
-        String cacheValue = redisTemplate.opsForValue().get(cacheKey);
-        SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
-        return AjaxResult.success(sysCache);
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @DeleteMapping("/clearCacheName/{cacheName}")
-    public AjaxResult clearCacheName(@PathVariable String cacheName)
-    {
-        Collection<String> cacheKeys = redisTemplate.keys(cacheName + "*");
-        redisTemplate.delete(cacheKeys);
-        return AjaxResult.success();
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @DeleteMapping("/clearCacheKey/{cacheKey}")
-    public AjaxResult clearCacheKey(@PathVariable String cacheKey)
-    {
-        redisTemplate.delete(cacheKey);
-        return AjaxResult.success();
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @DeleteMapping("/clearCacheAll")
-    public AjaxResult clearCacheAll()
-    {
-        Collection<String> cacheKeys = redisTemplate.keys("*");
-        redisTemplate.delete(cacheKeys);
-        return AjaxResult.success();
-    }
-}
+package com.ruoyi.project.monitor.controller;
+
+import com.ruoyi.common.constant.CacheConstants;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.project.monitor.domain.SysCache;
+import lombok.AllArgsConstructor;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+/**
+ * 缂撳瓨鐩戞帶
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/cache")
+@AllArgsConstructor
+public class CacheController
+{
+    private RedisTemplate<String, String> redisTemplate;
+
+    private final static List<SysCache> caches = new ArrayList<SysCache>();
+    {
+        caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "鐢ㄦ埛淇℃伅"));
+        caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "閰嶇疆淇℃伅"));
+        caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "鏁版嵁瀛楀吀"));
+        caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "楠岃瘉鐮�"));
+        caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "闃查噸鎻愪氦"));
+        caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "闄愭祦澶勭悊"));
+        caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "瀵嗙爜閿欒娆℃暟"));
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping()
+    public AjaxResult getInfo() throws Exception
+    {
+        Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
+        Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
+        Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());
+
+        Map<String, Object> result = new HashMap<>(3);
+        result.put("info", info);
+        result.put("dbSize", dbSize);
+
+        List<Map<String, String>> pieList = new ArrayList<>();
+        commandStats.stringPropertyNames().forEach(key -> {
+            Map<String, String> data = new HashMap<>(2);
+            String property = commandStats.getProperty(key);
+            data.put("name", StringUtils.removeStart(key, "cmdstat_"));
+            data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
+            pieList.add(data);
+        });
+        result.put("commandStats", pieList);
+        return AjaxResult.success(result);
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping("/getNames")
+    public AjaxResult cache()
+    {
+        return AjaxResult.success(caches);
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping("/getKeys/{cacheName}")
+    public AjaxResult getCacheKeys(@PathVariable String cacheName)
+    {
+        Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
+        return AjaxResult.success(new TreeSet<>(cacheKeys));
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping("/getValue/{cacheName}/{cacheKey}")
+    public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
+    {
+        String cacheValue = redisTemplate.opsForValue().get(cacheKey);
+        SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
+        return AjaxResult.success(sysCache);
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @DeleteMapping("/clearCacheName/{cacheName}")
+    public AjaxResult clearCacheName(@PathVariable String cacheName)
+    {
+        Collection<String> cacheKeys = redisTemplate.keys(cacheName + "*");
+        redisTemplate.delete(cacheKeys);
+        return AjaxResult.success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @DeleteMapping("/clearCacheKey/{cacheKey}")
+    public AjaxResult clearCacheKey(@PathVariable String cacheKey)
+    {
+        redisTemplate.delete(cacheKey);
+        return AjaxResult.success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @DeleteMapping("/clearCacheAll")
+    public AjaxResult clearCacheAll()
+    {
+        Collection<String> cacheKeys = redisTemplate.keys("*");
+        redisTemplate.delete(cacheKeys);
+        return AjaxResult.success();
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/monitor/controller/ServerController.java b/src/main/java/com/ruoyi/project/monitor/controller/ServerController.java
index 9a50b05..e1f55f1 100644
--- a/src/main/java/com/ruoyi/project/monitor/controller/ServerController.java
+++ b/src/main/java/com/ruoyi/project/monitor/controller/ServerController.java
@@ -1,27 +1,27 @@
-package com.ruoyi.project.monitor.controller;
-
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.framework.web.domain.Server;
-
-/**
- * 鏈嶅姟鍣ㄧ洃鎺�
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/server")
-public class ServerController
-{
-    @PreAuthorize("@ss.hasPermi('monitor:server:list')")
-    @GetMapping()
-    public AjaxResult getInfo() throws Exception
-    {
-        Server server = new Server();
-        server.copyTo();
-        return AjaxResult.success(server);
-    }
-}
+package com.ruoyi.project.monitor.controller;
+
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.domain.Server;
+
+/**
+ * 鏈嶅姟鍣ㄧ洃鎺�
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/server")
+public class ServerController
+{
+    @PreAuthorize("@ss.hasPermi('monitor:server:list')")
+    @GetMapping()
+    public AjaxResult getInfo() throws Exception
+    {
+        Server server = new Server();
+        server.copyTo();
+        return AjaxResult.success(server);
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/monitor/controller/SysJobController.java b/src/main/java/com/ruoyi/project/monitor/controller/SysJobController.java
index ee2c058..7abc9bd 100644
--- a/src/main/java/com/ruoyi/project/monitor/controller/SysJobController.java
+++ b/src/main/java/com/ruoyi/project/monitor/controller/SysJobController.java
@@ -1,186 +1,186 @@
-package com.ruoyi.project.monitor.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.quartz.SchedulerException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-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.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.exception.job.TaskException;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.job.CronUtils;
-import com.ruoyi.common.utils.job.ScheduleUtils;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.monitor.domain.SysJob;
-import com.ruoyi.project.monitor.service.ISysJobService;
-
-/**
- * 璋冨害浠诲姟淇℃伅鎿嶄綔澶勭悊
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/job")
-@AllArgsConstructor
-public class SysJobController extends BaseController
-{
-    private ISysJobService jobService;
-
-    /**
-     * 鏌ヨ瀹氭椂浠诲姟鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysJob sysJob)
-    {
-        startPage();
-        List<SysJob> list = jobService.selectJobList(sysJob);
-        return getDataTable(list);
-    }
-
-    /**
-     * 瀵煎嚭瀹氭椂浠诲姟鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:export')")
-    @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.EXPORT)
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysJob sysJob)
-    {
-        List<SysJob> list = jobService.selectJobList(sysJob);
-        ExcelUtil<SysJob> util = new ExcelUtil<SysJob>(SysJob.class);
-        util.exportExcel(response, list, "瀹氭椂浠诲姟");
-    }
-
-    /**
-     * 鑾峰彇瀹氭椂浠诲姟璇︾粏淇℃伅
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:query')")
-    @GetMapping(value = "/{jobId}")
-    public AjaxResult getInfo(@PathVariable("jobId") Long jobId)
-    {
-        return success(jobService.selectJobById(jobId));
-    }
-
-    /**
-     * 鏂板瀹氭椂浠诲姟
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:add')")
-    @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@RequestBody SysJob job) throws SchedulerException, TaskException
-    {
-        if (!CronUtils.isValid(job.getCronExpression()))
-        {
-            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛孋ron琛ㄨ揪寮忎笉姝g‘");
-        }
-        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
-        {
-            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'rmi'璋冪敤");
-        }
-        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
-        {
-            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'ldap(s)'璋冪敤");
-        }
-        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
-        {
-            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'http(s)'璋冪敤");
-        }
-        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
-        {
-            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆瀛樺湪杩濊");
-        }
-        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
-        {
-            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅湪鐧藉悕鍗曞唴");
-        }
-        job.setCreateBy(getUsername());
-        return toAjax(jobService.insertJob(job));
-    }
-
-    /**
-     * 淇敼瀹氭椂浠诲姟
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:edit')")
-    @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@RequestBody SysJob job) throws SchedulerException, TaskException
-    {
-        if (!CronUtils.isValid(job.getCronExpression()))
-        {
-            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛孋ron琛ㄨ揪寮忎笉姝g‘");
-        }
-        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
-        {
-            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'rmi'璋冪敤");
-        }
-        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
-        {
-            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'ldap(s)'璋冪敤");
-        }
-        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
-        {
-            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'http(s)'璋冪敤");
-        }
-        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
-        {
-            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆瀛樺湪杩濊");
-        }
-        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
-        {
-            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅湪鐧藉悕鍗曞唴");
-        }
-        job.setUpdateBy(getUsername());
-        return toAjax(jobService.updateJob(job));
-    }
-
-    /**
-     * 瀹氭椂浠诲姟鐘舵�佷慨鏀�
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')")
-    @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.UPDATE)
-    @PutMapping("/changeStatus")
-    public AjaxResult changeStatus(@RequestBody SysJob job) throws SchedulerException
-    {
-        SysJob newJob = jobService.selectJobById(job.getJobId());
-        newJob.setStatus(job.getStatus());
-        return toAjax(jobService.changeStatus(newJob));
-    }
-
-    /**
-     * 瀹氭椂浠诲姟绔嬪嵆鎵ц涓�娆�
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')")
-    @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.UPDATE)
-    @PutMapping("/run")
-    public AjaxResult run(@RequestBody SysJob job) throws SchedulerException
-    {
-        boolean result = jobService.run(job);
-        return result ? success() : error("浠诲姟涓嶅瓨鍦ㄦ垨宸茶繃鏈燂紒");
-    }
-
-    /**
-     * 鍒犻櫎瀹氭椂浠诲姟
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
-    @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{jobIds}")
-    public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException
-    {
-        jobService.deleteJobByIds(jobIds);
-        return success();
-    }
-}
+package com.ruoyi.project.monitor.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import org.quartz.SchedulerException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.exception.job.TaskException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.job.CronUtils;
+import com.ruoyi.common.utils.job.ScheduleUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+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.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.monitor.domain.SysJob;
+import com.ruoyi.project.monitor.service.ISysJobService;
+
+/**
+ * 璋冨害浠诲姟淇℃伅鎿嶄綔澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/job")
+@AllArgsConstructor
+public class SysJobController extends BaseController
+{
+    private ISysJobService jobService;
+
+    /**
+     * 鏌ヨ瀹氭椂浠诲姟鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysJob sysJob)
+    {
+        startPage();
+        List<SysJob> list = jobService.selectJobList(sysJob);
+        return getDataTable(list);
+    }
+
+    /**
+     * 瀵煎嚭瀹氭椂浠诲姟鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:export')")
+    @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysJob sysJob)
+    {
+        List<SysJob> list = jobService.selectJobList(sysJob);
+        ExcelUtil<SysJob> util = new ExcelUtil<SysJob>(SysJob.class);
+        util.exportExcel(response, list, "瀹氭椂浠诲姟");
+    }
+
+    /**
+     * 鑾峰彇瀹氭椂浠诲姟璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:query')")
+    @GetMapping(value = "/{jobId}")
+    public AjaxResult getInfo(@PathVariable("jobId") Long jobId)
+    {
+        return success(jobService.selectJobById(jobId));
+    }
+
+    /**
+     * 鏂板瀹氭椂浠诲姟
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:add')")
+    @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysJob job) throws SchedulerException, TaskException
+    {
+        if (!CronUtils.isValid(job.getCronExpression()))
+        {
+            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛孋ron琛ㄨ揪寮忎笉姝g‘");
+        }
+        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
+        {
+            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'rmi'璋冪敤");
+        }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
+        {
+            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'ldap(s)'璋冪敤");
+        }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
+        {
+            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'http(s)'璋冪敤");
+        }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
+        {
+            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆瀛樺湪杩濊");
+        }
+        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
+        {
+            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅湪鐧藉悕鍗曞唴");
+        }
+        job.setCreateBy(getUsername());
+        return toAjax(jobService.insertJob(job));
+    }
+
+    /**
+     * 淇敼瀹氭椂浠诲姟
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:edit')")
+    @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysJob job) throws SchedulerException, TaskException
+    {
+        if (!CronUtils.isValid(job.getCronExpression()))
+        {
+            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛孋ron琛ㄨ揪寮忎笉姝g‘");
+        }
+        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
+        {
+            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'rmi'璋冪敤");
+        }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
+        {
+            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'ldap(s)'璋冪敤");
+        }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
+        {
+            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'http(s)'璋冪敤");
+        }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
+        {
+            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆瀛樺湪杩濊");
+        }
+        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
+        {
+            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅湪鐧藉悕鍗曞唴");
+        }
+        job.setUpdateBy(getUsername());
+        return toAjax(jobService.updateJob(job));
+    }
+
+    /**
+     * 瀹氭椂浠诲姟鐘舵�佷慨鏀�
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')")
+    @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public AjaxResult changeStatus(@RequestBody SysJob job) throws SchedulerException
+    {
+        SysJob newJob = jobService.selectJobById(job.getJobId());
+        newJob.setStatus(job.getStatus());
+        return toAjax(jobService.changeStatus(newJob));
+    }
+
+    /**
+     * 瀹氭椂浠诲姟绔嬪嵆鎵ц涓�娆�
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')")
+    @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.UPDATE)
+    @PutMapping("/run")
+    public AjaxResult run(@RequestBody SysJob job) throws SchedulerException
+    {
+        boolean result = jobService.run(job);
+        return result ? success() : error("浠诲姟涓嶅瓨鍦ㄦ垨宸茶繃鏈燂紒");
+    }
+
+    /**
+     * 鍒犻櫎瀹氭椂浠诲姟
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
+    @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{jobIds}")
+    public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException
+    {
+        jobService.deleteJobByIds(jobIds);
+        return success();
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/monitor/controller/SysJobLogController.java b/src/main/java/com/ruoyi/project/monitor/controller/SysJobLogController.java
index 0c29d22..9ed3059 100644
--- a/src/main/java/com/ruoyi/project/monitor/controller/SysJobLogController.java
+++ b/src/main/java/com/ruoyi/project/monitor/controller/SysJobLogController.java
@@ -1,93 +1,93 @@
-package com.ruoyi.project.monitor.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-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.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.monitor.domain.SysJobLog;
-import com.ruoyi.project.monitor.service.ISysJobLogService;
-
-/**
- * 璋冨害鏃ュ織鎿嶄綔澶勭悊
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/jobLog")
-@AllArgsConstructor
-public class SysJobLogController extends BaseController
-{
-    private ISysJobLogService jobLogService;
-
-    /**
-     * 鏌ヨ瀹氭椂浠诲姟璋冨害鏃ュ織鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysJobLog sysJobLog)
-    {
-        startPage();
-        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
-        return getDataTable(list);
-    }
-
-    /**
-     * 瀵煎嚭瀹氭椂浠诲姟璋冨害鏃ュ織鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:export')")
-    @Log(title = "浠诲姟璋冨害鏃ュ織", businessType = BusinessType.EXPORT)
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysJobLog sysJobLog)
-    {
-        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
-        ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class);
-        util.exportExcel(response, list, "璋冨害鏃ュ織");
-    }
-    
-    /**
-     * 鏍规嵁璋冨害缂栧彿鑾峰彇璇︾粏淇℃伅
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:query')")
-    @GetMapping(value = "/{jobLogId}")
-    public AjaxResult getInfo(@PathVariable Long jobLogId)
-    {
-        return success(jobLogService.selectJobLogById(jobLogId));
-    }
-
-
-    /**
-     * 鍒犻櫎瀹氭椂浠诲姟璋冨害鏃ュ織
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
-    @Log(title = "瀹氭椂浠诲姟璋冨害鏃ュ織", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{jobLogIds}")
-    public AjaxResult remove(@PathVariable Long[] jobLogIds)
-    {
-        return toAjax(jobLogService.deleteJobLogByIds(jobLogIds));
-    }
-
-    /**
-     * 娓呯┖瀹氭椂浠诲姟璋冨害鏃ュ織
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
-    @Log(title = "璋冨害鏃ュ織", businessType = BusinessType.CLEAN)
-    @DeleteMapping("/clean")
-    public AjaxResult clean()
-    {
-        jobLogService.cleanJobLog();
-        return success();
-    }
-}
+package com.ruoyi.project.monitor.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+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.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.monitor.domain.SysJobLog;
+import com.ruoyi.project.monitor.service.ISysJobLogService;
+
+/**
+ * 璋冨害鏃ュ織鎿嶄綔澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/jobLog")
+@AllArgsConstructor
+public class SysJobLogController extends BaseController
+{
+    private ISysJobLogService jobLogService;
+
+    /**
+     * 鏌ヨ瀹氭椂浠诲姟璋冨害鏃ュ織鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysJobLog sysJobLog)
+    {
+        startPage();
+        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
+        return getDataTable(list);
+    }
+
+    /**
+     * 瀵煎嚭瀹氭椂浠诲姟璋冨害鏃ュ織鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:export')")
+    @Log(title = "浠诲姟璋冨害鏃ュ織", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysJobLog sysJobLog)
+    {
+        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
+        ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class);
+        util.exportExcel(response, list, "璋冨害鏃ュ織");
+    }
+    
+    /**
+     * 鏍规嵁璋冨害缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:query')")
+    @GetMapping(value = "/{jobLogId}")
+    public AjaxResult getInfo(@PathVariable Long jobLogId)
+    {
+        return success(jobLogService.selectJobLogById(jobLogId));
+    }
+
+
+    /**
+     * 鍒犻櫎瀹氭椂浠诲姟璋冨害鏃ュ織
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
+    @Log(title = "瀹氭椂浠诲姟璋冨害鏃ュ織", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{jobLogIds}")
+    public AjaxResult remove(@PathVariable Long[] jobLogIds)
+    {
+        return toAjax(jobLogService.deleteJobLogByIds(jobLogIds));
+    }
+
+    /**
+     * 娓呯┖瀹氭椂浠诲姟璋冨害鏃ュ織
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
+    @Log(title = "璋冨害鏃ュ織", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clean")
+    public AjaxResult clean()
+    {
+        jobLogService.cleanJobLog();
+        return success();
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java b/src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java
index 7f5085d..0c96a9d 100644
--- a/src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java
+++ b/src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java
@@ -1,70 +1,70 @@
-package com.ruoyi.project.monitor.controller;
-
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.framework.aspectj.lang.annotation.Log;
-import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
-import com.ruoyi.framework.security.service.SysPasswordService;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.monitor.domain.SysLogininfor;
-import com.ruoyi.project.monitor.service.ISysLogininforService;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-/**
- * 绯荤粺璁块棶璁板綍
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/logininfor")
-@AllArgsConstructor
-public class SysLogininforController extends BaseController {
-    private ISysLogininforService logininforService;
-    private SysPasswordService passwordService;
-
-    @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysLogininfor logininfor) {
-        startPage();
-        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
-        return getDataTable(list);
-    }
-
-    @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysLogininfor logininfor) {
-        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
-        ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
-        util.exportExcel(response, list, "鐧诲綍鏃ュ織");
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
-    @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{infoIds}")
-    public AjaxResult remove(@PathVariable Long[] infoIds) {
-        return toAjax(logininforService.deleteLogininforByIds(infoIds));
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
-    @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.CLEAN)
-    @DeleteMapping("/clean")
-    public AjaxResult clean() {
-        logininforService.cleanLogininfor();
-        return success();
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
-    @Log(title = "璐︽埛瑙i攣", businessType = BusinessType.OTHER)
-    @GetMapping("/unlock/{userName}")
-    public AjaxResult unlock(@PathVariable("userName") String userName) {
-        passwordService.clearLoginRecordCache(userName);
-        return success();
-    }
-}
+package com.ruoyi.project.monitor.controller;
+
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.security.service.SysPasswordService;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.monitor.domain.SysLogininfor;
+import com.ruoyi.project.monitor.service.ISysLogininforService;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 绯荤粺璁块棶璁板綍
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/logininfor")
+@AllArgsConstructor
+public class SysLogininforController extends BaseController {
+    private ISysLogininforService logininforService;
+    private SysPasswordService passwordService;
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysLogininfor logininfor) {
+        startPage();
+        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
+        return getDataTable(list);
+    }
+
+    @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysLogininfor logininfor) {
+        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
+        ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
+        util.exportExcel(response, list, "鐧诲綍鏃ュ織");
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+    @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{infoIds}")
+    public AjaxResult remove(@PathVariable Long[] infoIds) {
+        return toAjax(logininforService.deleteLogininforByIds(infoIds));
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+    @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clean")
+    public AjaxResult clean() {
+        logininforService.cleanLogininfor();
+        return success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
+    @Log(title = "璐︽埛瑙i攣", businessType = BusinessType.OTHER)
+    @GetMapping("/unlock/{userName}")
+    public AjaxResult unlock(@PathVariable("userName") String userName) {
+        passwordService.clearLoginRecordCache(userName);
+        return success();
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/monitor/controller/SysOperlogController.java b/src/main/java/com/ruoyi/project/monitor/controller/SysOperlogController.java
index 81bab02..091a5a6 100644
--- a/src/main/java/com/ruoyi/project/monitor/controller/SysOperlogController.java
+++ b/src/main/java/com/ruoyi/project/monitor/controller/SysOperlogController.java
@@ -1,70 +1,70 @@
-package com.ruoyi.project.monitor.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-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.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.monitor.domain.SysOperLog;
-import com.ruoyi.project.monitor.service.ISysOperLogService;
-
-/**
- * 鎿嶄綔鏃ュ織璁板綍
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/operlog")
-@AllArgsConstructor
-public class SysOperlogController extends BaseController
-{
-    private ISysOperLogService operLogService;
-
-    @PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysOperLog operLog)
-    {
-        startPage();
-        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
-        return getDataTable(list);
-    }
-
-    @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysOperLog operLog)
-    {
-        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
-        ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
-        util.exportExcel(response, list, "鎿嶄綔鏃ュ織");
-    }
-
-    @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.DELETE)
-    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
-    @DeleteMapping("/{operIds}")
-    public AjaxResult remove(@PathVariable Long[] operIds)
-    {
-        return toAjax(operLogService.deleteOperLogByIds(operIds));
-    }
-
-    @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.CLEAN)
-    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
-    @DeleteMapping("/clean")
-    public AjaxResult clean()
-    {
-        operLogService.cleanOperLog();
-        return success();
-    }
-}
+package com.ruoyi.project.monitor.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+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.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.monitor.domain.SysOperLog;
+import com.ruoyi.project.monitor.service.ISysOperLogService;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/operlog")
+@AllArgsConstructor
+public class SysOperlogController extends BaseController
+{
+    private ISysOperLogService operLogService;
+
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysOperLog operLog)
+    {
+        startPage();
+        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
+        return getDataTable(list);
+    }
+
+    @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysOperLog operLog)
+    {
+        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
+        ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
+        util.exportExcel(response, list, "鎿嶄綔鏃ュ織");
+    }
+
+    @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.DELETE)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+    @DeleteMapping("/{operIds}")
+    public AjaxResult remove(@PathVariable Long[] operIds)
+    {
+        return toAjax(operLogService.deleteOperLogByIds(operIds));
+    }
+
+    @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.CLEAN)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+    @DeleteMapping("/clean")
+    public AjaxResult clean()
+    {
+        operLogService.cleanOperLog();
+        return success();
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java b/src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java
index aa8c824..944656b 100644
--- a/src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java
+++ b/src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java
@@ -1,83 +1,83 @@
-package com.ruoyi.project.monitor.controller;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-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.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.aspectj.lang.annotation.Log;
-import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
-import com.ruoyi.framework.redis.RedisCache;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.monitor.domain.SysUserOnline;
-import com.ruoyi.project.system.service.ISysUserOnlineService;
-
-/**
- * 鍦ㄧ嚎鐢ㄦ埛鐩戞帶
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/online")
-@AllArgsConstructor
-public class SysUserOnlineController extends BaseController
-{
-    private ISysUserOnlineService userOnlineService;
-    private RedisCache redisCache;
-
-    @PreAuthorize("@ss.hasPermi('monitor:online:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(String ipaddr, String userName)
-    {
-        Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
-        List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
-        for (String key : keys)
-        {
-            LoginUser user = redisCache.getCacheObject(key);
-            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
-            {
-                userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
-            }
-            else if (StringUtils.isNotEmpty(ipaddr))
-            {
-                userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
-            }
-            else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
-            {
-                userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
-            }
-            else
-            {
-                userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
-            }
-        }
-        Collections.reverse(userOnlineList);
-        userOnlineList.removeAll(Collections.singleton(null));
-        return getDataTable(userOnlineList);
-    }
-
-    /**
-     * 寮洪��鐢ㄦ埛
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
-    @Log(title = "鍦ㄧ嚎鐢ㄦ埛", businessType = BusinessType.FORCE)
-    @DeleteMapping("/{tokenId}")
-    public AjaxResult forceLogout(@PathVariable String tokenId)
-    {
-        redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
-        return success();
-    }
-}
+package com.ruoyi.project.monitor.controller;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.CacheConstants;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.redis.RedisCache;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.monitor.domain.SysUserOnline;
+import com.ruoyi.project.system.service.ISysUserOnlineService;
+
+/**
+ * 鍦ㄧ嚎鐢ㄦ埛鐩戞帶
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/online")
+@AllArgsConstructor
+public class SysUserOnlineController extends BaseController
+{
+    private ISysUserOnlineService userOnlineService;
+    private RedisCache redisCache;
+
+    @PreAuthorize("@ss.hasPermi('monitor:online:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(String ipaddr, String userName)
+    {
+        Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
+        List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
+        for (String key : keys)
+        {
+            LoginUser user = redisCache.getCacheObject(key);
+            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
+            {
+                userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
+            }
+            else if (StringUtils.isNotEmpty(ipaddr))
+            {
+                userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
+            }
+            else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
+            {
+                userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
+            }
+            else
+            {
+                userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
+            }
+        }
+        Collections.reverse(userOnlineList);
+        userOnlineList.removeAll(Collections.singleton(null));
+        return getDataTable(userOnlineList);
+    }
+
+    /**
+     * 寮洪��鐢ㄦ埛
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
+    @Log(title = "鍦ㄧ嚎鐢ㄦ埛", businessType = BusinessType.FORCE)
+    @DeleteMapping("/{tokenId}")
+    public AjaxResult forceLogout(@PathVariable String tokenId)
+    {
+        redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
+        return success();
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysConfigController.java b/src/main/java/com/ruoyi/project/system/controller/SysConfigController.java
index a10687b..e73d60e 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysConfigController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysConfigController.java
@@ -1,127 +1,127 @@
-package com.ruoyi.project.system.controller;
-
-import com.ruoyi.common.utils.poi.ExcelUtil;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.system.domain.SysConfig;
-import com.ruoyi.project.system.service.ISysConfigService;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-/**
- * 鍙傛暟閰嶇疆 淇℃伅鎿嶄綔澶勭悊
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/config")
-@AllArgsConstructor
-public class SysConfigController extends BaseController
-{
-    private ISysConfigService configService;
-
-    /**
-     * 鑾峰彇鍙傛暟閰嶇疆鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('system:config:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysConfig config)
-    {
-        startPage();
-        List<SysConfig> list = configService.selectConfigList(config);
-        return getDataTable(list);
-    }
-
-    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('system:config:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysConfig config)
-    {
-        List<SysConfig> list = configService.selectConfigList(config);
-        ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
-        util.exportExcel(response, list, "鍙傛暟鏁版嵁");
-    }
-
-    /**
-     * 鏍规嵁鍙傛暟缂栧彿鑾峰彇璇︾粏淇℃伅
-     */
-    @PreAuthorize("@ss.hasPermi('system:config:query')")
-    @GetMapping(value = "/{configId}")
-    public AjaxResult getInfo(@PathVariable Long configId)
-    {
-        return success(configService.selectConfigById(configId));
-    }
-
-    /**
-     * 鏍规嵁鍙傛暟閿悕鏌ヨ鍙傛暟鍊�
-     */
-    @GetMapping(value = "/configKey/{configKey}")
-    public AjaxResult getConfigKey(@PathVariable String configKey)
-    {
-        return success(configService.selectConfigByKey(configKey));
-    }
-
-    /**
-     * 鏂板鍙傛暟閰嶇疆
-     */
-    @PreAuthorize("@ss.hasPermi('system:config:add')")
-    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysConfig config)
-    {
-        if (!configService.checkConfigKeyUnique(config))
-        {
-            return error("鏂板鍙傛暟'" + config.getConfigName() + "'澶辫触锛屽弬鏁伴敭鍚嶅凡瀛樺湪");
-        }
-        config.setCreateBy(getUsername());
-        return toAjax(configService.insertConfig(config));
-    }
-
-    /**
-     * 淇敼鍙傛暟閰嶇疆
-     */
-    @PreAuthorize("@ss.hasPermi('system:config:edit')")
-    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysConfig config)
-    {
-        if (!configService.checkConfigKeyUnique(config))
-        {
-            return error("淇敼鍙傛暟'" + config.getConfigName() + "'澶辫触锛屽弬鏁伴敭鍚嶅凡瀛樺湪");
-        }
-        config.setUpdateBy(getUsername());
-        return toAjax(configService.updateConfig(config));
-    }
-
-    /**
-     * 鍒犻櫎鍙傛暟閰嶇疆
-     */
-    @PreAuthorize("@ss.hasPermi('system:config:remove')")
-    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{configIds}")
-    public AjaxResult remove(@PathVariable Long[] configIds)
-    {
-        configService.deleteConfigByIds(configIds);
-        return success();
-    }
-
-    /**
-     * 鍒锋柊鍙傛暟缂撳瓨
-     */
-    @PreAuthorize("@ss.hasPermi('system:config:remove')")
-    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.CLEAN)
-    @DeleteMapping("/refreshCache")
-    public AjaxResult refreshCache()
-    {
-        configService.resetConfigCache();
-        return success();
-    }
-}
+package com.ruoyi.project.system.controller;
+
+import com.ruoyi.common.utils.poi.ExcelUtil;
+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.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysConfig;
+import com.ruoyi.project.system.service.ISysConfigService;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 鍙傛暟閰嶇疆 淇℃伅鎿嶄綔澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/config")
+@AllArgsConstructor
+public class SysConfigController extends BaseController
+{
+    private ISysConfigService configService;
+
+    /**
+     * 鑾峰彇鍙傛暟閰嶇疆鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysConfig config)
+    {
+        startPage();
+        List<SysConfig> list = configService.selectConfigList(config);
+        return getDataTable(list);
+    }
+
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:config:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysConfig config)
+    {
+        List<SysConfig> list = configService.selectConfigList(config);
+        ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
+        util.exportExcel(response, list, "鍙傛暟鏁版嵁");
+    }
+
+    /**
+     * 鏍规嵁鍙傛暟缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:query')")
+    @GetMapping(value = "/{configId}")
+    public AjaxResult getInfo(@PathVariable Long configId)
+    {
+        return success(configService.selectConfigById(configId));
+    }
+
+    /**
+     * 鏍规嵁鍙傛暟閿悕鏌ヨ鍙傛暟鍊�
+     */
+    @GetMapping(value = "/configKey/{configKey}")
+    public AjaxResult getConfigKey(@PathVariable String configKey)
+    {
+        return success(configService.selectConfigByKey(configKey));
+    }
+
+    /**
+     * 鏂板鍙傛暟閰嶇疆
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:add')")
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysConfig config)
+    {
+        if (!configService.checkConfigKeyUnique(config))
+        {
+            return error("鏂板鍙傛暟'" + config.getConfigName() + "'澶辫触锛屽弬鏁伴敭鍚嶅凡瀛樺湪");
+        }
+        config.setCreateBy(getUsername());
+        return toAjax(configService.insertConfig(config));
+    }
+
+    /**
+     * 淇敼鍙傛暟閰嶇疆
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:edit')")
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysConfig config)
+    {
+        if (!configService.checkConfigKeyUnique(config))
+        {
+            return error("淇敼鍙傛暟'" + config.getConfigName() + "'澶辫触锛屽弬鏁伴敭鍚嶅凡瀛樺湪");
+        }
+        config.setUpdateBy(getUsername());
+        return toAjax(configService.updateConfig(config));
+    }
+
+    /**
+     * 鍒犻櫎鍙傛暟閰嶇疆
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:remove')")
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{configIds}")
+    public AjaxResult remove(@PathVariable Long[] configIds)
+    {
+        configService.deleteConfigByIds(configIds);
+        return success();
+    }
+
+    /**
+     * 鍒锋柊鍙傛暟缂撳瓨
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:remove')")
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/refreshCache")
+    public AjaxResult refreshCache()
+    {
+        configService.resetConfigCache();
+        return success();
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java b/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java
index f61e42f..24e6c71 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java
@@ -1,134 +1,134 @@
-package com.ruoyi.project.system.controller;
-
-import java.util.List;
-
-import lombok.AllArgsConstructor;
-import org.apache.commons.lang3.ArrayUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-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.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.utils.StringUtils;
-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.AjaxResult;
-import com.ruoyi.project.system.domain.SysDept;
-import com.ruoyi.project.system.service.ISysDeptService;
-
-/**
- * 閮ㄩ棬淇℃伅
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/dept")
-@AllArgsConstructor
-public class SysDeptController extends BaseController
-{
-    private ISysDeptService deptService;
-
-    /**
-     * 鑾峰彇閮ㄩ棬鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('system:dept:list')")
-    @GetMapping("/list")
-    public AjaxResult list(SysDept dept)
-    {
-        List<SysDept> depts = deptService.selectDeptList(dept);
-        return success(depts);
-    }
-
-    /**
-     * 鏌ヨ閮ㄩ棬鍒楄〃锛堟帓闄よ妭鐐癸級
-     */
-    @PreAuthorize("@ss.hasPermi('system:dept:list')")
-    @GetMapping("/list/exclude/{deptId}")
-    public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
-    {
-        List<SysDept> depts = deptService.selectDeptList(new SysDept());
-        depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
-        return success(depts);
-    }
-
-    /**
-     * 鏍规嵁閮ㄩ棬缂栧彿鑾峰彇璇︾粏淇℃伅
-     */
-    @PreAuthorize("@ss.hasPermi('system:dept:query')")
-    @GetMapping(value = "/{deptId}")
-    public AjaxResult getInfo(@PathVariable Long deptId)
-    {
-        deptService.checkDeptDataScope(deptId);
-        return success(deptService.selectDeptById(deptId));
-    }
-
-    /**
-     * 鏂板閮ㄩ棬
-     */
-    @PreAuthorize("@ss.hasPermi('system:dept:add')")
-    @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysDept dept)
-    {
-        if (!deptService.checkDeptNameUnique(dept))
-        {
-            return error("鏂板閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛岄儴闂ㄥ悕绉板凡瀛樺湪");
-        }
-        dept.setCreateBy(getUsername());
-        return toAjax(deptService.insertDept(dept));
-    }
-
-    /**
-     * 淇敼閮ㄩ棬
-     */
-    @PreAuthorize("@ss.hasPermi('system:dept:edit')")
-    @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysDept dept)
-    {
-        Long deptId = dept.getDeptId();
-        deptService.checkDeptDataScope(deptId);
-        if (!deptService.checkDeptNameUnique(dept))
-        {
-            return error("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛岄儴闂ㄥ悕绉板凡瀛樺湪");
-        }
-        else if (dept.getParentId().equals(deptId))
-        {
-            return error("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛屼笂绾ч儴闂ㄤ笉鑳芥槸鑷繁");
-        }
-        else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
-        {
-            return error("璇ラ儴闂ㄥ寘鍚湭鍋滅敤鐨勫瓙閮ㄩ棬锛�");
-        }
-        dept.setUpdateBy(getUsername());
-        return toAjax(deptService.updateDept(dept));
-    }
-
-    /**
-     * 鍒犻櫎閮ㄩ棬
-     */
-    @PreAuthorize("@ss.hasPermi('system:dept:remove')")
-    @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{deptId}")
-    public AjaxResult remove(@PathVariable Long deptId)
-    {
-        if (deptService.hasChildByDeptId(deptId))
-        {
-            return warn("瀛樺湪涓嬬骇閮ㄩ棬,涓嶅厑璁稿垹闄�");
-        }
-        if (deptService.checkDeptExistUser(deptId))
-        {
-            return warn("閮ㄩ棬瀛樺湪鐢ㄦ埛,涓嶅厑璁稿垹闄�");
-        }
-        deptService.checkDeptDataScope(deptId);
-        return toAjax(deptService.deleteDeptById(deptId));
-    }
-}
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+
+import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.ArrayUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+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.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.StringUtils;
+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.AjaxResult;
+import com.ruoyi.project.system.domain.SysDept;
+import com.ruoyi.project.system.service.ISysDeptService;
+
+/**
+ * 閮ㄩ棬淇℃伅
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/dept")
+@AllArgsConstructor
+public class SysDeptController extends BaseController
+{
+    private ISysDeptService deptService;
+
+    /**
+     * 鑾峰彇閮ㄩ棬鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:list')")
+    @GetMapping("/list")
+    public AjaxResult list(SysDept dept)
+    {
+        List<SysDept> depts = deptService.selectDeptList(dept);
+        return success(depts);
+    }
+
+    /**
+     * 鏌ヨ閮ㄩ棬鍒楄〃锛堟帓闄よ妭鐐癸級
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:list')")
+    @GetMapping("/list/exclude/{deptId}")
+    public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
+    {
+        List<SysDept> depts = deptService.selectDeptList(new SysDept());
+        depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
+        return success(depts);
+    }
+
+    /**
+     * 鏍规嵁閮ㄩ棬缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:query')")
+    @GetMapping(value = "/{deptId}")
+    public AjaxResult getInfo(@PathVariable Long deptId)
+    {
+        deptService.checkDeptDataScope(deptId);
+        return success(deptService.selectDeptById(deptId));
+    }
+
+    /**
+     * 鏂板閮ㄩ棬
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:add')")
+    @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysDept dept)
+    {
+        if (!deptService.checkDeptNameUnique(dept))
+        {
+            return error("鏂板閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛岄儴闂ㄥ悕绉板凡瀛樺湪");
+        }
+        dept.setCreateBy(getUsername());
+        return toAjax(deptService.insertDept(dept));
+    }
+
+    /**
+     * 淇敼閮ㄩ棬
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:edit')")
+    @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysDept dept)
+    {
+        Long deptId = dept.getDeptId();
+        deptService.checkDeptDataScope(deptId);
+        if (!deptService.checkDeptNameUnique(dept))
+        {
+            return error("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛岄儴闂ㄥ悕绉板凡瀛樺湪");
+        }
+        else if (dept.getParentId().equals(deptId))
+        {
+            return error("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛屼笂绾ч儴闂ㄤ笉鑳芥槸鑷繁");
+        }
+        else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
+        {
+            return error("璇ラ儴闂ㄥ寘鍚湭鍋滅敤鐨勫瓙閮ㄩ棬锛�");
+        }
+        dept.setUpdateBy(getUsername());
+        return toAjax(deptService.updateDept(dept));
+    }
+
+    /**
+     * 鍒犻櫎閮ㄩ棬
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:remove')")
+    @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{deptId}")
+    public AjaxResult remove(@PathVariable Long deptId)
+    {
+        if (deptService.hasChildByDeptId(deptId))
+        {
+            return warn("瀛樺湪涓嬬骇閮ㄩ棬,涓嶅厑璁稿垹闄�");
+        }
+        if (deptService.checkDeptExistUser(deptId))
+        {
+            return warn("閮ㄩ棬瀛樺湪鐢ㄦ埛,涓嶅厑璁稿垹闄�");
+        }
+        deptService.checkDeptDataScope(deptId);
+        return toAjax(deptService.deleteDeptById(deptId));
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java b/src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java
index 58cb4c1..56c44c1 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java
@@ -1,120 +1,120 @@
-package com.ruoyi.project.system.controller;
-
-import java.util.ArrayList;
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-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.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.system.domain.SysDictData;
-import com.ruoyi.project.system.service.ISysDictDataService;
-import com.ruoyi.project.system.service.ISysDictTypeService;
-
-/**
- * 鏁版嵁瀛楀吀淇℃伅
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/dict/data")
-@AllArgsConstructor
-public class SysDictDataController extends BaseController
-{
-    private ISysDictDataService dictDataService;
-    private ISysDictTypeService dictTypeService;
-
-    @PreAuthorize("@ss.hasPermi('system:dict:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysDictData dictData)
-    {
-        startPage();
-        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
-        return getDataTable(list);
-    }
-
-    @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('system:dict:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysDictData dictData)
-    {
-        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
-        ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
-        util.exportExcel(response, list, "瀛楀吀鏁版嵁");
-    }
-
-    /**
-     * 鏌ヨ瀛楀吀鏁版嵁璇︾粏
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:query')")
-    @GetMapping(value = "/{dictCode}")
-    public AjaxResult getInfo(@PathVariable Long dictCode)
-    {
-        return success(dictDataService.selectDictDataById(dictCode));
-    }
-
-    /**
-     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁淇℃伅
-     */
-    @GetMapping(value = "/type/{dictType}")
-    public AjaxResult dictType(@PathVariable String dictType)
-    {
-        List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
-        if (StringUtils.isNull(data))
-        {
-            data = new ArrayList<SysDictData>();
-        }
-        return success(data);
-    }
-
-    /**
-     * 鏂板瀛楀吀绫诲瀷
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:add')")
-    @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysDictData dict)
-    {
-        dict.setCreateBy(getUsername());
-        return toAjax(dictDataService.insertDictData(dict));
-    }
-
-    /**
-     * 淇敼淇濆瓨瀛楀吀绫诲瀷
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
-    @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysDictData dict)
-    {
-        dict.setUpdateBy(getUsername());
-        return toAjax(dictDataService.updateDictData(dict));
-    }
-
-    /**
-     * 鍒犻櫎瀛楀吀绫诲瀷
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
-    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{dictCodes}")
-    public AjaxResult remove(@PathVariable Long[] dictCodes)
-    {
-        dictDataService.deleteDictDataByIds(dictCodes);
-        return success();
-    }
-}
+package com.ruoyi.project.system.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+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.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+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.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysDictData;
+import com.ruoyi.project.system.service.ISysDictDataService;
+import com.ruoyi.project.system.service.ISysDictTypeService;
+
+/**
+ * 鏁版嵁瀛楀吀淇℃伅
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/dict/data")
+@AllArgsConstructor
+public class SysDictDataController extends BaseController
+{
+    private ISysDictDataService dictDataService;
+    private ISysDictTypeService dictTypeService;
+
+    @PreAuthorize("@ss.hasPermi('system:dict:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysDictData dictData)
+    {
+        startPage();
+        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
+        return getDataTable(list);
+    }
+
+    @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:dict:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysDictData dictData)
+    {
+        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
+        ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
+        util.exportExcel(response, list, "瀛楀吀鏁版嵁");
+    }
+
+    /**
+     * 鏌ヨ瀛楀吀鏁版嵁璇︾粏
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:query')")
+    @GetMapping(value = "/{dictCode}")
+    public AjaxResult getInfo(@PathVariable Long dictCode)
+    {
+        return success(dictDataService.selectDictDataById(dictCode));
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁淇℃伅
+     */
+    @GetMapping(value = "/type/{dictType}")
+    public AjaxResult dictType(@PathVariable String dictType)
+    {
+        List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
+        if (StringUtils.isNull(data))
+        {
+            data = new ArrayList<SysDictData>();
+        }
+        return success(data);
+    }
+
+    /**
+     * 鏂板瀛楀吀绫诲瀷
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:add')")
+    @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysDictData dict)
+    {
+        dict.setCreateBy(getUsername());
+        return toAjax(dictDataService.insertDictData(dict));
+    }
+
+    /**
+     * 淇敼淇濆瓨瀛楀吀绫诲瀷
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
+    @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysDictData dict)
+    {
+        dict.setUpdateBy(getUsername());
+        return toAjax(dictDataService.updateDictData(dict));
+    }
+
+    /**
+     * 鍒犻櫎瀛楀吀绫诲瀷
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{dictCodes}")
+    public AjaxResult remove(@PathVariable Long[] dictCodes)
+    {
+        dictDataService.deleteDictDataByIds(dictCodes);
+        return success();
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java b/src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java
index f1a026f..a385016 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java
@@ -1,132 +1,132 @@
-package com.ruoyi.project.system.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-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.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.system.domain.SysDictType;
-import com.ruoyi.project.system.service.ISysDictTypeService;
-
-/**
- * 鏁版嵁瀛楀吀淇℃伅
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/dict/type")
-@AllArgsConstructor
-public class SysDictTypeController extends BaseController
-{
-    private ISysDictTypeService dictTypeService;
-
-    @PreAuthorize("@ss.hasPermi('system:dict:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysDictType dictType)
-    {
-        startPage();
-        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
-        return getDataTable(list);
-    }
-
-    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('system:dict:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysDictType dictType)
-    {
-        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
-        ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
-        util.exportExcel(response, list, "瀛楀吀绫诲瀷");
-    }
-
-    /**
-     * 鏌ヨ瀛楀吀绫诲瀷璇︾粏
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:query')")
-    @GetMapping(value = "/{dictId}")
-    public AjaxResult getInfo(@PathVariable Long dictId)
-    {
-        return success(dictTypeService.selectDictTypeById(dictId));
-    }
-
-    /**
-     * 鏂板瀛楀吀绫诲瀷
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:add')")
-    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysDictType dict)
-    {
-        if (!dictTypeService.checkDictTypeUnique(dict))
-        {
-            return error("鏂板瀛楀吀'" + dict.getDictName() + "'澶辫触锛屽瓧鍏哥被鍨嬪凡瀛樺湪");
-        }
-        dict.setCreateBy(getUsername());
-        return toAjax(dictTypeService.insertDictType(dict));
-    }
-
-    /**
-     * 淇敼瀛楀吀绫诲瀷
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
-    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysDictType dict)
-    {
-        if (!dictTypeService.checkDictTypeUnique(dict))
-        {
-            return error("淇敼瀛楀吀'" + dict.getDictName() + "'澶辫触锛屽瓧鍏哥被鍨嬪凡瀛樺湪");
-        }
-        dict.setUpdateBy(getUsername());
-        return toAjax(dictTypeService.updateDictType(dict));
-    }
-
-    /**
-     * 鍒犻櫎瀛楀吀绫诲瀷
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
-    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{dictIds}")
-    public AjaxResult remove(@PathVariable Long[] dictIds)
-    {
-        dictTypeService.deleteDictTypeByIds(dictIds);
-        return success();
-    }
-
-    /**
-     * 鍒锋柊瀛楀吀缂撳瓨
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
-    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.CLEAN)
-    @DeleteMapping("/refreshCache")
-    public AjaxResult refreshCache()
-    {
-        dictTypeService.resetDictCache();
-        return success();
-    }
-
-    /**
-     * 鑾峰彇瀛楀吀閫夋嫨妗嗗垪琛�
-     */
-    @GetMapping("/optionselect")
-    public AjaxResult optionselect()
-    {
-        List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
-        return success(dictTypes);
-    }
-}
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+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.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+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.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysDictType;
+import com.ruoyi.project.system.service.ISysDictTypeService;
+
+/**
+ * 鏁版嵁瀛楀吀淇℃伅
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/dict/type")
+@AllArgsConstructor
+public class SysDictTypeController extends BaseController
+{
+    private ISysDictTypeService dictTypeService;
+
+    @PreAuthorize("@ss.hasPermi('system:dict:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysDictType dictType)
+    {
+        startPage();
+        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
+        return getDataTable(list);
+    }
+
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:dict:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysDictType dictType)
+    {
+        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
+        ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
+        util.exportExcel(response, list, "瀛楀吀绫诲瀷");
+    }
+
+    /**
+     * 鏌ヨ瀛楀吀绫诲瀷璇︾粏
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:query')")
+    @GetMapping(value = "/{dictId}")
+    public AjaxResult getInfo(@PathVariable Long dictId)
+    {
+        return success(dictTypeService.selectDictTypeById(dictId));
+    }
+
+    /**
+     * 鏂板瀛楀吀绫诲瀷
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:add')")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysDictType dict)
+    {
+        if (!dictTypeService.checkDictTypeUnique(dict))
+        {
+            return error("鏂板瀛楀吀'" + dict.getDictName() + "'澶辫触锛屽瓧鍏哥被鍨嬪凡瀛樺湪");
+        }
+        dict.setCreateBy(getUsername());
+        return toAjax(dictTypeService.insertDictType(dict));
+    }
+
+    /**
+     * 淇敼瀛楀吀绫诲瀷
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysDictType dict)
+    {
+        if (!dictTypeService.checkDictTypeUnique(dict))
+        {
+            return error("淇敼瀛楀吀'" + dict.getDictName() + "'澶辫触锛屽瓧鍏哥被鍨嬪凡瀛樺湪");
+        }
+        dict.setUpdateBy(getUsername());
+        return toAjax(dictTypeService.updateDictType(dict));
+    }
+
+    /**
+     * 鍒犻櫎瀛楀吀绫诲瀷
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{dictIds}")
+    public AjaxResult remove(@PathVariable Long[] dictIds)
+    {
+        dictTypeService.deleteDictTypeByIds(dictIds);
+        return success();
+    }
+
+    /**
+     * 鍒锋柊瀛楀吀缂撳瓨
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/refreshCache")
+    public AjaxResult refreshCache()
+    {
+        dictTypeService.resetDictCache();
+        return success();
+    }
+
+    /**
+     * 鑾峰彇瀛楀吀閫夋嫨妗嗗垪琛�
+     */
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
+        return success(dictTypes);
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysLoginController.java b/src/main/java/com/ruoyi/project/system/controller/SysLoginController.java
index e5c5bfa..3334a07 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysLoginController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysLoginController.java
@@ -1,155 +1,155 @@
-package com.ruoyi.project.system.controller;
-
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.framework.security.LoginBody;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.security.service.SysLoginService;
-import com.ruoyi.framework.security.service.SysPermissionService;
-import com.ruoyi.framework.security.service.TokenService;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.project.system.domain.SysDept;
-import com.ruoyi.project.system.domain.SysMenu;
-import com.ruoyi.project.system.domain.SysUser;
-import com.ruoyi.project.system.domain.vo.SysUserDeptVo;
-import com.ruoyi.project.system.mapper.SysDeptMapper;
-import com.ruoyi.project.system.service.ISysMenuService;
-import com.ruoyi.project.system.service.ISysUserDeptService;
-import com.ruoyi.project.system.service.ISysUserService;
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.util.ObjectUtils;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * 鐧诲綍楠岃瘉
- * 
- * @author ruoyi
- */
-@RestController
-@AllArgsConstructor
-public class SysLoginController
-{
-    private SysLoginService loginService;
-    private ISysMenuService menuService;
-    private SysPermissionService permissionService;
-    private TokenService tokenService;
-    private ISysUserDeptService userDeptService;
-    private ISysUserService userService;
-    private SysDeptMapper sysDeptMapper;
-
-    /**
-     * 鐧诲綍鏂规硶
-     * 
-     * @param loginBody 鐧诲綍淇℃伅
-     * @return 缁撴灉
-     */
-    @PostMapping("/login")
-    public AjaxResult login(@RequestBody LoginBody loginBody)
-    {
-        AjaxResult ajax = AjaxResult.success();
-        // 鐢熸垚浠ょ墝
-        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
-                loginBody.getUuid());
-        ajax.put(Constants.TOKEN, token);
-        return ajax;
-    }
-
-    /**
-     * 鑾峰彇鐢ㄦ埛淇℃伅
-     * 
-     * @return 鐢ㄦ埛淇℃伅
-     */
-    @GetMapping("/getInfo")
-    public AjaxResult getInfo()
-    {
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        SysUser user = loginUser.getUser();
-        // 鑾峰彇褰撳墠鐧诲綍鍏徃
-        Long tenantId = loginUser.getTenantId();
-        if(null != tenantId){
-            user.setTenantId(tenantId);
-            SysDept sysDept = sysDeptMapper.selectDeptById(tenantId.longValue());
-            if(!ObjectUtils.isEmpty(sysDept)){
-                user.setCurrentFactoryName(sysDept.getDeptName());
-            }
-        }
-        // 瑙掕壊闆嗗悎
-        Set<String> roles = permissionService.getRolePermission(user);
-        // 鏉冮檺闆嗗悎
-        Set<String> permissions = permissionService.getMenuPermission(user);
-        if (!loginUser.getPermissions().equals(permissions))
-        {
-            loginUser.setPermissions(permissions);
-            tokenService.refreshToken(loginUser);
-        }
-        AjaxResult ajax = AjaxResult.success();
-        ajax.put("user", user);
-        ajax.put("aiEnabled", loginUser.getAiEnabled());
-        ajax.put("roles", roles);
-        ajax.put("permissions", permissions);
-        return ajax;
-    }
-
-    /**
-     * 鑾峰彇璺敱淇℃伅
-     * 
-     * @return 璺敱淇℃伅
-     */
-    @GetMapping("getRouters")
-    public AjaxResult getRouters()
-    {
-        Long userId = SecurityUtils.getUserId();
-        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
-        return AjaxResult.success(menuService.buildMenus(menus));
-    }
-
-    @PostMapping("/loginCheck")
-    public AjaxResult loginCheck(@RequestBody LoginBody loginBody)
-    {
-        try {
-            Long userId = loginService.loginCheck(loginBody.getUsername(), loginBody.getPassword());
-            return AjaxResult.success(userId);
-        }catch (Exception e) {
-            return AjaxResult.error(e.getMessage());
-        }
-    }
-
-    @GetMapping("/userLoginFacotryList")
-    public AjaxResult userLoginFacotryList(SysUserDeptVo sysUserDeptVo){
-        List<SysUserDeptVo> sysUserDeptVoList = userDeptService.userLoginFacotryList(sysUserDeptVo);
-        Map<Long, SysUserDeptVo> map = sysUserDeptVoList.stream()
-            .collect(Collectors.toMap(
-                    SysUserDeptVo::getDeptId,
-                    item -> item,
-                    (existing, replacement) -> existing // 濡傛灉閲嶅锛屼繚鐣欑涓�涓�
-            ));
-        List<SysUserDeptVo> uniqueList = new ArrayList<>(map.values());
-        return AjaxResult.success(uniqueList);
-    }
-
-    /**
-     * 閫夋嫨鍏徃鐧诲綍
-     *
-     * @param loginBody 鐧诲綍淇℃伅
-     * @return 缁撴灉
-     */
-    @PostMapping("/loginCheckFactory")
-    public AjaxResult loginCheckFactory(@RequestBody LoginBody loginBody)
-    {
-        AjaxResult ajax = AjaxResult.success();
-        // 鐢熸垚浠ょ墝
-        String token = loginService.loginCheckFactory(loginBody.getUsername(), loginBody.getPassword(),loginBody.getFactoryId());
-        ajax.put(Constants.TOKEN, token);
-        return ajax;
-    }
-}
+package com.ruoyi.project.system.controller;
+
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.security.LoginBody;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.framework.security.service.SysLoginService;
+import com.ruoyi.framework.security.service.SysPermissionService;
+import com.ruoyi.framework.security.service.TokenService;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.project.system.domain.SysDept;
+import com.ruoyi.project.system.domain.SysMenu;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.domain.vo.SysUserDeptVo;
+import com.ruoyi.project.system.mapper.SysDeptMapper;
+import com.ruoyi.project.system.service.ISysMenuService;
+import com.ruoyi.project.system.service.ISysUserDeptService;
+import com.ruoyi.project.system.service.ISysUserService;
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.ObjectUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 鐧诲綍楠岃瘉
+ * 
+ * @author ruoyi
+ */
+@RestController
+@AllArgsConstructor
+public class SysLoginController
+{
+    private SysLoginService loginService;
+    private ISysMenuService menuService;
+    private SysPermissionService permissionService;
+    private TokenService tokenService;
+    private ISysUserDeptService userDeptService;
+    private ISysUserService userService;
+    private SysDeptMapper sysDeptMapper;
+
+    /**
+     * 鐧诲綍鏂规硶
+     * 
+     * @param loginBody 鐧诲綍淇℃伅
+     * @return 缁撴灉
+     */
+    @PostMapping("/login")
+    public AjaxResult login(@RequestBody LoginBody loginBody)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        // 鐢熸垚浠ょ墝
+        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
+                loginBody.getUuid());
+        ajax.put(Constants.TOKEN, token);
+        return ajax;
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛淇℃伅
+     * 
+     * @return 鐢ㄦ埛淇℃伅
+     */
+    @GetMapping("/getInfo")
+    public AjaxResult getInfo()
+    {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        SysUser user = loginUser.getUser();
+        // 鑾峰彇褰撳墠鐧诲綍鍏徃
+        Long tenantId = loginUser.getTenantId();
+        if(null != tenantId){
+            user.setTenantId(tenantId);
+            SysDept sysDept = sysDeptMapper.selectDeptById(tenantId.longValue());
+            if(!ObjectUtils.isEmpty(sysDept)){
+                user.setCurrentFactoryName(sysDept.getDeptName());
+            }
+        }
+        // 瑙掕壊闆嗗悎
+        Set<String> roles = permissionService.getRolePermission(user);
+        // 鏉冮檺闆嗗悎
+        Set<String> permissions = permissionService.getMenuPermission(user);
+        if (!loginUser.getPermissions().equals(permissions))
+        {
+            loginUser.setPermissions(permissions);
+            tokenService.refreshToken(loginUser);
+        }
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("user", user);
+        ajax.put("aiEnabled", loginUser.getAiEnabled());
+        ajax.put("roles", roles);
+        ajax.put("permissions", permissions);
+        return ajax;
+    }
+
+    /**
+     * 鑾峰彇璺敱淇℃伅
+     * 
+     * @return 璺敱淇℃伅
+     */
+    @GetMapping("getRouters")
+    public AjaxResult getRouters()
+    {
+        Long userId = SecurityUtils.getUserId();
+        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
+        return AjaxResult.success(menuService.buildMenus(menus));
+    }
+
+    @PostMapping("/loginCheck")
+    public AjaxResult loginCheck(@RequestBody LoginBody loginBody)
+    {
+        try {
+            Long userId = loginService.loginCheck(loginBody.getUsername(), loginBody.getPassword());
+            return AjaxResult.success(userId);
+        }catch (Exception e) {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+
+    @GetMapping("/userLoginFacotryList")
+    public AjaxResult userLoginFacotryList(SysUserDeptVo sysUserDeptVo){
+        List<SysUserDeptVo> sysUserDeptVoList = userDeptService.userLoginFacotryList(sysUserDeptVo);
+        Map<Long, SysUserDeptVo> map = sysUserDeptVoList.stream()
+            .collect(Collectors.toMap(
+                    SysUserDeptVo::getDeptId,
+                    item -> item,
+                    (existing, replacement) -> existing // 濡傛灉閲嶅锛屼繚鐣欑涓�涓�
+            ));
+        List<SysUserDeptVo> uniqueList = new ArrayList<>(map.values());
+        return AjaxResult.success(uniqueList);
+    }
+
+    /**
+     * 閫夋嫨鍏徃鐧诲綍
+     *
+     * @param loginBody 鐧诲綍淇℃伅
+     * @return 缁撴灉
+     */
+    @PostMapping("/loginCheckFactory")
+    public AjaxResult loginCheckFactory(@RequestBody LoginBody loginBody)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        // 鐢熸垚浠ょ墝
+        String token = loginService.loginCheckFactory(loginBody.getUsername(), loginBody.getPassword(),loginBody.getFactoryId());
+        ajax.put(Constants.TOKEN, token);
+        return ajax;
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java b/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java
index 865e8a4..a59bdb3 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java
@@ -1,136 +1,136 @@
-package com.ruoyi.project.system.controller;
-
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.utils.StringUtils;
-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.AjaxResult;
-import com.ruoyi.project.system.domain.SysMenu;
-import com.ruoyi.project.system.service.ISysMenuService;
-import lombok.AllArgsConstructor;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-/**
- * 鑿滃崟淇℃伅
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/menu")
-@AllArgsConstructor
-public class SysMenuController extends BaseController
-{
-    private ISysMenuService menuService;
-
-    /**
-     * 鑾峰彇鑿滃崟鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('system:menu:list')")
-    @GetMapping("/list")
-    public AjaxResult list(SysMenu menu)
-    {
-        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
-        return success(menus);
-    }
-
-    /**
-     * 鏍规嵁鑿滃崟缂栧彿鑾峰彇璇︾粏淇℃伅
-     */
-    @PreAuthorize("@ss.hasPermi('system:menu:query')")
-    @GetMapping(value = "/{menuId}")
-    public AjaxResult getInfo(@PathVariable Long menuId)
-    {
-        return success(menuService.selectMenuById(menuId));
-    }
-
-    /**
-     * 鑾峰彇鑿滃崟涓嬫媺鏍戝垪琛�
-     */
-    @GetMapping("/treeselect")
-    public AjaxResult treeselect(SysMenu menu)
-    {
-        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
-        return success(menuService.buildMenuTreeSelect(menus));
-    }
-
-    /**
-     * 鍔犺浇瀵瑰簲瑙掕壊鑿滃崟鍒楄〃鏍�
-     */
-    @GetMapping(value = "/roleMenuTreeselect/{roleId}")
-    public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
-    {
-        List<SysMenu> menus = menuService.selectMenuList(getUserId());
-        AjaxResult ajax = AjaxResult.success();
-        ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
-        ajax.put("menus", menuService.buildMenuTreeSelect(menus));
-        return ajax;
-    }
-
-    /**
-     * 鏂板鑿滃崟
-     */
-    @PreAuthorize("@ss.hasPermi('system:menu:add')")
-    @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysMenu menu)
-    {
-        if (!menuService.checkMenuNameUnique(menu))
-        {
-            return error("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
-        }
-        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
-        {
-            return error("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�");
-        }
-        menu.setCreateBy(getUsername());
-        return toAjax(menuService.insertMenu(menu));
-    }
-
-    /**
-     * 淇敼鑿滃崟
-     */
-    @PreAuthorize("@ss.hasPermi('system:menu:edit')")
-    @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysMenu menu)
-    {
-        if (!menuService.checkMenuNameUnique(menu))
-        {
-            return error("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
-        }
-        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
-        {
-            return error("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�");
-        }
-        else if (menu.getMenuId().equals(menu.getParentId()))
-        {
-            return error("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屼笂绾ц彍鍗曚笉鑳介�夋嫨鑷繁");
-        }
-        menu.setUpdateBy(getUsername());
-        return toAjax(menuService.updateMenu(menu));
-    }
-
-    /**
-     * 鍒犻櫎鑿滃崟
-     */
-    @PreAuthorize("@ss.hasPermi('system:menu:remove')")
-    @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{menuId}")
-    public AjaxResult remove(@PathVariable("menuId") Long menuId)
-    {
-        if (menuService.hasChildByMenuId(menuId))
-        {
-            return warn("瀛樺湪瀛愯彍鍗�,涓嶅厑璁稿垹闄�");
-        }
-        if (menuService.checkMenuExistRole(menuId))
-        {
-            return warn("鑿滃崟宸插垎閰�,涓嶅厑璁稿垹闄�");
-        }
-        return toAjax(menuService.deleteMenuById(menuId));
-    }
+package com.ruoyi.project.system.controller;
+
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.StringUtils;
+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.AjaxResult;
+import com.ruoyi.project.system.domain.SysMenu;
+import com.ruoyi.project.system.service.ISysMenuService;
+import lombok.AllArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 鑿滃崟淇℃伅
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/menu")
+@AllArgsConstructor
+public class SysMenuController extends BaseController
+{
+    private ISysMenuService menuService;
+
+    /**
+     * 鑾峰彇鑿滃崟鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:list')")
+    @GetMapping("/list")
+    public AjaxResult list(SysMenu menu)
+    {
+        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
+        return success(menus);
+    }
+
+    /**
+     * 鏍规嵁鑿滃崟缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:query')")
+    @GetMapping(value = "/{menuId}")
+    public AjaxResult getInfo(@PathVariable Long menuId)
+    {
+        return success(menuService.selectMenuById(menuId));
+    }
+
+    /**
+     * 鑾峰彇鑿滃崟涓嬫媺鏍戝垪琛�
+     */
+    @GetMapping("/treeselect")
+    public AjaxResult treeselect(SysMenu menu)
+    {
+        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
+        return success(menuService.buildMenuTreeSelect(menus));
+    }
+
+    /**
+     * 鍔犺浇瀵瑰簲瑙掕壊鑿滃崟鍒楄〃鏍�
+     */
+    @GetMapping(value = "/roleMenuTreeselect/{roleId}")
+    public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
+    {
+        List<SysMenu> menus = menuService.selectMenuList(getUserId());
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
+        ajax.put("menus", menuService.buildMenuTreeSelect(menus));
+        return ajax;
+    }
+
+    /**
+     * 鏂板鑿滃崟
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:add')")
+    @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysMenu menu)
+    {
+        if (!menuService.checkMenuNameUnique(menu))
+        {
+            return error("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
+        }
+        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
+        {
+            return error("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�");
+        }
+        menu.setCreateBy(getUsername());
+        return toAjax(menuService.insertMenu(menu));
+    }
+
+    /**
+     * 淇敼鑿滃崟
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:edit')")
+    @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysMenu menu)
+    {
+        if (!menuService.checkMenuNameUnique(menu))
+        {
+            return error("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
+        }
+        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
+        {
+            return error("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�");
+        }
+        else if (menu.getMenuId().equals(menu.getParentId()))
+        {
+            return error("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屼笂绾ц彍鍗曚笉鑳介�夋嫨鑷繁");
+        }
+        menu.setUpdateBy(getUsername());
+        return toAjax(menuService.updateMenu(menu));
+    }
+
+    /**
+     * 鍒犻櫎鑿滃崟
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:remove')")
+    @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{menuId}")
+    public AjaxResult remove(@PathVariable("menuId") Long menuId)
+    {
+        if (menuService.hasChildByMenuId(menuId))
+        {
+            return warn("瀛樺湪瀛愯彍鍗�,涓嶅厑璁稿垹闄�");
+        }
+        if (menuService.checkMenuExistRole(menuId))
+        {
+            return warn("鑿滃崟宸插垎閰�,涓嶅厑璁稿垹闄�");
+        }
+        return toAjax(menuService.deleteMenuById(menuId));
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java b/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java
index 5aa3413..eaba7d0 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java
@@ -1,96 +1,96 @@
-package com.ruoyi.project.system.controller;
-
-import java.util.List;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.framework.web.domain.R;
-import io.swagger.v3.oas.annotations.Operation;
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.system.domain.SysNotice;
-import com.ruoyi.project.system.service.ISysNoticeService;
-
-/**
- * 鍏憡 淇℃伅鎿嶄綔澶勭悊
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/notice")
-@AllArgsConstructor
-public class SysNoticeController extends BaseController {
-    private ISysNoticeService noticeService;
-
-    /**
-     * 鑾峰彇閫氱煡鍏憡鍒楄〃
-     */
-    @GetMapping("/list")
-    public R<IPage<SysNotice>> list(SysNotice notice, Page page) {
-        IPage<SysNotice> list = noticeService.selectNoticeList(notice, page);
-        return R.ok(list);
-    }
-
-    /**
-     * 鑾峰彇鏈鏁伴噺
-     */
-    @GetMapping("/getCount")
-    public R getCount(Long consigneeId) {
-        return R.ok(noticeService.getCount(consigneeId));
-    }
-
-    /**
-     * 鏍规嵁閫氱煡鍏憡缂栧彿鑾峰彇璇︾粏淇℃伅
-     */
-    @GetMapping(value = "/{noticeId}")
-    public AjaxResult getInfo(@PathVariable Long noticeId) {
-        return success(noticeService.selectNoticeById(noticeId));
-    }
-
-    /**
-     * 鏂板閫氱煡鍏憡
-     */
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysNotice notice) {
-        return toAjax(noticeService.insertNotice(notice));
-    }
-
-    /**
-     * 淇敼閫氱煡鍏憡
-     */
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysNotice notice) {
-        return toAjax(noticeService.updateNotice(notice));
-    }
-
-    /**
-     * 鍒犻櫎閫氱煡鍏憡
-     */
-    @DeleteMapping("/{noticeIds}")
-    public AjaxResult remove(@PathVariable Long[] noticeIds) {
-        return toAjax(noticeService.deleteNoticeByIds(noticeIds));
-    }
-
-    /**
-     * 涓�閿凡璇�
-     */
-    @PostMapping("/readAll")
-    public AjaxResult readAll() {
-        return toAjax(noticeService.readAll());
-    }
-
-    @PostMapping("appReadNotice")
-    @Operation(summary = "绉诲姩绔牴鎹秷鎭疘D杩涜宸茶")
-    public AjaxResult appReadNotice(@RequestParam("noticeId") Long noticeId) {
-        boolean result = noticeService.appReadNotice(noticeId);
-        return toAjax(result);
-    }
-}
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.framework.web.domain.R;
+import io.swagger.v3.oas.annotations.Operation;
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+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.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysNotice;
+import com.ruoyi.project.system.service.ISysNoticeService;
+
+/**
+ * 鍏憡 淇℃伅鎿嶄綔澶勭悊
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/notice")
+@AllArgsConstructor
+public class SysNoticeController extends BaseController {
+    private ISysNoticeService noticeService;
+
+    /**
+     * 鑾峰彇閫氱煡鍏憡鍒楄〃
+     */
+    @GetMapping("/list")
+    public R<IPage<SysNotice>> list(SysNotice notice, Page page) {
+        IPage<SysNotice> list = noticeService.selectNoticeList(notice, page);
+        return R.ok(list);
+    }
+
+    /**
+     * 鑾峰彇鏈鏁伴噺
+     */
+    @GetMapping("/getCount")
+    public R getCount(Long consigneeId) {
+        return R.ok(noticeService.getCount(consigneeId));
+    }
+
+    /**
+     * 鏍规嵁閫氱煡鍏憡缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @GetMapping(value = "/{noticeId}")
+    public AjaxResult getInfo(@PathVariable Long noticeId) {
+        return success(noticeService.selectNoticeById(noticeId));
+    }
+
+    /**
+     * 鏂板閫氱煡鍏憡
+     */
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysNotice notice) {
+        return toAjax(noticeService.insertNotice(notice));
+    }
+
+    /**
+     * 淇敼閫氱煡鍏憡
+     */
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysNotice notice) {
+        return toAjax(noticeService.updateNotice(notice));
+    }
+
+    /**
+     * 鍒犻櫎閫氱煡鍏憡
+     */
+    @DeleteMapping("/{noticeIds}")
+    public AjaxResult remove(@PathVariable Long[] noticeIds) {
+        return toAjax(noticeService.deleteNoticeByIds(noticeIds));
+    }
+
+    /**
+     * 涓�閿凡璇�
+     */
+    @PostMapping("/readAll")
+    public AjaxResult readAll() {
+        return toAjax(noticeService.readAll());
+    }
+
+    @PostMapping("appReadNotice")
+    @Operation(summary = "绉诲姩绔牴鎹秷鎭疘D杩涜宸茶")
+    public AjaxResult appReadNotice(@RequestParam("noticeId") Long noticeId) {
+        boolean result = noticeService.appReadNotice(noticeId);
+        return toAjax(result);
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysPostController.java b/src/main/java/com/ruoyi/project/system/controller/SysPostController.java
index a4776c4..45c5bcc 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysPostController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysPostController.java
@@ -1,133 +1,133 @@
-package com.ruoyi.project.system.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-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.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.system.domain.SysPost;
-import com.ruoyi.project.system.service.ISysPostService;
-
-/**
- * 宀椾綅淇℃伅鎿嶄綔澶勭悊
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/post")
-@AllArgsConstructor
-public class SysPostController extends BaseController
-{
-    private ISysPostService postService;
-
-    /**
-     * 鑾峰彇宀椾綅鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('system:post:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysPost post)
-    {
-        startPage();
-        List<SysPost> list = postService.selectPostList(post);
-        return getDataTable(list);
-    }
-    /**
-     * 瀵煎嚭宀椾綅鍒楄〃
-     */
-    
-    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('system:post:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysPost post)
-    {
-        List<SysPost> list = postService.selectPostList(post);
-        ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
-        util.exportExcel(response, list, "宀椾綅鏁版嵁");
-    }
-
-    /**
-     * 鏍规嵁宀椾綅缂栧彿鑾峰彇璇︾粏淇℃伅
-     */
-    @PreAuthorize("@ss.hasPermi('system:post:query')")
-    @GetMapping(value = "/{postId}")
-    public AjaxResult getInfo(@PathVariable Long postId)
-    {
-        return success(postService.selectPostById(postId));
-    }
-
-    /**
-     * 鏂板宀椾綅
-     */
-    @PreAuthorize("@ss.hasPermi('system:post:add')")
-    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysPost post)
-    {
-        if (!postService.checkPostNameUnique(post))
-        {
-            return error("鏂板宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶅悕绉板凡瀛樺湪");
-        }
-        else if (!postService.checkPostCodeUnique(post))
-        {
-            return error("鏂板宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
-        }
-        post.setCreateBy(getUsername());
-        return toAjax(postService.insertPost(post));
-    }
-
-    /**
-     * 淇敼宀椾綅
-     */
-    @PreAuthorize("@ss.hasPermi('system:post:edit')")
-    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysPost post)
-    {
-        if (!postService.checkPostNameUnique(post))
-        {
-            return error("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶅悕绉板凡瀛樺湪");
-        }
-        else if (!postService.checkPostCodeUnique(post))
-        {
-            return error("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
-        }
-        post.setUpdateBy(getUsername());
-        return toAjax(postService.updatePost(post));
-    }
-
-    /**
-     * 鍒犻櫎宀椾綅
-     */
-    @PreAuthorize("@ss.hasPermi('system:post:remove')")
-    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{postIds}")
-    public AjaxResult remove(@PathVariable Long[] postIds)
-    {
-        return toAjax(postService.deletePostByIds(postIds));
-    }
-
-    /**
-     * 鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
-     */
-    @GetMapping("/optionselect")
-    public AjaxResult optionselect()
-    {
-        List<SysPost> posts = postService.selectPostAll();
-        return success(posts);
-    }
-}
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+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.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+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.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysPost;
+import com.ruoyi.project.system.service.ISysPostService;
+
+/**
+ * 宀椾綅淇℃伅鎿嶄綔澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/post")
+@AllArgsConstructor
+public class SysPostController extends BaseController
+{
+    private ISysPostService postService;
+
+    /**
+     * 鑾峰彇宀椾綅鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysPost post)
+    {
+        startPage();
+        List<SysPost> list = postService.selectPostList(post);
+        return getDataTable(list);
+    }
+    /**
+     * 瀵煎嚭宀椾綅鍒楄〃
+     */
+    
+    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:post:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysPost post)
+    {
+        List<SysPost> list = postService.selectPostList(post);
+        ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
+        util.exportExcel(response, list, "宀椾綅鏁版嵁");
+    }
+
+    /**
+     * 鏍规嵁宀椾綅缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:query')")
+    @GetMapping(value = "/{postId}")
+    public AjaxResult getInfo(@PathVariable Long postId)
+    {
+        return success(postService.selectPostById(postId));
+    }
+
+    /**
+     * 鏂板宀椾綅
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:add')")
+    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysPost post)
+    {
+        if (!postService.checkPostNameUnique(post))
+        {
+            return error("鏂板宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶅悕绉板凡瀛樺湪");
+        }
+        else if (!postService.checkPostCodeUnique(post))
+        {
+            return error("鏂板宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
+        }
+        post.setCreateBy(getUsername());
+        return toAjax(postService.insertPost(post));
+    }
+
+    /**
+     * 淇敼宀椾綅
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:edit')")
+    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysPost post)
+    {
+        if (!postService.checkPostNameUnique(post))
+        {
+            return error("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶅悕绉板凡瀛樺湪");
+        }
+        else if (!postService.checkPostCodeUnique(post))
+        {
+            return error("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
+        }
+        post.setUpdateBy(getUsername());
+        return toAjax(postService.updatePost(post));
+    }
+
+    /**
+     * 鍒犻櫎宀椾綅
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:remove')")
+    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{postIds}")
+    public AjaxResult remove(@PathVariable Long[] postIds)
+    {
+        return toAjax(postService.deletePostByIds(postIds));
+    }
+
+    /**
+     * 鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
+     */
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        List<SysPost> posts = postService.selectPostAll();
+        return success(posts);
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysProfileController.java b/src/main/java/com/ruoyi/project/system/controller/SysProfileController.java
index 62f6db5..66e89e2 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysProfileController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysProfileController.java
@@ -1,133 +1,133 @@
-package com.ruoyi.project.system.controller;
-
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.file.FileUploadUtils;
-import com.ruoyi.common.utils.file.MimeTypeUtils;
-import com.ruoyi.framework.aspectj.lang.annotation.Log;
-import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
-import com.ruoyi.framework.config.RuoYiConfig;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.security.service.TokenService;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.project.system.domain.SysUser;
-import com.ruoyi.project.system.service.ISysUserService;
-import lombok.AllArgsConstructor;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.util.Map;
-
-/**
- * 涓汉淇℃伅 涓氬姟澶勭悊
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/user/profile")
-@AllArgsConstructor
-public class SysProfileController extends BaseController
-{
-    private ISysUserService userService;
-    private TokenService tokenService;
-
-    /**
-     * 涓汉淇℃伅
-     */
-    @GetMapping
-    public AjaxResult profile()
-    {
-        LoginUser loginUser = getLoginUser();
-        SysUser user = loginUser.getUser();
-        AjaxResult ajax = AjaxResult.success(user);
-        ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
-        ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
-        return ajax;
-    }
-
-    /**
-     * 淇敼鐢ㄦ埛
-     */
-    @Log(title = "涓汉淇℃伅", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult updateProfile(@RequestBody SysUser user)
-    {
-        LoginUser loginUser = getLoginUser();
-        SysUser currentUser = loginUser.getUser();
-        currentUser.setNickName(user.getNickName());
-        currentUser.setEmail(user.getEmail());
-        currentUser.setPhonenumber(user.getPhonenumber());
-        currentUser.setSex(user.getSex());
-        if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
-        {
-            return error("淇敼鐢ㄦ埛'" + loginUser.getUsername() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
-        }
-        if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
-        {
-            return error("淇敼鐢ㄦ埛'" + loginUser.getUsername() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
-        }
-        if (userService.updateUserProfile(currentUser) > 0)
-        {
-            // 鏇存柊缂撳瓨鐢ㄦ埛淇℃伅
-            tokenService.setLoginUser(loginUser);
-            return success();
-        }
-        return error("淇敼涓汉淇℃伅寮傚父锛岃鑱旂郴绠$悊鍛�");
-    }
-
-    /**
-     * 閲嶇疆瀵嗙爜
-     */
-    @Log(title = "涓汉淇℃伅", businessType = BusinessType.UPDATE)
-    @PutMapping("/updatePwd")
-    public AjaxResult updatePwd(@RequestBody Map<String, String> params)
-    {
-        String oldPassword = params.get("oldPassword");
-        String newPassword = params.get("newPassword");
-        LoginUser loginUser = getLoginUser();
-        String userName = loginUser.getUsername();
-        String password = loginUser.getPassword();
-        if (!SecurityUtils.matchesPassword(oldPassword, password))
-        {
-            return error("淇敼瀵嗙爜澶辫触锛屾棫瀵嗙爜閿欒");
-        }
-        if (SecurityUtils.matchesPassword(newPassword, password))
-        {
-            return error("鏂板瘑鐮佷笉鑳戒笌鏃у瘑鐮佺浉鍚�");
-        }
-        newPassword = SecurityUtils.encryptPassword(newPassword);
-        if (userService.resetUserPwd(userName, newPassword) > 0)
-        {
-            // 鏇存柊缂撳瓨鐢ㄦ埛瀵嗙爜
-            loginUser.getUser().setPassword(newPassword);
-            tokenService.setLoginUser(loginUser);
-            return success();
-        }
-        return error("淇敼瀵嗙爜寮傚父锛岃鑱旂郴绠$悊鍛�");
-    }
-
-    /**
-     * 澶村儚涓婁紶
-     */
-    @Log(title = "鐢ㄦ埛澶村儚", businessType = BusinessType.UPDATE)
-    @PostMapping("/avatar")
-    public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
-    {
-        if (!file.isEmpty())
-        {
-            LoginUser loginUser = getLoginUser();
-            String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION);
-            if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
-            {
-                AjaxResult ajax = AjaxResult.success();
-                ajax.put("imgUrl", avatar);
-                // 鏇存柊缂撳瓨鐢ㄦ埛澶村儚
-                loginUser.getUser().setAvatar(avatar);
-                tokenService.setLoginUser(loginUser);
-                return ajax;
-            }
-        }
-        return error("涓婁紶鍥剧墖寮傚父锛岃鑱旂郴绠$悊鍛�");
-    }
-}
+package com.ruoyi.project.system.controller;
+
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.file.FileUploadUtils;
+import com.ruoyi.common.utils.file.MimeTypeUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.config.RuoYiConfig;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.framework.security.service.TokenService;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.service.ISysUserService;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Map;
+
+/**
+ * 涓汉淇℃伅 涓氬姟澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/user/profile")
+@AllArgsConstructor
+public class SysProfileController extends BaseController
+{
+    private ISysUserService userService;
+    private TokenService tokenService;
+
+    /**
+     * 涓汉淇℃伅
+     */
+    @GetMapping
+    public AjaxResult profile()
+    {
+        LoginUser loginUser = getLoginUser();
+        SysUser user = loginUser.getUser();
+        AjaxResult ajax = AjaxResult.success(user);
+        ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
+        ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
+        return ajax;
+    }
+
+    /**
+     * 淇敼鐢ㄦ埛
+     */
+    @Log(title = "涓汉淇℃伅", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult updateProfile(@RequestBody SysUser user)
+    {
+        LoginUser loginUser = getLoginUser();
+        SysUser currentUser = loginUser.getUser();
+        currentUser.setNickName(user.getNickName());
+        currentUser.setEmail(user.getEmail());
+        currentUser.setPhonenumber(user.getPhonenumber());
+        currentUser.setSex(user.getSex());
+        if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
+        {
+            return error("淇敼鐢ㄦ埛'" + loginUser.getUsername() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
+        }
+        if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
+        {
+            return error("淇敼鐢ㄦ埛'" + loginUser.getUsername() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
+        }
+        if (userService.updateUserProfile(currentUser) > 0)
+        {
+            // 鏇存柊缂撳瓨鐢ㄦ埛淇℃伅
+            tokenService.setLoginUser(loginUser);
+            return success();
+        }
+        return error("淇敼涓汉淇℃伅寮傚父锛岃鑱旂郴绠$悊鍛�");
+    }
+
+    /**
+     * 閲嶇疆瀵嗙爜
+     */
+    @Log(title = "涓汉淇℃伅", businessType = BusinessType.UPDATE)
+    @PutMapping("/updatePwd")
+    public AjaxResult updatePwd(@RequestBody Map<String, String> params)
+    {
+        String oldPassword = params.get("oldPassword");
+        String newPassword = params.get("newPassword");
+        LoginUser loginUser = getLoginUser();
+        String userName = loginUser.getUsername();
+        String password = loginUser.getPassword();
+        if (!SecurityUtils.matchesPassword(oldPassword, password))
+        {
+            return error("淇敼瀵嗙爜澶辫触锛屾棫瀵嗙爜閿欒");
+        }
+        if (SecurityUtils.matchesPassword(newPassword, password))
+        {
+            return error("鏂板瘑鐮佷笉鑳戒笌鏃у瘑鐮佺浉鍚�");
+        }
+        newPassword = SecurityUtils.encryptPassword(newPassword);
+        if (userService.resetUserPwd(userName, newPassword) > 0)
+        {
+            // 鏇存柊缂撳瓨鐢ㄦ埛瀵嗙爜
+            loginUser.getUser().setPassword(newPassword);
+            tokenService.setLoginUser(loginUser);
+            return success();
+        }
+        return error("淇敼瀵嗙爜寮傚父锛岃鑱旂郴绠$悊鍛�");
+    }
+
+    /**
+     * 澶村儚涓婁紶
+     */
+    @Log(title = "鐢ㄦ埛澶村儚", businessType = BusinessType.UPDATE)
+    @PostMapping("/avatar")
+    public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
+    {
+        if (!file.isEmpty())
+        {
+            LoginUser loginUser = getLoginUser();
+            String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION);
+            if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
+            {
+                AjaxResult ajax = AjaxResult.success();
+                ajax.put("imgUrl", avatar);
+                // 鏇存柊缂撳瓨鐢ㄦ埛澶村儚
+                loginUser.getUser().setAvatar(avatar);
+                tokenService.setLoginUser(loginUser);
+                return ajax;
+            }
+        }
+        return error("涓婁紶鍥剧墖寮傚父锛岃鑱旂郴绠$悊鍛�");
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysRegisterController.java b/src/main/java/com/ruoyi/project/system/controller/SysRegisterController.java
index ca7baf5..aa672cf 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysRegisterController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysRegisterController.java
@@ -1,33 +1,33 @@
-package com.ruoyi.project.system.controller;
-
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.security.RegisterBody;
-import com.ruoyi.framework.security.service.SysRegisterService;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.project.system.service.ISysConfigService;
-import lombok.AllArgsConstructor;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * 娉ㄥ唽楠岃瘉
- *
- * @author ruoyi
- */
-@RestController
-@AllArgsConstructor
-public class SysRegisterController extends BaseController {
-    private SysRegisterService registerService;
-    private ISysConfigService configService;
-
-    @PostMapping("/register")
-    public AjaxResult register(@RequestBody RegisterBody user) {
-        if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
-            return error("褰撳墠绯荤粺娌℃湁寮�鍚敞鍐屽姛鑳斤紒");
-        }
-        String msg = registerService.register(user);
-        return StringUtils.isEmpty(msg) ? success() : error(msg);
-    }
-}
+package com.ruoyi.project.system.controller;
+
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.security.RegisterBody;
+import com.ruoyi.framework.security.service.SysRegisterService;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.project.system.service.ISysConfigService;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 娉ㄥ唽楠岃瘉
+ *
+ * @author ruoyi
+ */
+@RestController
+@AllArgsConstructor
+public class SysRegisterController extends BaseController {
+    private SysRegisterService registerService;
+    private ISysConfigService configService;
+
+    @PostMapping("/register")
+    public AjaxResult register(@RequestBody RegisterBody user) {
+        if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
+            return error("褰撳墠绯荤粺娌℃湁寮�鍚敞鍐屽姛鑳斤紒");
+        }
+        String msg = registerService.register(user);
+        return StringUtils.isEmpty(msg) ? success() : error(msg);
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysRoleController.java b/src/main/java/com/ruoyi/project/system/controller/SysRoleController.java
index 3b05811..5f65a8d 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysRoleController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysRoleController.java
@@ -1,255 +1,255 @@
-package com.ruoyi.project.system.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-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.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.framework.aspectj.lang.annotation.Log;
-import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.framework.security.service.SysPermissionService;
-import com.ruoyi.framework.security.service.TokenService;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.system.domain.SysDept;
-import com.ruoyi.project.system.domain.SysRole;
-import com.ruoyi.project.system.domain.SysUser;
-import com.ruoyi.project.system.domain.SysUserRole;
-import com.ruoyi.project.system.service.ISysDeptService;
-import com.ruoyi.project.system.service.ISysRoleService;
-import com.ruoyi.project.system.service.ISysUserService;
-
-/**
- * 瑙掕壊淇℃伅
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/role")
-@AllArgsConstructor
-public class SysRoleController extends BaseController
-{
-    private ISysRoleService roleService;
-    private TokenService tokenService;
-    private SysPermissionService permissionService;
-    private ISysUserService userService;
-    private ISysDeptService deptService;
-
-    @PreAuthorize("@ss.hasPermi('system:role:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysRole role)
-    {
-        startPage();
-        List<SysRole> list = roleService.selectRoleList(role);
-        return getDataTable(list);
-    }
-
-    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('system:role:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysRole role)
-    {
-        List<SysRole> list = roleService.selectRoleList(role);
-        ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
-        util.exportExcel(response, list, "瑙掕壊鏁版嵁");
-    }
-
-    /**
-     * 鏍规嵁瑙掕壊缂栧彿鑾峰彇璇︾粏淇℃伅
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:query')")
-    @GetMapping(value = "/{roleId}")
-    public AjaxResult getInfo(@PathVariable Long roleId)
-    {
-        roleService.checkRoleDataScope(roleId);
-        return success(roleService.selectRoleById(roleId));
-    }
-
-    /**
-     * 鏂板瑙掕壊
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:add')")
-    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysRole role)
-    {
-        if (!roleService.checkRoleNameUnique(role))
-        {
-            return error("鏂板瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹插悕绉板凡瀛樺湪");
-        }
-        else if (!roleService.checkRoleKeyUnique(role))
-        {
-            return error("鏂板瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹叉潈闄愬凡瀛樺湪");
-        }
-        role.setCreateBy(getUsername());
-        return toAjax(roleService.insertRole(role));
-
-    }
-
-    /**
-     * 淇敼淇濆瓨瑙掕壊
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:edit')")
-    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysRole role)
-    {
-        roleService.checkRoleAllowed(role);
-        roleService.checkRoleDataScope(role.getRoleId());
-        if (!roleService.checkRoleNameUnique(role))
-        {
-            return error("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹插悕绉板凡瀛樺湪");
-        }
-        else if (!roleService.checkRoleKeyUnique(role))
-        {
-            return error("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹叉潈闄愬凡瀛樺湪");
-        }
-        role.setUpdateBy(getUsername());
-        
-        if (roleService.updateRole(role) > 0)
-        {
-            // 鏇存柊缂撳瓨鐢ㄦ埛鏉冮檺
-            LoginUser loginUser = getLoginUser();
-            if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
-            {
-                loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
-                loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
-                tokenService.setLoginUser(loginUser);
-            }
-            return success();
-        }
-        return error("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑱旂郴绠$悊鍛�");
-    }
-
-    /**
-     * 淇敼淇濆瓨鏁版嵁鏉冮檺
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:edit')")
-    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
-    @PutMapping("/dataScope")
-    public AjaxResult dataScope(@RequestBody SysRole role)
-    {
-        roleService.checkRoleAllowed(role);
-        roleService.checkRoleDataScope(role.getRoleId());
-        return toAjax(roleService.authDataScope(role));
-    }
-
-    /**
-     * 鐘舵�佷慨鏀�
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:edit')")
-    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
-    @PutMapping("/changeStatus")
-    public AjaxResult changeStatus(@RequestBody SysRole role)
-    {
-        roleService.checkRoleAllowed(role);
-        roleService.checkRoleDataScope(role.getRoleId());
-        role.setUpdateBy(getUsername());
-        return toAjax(roleService.updateRoleStatus(role));
-    }
-
-    /**
-     * 鍒犻櫎瑙掕壊
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:remove')")
-    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{roleIds}")
-    public AjaxResult remove(@PathVariable Long[] roleIds)
-    {
-        return toAjax(roleService.deleteRoleByIds(roleIds));
-    }
-
-    /**
-     * 鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:query')")
-    @GetMapping("/optionselect")
-    public AjaxResult optionselect()
-    {
-        return success(roleService.selectRoleAll());
-    }
-
-    /**
-     * 鏌ヨ宸插垎閰嶇敤鎴疯鑹插垪琛�
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:list')")
-    @GetMapping("/authUser/allocatedList")
-    public TableDataInfo allocatedList(SysUser user)
-    {
-        startPage();
-        List<SysUser> list = userService.selectAllocatedList(user);
-        return getDataTable(list);
-    }
-
-    /**
-     * 鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛�
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:list')")
-    @GetMapping("/authUser/unallocatedList")
-    public TableDataInfo unallocatedList(SysUser user)
-    {
-        startPage();
-        List<SysUser> list = userService.selectUnallocatedList(user);
-        return getDataTable(list);
-    }
-
-    /**
-     * 鍙栨秷鎺堟潈鐢ㄦ埛
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:edit')")
-    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT)
-    @PutMapping("/authUser/cancel")
-    public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole)
-    {
-        return toAjax(roleService.deleteAuthUser(userRole));
-    }
-
-    /**
-     * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:edit')")
-    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT)
-    @PutMapping("/authUser/cancelAll")
-    public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds)
-    {
-        return toAjax(roleService.deleteAuthUsers(roleId, userIds));
-    }
-
-    /**
-     * 鎵归噺閫夋嫨鐢ㄦ埛鎺堟潈
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:edit')")
-    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT)
-    @PutMapping("/authUser/selectAll")
-    public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
-    {
-        roleService.checkRoleDataScope(roleId);
-        return toAjax(roleService.insertAuthUsers(roleId, userIds));
-    }
-
-    /**
-     * 鑾峰彇瀵瑰簲瑙掕壊閮ㄩ棬鏍戝垪琛�
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:query')")
-    @GetMapping(value = "/deptTree/{roleId}")
-    public AjaxResult deptTree(@PathVariable("roleId") Long roleId)
-    {
-        AjaxResult ajax = AjaxResult.success();
-        ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
-        ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
-        return ajax;
-    }
-}
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+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.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.framework.security.service.SysPermissionService;
+import com.ruoyi.framework.security.service.TokenService;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysDept;
+import com.ruoyi.project.system.domain.SysRole;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.domain.SysUserRole;
+import com.ruoyi.project.system.service.ISysDeptService;
+import com.ruoyi.project.system.service.ISysRoleService;
+import com.ruoyi.project.system.service.ISysUserService;
+
+/**
+ * 瑙掕壊淇℃伅
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/role")
+@AllArgsConstructor
+public class SysRoleController extends BaseController
+{
+    private ISysRoleService roleService;
+    private TokenService tokenService;
+    private SysPermissionService permissionService;
+    private ISysUserService userService;
+    private ISysDeptService deptService;
+
+    @PreAuthorize("@ss.hasPermi('system:role:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysRole role)
+    {
+        startPage();
+        List<SysRole> list = roleService.selectRoleList(role);
+        return getDataTable(list);
+    }
+
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:role:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysRole role)
+    {
+        List<SysRole> list = roleService.selectRoleList(role);
+        ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
+        util.exportExcel(response, list, "瑙掕壊鏁版嵁");
+    }
+
+    /**
+     * 鏍规嵁瑙掕壊缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:query')")
+    @GetMapping(value = "/{roleId}")
+    public AjaxResult getInfo(@PathVariable Long roleId)
+    {
+        roleService.checkRoleDataScope(roleId);
+        return success(roleService.selectRoleById(roleId));
+    }
+
+    /**
+     * 鏂板瑙掕壊
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:add')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysRole role)
+    {
+        if (!roleService.checkRoleNameUnique(role))
+        {
+            return error("鏂板瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹插悕绉板凡瀛樺湪");
+        }
+        else if (!roleService.checkRoleKeyUnique(role))
+        {
+            return error("鏂板瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹叉潈闄愬凡瀛樺湪");
+        }
+        role.setCreateBy(getUsername());
+        return toAjax(roleService.insertRole(role));
+
+    }
+
+    /**
+     * 淇敼淇濆瓨瑙掕壊
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysRole role)
+    {
+        roleService.checkRoleAllowed(role);
+        roleService.checkRoleDataScope(role.getRoleId());
+        if (!roleService.checkRoleNameUnique(role))
+        {
+            return error("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹插悕绉板凡瀛樺湪");
+        }
+        else if (!roleService.checkRoleKeyUnique(role))
+        {
+            return error("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹叉潈闄愬凡瀛樺湪");
+        }
+        role.setUpdateBy(getUsername());
+        
+        if (roleService.updateRole(role) > 0)
+        {
+            // 鏇存柊缂撳瓨鐢ㄦ埛鏉冮檺
+            LoginUser loginUser = getLoginUser();
+            if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
+            {
+                loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
+                loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
+                tokenService.setLoginUser(loginUser);
+            }
+            return success();
+        }
+        return error("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑱旂郴绠$悊鍛�");
+    }
+
+    /**
+     * 淇敼淇濆瓨鏁版嵁鏉冮檺
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/dataScope")
+    public AjaxResult dataScope(@RequestBody SysRole role)
+    {
+        roleService.checkRoleAllowed(role);
+        roleService.checkRoleDataScope(role.getRoleId());
+        return toAjax(roleService.authDataScope(role));
+    }
+
+    /**
+     * 鐘舵�佷慨鏀�
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public AjaxResult changeStatus(@RequestBody SysRole role)
+    {
+        roleService.checkRoleAllowed(role);
+        roleService.checkRoleDataScope(role.getRoleId());
+        role.setUpdateBy(getUsername());
+        return toAjax(roleService.updateRoleStatus(role));
+    }
+
+    /**
+     * 鍒犻櫎瑙掕壊
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:remove')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{roleIds}")
+    public AjaxResult remove(@PathVariable Long[] roleIds)
+    {
+        return toAjax(roleService.deleteRoleByIds(roleIds));
+    }
+
+    /**
+     * 鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:query')")
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        return success(roleService.selectRoleAll());
+    }
+
+    /**
+     * 鏌ヨ宸插垎閰嶇敤鎴疯鑹插垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:list')")
+    @GetMapping("/authUser/allocatedList")
+    public TableDataInfo allocatedList(SysUser user)
+    {
+        startPage();
+        List<SysUser> list = userService.selectAllocatedList(user);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:list')")
+    @GetMapping("/authUser/unallocatedList")
+    public TableDataInfo unallocatedList(SysUser user)
+    {
+        startPage();
+        List<SysUser> list = userService.selectUnallocatedList(user);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鍙栨秷鎺堟潈鐢ㄦ埛
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT)
+    @PutMapping("/authUser/cancel")
+    public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole)
+    {
+        return toAjax(roleService.deleteAuthUser(userRole));
+    }
+
+    /**
+     * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT)
+    @PutMapping("/authUser/cancelAll")
+    public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds)
+    {
+        return toAjax(roleService.deleteAuthUsers(roleId, userIds));
+    }
+
+    /**
+     * 鎵归噺閫夋嫨鐢ㄦ埛鎺堟潈
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT)
+    @PutMapping("/authUser/selectAll")
+    public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
+    {
+        roleService.checkRoleDataScope(roleId);
+        return toAjax(roleService.insertAuthUsers(roleId, userIds));
+    }
+
+    /**
+     * 鑾峰彇瀵瑰簲瑙掕壊閮ㄩ棬鏍戝垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:query')")
+    @GetMapping(value = "/deptTree/{roleId}")
+    public AjaxResult deptTree(@PathVariable("roleId") Long roleId)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
+        ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
+        return ajax;
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysUserController.java b/src/main/java/com/ruoyi/project/system/controller/SysUserController.java
index 332d6b5..08be9f2 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysUserController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysUserController.java
@@ -1,292 +1,292 @@
-package com.ruoyi.project.system.controller;
-
-import java.util.List;
-import java.util.stream.Collectors;
-import jakarta.servlet.http.HttpServletResponse;
-
-import com.ruoyi.project.system.domain.vo.SysUserDeptVo;
-import com.ruoyi.project.system.mapper.SysUserMapper;
-import com.ruoyi.project.system.service.*;
-import lombok.AllArgsConstructor;
-import org.apache.commons.lang3.ArrayUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-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.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.multipart.MultipartFile;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.system.domain.SysDept;
-import com.ruoyi.project.system.domain.SysRole;
-import com.ruoyi.project.system.domain.SysUser;
-
-/**
- * 鐢ㄦ埛淇℃伅
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/user")
-@AllArgsConstructor
-public class SysUserController extends BaseController
-{
-    private ISysUserService userService;
-    private ISysRoleService roleService;
-    private ISysDeptService deptService;
-    private ISysPostService postService;
-    private ISysUserDeptService userDeptService;
-
-    /**
-     * 鑾峰彇鐢ㄦ埛鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysUser user)
-    {
-        startPage();
-        List<SysUser> list = userService.selectUserList(user);
-        return getDataTable(list);
-    }
-
-    /**
-     * 鑾峰彇鐢ㄦ埛鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:list')")
-    @GetMapping("/listAll")
-    public AjaxResult listAll(SysUser user)
-    {
-        List<SysUser> list = userService.selectUserList(user);
-        return AjaxResult.success(list);
-    }
-
-    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('system:user:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysUser user)
-    {
-        List<SysUser> list = userService.selectUserList(user);
-        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
-        util.exportExcel(response, list, "鐢ㄦ埛鏁版嵁");
-    }
-
-    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.IMPORT)
-    @PreAuthorize("@ss.hasPermi('system:user:import')")
-    @PostMapping("/importData")
-    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
-    {
-        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
-        List<SysUser> userList = util.importExcel(file.getInputStream());
-        String operName = getUsername();
-        String message = userService.importUser(userList, updateSupport, operName);
-        return success(message);
-    }
-
-    @PostMapping("/importTemplate")
-    public void importTemplate(HttpServletResponse response)
-    {
-        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
-        util.importTemplateExcel(response, "鐢ㄦ埛鏁版嵁");
-    }
-
-    /**
-     * 鏍规嵁鐢ㄦ埛缂栧彿鑾峰彇璇︾粏淇℃伅
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:query')")
-    @GetMapping(value = { "/", "/{userId}" })
-    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
-    {
-        AjaxResult ajax = AjaxResult.success();
-        if (StringUtils.isNotNull(userId))
-        {
-            userService.checkUserDataScope(userId);
-            SysUser sysUser = userService.selectUserById(userId);
-            ajax.put(AjaxResult.DATA_TAG, sysUser);
-            ajax.put("postIds", postService.selectPostListByUserId(userId));
-            ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
-        }
-        List<SysRole> roles = roleService.selectRoleAll();
-        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
-        ajax.put("posts", postService.selectPostAll());
-        SysUserDeptVo sysUserDeptVo = new SysUserDeptVo();
-        sysUserDeptVo.setUserId(userId);
-        List<SysUserDeptVo> sysUserDeptVos = userDeptService.userLoginFacotryList(sysUserDeptVo);
-        ajax.put("deptIds",sysUserDeptVos.stream().map(SysUserDeptVo::getDeptId).collect(Collectors.toList()));
-        return ajax;
-    }
-
-    /**
-     * 鏂板鐢ㄦ埛
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:add')")
-    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysUser user)
-    {
-        roleService.checkRoleDataScope(user.getRoleIds());
-        if (!userService.checkUserNameUnique(user))
-        {
-            return error("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岀櫥褰曡处鍙峰凡瀛樺湪");
-        }
-        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
-        {
-            return error("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
-        }
-        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
-        {
-            return error("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
-        }
-        user.setCreateBy(getUsername());
-        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
-        user.setTenantId(user.getDeptId());
-        return toAjax(userService.insertUser(user));
-    }
-
-    /**
-     * 淇敼鐢ㄦ埛
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:edit')")
-    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysUser user)
-    {
-        userService.checkUserAllowed(user);
-        userService.checkUserDataScope(user.getUserId());
-        roleService.checkRoleDataScope(user.getRoleIds());
-        if (!userService.checkUserNameUnique(user))
-        {
-            return error("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岀櫥褰曡处鍙峰凡瀛樺湪");
-        }
-        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
-        {
-            return error("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
-        }
-        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
-        {
-            return error("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
-        }
-        user.setUpdateBy(getUsername());
-        userService.bindUserDept(user);
-        return toAjax(userService.updateUser(user));
-    }
-
-    /**
-     * 鍒犻櫎鐢ㄦ埛
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:remove')")
-    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{userIds}")
-    public AjaxResult remove(@PathVariable Long[] userIds)
-    {
-        if (ArrayUtils.contains(userIds, getUserId()))
-        {
-            return error("褰撳墠鐢ㄦ埛涓嶈兘鍒犻櫎");
-        }
-        return toAjax(userService.deleteUserByIds(userIds));
-    }
-
-    /**
-     * 閲嶇疆瀵嗙爜
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
-    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
-    @PutMapping("/resetPwd")
-    public AjaxResult resetPwd(@RequestBody SysUser user)
-    {
-        userService.checkUserAllowed(user);
-        userService.checkUserDataScope(user.getUserId());
-        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
-        user.setUpdateBy(getUsername());
-        return toAjax(userService.resetPwd(user));
-    }
-
-    /**
-     * 鐘舵�佷慨鏀�
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:edit')")
-    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
-    @PutMapping("/changeStatus")
-    public AjaxResult changeStatus(@RequestBody SysUser user)
-    {
-        userService.checkUserAllowed(user);
-        userService.checkUserDataScope(user.getUserId());
-        user.setUpdateBy(getUsername());
-        return toAjax(userService.updateUserStatus(user));
-    }
-
-    /**
-     * 鏍规嵁鐢ㄦ埛缂栧彿鑾峰彇鎺堟潈瑙掕壊
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:query')")
-    @GetMapping("/authRole/{userId}")
-    public AjaxResult authRole(@PathVariable("userId") Long userId)
-    {
-        AjaxResult ajax = AjaxResult.success();
-        SysUser user = userService.selectUserById(userId);
-        List<SysRole> roles = roleService.selectRolesByUserId(userId);
-        ajax.put("user", user);
-        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
-        return ajax;
-    }
-
-    /**
-     * 鐢ㄦ埛鎺堟潈瑙掕壊
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:edit')")
-    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.GRANT)
-    @PutMapping("/authRole")
-    public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
-    {
-        userService.checkUserDataScope(userId);
-        roleService.checkRoleDataScope(roleIds);
-        userService.insertUserAuth(userId, roleIds);
-        return success();
-    }
-
-    /**
-     * 鑾峰彇閮ㄩ棬鏍戝垪琛�
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:list')")
-    @GetMapping("/deptTree")
-    public AjaxResult deptTree(SysDept dept)
-    {
-        return success(deptService.selectDeptTreeList(dept));
-    }
-
-    /**
-     * 涓嶅垎椤电敤鎴锋煡璇�
-     * @param user
-     * @return
-     */
-    @GetMapping("/userListNoPage")
-    public AjaxResult userListNoPage(SysUser user){
-        List<SysUser> sysUserList = userService.userListNoPage(user);
-        return AjaxResult.success(sysUserList);
-    }
-
-    /**
-     * 鏌ヨ褰撳墠鐢ㄦ埛鍏徃涓嬫墍鏈夌敤鎴�
-     * @param user
-     * @return
-     */
-    @GetMapping("/userListNoPageByTenantId")
-    public AjaxResult userListNoPageByTenantId(SysUser user){
-        //鑾峰彇鐧诲綍鐢ㄦ埛淇℃伅
-        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
-        user.setTenantId(loginUser.getTenantId());
-        List<SysUser> sysUserList = userService.userListNoPage(user);
-        return AjaxResult.success(sysUserList);
-    }
-}
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import jakarta.servlet.http.HttpServletResponse;
+
+import com.ruoyi.project.system.domain.vo.SysUserDeptVo;
+import com.ruoyi.project.system.mapper.SysUserMapper;
+import com.ruoyi.project.system.service.*;
+import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.ArrayUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+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.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+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.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysDept;
+import com.ruoyi.project.system.domain.SysRole;
+import com.ruoyi.project.system.domain.SysUser;
+
+/**
+ * 鐢ㄦ埛淇℃伅
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/user")
+@AllArgsConstructor
+public class SysUserController extends BaseController
+{
+    private ISysUserService userService;
+    private ISysRoleService roleService;
+    private ISysDeptService deptService;
+    private ISysPostService postService;
+    private ISysUserDeptService userDeptService;
+
+    /**
+     * 鑾峰彇鐢ㄦ埛鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysUser user)
+    {
+        startPage();
+        List<SysUser> list = userService.selectUserList(user);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:list')")
+    @GetMapping("/listAll")
+    public AjaxResult listAll(SysUser user)
+    {
+        List<SysUser> list = userService.selectUserList(user);
+        return AjaxResult.success(list);
+    }
+
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:user:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysUser user)
+    {
+        List<SysUser> list = userService.selectUserList(user);
+        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
+        util.exportExcel(response, list, "鐢ㄦ埛鏁版嵁");
+    }
+
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.IMPORT)
+    @PreAuthorize("@ss.hasPermi('system:user:import')")
+    @PostMapping("/importData")
+    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
+    {
+        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
+        List<SysUser> userList = util.importExcel(file.getInputStream());
+        String operName = getUsername();
+        String message = userService.importUser(userList, updateSupport, operName);
+        return success(message);
+    }
+
+    @PostMapping("/importTemplate")
+    public void importTemplate(HttpServletResponse response)
+    {
+        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
+        util.importTemplateExcel(response, "鐢ㄦ埛鏁版嵁");
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:query')")
+    @GetMapping(value = { "/", "/{userId}" })
+    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        if (StringUtils.isNotNull(userId))
+        {
+            userService.checkUserDataScope(userId);
+            SysUser sysUser = userService.selectUserById(userId);
+            ajax.put(AjaxResult.DATA_TAG, sysUser);
+            ajax.put("postIds", postService.selectPostListByUserId(userId));
+            ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
+        }
+        List<SysRole> roles = roleService.selectRoleAll();
+        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
+        ajax.put("posts", postService.selectPostAll());
+        SysUserDeptVo sysUserDeptVo = new SysUserDeptVo();
+        sysUserDeptVo.setUserId(userId);
+        List<SysUserDeptVo> sysUserDeptVos = userDeptService.userLoginFacotryList(sysUserDeptVo);
+        ajax.put("deptIds",sysUserDeptVos.stream().map(SysUserDeptVo::getDeptId).collect(Collectors.toList()));
+        return ajax;
+    }
+
+    /**
+     * 鏂板鐢ㄦ埛
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:add')")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysUser user)
+    {
+        roleService.checkRoleDataScope(user.getRoleIds());
+        if (!userService.checkUserNameUnique(user))
+        {
+            return error("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岀櫥褰曡处鍙峰凡瀛樺湪");
+        }
+        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
+        {
+            return error("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
+        }
+        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
+        {
+            return error("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
+        }
+        user.setCreateBy(getUsername());
+        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+        user.setTenantId(user.getDeptId());
+        return toAjax(userService.insertUser(user));
+    }
+
+    /**
+     * 淇敼鐢ㄦ埛
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:edit')")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysUser user)
+    {
+        userService.checkUserAllowed(user);
+        userService.checkUserDataScope(user.getUserId());
+        roleService.checkRoleDataScope(user.getRoleIds());
+        if (!userService.checkUserNameUnique(user))
+        {
+            return error("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岀櫥褰曡处鍙峰凡瀛樺湪");
+        }
+        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
+        {
+            return error("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
+        }
+        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
+        {
+            return error("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
+        }
+        user.setUpdateBy(getUsername());
+        userService.bindUserDept(user);
+        return toAjax(userService.updateUser(user));
+    }
+
+    /**
+     * 鍒犻櫎鐢ㄦ埛
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:remove')")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{userIds}")
+    public AjaxResult remove(@PathVariable Long[] userIds)
+    {
+        if (ArrayUtils.contains(userIds, getUserId()))
+        {
+            return error("褰撳墠鐢ㄦ埛涓嶈兘鍒犻櫎");
+        }
+        return toAjax(userService.deleteUserByIds(userIds));
+    }
+
+    /**
+     * 閲嶇疆瀵嗙爜
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/resetPwd")
+    public AjaxResult resetPwd(@RequestBody SysUser user)
+    {
+        userService.checkUserAllowed(user);
+        userService.checkUserDataScope(user.getUserId());
+        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+        user.setUpdateBy(getUsername());
+        return toAjax(userService.resetPwd(user));
+    }
+
+    /**
+     * 鐘舵�佷慨鏀�
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:edit')")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public AjaxResult changeStatus(@RequestBody SysUser user)
+    {
+        userService.checkUserAllowed(user);
+        userService.checkUserDataScope(user.getUserId());
+        user.setUpdateBy(getUsername());
+        return toAjax(userService.updateUserStatus(user));
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛缂栧彿鑾峰彇鎺堟潈瑙掕壊
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:query')")
+    @GetMapping("/authRole/{userId}")
+    public AjaxResult authRole(@PathVariable("userId") Long userId)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        SysUser user = userService.selectUserById(userId);
+        List<SysRole> roles = roleService.selectRolesByUserId(userId);
+        ajax.put("user", user);
+        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
+        return ajax;
+    }
+
+    /**
+     * 鐢ㄦ埛鎺堟潈瑙掕壊
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:edit')")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.GRANT)
+    @PutMapping("/authRole")
+    public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
+    {
+        userService.checkUserDataScope(userId);
+        roleService.checkRoleDataScope(roleIds);
+        userService.insertUserAuth(userId, roleIds);
+        return success();
+    }
+
+    /**
+     * 鑾峰彇閮ㄩ棬鏍戝垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:list')")
+    @GetMapping("/deptTree")
+    public AjaxResult deptTree(SysDept dept)
+    {
+        return success(deptService.selectDeptTreeList(dept));
+    }
+
+    /**
+     * 涓嶅垎椤电敤鎴锋煡璇�
+     * @param user
+     * @return
+     */
+    @GetMapping("/userListNoPage")
+    public AjaxResult userListNoPage(SysUser user){
+        List<SysUser> sysUserList = userService.userListNoPage(user);
+        return AjaxResult.success(sysUserList);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鍏徃涓嬫墍鏈夌敤鎴�
+     * @param user
+     * @return
+     */
+    @GetMapping("/userListNoPageByTenantId")
+    public AjaxResult userListNoPageByTenantId(SysUser user){
+        //鑾峰彇鐧诲綍鐢ㄦ埛淇℃伅
+        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
+        user.setTenantId(loginUser.getTenantId());
+        List<SysUser> sysUserList = userService.userListNoPage(user);
+        return AjaxResult.success(sysUserList);
+    }
+}
diff --git a/src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java b/src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java
index ec16cea..a94fe62 100644
--- a/src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java
+++ b/src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java
@@ -1,255 +1,255 @@
-package com.ruoyi.project.tool.gen.controller;
-
-import com.alibaba.druid.DbType;
-import com.alibaba.druid.sql.SQLUtils;
-import com.alibaba.druid.sql.ast.SQLStatement;
-import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.sql.SqlUtil;
-import com.ruoyi.framework.aspectj.lang.annotation.Log;
-import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
-import com.ruoyi.framework.config.GenConfig;
-import com.ruoyi.framework.web.controller.BaseController;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.project.tool.gen.domain.GenTable;
-import com.ruoyi.project.tool.gen.domain.GenTableColumn;
-import com.ruoyi.project.tool.gen.service.IGenTableColumnService;
-import com.ruoyi.project.tool.gen.service.IGenTableService;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.apache.commons.io.IOUtils;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 浠g爜鐢熸垚 鎿嶄綔澶勭悊
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/tool/gen")
-@AllArgsConstructor
-public class GenController extends BaseController
-{
-    private IGenTableService genTableService;
-    private IGenTableColumnService genTableColumnService;
-
-    /**
-     * 鏌ヨ浠g爜鐢熸垚鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
-    @GetMapping("/list")
-    public TableDataInfo genList(GenTable genTable)
-    {
-        startPage();
-        List<GenTable> list = genTableService.selectGenTableList(genTable);
-        return getDataTable(list);
-    }
-
-    /**
-     * 鑾峰彇浠g爜鐢熸垚淇℃伅
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:query')")
-    @GetMapping(value = "/{talbleId}")
-    public AjaxResult getInfo(@PathVariable Long talbleId)
-    {
-        GenTable table = genTableService.selectGenTableById(talbleId);
-        List<GenTable> tables = genTableService.selectGenTableAll();
-        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(talbleId);
-        Map<String, Object> map = new HashMap<String, Object>();
-        map.put("info", table);
-        map.put("rows", list);
-        map.put("tables", tables);
-        return success(map);
-    }
-
-    /**
-     * 鏌ヨ鏁版嵁搴撳垪琛�
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
-    @GetMapping("/db/list")
-    public TableDataInfo dataList(GenTable genTable)
-    {
-        startPage();
-        List<GenTable> list = genTableService.selectDbTableList(genTable);
-        return getDataTable(list);
-    }
-
-    /**
-     * 鏌ヨ鏁版嵁琛ㄥ瓧娈靛垪琛�
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
-    @GetMapping(value = "/column/{tableId}")
-    public TableDataInfo columnList(Long tableId)
-    {
-        TableDataInfo dataInfo = new TableDataInfo();
-        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
-        dataInfo.setRows(list);
-        dataInfo.setTotal(list.size());
-        return dataInfo;
-    }
-
-    /**
-     * 瀵煎叆琛ㄧ粨鏋勶紙淇濆瓨锛�
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:import')")
-    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.IMPORT)
-    @PostMapping("/importTable")
-    public AjaxResult importTableSave(String tables)
-    {
-        String[] tableNames = Convert.toStrArray(tables);
-        // 鏌ヨ琛ㄤ俊鎭�
-        List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);
-        genTableService.importGenTable(tableList, SecurityUtils.getUsername());
-        return success();
-    }
-
-    /**
-     * 鍒涘缓琛ㄧ粨鏋勶紙淇濆瓨锛�
-     */
-    @PreAuthorize("@ss.hasRole('admin')")
-    @Log(title = "鍒涘缓琛�", businessType = BusinessType.OTHER)
-    @PostMapping("/createTable")
-    public AjaxResult createTableSave(String sql)
-    {
-        try
-        {
-            SqlUtil.filterKeyword(sql);
-            List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql);
-            List<String> tableNames = new ArrayList<>();
-            for (SQLStatement sqlStatement : sqlStatements)
-            {
-                if (sqlStatement instanceof MySqlCreateTableStatement)
-                {
-                    MySqlCreateTableStatement createTableStatement = (MySqlCreateTableStatement) sqlStatement;
-                    if (genTableService.createTable(createTableStatement.toString()))
-                    {
-                        String tableName = createTableStatement.getTableName().replaceAll("`", "");
-                        tableNames.add(tableName);
-                    }
-                }
-            }
-            List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames.toArray(new String[tableNames.size()]));
-            String operName = SecurityUtils.getUsername();
-            genTableService.importGenTable(tableList, operName);
-            return AjaxResult.success();
-        }
-        catch (Exception e)
-        {
-            logger.error(e.getMessage(), e);
-            return AjaxResult.error("鍒涘缓琛ㄧ粨鏋勫紓甯�");
-        }
-    }
-
-    /**
-     * 淇敼淇濆瓨浠g爜鐢熸垚涓氬姟
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
-    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult editSave(@Validated @RequestBody GenTable genTable)
-    {
-        genTableService.validateEdit(genTable);
-        genTableService.updateGenTable(genTable);
-        return success();
-    }
-
-    /**
-     * 鍒犻櫎浠g爜鐢熸垚
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:remove')")
-    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{tableIds}")
-    public AjaxResult remove(@PathVariable Long[] tableIds)
-    {
-        genTableService.deleteGenTableByIds(tableIds);
-        return success();
-    }
-
-    /**
-     * 棰勮浠g爜
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:preview')")
-    @GetMapping("/preview/{tableId}")
-    public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException
-    {
-        Map<String, String> dataMap = genTableService.previewCode(tableId);
-        return success(dataMap);
-    }
-
-    /**
-     * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
-    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
-    @GetMapping("/download/{tableName}")
-    public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException
-    {
-        byte[] data = genTableService.downloadCode(tableName);
-        genCode(response, data);
-    }
-
-    /**
-     * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
-    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
-    @GetMapping("/genCode/{tableName}")
-    public AjaxResult genCode(@PathVariable("tableName") String tableName)
-    {
-        if (!GenConfig.isAllowOverwrite())
-        {
-            return AjaxResult.error("銆愮郴缁熼璁俱�戜笉鍏佽鐢熸垚鏂囦欢瑕嗙洊鍒版湰鍦�");
-        }
-        genTableService.generatorCode(tableName);
-        return success();
-    }
-
-    /**
-     * 鍚屾鏁版嵁搴�
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
-    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.UPDATE)
-    @GetMapping("/synchDb/{tableName}")
-    public AjaxResult synchDb(@PathVariable("tableName") String tableName)
-    {
-        genTableService.synchDb(tableName);
-        return success();
-    }
-
-    /**
-     * 鎵归噺鐢熸垚浠g爜
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
-    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
-    @GetMapping("/batchGenCode")
-    public void batchGenCode(HttpServletResponse response, String tables) throws IOException
-    {
-        String[] tableNames = Convert.toStrArray(tables);
-        byte[] data = genTableService.downloadCode(tableNames);
-        genCode(response, data);
-    }
-
-    /**
-     * 鐢熸垚zip鏂囦欢
-     */
-    private void genCode(HttpServletResponse response, byte[] data) throws IOException
-    {
-        response.reset();
-        response.addHeader("Access-Control-Allow-Origin", "*");
-        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
-        response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"");
-        response.addHeader("Content-Length", "" + data.length);
-        response.setContentType("application/octet-stream; charset=UTF-8");
-        IOUtils.write(data, response.getOutputStream());
-    }
+package com.ruoyi.project.tool.gen.controller;
+
+import com.alibaba.druid.DbType;
+import com.alibaba.druid.sql.SQLUtils;
+import com.alibaba.druid.sql.ast.SQLStatement;
+import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
+import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.sql.SqlUtil;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.config.GenConfig;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.tool.gen.domain.GenTable;
+import com.ruoyi.project.tool.gen.domain.GenTableColumn;
+import com.ruoyi.project.tool.gen.service.IGenTableColumnService;
+import com.ruoyi.project.tool.gen.service.IGenTableService;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import org.apache.commons.io.IOUtils;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 浠g爜鐢熸垚 鎿嶄綔澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/tool/gen")
+@AllArgsConstructor
+public class GenController extends BaseController
+{
+    private IGenTableService genTableService;
+    private IGenTableColumnService genTableColumnService;
+
+    /**
+     * 鏌ヨ浠g爜鐢熸垚鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
+    @GetMapping("/list")
+    public TableDataInfo genList(GenTable genTable)
+    {
+        startPage();
+        List<GenTable> list = genTableService.selectGenTableList(genTable);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鑾峰彇浠g爜鐢熸垚淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:query')")
+    @GetMapping(value = "/{talbleId}")
+    public AjaxResult getInfo(@PathVariable Long talbleId)
+    {
+        GenTable table = genTableService.selectGenTableById(talbleId);
+        List<GenTable> tables = genTableService.selectGenTableAll();
+        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(talbleId);
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("info", table);
+        map.put("rows", list);
+        map.put("tables", tables);
+        return success(map);
+    }
+
+    /**
+     * 鏌ヨ鏁版嵁搴撳垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
+    @GetMapping("/db/list")
+    public TableDataInfo dataList(GenTable genTable)
+    {
+        startPage();
+        List<GenTable> list = genTableService.selectDbTableList(genTable);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鏌ヨ鏁版嵁琛ㄥ瓧娈靛垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
+    @GetMapping(value = "/column/{tableId}")
+    public TableDataInfo columnList(Long tableId)
+    {
+        TableDataInfo dataInfo = new TableDataInfo();
+        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
+        dataInfo.setRows(list);
+        dataInfo.setTotal(list.size());
+        return dataInfo;
+    }
+
+    /**
+     * 瀵煎叆琛ㄧ粨鏋勶紙淇濆瓨锛�
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:import')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.IMPORT)
+    @PostMapping("/importTable")
+    public AjaxResult importTableSave(String tables)
+    {
+        String[] tableNames = Convert.toStrArray(tables);
+        // 鏌ヨ琛ㄤ俊鎭�
+        List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);
+        genTableService.importGenTable(tableList, SecurityUtils.getUsername());
+        return success();
+    }
+
+    /**
+     * 鍒涘缓琛ㄧ粨鏋勶紙淇濆瓨锛�
+     */
+    @PreAuthorize("@ss.hasRole('admin')")
+    @Log(title = "鍒涘缓琛�", businessType = BusinessType.OTHER)
+    @PostMapping("/createTable")
+    public AjaxResult createTableSave(String sql)
+    {
+        try
+        {
+            SqlUtil.filterKeyword(sql);
+            List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql);
+            List<String> tableNames = new ArrayList<>();
+            for (SQLStatement sqlStatement : sqlStatements)
+            {
+                if (sqlStatement instanceof MySqlCreateTableStatement)
+                {
+                    MySqlCreateTableStatement createTableStatement = (MySqlCreateTableStatement) sqlStatement;
+                    if (genTableService.createTable(createTableStatement.toString()))
+                    {
+                        String tableName = createTableStatement.getTableName().replaceAll("`", "");
+                        tableNames.add(tableName);
+                    }
+                }
+            }
+            List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames.toArray(new String[tableNames.size()]));
+            String operName = SecurityUtils.getUsername();
+            genTableService.importGenTable(tableList, operName);
+            return AjaxResult.success();
+        }
+        catch (Exception e)
+        {
+            logger.error(e.getMessage(), e);
+            return AjaxResult.error("鍒涘缓琛ㄧ粨鏋勫紓甯�");
+        }
+    }
+
+    /**
+     * 淇敼淇濆瓨浠g爜鐢熸垚涓氬姟
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult editSave(@Validated @RequestBody GenTable genTable)
+    {
+        genTableService.validateEdit(genTable);
+        genTableService.updateGenTable(genTable);
+        return success();
+    }
+
+    /**
+     * 鍒犻櫎浠g爜鐢熸垚
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:remove')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{tableIds}")
+    public AjaxResult remove(@PathVariable Long[] tableIds)
+    {
+        genTableService.deleteGenTableByIds(tableIds);
+        return success();
+    }
+
+    /**
+     * 棰勮浠g爜
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:preview')")
+    @GetMapping("/preview/{tableId}")
+    public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException
+    {
+        Map<String, String> dataMap = genTableService.previewCode(tableId);
+        return success(dataMap);
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
+    @GetMapping("/download/{tableName}")
+    public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException
+    {
+        byte[] data = genTableService.downloadCode(tableName);
+        genCode(response, data);
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
+    @GetMapping("/genCode/{tableName}")
+    public AjaxResult genCode(@PathVariable("tableName") String tableName)
+    {
+        if (!GenConfig.isAllowOverwrite())
+        {
+            return AjaxResult.error("銆愮郴缁熼璁俱�戜笉鍏佽鐢熸垚鏂囦欢瑕嗙洊鍒版湰鍦�");
+        }
+        genTableService.generatorCode(tableName);
+        return success();
+    }
+
+    /**
+     * 鍚屾鏁版嵁搴�
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.UPDATE)
+    @GetMapping("/synchDb/{tableName}")
+    public AjaxResult synchDb(@PathVariable("tableName") String tableName)
+    {
+        genTableService.synchDb(tableName);
+        return success();
+    }
+
+    /**
+     * 鎵归噺鐢熸垚浠g爜
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
+    @GetMapping("/batchGenCode")
+    public void batchGenCode(HttpServletResponse response, String tables) throws IOException
+    {
+        String[] tableNames = Convert.toStrArray(tables);
+        byte[] data = genTableService.downloadCode(tableNames);
+        genCode(response, data);
+    }
+
+    /**
+     * 鐢熸垚zip鏂囦欢
+     */
+    private void genCode(HttpServletResponse response, byte[] data) throws IOException
+    {
+        response.reset();
+        response.addHeader("Access-Control-Allow-Origin", "*");
+        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
+        response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"");
+        response.addHeader("Content-Length", "" + data.length);
+        response.setContentType("application/octet-stream; charset=UTF-8");
+        IOUtils.write(data, response.getOutputStream());
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java b/src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java
index 813fb44..f265ab0 100644
--- a/src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java
+++ b/src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java
@@ -1,27 +1,19 @@
 package com.ruoyi.purchase.controller;
 
-import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.basic.service.ISupplierService;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.purchase.dto.InvoicePurchaseReportDto;
-import com.ruoyi.purchase.dto.VatDto;
-import com.ruoyi.purchase.pojo.InvoicePurchase;
-import com.ruoyi.purchase.service.IInvoicePurchaseService;
-import com.ruoyi.waterrecord.pojo.WaterRecord;
-import io.swagger.v3.oas.annotations.tags.Tag;
+import com.ruoyi.framework.web.domain.R;
 import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletResponse;
 import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
-
-import jakarta.servlet.http.HttpServletResponse;
-import java.util.List;
 
 @RestController
 @Tag(name = "閲囪喘鎶ヨ〃")
@@ -29,40 +21,45 @@
 @AllArgsConstructor
 public class AccountingReportController {
 
-    private IInvoicePurchaseService invoicePurchaseService;
+    private final ISupplierService supplierService;
+
 
     @GetMapping("/list")
     @Log(title = "閲囪喘鎶ヨ〃-椤圭洰鍒╂鼎", businessType = BusinessType.OTHER)
-    public AjaxResult list(Page page, InvoicePurchaseReportDto invoicePurchaseReportDto) {
-        IPage<InvoicePurchaseReportDto> result =invoicePurchaseService.listPurchaseReport(page, invoicePurchaseReportDto);
-        return AjaxResult.success(result);
+    public AjaxResult list(Page page) {
+        return AjaxResult.success();
     }
 
     @Log(title = "閲囪喘鎶ヨ〃-椤圭洰鍒╂鼎瀵煎嚭", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
     @Operation(summary = "閲囪喘鎶ヨ〃-椤圭洰鍒╂鼎瀵煎嚭")
     public void export(HttpServletResponse response) {
-        Page page = new Page(-1,-1);
-        InvoicePurchaseReportDto waterRecord = new InvoicePurchaseReportDto();
-        IPage<InvoicePurchaseReportDto> listPage = invoicePurchaseService.listPurchaseReport(page, waterRecord);
-        ExcelUtil<InvoicePurchaseReportDto> util = new ExcelUtil<InvoicePurchaseReportDto>(InvoicePurchaseReportDto.class);
-        util.exportExcel(response, listPage.getRecords() , "椤圭洰鍒╂鼎瀵煎嚭");
+
     }
 
     @Log(title = "閲囪喘鎶ヨ〃-澧炲�肩◣姣斿", businessType = BusinessType.OTHER)
     @GetMapping("/listVat")
     public AjaxResult listVat(Page page,String month) {
-        IPage<VatDto> result = invoicePurchaseService.listVat(page, month);
-        return AjaxResult.success(result);
+        return AjaxResult.success();
     }
 
     @Log(title = "閲囪喘鎶ヨ〃-澧炲�肩◣姣斿", businessType = BusinessType.EXPORT)
     @PostMapping("/exportTwo")
     @Operation(summary = "閲囪喘鎶ヨ〃-澧炲�肩◣姣斿")
     public void exportTwo(HttpServletResponse response) {
-        Page page = new Page(-1,-1);
-        IPage<VatDto> result = invoicePurchaseService.listVat(page, null);
-        ExcelUtil<VatDto> util = new ExcelUtil<VatDto>(VatDto.class);
-        util.exportExcel(response, result.getRecords() , "澧炲�肩◣姣斿");
+    }
+
+    @GetMapping("/supplierTransactions")
+    @Log(title = "渚涘簲鍟嗗線鏉�", businessType = BusinessType.OTHER)
+    @Operation(summary = "渚涘簲鍟嗗線鏉�")
+    public R supplierTransactions(Page page, String supplierName) {
+        return R.ok(supplierService.supplierTransactions(page,supplierName));
+    }
+
+    @GetMapping("/supplierTransactionsDetails")
+    @Log(title = "渚涘簲鍟嗗線鏉ユ槑缁�", businessType = BusinessType.OTHER)
+    @Operation(summary = "渚涘簲鍟嗗線鏉ユ槑缁�")
+    public R supplierTransactionsDetails(Page page, Long supplierId) {
+        return R.ok(supplierService.supplierTransactionsDetails(page,supplierId));
     }
 }
diff --git a/src/main/java/com/ruoyi/purchase/controller/InvoicePurchaseController.java b/src/main/java/com/ruoyi/purchase/controller/InvoicePurchaseController.java
deleted file mode 100644
index afd9213..0000000
--- a/src/main/java/com/ruoyi/purchase/controller/InvoicePurchaseController.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.ruoyi.purchase.controller;
-
-import com.ruoyi.common.utils.poi.ExcelUtil;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.purchase.dto.InvoicePurchaseDto;
-import com.ruoyi.purchase.pojo.InvoicePurchase;
-import com.ruoyi.purchase.service.IInvoicePurchaseService;
-import com.ruoyi.sales.service.ICommonFileService;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.web.bind.annotation.*;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * 鍙戠エ淇℃伅Controller
- *
- * @author ruoyi
- * @date 2025-05-14
- */
-@RestController
-@AllArgsConstructor
-@RequestMapping("/purchase/invoice")
-public class InvoicePurchaseController extends BaseController {
-
-    private IInvoicePurchaseService invoicePurchaseService;
-
-    private ICommonFileService commonFileService;
-
-    /**
-     * 鏌ヨ鍙戠エ淇℃伅鍒楄〃
-     */
-    @GetMapping("/list")
-    public TableDataInfo list(InvoicePurchaseDto invoicePurchaseDto) {
-        startPage();
-        List<InvoicePurchaseDto> list = invoicePurchaseService.selectInvoicePurchaseList(invoicePurchaseDto);
-        return getDataTable(list);
-    }
-
-    /**
-     * 瀵煎嚭鍙戠エ淇℃伅鍒楄〃
-     */
-    @Log(title = "鍙戠エ淇℃伅", businessType = BusinessType.EXPORT)
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, InvoicePurchase invoicePurchase) {
-        List<InvoicePurchase> list = invoicePurchaseService.selectInvoicePurchaseLists(invoicePurchase);
-        ExcelUtil<InvoicePurchase> util = new ExcelUtil<InvoicePurchase>(InvoicePurchase.class);
-        util.exportExcel(response, list, "鍙戠エ淇℃伅鏁版嵁");
-    }
-
-    /**
-     * 鏌ヨ鍙戠エ淇℃伅
-     */
-    @GetMapping("/getInvoiceById")
-    public InvoicePurchaseDto getInvoiceById(InvoicePurchaseDto invoicePurchaseDto) {
-        return invoicePurchaseService.getInvoiceById(invoicePurchaseDto);
-    }
-
-    /**
-     * 鏂板淇敼鍙戠エ淇℃伅
-     */
-    @Log(title = "鍙戠エ淇℃伅", businessType = BusinessType.INSERT)
-    @PostMapping("/addOrUpdateInvoice")
-    public AjaxResult addOrUpdateInvoice(@RequestBody InvoicePurchaseDto invoicePurchaseDto) throws IOException {
-        return toAjax(invoicePurchaseService.addOrUpdateInvoice(invoicePurchaseDto));
-    }
-
-    /**
-     * 鍒犻櫎鍙戠エ淇℃伅
-     */
-    @Log(title = "鍙戠エ淇℃伅", businessType = BusinessType.DELETE)
-    @DeleteMapping("/delInvoice")
-    public AjaxResult remove(@RequestBody Long[] ids) {
-        return toAjax(invoicePurchaseService.delInvoice(ids));
-    }
-
-}
diff --git a/src/main/java/com/ruoyi/purchase/controller/PaymentRegistrationController.java b/src/main/java/com/ruoyi/purchase/controller/PaymentRegistrationController.java
deleted file mode 100644
index 289110c..0000000
--- a/src/main/java/com/ruoyi/purchase/controller/PaymentRegistrationController.java
+++ /dev/null
@@ -1,184 +0,0 @@
-package com.ruoyi.purchase.controller;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.purchase.dto.PaymentHistoryRecordVo;
-import com.ruoyi.purchase.dto.PaymentLedgerDto;
-import com.ruoyi.purchase.dto.PaymentRegistrationDto;
-import com.ruoyi.purchase.pojo.PaymentRegistration;
-import com.ruoyi.purchase.service.IPaymentRegistrationService;
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.*;
-
-import jakarta.servlet.http.HttpServletResponse;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 浠樻鐧昏Controller
- *
- * @author ruoyi
- * @date 2025-05-15
- */
-@RestController
-@RequestMapping("/purchase/paymentRegistration")
-@AllArgsConstructor
-public class PaymentRegistrationController extends BaseController {
-    private IPaymentRegistrationService paymentRegistrationService;
-
-    /**
-     * 鏌ヨ浠樻鐧昏鍒楄〃
-     */
-//    @PreAuthorize("@ss.hasPermi('system:registration:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(PaymentRegistrationDto paymentRegistrationDto) {
-        startPage();
-        List<PaymentRegistrationDto> list = paymentRegistrationService.selectPaymentRegistrationList(paymentRegistrationDto);
-        return getDataTable(list);
-    }
-
-    /**
-     * 瀵煎嚭浠樻娴佹按鍒楄〃
-     */
-    @Log(title = "瀵煎嚭浠樻娴佹按鍒楄〃", businessType = BusinessType.EXPORT)
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, PaymentRegistrationDto paymentRegistrationDto)
-    {
-        Page page = new Page<>(-1,-1);
-        IPage<PaymentRegistrationDto> paymentRegistrationDtoIPage = paymentHistoryListPage(page, paymentRegistrationDto);
-        ExcelUtil<PaymentRegistrationDto> util = new ExcelUtil<PaymentRegistrationDto>(PaymentRegistrationDto.class);
-        util.exportExcel(response, paymentRegistrationDtoIPage.getRecords(), "瀵煎嚭浠樻娴佹按鍒楄〃");
-    }
-
-    /**
-     * 鑾峰彇浠樻鐧昏璇︾粏淇℃伅
-     */
-    @GetMapping(value = "/{id}")
-    public AjaxResult getInfo(@PathVariable("id") Long id) {
-        return success(paymentRegistrationService.selectPaymentRegistrationById(id));
-    }
-
-    /**
-     * 鏂板浠樻鐧昏
-     */
-    @Log(title = "浠樻鐧昏", businessType = BusinessType.INSERT)
-    @PostMapping
-    @Transactional(rollbackFor = Exception.class)
-    public AjaxResult add(@RequestBody List<PaymentRegistration>  paymentRegistration) {
-        return toAjax(paymentRegistrationService.insertPaymentRegistration(paymentRegistration));
-    }
-
-    /**
-     * 淇敼浠樻鐧昏
-     */
-    @Log(title = "浠樻鐧昏", businessType = BusinessType.UPDATE)
-    @PutMapping
-    @Transactional(rollbackFor = Exception.class)
-    public AjaxResult edit(@RequestBody PaymentRegistration paymentRegistration) {
-        return toAjax(paymentRegistrationService.updatePaymentRegistration(paymentRegistration));
-    }
-
-    /**
-     * 鍒犻櫎浠樻鐧昏
-     */
-    @Log(title = "浠樻鐧昏", businessType = BusinessType.DELETE)
-    @DeleteMapping("/del")
-    public AjaxResult remove(@RequestBody Long[] ids) {
-        return toAjax(paymentRegistrationService.deletePaymentRegistrationByIds(ids));
-    }
-
-    /**
-     * 鍒犻櫎浠樻鐧昏
-     */
-    @Log(title = "浠樻鐧昏", businessType = BusinessType.DELETE)
-    @DeleteMapping("/delete")
-    public AjaxResult delete(@RequestBody Long[] ids) {
-        return toAjax(paymentRegistrationService.delete(ids));
-    }
-
-    /**
-     * 鑾峰彇浠樻鐧昏璇︾粏淇℃伅
-     */
-    @GetMapping(value = "/byPurchaseId/{id}")
-    public AjaxResult getPurchaseInfo(@PathVariable("id") Long id) {
-        return success(paymentRegistrationService.selectPaymentRegistrationByPurchaseId(id));
-    }
-
-    /**
-     * 鑾峰彇浠樻鐧昏璇︾粏淇℃伅
-     */
-    @GetMapping(value = "/paymentLedgerList")
-    public AjaxResult paymentLedgerList(PaymentLedgerDto paymentLedgerDto, Page page,
-                                        Integer detailPageNum,
-                                        Integer detailPageSize) {
-        IPage<Map<String, Object>> mapIPage = paymentRegistrationService.selectPaymentLedgerList(paymentLedgerDto, page, detailPageNum, detailPageSize);
-        return success(mapIPage);
-    }
-
-    /**
-     * 渚涘簲鍟嗗線鏉ュ垎椤垫帴鍙�
-     */
-    @GetMapping("/supplierNameListPage")
-    public AjaxResult supplierNameListPage(PaymentLedgerDto paymentLedgerDto, Page page){
-        return success(paymentRegistrationService.supplierNameListPage(page,paymentLedgerDto));
-    }
-
-    /**
-     * 渚涘簲鍟嗗線鏉ュ垎椤垫帴鍙�
-     */
-    @GetMapping("/supplierNameListPageDetails")
-    public AjaxResult supplierNameListPageDetails(PaymentLedgerDto paymentLedgerDto){
-        return success(paymentRegistrationService.supplierNameListPageDetails(paymentLedgerDto));
-    }
-
-    /**
-     * 鑾峰彇鏈湀搴斾粯淇℃伅
-     */
-    @GetMapping(value = "/paymentMonthList")
-    public AjaxResult paymentMonthList() {
-        return success(paymentRegistrationService.paymentMonthList());
-    }
-
-    /**
-     * 鏌ヨ浠樻鐧昏鍒楄〃
-     *
-     * @param paymentRegistrationDto 浠樻鐧昏
-     * @return 浠樻鐧昏闆嗗悎
-     */
-    @GetMapping("/paymentHistoryList")
-    public TableDataInfo paymentHistoryList(PaymentRegistrationDto paymentRegistrationDto) {
-        startPage();
-        List<PaymentRegistrationDto> list = paymentRegistrationService.paymentHistoryList(paymentRegistrationDto);
-        return getDataTable(list);
-    }
-
-    /**
-     * 鏌ヨ渚涘簲鍟嗗線鏉ヨ褰�
-     * @param supplierId
-     * @return
-     */
-    @GetMapping("/getPaymentRecordList/{supplierId}")
-    public AjaxResult getPaymentRecordList(@PathVariable Long supplierId) {
-        List<PaymentHistoryRecordVo> paymentRecordList = paymentRegistrationService.getPaymentRecordList(supplierId);
-        return success(paymentRecordList);
-    }
-
-    /**
-     * 鏌ヨ浠樻鐧昏鍒楄〃
-     *
-     * @param paymentRegistrationDto 浠樻鐧昏
-     * @return 浠樻鐧昏闆嗗悎
-     */
-    @GetMapping("/paymentHistoryListPage")
-    public IPage<PaymentRegistrationDto> paymentHistoryListPage(Page page, PaymentRegistrationDto paymentRegistrationDto) {
-        return paymentRegistrationService.paymentHistoryListPage(page,paymentRegistrationDto);
-    }
-}
diff --git a/src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java b/src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
index 3290499..0951d3b 100644
--- a/src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
+++ b/src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
@@ -1,8 +1,6 @@
 package com.ruoyi.purchase.controller;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
@@ -17,27 +15,23 @@
 import com.ruoyi.purchase.pojo.PurchaseLedgerTemplate;
 import com.ruoyi.purchase.pojo.SalesLedgerProductTemplate;
 import com.ruoyi.purchase.service.IPurchaseLedgerService;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.service.ISalesLedgerProductService;
 import com.ruoyi.sales.service.ISalesLedgerService;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.annotations.ApiParam;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletResponse;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
-import jakarta.servlet.http.HttpServletResponse;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.math.BigDecimal;
 import java.net.URLEncoder;
 import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
 
 /**
  * 閲囪喘鍙拌处Controller
@@ -132,19 +126,6 @@
         util.exportExcel(response, list, "銆愯濉啓鍔熻兘鍚嶇О銆戞暟鎹�");
     }
 
-    /**
-     * 瀵煎嚭鏉ョエ鐧昏鍒楄〃
-     */
-    @Log(title = "瀵煎嚭鏉ョエ鐧昏鍒楄〃", businessType = BusinessType.EXPORT)
-    @PostMapping("/exportOne")
-    public void exportOne(HttpServletResponse response, PurchaseLedger purchaseLedger) {
-        Page page = new Page();
-        page.setCurrent(-1);
-        page.setSize(-1);
-        IPage<PurchaseLedgerDto> purchaseLedgerDtoIPage = purchaseLedgerService.selectPurchaseLedgerListPage(page, new PurchaseLedgerDto());
-        ExcelUtil<PurchaseLedgerDto> util = new ExcelUtil<PurchaseLedgerDto>(PurchaseLedgerDto.class);
-        util.exportExcel(response, purchaseLedgerDtoIPage.getRecords(), "瀵煎嚭鏉ョエ鐧昏鍒楄〃");
-    }
 
     /**
      * 鏂板淇敼閲囪喘鍙拌处
@@ -219,7 +200,7 @@
      */
     @GetMapping("/getProductBySalesNo")
     public AjaxResult getProductBySalesNo(Long id) {
-        return AjaxResult.success(purchaseLedgerService.getProductBySalesNo(id));
+        return AjaxResult.success();
     }
 
     /**
diff --git a/src/main/java/com/ruoyi/purchase/controller/PurchaseReturnOrdersController.java b/src/main/java/com/ruoyi/purchase/controller/PurchaseReturnOrdersController.java
index bb669b6..e4c7bf7 100644
--- a/src/main/java/com/ruoyi/purchase/controller/PurchaseReturnOrdersController.java
+++ b/src/main/java/com/ruoyi/purchase/controller/PurchaseReturnOrdersController.java
@@ -1,12 +1,18 @@
 package com.ruoyi.purchase.controller;
 
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.pojo.AccountStatementDetails;
+import com.ruoyi.account.service.AccountStatementDetailsService;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.OrderUtils;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.purchase.dto.PurchaseReturnOrderDto;
 import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper;
+import com.ruoyi.purchase.pojo.PurchaseReturnOrders;
 import com.ruoyi.purchase.service.PurchaseReturnOrdersService;
 import com.ruoyi.purchase.vo.PurchaseStockInProductVo;
 import io.swagger.v3.oas.annotations.Operation;
@@ -31,6 +37,7 @@
 public class PurchaseReturnOrdersController {
     private PurchaseReturnOrdersService purchaseReturnOrdersService;
     private PurchaseReturnOrdersMapper purchaseReturnOrdersMapper;
+    private AccountStatementDetailsService accountStatementDetailsService;
 
 
     @GetMapping("/listPage")
@@ -56,6 +63,13 @@
 
     @PostMapping("/deleteById/{id}")
     public AjaxResult deleteById(@PathVariable Long id) {
+        //濡傛灉璇ラ噰璐��璐у凡缁忕敓鎴愬璐﹀崟鍒欐棤娉曞垹闄�
+        PurchaseReturnOrders purchaseReturnOrders = purchaseReturnOrdersService.getById(id);
+        List<AccountStatementDetails> accountStatementDetails = accountStatementDetailsService.list(Wrappers.<AccountStatementDetails>lambdaQuery()
+                .eq(AccountStatementDetails::getReceiptNumber, purchaseReturnOrders.getNo()));
+        if (CollectionUtils.isNotEmpty(accountStatementDetails)){
+            throw new ServiceException("璇ラ噰璐��璐у崟宸茬粡鐢熸垚瀵硅处鍗曪紝鏃犳硶鍒犻櫎");
+        }
         purchaseReturnOrdersService.deleteById(id);
         return AjaxResult.success();
     }
diff --git a/src/main/java/com/ruoyi/purchase/controller/TicketRegistrationController.java b/src/main/java/com/ruoyi/purchase/controller/TicketRegistrationController.java
deleted file mode 100644
index db628af..0000000
--- a/src/main/java/com/ruoyi/purchase/controller/TicketRegistrationController.java
+++ /dev/null
@@ -1,206 +0,0 @@
-package com.ruoyi.purchase.controller;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.purchase.dto.PaymentRegistrationDto;
-import com.ruoyi.purchase.dto.ProductRecordDto;
-import com.ruoyi.purchase.dto.TicketRegistrationDto;
-import com.ruoyi.purchase.pojo.PaymentRegistration;
-import com.ruoyi.purchase.pojo.ProductRecord;
-import com.ruoyi.purchase.pojo.TicketRegistration;
-import com.ruoyi.purchase.service.IPaymentRegistrationService;
-import com.ruoyi.purchase.service.IProductRecordService;
-import com.ruoyi.purchase.service.ITicketRegistrationService;
-import com.ruoyi.purchase.service.impl.PaymentRegistrationServiceImpl;
-import com.ruoyi.sales.service.ICommonFileService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.CollectionUtils;
-import org.springframework.web.bind.annotation.*;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * 鏉ョエ鐧昏Controller
- *
- * @author ruoyi
- * @date 2025-05-13
- */
-@RestController
-@RequestMapping("/purchase/registration")
-@AllArgsConstructor
-@Tag(name = "鏉ョエ鐧昏")
-public class TicketRegistrationController extends BaseController {
-
-    private final PaymentRegistrationServiceImpl paymentRegistrationServiceImpl;
-    private ITicketRegistrationService ticketRegistrationService;
-
-    private ICommonFileService commonFileService;
-
-    private IProductRecordService productRecordService;
-
-    private IPaymentRegistrationService paymentRegistrationService;
-
-    /**
-     * 鏌ヨ鏉ョエ鐧昏鍒楄〃
-     */
-    @GetMapping("/list")
-    public TableDataInfo list(TicketRegistration ticketRegistration) {
-        startPage();
-        List<TicketRegistration> list = ticketRegistrationService.selectTicketRegistrationList(ticketRegistration);
-        return getDataTable(list);
-    }
-
-    @Operation(summary = "鏍规嵁id鏌ヨ浠樻娴佹按淇℃伅")
-    @GetMapping("/getById")
-    public List<PaymentRegistrationDto> getById( Long id ) {
-        return ticketRegistrationService.getPaymentRegistrationDtoById(id);
-    }
-
-    @Operation(summary = "鏍规嵁id鏌ヨ浠樻娴佹按")
-    @GetMapping("/getPaymentRegistrationById")
-    public AjaxResult getPaymentRegistrationById(Long id) {
-        PaymentRegistration byId = paymentRegistrationService.getById(id);
-        return AjaxResult.success(byId);
-    }
-
-    @Operation(summary = "淇敼浠樻娴佹按")
-    @PutMapping("/updatePaymentRegistration")
-    @Log(title = "淇敼浠樻娴佹按", businessType = BusinessType.UPDATE)
-    public AjaxResult updatePaymentRegistration(@RequestBody PaymentRegistration paymentRegistratio) {
-        return AjaxResult.success(paymentRegistrationService.updatePaymentRegistration(paymentRegistratio));
-    }
-
-    @Operation(summary = "鍒犻櫎浠樻娴佹按")
-    @DeleteMapping("/delPaymentRegistration")
-    @Transactional(rollbackFor = Exception.class)
-    public AjaxResult delPaymentRegistration(@RequestBody List<Long> id) {
-        return toAjax(paymentRegistrationService.delPaymentRegistration(id));
-    }
-
-    /**
-     * 瀵煎嚭鏉ョエ鐧昏鍒楄〃
-     */
-    @Log(title = "鏉ョエ鐧昏", businessType = BusinessType.EXPORT)
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, TicketRegistration ticketRegistration) {
-        List<TicketRegistration> list = ticketRegistrationService.selectTicketRegistrationList(ticketRegistration);
-        ExcelUtil<TicketRegistration> util = new ExcelUtil<TicketRegistration>(TicketRegistration.class);
-        util.exportExcel(response, list, "鏉ョエ鐧昏鏁版嵁");
-    }
-
-    /**
-     * 浠樻鐧昏瀵煎嚭
-     */
-    @Log(title = "浠樻鐧昏瀵煎嚭", businessType = BusinessType.EXPORT)
-    @PostMapping("/exportOne")
-    public void exportOne(HttpServletResponse response, TicketRegistration ticketRegistration) {
-        Page page = new Page<>(-1, -1);
-        IPage<TicketRegistration> ticketRegistrationIPage = listPage(page, ticketRegistration);
-        ExcelUtil<TicketRegistration> util = new ExcelUtil<TicketRegistration>(TicketRegistration.class);
-        util.exportExcel(response, ticketRegistrationIPage.getRecords(), "浠樻鐧昏瀵煎嚭");
-    }
-
-    /**
-     * 鏌ヨ鏉ョエ鐧昏鍜屼骇鍝佺埗瀛愬垪琛�
-     */
-    @GetMapping("/getRegistrationById")
-    public TicketRegistrationDto getRegistrationById(TicketRegistrationDto ticketRegistrationDto) {
-        return ticketRegistrationService.getRegistrationById(ticketRegistrationDto);
-    }
-
-    /**
-     * 鏂板淇敼鏉ョエ鐧昏
-     */
-    @Log(title = "鏉ョエ鐧昏", businessType = BusinessType.INSERT)
-    @PostMapping("/addOrUpdateRegistration")
-    @Transactional(rollbackFor = Exception.class)
-    public AjaxResult addOrUpdateRegistration(@RequestBody List<TicketRegistrationDto> ticketRegistrationDto) throws IOException {
-        if(CollectionUtils.isEmpty(ticketRegistrationDto)) return AjaxResult.error("璇烽�夋嫨瑕佷繚瀛樼殑璁板綍");
-        for (TicketRegistrationDto ticketRegistrationDto1 : ticketRegistrationDto) {
-            ticketRegistrationService.addOrUpdateRegistration(ticketRegistrationDto1);
-        }
-        return toAjax(1);
-    }
-
-
-    @PostMapping("/getProductRecordById")
-    public AjaxResult getProductRecordById(@RequestBody ProductRecordDto productRecordDto) {
-        if (productRecordDto.getId() == null) {
-            return AjaxResult.error("鍙傛暟閿欒");
-        }
-        return AjaxResult.success(productRecordService.getProductRecordById(productRecordDto));
-    }
-
-    @Schema(description = "淇敼鏉ョエ鐧昏")
-    @PostMapping("/updateRegistration")
-    public AjaxResult updateRegistration(@RequestBody ProductRecordDto productRecordDto) {
-
-        return productRecordService.updateRecord(productRecordDto);
-    }
-
-    /**
-     * 鍒犻櫎鏉ョエ鐧昏(鏉ョエ鍙拌处)
-     */
-    @Log(title = "鍒犻櫎鏉ョエ鐧昏(鏉ョエ鍙拌处)", businessType = BusinessType.DELETE)
-    @DeleteMapping("/delRegistration")
-    @Transactional(rollbackFor = Exception.class)
-    public AjaxResult delRegistration(@RequestBody Long[] ids) {
-        return toAjax(ticketRegistrationService.delRegistration(ids));
-    }
-
-    /**
-     * 鏌ヨ浜у搧淇℃伅寮�绁ㄨ褰曞垪琛�
-     */
-    @GetMapping("/productRecordList")
-    public List<ProductRecord> productRecordList(TicketRegistrationDto ticketRegistrationDto) {
-        List<ProductRecord> list = productRecordService.selectProductRecordList(ticketRegistrationDto);
-        return list;
-    }
-
-    /**
-     * 鍒嗛〉鏌ヨ浜у搧淇℃伅寮�绁ㄨ褰曞垪琛�
-     */
-    @GetMapping("/productRecordPage")
-    public AjaxResult productRecordPage(Page page, TicketRegistrationDto ticketRegistrationDto) {
-
-        IPage<ProductRecordDto> list = productRecordService.productRecordPage(page,ticketRegistrationDto);
-        return AjaxResult.success(list);
-    }
-
-    /**
-     * 鏌ヨ鍙戠エ鍙�
-     */
-    @GetMapping("/getTicketNo")
-    public AjaxResult getTicketNo(TicketRegistrationDto ticketRegistrationDto) {
-        return AjaxResult.success(ticketRegistrationService.getTicketNo(ticketRegistrationDto));
-    }
-
-    /**
-     * 鏌ヨ鏉ョエ鐧昏鍒楄〃
-     */
-    @GetMapping("/listPage")
-    public IPage<TicketRegistration> listPage(Page page, TicketRegistration ticketRegistration) {
-        return ticketRegistrationService.selectTicketRegistrationListPage(page,ticketRegistration);
-    }
-
-    @Schema(description = "鏍规嵁id鏌ヨ鏉ユ紓鐧昏")
-    @GetMapping("/getPuargeById")
-    public AjaxResult getPuargeById(Long id) {
-        return AjaxResult.success(ticketRegistrationService.getPuargeById( id));
-    }
-
-
-
-}
diff --git a/src/main/java/com/ruoyi/purchase/dto/InvoicePurchaseDto.java b/src/main/java/com/ruoyi/purchase/dto/InvoicePurchaseDto.java
deleted file mode 100644
index c8a8671..0000000
--- a/src/main/java/com/ruoyi/purchase/dto/InvoicePurchaseDto.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.ruoyi.purchase.dto;
-
-import com.ruoyi.sales.pojo.CommonFile;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.util.List;
-
-@Data
-public class InvoicePurchaseDto {
-
-    private Long id;
-
-    /**
-     * 閲囪喘鍙拌处id
-     */
-    private Long purchaseLedgerId;
-
-    /**
-     * 閲囪喘鍚堝悓鍙�
-     */
-    private String purchaseContractNo;
-
-    /**
-     * 鍏宠仈閿�鍞彴璐︿富琛ㄤ富閿�
-     */
-    private Long salesLedgerId;
-
-    /**
-     * 閿�鍞悎鍚屽彿
-     */
-    private String salesContractNo;
-
-    /**
-     * 渚涘簲鍟嗗悕绉�
-     */
-    private String supplierName;
-
-    /**
-     * 鍙戠エ鍙�
-     */
-    private String invoiceNumber;
-
-    /**
-     * 鍙戠エ閲戦锛堝厓锛�
-     */
-    private BigDecimal invoiceAmount;
-
-    /**
-     * 绋庣巼
-     */
-    private BigDecimal taxRate;
-
-    /**
-     * 寮�绁ㄤ汉ID
-     */
-    private Long issUerId;
-
-    /**
-     * 寮�绁ㄤ汉
-     */
-    private String issUer;
-
-    /**
-     * 寮�绁ㄦ棩鏈�
-     */
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private LocalDate issueDate;
-
-    private List<String> tempFileIds;
-    private List<CommonFile> CommonFiles;
-
-    private String fileName;
-}
diff --git a/src/main/java/com/ruoyi/purchase/dto/InvoicePurchaseReportDto.java b/src/main/java/com/ruoyi/purchase/dto/InvoicePurchaseReportDto.java
deleted file mode 100644
index 45347ad..0000000
--- a/src/main/java/com/ruoyi/purchase/dto/InvoicePurchaseReportDto.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.ruoyi.purchase.dto;
-
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import lombok.Data;
-
-/**
- * 鎶ヨ〃鍒嗘瀽---椤圭洰鍒╂鼎
- */
-@Data
-public class InvoicePurchaseReportDto {
-
-    //閿�鍞悎鍚屽彿
-    @Excel(name = "閿�鍞悎鍚屽彿")
-    private String customerContractNo;
-//    瀹㈡埛鍚嶇О
-    @Excel(name = "瀹㈡埛鍚嶇О")
-    private String customerName;
-//    椤圭洰鍚嶇О
-    @Excel(name = "椤圭洰鍚嶇О")
-    private String projectName;
-//    鍚堝悓閲戦
-    @Excel(name = "鍚堝悓閲戦")
-    private String contractAmount;
-//    閲囪喘閲戦
-    @Excel(name = "閲囪喘閲戦")
-    private String purchaseAmount;
-
-    private String saleTaxExclusiveTotalPrice;
-
-    private String taxExclusiveTotalPrice;
-//    鍒╂鼎
-    @Excel(name = "鍒╂鼎")
-    private String balance;
-    //    鍒╂鼎鐜�
-    @Excel(name = "鍒╂鼎鐜�")
-    private String balanceRatio;
-    //    澧炲�肩◣
-    @Excel(name = "澧炲�肩◣")
-    private String balanceAmount;
-
-}
diff --git a/src/main/java/com/ruoyi/purchase/dto/PaymentRegistrationDto.java b/src/main/java/com/ruoyi/purchase/dto/PaymentRegistrationDto.java
deleted file mode 100644
index 8d56648..0000000
--- a/src/main/java/com/ruoyi/purchase/dto/PaymentRegistrationDto.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.ruoyi.purchase.dto;
-
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import com.ruoyi.purchase.pojo.PaymentRegistration;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Data
-public class PaymentRegistrationDto extends PaymentRegistration {
-
-    // 鏌ヨ鍒楄〃鏌ヨ鐢ㄤ緵搴斿晢鍙峰拰鍚堝悓鍙�
-    private String supplierNameOrContractNo;
-
-    // 閿�鍞悎鍚屽彿
-    private String salesContractNo;
-
-    // 閲囪喘鍚堝悓鍙�
-    @Excel(name = "閲囪喘鍚堝悓鍙�")
-    private String purchaseContractNumber;
-
-    // 渚涘簲鍟嗗悕绉�
-    @Excel(name = "渚涘簲鍟嗗悕绉�")
-    private String supplierName;
-
-    // 鍙戠エ鍙�
-    private String invoiceNumber;
-
-    // 鍙戠エ閲戦
-    private BigDecimal invoiceAmount;
-
-    // 寰呬粯娆鹃噾棰�
-    private BigDecimal unPaymentAmount;
-
-    // 浠樻閲戦
-    private BigDecimal paymentAmount;
-
-    // 搴斾粯閲戦
-    private BigDecimal payableAmount;
-
-    // 绋庣巼
-    private String taxRate;
-
-    // 鐧昏浜�
-    private String registrant;
-
-    private String searchText;
-
-    // 宸蹭粯娆炬�婚噾棰�
-    private BigDecimal paymentAmountTotal;
-
-    private String paymentDateStart;
-
-    private String paymentDateEnd;
-}
diff --git a/src/main/java/com/ruoyi/purchase/dto/ProductRecordDto.java b/src/main/java/com/ruoyi/purchase/dto/ProductRecordDto.java
deleted file mode 100644
index 1b3c691..0000000
--- a/src/main/java/com/ruoyi/purchase/dto/ProductRecordDto.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.ruoyi.purchase.dto;
-
-import com.ruoyi.other.pojo.TempFile;
-import com.ruoyi.purchase.pojo.ProductRecord;
-import com.ruoyi.sales.pojo.CommonFile;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-@Data
-public class ProductRecordDto extends ProductRecord {
-
-    private Long ticketRegistrationId;
-
-    //閿�鍞悎鍚屽彿
-    private String salesContractNo;
-    //瀹㈡埛鍚堝悓鍙�
-    private String customerContarctNo;
-
-    //瀹㈡埛鍚嶇О
-    private String customerName;
-    //浜у搧鍚嶇О
-    private String productModel;
-    //閲囪喘鍚堝悓鍙�
-    private String purchaseContractNumber;
-    //渚涘簲鍟嗗悕绉�
-    private String supplierName;
-    private String projectName;
-    private Long issUerId;
-    private String issUer;
-    /**
-     * 鍚堝悓閲戦锛堜骇鍝佸惈绋庢�讳环锛�
-     */
-    private BigDecimal contractAmount = BigDecimal.ZERO;
-    //澧炲�肩◣
-    /**
-     * 宸叉潵绁ㄩ噾棰濓紙鍙戠エ閲戦锛�
-     */
-    private BigDecimal invoiceTotal = BigDecimal.ZERO;
-    private BigDecimal invoiceAmount = BigDecimal.ZERO;
-    /**
-     * 鍙戠エ鍙�
-     */
-    private String invoiceNumber;
-    private BigDecimal unTicketsPrice = BigDecimal.ZERO;
-
-    private List<CommonFile> commonFiles;
-
-    private List<String> tempFileIds;
-}
diff --git a/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java b/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
index 455dc9b..cd3b9fd 100644
--- a/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
+++ b/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
@@ -165,26 +165,11 @@
     private BigDecimal invoiceAmount;
 
     /**
-     * 鏉ョエ鐧昏id
-     */
-    private Long ticketRegistrationId;
-
-    /**
      * 鍚堝悓閲戦锛堜骇鍝佸惈绋庢�讳环锛�
      */
     @Excel(name = "鍚堝悓閲戦")
     private BigDecimal contractAmount = BigDecimal.ZERO;
 
-
-    @TableField(exist = false)
-    @Schema(description = "鏉ョエ閲戦")
-    @Excel(name = "宸叉潵绁ㄩ噾棰�(鍏�)")
-    private BigDecimal receiptPaymentAmount =  BigDecimal.ZERO;
-
-    @Schema(description = "鏈潵绁ㄩ噾棰�")
-    @TableField(exist = false)
-    @Excel(name = "鏈潵绁ㄩ噾棰�(鍏�)")
-    private BigDecimal unReceiptPaymentAmount =BigDecimal.ZERO;
 
     @Schema(description = "鏂囦欢绫诲瀷  鍙� 4")
     @TableField(exist = false)
diff --git a/src/main/java/com/ruoyi/purchase/dto/TicketRegistrationDto.java b/src/main/java/com/ruoyi/purchase/dto/TicketRegistrationDto.java
deleted file mode 100644
index 59f1da3..0000000
--- a/src/main/java/com/ruoyi/purchase/dto/TicketRegistrationDto.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.ruoyi.purchase.dto;
-
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import com.ruoyi.purchase.pojo.TicketRegistration;
-import com.ruoyi.sales.pojo.CommonFile;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.time.LocalDate;
-import java.util.List;
-
-/**
- * 鏉ョエ鐧昏琛�
- */
-
-@Data
-@TableName("ticket_registration")
-public class TicketRegistrationDto extends TicketRegistration {
-
-    /**
-     * 涓婚敭ID
-     */
-    private Long id;
-
-    /**
-     * 閲囪喘鍙拌处id
-     */
-    private Long purchaseLedgerId;
-
-    /**
-     * 閲囪喘鍚堝悓鍙�
-     */
-    private String purchaseContractNumber;
-
-    /**
-     * 閿�鍞悎鍚屽彿
-     */
-    private String salesContractNo;
-
-    /**
-     * 寮�绁ㄦ棩鏈�
-     */
-
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private LocalDate entryDate;
-
-    /**
-     * 瀹㈡埛鍚嶇О
-     */
-    private String customerName;
-
-    /**
-     * 涓氬姟鍛�
-     */
-    private String businessPerson;
-
-
-
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    @TableField(exist = false)
-    private LocalDate enterDate;
-
-    /**
-     * 涓氬姟鍛榠d
-     */
-    private Long businessPersonId;
-
-    /**
-     * 椤圭洰鍚嶇О
-     */
-    private String projectName;
-
-    private List<SalesLedgerProduct> productData;
-
-    private Long salesContractNoId;
-    private String supplierName;
-
-    private List<String> tempFileIds;
-    private List<CommonFile> CommonFiles;
-
-    private String fileName;
-
-    @TableField(exist = false)
-    private String createdAtStart;
-    @TableField(exist = false)
-    private String createdAtEnd;
-}
diff --git a/src/main/java/com/ruoyi/purchase/mapper/InvoicePurchaseMapper.java b/src/main/java/com/ruoyi/purchase/mapper/InvoicePurchaseMapper.java
deleted file mode 100644
index b1dc03c..0000000
--- a/src/main/java/com/ruoyi/purchase/mapper/InvoicePurchaseMapper.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.ruoyi.purchase.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.purchase.dto.InvoicePurchaseReportDto;
-import com.ruoyi.purchase.dto.VatDto;
-import com.ruoyi.purchase.pojo.InvoicePurchase;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * 鍙戠エ淇℃伅Mapper鎺ュ彛
- *
- * @author ruoyi
- * @date 2025-05-14
- */
-public interface InvoicePurchaseMapper extends BaseMapper<InvoicePurchase> {
-
-
-    IPage<InvoicePurchaseReportDto> selectPurchaseReport(IPage page, @Param("c") InvoicePurchaseReportDto invoicePurchaseReportDto);
-
-    IPage<VatDto> listVat(Page page,@Param("month") String month);
-
-    List<VatDto>  listVat1();
-}
diff --git a/src/main/java/com/ruoyi/purchase/mapper/PaymentRegistrationMapper.java b/src/main/java/com/ruoyi/purchase/mapper/PaymentRegistrationMapper.java
deleted file mode 100644
index 196d531..0000000
--- a/src/main/java/com/ruoyi/purchase/mapper/PaymentRegistrationMapper.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.ruoyi.purchase.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.purchase.dto.PaymentHistoryRecordVo;
-import com.ruoyi.purchase.dto.PaymentLedgerDto;
-import com.ruoyi.purchase.dto.PaymentRegistrationDto;
-import com.ruoyi.purchase.pojo.PaymentRegistration;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * 浠樻鐧昏Mapper鎺ュ彛
- *
- * @author ruoyi
- * @date 2025-05-15
- */
-public interface PaymentRegistrationMapper extends BaseMapper<PaymentRegistration> {
-    /**
-     * 鏌ヨ浠樻鐧昏
-     *
-     * @param id 浠樻鐧昏涓婚敭
-     * @return 浠樻鐧昏
-     */
-    public PaymentRegistrationDto selectPaymentRegistrationById(@Param("id") Long id);
-
-    /**
-     * 鏌ヨ浠樻鐧昏鍒楄〃
-     *
-     * @param paymentRegistrationDto 浠樻鐧昏
-     * @return 浠樻鐧昏闆嗗悎
-     */
-    public List<PaymentRegistrationDto> selectPaymentRegistrationList(PaymentRegistrationDto paymentRegistrationDto);
-
-    /**
-     * 鏌ヨ浠樻鐧昏鍒楄〃
-     *
-     * @param paymentRegistrationDto 浠樻鐧昏
-     * @return 浠樻鐧昏闆嗗悎
-     */
-    public List<PaymentRegistrationDto> paymentHistoryList(@Param("params") PaymentRegistrationDto paymentRegistrationDto);
-
-    /**
-     * 璁$畻姣忓紶鍙戠エ鐨勫凡寮�绁ㄩ噾棰�
-     * @param ticketRegistrationIds
-     * @return
-     */
-    public List<PaymentRegistrationDto> countPaymentTotalByTicketRegId(List<Long> ticketRegistrationIds);
-
-    /**
-     * 鏌ヨ渚涘簲鍟嗗線鏉ヨ褰�
-     * @param supplierId
-     * @return
-     */
-    List<PaymentHistoryRecordVo> getPaymentRecordList(Long supplierId);
-
-    /**
-     * 鏌ヨ浠樻鐧昏鍒楄〃
-     *
-     * @param paymentRegistrationDto 浠樻鐧昏
-     * @return 浠樻鐧昏闆嗗悎
-     */
-    IPage<PaymentRegistrationDto> paymentHistoryListPage(Page page, @Param("params") PaymentRegistrationDto paymentRegistrationDto);
-
-    IPage<PaymentRegistrationDto> supplierNameListPage(Page page,@Param("req") PaymentLedgerDto paymentLedgerDto);
-
-    List<PaymentRegistrationDto> supplierNameListPageDetails(@Param("req") PaymentLedgerDto paymentLedgerDto);
-}
diff --git a/src/main/java/com/ruoyi/purchase/mapper/ProductRecordMapper.java b/src/main/java/com/ruoyi/purchase/mapper/ProductRecordMapper.java
deleted file mode 100644
index b4bdea9..0000000
--- a/src/main/java/com/ruoyi/purchase/mapper/ProductRecordMapper.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.purchase.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.purchase.dto.ProductRecordDto;
-import com.ruoyi.purchase.dto.TicketRegistrationDto;
-import com.ruoyi.purchase.pojo.ProductRecord;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * 閲囪喘鍙拌处浜у搧寮�绁ㄨ褰昅apper鎺ュ彛
- *
- * @author ruoyi
- * @date 2025-05-23
- */
-public interface ProductRecordMapper extends BaseMapper<ProductRecord> {
-
-    IPage<ProductRecordDto> productRecordPage(Page page, @Param("c") TicketRegistrationDto ticketRegistrationDto);
-
-    List<ProductRecordDto> getProductRecordById(@Param("c") ProductRecordDto productRecordDto);
-}
diff --git a/src/main/java/com/ruoyi/purchase/mapper/PurchaseLedgerMapper.java b/src/main/java/com/ruoyi/purchase/mapper/PurchaseLedgerMapper.java
index c3201e0..8d5ab54 100644
--- a/src/main/java/com/ruoyi/purchase/mapper/PurchaseLedgerMapper.java
+++ b/src/main/java/com/ruoyi/purchase/mapper/PurchaseLedgerMapper.java
@@ -3,7 +3,6 @@
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.ruoyi.purchase.dto.PaymentRegistrationDto;
 import com.ruoyi.purchase.dto.PurchaseLedgerDto;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
 import org.apache.ibatis.annotations.Param;
@@ -23,8 +22,6 @@
     int updateContractAmountById(@Param("id") Long id, @Param("totalTaxInclusiveAmount") BigDecimal totalTaxInclusiveAmount);
 
     IPage<PurchaseLedgerDto> selectPurchaseLedgerListPage(IPage ipage, @Param("c") PurchaseLedgerDto purchaseLedger);
-
-    List<PaymentRegistrationDto> getPaymentRegistrationDtoById(Long id);
 
     List<IncomeExpenseAnalysisDto> selectPurchaseStats(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("dateFormat") String dateFormat);
 
diff --git a/src/main/java/com/ruoyi/purchase/mapper/PurchaseReturnOrdersMapper.java b/src/main/java/com/ruoyi/purchase/mapper/PurchaseReturnOrdersMapper.java
index 9d28354..4eb517f 100644
--- a/src/main/java/com/ruoyi/purchase/mapper/PurchaseReturnOrdersMapper.java
+++ b/src/main/java/com/ruoyi/purchase/mapper/PurchaseReturnOrdersMapper.java
@@ -3,8 +3,8 @@
 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.account.bean.dto.PurchaseReturnDto;
-import com.ruoyi.account.bean.vo.PurchaseReturnVo;
+import com.ruoyi.account.bean.dto.purchase.PurchaseReturnDto;
+import com.ruoyi.account.bean.vo.purchase.PurchaseReturnVo;
 import com.ruoyi.purchase.dto.PurchaseReturnOrderDto;
 import com.ruoyi.purchase.dto.PurchaseReturnOrderHasAllInfoDto;
 import com.ruoyi.purchase.pojo.PurchaseReturnOrders;
diff --git a/src/main/java/com/ruoyi/purchase/mapper/TicketRegistrationMapper.java b/src/main/java/com/ruoyi/purchase/mapper/TicketRegistrationMapper.java
deleted file mode 100644
index 39633c1..0000000
--- a/src/main/java/com/ruoyi/purchase/mapper/TicketRegistrationMapper.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.ruoyi.purchase.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.purchase.pojo.TicketRegistration;
-
-/**
- * 鏉ョエ鐧昏Mapper鎺ュ彛
- *
- * @author ruoyi
- * @date 2025-05-13
- */
-public interface TicketRegistrationMapper extends BaseMapper<TicketRegistration> {
-}
diff --git a/src/main/java/com/ruoyi/purchase/pojo/InvoicePurchase.java b/src/main/java/com/ruoyi/purchase/pojo/InvoicePurchase.java
deleted file mode 100644
index 0d9eb46..0000000
--- a/src/main/java/com/ruoyi/purchase/pojo/InvoicePurchase.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package com.ruoyi.purchase.pojo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.util.Date;
-
-/**
- * 鍙戠エ淇℃伅瀵硅薄 invoice_purchase
- *
- * @author ruoyi
- * @date 2025-05-14
- */
-@TableName("invoice_purchase")
-@Data
-public class InvoicePurchase {
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭ID
-     */
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 閲囪喘鍙拌处id
-     */
-    private Long purchaseLedgerId;
-
-    /**
-     * 閲囪喘鍚堝悓鍙�
-     */
-    @Excel(name = "閲囪喘鍚堝悓鍙�")
-    private String purchaseContractNo;
-
-    /**
-     * 鍏宠仈閿�鍞彴璐︿富琛ㄤ富閿�
-     */
-    private Long salesLedgerId;
-
-    /**
-     * 閿�鍞悎鍚屽彿
-     */
-    @Excel(name = "閿�鍞悎鍚屽彿")
-    private String salesContractNo;
-
-    /**
-     * 渚涘簲鍟嗗悕绉�
-     */
-    @Excel(name = "渚涘簲鍟嗗悕绉�")
-    private String supplierName;
-
-    /**
-     * 鍙戠エ鍙�
-     */
-    @Excel(name = "鍙戠エ鍙�")
-    private String invoiceNumber;
-
-    /**
-     * 鍙戠エ閲戦锛堝厓锛�
-     */
-    @Excel(name = "鍙戠エ閲戦(鍏�)")
-    private BigDecimal invoiceAmount;
-
-    /**
-     * 绋庣巼
-     */
-    @Excel(name = "绋庣巼(%)")
-    private BigDecimal taxRate;
-
-    /**
-     * 寮�绁ㄤ汉ID
-     */
-    private Long issUerId;
-
-    /**
-     * 寮�绁ㄤ汉
-     */
-    @Excel(name = "寮�绁ㄤ汉")
-    private String issUer;
-
-    /**
-     * 寮�绁ㄦ棩鏈�
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd" ,timezone = "GMT+8")
-    @Excel(name = "寮�绁ㄦ棩鏈�", width = 30, dateFormat = "yyyy-MM-dd")
-    private LocalDate issueDate;
-
-    /**
-     * 鍙戠エ鏂囦欢锛圥DF鏍煎紡锛�
-     */
-    private String invoiceFile;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    private Date createdAt;
-
-    /**
-     * 鏇存柊鏃堕棿
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    private Date updatedAt;
-    
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-    @Schema(description = "鍒涘缓鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-
-}
diff --git a/src/main/java/com/ruoyi/purchase/pojo/PaymentRegistration.java b/src/main/java/com/ruoyi/purchase/pojo/PaymentRegistration.java
deleted file mode 100644
index a84cf04..0000000
--- a/src/main/java/com/ruoyi/purchase/pojo/PaymentRegistration.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.ruoyi.purchase.pojo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * 浠樻鐧昏瀵硅薄 payment_registration
- *
- * @author ruoyi
- * @date 2025-05-15
- */
-
-@Data
-@TableName("payment_registration")
-public class PaymentRegistration {
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * id
-     */
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 閿�鍞彴璐d
-     */
-    private Long saleLedgerId;
-
-    /**
-     * 閲囪喘鍙拌处id
-     */
-    private Long purchaseLedgerId;
-
-    /**
-     * 閲囪喘璁㈠崟浜у搧id
-     */
-    private Long salesLedgerProductId;
-
-    /**
-     * 渚涘簲鍟唅d
-     */
-    private Long supplierId;
-
-    /**
-     * 鍙戠エid
-     */
-    private Long ticketRegistrationId;
-
-    /**
-     * 鏈浠樻閲戦
-     */
-    @Excel(name = "浠樻閲戦")
-    private BigDecimal currentPaymentAmount;
-
-    /**
-     * 浠樻褰㈠紡
-     */
-    @Excel(name = "浠樻褰㈠紡")
-    private String paymentMethod;
-
-    /**
-     * 绋庣巼
-     */
-    private String taxRate;
-
-    /**
-     * 鐧昏浜�
-     */
-    private Long registrantId;
-
-    // 绉熸埛id
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-    /**
-     * 浠樻鏃ユ湡
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "浠樻鏃ユ湡", width = 30, dateFormat = "yyyy-MM-dd")
-    private Date paymentDate;
-
-    /**
-     * 鐧昏鏃ユ湡
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "鐧昏鏃ユ湡", width = 30, dateFormat = "yyyy-MM-dd")
-    private Date registrationtDate;
-
-    /**
-     * 鍒涘缓鏃ユ湡
-     */
-    @TableField(fill = FieldFill.INSERT)
-    private Date createTime;
-
-    /**
-     * 淇敼鏃ユ湡
-     */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Date updateTime;
-    @Schema(description = "鍒涘缓鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-
-}
diff --git a/src/main/java/com/ruoyi/purchase/pojo/ProductRecord.java b/src/main/java/com/ruoyi/purchase/pojo/ProductRecord.java
deleted file mode 100644
index 5003107..0000000
--- a/src/main/java/com/ruoyi/purchase/pojo/ProductRecord.java
+++ /dev/null
@@ -1,139 +0,0 @@
-package com.ruoyi.purchase.pojo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import lombok.Data;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * 閲囪喘鍙拌处浜у搧寮�绁ㄨ褰曞璞� product_record
- *
- * @author ruoyi
- * @date 2025-05-23
- */
-@Data
-@TableName("product_record")
-public class ProductRecord implements Serializable {
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭id
-     */
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 鏉ョエ鐧昏id
-     */
-    private Long ticketRegistrationId;
-
-    /**
-     * 閲囪喘鍙拌处id
-     */
-    private Long purchaseLedgerId;
-
-    /**
-     * 浜у搧id
-     */
-    private Long saleLedgerProjectId;
-
-    /**
-     * 浜у搧澶х被
-     */
-    private String productCategory;
-
-    /**
-     * 瑙勬牸鍨嬪彿
-     */
-    private String specificationModel;
-
-    /**
-     * 鍗曚綅
-     */
-    private String unit;
-
-    /**
-     * 鏁伴噺
-     */
-    private BigDecimal quantity;
-
-    /**
-     * 绋庣巼
-     */
-    private BigDecimal taxRate;
-
-    /**
-     * 鍚◣鍗曚环
-     */
-    private BigDecimal taxInclusiveUnitPrice;
-
-    /**
-     * 鍚◣鎬讳环
-     */
-    private BigDecimal taxInclusiveTotalPrice;
-
-    /**
-     * 涓嶅惈绋庢�讳环
-     */
-    private BigDecimal taxExclusiveTotalPrice;
-
-    /**
-     * 鍙戠エ绫诲瀷
-     */
-    private String invoiceType;
-
-    /**
-     * 1.閿�鍞彴璐︼紝2.閲囪喘鍙拌处
-     */
-    private String type;
-
-    /**
-     * 鏈鏉ョエ鏁�
-     */
-    private BigDecimal ticketsNum;
-
-    /**
-     * 鏈鏉ョエ閲戦(鍏�)
-     */
-    private BigDecimal ticketsAmount;
-
-    /**
-     * 鏈潵绁ㄦ暟
-     */
-    private BigDecimal futureTickets = BigDecimal.ZERO;
-
-    /**
-     * 鏈潵绁ㄩ噾棰�(鍏�)
-     */
-    private BigDecimal futureTicketsAmount = BigDecimal.ZERO;
-
-    /**
-     * 浜у搧id
-     */
-    private Long productId;
-
-    /**
-     * 鍨嬪彿id
-     */
-    private Long productModelId;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    private Date createdAt;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-    @Schema(description = "鍒涘缓鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-
-}
diff --git a/src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java b/src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java
index 717dc66..980c6bc 100644
--- a/src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java
+++ b/src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java
@@ -136,14 +136,6 @@
      */
     private String phoneNumber;
 
-    @TableField(exist = false)
-    @Schema(description = "鏉ョエ閲戦")
-    private String receiptPaymentAmount;
-
-    @Schema(description = "鏈潵绁ㄩ噾棰�")
-    @TableField(exist = false)
-    private String unReceiptPaymentAmount;
-
     @Schema(description = "鏂囦欢绫诲瀷  鍙� 4")
     @TableField(exist = false)
     private Integer type;
diff --git a/src/main/java/com/ruoyi/purchase/pojo/TicketRegistration.java b/src/main/java/com/ruoyi/purchase/pojo/TicketRegistration.java
deleted file mode 100644
index 0dcf7c6..0000000
--- a/src/main/java/com/ruoyi/purchase/pojo/TicketRegistration.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package com.ruoyi.purchase.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.util.Date;
-
-/**
- * 鏉ョエ鐧昏瀵硅薄 ticket_registration
- *
- * @author ruoyi
- * @date 2025-05-13
- */
-@Data
-@TableName("ticket_registration")
-public class TicketRegistration{
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭ID
-     */
-    @TableId(value = "id", type = IdType.AUTO)
-    private Long id;
-
-    /**
-     * 鐘舵��
-     */
-    @Excel(name = "鐘舵��")
-    @TableField(exist = false)
-    private String statusName;
-
-    /**
-     * 閲囪喘鍙拌处id
-     */
-    private Long purchaseLedgerId;
-
-    /**
-     * 閲囪喘鍚堝悓鍙�
-     */
-    @Excel(name = "閲囪喘鍚堝悓鍙�")
-    private String purchaseContractNumber;
-
-    /**
-     * 閿�鍞悎鍚屽彿
-     */
-    @Excel(name = "閿�鍞悎鍚屽彿")
-    private String salesContractNo;
-
-    /**
-     * 渚涘簲鍟嗗悕绉�
-     */
-    @Excel(name = "渚涘簲鍟嗗悕绉�")
-    private String supplierName;
-
-    /**
-     * 瀹㈡埛鍚嶇О
-     */
-    private String customerName;
-
-//    /**
-//     * 涓氬姟鍛�
-//     */
-//    @Excel(name = "涓氬姟鍛�")
-//    private String businessPerson;
-//
-//    /**
-//     * 涓氬姟鍛榠d
-//     */
-//    private Long businessPersonId;
-
-    /**
-     * 鍙戠エ鍙�
-     */
-    @Excel(name = "鍙戠エ鍙�")
-    private String invoiceNumber;
-
-    /**
-     * 鍙戠エ閲戦锛堝厓锛�
-     */
-    @Excel(name = "鍙戠エ閲戦(鍏�)")
-    private BigDecimal invoiceAmount;
-
-    /**
-     * 寮�绁ㄤ汉ID
-     */
-    @Excel(name = "寮�绁ㄤ汉")
-    private String issUerId;
-
-    /**
-     * 寮�绁ㄤ汉
-     */
-    @Excel(name = "寮�绁ㄤ汉")
-    private String issUer;
-
-    /**
-     * 寮�绁ㄦ棩鏈�
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd" ,timezone = "GMT+8")
-    @Excel(name = "寮�绁ㄦ棩鏈�", width = 30, dateFormat = "yyyy-MM-dd")
-    private LocalDate issueDate;
-
-    /**
-     * 椤圭洰鍚嶇О
-     */
-    @Excel(name = "椤圭洰鍚嶇О")
-    private String projectName;
-
-    /**
-     * 浜у搧淇℃伅
-     */
-    private Long productId;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    private Date createdAt;
-
-    /**
-     * 鏇存柊鏃堕棿
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    private Date updatedAt;
-
-    /**
-     * 鍏宠仈閿�鍞彴璐︿富琛ㄤ富閿�
-     */
-    private Long salesLedgerId;
-
-    /**
-     * 鍚堝悓閲戦锛堜骇鍝佸惈绋庢�讳环锛�
-     */
-    private BigDecimal contractAmount;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-    @Schema(description = "宸蹭粯娆炬�婚噾棰�")
-    @TableField(exist = false)
-    @Excel(name = "宸蹭粯娆炬�婚噾棰�")
-    private BigDecimal paymentAmountTotal;
-
-    @Schema(description = "鏈粯娆炬�婚噾棰�")
-    @TableField(exist = false)
-    @Excel(name = "鏈粯娆炬�婚噾棰�")
-    private BigDecimal unPaymentAmountTotal;
-
-    @TableField(exist = false)
-    private Boolean status;
-
-    @TableField(exist = false)
-    private String issueDateStart;
-    @TableField(exist = false)
-    private String issueDateEnd;
-
-    @TableField(exist = false)
-    private String supplierNameOrContractNo;
-
-    @Schema(description = "褰曞叆鏃堕棿")
-    private LocalDate enterDate;
-    @Schema(description = "鍒涘缓鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-
-}
diff --git a/src/main/java/com/ruoyi/purchase/service/IInvoicePurchaseService.java b/src/main/java/com/ruoyi/purchase/service/IInvoicePurchaseService.java
deleted file mode 100644
index cc17fc2..0000000
--- a/src/main/java/com/ruoyi/purchase/service/IInvoicePurchaseService.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.ruoyi.purchase.service;
-
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.purchase.dto.InvoicePurchaseDto;
-import com.ruoyi.purchase.dto.InvoicePurchaseReportDto;
-import com.ruoyi.purchase.dto.VatDto;
-import com.ruoyi.purchase.pojo.InvoicePurchase;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * 鍙戠エ淇℃伅Service鎺ュ彛
- *
- * @author ruoyi
- * @date 2025-05-14
- */
-public interface IInvoicePurchaseService extends IService<InvoicePurchase> {
-    List<InvoicePurchaseDto> selectInvoicePurchaseList(InvoicePurchaseDto invoicePurchaseDto);
-
-    int delInvoice(Long[] ids);
-
-    int addOrUpdateInvoice(InvoicePurchaseDto invoicePurchaseDto) throws IOException;
-
-    InvoicePurchaseDto getInvoiceById(InvoicePurchaseDto invoicePurchaseDto);
-
-    List<InvoicePurchase> selectInvoicePurchaseLists(InvoicePurchase invoicePurchase);
-
-    IPage<InvoicePurchaseReportDto> listPurchaseReport(Page page, InvoicePurchaseReportDto invoicePurchaseReportDto);
-
-    IPage<VatDto> listVat(Page page,String month);
-}
diff --git a/src/main/java/com/ruoyi/purchase/service/IPaymentRegistrationService.java b/src/main/java/com/ruoyi/purchase/service/IPaymentRegistrationService.java
deleted file mode 100644
index 88052fa..0000000
--- a/src/main/java/com/ruoyi/purchase/service/IPaymentRegistrationService.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package com.ruoyi.purchase.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.purchase.dto.PaymentHistoryRecordVo;
-import com.ruoyi.purchase.dto.PaymentLedgerDto;
-import com.ruoyi.purchase.dto.PaymentRegistrationDto;
-import com.ruoyi.purchase.pojo.PaymentRegistration;
-
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 浠樻鐧昏Service鎺ュ彛
- *
- * @author ruoyi
- * @date 2025-05-15
- */
-public interface IPaymentRegistrationService extends IService<PaymentRegistration> {
-    /**
-     * 鏌ヨ浠樻鐧昏
-     *
-     * @param id 浠樻鐧昏涓婚敭
-     * @return 浠樻鐧昏
-     */
-    public PaymentRegistration selectPaymentRegistrationById(Long id);
-
-    /**
-     * 鏌ヨ浠樻鐧昏鍒楄〃
-     *
-     * @param paymentRegistrationDto 浠樻鐧昏
-     * @return 浠樻鐧昏闆嗗悎
-     */
-    public List<PaymentRegistrationDto> selectPaymentRegistrationList(PaymentRegistrationDto paymentRegistrationDto);
-
-    /**
-     * 鏂板浠樻鐧昏
-     *
-     * @param paymentRegistration 浠樻鐧昏
-     * @return 缁撴灉
-     */
-    public int insertPaymentRegistration(List<PaymentRegistration>  paymentRegistration);
-
-    /**
-     * 淇敼浠樻鐧昏
-     *
-     * @param paymentRegistration 浠樻鐧昏
-     * @return 缁撴灉
-     */
-    public int updatePaymentRegistration(PaymentRegistration paymentRegistration);
-
-    /**
-     * 鎵归噺鍒犻櫎浠樻鐧昏
-     *
-     * @param ids 闇�瑕佸垹闄ょ殑浠樻鐧昏涓婚敭闆嗗悎
-     * @return 缁撴灉
-     */
-    public int deletePaymentRegistrationByIds(Long[] ids);
-
-    /**
-     * 閫氳繃閲囪喘鍚堝悓鍙锋煡璇㈤攢鍞悎鍚屽彿锛屼緵搴斿晢鍚嶇О锛屽彂绁ㄥ彿锛屽彂绁ㄩ噾棰濓紝绋庣巼
-     *
-     * @param purchaseId 閲囪喘鍚堝悓id
-     * @return 缁撴灉
-     */
-    PaymentRegistration selectPaymentRegistrationByPurchaseId(Long purchaseId);
-
-    IPage<Map<String, Object>> selectPaymentLedgerList(PaymentLedgerDto paymentLedgerDto, Page page,
-                                                       Integer detailPageNum,
-                                                       Integer detailPageSize);
-
-    Map<String, BigDecimal> paymentMonthList();
-
-    /**
-     * 鏌ヨ浠樻鐧昏鍒楄〃
-     *
-     * @param paymentRegistrationDto 浠樻鐧昏
-     * @return 浠樻鐧昏闆嗗悎
-     */
-    public List<PaymentRegistrationDto> paymentHistoryList(PaymentRegistrationDto paymentRegistrationDto);
-
-    /**
-     * 鏌ヨ渚涘簲鍟嗗線鏉ヨ褰�
-     * @param supplierId
-     * @return
-     */
-    List<PaymentHistoryRecordVo> getPaymentRecordList(Long supplierId);
-
-    /**
-     * 鏌ヨ浠樻鐧昏鍒楄〃鍒嗛〉
-     *
-     * @param paymentRegistrationDto 浠樻鐧昏
-     * @return 浠樻鐧昏闆嗗悎
-     */
-    IPage<PaymentRegistrationDto> paymentHistoryListPage(Page page, PaymentRegistrationDto paymentRegistrationDto);
-
-    Boolean delete(Long[] ids);
-
-    int delPaymentRegistration(List<Long> ids);
-
-    IPage<PaymentRegistrationDto> supplierNameListPage(Page page, PaymentLedgerDto paymentLedgerDto);
-
-    List<PaymentRegistrationDto> supplierNameListPageDetails(PaymentLedgerDto paymentLedgerDto);
-}
diff --git a/src/main/java/com/ruoyi/purchase/service/IProductRecordService.java b/src/main/java/com/ruoyi/purchase/service/IProductRecordService.java
deleted file mode 100644
index 3ab3d32..0000000
--- a/src/main/java/com/ruoyi/purchase/service/IProductRecordService.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.ruoyi.purchase.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.purchase.dto.ProductRecordDto;
-import com.ruoyi.purchase.dto.TicketRegistrationDto;
-import com.ruoyi.purchase.pojo.ProductRecord;
-
-import java.util.List;
-
-/**
- * 閲囪喘鍙拌处浜у搧寮�绁ㄨ褰昐ervice鎺ュ彛
- *
- * @author ruoyi
- * @date 2025-05-23
- */
-public interface IProductRecordService extends IService<ProductRecord> {
-
-    List<ProductRecord> selectProductRecordList(TicketRegistrationDto ticketRegistrationDto);
-
-    IPage<ProductRecordDto> productRecordPage(Page page, TicketRegistrationDto ticketRegistrationDto);
-
-    AjaxResult updateRecord(ProductRecordDto productRecordDto);
-
-    ProductRecordDto getProductRecordById(ProductRecordDto productRecordDto);
-}
diff --git a/src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java b/src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
index d09050e..a0378af 100644
--- a/src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
+++ b/src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
@@ -6,7 +6,6 @@
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.purchase.dto.PurchaseLedgerDto;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -39,8 +38,6 @@
     PurchaseLedgerDto getPurchaseNoById(Long id);
 
     IPage<PurchaseLedgerDto> selectPurchaseLedgerListPage(IPage ipage, PurchaseLedgerDto purchaseLedger);
-
-    List<InvoiceRegistrationProduct> getProductBySalesNo(Long id);
 
     String getPurchaseNo();
 
diff --git a/src/main/java/com/ruoyi/purchase/service/ITicketRegistrationService.java b/src/main/java/com/ruoyi/purchase/service/ITicketRegistrationService.java
deleted file mode 100644
index 6c1cf5b..0000000
--- a/src/main/java/com/ruoyi/purchase/service/ITicketRegistrationService.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.ruoyi.purchase.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.purchase.dto.PaymentRegistrationDto;
-import com.ruoyi.purchase.dto.PurchaseLedgerDto;
-import com.ruoyi.purchase.dto.TicketRegistrationDto;
-import com.ruoyi.purchase.pojo.TicketRegistration;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * 鏉ョエ鐧昏Service鎺ュ彛
- *
- * @author ruoyi
- * @date 2025-05-13
- */
-public interface ITicketRegistrationService extends IService<TicketRegistration> {
-
-    List<TicketRegistration> selectTicketRegistrationList(TicketRegistration ticketRegistration);
-
-    int addOrUpdateRegistration(TicketRegistrationDto ticketRegistrationDto) throws IOException;
-
-    int delRegistration(Long[] ids);
-
-    TicketRegistrationDto getRegistrationById(TicketRegistrationDto ticketRegistrationDto);
-
-    List getTicketNo(TicketRegistrationDto ticketRegistrationDto);
-
-    IPage<TicketRegistration> selectTicketRegistrationListPage(Page page, TicketRegistration ticketRegistration);
-
-    PurchaseLedgerDto getPuargeById(Long id);
-
-    List<PaymentRegistrationDto> getPaymentRegistrationDtoById(Long id);
-}
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/InvoicePurchaseServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/InvoicePurchaseServiceImpl.java
deleted file mode 100644
index 8b76b1a..0000000
--- a/src/main/java/com/ruoyi/purchase/service/impl/InvoicePurchaseServiceImpl.java
+++ /dev/null
@@ -1,178 +0,0 @@
-package com.ruoyi.purchase.service.impl;
-
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.common.enums.FileNameType;
-import com.ruoyi.common.utils.bean.BeanUtils;
-import com.ruoyi.other.mapper.TempFileMapper;
-import com.ruoyi.project.system.domain.SysUser;
-import com.ruoyi.project.system.mapper.SysUserMapper;
-import com.ruoyi.purchase.dto.InvoicePurchaseDto;
-import com.ruoyi.purchase.dto.InvoicePurchaseReportDto;
-import com.ruoyi.purchase.dto.VatDto;
-import com.ruoyi.purchase.mapper.InvoicePurchaseMapper;
-import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
-import com.ruoyi.purchase.pojo.InvoicePurchase;
-import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.purchase.service.IInvoicePurchaseService;
-import com.ruoyi.sales.mapper.CommonFileMapper;
-import com.ruoyi.sales.pojo.CommonFile;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-
-import java.io.IOException;
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * 鍙戠エ淇℃伅Service涓氬姟灞傚鐞�
- *
- * @author ruoyi
- * @date 2025-05-14
- */
-@Service
-@RequiredArgsConstructor
-@Slf4j
-public class InvoicePurchaseServiceImpl extends ServiceImpl<InvoicePurchaseMapper, InvoicePurchase> implements IInvoicePurchaseService {
-
-    private final InvoicePurchaseMapper invoicePurchaseMapper;
-
-    private final PurchaseLedgerMapper purchaseLedgerMapper;
-
-    private final SysUserMapper userMapper;
-
-    private final CommonFileMapper commonFileMapper;
-
-
-
-    @Override
-    public List<InvoicePurchaseDto> selectInvoicePurchaseList(InvoicePurchaseDto invoicePurchaseDto) {
-        // 鏋勫缓鍙戠エ鏌ヨ鏉′欢
-        LambdaQueryWrapper<InvoicePurchase> queryWrapper = new LambdaQueryWrapper<>();
-        Optional.ofNullable(invoicePurchaseDto)
-                .ifPresent(dto -> {
-                    if (StringUtils.hasText(dto.getPurchaseContractNo())) {
-                        queryWrapper.like(InvoicePurchase::getPurchaseContractNo, dto.getPurchaseContractNo());
-                    }
-                    if (StringUtils.hasText(dto.getSupplierName())) {
-                        queryWrapper.like(InvoicePurchase::getSupplierName, dto.getSupplierName());
-                    }
-                    // 澶勭悊鏃ユ湡绫诲瀷瀛楁
-                    if (dto.getIssueDate() != null) {
-                        queryWrapper.eq(InvoicePurchase::getIssueDate,invoicePurchaseDto.getIssueDate());
-                    }
-                });
-
-        // 鏌ヨ鍙戠エ鍒楄〃
-        List<InvoicePurchase> invoiceList = invoicePurchaseMapper.selectList(queryWrapper);
-
-        // 濡傛灉娌℃湁鏌ヨ鍒板彂绁紝鐩存帴杩斿洖绌哄垪琛�
-        if (CollectionUtils.isEmpty(invoiceList)) {
-            return Collections.emptyList();
-        }
-
-        // 鎻愬彇鎵�鏈夊彂绁↖D
-        List<Long> invoiceIds = invoiceList.stream()
-                .map(InvoicePurchase::getId)
-                .collect(Collectors.toList());
-
-        // 鎵归噺鏌ヨ杩欎簺鍙戠エ鍏宠仈鐨勬枃浠朵俊鎭�
-        LambdaQueryWrapper<CommonFile> fileQueryWrapper = new LambdaQueryWrapper<>();
-        fileQueryWrapper.in(CommonFile::getCommonId, invoiceIds)
-                .eq(CommonFile::getType, FileNameType.INVOICE.getValue());
-        List<CommonFile> fileList = commonFileMapper.selectList(fileQueryWrapper);
-
-        // 灏嗘枃浠朵俊鎭槧灏勫埌瀵瑰簲鐨勫彂绁↖D
-        Map<Long, String> fileMap = fileList.stream()
-                .collect(Collectors.toMap(
-                        CommonFile::getCommonId,
-                        CommonFile::getName,
-                        (existing, replacement) -> existing // 濡傛灉鏈夊涓枃浠讹紝鍙栫涓�涓�
-                ));
-
-        // 灏嗘枃浠朵俊鎭缃埌鍙戠エDTO涓�
-        List<InvoicePurchaseDto> resultList = new ArrayList<>();
-        for (InvoicePurchase invoice : invoiceList) {
-            InvoicePurchaseDto dto = new InvoicePurchaseDto();
-            // 灏咺nvoicePurchase鐨勫睘鎬у鍒跺埌DTO
-            BeanUtils.copyProperties(invoice, dto);
-            // 璁剧疆鏂囦欢鍚嶏紝濡傛灉瀛樺湪鐨勮瘽
-            dto.setFileName(fileMap.getOrDefault(invoice.getId(), null));
-            resultList.add(dto);
-        }
-
-        return resultList;
-    }
-
-    @Override
-    public int delInvoice(Long[] ids) {
-        return invoicePurchaseMapper.deleteBatchIds(Arrays.asList(ids));
-    }
-
-    @Override
-    public int addOrUpdateInvoice(InvoicePurchaseDto invoicePurchaseDto) throws IOException {
-        int i;
-        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(invoicePurchaseDto.getPurchaseLedgerId());
-        InvoicePurchase invoicePurchase = new InvoicePurchase();
-        BeanUtils.copyProperties(invoicePurchaseDto, invoicePurchase);
-        invoicePurchase.setPurchaseContractNo(purchaseLedger.getPurchaseContractNumber());
-        invoicePurchase.setSalesContractNo(purchaseLedger.getSalesContractNo());
-        SysUser sysUser = userMapper.selectUserById(invoicePurchase.getIssUerId());
-        invoicePurchase.setIssUer(sysUser.getNickName());
-        invoicePurchase.setTenantId(purchaseLedger.getTenantId());
-        if (invoicePurchaseDto.getId() == null) {
-            i = invoicePurchaseMapper.insert(invoicePurchase);
-        } else {
-            i = invoicePurchaseMapper.updateById(invoicePurchase);
-        }
-
-        // 杩佺Щ涓存椂鏂囦欢鍒版寮忕洰褰�
-//        if (invoicePurchaseDto.getTempFileIds() != null && !invoicePurchaseDto.getTempFileIds().isEmpty()) {
-//            migrateTempFilesToFormal(invoicePurchase.getId(), invoicePurchaseDto.getTempFileIds());
-//        }
-
-        return i;
-    }
-
-    @Override
-    public InvoicePurchaseDto getInvoiceById(InvoicePurchaseDto invoicePurchaseDto) {
-        InvoicePurchase invoicePurchase = invoicePurchaseMapper.selectById(invoicePurchaseDto.getId());
-        InvoicePurchaseDto resultDto = new InvoicePurchaseDto();
-        BeanUtils.copyProperties(invoicePurchase, resultDto);
-
-        // 鏌ヨ涓婁紶鏂囦欢
-        LambdaQueryWrapper<CommonFile> commonFileLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        commonFileLambdaQueryWrapper.eq(CommonFile::getCommonId, invoicePurchaseDto.getId())
-                .eq(CommonFile::getType, FileNameType.INVOICE.getValue());
-        List<CommonFile> commonFiles = commonFileMapper.selectList(commonFileLambdaQueryWrapper);
-        resultDto.setCommonFiles(commonFiles);
-        return resultDto;
-    }
-
-    @Override
-    public List<InvoicePurchase> selectInvoicePurchaseLists(InvoicePurchase invoicePurchase) {
-        return invoicePurchaseMapper.selectList(new LambdaQueryWrapper<>());
-    }
-
-    @Override
-    public IPage<InvoicePurchaseReportDto> listPurchaseReport(Page page, InvoicePurchaseReportDto invoicePurchaseReportDto) {
-        // 澧炲�肩◣ = 閿�鍞殑锛堝惈绋庢�讳环-涓嶅惈绋庢�讳环锛夊噺鍘婚噰璐殑锛堝惈绋庢�讳环-涓嶅惈绋庢�讳环锛�
-        return invoicePurchaseMapper.selectPurchaseReport(page, invoicePurchaseReportDto);
-    }
-
-    @Override
-    public IPage<VatDto> listVat(Page page, String month) {
-        IPage<VatDto> vatDtos = invoicePurchaseMapper.listVat(page,month);
-        vatDtos.getRecords().forEach(vatDto -> {
-            vatDto.setTaxAmount(vatDto.getJTaxAmount().subtract(vatDto.getXTaxAmount()));
-        });
-        return vatDtos;
-    }
-}
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PaymentRegistrationServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PaymentRegistrationServiceImpl.java
deleted file mode 100644
index d5875e3..0000000
--- a/src/main/java/com/ruoyi/purchase/service/impl/PaymentRegistrationServiceImpl.java
+++ /dev/null
@@ -1,564 +0,0 @@
-package com.ruoyi.purchase.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.account.pojo.AccountExpense;
-import com.ruoyi.account.service.AccountExpenseService;
-import com.ruoyi.basic.mapper.SupplierManageMapper;
-import com.ruoyi.basic.pojo.SupplierManage;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.framework.security.LoginUser;
-import com.ruoyi.purchase.dto.PaymentHistoryRecordVo;
-import com.ruoyi.purchase.dto.PaymentLedgerDto;
-import com.ruoyi.purchase.dto.PaymentRegistrationDto;
-import com.ruoyi.purchase.mapper.PaymentRegistrationMapper;
-import com.ruoyi.purchase.mapper.ProductRecordMapper;
-import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
-import com.ruoyi.purchase.mapper.TicketRegistrationMapper;
-import com.ruoyi.purchase.pojo.PaymentRegistration;
-import com.ruoyi.purchase.pojo.ProductRecord;
-import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.purchase.pojo.TicketRegistration;
-import com.ruoyi.purchase.service.IPaymentRegistrationService;
-import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
-import org.springframework.util.ObjectUtils;
-import org.springframework.util.StringUtils;
-
-import java.math.BigDecimal;
-import java.text.SimpleDateFormat;
-import java.time.LocalDate;
-import java.time.YearMonth;
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * 浠樻鐧昏Service涓氬姟灞傚鐞�
- *
- * @author ruoyi
- * @date 2025-05-15
- */
-@Service
-@RequiredArgsConstructor
-public class PaymentRegistrationServiceImpl extends ServiceImpl<PaymentRegistrationMapper, PaymentRegistration> implements IPaymentRegistrationService {
-
-    private final PaymentRegistrationMapper paymentRegistrationMapper;
-    private final PurchaseLedgerMapper purchaseLedgerMapper;
-    private final SupplierManageMapper supplierManageMapper;
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-    private final TicketRegistrationMapper ticketRegistrationMapper;
-    private final ProductRecordMapper productRecordMapper;
-    private final AccountExpenseService accountExpenseService;
-
-    /**
-     * 鏌ヨ浠樻鐧昏
-     *
-     * @param id 浠樻鐧昏涓婚敭
-     * @return 浠樻鐧昏
-     */
-    @Override
-    public PaymentRegistration selectPaymentRegistrationById(Long id) {
-        return paymentRegistrationMapper.selectPaymentRegistrationById(id);
-    }
-
-    /**
-     * 鏌ヨ浠樻鐧昏鍒楄〃
-     *
-     * @param paymentRegistrationDto 浠樻鐧昏
-     * @return 浠樻鐧昏
-     */
-    @Override
-    public List<PaymentRegistrationDto> selectPaymentRegistrationList(PaymentRegistrationDto paymentRegistrationDto) {
-        List<PaymentRegistrationDto> list = paymentRegistrationMapper.selectPaymentRegistrationList(paymentRegistrationDto);
-        for (PaymentRegistrationDto registrationDto : list) {
-            List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper.selectList(new QueryWrapper<PaymentRegistration>()
-                    .eq("ticket_registration_id", registrationDto.getTicketRegistrationId()));
-            BigDecimal total = paymentRegistrations.stream().map(PaymentRegistration::getCurrentPaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
-            BigDecimal invoiceAmount = (null != registrationDto.getInvoiceAmount())? registrationDto.getInvoiceAmount() : BigDecimal.ZERO;
-            registrationDto.setUnPaymentAmount(invoiceAmount.subtract(total));
-        }
-        return list;
-    }
-
-    /**
-     * 鏂板浠樻鐧昏
-     *
-     * @param paymentRegistrationList 浠樻鐧昏
-     * @return 缁撴灉
-     */
-    @Override
-    public int insertPaymentRegistration(List<PaymentRegistration> paymentRegistrationList) {
-        LoginUser userId = SecurityUtils.getLoginUser();
-        for (PaymentRegistration paymentRegistration : paymentRegistrationList) {
-            PaymentRegistration byId = paymentRegistration;
-            if (!ObjectUtils.isEmpty(paymentRegistration.getId())){
-                paymentRegistration = this.getById(paymentRegistration.getId());
-            }
-            PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(paymentRegistration.getPurchaseLedgerId());
-            if(null==purchaseLedger) throw new RuntimeException("鏈壘鍒伴噰璐崟");
-            // 宸插洖娆鹃噾棰�
-            SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(paymentRegistration.getSalesLedgerProductId());
-            if(null==salesLedgerProduct) throw new RuntimeException("鏈壘鍒伴噰璐崟浜у搧");
-            if (salesLedgerProduct.getPendingTicketsTotal().compareTo(paymentRegistration.getCurrentPaymentAmount())<0){
-                throw new RuntimeException("鏈鍥炴閲戦涓嶈兘澶т簬寰呭洖娆鹃噾棰�");
-            }
-            paymentRegistration.setCreateTime(DateUtils.getNowDate());
-            paymentRegistration.setUpdateTime(DateUtils.getNowDate());
-            paymentRegistration.setRegistrantId(userId.getUserId());
-            salesLedgerProduct.setTicketsTotal(salesLedgerProduct.getTicketsTotal().add(paymentRegistration.getCurrentPaymentAmount()));
-            salesLedgerProduct.setPendingTicketsTotal(salesLedgerProduct.getTaxInclusiveTotalPrice().subtract(salesLedgerProduct.getTicketsTotal()));
-            paymentRegistrationMapper.insert(paymentRegistration);
-            salesLedgerProductMapper.updateById(salesLedgerProduct);
-            // 2. 澶勭悊璐︽埛鏀嚭
-            AccountExpense accountExpense = new AccountExpense();
-            accountExpense.setExpenseDate(purchaseLedger.getEntryDate());
-            accountExpense.setExpenseType("4");
-            accountExpense.setSupplierName(purchaseLedger.getSupplierName());
-            accountExpense.setExpenseMoney(paymentRegistration.getCurrentPaymentAmount());
-            accountExpense.setExpenseDescribed("浠樻鏀嚭");
-
-            accountExpense.setExpenseMethod(paymentRegistration.getPaymentMethod());
-            accountExpense.setBusinessId(paymentRegistration.getId());
-            accountExpense.setBusinessType(1);
-            accountExpense.setInputTime(new Date());
-            accountExpense.setInputUser(userId.getNickName());
-            accountExpenseService.save(accountExpense);
-        }
-        return 1;
-
-    }
-
-    /**
-     * 淇敼浠樻鐧昏
-     *
-     * @param paymentRegistration 浠樻鐧昏
-     * @return 缁撴灉
-     */
-    @Override
-    public int updatePaymentRegistration(PaymentRegistration paymentRegistration) {
-        PaymentRegistration paymentRegistration1 = paymentRegistrationMapper.selectById(paymentRegistration.getId());
-        if(null==paymentRegistration1) throw new RuntimeException("鏈壘鍒颁粯娆剧櫥璁�");
-        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(paymentRegistration1.getSalesLedgerProductId());
-        if(null==salesLedgerProduct) throw new RuntimeException("鏈壘鍒伴噰璐崟浜у搧");
-        // 鍒ゆ柇浠樻閲戦涓嶅彲澶т簬寰呬粯娆鹃噾棰�
-        BigDecimal subtract = paymentRegistration.getCurrentPaymentAmount().subtract(paymentRegistration1.getCurrentPaymentAmount());
-        if (subtract.compareTo(salesLedgerProduct.getPendingTicketsTotal()) > 0) {
-            throw new RuntimeException("浠樻閲戦瓒呭嚭寰呬粯娆鹃噾棰�");
-        }
-        paymentRegistration.setUpdateTime(DateUtils.getNowDate());
-        // 鍚屾淇敼璐︽埛鏀嚭
-        LambdaQueryWrapper<AccountExpense> accountExpenseLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        accountExpenseLambdaQueryWrapper.eq(AccountExpense::getBusinessId, paymentRegistration.getId())
-                .eq(AccountExpense::getBusinessType, 1)
-                .last("limit 1");
-        AccountExpense accountExpense = accountExpenseService.getOne(accountExpenseLambdaQueryWrapper);
-        if(null!=accountExpense){
-            accountExpense.setExpenseMoney(paymentRegistration.getCurrentPaymentAmount());
-            accountExpenseService.updateById(accountExpense);
-        }
-        // 淇敼閲囪喘浜у搧浠樻閲戦
-        salesLedgerProduct.setTicketsTotal(salesLedgerProduct.getTicketsTotal().add(subtract));
-        salesLedgerProduct.setPendingTicketsTotal(salesLedgerProduct.getTaxInclusiveTotalPrice().subtract(salesLedgerProduct.getTicketsTotal()));
-        salesLedgerProductMapper.updateById(salesLedgerProduct);
-        return paymentRegistrationMapper.updateById(paymentRegistration);
-    }
-
-    /**
-     * 鎵归噺鍒犻櫎浠樻鐧昏
-     *
-     * @param ids 闇�瑕佸垹闄ょ殑浠樻鐧昏涓婚敭
-     * @return 缁撴灉
-     */
-    @Override
-    public int deletePaymentRegistrationByIds(Long[] ids) {
-        return paymentRegistrationMapper.delete(new QueryWrapper<PaymentRegistration>().in("id", ids));
-    }
-
-    @Override
-    public PaymentRegistration selectPaymentRegistrationByPurchaseId(Long id) {
-        PaymentRegistrationDto paymentRegistrationDto = new PaymentRegistrationDto();
-        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(id);
-        paymentRegistrationDto.setSalesContractNo(purchaseLedger.getSalesContractNo());
-        paymentRegistrationDto.setSupplierName(purchaseLedger.getSupplierName());
-        paymentRegistrationDto.setSupplierId(purchaseLedger.getSupplierId());
-
-        List<TicketRegistration> ticketRegistrations = ticketRegistrationMapper.selectList(new QueryWrapper<TicketRegistration>()
-                .eq("purchase_contract_number", purchaseLedger.getPurchaseContractNumber()));
-        if (ticketRegistrations != null && ticketRegistrations.size() > 0) {
-            paymentRegistrationDto.setInvoiceNumber(ticketRegistrations.get(0).getInvoiceNumber());
-            paymentRegistrationDto.setInvoiceAmount(ticketRegistrations.get(0).getInvoiceAmount());
-        }
-        return paymentRegistrationDto;
-    }
-
-    @Override
-    public IPage<Map<String, Object>> selectPaymentLedgerList(
-            PaymentLedgerDto paymentLedgerDto,
-            Page page,
-            Integer detailPageNum,
-            Integer detailPageSize) {
-        LambdaQueryWrapper<SupplierManage> queryWrapper = new LambdaQueryWrapper<>();
-        Optional.ofNullable(paymentLedgerDto)
-                .ifPresent(dto -> {
-                    if (StringUtils.hasText(dto.getSupplierName())) {
-                        queryWrapper.like(SupplierManage::getSupplierName, dto.getSupplierName());
-                    }
-                });
-
-        IPage<SupplierManage> supplierPage = supplierManageMapper.selectPage(page, queryWrapper);
-        List<SupplierManage> supplierManages = supplierPage.getRecords();
-
-        IPage<Map<String, Object>> resultPage = new Page<>(page.getCurrent(), page.getSize(), supplierPage.getTotal());
-        List<Map<String, Object>> result = new ArrayList<>();
-
-        for (SupplierManage supplierManage : supplierManages) {
-            Map<String, Object> res = new HashMap<>();
-            res.put("supplierName", supplierManage.getSupplierName());
-            res.put("supplierId", supplierManage.getId());
-
-            // 搴斾粯閲戦璁$畻
-            BigDecimal payableAmount = BigDecimal.ZERO;
-            List<PurchaseLedger> purchaseLedgers = purchaseLedgerMapper.selectList(
-                    new QueryWrapper<PurchaseLedger>().eq("supplier_id", supplierManage.getId())
-            );
-            List<SalesLedgerProduct> salesLedgerProducts = purchaseLedgers.stream()
-                    .filter(Objects::nonNull)
-                    .map(PurchaseLedger::getId)
-                    .filter(Objects::nonNull)
-                    .flatMap(id -> salesLedgerProductMapper.selectList(
-                            new QueryWrapper<SalesLedgerProduct>().eq("sales_ledger_id", id).eq("type",2)
-                    ).stream())
-                    .collect(Collectors.toList());
-            payableAmount = salesLedgerProducts.stream()
-                    .map(SalesLedgerProduct::getTaxInclusiveTotalPrice)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-            // 鏉ョエ閲戦璁$畻
-            List<TicketRegistration> ticketRegistrations = purchaseLedgers.stream()
-                    .map(PurchaseLedger::getId)
-                    .filter(Objects::nonNull)
-                    .map(id -> ticketRegistrationMapper.selectList(
-                            new LambdaQueryWrapper<TicketRegistration>().eq(TicketRegistration::getPurchaseLedgerId, id)
-                    ))
-                    .flatMap(Collection::stream)
-                    .collect(Collectors.toList());
-            BigDecimal invoiceAmount = ticketRegistrations.stream()
-                    .map(TicketRegistration::getInvoiceAmount)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-            // 浠樻璁板綍鍙婅鎯呭垎椤�
-            List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper.selectList(
-                    new QueryWrapper<PaymentRegistration>().eq("supplier_id", supplierManage.getId())
-            );
-            BigDecimal paymentAmount = paymentRegistrations.stream()
-                    .map(PaymentRegistration::getCurrentPaymentAmount)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-            // 璇︽儏鍒嗛〉澶勭悊
-            detailPageNum = detailPageNum != null ? detailPageNum : 1;
-            detailPageSize = detailPageSize != null ? detailPageSize : paymentRegistrations.size(); // 榛樿鏄剧ず鍏ㄩ儴
-            int totalDetails = paymentRegistrations.size();
-            int start = (detailPageNum - 1) * detailPageSize;
-            int end = Math.min(start + detailPageSize, totalDetails);
-            List<PaymentRegistration> pagedDetails = paymentRegistrations.subList(start, end);
-
-            // 鏋勫缓璇︽儏鍒楄〃
-            List<Map<String, Object>> details = pagedDetails.stream()
-                    .filter(Objects::nonNull)
-                    .map(pr -> {
-                        Map<String, Object> detail = new HashMap<>();
-                        detail.put("paymentAmount", pr.getCurrentPaymentAmount());
-
-                        // 鎵归噺鏌ヨ TicketRegistration锛堥伩鍏� N+1锛�
-                        TicketRegistration ticketRegistration = ticketRegistrationMapper.selectById(pr.getTicketRegistrationId());
-                        if (ticketRegistration != null) {
-                            detail.put("payableAmount", ticketRegistration.getInvoiceAmount());
-                            BigDecimal voteCount = productRecordMapper.selectList(
-                                            new LambdaQueryWrapper<ProductRecord>().eq(ProductRecord::getTicketRegistrationId, ticketRegistration.getId())
-                                    ).stream()
-                                    .map(ProductRecord::getTicketsNum)
-                                    .filter(Objects::nonNull)
-                                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-                            detail.put("voteCount", voteCount);
-                        }
-
-                        // 鏃ユ湡鏍煎紡鍖栵紙寤鸿浣跨敤 LocalDateTime锛�
-                        if (pr.getPaymentDate() != null) {
-                            detail.put("paymentDate", new SimpleDateFormat("yyyy-MM-dd").format(pr.getPaymentDate()));
-                        }
-                        return detail;
-                    })
-                    .collect(Collectors.toList());
-
-            // 灏佽璇︽儏鍒嗛〉鍏冩暟鎹�
-            Map<String, Object> detailPagination = new HashMap<>();
-            detailPagination.put("total", totalDetails);
-            detailPagination.put("pageNum", detailPageNum);
-            detailPagination.put("pageSize", detailPageSize);
-            detailPagination.put("pages", (int) Math.ceil((double) totalDetails / detailPageSize));
-
-            // 搴斾粯閲戦閫昏緫涓嶉噰鐢ㄥ悎鍚岄噾棰濇敼鎴�  鍙戠エ閲戦鍑忎粯娆鹃噾棰�
-            payableAmount = invoiceAmount.subtract(paymentAmount);
-            res.put("invoiceAmount", invoiceAmount);
-            res.put("payableAmount", payableAmount);
-            res.put("paymentAmount", paymentAmount);
-            res.put("details", details);
-            res.put("detailPagination", detailPagination); // 娣诲姞璇︽儏鍒嗛〉淇℃伅
-            result.add(res);
-        }
-
-        resultPage.setRecords(result);
-        return resultPage;
-    }
-
-    @Override
-    public Map<String, BigDecimal> paymentMonthList() {
-
-        // 鏌ヨ渚涘簲鍟嗗垪琛�
-        List<SupplierManage> suppliers = supplierManageMapper.selectList(null);
-        if (CollectionUtils.isEmpty(suppliers)) {
-            Map<String, BigDecimal> result = new HashMap<>();
-            result.put("payableAmount", BigDecimal.ZERO);
-            result.put("paymentAmount", BigDecimal.ZERO);
-            return result;
-        }
-
-        // 鎻愬彇鎵�鏈変緵搴斿晢ID
-        List<Long> supplierIds = suppliers.stream()
-                .map(SupplierManage::getId) // 鍏堣幏鍙朓nteger绫诲瀷鐨処D
-                .filter(Objects::nonNull)    // 杩囨护鎺夊彲鑳界殑null鍊�
-                .collect(Collectors.toList());
-
-        // 鑾峰彇褰撴湀鐨勫紑濮嬪拰缁撴潫鏃ユ湡
-        YearMonth currentMonth = YearMonth.now();
-        LocalDate startDate = currentMonth.atDay(1);
-        LocalDate endDate = currentMonth.atEndOfMonth();
-
-        // 鎵归噺鏌ヨ閲囪喘鍙拌处锛堝綋鏈堬級
-        Map<Long, List<PurchaseLedger>> purchaseLedgerMap = batchQueryPurchaseLedgers(supplierIds, startDate, endDate);
-
-        // 鎵归噺鏌ヨ閿�鍞彴璐︿骇鍝�
-        Map<Long, List<SalesLedgerProduct>> salesLedgerProductMap = batchQuerySalesLedgerProducts(purchaseLedgerMap);
-
-        // 鎵归噺鏌ヨ浠樻璁板綍锛堝綋鏈堬級
-        Map<Long, List<PaymentRegistration>> paymentRegistrationMap = batchQueryPaymentRegistrations(supplierIds, startDate, endDate);
-
-        // 璁$畻搴斾粯閲戦鍜屼粯娆鹃噾棰�
-        BigDecimal totalPayableAmount = calculateTotalPayableAmount(purchaseLedgerMap, salesLedgerProductMap);
-        BigDecimal totalPaymentAmount = calculateTotalPaymentAmount(paymentRegistrationMap);
-
-        // 鏋勫缓缁撴灉
-        Map<String, BigDecimal> result = new HashMap<>();
-        result.put("payableAmount", totalPayableAmount);
-        result.put("paymentAmount", totalPaymentAmount);
-        return result;
-    }
-
-    /**
-     * 鏌ヨ浠樻鐧昏鍒楄〃
-     *
-     * @param paymentRegistrationDto 浠樻鐧昏
-     * @return 浠樻鐧昏闆嗗悎
-     */
-    @Override
-    public List<PaymentRegistrationDto> paymentHistoryList(PaymentRegistrationDto paymentRegistrationDto) {
-        return paymentRegistrationMapper.paymentHistoryList(paymentRegistrationDto);
-    }
-
-    /**
-     * 鏌ヨ渚涘簲鍟嗗線鏉ヨ褰�
-     * @param supplierId
-     * @return
-     */
-    @Override
-    public List<PaymentHistoryRecordVo> getPaymentRecordList(Long supplierId) {
-        List<PaymentHistoryRecordVo> paymentRecordList = paymentRegistrationMapper.getPaymentRecordList(supplierId);
-        List<PaymentHistoryRecordVo> result = new ArrayList<>();
-        List<PaymentHistoryRecordVo> newResult = new ArrayList<>();
-        // 搴斾粯鎬婚噾棰濋噾棰濊绠�
-        BigDecimal amountTotal = BigDecimal.ZERO;
-        if(CollectionUtils.isNotEmpty(paymentRecordList)) {
-            Map<LocalDate, List<PaymentHistoryRecordVo>> dateListMap = paymentRecordList.stream().collect(
-                                                                        Collectors.groupingBy(
-                                                                                PaymentHistoryRecordVo::getHappenTime,
-                                                                                LinkedHashMap::new,
-                                                                                Collectors.toList()
-                                                                        )
-                                                                        );
-            for (LocalDate localDate : dateListMap.keySet()) {
-                BigDecimal currentPaymentAmount = BigDecimal.ZERO;
-                BigDecimal invoiceAmount = BigDecimal.ZERO;
-                BigDecimal currentDateTotal = BigDecimal.ZERO;
-                List<PaymentHistoryRecordVo> paymentHistoryRecordVos = dateListMap.get(localDate);
-                // 璁$畻褰撳ぉ姹囨鏁�
-                currentPaymentAmount = paymentHistoryRecordVos.stream()
-                                            .filter(item ->item.getType() == 0)
-                                            .map(PaymentHistoryRecordVo::getCurrentPaymentAmount)
-                                            .reduce(BigDecimal.ZERO,BigDecimal::add);
-                // 璁$畻浠婂ぉ鏉ョエ鏁�
-                invoiceAmount = paymentHistoryRecordVos.stream()
-                        .filter(item ->item.getType() == 1)
-                        .map(PaymentHistoryRecordVo::getInvoiceAmount)
-                        .reduce(BigDecimal.ZERO,BigDecimal::add);
-                // 璁$畻褰撴棩姹囨��
-                currentDateTotal = currentDateTotal.add(invoiceAmount).subtract(currentPaymentAmount);
-                PaymentHistoryRecordVo paymentHistoryRecordVo = new PaymentHistoryRecordVo();
-                paymentHistoryRecordVo.setHappenTime(localDate);
-                paymentHistoryRecordVo.setCurrentPaymentAmount(currentPaymentAmount);
-                paymentHistoryRecordVo.setInvoiceAmount(invoiceAmount);
-                amountTotal = paymentHistoryRecordVo.getInvoiceAmount().subtract(paymentHistoryRecordVo.getCurrentPaymentAmount());
-                paymentHistoryRecordVo.setPayableAmount(amountTotal);
-                result.add(paymentHistoryRecordVo);
-            }
-
-
-            for (int i = 0; i < result.size(); i++) {
-                PaymentHistoryRecordVo paymentHistoryRecordVo = result.get(i);
-                if (i == 0) {
-                    paymentHistoryRecordVo.setPayableAmount(paymentHistoryRecordVo.getInvoiceAmount().subtract(paymentHistoryRecordVo.getCurrentPaymentAmount()));
-                }else {
-                    PaymentHistoryRecordVo paymentHistoryRecordVo1 = result.get(i-1);
-                    paymentHistoryRecordVo.setPayableAmount(paymentHistoryRecordVo1.getPayableAmount()
-                            .add(paymentHistoryRecordVo.getInvoiceAmount()).subtract(paymentHistoryRecordVo.getCurrentPaymentAmount()));
-                }
-                newResult.add(paymentHistoryRecordVo);
-            }
-        }
-        return newResult;
-    }
-
-    /**
-     * 鏌ヨ浠樻鐧昏鍒楄〃鍒嗛〉
-     *
-     * @param paymentRegistrationDto 浠樻鐧昏
-     * @return 浠樻鐧昏闆嗗悎
-     */
-    @Override
-    public IPage<PaymentRegistrationDto> paymentHistoryListPage(Page page, PaymentRegistrationDto paymentRegistrationDto) {
-        return paymentRegistrationMapper.paymentHistoryListPage(page, paymentRegistrationDto);
-    }
-
-    @Override
-    public Boolean delete(Long[] ids) {
-        for (Long id : ids) {
-            List<ProductRecord> productRecords = productRecordMapper.selectList(new QueryWrapper<ProductRecord>().lambda().eq(ProductRecord::getTicketRegistrationId, id));
-            for (ProductRecord productRecord : productRecords) {
-                SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(productRecord.getSaleLedgerProjectId());
-                salesLedgerProduct.setTicketsNum(salesLedgerProduct.getTicketsNum().subtract(productRecord.getTicketsNum()));
-                salesLedgerProduct.setTicketsAmount(salesLedgerProduct.getTicketsAmount().subtract(productRecord.getTicketsAmount()));
-                salesLedgerProduct.setFutureTickets(salesLedgerProduct.getFutureTickets().add(productRecord.getTicketsNum()));
-                salesLedgerProduct.setFutureTicketsAmount(salesLedgerProduct.getFutureTicketsAmount().add(productRecord.getTicketsAmount()));
-                salesLedgerProductMapper.updateById(salesLedgerProduct);
-            }
-            ticketRegistrationMapper.delete(new QueryWrapper<TicketRegistration>().lambda().eq(TicketRegistration::getId, id));
-            productRecordMapper.delete(new QueryWrapper<ProductRecord>().lambda().eq(ProductRecord::getTicketRegistrationId, id));
-        }
-        return true;
-    }
-
-    @Override
-    public int delPaymentRegistration(List<Long> ids) {
-        LambdaQueryWrapper<AccountExpense> accountExpenseLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        accountExpenseLambdaQueryWrapper.in(AccountExpense::getBusinessId, ids)
-                .eq(AccountExpense::getBusinessType, 1);
-        accountExpenseService.remove(accountExpenseLambdaQueryWrapper);
-        // 淇敼閲囪喘浜у搧鐨勫凡浠樻閲戦,寰呬粯娆鹃噾棰�
-        List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper.selectBatchIds(ids);
-        for (PaymentRegistration paymentRegistration : paymentRegistrations) {
-            SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(paymentRegistration.getSalesLedgerProductId());
-            salesLedgerProduct.setTicketsTotal(salesLedgerProduct.getTicketsTotal().subtract(paymentRegistration.getCurrentPaymentAmount()));
-            salesLedgerProduct.setPendingTicketsTotal(salesLedgerProduct.getPendingTicketsTotal().add(paymentRegistration.getCurrentPaymentAmount()));
-            salesLedgerProductMapper.updateById(salesLedgerProduct);
-        }
-        return paymentRegistrationMapper.deleteBatchIds(ids);
-    }
-
-    @Override
-    public IPage<PaymentRegistrationDto> supplierNameListPage(Page page, PaymentLedgerDto paymentLedgerDto) {
-        return paymentRegistrationMapper.supplierNameListPage(page, paymentLedgerDto);
-    }
-
-    @Override
-    public List<PaymentRegistrationDto> supplierNameListPageDetails(PaymentLedgerDto paymentLedgerDto) {
-        return paymentRegistrationMapper.supplierNameListPageDetails(paymentLedgerDto);
-    }
-
-    // 鎵归噺鏌ヨ閲囪喘鍙拌处锛堝綋鏈堬級
-    private Map<Long, List<PurchaseLedger>> batchQueryPurchaseLedgers(List<Long> supplierIds, LocalDate startDate, LocalDate endDate) {
-        LambdaQueryWrapper<PurchaseLedger> query = new LambdaQueryWrapper<>();
-        query.in(PurchaseLedger::getSupplierId, supplierIds)
-                .ge(PurchaseLedger::getCreatedAt, startDate)
-                .le(PurchaseLedger::getCreatedAt, endDate);
-        List<PurchaseLedger> purchaseLedgers = purchaseLedgerMapper.selectList(query);
-
-        return purchaseLedgers.stream()
-                .filter(pl -> pl.getSupplierId() != null)
-                .collect(Collectors.groupingBy(PurchaseLedger::getSupplierId));
-    }
-
-    // 鎵归噺鏌ヨ閿�鍞彴璐︿骇鍝�
-    private Map<Long, List<SalesLedgerProduct>> batchQuerySalesLedgerProducts(Map<Long, List<PurchaseLedger>> purchaseLedgerMap) {
-        // 鎻愬彇鎵�鏈夐噰璐彴璐D
-        List<Long> purchaseLedgerIds = purchaseLedgerMap.values().stream()
-                .flatMap(Collection::stream)
-                .map(PurchaseLedger::getId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toList());
-
-        if (purchaseLedgerIds.isEmpty()) {
-            return Collections.emptyMap();
-        }
-
-        LambdaQueryWrapper<SalesLedgerProduct> query = new LambdaQueryWrapper<>();
-        query.in(SalesLedgerProduct::getSalesLedgerId, purchaseLedgerIds);
-        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(query);
-
-        return products.stream()
-                .filter(slp -> slp.getSalesLedgerId() != null)
-                .collect(Collectors.groupingBy(SalesLedgerProduct::getSalesLedgerId));
-    }
-
-    // 鎵归噺鏌ヨ浠樻璁板綍锛堝綋鏈堬級
-    private Map<Long, List<PaymentRegistration>> batchQueryPaymentRegistrations(List<Long> supplierIds, LocalDate startDate, LocalDate endDate) {
-        LambdaQueryWrapper<PaymentRegistration> query = new LambdaQueryWrapper<>();
-        query.in(PaymentRegistration::getSupplierId, supplierIds)
-                .ge(PaymentRegistration::getPaymentDate, startDate)
-                .le(PaymentRegistration::getPaymentDate, endDate);
-        List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper.selectList(query);
-
-        return paymentRegistrations.stream()
-                .filter(pr -> pr.getSupplierId() != null)
-                .collect(Collectors.groupingBy(PaymentRegistration::getSupplierId));
-    }
-
-    // 璁$畻鎬诲簲浠橀噾棰�
-    private BigDecimal calculateTotalPayableAmount(Map<Long, List<PurchaseLedger>> purchaseLedgerMap,
-                                                   Map<Long, List<SalesLedgerProduct>> salesLedgerProductMap) {
-        return purchaseLedgerMap.values().stream()
-                .flatMap(Collection::stream)
-                .map(pl -> salesLedgerProductMap.getOrDefault(pl.getId(), Collections.emptyList()))
-                .flatMap(Collection::stream)
-                .map(SalesLedgerProduct::getTaxInclusiveTotalPrice)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-    }
-
-    // 璁$畻鎬讳粯娆鹃噾棰�
-    private BigDecimal calculateTotalPaymentAmount(Map<Long, List<PaymentRegistration>> paymentRegistrationMap) {
-        return paymentRegistrationMap.values().stream()
-                .flatMap(Collection::stream)
-                .map(PaymentRegistration::getCurrentPaymentAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-    }
-}
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java
deleted file mode 100644
index 961e759..0000000
--- a/src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package com.ruoyi.purchase.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.common.enums.FileNameType;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.purchase.dto.ProductRecordDto;
-import com.ruoyi.purchase.dto.TicketRegistrationDto;
-import com.ruoyi.purchase.mapper.ProductRecordMapper;
-import com.ruoyi.purchase.mapper.TicketRegistrationMapper;
-import com.ruoyi.purchase.pojo.ProductRecord;
-import com.ruoyi.purchase.pojo.TicketRegistration;
-import com.ruoyi.purchase.service.IProductRecordService;
-import com.ruoyi.sales.mapper.CommonFileMapper;
-import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.pojo.CommonFile;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import lombok.RequiredArgsConstructor;
-import org.springframework.beans.BeanUtils;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * 閲囪喘鍙拌处浜у搧寮�绁ㄨ褰昐ervice涓氬姟灞傚鐞�
- *
- * @author ruoyi
- * @date 2025-05-23
- */
-@Service
-@RequiredArgsConstructor
-public class ProductRecordServiceImpl extends ServiceImpl<ProductRecordMapper, ProductRecord> implements IProductRecordService {
-
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-    private final ProductRecordMapper productRecordMapper;
-    private final CommonFileMapper commonFileMapper;
-    /**
-     * 鏌ヨ閲囪喘鍙拌处浜у搧寮�绁ㄨ褰�
-     *
-     * @param ticketRegistrationDto 閲囪喘鍙拌处浜у搧寮�绁ㄨ褰曚富閿�
-     * @return 閲囪喘鍙拌处浜у搧寮�绁ㄨ褰�
-     */
-    @Override
-    public List<ProductRecord> selectProductRecordList(TicketRegistrationDto ticketRegistrationDto) {
-        return productRecordMapper.selectList(new LambdaQueryWrapper<ProductRecord>().eq(ProductRecord::getTicketRegistrationId, ticketRegistrationDto.getId())
-                .eq(ProductRecord::getType, "2"));
-    }
-
-    @Override
-    public IPage<ProductRecordDto> productRecordPage(Page page, TicketRegistrationDto ticketRegistrationDto) {
-        IPage<ProductRecordDto> productRecordDtoIPage1 = productRecordMapper.productRecordPage(page, ticketRegistrationDto);
-        page.setSize(productRecordDtoIPage1.getTotal());
-        IPage<ProductRecordDto> productRecordDtoIPage = productRecordMapper.productRecordPage(page, ticketRegistrationDto);
-        productRecordDtoIPage.getRecords().forEach(productRecordDto -> {
-            productRecordDto.setCommonFiles(commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>().eq(CommonFile::getCommonId, productRecordDto.getId())
-                    .eq(CommonFile::getType, FileNameType.PURCHASELEDGER.getValue())));
-        });
-        return productRecordDtoIPage;
-    }
-
-    private final TicketRegistrationMapper ticketRegistrationMapper;
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public AjaxResult updateRecord(ProductRecordDto productRecordDto) {
-        ProductRecord productRecord = productRecordMapper.selectById(productRecordDto.getId());
-        if (productRecord == null) return AjaxResult.error("璁板綍涓嶅瓨鍦�");
-
-        //  鏇存柊浜у搧鍙拌处
-        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(productRecord.getSaleLedgerProjectId());
-        if (salesLedgerProduct != null) {
-            // 鏈潵绁ㄩ噾棰� = 鍘熸湭鏉ョエ閲戦 + 鏃ц閲戦 - 鏂拌閲戦
-            BigDecimal futureTicketsAmount = salesLedgerProduct.getFutureTicketsAmount()
-                    .add(productRecord.getTicketsAmount())
-                    .subtract(productRecordDto.getTicketsAmount());
-            salesLedgerProduct.setFutureTicketsAmount(futureTicketsAmount);
-
-            // 鏈潵绁ㄦ暟 = 鍘熸湭鏉ョエ鏁� + 鏃ц鏁伴噺 - 鏂拌鏁伴噺
-            BigDecimal futureTickets = salesLedgerProduct.getFutureTickets()
-                    .add(productRecord.getTicketsNum())
-                    .subtract(productRecordDto.getTicketsNum());
-            salesLedgerProduct.setFutureTickets(futureTickets);
-
-            // 鏇存柊浜у搧琛ㄦ湰娆℃暟鍊�
-            salesLedgerProduct.setTicketsAmount(productRecordDto.getTicketsAmount());
-            salesLedgerProduct.setTicketsNum(productRecordDto.getTicketsNum());
-            salesLedgerProductMapper.updateById(salesLedgerProduct);
-        }
-
-        //  鏇存柊鏉ョエ鐧昏
-        TicketRegistration ticketRegistration = ticketRegistrationMapper.selectById(productRecord.getTicketRegistrationId());
-        if (ticketRegistration != null) {
-            // 閲戦 = 鏂伴噾棰� - 鏃ч噾棰�
-            BigDecimal amountDiff = productRecordDto.getTicketsAmount().subtract(productRecord.getTicketsAmount());
-            // 鎬婚噾棰� = 鍘熸�婚噾棰� + 宸��
-            ticketRegistration.setInvoiceAmount(ticketRegistration.getInvoiceAmount().add(amountDiff));
-            // 鏇存柊鍙戠エ鍙�
-            ticketRegistration.setInvoiceNumber(productRecordDto.getInvoiceNumber());
-
-            ticketRegistrationMapper.updateById(ticketRegistration);
-        }
-
-        BeanUtils.copyProperties(productRecordDto, productRecord);
-        // 閲嶆柊璁$畻鏈潵绁ㄩ噾棰濓紙鏍规嵁鍓╀綑绁ㄦ暟 * 鍗曚环锛�
-        productRecord.setFutureTicketsAmount(productRecord.getFutureTickets().multiply(productRecord.getTaxInclusiveUnitPrice()));
-        productRecordMapper.updateById(productRecord);
-
-        return AjaxResult.success("淇敼鎴愬姛");
-    }
-
-    @Override
-    public ProductRecordDto getProductRecordById(ProductRecordDto productRecordDto) {
-        List<ProductRecordDto> productRecordDtoList = productRecordMapper.getProductRecordById(productRecordDto);
-        if (CollectionUtils.isNotEmpty(productRecordDtoList)) {
-            ProductRecordDto productRecordDto1 = productRecordDtoList.stream()
-                    .filter(item -> item.getId().equals(productRecordDto.getId()))
-                    .findFirst()
-                    .orElse(null);
-            // 杩囨护鍑轰笌浼犲叆鐨� productRecordDto 涓婚敭鐩稿悓鐨勮褰�
-            BigDecimal reduce = productRecordDtoList
-                    .stream()
-                    .filter(item -> item.getProductModelId().equals(productRecordDto.getProductModelId()))
-                    .map(ProductRecordDto::getTicketsNum)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-            if (productRecordDto1 != null) {
-                productRecordDto1.setFutureTickets(productRecordDto1.getQuantity().subtract(reduce));
-                productRecordDto1.setFutureTicketsAmount(productRecordDto1.getFutureTickets().multiply(productRecordDto1.getTaxInclusiveUnitPrice()));
-            }
-            return productRecordDto1;
-        }
-        return null;
-    }
-}
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
index 3afd306..c8b53b6 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -37,14 +37,8 @@
 import com.ruoyi.purchase.dto.PurchaseLedgerDto;
 import com.ruoyi.purchase.dto.PurchaseLedgerImportDto;
 import com.ruoyi.purchase.dto.PurchaseLedgerProductImportDto;
-import com.ruoyi.purchase.mapper.PaymentRegistrationMapper;
-import com.ruoyi.purchase.mapper.ProductRecordMapper;
 import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
-import com.ruoyi.purchase.mapper.TicketRegistrationMapper;
-import com.ruoyi.purchase.pojo.PaymentRegistration;
-import com.ruoyi.purchase.pojo.ProductRecord;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.purchase.pojo.TicketRegistration;
 import com.ruoyi.purchase.service.IPurchaseLedgerService;
 import com.ruoyi.quality.mapper.QualityInspectMapper;
 import com.ruoyi.quality.mapper.QualityInspectParamMapper;
@@ -55,11 +49,9 @@
 import com.ruoyi.quality.pojo.QualityTestStandard;
 import com.ruoyi.quality.pojo.QualityTestStandardParam;
 import com.ruoyi.sales.mapper.CommonFileMapper;
-import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper;
 import com.ruoyi.sales.mapper.SalesLedgerMapper;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
 import com.ruoyi.sales.pojo.CommonFile;
-import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
 import com.ruoyi.sales.pojo.SalesLedger;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
@@ -103,10 +95,6 @@
     private final ProductMapper productMapper;
     private final ProductModelMapper productModelMapper;
     private final SysUserMapper sysUserMapper;
-    private final TicketRegistrationMapper ticketRegistrationMapper;
-    private final ProductRecordMapper productRecordMapper;
-    private final PaymentRegistrationMapper paymentRegistrationMapper;
-    private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
     private final StringRedisTemplate redisTemplate;
     private final QualityInspectMapper qualityInspectMapper;
     private final CommonFileServiceImpl commonFileService;
@@ -303,9 +291,6 @@
 
                 LocalDateTime localDateTime = entryDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                 salesLedgerProduct.setRegisterDate(localDateTime);
-                salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity());
-                salesLedgerProduct.setFutureTicketsAmount(salesLedgerProduct.getTaxInclusiveTotalPrice());
-                salesLedgerProduct.setPendingTicketsTotal(salesLedgerProduct.getTaxInclusiveTotalPrice());
                 salesLedgerProductMapper.insert(salesLedgerProduct);
             }
         }
@@ -353,18 +338,6 @@
         queryWrapper.in(SalesLedgerProduct::getSalesLedgerId, ids)
                 .eq(SalesLedgerProduct::getType, 2);
         salesLedgerProductMapper.delete(queryWrapper);
-        // 鎵归噺鍒犻櫎鍏宠仈鐨勯噰璐彴璐︾殑鏉ョエ鐧昏
-        LambdaQueryWrapper<TicketRegistration> ticketRegistrationLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        ticketRegistrationLambdaQueryWrapper.in(TicketRegistration::getPurchaseLedgerId,ids);
-        ticketRegistrationMapper.delete(ticketRegistrationLambdaQueryWrapper);
-        // 鎵归噺鍒犻櫎鍏宠仈鐨勯噰璐彴璐︾殑鏉ョエ鐧昏璁板綍
-        LambdaQueryWrapper<ProductRecord> productRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        productRecordLambdaQueryWrapper.in(ProductRecord::getPurchaseLedgerId,ids);
-        productRecordMapper.delete(productRecordLambdaQueryWrapper);
-        // 鎵归噺鍒犻櫎浠樻鐧昏
-        LambdaQueryWrapper<PaymentRegistration> paymentRegistrationLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        paymentRegistrationLambdaQueryWrapper.in(PaymentRegistration::getPurchaseLedgerId, ids);
-        paymentRegistrationMapper.delete(paymentRegistrationLambdaQueryWrapper);
         //鎵归噺鍒犻櫎妫�楠屾爣鍑�
         LambdaQueryWrapper<QualityInspect> materialInspectLambdaQueryWrapper = new LambdaQueryWrapper<>();
         materialInspectLambdaQueryWrapper.in(QualityInspect::getPurchaseLedgerId, ids);
@@ -467,14 +440,6 @@
         queryWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId())
                 .eq(SalesLedgerProduct::getType, 2);
         List<SalesLedgerProduct> productList = salesLedgerProductMapper.selectList(queryWrapper);
-        productList.forEach(product -> {
-            product.setFutureTickets(product.getFutureTickets() != null ? product.getFutureTickets() : product.getQuantity());
-            product.setFutureTicketsAmount(product.getFutureTicketsAmount() != null ? product.getFutureTicketsAmount() : product.getTaxInclusiveTotalPrice());
-            product.setTicketsNum(null);
-            product.setTicketsAmount(null);
-            product.setTempFutureTickets(product.getFutureTickets());
-            product.setTempFutureTicketsAmount(product.getFutureTicketsAmount());
-        });
         resultDto.setProductData(productList);
         return resultDto;
     }
@@ -501,12 +466,6 @@
         PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(id);
 
         BeanUtils.copyProperties(purchaseLedger, purchaseLedgerDto);
-//        TicketRegistration ticketRegistration = ticketRegistrationMapper.selectOne(new LambdaQueryWrapper<TicketRegistration>().eq(TicketRegistration::getPurchaseLedgerId, id));
-//        if (ticketRegistration != null) {
-//            purchaseLedgerDto.setInvoiceNumber(ticketRegistration.getInvoiceNumber());
-//            purchaseLedgerDto.setInvoiceAmount(ticketRegistration.getInvoiceAmount());
-//            purchaseLedgerDto.setTicketRegistrationId(ticketRegistration.getId());
-//        }
         return purchaseLedgerDto;
     }
 
@@ -537,18 +496,6 @@
             records.forEach(dto -> dto.setSalesLedgerFiles(fileMap.getOrDefault(dto.getId(), new ArrayList<>())));
         }
         return purchaseLedgerDtoIPage;
-    }
-
-    @Override
-    public List<InvoiceRegistrationProduct> getProductBySalesNo(Long id) {
-        List<InvoiceRegistrationProduct> invoiceRegistrationProducts = invoiceRegistrationProductMapper.selectList(new LambdaQueryWrapper<InvoiceRegistrationProduct>()
-                .select(InvoiceRegistrationProduct::getId, InvoiceRegistrationProduct::getProductCategory, InvoiceRegistrationProduct::getSpecificationModel,
-                        InvoiceRegistrationProduct::getUnit, InvoiceRegistrationProduct::getQuantity)
-                .eq(InvoiceRegistrationProduct::getSalesLedgerId, id));
-        if (invoiceRegistrationProducts.isEmpty()) {
-            return new ArrayList<>();
-        }
-        return invoiceRegistrationProducts;
     }
 
     @Override
@@ -655,8 +602,6 @@
                     salesLedgerProduct.setType(2);
                     // 璁$畻涓嶅惈绋庢�讳环
                     salesLedgerProduct.setTaxExclusiveTotalPrice(salesLedgerProduct.getTaxInclusiveTotalPrice().divide(new BigDecimal(1).add(salesLedgerProduct.getTaxRate().divide(new BigDecimal(100))), 2, RoundingMode.HALF_UP));
-                    salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity());
-                    salesLedgerProduct.setFutureTicketsAmount(salesLedgerProduct.getTaxExclusiveTotalPrice());
                     list.stream()
                             .filter(map -> map.get("productName").equals(salesLedgerProduct.getProductCategory()) && map.get("model").equals(salesLedgerProduct.getSpecificationModel()))
                             .findFirst()
@@ -667,7 +612,6 @@
                     salesLedgerProduct.setRegister(loginUser.getNickName());
                     salesLedgerProduct.setRegisterDate(LocalDateTime.now());
                     salesLedgerProduct.setApproveStatus(0);
-                    salesLedgerProduct.setPendingTicketsTotal(salesLedgerProductImportDto.getTaxInclusiveTotalPrice());
                     // 鏄惁璐ㄦ鍒ゆ柇
                     salesLedgerProduct.setIsChecked(salesLedgerProductImportDto.getIsChecked() == 1);
                     if(salesLedgerProductImportDto.getIsChecked() == 1){
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java
index 24e3405..318c36d 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java
@@ -6,12 +6,7 @@
 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.account.pojo.AccountIncome;
-import com.ruoyi.account.service.AccountIncomeService;
 import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.framework.security.LoginUser;
 import com.ruoyi.procurementrecord.utils.StockUtils;
 import com.ruoyi.purchase.dto.PurchaseReturnOrderDto;
 import com.ruoyi.purchase.dto.PurchaseReturnOrderHasAllInfoDto;
@@ -29,13 +24,11 @@
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.service.ISalesLedgerService;
 import com.ruoyi.stock.mapper.StockOutRecordMapper;
-import com.ruoyi.stock.pojo.StockOutRecord;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
-import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -52,7 +45,6 @@
     private final PurchaseReturnOrdersMapper purchaseReturnOrdersMapper;
     private final PurchaseReturnOrderProductsMapper purchaseReturnOrderProductsMapper;
     private final ISalesLedgerService salesLedgerService;
-    private final AccountIncomeService accountIncomeService;
     private final StockUtils stockUtils;
     private final SalesLedgerProductMapper salesLedgerProductMapper;
     private final PurchaseLedgerMapper purchaseLedgerMapper;
@@ -84,21 +76,6 @@
         }else {
             throw new RuntimeException("璇烽�夋嫨閫�璐у晢鍝�");
         }
-
-        // 瀵硅储鍔$鐞嗗彴璐︽坊鍔犱竴绗旇繘璐︽敹鍏�.
-        AccountIncome accountIncome = new AccountIncome();
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        accountIncome.setInputUser(loginUser.getUsername());
-        accountIncome.setIncomeMoney(purchaseReturnOrderDto.getTotalAmount());
-        accountIncome.setIncomeDate(DateUtils.toDate(purchaseReturnOrderDto.getPreparedAt()));
-        accountIncome.setInputTime(DateUtils.toDate(purchaseReturnOrderDto.getPreparedAt()));
-        accountIncome.setBusinessId(purchaseReturnOrderDto.getId());
-        accountIncome.setBusinessType(1);
-        accountIncome.setIncomeType("4");
-        accountIncome.setCustomerName(purchaseReturnOrderDto.getSupplierName());
-        accountIncome.setIncomeDescribed(purchaseReturnOrderDto.getRemark());
-        accountIncome.setIncomeMethod(String.valueOf(purchaseReturnOrderDto.getIncomeType()));
-        accountIncomeService.save(accountIncome);
         return true;
     }
 
@@ -122,15 +99,9 @@
         updateWrapper.eq(PurchaseReturnOrderProducts::getPurchaseReturnOrderId, id);
         purchaseReturnOrderProductsMapper.delete(updateWrapper);
         //(閲囪喘閫�璐х殑鏁版嵁闇�瑕佸垹鎺�)
-        stockOutRecordMapper.delete(Wrappers.<StockOutRecord>lambdaQuery()
-                .eq(StockOutRecord::getRecordType,StockOutQualifiedRecordTypeEnum.PURCHASE_RETURN_STOCK_OUT.getCode())
-                .in(StockOutRecord::getRecordId, purchaseReturnOrderProducts.stream().map(PurchaseReturnOrderProducts::getId).collect(Collectors.toList())));
-        // 璐㈠姟
-        LambdaUpdateWrapper<AccountIncome> updateWrapperAccountIncome = new LambdaUpdateWrapper<>();
-        updateWrapperAccountIncome.eq(AccountIncome::getBusinessId, id);
-        updateWrapperAccountIncome.eq(AccountIncome::getBusinessType, 1);
-        updateWrapperAccountIncome.eq(AccountIncome::getIncomeType, 4);
-        accountIncomeService.remove(updateWrapperAccountIncome);
+        purchaseReturnOrderProducts.stream().forEach(purchaseReturnOrderProducts1 -> {
+            stockUtils.deleteStockOutRecord(purchaseReturnOrderProducts1.getId(),StockOutQualifiedRecordTypeEnum.PURCHASE_RETURN_STOCK_OUT.getCode());
+        });
     }
 
     @Override
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/TicketRegistrationServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/TicketRegistrationServiceImpl.java
deleted file mode 100644
index a98d924..0000000
--- a/src/main/java/com/ruoyi/purchase/service/impl/TicketRegistrationServiceImpl.java
+++ /dev/null
@@ -1,464 +0,0 @@
-package com.ruoyi.purchase.service.impl;
-
-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.CollectionUtils;
-import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.common.enums.FileNameType;
-import com.ruoyi.common.enums.SalesLedgerType;
-import com.ruoyi.common.exception.base.BaseException;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.bean.BeanUtils;
-import com.ruoyi.other.mapper.TempFileMapper;
-import com.ruoyi.purchase.dto.PaymentRegistrationDto;
-import com.ruoyi.purchase.dto.PurchaseLedgerDto;
-import com.ruoyi.purchase.dto.TicketRegistrationDto;
-import com.ruoyi.purchase.mapper.PaymentRegistrationMapper;
-import com.ruoyi.purchase.mapper.ProductRecordMapper;
-import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
-import com.ruoyi.purchase.mapper.TicketRegistrationMapper;
-import com.ruoyi.purchase.pojo.PaymentRegistration;
-import com.ruoyi.purchase.pojo.ProductRecord;
-import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.purchase.pojo.TicketRegistration;
-import com.ruoyi.purchase.service.ITicketRegistrationService;
-import com.ruoyi.sales.mapper.CommonFileMapper;
-import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.pojo.CommonFile;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import com.ruoyi.sales.service.ISalesLedgerProductService;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * 鏉ョエ鐧昏Service涓氬姟灞傚鐞�
- *
- * @author ruoyi
- * @date 2025-05-13
- */
-@Service
-@RequiredArgsConstructor
-@Slf4j
-public class TicketRegistrationServiceImpl extends ServiceImpl<TicketRegistrationMapper, TicketRegistration> implements ITicketRegistrationService {
-
-    private final TicketRegistrationMapper ticketRegistrationMapper;
-
-    private final PurchaseLedgerMapper purchaseLedgerMapper;
-
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-
-    private final CommonFileMapper commonFileMapper;
-
-    private final TempFileMapper tempFileMapper;
-
-    private final ProductRecordMapper productRecordMapper;
-
-    private final ISalesLedgerProductService salesLedgerProductService;
-
-    private final PaymentRegistrationMapper paymentRegistrationMapper;
-
-
-    @Override
-    public List<TicketRegistration> selectTicketRegistrationList(TicketRegistration ticketRegistration) {
-        LambdaQueryWrapper<TicketRegistration> queryWrapper = new LambdaQueryWrapper<>();
-        if (StringUtils.isNotBlank(ticketRegistration.getPurchaseContractNumber())) {
-            queryWrapper.like(TicketRegistration::getPurchaseContractNumber, ticketRegistration.getPurchaseContractNumber())
-                    .like(TicketRegistration::getSupplierName, ticketRegistration.getSupplierName())
-                    .eq(TicketRegistration::getIssueDate, ticketRegistration.getIssueDate());
-        }
-        List<TicketRegistration> ticketRegistrationList = ticketRegistrationMapper.selectList(queryWrapper);
-        // 璁$畻宸蹭粯娆鹃噾棰�
-        if (CollectionUtils.isNotEmpty(ticketRegistrationList)) {
-            List<Long> ids = ticketRegistrationList.stream().map(TicketRegistration::getId).collect(Collectors.toList());
-            List<PaymentRegistrationDto> paymentRegistrationDtoList = paymentRegistrationMapper.countPaymentTotalByTicketRegId(ids);
-            for (TicketRegistration registration : ticketRegistrationList) {
-                BigDecimal paymentAmountTotal = BigDecimal.ZERO;
-                for (PaymentRegistrationDto paymentRegistrationDto : paymentRegistrationDtoList) {
-                    if (registration.getId().equals(paymentRegistrationDto.getTicketRegistrationId())) {
-                        paymentAmountTotal = paymentRegistrationDto.getPaymentAmountTotal();
-                        break;
-                    }
-                }
-                BigDecimal invoiceAmount = registration.getInvoiceAmount();
-                BigDecimal subtractAmount = invoiceAmount.subtract(paymentAmountTotal);
-                registration.setPaymentAmountTotal(paymentAmountTotal);
-                registration.setUnPaymentAmountTotal(subtractAmount);
-            }
-        }
-
-        return ticketRegistrationList;
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public int addOrUpdateRegistration(TicketRegistrationDto ticketRegistrationDto) throws IOException {
-        // 1. 鏌ヨ閲囪喘鍙拌处璁板綍
-        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(ticketRegistrationDto.getPurchaseLedgerId());
-        if (purchaseLedger == null) {
-            // 澶勭悊閲囪喘鍙拌处涓嶅瓨鍦ㄧ殑鎯呭喌锛屼緥濡傛姏鍑哄紓甯告垨杩斿洖閿欒
-            throw new IllegalArgumentException("閲囪喘鍙拌处璁板綍涓嶅瓨鍦紝ID: " + ticketRegistrationDto.getPurchaseLedgerId());
-        }
-
-
-
-        // 3. 鍒涘缓鎴栨洿鏂扮エ鎹櫥璁板疄浣�
-        TicketRegistration ticketRegistration = new TicketRegistration();
-        BeanUtils.copyProperties(ticketRegistrationDto, ticketRegistration);
-        ticketRegistration.setPurchaseContractNumber(purchaseLedger.getPurchaseContractNumber());
-        ticketRegistration.setTenantId(purchaseLedger.getTenantId());
-        ticketRegistration.setIssueDate(ticketRegistrationDto.getEntryDate());
-        ticketRegistration.setContractAmount(purchaseLedger.getContractAmount());
-        ticketRegistration.setSalesLedgerId(purchaseLedger.getSalesLedgerId());
-        ticketRegistration.setEnterDate(ticketRegistrationDto.getEnterDate());
-
-        // 4. 澶勭悊瀛愯〃鏁版嵁
-        List<SalesLedgerProduct> productData = ticketRegistrationDto.getProductData();
-        if (CollectionUtils.isNotEmpty(productData)) {
-            handleSalesLedgerProducts(purchaseLedger.getId(), productData, 2);
-        }
-
-        // 5. 鎵ц鎻掑叆鎴栨洿鏂版搷浣�
-        int rowsAffected = ticketRegistrationMapper.insert(ticketRegistration);
-
-        // 6. 澧炲姞閲囪喘鍙拌处浜у搧寮�绁ㄨ褰�
-        List<SalesLedgerProduct> salesLedgerProducts = ticketRegistrationDto.getProductData();
-        if (CollectionUtils.isNotEmpty(salesLedgerProducts)) {
-            int insert = 0 ;
-            for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
-                //鎺掗櫎鎺夊紑绁ㄤ负0鐨勬暟鎹�
-                if (salesLedgerProduct.getTicketsNum() != null && salesLedgerProduct.getTicketsNum().compareTo(BigDecimal.ZERO) > 0) {
-                    ProductRecord productRecord = new ProductRecord();
-
-                    productRecord.setTicketRegistrationId(ticketRegistration.getId());
-                    productRecord.setPurchaseLedgerId(ticketRegistrationDto.getPurchaseLedgerId());
-                    productRecord.setCreatedAt(DateUtils.getNowDate());
-                    BeanUtils.copyProperties(salesLedgerProduct, productRecord);
-                    //鍚屾鏇存柊鍏朵粬鍓╀綑鏁伴噺鍜岄噾棰�
-                    productRecordMapper.update(
-                            null,
-                            new LambdaUpdateWrapper<ProductRecord>()
-                                    .eq(ProductRecord::getPurchaseLedgerId, ticketRegistrationDto.getPurchaseLedgerId())
-                                    .set(ProductRecord::getFutureTickets, salesLedgerProduct.getFutureTickets())
-                                    .set(ProductRecord::getFutureTicketsAmount, salesLedgerProduct.getFutureTicketsAmount())
-                    );
-                    productRecord.setSaleLedgerProjectId(salesLedgerProduct.getId());
-                    productRecord.setId(null);
-                    productRecord.setType("2");
-                    insert += productRecordMapper.insert(productRecord);
-                }
-            }
-            if (insert <= 0) {
-                throw new RuntimeException("浜у搧寮�绁ㄦ暟閮戒负0锛岃妫�鏌�");
-            }
-        }
-        return rowsAffected;
-    }
-
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public int delRegistration(Long[] ids) {
-
-        //  鏌ヨ瑕佸垹闄ょ殑浜у搧鏉ョエ璁板綍
-        LambdaQueryWrapper<ProductRecord> productWrapper = new LambdaQueryWrapper<>();
-        productWrapper.in(ProductRecord::getId, Arrays.asList(ids));
-        List<ProductRecord> productRecords = productRecordMapper.selectList(productWrapper);
-
-        if (CollectionUtils.isEmpty(productRecords)) {
-            return 0;
-        }
-
-        //  鏀堕泦鍏宠仈ID
-        Set<Long> ticketRegistrationIds = productRecords.stream()
-                .map(ProductRecord::getTicketRegistrationId)
-                .collect(Collectors.toSet());
-
-        Set<Long> salesLedgerProductIds = productRecords.stream()
-                .map(ProductRecord::getSaleLedgerProjectId)
-                .collect(Collectors.toSet());
-
-        //  鏌ヨ鏉ョエ鐧昏
-        List<TicketRegistration> ticketRegistrations =
-                ticketRegistrationMapper.selectBatchIds(ticketRegistrationIds);
-
-        //  澶勭悊鏉ョエ鐧昏閲戦銆佷粯娆炬祦姘�
-        for (TicketRegistration ticket : ticketRegistrations) {
-
-            // 璇ユ潵绁ㄧ櫥璁颁笅鎵�鏈変骇鍝佽褰�
-            List<ProductRecord> recordsOfTicket = productRecords.stream()
-                    .filter(r -> r.getTicketRegistrationId().equals(ticket.getId()))
-                    .collect(Collectors.toList());
-
-            // 璁$畻瑕佸洖閫�鐨勯噾棰�
-            BigDecimal rollbackAmount = recordsOfTicket.stream()
-                    .map(ProductRecord::getTicketsAmount)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-            BigDecimal remain = ticket.getInvoiceAmount().subtract(rollbackAmount);
-
-            if (remain.compareTo(BigDecimal.ZERO) <= 0) {
-                // 鍒犻櫎鏉ョエ鐧昏
-                ticketRegistrationMapper.deleteById(ticket.getId());
-                // 鍒犻櫎浠樻娴佹按
-                paymentRegistrationMapper.delete(
-                        new LambdaQueryWrapper<PaymentRegistration>()
-                                .eq(PaymentRegistration::getTicketRegistrationId, ticket.getId())
-                );
-            } else {
-                ticket.setInvoiceAmount(remain);
-                ticketRegistrationMapper.updateById(ticket);
-            }
-        }
-
-        //  鍥為��閿�鍞彴璐︿骇鍝佺殑鏈潵绁�
-        for (ProductRecord record : productRecords) {
-
-            LambdaQueryWrapper<SalesLedgerProduct> wrapper = new LambdaQueryWrapper<>();
-            wrapper.eq(SalesLedgerProduct::getId, record.getSaleLedgerProjectId())
-                    .eq(SalesLedgerProduct::getType, 2);
-
-            SalesLedgerProduct product = salesLedgerProductMapper.selectOne(wrapper);
-            if (product != null) {
-                product.setFutureTickets(
-                        product.getFutureTickets().add(record.getTicketsNum())
-                );
-                product.setFutureTicketsAmount(
-                        product.getFutureTicketsAmount().add(record.getTicketsAmount())
-                );
-                salesLedgerProductMapper.updateById(product);
-            }
-        }
-
-        //  鍒犻櫎浜у搧鏉ョエ璁板綍
-        productRecordMapper.delete(productWrapper);
-
-        //  閲嶆柊璁$畻 currentInvoiceAmount
-        for (Long productId : salesLedgerProductIds) {
-            refreshCurrentInvoiceAmount(productId);
-        }
-
-        return 1;
-    }
-
-    private void refreshCurrentInvoiceAmount(Long salesLedgerProductId) {
-
-        // 鏌ヨ璇ヤ骇鍝佹渶鏂颁竴鏉℃潵绁ㄨ褰�
-        LambdaQueryWrapper<ProductRecord> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(ProductRecord::getSaleLedgerProjectId, salesLedgerProductId)
-                .orderByDesc(ProductRecord::getCreatedAt)
-                .last("limit 1");
-
-        ProductRecord latestRecord = productRecordMapper.selectOne(wrapper);
-
-        SalesLedgerProduct product =
-                salesLedgerProductMapper.selectById(salesLedgerProductId);
-
-        if (product == null) {
-            return;
-        }
-
-        if (latestRecord == null) {
-            //  娌℃湁浠讳綍鏉ョエ璁板綍
-            product.setTicketsAmount(BigDecimal.ZERO);
-        } else {
-            //  姘歌繙鍙栨渶鏂颁竴鏉�
-            product.setTicketsAmount(latestRecord.getTicketsAmount());
-        }
-
-        salesLedgerProductMapper.updateById(product);
-    }
-
-
-    @Override
-    public TicketRegistrationDto getRegistrationById(TicketRegistrationDto ticketRegistrationDto) {
-        TicketRegistration ticketRegistration = ticketRegistrationMapper.selectById(ticketRegistrationDto.getId());
-        LambdaQueryWrapper<PurchaseLedger> purchaseQueryWrapper = new LambdaQueryWrapper<>();
-        purchaseQueryWrapper.eq(PurchaseLedger::getId, ticketRegistration.getPurchaseLedgerId());
-        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(purchaseQueryWrapper);
-        if (ticketRegistration == null) {
-            throw new BaseException("閲囪喘鍙拌处涓嶅瓨鍦�");
-        }
-        // 鍒涘缓骞跺~鍏匘TO
-        TicketRegistrationDto resultDto = new TicketRegistrationDto();
-        BeanUtils.copyProperties(ticketRegistration, resultDto);
-
-        // 鏌ヨ骞惰缃叧鑱斾骇鍝�
-        LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId())
-                .eq(SalesLedgerProduct::getType, 2);
-        List<SalesLedgerProduct> productList = salesLedgerProductMapper.selectList(queryWrapper);
-        resultDto.setProductData(productList);
-        return resultDto;
-    }
-
-    @Override
-    public List getTicketNo(TicketRegistrationDto ticketRegistrationDto) {
-        LambdaQueryWrapper<TicketRegistration> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.select(TicketRegistration::getId, TicketRegistration::getInvoiceNumber, TicketRegistration::getInvoiceAmount)
-                .eq(TicketRegistration::getPurchaseLedgerId, ticketRegistrationDto.getId());
-        List<Map<String, Object>> result = ticketRegistrationMapper.selectMaps(queryWrapper);
-        // 灏嗕笅鍒掔嚎鍛藉悕杞崲涓洪┘宄板懡鍚�
-        return result.stream().map(map -> map.entrySet().stream()
-                .collect(Collectors.toMap(
-                        entry -> underlineToCamel(entry.getKey()),
-                        Map.Entry::getValue))
-        ).collect(Collectors.toList());
-    }
-
-    @Override
-    public IPage<TicketRegistration> selectTicketRegistrationListPage(Page page, TicketRegistration ticketRegistration) {
-        LambdaQueryWrapper<TicketRegistration> queryWrapper = new LambdaQueryWrapper<>();
-        if (StringUtils.isNotBlank(ticketRegistration.getSupplierNameOrContractNo())) {
-            queryWrapper.and(wrapper -> wrapper
-                    .like(TicketRegistration::getPurchaseContractNumber, ticketRegistration.getSupplierNameOrContractNo())
-                    .or()
-                    .like(TicketRegistration::getSupplierName, ticketRegistration.getSupplierNameOrContractNo())
-                    .or()
-                    .like(TicketRegistration::getSalesContractNo, ticketRegistration.getSupplierNameOrContractNo()));
-        }
-        if (!ObjectUtils.isEmpty(ticketRegistration.getIssueDateStart()) && !ObjectUtils.isEmpty(ticketRegistration.getIssueDateEnd())) {
-            queryWrapper.between(TicketRegistration::getIssueDate, LocalDate.parse(ticketRegistration.getIssueDateStart(), DateTimeFormatter.ofPattern("yyyy-MM-dd")), LocalDate.parse(ticketRegistration.getIssueDateEnd(), DateTimeFormatter.ofPattern("yyyy-MM-dd")));
-        }
-        IPage<TicketRegistration> ticketRegistrationIPage = ticketRegistrationMapper.selectPage(page, queryWrapper);
-        // 璁$畻宸蹭粯娆鹃噾棰�
-        if (CollectionUtils.isNotEmpty(ticketRegistrationIPage.getRecords())) {
-            List<Long> ids = ticketRegistrationIPage.getRecords().stream().map(TicketRegistration::getId).collect(Collectors.toList());
-            List<PaymentRegistrationDto> paymentRegistrationDtoList = paymentRegistrationMapper.countPaymentTotalByTicketRegId(ids);
-            for (TicketRegistration registration : ticketRegistrationIPage.getRecords()) {
-                BigDecimal paymentAmountTotal = BigDecimal.ZERO;
-                for (PaymentRegistrationDto paymentRegistrationDto : paymentRegistrationDtoList) {
-                    if (registration.getId().equals(paymentRegistrationDto.getTicketRegistrationId())) {
-                        paymentAmountTotal = paymentRegistrationDto.getPaymentAmountTotal();
-                        break;
-                    }
-                }
-                BigDecimal invoiceAmount = registration.getInvoiceAmount();
-                BigDecimal subtractAmount = invoiceAmount.subtract(paymentAmountTotal);
-                registration.setPaymentAmountTotal(paymentAmountTotal);
-                registration.setUnPaymentAmountTotal(subtractAmount);
-            }
-        }
-        if (!ObjectUtils.isEmpty(ticketRegistration.getStatus())) {
-
-            if (ticketRegistration.getStatus()) {
-                ticketRegistrationIPage.getRecords().removeIf(receiptPaymentDto1 -> new BigDecimal("0.00").equals(receiptPaymentDto1.getUnPaymentAmountTotal()));
-                ticketRegistrationIPage.setTotal(ticketRegistrationIPage.getRecords().size());
-            }
-        }
-        ticketRegistrationIPage.getRecords().forEach(item -> {
-            // 宸蹭粯娆鹃噾棰� == 寰呬粯娆鹃噾棰�
-            item.setStatusName(item.getPaymentAmountTotal().compareTo(item.getInvoiceAmount()) == 0 ? "宸插畬鎴愪粯娆�" : "鏈畬鎴愪粯娆�");
-        });
-        return ticketRegistrationIPage;
-    }
-
-    @Override
-    public PurchaseLedgerDto getPuargeById(Long id) {
-        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(id);
-        PurchaseLedgerDto purchaseLedgerDto = new PurchaseLedgerDto();
-        BeanUtils.copyProperties(purchaseLedger, purchaseLedgerDto);
-        SalesLedgerProduct salesLedgerProduct = new SalesLedgerProduct();
-        salesLedgerProduct.setSalesLedgerId(id);
-        salesLedgerProduct.setType(SalesLedgerType.SALES_LEDGER_TYPE_SALES_LEDGER.getCode());
-        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductService.selectSalesLedgerProductList(salesLedgerProduct);
-        purchaseLedgerDto.setProductData(salesLedgerProducts);
-        List<CommonFile> commonFiles = commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
-                .eq(CommonFile::getType, FileNameType.PURCHASELEDGER.getValue())
-                .eq(CommonFile::getCommonId, id));
-        purchaseLedgerDto.setSalesLedgerFiles(commonFiles);
-        return purchaseLedgerDto;
-    }
-
-    @Override
-    public List<PaymentRegistrationDto> getPaymentRegistrationDtoById(Long id) {
-        List<PaymentRegistrationDto> paymentRegistrationDtos =purchaseLedgerMapper.getPaymentRegistrationDtoById(id);
-        return paymentRegistrationDtos;
-    }
-
-    private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, Integer type) {
-        if (products == null || products.isEmpty()) {
-            return;
-        }
-
-        // 杩囨护鍑烘湁 ID 鐨勮褰曪紙鍗抽渶瑕佹洿鏂扮殑璁板綍锛�
-        List<SalesLedgerProduct> updateList = products.stream()
-                .filter(p -> p.getId() != null)
-                .peek(p -> {
-                    p.setSalesLedgerId(salesLedgerId);
-                    p.setType(type);
-                })
-                .collect(Collectors.toList());
-
-        // 鎵归噺鏇存柊锛堥渶瑕� MyBatis 鎻愪緵鎵归噺鏇存柊鏂规硶锛�
-        if (!updateList.isEmpty()) {
-            updateList.forEach(product -> {
-                // 闈炵┖鏍¢獙锛屼换涓�瀛楁涓虹┖鍒欐姏鍑哄紓甯�
-                if (product.getQuantity() == null) {
-                    throw new BaseException("鏁伴噺涓嶈兘涓虹┖");
-                }
-                if (product.getTicketsNum() == null) {
-                    throw new BaseException("宸插紑绁ㄦ暟閲忎笉鑳戒负绌�");
-                }
-                if (product.getTaxInclusiveTotalPrice() == null) {
-                    throw new BaseException("鍚◣鎬讳环涓嶈兘涓虹┖");
-                }
-                if (product.getTicketsAmount() == null) {
-                    throw new BaseException("鏈鏉ョエ閲戦(鍏�)涓嶈兘涓虹┖");
-                }
-
-                // 璁$畻 futureTickets锛堢洿鎺ヤ娇鐢� BigDecimal 璁$畻锛岄伩鍏嶇簿搴︿涪澶憋級
-//                product.setFutureTickets(
-//                        product.getQuantity()
-//                                .subtract(product.getTicketsNum())
-//                );
-
-
-                // 璁$畻 futureTicketsAmount
-//                product.setFutureTicketsAmount(
-//                        product.getTaxInclusiveTotalPrice()
-//                                .subtract(product.getTicketsAmount())
-//                );
-                product.setType(type);
-                salesLedgerProductMapper.updateById(product);
-            });
-        }
-    }
-
-    /**
-     * 涓嬪垝绾垮懡鍚嶈浆椹煎嘲鍛藉悕
-     */
-    private String underlineToCamel(String param) {
-        if (param == null || "".equals(param.trim())) {
-            return "";
-        }
-        int len = param.length();
-        StringBuilder sb = new StringBuilder(len);
-        for (int i = 0; i < len; i++) {
-            char c = param.charAt(i);
-            if (c == '_') {
-                if (++i < len) {
-                    sb.append(Character.toUpperCase(param.charAt(i)));
-                }
-            } else {
-                sb.append(Character.toLowerCase(c));
-            }
-        }
-        return sb.toString();
-    }
-}
diff --git a/src/main/java/com/ruoyi/purchase/vo/SupplierTransactionsDetailsVo.java b/src/main/java/com/ruoyi/purchase/vo/SupplierTransactionsDetailsVo.java
new file mode 100644
index 0000000..3533e6e
--- /dev/null
+++ b/src/main/java/com/ruoyi/purchase/vo/SupplierTransactionsDetailsVo.java
@@ -0,0 +1,33 @@
+package com.ruoyi.purchase.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@Schema(name = "SupplierTransactionsDetailsVo", description = "閲囪喘绠$悊--渚涘簲鍟嗗線鏉ユ槑缁�(杩斿洖)")
+public class SupplierTransactionsDetailsVo {
+
+    @Schema(description = "閲囪喘鍗旾D")
+    private Long purchaseLedgerId;
+
+    @Schema(description = "閲囪喘鍚堝悓鍙�")
+    private String purchaseContractNumber;
+
+    @Schema(description = "閲囪喘鍚堝悓绛捐鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date executionDate;
+
+    @Schema(description = "鍚堝悓閲戦")
+    private BigDecimal contractAmount;
+
+    @Schema(description = "浠樻閲戦")
+    private BigDecimal paymentAmount;
+
+    @Schema(description = "搴斾粯閲戦")
+    private BigDecimal payableAmount;
+
+}
diff --git a/src/main/java/com/ruoyi/purchase/vo/SupplierTransactionsVo.java b/src/main/java/com/ruoyi/purchase/vo/SupplierTransactionsVo.java
new file mode 100644
index 0000000..35cefc0
--- /dev/null
+++ b/src/main/java/com/ruoyi/purchase/vo/SupplierTransactionsVo.java
@@ -0,0 +1,30 @@
+package com.ruoyi.purchase.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(name = "SupplierTransactionsVo", description = "閲囪喘绠$悊--渚涘簲鍟嗗線鏉�(杩斿洖)")
+public class SupplierTransactionsVo {
+
+    @Schema(description = "渚涘簲鍟咺D")
+    private Long supplierId;
+
+    @Schema(description = "渚涘簲鍟嗗悕绉�")
+    private String supplierName;
+
+    @Schema(description = "鍚堝悓鎬婚噾棰�")
+    //璇ヤ緵搴斿晢閲囪喘鍚堝悓绱閲戦
+    private BigDecimal contractAmounts;
+
+    @Schema(description = "浠樻閲戦")
+    //璇ヤ緵搴斿晢閲囪喘浠樻绱閲戦
+    private BigDecimal paymentAmount;
+
+    @Schema(description = "搴斾粯閲戦")
+    //璇ヤ緵搴斿晢閲囪喘搴斾粯绱閲戦=璐㈠姟(鍏ュ簱-閫�璐�)
+    private BigDecimal payableAmount;
+
+}
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java b/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
index fcaceb6..dc05d88 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
@@ -2,7 +2,9 @@
 
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.quality.dto.QualityInspectDto;
 import com.ruoyi.quality.pojo.QualityInspect;
 import com.ruoyi.quality.pojo.QualityInspectFile;
@@ -10,7 +12,9 @@
 import com.ruoyi.quality.service.IQualityInspectFileService;
 import com.ruoyi.quality.service.IQualityInspectParamService;
 import com.ruoyi.quality.service.IQualityInspectService;
+import io.swagger.v3.oas.annotations.Operation;
 import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
 import lombok.AllArgsConstructor;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
@@ -37,8 +41,10 @@
      * @return
      */
     @PostMapping("/add")
-    public AjaxResult add(@RequestBody QualityInspectDto qualityInspectDto) {
-        return AjaxResult.success(qualityInspectService.add(qualityInspectDto));
+    @Operation(summary = "鏂板妫�楠�")
+    @Log(title = "鏂板妫�楠�", businessType = BusinessType.INSERT)
+    public R<?> add(@RequestBody QualityInspectDto qualityInspectDto) {
+        return R.ok(qualityInspectService.add(qualityInspectDto));
     }
 
     /**
@@ -48,9 +54,11 @@
      * @return
      */
     @DeleteMapping("/del")
-    public AjaxResult delQualityInspect(@RequestBody List<Integer> ids) {
+    @Operation(summary = "鍒犻櫎妫�楠�")
+    @Log(title = "鍒犻櫎妫�楠�", businessType = BusinessType.DELETE)
+    public R<?> delQualityInspect(@RequestBody List<Integer> ids) {
         if (CollectionUtils.isEmpty(ids)) {
-            return AjaxResult.error("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
+            return R.fail("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
         }
         //濡傛灉宸茬粡鎻愪氦灏变笉鍏佽鍒犻櫎
         List<QualityInspect> qualityInspects = qualityInspectService.listByIds(ids);
@@ -66,7 +74,7 @@
         qualityInspectFileService.remove(Wrappers.<QualityInspectFile>lambdaQuery()
                 .in(QualityInspectFile::getInspectId, ids));
         //鍒犻櫎妫�楠屽崟
-        return AjaxResult.success(qualityInspectService.removeBatchByIds(ids));
+        return R.ok(qualityInspectService.removeBatchByIds(ids));
     }
 
     /**
@@ -76,8 +84,10 @@
      * @return
      */
     @GetMapping("/{id}")
-    public AjaxResult QualityInspectDetail(@PathVariable("id") Integer id) {
-        return AjaxResult.success(qualityInspectService.getDetailById(id));
+    @Operation(summary = "妫�楠岃鎯�")
+    @Log(title = "妫�楠岃鎯�", businessType = BusinessType.OTHER)
+    public R<?> QualityInspectDetail(@PathVariable("id") Integer id) {
+        return R.ok(qualityInspectService.getDetailById(id));
     }
 
     /**
@@ -87,8 +97,10 @@
      * @return
      */
     @PostMapping("/update")
-    public AjaxResult update(@RequestBody QualityInspectDto qualityInspectDto) {
-        return AjaxResult.success(qualityInspectService.updateQualityInspect(qualityInspectDto));
+    @Operation(summary = "淇敼妫�楠�")
+    @Log(title = "淇敼妫�楠�", businessType = BusinessType.UPDATE)
+    public R<?> update(@RequestBody QualityInspectDto qualityInspectDto) {
+        return R.ok(qualityInspectService.updateQualityInspect(qualityInspectDto));
     }
 
     /**
@@ -99,8 +111,10 @@
      * @return
      */
     @GetMapping("/listPage")
-    public AjaxResult qualityInspectListPage(Page page, QualityInspectDto qualityInspect) {
-        return AjaxResult.success(qualityInspectService.qualityInspectListPage(page, qualityInspect));
+    @Operation(summary = "鍒嗛〉鏌ヨ妫�楠�")
+    @Log(title = "鍒嗛〉鏌ヨ妫�楠�", businessType = BusinessType.OTHER)
+    public R<?> qualityInspectListPage(Page page, QualityInspectDto qualityInspect) {
+        return R.ok(qualityInspectService.qualityInspectListPage(page, qualityInspect));
     }
 
     /**
@@ -110,6 +124,8 @@
      * @param qualityInspect
      */
     @PostMapping("/export")
+    @Operation(summary = "瀵煎嚭妫�楠�")
+    @Log(title = "瀵煎嚭妫�楠�", businessType = BusinessType.EXPORT)
     public void qualityInspectExport(HttpServletResponse response, QualityInspect qualityInspect) {
         qualityInspectService.qualityInspectExport(response, qualityInspect);
     }
@@ -121,8 +137,10 @@
      * @return
      */
     @PostMapping("/submit")
-    public AjaxResult submit(@RequestBody QualityInspect qualityInspect) {
-        return AjaxResult.success(qualityInspectService.submit(qualityInspect));
+    @Operation(summary = "鎻愪氦妫�楠�")
+    @Log(title = "鎻愪氦妫�楠�", businessType = BusinessType.OTHER)
+    public R<?> submit(@Valid @RequestBody QualityInspect qualityInspect) {
+        return R.ok(qualityInspectService.submit(qualityInspect));
     }
 
     /**
@@ -132,6 +150,8 @@
      * @param qualityInspect
      */
     @PostMapping("/down")
+    @Operation(summary = "涓嬭浇妫�楠�")
+    @Log(title = "涓嬭浇妫�楠�", businessType = BusinessType.OTHER)
     public void down(HttpServletResponse response, @RequestBody QualityInspect qualityInspect) {
         qualityInspectService.down(response, qualityInspect);
     }
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java b/src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java
index 263b201..48fc093 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java
@@ -2,13 +2,16 @@
 
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.quality.pojo.QualityInspect;
 import com.ruoyi.quality.pojo.QualityInspectFile;
 import com.ruoyi.quality.pojo.QualityInspectParam;
 import com.ruoyi.quality.service.IQualityInspectFileService;
 import com.ruoyi.quality.service.IQualityInspectParamService;
 import com.ruoyi.quality.service.IQualityInspectService;
+import io.swagger.v3.oas.annotations.Operation;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
 
@@ -32,8 +35,10 @@
      * @return
      */
     @GetMapping("/{inspectId}")
-    public AjaxResult QualityInspectParamDetail(@PathVariable("inspectId") Integer inspectId) {
-        return AjaxResult.success(qualityInspectParamService.qualityInspectParamDetail(inspectId));
+    @Operation(summary = "妫�楠屽弬鏁伴」璇︽儏")
+    @Log(title = "妫�楠屽弬鏁伴」璇︽儏", businessType = BusinessType.OTHER)
+    public R<?> QualityInspectParamDetail(@PathVariable("inspectId") Integer inspectId) {
+        return R.ok(qualityInspectParamService.qualityInspectParamDetail(inspectId));
     }
 
 
@@ -43,8 +48,10 @@
      * @return
      */
     @PostMapping("/update")
-    public AjaxResult update(@RequestBody List<QualityInspectParam> qualityInspectParams) {
-        return AjaxResult.success(qualityInspectParamService.updateBatchById(qualityInspectParams));
+    @Operation(summary = "淇敼妫�楠屽弬鏁伴」")
+    @Log(title = "淇敼妫�楠屽弬鏁伴」", businessType = BusinessType.UPDATE)
+    public R<?> update(@RequestBody List<QualityInspectParam> qualityInspectParams) {
+        return R.ok(qualityInspectParamService.updateBatchById(qualityInspectParams));
     }
 
     /**
@@ -53,11 +60,13 @@
      * @return
      */
     @DeleteMapping("/del")
-    public AjaxResult delQualityUnqualified(@RequestBody List<Integer> ids) {
+    @Operation(summary = "鍒犻櫎妫�楠屽弬鏁伴」")
+    @Log(title = "鍒犻櫎妫�楠屽弬鏁伴」", businessType = BusinessType.DELETE)
+    public R<?> delQualityUnqualified(@RequestBody List<Integer> ids) {
         if(CollectionUtils.isEmpty(ids)){
-            return AjaxResult.error("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
+            return R.fail("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
         }
-        return AjaxResult.success(qualityInspectParamService.removeBatchByIds(ids));
+        return R.ok(qualityInspectParamService.removeBatchByIds(ids));
     }
 
 
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityReportController.java b/src/main/java/com/ruoyi/quality/controller/QualityReportController.java
index 4d005b0..370e8f0 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityReportController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityReportController.java
@@ -1,6 +1,8 @@
 package com.ruoyi.quality.controller;
 
-import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.quality.service.QualityReportService;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -30,8 +32,9 @@
      */
     @Operation(summary = "鑾峰彇妫�楠岀粺璁℃暟鎹�")
     @GetMapping("/getInspectStatistics")
-    public AjaxResult getInspectStatistics() {
-        return AjaxResult.success(qualityReportService.getInspectStatistics());
+    @Log(title = "鑾峰彇妫�楠岀粺璁℃暟鎹�", businessType = BusinessType.OTHER)
+    public R<?> getInspectStatistics() {
+        return R.ok(qualityReportService.getInspectStatistics());
     }
 
     /**
@@ -39,8 +42,9 @@
      */
     @Operation(summary = "鑾峰彇鍚堟牸鐜囩粺璁℃暟鎹�")
     @GetMapping("/getPassRateStatistics")
-    public AjaxResult getPassRateStatistics() {
-        return AjaxResult.success(qualityReportService.getPassRateStatistics());
+    @Log(title = "鑾峰彇鍚堟牸鐜囩粺璁℃暟鎹�", businessType = BusinessType.OTHER)
+    public R<?> getPassRateStatistics() {
+        return R.ok(qualityReportService.getPassRateStatistics());
     }
 
     /**
@@ -48,8 +52,9 @@
      */
     @Operation(summary = "鑾峰彇鏈堝害鍚堟牸鐜囩粺璁℃暟鎹�")
     @GetMapping("/getMonthlyPassRateStatistics")
-    public AjaxResult getMonthlyPassRateStatistics(@RequestParam("year") String year) {
-        return AjaxResult.success(qualityReportService.getMonthlyPassRateStatistics(year));
+    @Log(title = "鑾峰彇鏈堝害鍚堟牸鐜囩粺璁℃暟鎹�", businessType = BusinessType.OTHER)
+    public R<?> getMonthlyPassRateStatistics(@RequestParam("year") String year) {
+        return R.ok(qualityReportService.getMonthlyPassRateStatistics(year));
     }
 
     /**
@@ -57,8 +62,9 @@
      */
     @Operation(summary = "鑾峰彇骞村害鎬诲悎鏍肩巼缁熻鏁版嵁")
     @GetMapping("/getYearlyPassRateStatistics")
-    public AjaxResult getYearlyPassRateStatistics(@RequestParam("year") String year) {
-        return AjaxResult.success(qualityReportService.getYearlyPassRateStatistics(year));
+    @Log(title = "鑾峰彇骞村害鎬诲悎鏍肩巼缁熻鏁版嵁", businessType = BusinessType.OTHER)
+    public R<?> getYearlyPassRateStatistics(@RequestParam("year") String year) {
+        return R.ok(qualityReportService.getYearlyPassRateStatistics(year));
     }
 
     /**
@@ -66,8 +72,9 @@
      */
     @Operation(summary = "鑾峰彇鏈堝害瀹屾垚鏄庣粏鏁版嵁")
     @GetMapping("/getMonthlyCompletionDetails")
-    public AjaxResult getMonthlyCompletionDetails(@RequestParam("year") String year) {
-        return AjaxResult.success(qualityReportService.getMonthlyCompletionDetails(year));
+    @Log(title = "鑾峰彇鏈堝害瀹屾垚鏄庣粏鏁版嵁", businessType = BusinessType.OTHER)
+    public R<?> getMonthlyCompletionDetails(@RequestParam("year") String year) {
+        return R.ok(qualityReportService.getMonthlyCompletionDetails(year));
     }
 
     /**
@@ -75,8 +82,9 @@
      */
     @Operation(summary = "鑾峰彇鐑偣妫�娴嬫寚鏍囩粺璁�")
     @GetMapping("/getTopParameters")
-    public AjaxResult getTopParameters(@RequestParam("modelType") Integer modelType) {
-        return AjaxResult.success(qualityReportService.getTopParameters(modelType));
+    @Log(title = "鑾峰彇鐑偣妫�娴嬫寚鏍囩粺璁�", businessType = BusinessType.OTHER)
+    public R<?> getTopParameters(@RequestParam("modelType") Integer modelType) {
+        return R.ok(qualityReportService.getTopParameters(modelType));
     }
 
 }
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java b/src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java
index 539f3f7..7f2142e 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java
@@ -1,8 +1,12 @@
 package com.ruoyi.quality.controller;
 
-import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.quality.pojo.QualityTestStandardBinding;
 import com.ruoyi.quality.service.QualityTestStandardBindingService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.AllArgsConstructor;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
@@ -20,6 +24,7 @@
 @RestController
 @RequestMapping("/qualityTestStandardBinding")
 @AllArgsConstructor
+@Tag(name = "妫�娴嬫爣鍑嗕富琛ㄤ笌浜у搧鍏宠仈琛�")
 public class QualityTestStandardBindingController {
 
     private QualityTestStandardBindingService qualityTestStandardBindingService;
@@ -31,8 +36,10 @@
      * @return
      */
     @PostMapping("/add")
-    public AjaxResult add(@RequestBody List<QualityTestStandardBinding> qualityTestStandardBindings) {
-        return AjaxResult.success(qualityTestStandardBindingService.add(qualityTestStandardBindings));
+    @Operation(summary = "鏂板妫�娴嬫爣鍑嗕富琛ㄤ笌浜у搧鍏宠仈琛�")
+    @Log(title = "鏂板妫�娴嬫爣鍑嗕富琛ㄤ笌浜у搧鍏宠仈琛�", businessType = BusinessType.INSERT)
+    public R<?> add(@RequestBody List<QualityTestStandardBinding> qualityTestStandardBindings) {
+        return R.ok(qualityTestStandardBindingService.add(qualityTestStandardBindings));
     }
 
     /**
@@ -42,11 +49,13 @@
      * @return
      */
     @DeleteMapping("/del")
-    public AjaxResult delQualityTestStandard(@RequestBody List<Integer> ids) {
+    @Operation(summary = "鍒犻櫎妫�娴嬫爣鍑嗕富琛ㄤ笌浜у搧鍏宠仈琛�")
+    @Log(title = "鍒犻櫎妫�娴嬫爣鍑嗕富琛ㄤ笌浜у搧鍏宠仈琛�", businessType = BusinessType.DELETE)
+    public R<?> delQualityTestStandard(@RequestBody List<Integer> ids) {
         if (CollectionUtils.isEmpty(ids)) {
-            return AjaxResult.error("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
+            return R.fail("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
         }
-        return AjaxResult.success(qualityTestStandardBindingService.removeBatchByIds(ids));
+        return R.ok(qualityTestStandardBindingService.removeBatchByIds(ids));
     }
 
     /**
@@ -55,8 +64,10 @@
      * @return
      */
     @GetMapping("/list")
-    public AjaxResult listBinding(Long testStandardId) {
-        return AjaxResult.success(qualityTestStandardBindingService.listBinding(testStandardId));
+    @Operation(summary = "妫�娴嬫寚鏍囩淮鎶ゆ煡璇�")
+    @Log(title = "妫�娴嬫寚鏍囩淮鎶ゆ煡璇�", businessType = BusinessType.OTHER)
+    public R<?> listBinding(Long testStandardId) {
+        return R.ok(qualityTestStandardBindingService.listBinding(testStandardId));
     }
 
 }
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java b/src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java
index a61ffed..ab8fca9 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java
@@ -2,11 +2,15 @@
 
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.quality.pojo.QualityTestStandard;
 import com.ruoyi.quality.pojo.QualityTestStandardParam;
 import com.ruoyi.quality.service.IQualityTestStandardService;
 import com.ruoyi.quality.service.QualityTestStandardParamService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
 
@@ -24,6 +28,7 @@
  */
 @RestController
 @RequestMapping("/qualityTestStandard")
+@Tag(name = "妫�娴嬫爣鍑嗕富琛�")
 public class QualityTestStandardController {
 
     @Resource
@@ -39,8 +44,10 @@
      * @return
      */
     @PostMapping("/add")
-    public AjaxResult add(@RequestBody QualityTestStandard qualityTestStandard) {
-        return AjaxResult.success(qualityTestStandardService.save(qualityTestStandard));
+    @Operation(summary = "鏂板妫�娴嬫爣鍑嗕富琛�")
+    @Log(title = "鏂板妫�娴嬫爣鍑嗕富琛�", businessType = BusinessType.INSERT)
+    public R<?> add(@RequestBody QualityTestStandard qualityTestStandard) {
+        return R.ok(qualityTestStandardService.save(qualityTestStandard));
     }
 
     /**
@@ -49,11 +56,13 @@
      * @return
      */
     @DeleteMapping("/del")
-    public AjaxResult delQualityTestStandard(@RequestBody List<Integer> ids) {
+    @Operation(summary = "鍒犻櫎妫�娴嬫爣鍑嗕富琛�")
+    @Log(title = "鍒犻櫎妫�娴嬫爣鍑嗕富琛�", businessType = BusinessType.DELETE)
+    public R<?> delQualityTestStandard(@RequestBody List<Integer> ids) {
         if(CollectionUtils.isEmpty(ids)){
-            return AjaxResult.error("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
+            return R.fail("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
         }
-        return AjaxResult.success(qualityTestStandardService.delQualityTestStandard(ids));
+        return R.ok(qualityTestStandardService.delQualityTestStandard(ids));
     }
 
     /**
@@ -62,8 +71,10 @@
      * @return
      */
     @PostMapping("/update")
-    public AjaxResult update(@RequestBody QualityTestStandard qualityTestStandard) {
-        return AjaxResult.success(qualityTestStandardService.updateById(qualityTestStandard));
+    @Operation(summary = "妫�娴嬫爣鍑嗕富琛ㄤ慨鏀�")
+    @Log(title = "妫�娴嬫爣鍑嗕富琛ㄤ慨鏀�", businessType = BusinessType.UPDATE)
+    public R<?> update(@RequestBody QualityTestStandard qualityTestStandard) {
+        return R.ok(qualityTestStandardService.updateById(qualityTestStandard));
     }
 
     /**
@@ -73,8 +84,10 @@
      * @return
      */
     @GetMapping("/listPage")
-    public AjaxResult qualityTestStandardListPage(Page page, QualityTestStandard qualityTestStandard) {
-        return AjaxResult.success(qualityTestStandardService.qualityTestStandardListPage(page, qualityTestStandard));
+    @Operation(summary = "妫�娴嬫爣鍑嗕富琛ㄥ垎椤垫煡璇�")
+    @Log(title = "妫�娴嬫爣鍑嗕富琛ㄥ垎椤垫煡璇�", businessType = BusinessType.OTHER)
+    public R<?> qualityTestStandardListPage(Page page, QualityTestStandard qualityTestStandard) {
+        return R.ok(qualityTestStandardService.qualityTestStandardListPage(page, qualityTestStandard));
     }
 
     /**
@@ -83,8 +96,10 @@
      * @return
      */
     @PostMapping("/copyParam")
-    public AjaxResult copyParam(@RequestBody QualityTestStandard qualityTestStandard) {
-        return AjaxResult.success(qualityTestStandardService.copyParam(qualityTestStandard));
+    @Operation(summary = "妫�娴嬫爣鍑嗗鍒跺弬鏁�")
+    @Log(title = "妫�娴嬫爣鍑嗗鍒跺弬鏁�", businessType = BusinessType.OTHER)
+    public R<?> copyParam(@RequestBody QualityTestStandard qualityTestStandard) {
+        return R.ok(qualityTestStandardService.copyParam(qualityTestStandard));
     }
 
     /**
@@ -93,8 +108,10 @@
      * @return
      */
     @PostMapping("/qualityTestStandardAudit")
-    public AjaxResult qualityTestStandardAudit(@RequestBody List<QualityTestStandard> qualityTestStandards) {
-        return AjaxResult.success(qualityTestStandardService.updateBatchById(qualityTestStandards));
+    @Operation(summary = "妫�娴嬫爣鍑嗘壒閲忓鏍�")
+    @Log(title = "妫�娴嬫爣鍑嗘壒閲忓鏍�", businessType = BusinessType.OTHER)
+    public R<?> qualityTestStandardAudit(@RequestBody List<QualityTestStandard> qualityTestStandards) {
+        return R.ok(qualityTestStandardService.updateBatchById(qualityTestStandards));
     }
 
     /**
@@ -102,8 +119,10 @@
      * @return
      */
     @GetMapping("/getQualityTestStandardByProductId")
-    public AjaxResult getQualityTestStandardByProductId(@Nonnull Long productId, @Nonnull Integer inspectType, String process) {
-        return AjaxResult.success(qualityTestStandardService.getQualityTestStandardByProductId(productId,inspectType,process));
+    @Operation(summary = "鏍规嵁浜у搧id鏌ヨ鐩稿叧鐨勬楠屾爣鍑�")
+    @Log(title = "鏍规嵁浜у搧id鏌ヨ鐩稿叧鐨勬楠屾爣鍑�", businessType = BusinessType.OTHER)
+    public R<?> getQualityTestStandardByProductId(@Nonnull Long productId, @Nonnull Integer inspectType, String process) {
+        return R.ok(qualityTestStandardService.getQualityTestStandardByProductId(productId,inspectType,process));
     }
 
     /**
@@ -111,8 +130,10 @@
      * @return
      */
     @GetMapping("/getQualityTestStandardParamByTestStandardId")
-    public AjaxResult getQualityTestStandardParamByTestStandardId(Long testStandardId) {
-        return AjaxResult.success(qualityTestStandardParamService.list(Wrappers.<QualityTestStandardParam>lambdaQuery().eq(QualityTestStandardParam::getTestStandardId, testStandardId)));
+    @Operation(summary = "鏍规嵁妫�娴嬫爣鍑唅d鏌ヨ鐩稿叧鐨勬楠屾爣鍑嗗弬鏁�")
+    @Log(title = "鏍规嵁妫�娴嬫爣鍑唅d鏌ヨ鐩稿叧鐨勬楠屾爣鍑嗗弬鏁�", businessType = BusinessType.OTHER)
+    public R<?> getQualityTestStandardParamByTestStandardId(Long testStandardId) {
+        return R.ok(qualityTestStandardParamService.list(Wrappers.<QualityTestStandardParam>lambdaQuery().eq(QualityTestStandardParam::getTestStandardId, testStandardId)));
     }
 
 }
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java b/src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java
index e5c883c..16788c9 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java
@@ -2,10 +2,14 @@
 
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.quality.pojo.QualityTestStandard;
 import com.ruoyi.quality.pojo.QualityTestStandardParam;
 import com.ruoyi.quality.service.QualityTestStandardParamService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.AllArgsConstructor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.CollectionUtils;
@@ -24,6 +28,7 @@
 @RestController
 @RequestMapping("/qualityTestStandardParam")
 @AllArgsConstructor
+@Tag(name = "妫�娴嬫爣鍑嗗弬鏁�")
 public class QualityTestStandardParamController {
 
     private QualityTestStandardParamService qualityTestStandardParamService;
@@ -34,8 +39,10 @@
      * @return
      */
     @PostMapping("/add")
-    public AjaxResult add(@RequestBody QualityTestStandardParam qualityTestStandardParam) {
-        return AjaxResult.success(qualityTestStandardParamService.save(qualityTestStandardParam));
+    @Operation(summary = "鏂板妫�娴嬫爣鍑嗗弬鏁�")
+    @Log(title = "鏂板妫�娴嬫爣鍑嗗弬鏁�", businessType = BusinessType.INSERT)
+    public R<?> add(@RequestBody QualityTestStandardParam qualityTestStandardParam) {
+        return R.ok(qualityTestStandardParamService.save(qualityTestStandardParam));
     }
 
     /**
@@ -44,11 +51,13 @@
      * @return
      */
     @DeleteMapping("/del")
-    public AjaxResult delQualityTestStandard(@RequestBody List<Integer> ids) {
+    @Operation(summary = "鍒犻櫎妫�娴嬫寚鏍囩淮鎶�")
+    @Log(title = "鍒犻櫎妫�娴嬫寚鏍囩淮鎶�", businessType = BusinessType.DELETE)
+    public R<?> delQualityTestStandard(@RequestBody List<Integer> ids) {
         if(CollectionUtils.isEmpty(ids)){
-            return AjaxResult.error("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
+            return R.fail("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
         }
-        return AjaxResult.success(qualityTestStandardParamService.removeBatchByIds(ids));
+        return R.ok(qualityTestStandardParamService.removeBatchByIds(ids));
     }
 
     /**
@@ -57,8 +66,10 @@
      * @return
      */
     @PostMapping("/update")
-    public AjaxResult update(@RequestBody QualityTestStandardParam qualityTestStandardParam) {
-        return AjaxResult.success(qualityTestStandardParamService.updateById(qualityTestStandardParam));
+    @Operation(summary = "妫�娴嬫寚鏍囩淮鎶や慨鏀�")
+    @Log(title = "妫�娴嬫寚鏍囩淮鎶や慨鏀�", businessType = BusinessType.UPDATE)
+    public R<?> update(@RequestBody QualityTestStandardParam qualityTestStandardParam) {
+        return R.ok(qualityTestStandardParamService.updateById(qualityTestStandardParam));
     }
 
     /**
@@ -66,8 +77,10 @@
      * @return
      */
     @GetMapping("/list")
-    public AjaxResult list(Long testStandardId) {
-        return AjaxResult.success(qualityTestStandardParamService.list(Wrappers.<QualityTestStandardParam>lambdaQuery().eq(QualityTestStandardParam::getTestStandardId,testStandardId)));
+    @Operation(summary = "妫�娴嬫寚鏍囩淮鎶ゆ煡璇�")
+    @Log(title = "妫�娴嬫寚鏍囩淮鎶ゆ煡璇�", businessType = BusinessType.OTHER)
+    public R<?> list(Long testStandardId) {
+        return R.ok(qualityTestStandardParamService.list(Wrappers.<QualityTestStandardParam>lambdaQuery().eq(QualityTestStandardParam::getTestStandardId,testStandardId)));
     }
 
 }
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java b/src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
index 3b20f82..a2222c3 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
@@ -1,9 +1,13 @@
 package com.ruoyi.quality.controller;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.quality.pojo.QualityUnqualified;
 import com.ruoyi.quality.service.IQualityUnqualifiedService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
 
@@ -16,6 +20,7 @@
  */
 @RestController
 @RequestMapping("/quality/qualityUnqualified")
+@Tag(name = "涓嶅悎鏍肩鐞�")
 public class QualityUnqualifiedController {
 
     @Resource
@@ -28,9 +33,11 @@
      * @return
      */
     @PostMapping("/add")
-    public AjaxResult add(@RequestBody QualityUnqualified qualityUnqualified) {
+    @Operation(summary = "鏂板涓嶅悎鏍肩鐞�")
+    @Log(title = "鏂板涓嶅悎鏍肩鐞�", businessType = BusinessType.INSERT)
+    public R<?> add(@RequestBody QualityUnqualified qualityUnqualified) {
         qualityUnqualified.setInspectState(0);
-        return AjaxResult.success(qualityUnqualifiedService.save(qualityUnqualified));
+        return R.ok(qualityUnqualifiedService.save(qualityUnqualified));
     }
 
     /**
@@ -39,13 +46,15 @@
      * @return
      */
     @DeleteMapping("/del")
-    public AjaxResult delQualityUnqualified(@RequestBody List<Integer> ids) {
+    @Operation(summary = "鍒犻櫎涓嶅悎鏍肩鐞�")
+    @Log(title = "鍒犻櫎涓嶅悎鏍肩鐞�", businessType = BusinessType.DELETE)
+    public R<?> delQualityUnqualified(@RequestBody List<Integer> ids) {
        qualityUnqualifiedService.listByIds(ids).stream().forEach(qualityUnqualified -> {
            if (qualityUnqualified.getInspectState()==1){
                throw new RuntimeException("璇ヤ笉鍚堟牸鏁版嵁宸茬粡澶勭悊鏃犳硶鍒犻櫎!");
            }
        });
-        return AjaxResult.success(qualityUnqualifiedService.removeBatchByIds(ids));
+        return R.ok(qualityUnqualifiedService.removeBatchByIds(ids));
     }
 
     /**
@@ -54,8 +63,10 @@
      * @return
      */
     @GetMapping("/{id}")
-    public AjaxResult QualityUnqualifiedDetail(@PathVariable("id") Integer id) {
-        return AjaxResult.success(qualityUnqualifiedService.getUnqualified(id));
+    @Operation(summary = "涓嶅悎鏍肩鐞嗚鎯�")
+    @Log(title = "涓嶅悎鏍肩鐞嗚鎯�", businessType = BusinessType.OTHER)
+    public R<?> QualityUnqualifiedDetail(@PathVariable("id") Integer id) {
+        return R.ok(qualityUnqualifiedService.getUnqualified(id));
     }
 
     /**
@@ -64,8 +75,10 @@
      * @return
      */
     @PostMapping("/update")
-    public AjaxResult update(@RequestBody QualityUnqualified qualityUnqualified) {
-        return AjaxResult.success(qualityUnqualifiedService.updateById(qualityUnqualified));
+    @Operation(summary = "涓嶅悎鏍肩鐞嗕慨鏀�")
+    @Log(title = "涓嶅悎鏍肩鐞嗕慨鏀�", businessType = BusinessType.UPDATE)
+    public R<?> update(@RequestBody QualityUnqualified qualityUnqualified) {
+        return R.ok(qualityUnqualifiedService.updateById(qualityUnqualified));
     }
 
     /**
@@ -75,8 +88,10 @@
      * @return
      */
     @GetMapping("/listPage")
-    public AjaxResult qualityUnqualifiedListPage(Page page, QualityUnqualified qualityUnqualified) {
-        return AjaxResult.success(qualityUnqualifiedService.qualityUnqualifiedListPage(page, qualityUnqualified));
+    @Operation(summary = "涓嶅悎鏍肩鐞嗗垎椤垫煡璇�")
+    @Log(title = "涓嶅悎鏍肩鐞嗗垎椤垫煡璇�", businessType = BusinessType.OTHER)
+    public R<?> qualityUnqualifiedListPage(Page page, QualityUnqualified qualityUnqualified) {
+        return R.ok(qualityUnqualifiedService.qualityUnqualifiedListPage(page, qualityUnqualified));
     }
 
     /**
@@ -85,6 +100,8 @@
      * @param qualityUnqualified
      */
     @PostMapping("/export")
+    @Operation(summary = "涓嶅悎鏍肩鐞嗗鍑�")
+    @Log(title = "涓嶅悎鏍肩鐞嗗鍑�", businessType = BusinessType.EXPORT)
     public void qualityUnqualifiedExport(HttpServletResponse response,QualityUnqualified qualityUnqualified) {
         qualityUnqualifiedService.qualityUnqualifiedExport(response, qualityUnqualified);
     }
@@ -95,8 +112,10 @@
      * @return
      */
     @PostMapping("/deal")
-    public AjaxResult deal(@RequestBody QualityUnqualified qualityUnqualified) {
-        return AjaxResult.success(qualityUnqualifiedService.deal(qualityUnqualified));
+    @Operation(summary = "涓嶅悎鏍肩鐞嗗鐞�")
+    @Log(title = "涓嶅悎鏍肩鐞嗗鐞�", businessType = BusinessType.OTHER)
+    public R<?> deal(@RequestBody QualityUnqualified qualityUnqualified) {
+        return R.ok(qualityUnqualifiedService.deal(qualityUnqualified));
     }
 
 
diff --git a/src/main/java/com/ruoyi/quality/pojo/QualityInspect.java b/src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
index 62b047a..73179fa 100644
--- a/src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
+++ b/src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
@@ -5,9 +5,10 @@
 import com.ruoyi.dto.DateQueryDto;
 import com.ruoyi.framework.aspectj.lang.annotation.Excel;
 import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
-import jakarta.validation.constraints.NotBlank;
+import java.io.Serial;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
@@ -20,6 +21,7 @@
 @TableName(value = "quality_inspect")
 @Data
 public class QualityInspect extends DateQueryDto implements Serializable {
+    @Serial
     private static final long serialVersionUID = 1L;
 
     /**
@@ -32,7 +34,7 @@
      * 绫诲埆(0:鍘熸潗鏂欐楠�;1:杩囩▼妫�楠�;2:鍑哄巶妫�楠�)
      */
     @Excel(name = "绫诲埆",readConverterExp = "0=鍘熸潗鏂欐楠�,1=杩囩▼妫�楠�,2=鍑哄巶妫�楠�")
-    @NotBlank(message = "绫诲埆涓嶈兘涓虹┖!!")
+    @NotNull(message = "绫诲埆涓嶈兘涓虹┖")
     private Integer inspectType;
 
     /**
@@ -72,7 +74,7 @@
     /**
      * 鍏宠仈浜у搧id
      */
-    @NotBlank(message = "浜у搧id涓嶈兘涓虹┖")
+    @NotNull(message = "浜у搧id涓嶈兘涓虹┖")
     private Long productId;
 
     /**
@@ -101,10 +103,12 @@
 
     @Excel(name = "鍚堟牸鏁伴噺")
     @TableField("qualified_quantity")
+    @NotNull(message = "鍚堟牸鏁伴噺涓嶈兘涓虹┖")
     private BigDecimal qualifiedQuantity;
 
     @Excel(name = "涓嶅悎鏍兼暟閲�")
     @TableField("unqualified_quantity")
+    @NotNull(message = "涓嶅悎鏍兼暟閲忎笉鑳戒负绌�")
     private BigDecimal unqualifiedQuantity;
 
     /**
diff --git a/src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java b/src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java
index 31984af..249299a 100644
--- a/src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java
+++ b/src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java
@@ -143,4 +143,7 @@
 
     @TableField(fill = FieldFill.INSERT)
     private Long deptId;
+
+    @Schema(description = "鍏宠仈浜у搧鍨嬪彿id")
+    private Long productModelId;
 }
diff --git a/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java b/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
index 625ff8b..7be310d 100644
--- a/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
+++ b/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -95,6 +95,14 @@
             throw new RuntimeException("璇峰厛鍒ゆ柇鏄惁鍚堟牸");
         }
 
+        if (ObjectUtils.isNull(qualityInspect.getQualifiedQuantity())) {
+            throw new RuntimeException("鍚堟牸鏁伴噺涓嶈兘涓虹┖");
+        }
+
+        if (ObjectUtils.isNull(qualityInspect.getUnqualifiedQuantity())) {
+            throw new RuntimeException("涓嶅悎鏍兼暟閲忎笉鑳戒负绌�");
+        }
+
         // 鍖哄垎鍚堟牸鏁伴噺浠ュ強涓嶅悎鏍煎鐞嗚繘琛屽搴旂殑澶勭悊
         Assert.isTrue(qualityInspect.getQuantity().compareTo(qualityInspect.getQualifiedQuantity().add(qualityInspect.getUnqualifiedQuantity())) == 0,"璇锋鏌ュ悎鏍兼暟閲忓拰涓嶅悎鏍兼暟閲忥紝闇�瑕佸悎鏍兼暟閲�+涓嶅悎鏍兼暟閲忎笌鎬绘暟淇濇寔涓�鑷�");
         if(qualityInspect.getQualifiedQuantity().compareTo(BigDecimal.ZERO) > 0){
@@ -121,6 +129,7 @@
             BeanUtils.copyProperties(qualityInspect, qualityUnqualified);
             qualityUnqualified.setInspectState(0);//寰呭鐞�
             qualityUnqualified.setQuantity(qualityInspect.getUnqualifiedQuantity());
+            qualityUnqualified.setProductModelId(qualityInspect.getProductModelId());
             List<QualityInspectParam> inspectParams = qualityInspectParamService.list(Wrappers.<QualityInspectParam>lambdaQuery().eq(QualityInspectParam::getInspectId, inspect.getId()));
             String text = inspectParams.stream().map(QualityInspectParam::getParameterItem).collect(Collectors.joining(","));
             qualityUnqualified.setDefectivePhenomena(text + "杩欎簺鎸囨爣涓瓨鍦ㄤ笉鍚堟牸");//涓嶅悎鏍肩幇璞�
diff --git a/src/main/java/com/ruoyi/sales/controller/InvoiceLedgerController.java b/src/main/java/com/ruoyi/sales/controller/InvoiceLedgerController.java
deleted file mode 100644
index 0559ff8..0000000
--- a/src/main/java/com/ruoyi/sales/controller/InvoiceLedgerController.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package com.ruoyi.sales.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.framework.aspectj.lang.annotation.Log;
-import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.sales.dto.InvoiceLedgerDto;
-import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
-import com.ruoyi.sales.mapper.InvoiceLedgerFileMapper;
-import com.ruoyi.sales.service.InvoiceLedgerService;
-import io.jsonwebtoken.lang.Collections;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-@RestController
-@RequestMapping("/invoiceLedger")
-@AllArgsConstructor
-public class InvoiceLedgerController {
-
-    private InvoiceLedgerService invoiceLedgerService;
-    private InvoiceLedgerFileMapper invoiceLedgerFileMapper;
-
-    /**
-     * 寮�绁ㄥ彴璐︽柊澧�
-     * @param productDto
-     * @return
-     */
-    @PostMapping("/saveOrUpdate")
-    public AjaxResult invoiceLedgerSaveOrUpdate(@RequestBody InvoiceRegistrationProductDto productDto) {
-        invoiceLedgerService.invoiceLedgerSaveOrUpdate(productDto);
-        return AjaxResult.success();
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐﹀垹闄�
-     * @param ids
-     * @return
-     */
-    @DeleteMapping("/del")
-    public AjaxResult invoiceLedgerDel(@RequestBody List<Integer> ids) {
-        invoiceLedgerService.invoiceLedgerDel(ids);
-        return AjaxResult.success();
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐﹀垎椤垫煡璇�
-     * @param page
-     * @param invoiceLedgerDto
-     * @return
-     */
-    @GetMapping("/page")
-    public AjaxResult invoiceLedgerPage(Page page, InvoiceLedgerDto invoiceLedgerDto) {
-        return AjaxResult.success(invoiceLedgerService.invoiceLedgerPage(page, invoiceLedgerDto));
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐︽枃浠舵煡璇�
-     * @param invoiceLedgerId
-     * @return
-     */
-    @GetMapping("/fileList")
-    public AjaxResult invoiceLedgerFileList(Integer invoiceLedgerId) {
-        return AjaxResult.success(invoiceLedgerService.invoiceLedgerFileList(invoiceLedgerId));
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐︽枃浠跺垹闄�
-     */
-    @DeleteMapping("/delFile")
-    @Log(title = "寮�绁ㄥ彴璐�", businessType = BusinessType.DELETE)
-    public AjaxResult invoiceLedgerDelFile(@RequestBody List<Integer> ids) {
-        if(Collections.isEmpty(ids)) return AjaxResult.error("璇烽�夋嫨瑕佸垹闄ょ殑鏂囦欢");
-        invoiceLedgerFileMapper.deleteBatchIds(ids);
-        return AjaxResult.success();
-    }
-
-
-
-    /**
-     * 寮�绁ㄥ彴璐︽枃浠朵笂浼�
-     * @param file
-     * @return
-     */
-    @PostMapping("/uploadFile")
-    public AjaxResult invoiceLedgerUploadFile(MultipartFile file) {
-        try {
-            return AjaxResult.success(invoiceLedgerService.invoiceLedgerUploadFile(file));
-        }catch (Exception e) {
-            return AjaxResult.error(e.getMessage());
-        }
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐﹀鍑�
-     * @param response
-     * @param invoiceRegistrationProductDto
-     * @return
-     */
-    @PostMapping("/export")
-    public void invoiceLedgerExport(HttpServletResponse response, InvoiceRegistrationProductDto invoiceRegistrationProductDto) {
-        invoiceLedgerService.invoiceLedgerExport(response, invoiceRegistrationProductDto);
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐﹁鎯�
-     * @param id
-     * @return
-     */
-    @GetMapping("/info")
-    public AjaxResult invoiceLedgerInfo(Integer id) {
-        return AjaxResult.success(invoiceLedgerService.invoiceLedgerDetail(id));
-    }
-
-    /**
-     * 鏂囦欢鎻愪氦
-     * @param invoiceLedgerDto
-     * @return
-     */
-    @PostMapping("/commitFile")
-    public AjaxResult invoiceLedgerCommitFile(@RequestBody InvoiceLedgerDto invoiceLedgerDto) {
-        try {
-            invoiceLedgerService.invoiceLedgerCommitFile(invoiceLedgerDto);
-            return AjaxResult.success();
-        }catch (Exception e) {
-            return AjaxResult.error(e.getMessage());
-        }
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐︽煡璇�
-     * @param invoiceLedgerDto
-     * @return
-     */
-    @GetMapping("/list")
-    public AjaxResult invoiceLedgerList(InvoiceLedgerDto invoiceLedgerDto) {
-        return AjaxResult.success(invoiceLedgerService.invoiceLedgerList(invoiceLedgerDto));
-    }
-
-    /**
-     * 瀹㈡埛閿�鍞褰�
-     * @param page
-     * @param invoiceLedgerDto
-     * @return
-     */
-    @GetMapping("/salesAccount")
-    public AjaxResult invoiceLedgerSalesAccount(Page page, InvoiceLedgerDto invoiceLedgerDto) {
-        return AjaxResult.success(invoiceLedgerService.invoiceLedgerSalesAccount(page,invoiceLedgerDto));
-    }
-
-    /**
-     * 鏈湀寮�绁ㄩ噾棰�
-     */
-    @GetMapping("/getInvoiceAmount")
-    public AjaxResult getInvoiceAmount() {
-        try {
-            BigDecimal amount = invoiceLedgerService.getInvoiceAmount();
-            return AjaxResult.success(amount != null ? amount : BigDecimal.ZERO);
-        } catch (Exception e) {
-            return AjaxResult.error("鑾峰彇寮�绁ㄩ噾棰濆け璐ワ細" + e.getMessage());
-        }
-    }
-
-    /**
-     * 浜у搧寮�绁ㄨ褰曟煡璇�
-     * @param page
-     * @param registrationProductDto
-     * @return
-     */
-    @GetMapping("/registrationProductPage")
-    public AjaxResult registrationProductPage(Page page, InvoiceRegistrationProductDto registrationProductDto) {
-
-        return AjaxResult.success(invoiceLedgerService.registrationProductPage(page,registrationProductDto));
-    }
-
-    /**
-     * 浜у搧寮�绁ㄨ鎯�
-     * @param id
-     * @return
-     */
-    @GetMapping("/invoiceLedgerProductInfo")
-    public AjaxResult invoiceLedgerProductDetail(Integer id) {
-        return AjaxResult.success(invoiceLedgerService.invoiceLedgerProductDetail(id));
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐﹀垹闄�
-     * @param invoiceRegistrationProductId
-     * @return
-     */
-    @DeleteMapping("delInvoiceLedger/{invoiceRegistrationProductId}")
-    public AjaxResult delInvoiceLedger(@PathVariable Integer invoiceRegistrationProductId) {
-        try {
-            invoiceLedgerService.delInvoiceLedger(invoiceRegistrationProductId);
-            return AjaxResult.success();
-        }catch (Exception e) {
-            return AjaxResult.error(e.getMessage());
-        }
-    }
-
-}
diff --git a/src/main/java/com/ruoyi/sales/controller/InvoiceRegistrationController.java b/src/main/java/com/ruoyi/sales/controller/InvoiceRegistrationController.java
deleted file mode 100644
index 8ea6c11..0000000
--- a/src/main/java/com/ruoyi/sales/controller/InvoiceRegistrationController.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package com.ruoyi.sales.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.framework.aspectj.lang.annotation.Log;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.sales.dto.InvoiceRegistrationDto;
-import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
-import com.ruoyi.sales.dto.SalesLedgerDto;
-import com.ruoyi.sales.service.InvoiceRegistrationService;
-import io.jsonwebtoken.lang.Collections;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-@RestController
-@RequestMapping("/invoiceRegistration")
-@AllArgsConstructor
-public class InvoiceRegistrationController {
-
-    private InvoiceRegistrationService invoiceRegistrationService;
-
-    /**
-     * 寮�绁ㄧ櫥璁拌褰曟柊澧�
-     * @param salesLedgerDto
-     * @return
-     */
-    @PostMapping("/save")
-    @Log(title = "寮�绁ㄧ櫥璁�", businessType = com.ruoyi.framework.aspectj.lang.enums.BusinessType.INSERT)
-    @Transactional(rollbackFor = Exception.class)
-    public AjaxResult invoiceRegistrationSave(@RequestBody List<SalesLedgerDto> salesLedgerDto) {
-        if(Collections.isEmpty(salesLedgerDto)) return AjaxResult.error("璇烽�夋嫨瑕佷繚瀛樼殑璁板綍");
-        salesLedgerDto.forEach(item ->{
-            invoiceRegistrationService.invoiceRegistrationSave(item);
-        });
-
-        return AjaxResult.success();
-    }
-
-    /**
-     * 寮�绁ㄧ櫥璁板垹闄�
-     * @param ids
-     * @return
-     */
-    @DeleteMapping("/del")
-    public AjaxResult invoiceRegistrationDel(@RequestBody  List<Integer> ids) {
-        invoiceRegistrationService.invoiceRegistrationDel(ids);
-        return AjaxResult.success();
-    }
-
-    /**
-     * 寮�绁ㄨ褰曚慨鏀�
-     * @param invoiceRegistrationDto
-     * @return
-     */
-    @PostMapping("/update")
-    public AjaxResult invoiceRegistrationUpdate(@RequestBody InvoiceRegistrationDto invoiceRegistrationDto) {
-        invoiceRegistrationService.invoiceRegistrationUpdate(invoiceRegistrationDto);
-        return AjaxResult.success();
-    }
-
-    /**
-     * 寮�绁ㄧ櫥璁板垎椤垫煡璇�
-     * @param page
-     * @param invoiceRegistrationDto
-     * @return
-     */
-    @GetMapping("/listPage")
-    public AjaxResult invoiceRegistrationListPage(Page page, InvoiceRegistrationDto invoiceRegistrationDto) {
-        return AjaxResult.success(invoiceRegistrationService.invoiceRegistrationListPage(page, invoiceRegistrationDto));
-    }
-
-    /**
-     * 寮�绁ㄧ櫥璁颁骇鍝佹煡璇�
-     * @param invoiceRegistrationProductDto
-     * @return
-     */
-    @GetMapping("/productList")
-    public AjaxResult invoiceRegistrationProductList(InvoiceRegistrationProductDto invoiceRegistrationProductDto) {
-        return AjaxResult.success(invoiceRegistrationService.invoiceRegistrationProductList(invoiceRegistrationProductDto));
-    }
-
-    /**
-     * 寮�绁ㄧ櫥璁颁骇鍝佽鎯�
-     * @param id
-     * @return
-     */
-    @GetMapping("/detail")
-    public AjaxResult invoiceRegistrationDetail(Integer id) {
-        return AjaxResult.success(invoiceRegistrationService.invoiceRegistrationDetail(id));
-    }
-
-    /**
-     * 寮�绁ㄧ櫥璁板鍑�
-     * @param response
-     * @param invoiceRegistrationDto
-     */
-    @PostMapping("/export")
-    public void invoiceRegistrationExport(HttpServletResponse response, InvoiceRegistrationDto invoiceRegistrationDto) {
-        invoiceRegistrationService.invoiceRegistrationExport(response, invoiceRegistrationDto);
-    }
-}
diff --git a/src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java b/src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java
index 8ad4f02..577508a 100644
--- a/src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java
+++ b/src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java
@@ -1,11 +1,16 @@
 package com.ruoyi.sales.controller;
 
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.basic.service.ICustomerService;
+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.AjaxResult;
+import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.sales.dto.StatisticsTableDto;
 import com.ruoyi.sales.service.impl.MetricStatisticsServiceImpl;
-import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.AllArgsConstructor;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -21,7 +26,8 @@
 @AllArgsConstructor
 public class MetricStatisticsController extends BaseController {
 
-    private MetricStatisticsServiceImpl metricStatisticsService;
+    private final MetricStatisticsServiceImpl metricStatisticsService;
+    private final ICustomerService customerService;
 
     @Operation(summary = "澶撮儴鎬昏")
     @GetMapping("/total")
@@ -35,4 +41,18 @@
         return metricStatisticsService.statisticsTable(statisticsTableDto);
     }
 
+    @GetMapping("/customewTransactions")
+    @Log(title = "瀹㈡埛寰�鏉�", businessType = BusinessType.OTHER)
+    @Operation(summary = "瀹㈡埛寰�鏉�")
+    public R customewTransactions(Page page, String customerName) {
+        return R.ok(customerService.customewTransactions(page,customerName));
+    }
+
+    @GetMapping("/customewTransactionsDetails")
+    @Log(title = "瀹㈡埛寰�鏉ユ槑缁�", businessType = BusinessType.OTHER)
+    @Operation(summary = "瀹㈡埛寰�鏉ユ槑缁�")
+    public R customewTransactionsDetails(Page page, Long customerId) {
+        return R.ok(customerService.customewTransactionsDetails(page,customerId));
+    }
+
 }
diff --git a/src/main/java/com/ruoyi/sales/controller/ReceiptPaymentController.java b/src/main/java/com/ruoyi/sales/controller/ReceiptPaymentController.java
deleted file mode 100644
index 5512a8d..0000000
--- a/src/main/java/com/ruoyi/sales/controller/ReceiptPaymentController.java
+++ /dev/null
@@ -1,191 +0,0 @@
-package com.ruoyi.sales.controller;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.common.utils.bean.BeanUtils;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-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.AjaxResult;
-import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.sales.dto.InvoiceLedgerDto;
-import com.ruoyi.sales.dto.ReceiptPaymentDto;
-import com.ruoyi.sales.dto.ReceiptPaymentRecordDto;
-import com.ruoyi.sales.pojo.ReceiptPayment;
-import com.ruoyi.sales.service.ReceiptPaymentService;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.*;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-@RestController
-@RequestMapping("/receiptPayment")
-@AllArgsConstructor
-public class ReceiptPaymentController extends BaseController {
-
-    private ReceiptPaymentService receiptPaymentService;
-
-    /**
-     * 鍥炴鐧昏鏂板
-     * @param receiptPayment
-     * @return
-     */
-    @PostMapping("/saveOrUpdate")
-    public AjaxResult receiptPaymentSaveOrUpdate (@RequestBody List<ReceiptPayment> receiptPayment) {
-        receiptPaymentService.receiptPaymentSaveOrUpdate(receiptPayment);
-        return AjaxResult.success();
-    }
-
-    /**
-     * 鍥炴鐧昏淇敼
-     * @param receiptPayment
-     * @return
-     */
-    @PostMapping("/update")
-    @Transactional(rollbackFor = Exception.class)
-    public AjaxResult receiptPaymentUpdate (@RequestBody ReceiptPayment receiptPayment) {
-        return AjaxResult.success(receiptPaymentService.receiptPaymentUpdate(receiptPayment));
-    }
-
-    /**
-     * 鍥炴鐧昏鍒犻櫎
-     * @param ids
-     * @return
-     */
-    @DeleteMapping("/del")
-    @Transactional(rollbackFor = Exception.class)
-    public AjaxResult receiptPaymentDel (@RequestBody List<Integer> ids) {
-        return AjaxResult.success(receiptPaymentService.receiptPaymentDel(ids));
-    }
-
-    /**
-     * 瀹㈡埛寰�鏉ヨ褰曟煡璇�
-     * @param receiptPaymentDto
-     * @return
-     */
-    @GetMapping("/customerInteractions")
-    public AjaxResult customerInteractions (InvoiceLedgerDto receiptPaymentDto) {
-        return AjaxResult.success(receiptPaymentService.customerInteractions(receiptPaymentDto));
-    }
-
-    /**
-     * 鍥炴鐧昏璇︽儏
-     * @param id
-     * @return
-     */
-    @GetMapping("/info")
-    public AjaxResult receiptPaymentInfo (Integer id) {
-        return AjaxResult.success(receiptPaymentService.receiptPaymentInfo(id));
-    }
-
-    /**
-     * 鏈湀鍥炴閲戦
-     */
-    @GetMapping("/getReceiptAmount")
-    public AjaxResult getReceiptAmount() {
-        try {
-            BigDecimal receiptAmount = receiptPaymentService.getReceiptAmount();
-            return AjaxResult.success(receiptAmount != null ? receiptAmount : BigDecimal.ZERO);
-        } catch (Exception e) {
-            return AjaxResult.error("鑾峰彇鍥炴閲戦澶辫触锛�" + e.getMessage());
-        }
-    }
-
-    /**
-     * 鏌ヨ宸茬粡缁戝畾鍙戠エ鐨勫紑绁ㄥ彴璐�
-     * @param page
-     * @param receiptPaymentDto
-     * @return
-     */
-    @GetMapping("/bindInvoiceNoRegPage")
-    public AjaxResult bindInvoiceNoRegPage(Page page, ReceiptPaymentDto receiptPaymentDto) {
-        return AjaxResult.success(receiptPaymentService.bindInvoiceNoRegPage(page,receiptPaymentDto));
-    }
-
-    @Schema(description = "瀵煎嚭鍥炴鐧昏")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, String ids) {
-        if (ids == null || ids.isEmpty()) {
-            receiptPaymentService.exportPaymentList(response, null);
-        } else {
-            ArrayList<Long> idList = (ArrayList<Long>) Arrays.stream(ids.split(","))
-                    .map(s -> s.replaceAll("[\\[\\]]", "").trim())
-                    .map(Long::valueOf)
-                    .collect(Collectors.toList());
-            receiptPaymentService.exportPaymentList(response, idList);
-        }
-    }
-
-
-    /**
-     * 寮�绁ㄥ彴璐﹁鎯�
-     * @param id
-     * @return
-     */
-    @GetMapping("/invoiceInfo")
-    public AjaxResult invoiceInfo (Integer id) {
-        return AjaxResult.success(receiptPaymentService.invoiceInfo(id));
-    }
-
-    /**
-     * 鏈湀搴旀敹,鍥炴閲戦
-     */
-    @GetMapping("/getAmountMouth")
-    public AjaxResult getAmountMouth() {
-        return  AjaxResult.success(receiptPaymentService.getAmountMouth());
-    }
-
-    /**
-     * 鏌ヨ鍥炴璁板綍
-     */
-    @GetMapping("/receiptPaymentHistoryList")
-    public TableDataInfo receiptPaymentHistoryList(ReceiptPaymentDto receiptPaymentDto) {
-        startPage();
-        List<ReceiptPaymentDto> list = receiptPaymentService.receiptPaymentHistoryList(receiptPaymentDto);
-        return getDataTable(list);
-    }
-
-    /**
-     * 鏌ヨ鍥炴璁板綍
-     */
-    @GetMapping("/receiptPaymentHistoryListPage")
-    public IPage<ReceiptPaymentDto> receiptPaymentHistoryListPage(Page page, ReceiptPaymentDto receiptPaymentDto) {
-        return receiptPaymentService.receiptPaymentHistoryListPage(page,receiptPaymentDto);
-    }
-
-    /**
-     * 瀵煎嚭鍥炴娴佹按鍒楄〃
-     */
-    @Log(title = "瀵煎嚭鍥炴娴佹按鍒楄〃", businessType = BusinessType.EXPORT)
-    @PostMapping("/exportOne")
-    public void exportOne(HttpServletResponse response, ReceiptPaymentDto salesLedgerDto) {
-        Page page = new Page();
-        page.setCurrent(-1);
-        page.setSize(-1);
-        IPage<ReceiptPaymentDto> salesLedgerIPage = receiptPaymentHistoryListPage(page, salesLedgerDto);
-        ExcelUtil<ReceiptPaymentRecordDto> util = new ExcelUtil<ReceiptPaymentRecordDto>(ReceiptPaymentRecordDto.class);
-        List<ReceiptPaymentRecordDto> receiptPaymentRecordDtos = new ArrayList<>();
-        salesLedgerIPage.getRecords().forEach(receiptPaymentRecordDto -> {
-            ReceiptPaymentRecordDto receiptPaymentRecordDto1 = new ReceiptPaymentRecordDto();
-            BeanUtils.copyProperties(receiptPaymentRecordDto, receiptPaymentRecordDto1);
-            receiptPaymentRecordDtos.add(receiptPaymentRecordDto1);
-        });
-        util.exportExcel(response, receiptPaymentRecordDtos, "瀵煎嚭寮�绁ㄧ櫥璁板垪琛�");
-    }
-
-    /**
-     * 鏌ヨ鍥炴璁板綍涓嶅垎椤�
-     */
-    @GetMapping("/receiptPaymentHistoryListNoPage")
-    public List<ReceiptPaymentDto> receiptPaymentHistoryListNoPage(ReceiptPaymentDto receiptPaymentDto) {
-        return receiptPaymentService.receiptPaymentHistoryListNoPage(receiptPaymentDto);
-    }
-}
diff --git a/src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java b/src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
index ceb3702..44b8563 100644
--- a/src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
+++ b/src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
@@ -1,11 +1,11 @@
 package com.ruoyi.sales.controller;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.basic.enums.ApplicationTypeEnum;
 import com.ruoyi.basic.enums.RecordTypeEnum;
+import com.ruoyi.basic.utils.FileUtil;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
@@ -13,25 +13,20 @@
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.framework.web.page.TableDataInfo;
-import com.ruoyi.sales.dto.InvoiceLedgerDto;
 import com.ruoyi.sales.dto.SalesLedgerDto;
-import com.ruoyi.sales.mapper.InvoiceLedgerMapper;
-import com.ruoyi.sales.mapper.ReceiptPaymentMapper;
-import com.ruoyi.sales.pojo.ReceiptPayment;
 import com.ruoyi.sales.pojo.SalesLedger;
 import com.ruoyi.sales.service.ICommonFileService;
 import com.ruoyi.sales.service.ISalesLedgerService;
 import com.ruoyi.sales.vo.SalesLedgerVo;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.annotations.ApiParam;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
-import com.ruoyi.basic.utils.FileUtil;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -57,8 +52,6 @@
 
     private ISalesLedgerService salesLedgerService;
     private ICommonFileService commonFileService;
-    private InvoiceLedgerMapper invoiceLedgerMapper;
-    private ReceiptPaymentMapper receiptPaymentMapper;
     private final FileUtil fileUtil;
 
     /**
@@ -122,20 +115,6 @@
         if(CollectionUtils.isEmpty(list)){
             return getDataTable(list);
         }
-        List<Long> salesLedgerIds = list.stream().map(SalesLedger::getId).collect(Collectors.toList());
-        List<InvoiceLedgerDto> invoiceLedgerDtoList = invoiceLedgerMapper.invoicedTotal(salesLedgerIds);
-        if(CollectionUtils.isEmpty(invoiceLedgerDtoList)){
-            return getDataTable(list);
-        }
-        for (SalesLedger salesLedger : list) {
-            for (InvoiceLedgerDto invoiceLedgerDto : invoiceLedgerDtoList) {
-                if (salesLedger.getId().intValue() == invoiceLedgerDto.getSalesLedgerId()) {
-                    BigDecimal noInvoiceAmountTotal = salesLedger.getContractAmount().subtract(invoiceLedgerDto.getInvoiceTotal());
-                    salesLedger.setNoInvoiceAmountTotal(noInvoiceAmountTotal);
-                }
-            }
-        }
-
         return getDataTable(list);
     }
 
@@ -267,77 +246,29 @@
         //  鑾峰彇褰撳墠椤垫墍鏈夊彴璐﹁褰曠殑 ID 闆嗗悎
         List<Long> salesLedgerIds = iPage.getRecords().stream().map(SalesLedger::getId).collect(Collectors.toList());
 
-        //  鏌ヨ鍙戠エ淇℃伅鐨勫凡寮�绁ㄩ噾棰�
-        List<InvoiceLedgerDto> invoiceLedgerDtoList = invoiceLedgerMapper.invoicedTotal(salesLedgerIds);
-        if (CollectionUtils.isEmpty(invoiceLedgerDtoList)) {
-            invoiceLedgerDtoList = Collections.emptyList();
-        }
 
-        //  杞崲鍙戠エ鏁版嵁, key 涓哄彴璐D, value 涓鸿鍙拌处鐨勬�诲紑绁ㄩ噾棰�
-        Map<Long, BigDecimal> invoiceTotals = invoiceLedgerDtoList.stream()
-                .filter(dto -> dto.getSalesLedgerId() != null && dto.getInvoiceTotal() != null)
-                .collect(Collectors.toMap(
-                        dto -> dto.getSalesLedgerId().longValue(),
-                        InvoiceLedgerDto::getInvoiceTotal,
-                        BigDecimal::add // 瀛樺湪閲嶅ID鎵ц绱姞
-                ));
 
-        //  鏌ヨ鍥炴/浠樻璁板綍
-        List<ReceiptPayment> receiptPayments = Collections.emptyList();
-        if (!CollectionUtils.isEmpty(salesLedgerIds)) {
-            receiptPayments = receiptPaymentMapper.selectList(new LambdaQueryWrapper<ReceiptPayment>()
-                    .in(ReceiptPayment::getSalesLedgerId, salesLedgerIds));
-        }
 
         //  杞崲鍥炴鏁版嵁, key 涓哄彴璐D, value 涓鸿鍙拌处鐨勬�诲洖娆鹃噾棰�
         Map<Long, BigDecimal> receiptTotals = new HashMap<>();
-        if (!CollectionUtils.isEmpty(receiptPayments)) {
-            for (ReceiptPayment receiptPayment : receiptPayments) {
-                if (receiptPayment.getSalesLedgerId() != null && receiptPayment.getReceiptPaymentAmount() != null) {
-                    //  濡傛灉 key 瀛樺湪鍒欑浉鍔�,涓嶅瓨鍦ㄥ垯鏀惧叆
-                    receiptTotals.merge(receiptPayment.getSalesLedgerId(), receiptPayment.getReceiptPaymentAmount(), BigDecimal::add);
-                }
-            }
-        }
+
 
         for (SalesLedgerVo salesLedgerVo : iPage.getRecords()) {
             Long ledgerId = salesLedgerVo.getId();
             // 鍚堝悓鎬婚噾棰�
             BigDecimal contractAmount = salesLedgerVo.getContractAmount() == null ? BigDecimal.ZERO : salesLedgerVo.getContractAmount();
             // 寮�绁ㄦ�婚鍜屽洖娆炬�婚
-            BigDecimal invoiceTotal = invoiceTotals.getOrDefault(ledgerId, BigDecimal.ZERO);
             BigDecimal receiptPaymentAmountTotal = receiptTotals.getOrDefault(ledgerId, BigDecimal.ZERO);
 
-            //  鏈紑绁ㄩ噾棰� = 鍚堝悓閲戦 - 宸插紑绁ㄩ噾棰�
-            BigDecimal noInvoiceAmountTotal = contractAmount.subtract(invoiceTotal);
-            if (noInvoiceAmountTotal.compareTo(BigDecimal.ZERO) < 0) {
-                noInvoiceAmountTotal = BigDecimal.ZERO;
-            }
-
-            //  寰呭洖娆鹃噾棰� = 宸插紑绁ㄩ噾棰� - 宸插洖娆鹃噾棰�
-            BigDecimal noReceiptPaymentAmountTotal = invoiceTotal.subtract(receiptPaymentAmountTotal);
-            if (noReceiptPaymentAmountTotal.compareTo(BigDecimal.ZERO) < 0) {
-                noReceiptPaymentAmountTotal = BigDecimal.ZERO;
-            }
-
-            salesLedgerVo.setNoInvoiceAmountTotal(noInvoiceAmountTotal);
-            salesLedgerVo.setInvoiceTotal(invoiceTotal);
-            salesLedgerVo.setReceiptPaymentAmountTotal(receiptPaymentAmountTotal);
-            salesLedgerVo.setNoReceiptAmount(noReceiptPaymentAmountTotal);
-
             //  濡傛灉宸茬粡鏈夎繃寮�绁ㄦ垨鍥炴鎿嶄綔,鍒欎笉鍏佽缂栬緫
-            boolean hasInvoiceOperation = invoiceTotal.compareTo(BigDecimal.ZERO) > 0;
             boolean hasReceiptOperation = receiptPaymentAmountTotal.compareTo(BigDecimal.ZERO) > 0;
-            salesLedgerVo.setIsEdit(!(hasInvoiceOperation || hasReceiptOperation));
+            salesLedgerVo.setIsEdit(hasReceiptOperation);
 
             salesLedgerVo.setStorageBlobVOs(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum.FILE, RecordTypeEnum.SALES_LEDGER, ledgerId));
         }
 
         if (ObjectUtils.isNotEmpty(salesLedgerDto.getStatus())) {
             if (salesLedgerDto.getStatus()) {
-                // 娓呴櫎鎵�鏈夆�滄湭寮�绁ㄩ噾棰濃�濅负 0 鐨勮褰�
-                iPage.getRecords().removeIf(salesLedger ->
-                        Objects.equals(salesLedger.getNoInvoiceAmountTotal(), new BigDecimal("0.00")));
                 iPage.setTotal(iPage.getRecords().size());
             }
         }
diff --git a/src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java b/src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
index 9485919..6d45432 100644
--- a/src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
+++ b/src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
@@ -1,8 +1,6 @@
 package com.ruoyi.sales.controller;
 
 import cn.hutool.core.collection.CollUtil;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
@@ -13,7 +11,6 @@
 import com.ruoyi.procurementrecord.utils.StockUtils;
 import com.ruoyi.purchase.dto.SimpleReturnOrderGroupDto;
 import com.ruoyi.purchase.mapper.PurchaseReturnOrderProductsMapper;
-import com.ruoyi.sales.dto.SalesLedgerProductDto;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.service.ISalesLedgerProductService;
 import jakarta.servlet.http.HttpServletResponse;
@@ -43,26 +40,6 @@
 
 
     /**
-     * 鍥炴鐧昏鍒嗛〉鏌ヨ
-     */
-    @GetMapping("/listPageSalesLedger")
-    public AjaxResult listPage(Page page, SalesLedgerProductDto salesLedgerProduct) {
-        IPage<SalesLedgerProductDto> list = salesLedgerProductService.listPage(page,salesLedgerProduct);
-        return AjaxResult.success(list);
-    }
-
-
-    /**
-     * 浠樻鐧昏鍒嗛〉鏌ヨ
-     */
-    @GetMapping("/listPagePurchaseLedger")
-    public AjaxResult listPagePurchaseLedger(Page page, SalesLedgerProductDto salesLedgerProduct) {
-        IPage<SalesLedgerProductDto> list = salesLedgerProductService.listPagePurchaseLedger(page,salesLedgerProduct);
-        return AjaxResult.success(list);
-    }
-
-
-    /**
      * 鏌ヨ浜у搧淇℃伅鍒楄〃
      */
     @GetMapping("/list")
@@ -76,12 +53,6 @@
         Map<Long, BigDecimal> returnOrderGroupDtoMap = groupListByProductIds.stream().collect(Collectors.toMap(SimpleReturnOrderGroupDto::getProductModelId, item -> item.getSumReturnQuantity()));
 
         list.forEach(item -> {
-            if (item.getFutureTickets().compareTo(BigDecimal.ZERO) == 0) {
-                item.setFutureTickets(BigDecimal.ZERO);
-            }
-            if (item.getFutureTicketsAmount().compareTo(BigDecimal.ZERO) == 0) {
-                item.setFutureTicketsAmount(BigDecimal.ZERO);
-            }
             if (item.getApproveStatus() != 2) {
                 if (item.getHasSufficientStock() == 0) {
                     item.setApproveStatus(0);
diff --git a/src/main/java/com/ruoyi/sales/dto/InvoiceLedgerDto.java b/src/main/java/com/ruoyi/sales/dto/InvoiceLedgerDto.java
deleted file mode 100644
index 8f15d3b..0000000
--- a/src/main/java/com/ruoyi/sales/dto/InvoiceLedgerDto.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.ruoyi.sales.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.vo.FileVo;
-import com.ruoyi.sales.pojo.InvoiceLedger;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.util.Date;
-import java.util.List;
-
-@Data
-public class InvoiceLedgerDto extends InvoiceLedger {
-
-    private List<FileVo> fileList;
-
-    @Schema(description = "鏌ヨ鏂囨湰")
-    private String searchText;
-
-    @Schema(description = "瀹㈡埛鍚嶇О")
-    private String customerName;
-
-    @Schema(description = "瀹㈡埛ID")
-    private Integer customerId;
-
-    @Schema(description = "瀹㈡埛鍚堝悓鍙�")
-    private String customerContractNo;
-
-    @Schema(description = "涓氬姟鍛�")
-    private String salesman;
-
-    @Schema(description = "鍙戠エ鏂囦欢鍚�")
-    private String invoiceFileName;
-
-    @Schema(description = "鍥炴閲戦")
-    private BigDecimal receiptPaymentAmount;
-
-    @Schema(description = "鍥炴鏃ユ湡")
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    private Date receiptPaymentDate;
-
-    @Schema(description = "鏈洖娆鹃噾棰�")
-    private BigDecimal unReceiptPaymentAmount;
-
-    @Schema(description = "绋庣巼")
-    private BigDecimal taxRate;
-
-    @Schema(description = "閿�鍞悎鍚屽彿")
-    private String salesContractNo;
-
-    @Schema(description = "閿�鍞悎鍚孖D")
-    private Integer salesLedgerId;
-
-    private String paymentMethod;
-}
diff --git a/src/main/java/com/ruoyi/sales/dto/InvoiceRegistrationDto.java b/src/main/java/com/ruoyi/sales/dto/InvoiceRegistrationDto.java
deleted file mode 100644
index af7dedc..0000000
--- a/src/main/java/com/ruoyi/sales/dto/InvoiceRegistrationDto.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.ruoyi.sales.dto;
-
-import com.ruoyi.sales.pojo.InvoiceRegistration;
-import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-@Data
-public class InvoiceRegistrationDto extends InvoiceRegistration {
-
-    @Schema(description = "寮�绁ㄧ櫥璁颁骇鍝侀泦鍚�")
-    private List<InvoiceRegistrationProductDto> productDtoList;
-
-    @Schema(description = "瀹㈡埛鍚堝悓鍙�")
-    private String customerContractNo;
-
-    @Schema(description = "瀹㈡埛鍚嶇О")
-    private String customerName;
-
-    @Schema(description = "鍚堝悓閲戦")
-    private BigDecimal contractAmount;
-
-    @Schema(description = "鏈紑绁ㄩ噾棰�")
-    private BigDecimal noInvoiceAmountTotal;
-
-}
diff --git a/src/main/java/com/ruoyi/sales/dto/InvoiceRegistrationProductDto.java b/src/main/java/com/ruoyi/sales/dto/InvoiceRegistrationProductDto.java
deleted file mode 100644
index 4f94afc..0000000
--- a/src/main/java/com/ruoyi/sales/dto/InvoiceRegistrationProductDto.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.ruoyi.sales.dto;
-
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.vo.FileVo;
-import com.ruoyi.sales.pojo.CommonFile;
-import com.ruoyi.sales.pojo.InvoiceLedgerFile;
-import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.List;
-
-@Data
-public class InvoiceRegistrationProductDto extends InvoiceRegistrationProduct {
-
-    @Schema(description = "瀹㈡埛鍚堝悓鍙�")
-    private String customerContractNo;
-
-    @Schema(description = "瀹㈡埛鍚嶇О")
-    private String customerName;
-
-    @Schema(description = "閿�鍞悎鍚屽彿")
-    private String salesContractNo;
-
-    @Schema(description = "闄勪欢")
-    private List<FileVo> fileList;
-
-    @Schema(description = "鍙戠エ鍙�")
-    private String invoiceNo;
-
-    @Schema(description = "鍙戠エ閲戦")
-    private BigDecimal invoiceTotal;
-
-    @Schema(description = "寮�绁ㄤ汉")
-    private String invoicePerson;
-
-    @Schema(description = "寮�绁ㄦ椂闂�")
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private LocalDate invoiceDate;
-
-    @TableField(exist = false)
-    private String invoiceDateStart;
-    @TableField(exist = false)
-    private String invoiceDateEnd;
-
-    @Schema(description = "寮�绁ㄥ彴璐d")
-    private Integer invoiceLedgerId;
-
-    @Schema(description = "鍙戠エ鏂囦欢鍚�")
-    private String invoiceFileName;
-
-    private List<InvoiceLedgerFile> commonFiles;
-
-    private String searchText;
-
-    private Boolean status;
-
-    private String projectName;
-
-
-    @TableField(exist = false)
-    private String createTimeStart;
-    @TableField(exist = false)
-    private String createTimeEnd;
-
-
-}
diff --git a/src/main/java/com/ruoyi/sales/dto/ReceiptPaymentDto.java b/src/main/java/com/ruoyi/sales/dto/ReceiptPaymentDto.java
deleted file mode 100644
index fb2004a..0000000
--- a/src/main/java/com/ruoyi/sales/dto/ReceiptPaymentDto.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.ruoyi.sales.dto;
-
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import com.ruoyi.sales.pojo.ReceiptPayment;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.util.Date;
-
-@Data
-public class ReceiptPaymentDto extends ReceiptPayment {
-
-    @Schema(description = "瀹㈡埛鍚堝悓鍙�")
-    @Excel(name = "瀹㈡埛鍚堝悓鍙�")
-    private String customerContractNo;
-
-    @Schema(description = "鐘舵��")
-    @Excel(name = "鐘舵��")
-    private String statusName;
-
-
-    @Schema(description = "瀹㈡埛鍚嶇О")
-    @Excel(name = "瀹㈡埛鍚嶇О")
-    private String customerName;
-
-    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "寮�绁ㄦ棩鏈�",width = 30,dateFormat = "yyyy-MM-dd")
-    @Schema(description = "寮�绁ㄦ棩鏈�")
-    private Date invoiceDate;
-
-    @TableField(exist = false)
-    private String invoiceDateStart;
-    @TableField(exist = false)
-    private String invoiceDateEnd;
-
-    @Schema(description = "鏌ヨ鏂囨湰")
-    private String searchText;
-
-    @Schema(description = "閿�鍞彴璐ales_ledger")
-    @Excel(isExport = false)
-    private Long salesLedgerId;
-
-    @Schema(description = "閿�鍞悎鍚屽彿")
-    @Excel(name = "閿�鍞悎鍚屽彿")
-    private String salesContractNo;
-
-    @Schema(description = "瀹㈡埛鍚嶇ОID")
-    @Excel(isExport = false)
-    private Integer customerId;
-
-    @Schema(description = "鍙戠エ鍙�")
-    @Excel(name = "鍙戠エ鍙�")
-    private String invoiceNo;
-
-    @Schema(description = "鍙戠エ閲戦")
-    @Excel(name = "鍙戠エ閲戦")
-    private BigDecimal invoiceTotal;
-
-    @Schema(description = "绋庣巼锛�%锛�")
-    @Excel(name = "绋庣巼锛�%锛�")
-    private BigDecimal taxRate;
-
-    @Schema(description = "浜у搧澶х被")
-    @Excel(name = "浜у搧澶х被")
-    private String productCategory;
-
-    @Schema(description = "鍥炴閲戦")
-    @Excel(name = "鍥炴閲戦")
-    private BigDecimal receiptPaymentAmountTotal;
-
-    @Schema(description = "寰呭洖娆鹃噾棰�")
-    @Excel(name = "寰呭洖娆鹃噾棰�")
-    private BigDecimal noReceiptAmount;
-
-    @TableField(exist = false)
-    @Excel(isExport = false)
-    private Boolean status;
-
-    @TableField(exist = false)
-    @Excel(isExport = false)
-    private String receiptPaymentDateStart;
-    @TableField(exist = false)
-    @Excel(isExport = false)
-    private String receiptPaymentDateEnd;
-
-    @Schema(description = "椤圭洰鍚嶇О")
-    @Excel(name = "椤圭洰鍚嶇О")
-    private String projectName;
-
-
-}
diff --git a/src/main/java/com/ruoyi/sales/dto/ReceiptPaymentExeclDto.java b/src/main/java/com/ruoyi/sales/dto/ReceiptPaymentExeclDto.java
deleted file mode 100644
index 4212961..0000000
--- a/src/main/java/com/ruoyi/sales/dto/ReceiptPaymentExeclDto.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.ruoyi.sales.dto;
-
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Data
-public class ReceiptPaymentExeclDto {
-
-    @Schema(description = "閿�鍞悎鍚屽彿")
-    @Excel(name = "閿�鍞悎鍚屽彿",sort = 1)
-    private String salesContractNo;
-
-    @Schema(description = "瀹㈡埛鍚堝悓鍙�")
-    @Excel(name = "瀹㈡埛鍚堝悓鍙�",sort = 2)
-
-    private String customerContractNo;
-
-    @Schema(description = "瀹㈡埛鍚嶇О")
-    @Excel(name = "瀹㈡埛鍚嶇О",sort = 3)
-    private String customerName;
-
-    @Schema(description = "浜у搧澶х被")
-    @Excel(name = "浜у搧澶х被",sort = 4)
-    private String productCategory;
-
-    @Schema(description = "椤圭洰鍚嶇О")
-    @Excel(name = "椤圭洰鍚嶇О",sort = 5)
-    private String projectName;
-
-    @Schema(description = "鍙戠エ鍙�")
-    @Excel(name = "鍙戠エ鍙�",sort = 6)
-    private String invoiceNo;
-
-    @Schema(description = "鍙戠エ閲戦")
-    @Excel(name = "鍙戠エ閲戦",sort = 7)
-    private BigDecimal invoiceTotal;
-
-    @Schema(description = "绋庣巼锛�%锛�")
-    @Excel(name = "绋庣巼锛�%锛�",sort = 8)
-    private BigDecimal taxRate;
-
-    @Schema(description = "鍥炴閲戦")
-    @Excel(name = "鍥炴閲戦",sort = 9)
-    private BigDecimal receiptPaymentAmountTotal;
-
-    @Schema(description = "寰呭洖娆鹃噾棰�")
-    @Excel(name = "寰呭洖娆鹃噾棰�",sort = 10)
-    private BigDecimal noReceiptAmount;
-
-
-
-
-}
diff --git a/src/main/java/com/ruoyi/sales/dto/ReceiptPaymentRecordDto.java b/src/main/java/com/ruoyi/sales/dto/ReceiptPaymentRecordDto.java
deleted file mode 100644
index c2410e8..0000000
--- a/src/main/java/com/ruoyi/sales/dto/ReceiptPaymentRecordDto.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.ruoyi.sales.dto;
-
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.Date;
-
-/**
- * @author :yys
- * @date : 2025/10/31 10:17
- */
-@Data
-public class ReceiptPaymentRecordDto {
-
-    @Schema(description = "瀹㈡埛鍚堝悓鍙�")
-    @Excel(name = "瀹㈡埛鍚堝悓鍙�")
-    private String customerContractNo;
-
-    @Schema(description = "瀹㈡埛鍚嶇О")
-    @Excel(name = "瀹㈡埛鍚嶇О")
-    private String customerName;
-
-    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "鐧昏鏃ユ湡",width = 30,dateFormat = "yyyy-MM-dd")
-    @Schema(description = "鐧昏鏃ユ湡")
-    private LocalDateTime createTime;
-
-    @Schema(description = "閿�鍞悎鍚屽彿")
-    @Excel(name = "閿�鍞悎鍚屽彿")
-    private String salesContractNo;
-
-    @Schema(description = "鍥炴閲戦")
-    @Excel(name = "鍥炴閲戦")
-    private BigDecimal receiptPaymentAmount;
-
-    @Schema(description = "椤圭洰鍚嶇О")
-    @Excel(name = "椤圭洰鍚嶇О")
-    private String projectName;
-
-    @Schema(description = "鍥炴褰㈠紡 0鐢垫眹1鎵垮厬")
-    @Excel(name = "鍥炴褰㈠紡",readConverterExp = "0=鐢垫眹,1=鎵垮厬")
-    private String receiptPaymentType;
-
-    @Schema(description = "鐧昏浜�")
-    @Excel(name = "鐧昏浜�")
-    private String registrant;
-
-    @Schema(description = "鏉ユ鏃ユ湡")
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "鏉ユ鏃ユ湡",width = 30,dateFormat = "yyyy-MM-dd")
-    private LocalDate receiptPaymentDate;
-
-}
diff --git a/src/main/java/com/ruoyi/sales/dto/SalesLedgerImportDto.java b/src/main/java/com/ruoyi/sales/dto/SalesLedgerImportDto.java
index 2430d10..0023e17 100644
--- a/src/main/java/com/ruoyi/sales/dto/SalesLedgerImportDto.java
+++ b/src/main/java/com/ruoyi/sales/dto/SalesLedgerImportDto.java
@@ -43,6 +43,10 @@
     @Excel(name = "绛捐鏃ユ湡", width = 30, dateFormat = "yyyy-MM-dd")
     private Date executionDate;
 
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "浜や粯鏃ユ湡", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date deliveryDate;
+
     @Schema(description = "浠樻鏂瑰紡")
     @Excel(name = "浠樻鏂瑰紡")
     private String paymentMethod;
diff --git a/src/main/java/com/ruoyi/sales/dto/SalesLedgerProductImportDto.java b/src/main/java/com/ruoyi/sales/dto/SalesLedgerProductImportDto.java
index 2c95909..9f05b60 100644
--- a/src/main/java/com/ruoyi/sales/dto/SalesLedgerProductImportDto.java
+++ b/src/main/java/com/ruoyi/sales/dto/SalesLedgerProductImportDto.java
@@ -73,6 +73,9 @@
     @Excel(name = "鏄惁璐ㄦ", readConverterExp = "0=鍚�,1=鏄�")
     private Boolean isChecked;
 
-
-
+    /**
+     * 鏄惁鐢熶骇
+     */
+    @Excel(name = "鏄惁鐢熶骇", readConverterExp = "0=鍚�,1=鏄�")
+    private Integer isProduction;
 }
diff --git a/src/main/java/com/ruoyi/sales/excel/InvoiceLedgerExcelDto.java b/src/main/java/com/ruoyi/sales/excel/InvoiceLedgerExcelDto.java
index b5d09a7..82da2a9 100644
--- a/src/main/java/com/ruoyi/sales/excel/InvoiceLedgerExcelDto.java
+++ b/src/main/java/com/ruoyi/sales/excel/InvoiceLedgerExcelDto.java
@@ -1,19 +1,12 @@
 package com.ruoyi.sales.excel;
 
-import com.baomidou.mybatisplus.annotation.FieldFill;
-import com.baomidou.mybatisplus.annotation.TableField;
 import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.vo.FileVo;
 import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import com.ruoyi.sales.pojo.InvoiceLedger;
-import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
 import java.math.BigDecimal;
 import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.List;
 
 @Data
 public class InvoiceLedgerExcelDto {
diff --git a/src/main/java/com/ruoyi/sales/excel/InvoiceRegisAndProductExcelDto.java b/src/main/java/com/ruoyi/sales/excel/InvoiceRegisAndProductExcelDto.java
deleted file mode 100644
index 8979504..0000000
--- a/src/main/java/com/ruoyi/sales/excel/InvoiceRegisAndProductExcelDto.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.ruoyi.sales.excel;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-
-@Data
-public class InvoiceRegisAndProductExcelDto {
-
-    @Excel(name = "閿�鍞悎鍚屽彿")
-    private String salesContractNo;
-
-    @Excel(name = "瀹㈡埛鍚堝悓鍙�")
-    private String customerContractNo;
-
-    @Excel(name = "瀹㈡埛鍚嶇О")
-    private String customerName;
-
-    @Excel(name =  "涓氬姟鍛�")
-    private String salesman;
-
-    @Excel(name = "椤圭洰鍚嶇О")
-    private String projectName;
-
-    @Excel(name =  "鍚堝悓閲戦")
-    private BigDecimal contractAmount;
-
-    @Excel(name =  "浜у搧澶х被")
-    private String productCategory;
-
-    @Excel(name =  "瑙勬牸鍨嬪彿")
-    private String specificationModel;
-
-    @Excel(name =  "鍗曚綅")
-    private String unit;
-
-    @Excel(name =  "鏁伴噺")
-    private BigDecimal quantity;
-
-    @Excel(name =  "绋庣巼%")
-    private BigDecimal taxRate;
-
-    @Excel(name = "鍚◣鍗曚环")
-    private BigDecimal taxInclusiveUnitPrice;
-
-    @Excel(name = "鍚◣鎬讳环")
-    private BigDecimal taxInclusiveTotalPrice;
-
-    @Excel(name ="涓嶅惈绋庢�讳环")
-    private BigDecimal taxExclusiveTotalPrice;
-
-    @Excel(name ="鍙戠エ绫诲瀷")
-    private String invoiceType;
-
-    @Excel(name ="寮�绁ㄦ暟")
-    private Integer invoiceNum;
-
-    @Excel(name ="鏈紑绁ㄦ暟")
-    private Integer noInvoiceNum;
-
-    @Excel(name ="寮�绁ㄩ噾棰�")
-    private BigDecimal invoiceAmount;
-
-    @Excel(name ="鏈紑绁ㄩ噾棰�")
-    private BigDecimal noInvoiceAmount;
-
-
-}
diff --git a/src/main/java/com/ruoyi/sales/mapper/InvoiceLedgerFileMapper.java b/src/main/java/com/ruoyi/sales/mapper/InvoiceLedgerFileMapper.java
deleted file mode 100644
index b8c0b4c..0000000
--- a/src/main/java/com/ruoyi/sales/mapper/InvoiceLedgerFileMapper.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.ruoyi.sales.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.ruoyi.sales.pojo.InvoiceLedger;
-import com.ruoyi.sales.pojo.InvoiceLedgerFile;
-
-public interface InvoiceLedgerFileMapper extends BaseMapper<InvoiceLedgerFile> {
-}
diff --git a/src/main/java/com/ruoyi/sales/mapper/InvoiceLedgerMapper.java b/src/main/java/com/ruoyi/sales/mapper/InvoiceLedgerMapper.java
deleted file mode 100644
index a797024..0000000
--- a/src/main/java/com/ruoyi/sales/mapper/InvoiceLedgerMapper.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.ruoyi.sales.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.sales.dto.InvoiceLedgerDto;
-import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
-import com.ruoyi.sales.pojo.InvoiceLedger;
-import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-public interface InvoiceLedgerMapper extends BaseMapper<InvoiceLedger> {
-
-    /**
-     * 寮�绁ㄥ彴璐﹀垎椤垫煡璇�
-     * @param page
-     * @param invoiceLedgerDto
-     * @return
-     */
-    IPage<InvoiceLedgerDto> invoiceLedgerPage(Page page, @Param("invoiceLedgerDto") InvoiceLedgerDto invoiceLedgerDto);
-
-    /**
-     * 寮�绁ㄥ彴璐︽煡璇�
-     * @param invoiceLedgerDto
-     * @return
-     */
-    List<InvoiceLedgerDto> invoiceLedgerList(@Param("invoiceLedgerDto") InvoiceLedgerDto invoiceLedgerDto);
-
-    /**
-     * 寮�绁ㄥ彴璐﹁鎯�
-     * @param id
-     * @return
-     */
-    InvoiceLedgerDto invoiceLedgerInfo(Integer id);
-
-    /**
-     * 瀹㈡埛閿�鍞褰�
-     * @param page
-     * @param invoiceLedgerDto
-     * @return
-     */
-    IPage<InvoiceLedgerDto> invoiceLedgerSalesAccount(Page page,@Param("invoiceLedgerDto") InvoiceLedgerDto invoiceLedgerDto);
-
-    /**
-     * 浜у搧寮�绁ㄥ彴璐﹁鎯�
-     * @param id
-     * @return
-     */
-    InvoiceRegistrationProductDto invoiceLedgerProductInfo(Integer id);
-
-    /**
-     * 鏍规嵁閿�鍞悎鍚岃绠楀凡寮�绁ㄩ噾棰�
-     * @param salesLedgerIds
-     * @return
-     */
-    List<InvoiceLedgerDto> invoicedTotal(List<Long> salesLedgerIds);
-
-}
diff --git a/src/main/java/com/ruoyi/sales/mapper/InvoiceRegistrationMapper.java b/src/main/java/com/ruoyi/sales/mapper/InvoiceRegistrationMapper.java
deleted file mode 100644
index 54425c4..0000000
--- a/src/main/java/com/ruoyi/sales/mapper/InvoiceRegistrationMapper.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.ruoyi.sales.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.sales.dto.InvoiceRegistrationDto;
-import com.ruoyi.sales.excel.InvoiceRegisAndProductExcelDto;
-import com.ruoyi.sales.pojo.InvoiceRegistration;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-public interface InvoiceRegistrationMapper extends BaseMapper<InvoiceRegistration> {
-
-    /**
-     * 寮�绁ㄧ櫥璁板垎椤垫煡璇�
-     * @param page
-     * @param invoiceRegistrationDto
-     * @return
-     */
-    IPage<InvoiceRegistrationDto> invoiceRegistrationListPage(Page page, @Param("invoiceRegistrationDto") InvoiceRegistrationDto invoiceRegistrationDto);
-
-    /**
-     * 寮�绁ㄧ櫥璁板鍑烘暟鎹煡璇�
-     * @return
-     */
-    List<InvoiceRegisAndProductExcelDto> invoiceRegisAndProductExcelDtoList();
-}
diff --git a/src/main/java/com/ruoyi/sales/mapper/InvoiceRegistrationProductMapper.java b/src/main/java/com/ruoyi/sales/mapper/InvoiceRegistrationProductMapper.java
deleted file mode 100644
index 1c1ae7a..0000000
--- a/src/main/java/com/ruoyi/sales/mapper/InvoiceRegistrationProductMapper.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.ruoyi.sales.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.sales.dto.InvoiceRegistrationProductDto;
-import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-public interface InvoiceRegistrationProductMapper extends BaseMapper<InvoiceRegistrationProduct> {
-
-    /**
-     * 寮�绁ㄧ櫥璁颁骇鍝佹煡璇�
-     * @param invoiceRegistrationProductDto
-     * @return
-     */
-    List<InvoiceRegistrationProductDto> invoiceRegistrationProductList(@Param("invoiceRegistrationProductDto") InvoiceRegistrationProductDto invoiceRegistrationProductDto);
-
-    /**
-     * 寮�绁ㄧ櫥璁颁骇鍝佸垎椤垫煡璇�
-     * @param page
-     * @param invoiceRegistrationProductDto
-     * @return
-     */
-    IPage<InvoiceRegistrationProductDto> invoiceRegistrationProductPage(Page page, @Param("invoiceRegistrationProductDto") InvoiceRegistrationProductDto invoiceRegistrationProductDto);
-}
diff --git a/src/main/java/com/ruoyi/sales/mapper/ReceiptPaymentMapper.java b/src/main/java/com/ruoyi/sales/mapper/ReceiptPaymentMapper.java
deleted file mode 100644
index 576ebd7..0000000
--- a/src/main/java/com/ruoyi/sales/mapper/ReceiptPaymentMapper.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.ruoyi.sales.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.sales.dto.CustomerInteractionDto;
-import com.ruoyi.sales.dto.InvoiceLedgerDto;
-import com.ruoyi.sales.dto.ReceiptPaymentDto;
-import com.ruoyi.sales.dto.ReceiptPaymentExeclDto;
-import com.ruoyi.sales.pojo.ReceiptPayment;
-import org.apache.ibatis.annotations.Param;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.List;
-
-public interface ReceiptPaymentMapper extends BaseMapper<ReceiptPayment> {
-
-    IPage<ReceiptPaymentDto> receiptPaymentListPage(Page page, @Param("receiptPaymentDto") ReceiptPaymentDto receiptPaymentDto);
-
-    ReceiptPaymentDto receiptPaymentInfo(Integer id);
-
-    /**
-     * 鏌ヨ宸茬粡缁戝畾鍙戠エ鐨勫紑绁ㄥ彴璐�
-     * @param page
-     * @param receiptPaymentDto
-     * @return
-     */
-    IPage<ReceiptPaymentDto> bindInvoiceNoRegPage(Page page, @Param("req") ReceiptPaymentDto receiptPaymentDto);
-
-    /**
-     * 寮�绁ㄥ彴璐﹁鎯�
-     * @param id
-     * @return
-     */
-    InvoiceLedgerDto invoiceInfo(Integer id);
-
-    /**
-     * 璁$畻鍓嶅灏戞潯鏁版嵁鍥炴閲戦缁煎悎
-     * @param customerId
-     * @param total
-     * @return
-     */
-    BigDecimal getReceiptAmount(@Param("customerId") Integer customerId, @Param("total") long total);
-
-    /**
-     * 鏌ヨ鍥炴璁板綍
-     */
-    List<ReceiptPaymentDto> receiptPaymentHistoryList(@Param("params") ReceiptPaymentDto receiptPaymentDto);
-
-    /**
-     * 鏌ヨ鍥炴璁板綍鍒嗛〉
-     */
-    IPage<ReceiptPaymentDto> receiptPaymentHistoryListPage(Page page,@Param("params") ReceiptPaymentDto receiptPaymentDto);
-
-    /**
-     * 瀹㈡埛寰�鏉ヨ褰曟煡璇�
-     * @param receiptPaymentDto
-     * @return
-     */
-    List<CustomerInteractionDto> customerInteractions (ReceiptPaymentDto receiptPaymentDto);
-
-    /**
-     * 瀹㈡埛鍥炴璁板綍鏌ヨ
-     * @param invoiceLedgerDto
-     * @return
-     */
-    List<InvoiceLedgerDto> invoiceLedgerSalesAccount(@Param("invoiceLedgerDto") InvoiceLedgerDto invoiceLedgerDto);
-
-    /**
-     * 鏌ヨ鍥炴璁板綍涓嶅垎椤�
-     */
-    List<ReceiptPaymentDto> receiptPaymentHistoryListNoPage( @Param("params") ReceiptPaymentDto receiptPaymentDto);
-
-    /**
-     * 閫氳繃寮�绁ㄧ櫥璁颁骇鍝乮d鏌ヨ鏄惁宸茬粡鏈夊洖娆捐褰�
-     * @param invoiceRegistrationProductId
-     * @return
-     */
-    List<ReceiptPayment> receiptPaymentListByProdRegId(Integer invoiceRegistrationProductId);
-
-    List<ReceiptPaymentDto> bindInvoiceNoRegListAll();
-
-    List<ReceiptPaymentExeclDto> bindInvoiceNoRegListByIds(List<Long> ids,Long tenantId);
-
-
-}
diff --git a/src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java b/src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java
index f8e22b9..2615d19 100644
--- a/src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java
+++ b/src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java
@@ -5,7 +5,6 @@
 import com.ruoyi.common.config.MyBaseMapper;
 import com.ruoyi.purchase.dto.ProcurementBusinessSummaryDto;
 import com.ruoyi.sales.dto.LossProductModelDto;
-import com.ruoyi.sales.dto.SalesLedgerProductDto;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import org.apache.ibatis.annotations.Param;
 
@@ -26,10 +25,6 @@
     List<SalesLedgerProduct> selectSalesLedgerProductList(@Param("salesLedgerProduct") SalesLedgerProduct salesLedgerProduct);
 
     SalesLedgerProduct selectSalesLedgerProductByMainId(@Param("productMainId") Long productMainId);
-
-    IPage<SalesLedgerProductDto> listPage(Page page, @Param("req") SalesLedgerProductDto salesLedgerProduct);
-
-    IPage<SalesLedgerProductDto> listPagePurchaseLedger(Page page, @Param("req") SalesLedgerProductDto salesLedgerProduct);
 
     IPage<ProcurementBusinessSummaryDto> procurementBusinessSummaryListPage(Page page, @Param("req") ProcurementBusinessSummaryDto procurementBusinessSummaryDto);
 
diff --git a/src/main/java/com/ruoyi/sales/pojo/InvoiceLedger.java b/src/main/java/com/ruoyi/sales/pojo/InvoiceLedger.java
deleted file mode 100644
index ef85b3a..0000000
--- a/src/main/java/com/ruoyi/sales/pojo/InvoiceLedger.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.ruoyi.sales.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.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-
-@Data
-public class InvoiceLedger {
-
-    /**
-     * 搴忓彿
-     */
-    @TableId(type = IdType.AUTO)
-    private Integer id;
-
-    @Schema(description = "invoice_registration_product琛ㄤ富閿�")
-    private Integer invoiceRegistrationProductId;
-
-    @Schema(description = "鍙戠エ鍙�")
-    private String invoiceNo;
-
-    @Schema(description = "鍙戠エ閲戦")
-    private BigDecimal invoiceTotal;
-
-    @Schema(description = "寮�绁ㄤ汉")
-    private String invoicePerson;
-
-    @Schema(description = "寮�绁ㄦ椂闂�")
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private LocalDate invoiceDate;
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    @Schema(description = "鍒涘缓鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @Schema(description = "淇敼鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    @Schema(description = "淇敼鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-
-    @Schema(description = "绉熸埛ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/sales/pojo/InvoiceLedgerFile.java b/src/main/java/com/ruoyi/sales/pojo/InvoiceLedgerFile.java
deleted file mode 100644
index 0d4a4f5..0000000
--- a/src/main/java/com/ruoyi/sales/pojo/InvoiceLedgerFile.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.ruoyi.sales.pojo;
-
-import com.baomidou.mybatisplus.annotation.FieldFill;
-import com.baomidou.mybatisplus.annotation.TableField;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-@Data
-public class InvoiceLedgerFile {
-
-    @Schema(description = "鏂囦欢ID")
-    private Long id;
-
-    @Schema(description = "鏂囦欢鍚嶇О")
-    private String name;
-
-    @Schema(description = "鏂囦欢璺緞")
-    private String url;
-
-    @Schema(description = "鏂囦欢澶у皬")
-    private int fileSize;
-
-    @Schema(description = "寮�绁ㄥ彴璐D")
-    private Integer invoiceLedgerId;
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    @Schema(description = "淇敼鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    @Schema(description = "鍒涘缓鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @Schema(description = "淇敼鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-
-    @Schema(description = "绉熸埛ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/sales/pojo/InvoiceRegistration.java b/src/main/java/com/ruoyi/sales/pojo/InvoiceRegistration.java
deleted file mode 100644
index e7a926b..0000000
--- a/src/main/java/com/ruoyi/sales/pojo/InvoiceRegistration.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.ruoyi.sales.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-@Data
-@TableName("invoice_registration")
-public class InvoiceRegistration {
-
-    /**
-     * 搴忓彿
-     */
-    @TableId(type = IdType.AUTO)
-    private Integer id;
-
-    @Schema(description = "閿�鍞彴璐ales_ledger涓婚敭")
-    private Integer salesLedgerId;
-
-    @Schema(description = "閿�鍞悎鍚屽彿")
-    private String salesContractNo;
-
-    @Schema(description = "瀹㈡埛鍚嶇ОID")
-    private Integer customerId;
-
-    @Schema(description = "涓氬姟鍛�")
-    private String salesman;
-
-    @Schema(description = "椤圭洰鍚嶇О")
-    private String projectName;
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    @Schema(description = "鍒涘缓鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @Schema(description = "淇敼鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    @Schema(description = "淇敼鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-
-    @Schema(description = "绉熸埛ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/sales/pojo/InvoiceRegistrationProduct.java b/src/main/java/com/ruoyi/sales/pojo/InvoiceRegistrationProduct.java
deleted file mode 100644
index 75ef549..0000000
--- a/src/main/java/com/ruoyi/sales/pojo/InvoiceRegistrationProduct.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.ruoyi.sales.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-
-@TableName("invoice_registration_product")
-@Data
-public class InvoiceRegistrationProduct {
-
-    /**
-     * 搴忓彿
-     */
-    @TableId(type = IdType.AUTO)
-    private Integer id;
-
-    @Schema(description = "鍏宠仈閿�鍞彴璐︿富琛ㄤ富閿�")
-    private Integer salesLedgerId;
-
-    @Schema(description = "sales_ledger_product涓婚敭")
-    private Integer salesLedgerProductId;
-
-    @Schema(description = "寮�绁ㄧ櫥璁拌〃invoice_registration涓婚敭")
-    private Integer invoiceRegistrationId;
-
-    @Schema(description = "浜у搧澶х被")
-    private String productCategory;
-
-    @Schema(description = "瑙勬牸鍨嬪彿")
-    private String specificationModel;
-
-    @Schema(description = "鍗曚綅")
-    private String unit;
-
-    @Schema(description = "鏁伴噺")
-    private BigDecimal quantity;
-
-    @Schema(description = "绋庣巼")
-    private BigDecimal taxRate;
-
-    @Schema(description = "鍚◣鍗曚环")
-    private BigDecimal taxInclusiveUnitPrice;
-
-    @Schema(description = "鍚◣鎬讳环")
-    private BigDecimal taxInclusiveTotalPrice;
-
-    @Schema(description = "涓嶅惈绋庢�讳环")
-    private BigDecimal taxExclusiveTotalPrice;
-
-    @Schema(description = "鍙戠エ绫诲瀷")
-    private String invoiceType;
-
-    @Schema(description = "寮�绁ㄦ暟")
-    private BigDecimal invoiceNum;
-
-    @Schema(description = "鏈紑绁ㄦ暟")
-    private BigDecimal noInvoiceNum;
-
-    @Schema(description = "寮�绁ㄩ噾棰�")
-    private BigDecimal invoiceAmount;
-
-    @Schema(description = "鏈紑绁ㄩ噾棰�")
-    private BigDecimal noInvoiceAmount;
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    private LocalDateTime createTime;
-
-    @Schema(description = "鍒涘缓鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @Schema(description = "淇敼鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    @Schema(description = "淇敼鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-
-    @Schema(description = "绉熸埛ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/sales/pojo/ReceiptPayment.java b/src/main/java/com/ruoyi/sales/pojo/ReceiptPayment.java
deleted file mode 100644
index 132bfa2..0000000
--- a/src/main/java/com/ruoyi/sales/pojo/ReceiptPayment.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.ruoyi.sales.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.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.List;
-
-@Data
-public class ReceiptPayment {
-
-    /**
-     * 搴忓彿
-     */
-    @TableId(type = IdType.AUTO)
-    private Integer id;
-
-    @Schema(description = "鍥炴褰㈠紡 0鐢垫眹1鎵垮厬")
-    private String receiptPaymentType;
-
-    @Schema(description = "鍥炴閲戦")
-    private BigDecimal receiptPaymentAmount;
-
-    @Schema(description = "鐧昏浜�")
-    private String registrant;
-
-    @Schema(description = "invoice_ledger寮�绁ㄥ彴璐︿富閿甀D")
-    private Integer invoiceLedgerId;
-
-    @Schema(description = "sales_ledger閿�鍞彴璐︿富閿甀D")
-    private Long salesLedgerId;
-
-    @Schema(description = "sales_ledger_product閿�鍞彴璐︿骇鍝佷富閿甀D")
-    private Long salesLedgerProductId;
-
-    @Schema(description = "鏉ユ鏃ユ湡")
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private LocalDate receiptPaymentDate;
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    private LocalDateTime createTime;
-
-    @Schema(description = "鍒涘缓鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    @Schema(description = "淇敼鏃堕棿")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private LocalDateTime updateTime;
-
-    @Schema(description = "淇敼鐢ㄦ埛")
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-
-    @Schema(description = "绉熸埛ID")
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
diff --git a/src/main/java/com/ruoyi/sales/pojo/SalesLedger.java b/src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
index bc4d02c..00736ba 100644
--- a/src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
+++ b/src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
@@ -1,15 +1,15 @@
 package com.ruoyi.sales.pojo;
 
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.util.Date;
-
 import com.baomidou.mybatisplus.annotation.*;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.ruoyi.framework.aspectj.lang.annotation.Excel;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.Date;
 
 /**
  * 閿�鍞彴璐﹀璞� sales_ledger
@@ -103,26 +103,8 @@
     @Excel(name = "鍚堝悓閲戦")
     private BigDecimal contractAmount;
 
-    @TableField(exist = false)
-    @Schema(description = "鏈紑绁ㄩ噾棰�(鍏�)")
-    @Excel(name = "鏈紑绁ㄩ噾棰�")
-    private BigDecimal noInvoiceAmountTotal = BigDecimal.ZERO;
-
     @Schema(description = "绛捐鏃ユ湡")
     private LocalDate executionDate;
-
-    @TableField(exist = false)
-    @Schema(description = "宸插紑绁ㄩ噾棰�(鍏�)")
-    @Excel(name = "宸插紑绁ㄩ噾棰�")
-    private BigDecimal invoiceTotal = BigDecimal.ZERO;
-
-    @TableField(exist = false)
-    @Schema(description = "鍥炴閲戦")
-    private BigDecimal receiptPaymentAmountTotal = BigDecimal.ZERO;
-
-    @TableField(exist = false)
-    @Schema(description = "寰呭洖娆鹃噾棰�")
-    private BigDecimal noReceiptAmount = BigDecimal.ZERO;
 
     @Schema(description = "浠樻鏂瑰紡")
     private String paymentMethod;
diff --git a/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java b/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
index fa528a9..08bb128 100644
--- a/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
+++ b/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -62,12 +62,6 @@
     private String unit;
 
     /**
-     * 鐢熶骇鐐掓満
-     */
-    @Excel(name = "鐢熶骇鐐掓満")
-    private String speculativeTradingName;
-
-    /**
      * 鏁伴噺
      */
     @Excel(name = "鏁伴噺")
@@ -110,46 +104,6 @@
     private Integer type;
 
     /**
-     * 鏈鏉ョエ鏁�
-     */
-    private BigDecimal ticketsNum=BigDecimal.ZERO;
-
-    /**
-     * 鏈鏉ョエ閲戦(鍏�)
-     */
-    private BigDecimal ticketsAmount=BigDecimal.ZERO;
-
-    /**
-     * 鏈潵绁ㄦ暟
-     */
-    private BigDecimal futureTickets=BigDecimal.ZERO;
-
-    /**
-     * 鏈潵绁ㄩ噾棰�(鍏�)
-     */
-    private BigDecimal futureTicketsAmount=BigDecimal.ZERO;
-
-    @Schema(description = "寮�绁ㄦ暟")
-    private BigDecimal invoiceNum = BigDecimal.ZERO;
-
-    @Schema(description = "鏈紑绁ㄦ暟")
-    private BigDecimal noInvoiceNum = BigDecimal.ZERO;
-
-    @Schema(description = "寮�绁ㄩ噾棰�")
-    private BigDecimal invoiceAmount = BigDecimal.ZERO;
-
-    @Schema(description = "鏈紑绁ㄩ噾棰�")
-    private BigDecimal noInvoiceAmount = BigDecimal.ZERO;
-
-    @Schema(description = "鏈寮�绁ㄦ暟")
-    @TableField(exist = false)
-    private BigDecimal currentInvoiceNum;
-
-    @TableField(exist = false)
-    @Schema(description = "鏈寮�绁ㄩ噾棰�")
-    private BigDecimal currentInvoiceAmount;
-
-    /**
      *  浜у搧id
      */
     private Long productId;
@@ -158,26 +112,6 @@
      * 浜у搧瑙勬牸id
      */
     private Long productModelId;
-
-    @Schema(description = "鍒濆鏈紑绁ㄦ暟")
-    @TableField(exist = false)
-    private BigDecimal originalNoInvoiceNum;
-
-    @Schema(description = "涓存椂鏈紑绁ㄦ暟")
-    @TableField(exist = false)
-    private BigDecimal tempNoInvoiceNum;
-
-    @Schema(description = "涓存椂鏈紑绁ㄩ噾棰�")
-    @TableField(exist = false)
-    private BigDecimal tempnoInvoiceAmount;
-
-    @Schema(description = "涓存椂鏈潵绁ㄦ暟")
-    @TableField(exist = false)
-    private BigDecimal tempFutureTickets;
-
-    @Schema(description = "涓存椂鏈潵绁ㄩ噾棰�")
-    @TableField(exist = false)
-    private BigDecimal tempFutureTicketsAmount;
 
     @Schema(description = "鐧昏浜�")
     private String register;
@@ -218,18 +152,6 @@
 //    @TableField(exist = false)
     @Schema(description = "浜у搧鐘舵�侊細1-鍏呰冻")
     private Integer approveStatus;
-
-    @Schema(description = "寰呭洖娆炬�婚噾棰�")
-    private BigDecimal pendingInvoiceTotal;
-
-    @Schema(description = "鍥炴鎬婚噾棰�")
-    private BigDecimal invoiceTotal = BigDecimal.ZERO;
-
-    @Schema(description = "寰呬粯娆炬�婚噾棰�")
-    private BigDecimal pendingTicketsTotal;
-
-    @Schema(description = "浠樻鎬婚噾棰�")
-    private BigDecimal ticketsTotal = BigDecimal.ZERO;
 
     @Schema(description = "鏄惁璐ㄦ")
     //閽堝閲囪喘鍙拌处锛屾槸鍚﹁川妫�
diff --git a/src/main/java/com/ruoyi/sales/service/ISalesLedgerProductService.java b/src/main/java/com/ruoyi/sales/service/ISalesLedgerProductService.java
index 47e0616..00fc350 100644
--- a/src/main/java/com/ruoyi/sales/service/ISalesLedgerProductService.java
+++ b/src/main/java/com/ruoyi/sales/service/ISalesLedgerProductService.java
@@ -1,10 +1,7 @@
 package com.ruoyi.sales.service;
 
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ruoyi.framework.web.domain.R;
-import com.ruoyi.sales.dto.SalesLedgerProductDto;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 
 import java.util.List;
@@ -24,10 +21,6 @@
     int deleteSalesLedgerProductByIds(Long[] ids);
 
     int addOrUpdateSalesLedgerProduct(SalesLedgerProduct salesLedgerProduct);
-
-    IPage<SalesLedgerProductDto> listPage(Page page, SalesLedgerProductDto salesLedgerProduct);
-
-    IPage<SalesLedgerProductDto> listPagePurchaseLedger(Page page, SalesLedgerProductDto salesLedgerProduct);
 
     R judgmentInventory(SalesLedgerProduct salesLedgerProduct);
 
diff --git a/src/main/java/com/ruoyi/sales/service/InvoiceLedgerService.java b/src/main/java/com/ruoyi/sales/service/InvoiceLedgerService.java
deleted file mode 100644
index e9335ca..0000000
--- a/src/main/java/com/ruoyi/sales/service/InvoiceLedgerService.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package com.ruoyi.sales.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.common.vo.FileVo;
-import com.ruoyi.sales.dto.InvoiceLedgerDto;
-import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
-import com.ruoyi.sales.pojo.InvoiceLedgerFile;
-import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
-import org.springframework.web.multipart.MultipartFile;
-
-import jakarta.servlet.http.HttpServletResponse;
-import java.math.BigDecimal;
-import java.util.List;
-
-public interface InvoiceLedgerService {
-
-    /**
-     * 寮�绁ㄥ彴璐︽柊澧�
-     * @param productDto
-     * @return
-     */
-    int invoiceLedgerSaveOrUpdate( InvoiceRegistrationProductDto productDto);
-
-    /**
-     * 寮�绁ㄥ彴璐﹀垹闄�
-     * @param ids
-     * @return
-     */
-    int invoiceLedgerDel(List<Integer> ids);
-
-    /**
-     * 寮�绁ㄥ彴璐﹀垎椤垫煡璇�
-     * @param page
-     * @param invoiceLedgerDto
-     * @return
-     */
-    IPage<InvoiceLedgerDto> invoiceLedgerPage(Page page, InvoiceLedgerDto invoiceLedgerDto);
-
-    /**
-     * 寮�绁ㄥ彴璐︽枃浠舵煡璇�
-     * @param invoiceLedgerId
-     * @return
-     */
-    List<InvoiceLedgerFile> invoiceLedgerFileList(Integer invoiceLedgerId);
-
-    /**
-     * 寮�绁ㄥ彴璐︽枃浠朵笂浼�
-     * @param file
-     * @return
-     */
-    FileVo invoiceLedgerUploadFile(MultipartFile file);
-
-    /**
-     * 闄勪欢涓嬭浇
-     * @param response
-     * @param invoiceRegistrationProductDto
-     * @return
-     */
-    void invoiceLedgerExport(HttpServletResponse response ,InvoiceRegistrationProductDto invoiceRegistrationProductDto);
-
-    /**
-     * 寮�绁ㄥ彴璐﹁鎯�
-     * @param id
-     * @return
-     */
-    InvoiceLedgerDto invoiceLedgerDetail(Integer id);
-
-    /**
-     * 闄勪欢鎻愪氦
-     * @param invoiceLedgerDto
-     * @return
-     */
-    void invoiceLedgerCommitFile(InvoiceLedgerDto invoiceLedgerDto);
-
-    /**
-     * 寮�绁ㄥ彴璐︽煡璇�
-     * @param invoiceLedgerDto
-     * @return
-     */
-    List<InvoiceLedgerDto> invoiceLedgerList(InvoiceLedgerDto invoiceLedgerDto);
-
-    /**
-     * 瀹㈡埛閿�鍞褰�
-     * @param page
-     * @param invoiceLedgerDto
-     * @return
-     */
-    IPage<InvoiceLedgerDto> invoiceLedgerSalesAccount(Page page, InvoiceLedgerDto invoiceLedgerDto);
-
-    BigDecimal getInvoiceAmount();
-
-    /**
-     * 寮�绁ㄧ櫥璁颁骇鍝佸垎椤垫煡璇�
-     * @param page
-     * @param registrationProductDto
-     * @return
-     */
-    IPage<InvoiceRegistrationProductDto>  registrationProductPage(Page page, InvoiceRegistrationProductDto registrationProductDto);
-
-    /**
-     * 浜у搧寮�绁ㄥ彴璐﹁鎯�
-     * @param id
-     * @return
-     */
-    InvoiceRegistrationProductDto invoiceLedgerProductDetail(Integer id);
-
-    /**
-     * 寮�绁ㄥ彴璐﹀垹闄�
-     * @param invoiceRegistrationProductId
-     * @return
-     */
-    void delInvoiceLedger(Integer invoiceRegistrationProductId);
-}
diff --git a/src/main/java/com/ruoyi/sales/service/InvoiceRegistrationService.java b/src/main/java/com/ruoyi/sales/service/InvoiceRegistrationService.java
deleted file mode 100644
index 4044a4e..0000000
--- a/src/main/java/com/ruoyi/sales/service/InvoiceRegistrationService.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.ruoyi.sales.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.sales.dto.InvoiceRegistrationDto;
-import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
-import com.ruoyi.sales.dto.SalesLedgerDto;
-import org.springframework.web.bind.annotation.RequestBody;
-
-import jakarta.servlet.http.HttpServletResponse;
-import java.util.List;
-
-public interface InvoiceRegistrationService {
-
-    /**
-     * 寮�绁ㄧ櫥璁拌褰曟柊澧�
-     * @param salesLedgerDto
-     * @return
-     */
-    void invoiceRegistrationSave(SalesLedgerDto salesLedgerDto);
-
-    /**
-     * 寮�绁ㄧ櫥璁板垹闄�
-     * @param ids
-     * @return
-     */
-    int invoiceRegistrationDel(List<Integer> ids);
-
-
-    /**
-     * 寮�绁ㄨ褰曚慨鏀�
-     * @param invoiceRegistrationDto
-     * @return
-     */
-    void invoiceRegistrationUpdate(InvoiceRegistrationDto invoiceRegistrationDto);
-
-    /**
-     * 寮�绁ㄧ櫥璁板垎椤垫煡璇�
-     * @param page
-     * @param invoiceRegistrationDto
-     * @return
-     */
-    IPage<InvoiceRegistrationDto> invoiceRegistrationListPage(Page page, InvoiceRegistrationDto invoiceRegistrationDto);
-
-    /**
-     * 寮�绁ㄧ櫥璁颁骇鍝佹煡璇�
-     * @param invoiceRegistrationProductDto
-     * @return
-     */
-    List<InvoiceRegistrationProductDto> invoiceRegistrationProductList(InvoiceRegistrationProductDto invoiceRegistrationProductDto);
-
-    /**
-     * 寮�绁ㄧ櫥璁拌鎯�
-     * @param id
-     * @return
-     */
-    InvoiceRegistrationDto invoiceRegistrationDetail(Integer id);
-
-    /**
-     * 寮�绁ㄧ櫥璁板鍑�
-     * @param response
-     * @param invoiceRegistrationDto
-     */
-    void invoiceRegistrationExport(HttpServletResponse response, InvoiceRegistrationDto invoiceRegistrationDto);
-}
diff --git a/src/main/java/com/ruoyi/sales/service/ReceiptPaymentService.java b/src/main/java/com/ruoyi/sales/service/ReceiptPaymentService.java
deleted file mode 100644
index 49378c8..0000000
--- a/src/main/java/com/ruoyi/sales/service/ReceiptPaymentService.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package com.ruoyi.sales.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.sales.dto.CustomerInteractionDto;
-import com.ruoyi.sales.dto.InvoiceLedgerDto;
-import com.ruoyi.sales.dto.ReceiptPaymentDto;
-import com.ruoyi.sales.pojo.ReceiptPayment;
-
-import jakarta.servlet.http.HttpServletResponse;
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
-
-public interface ReceiptPaymentService {
-
-    /**
-     * 鍥炴鐧昏鏂板
-     * @param receiptPayment
-     * @return
-     */
-    int receiptPaymentSaveOrUpdate(List<ReceiptPayment> receiptPayment);
-
-    /**
-     * 鍥炴鐧昏淇敼
-     * @param receiptPayment
-     * @return
-     */
-    int receiptPaymentUpdate(ReceiptPayment receiptPayment);
-
-    /**
-     * 鍥炴鐧昏鍒犻櫎
-     * @param ids
-     * @return
-     */
-    int receiptPaymentDel(List<Integer> ids);
-
-    /**
-     * 鍥炴鐧昏鍒嗛〉鏌ヨ
-     * @param page
-     * @param receiptPaymentDto
-     * @return
-     */
-    IPage<ReceiptPaymentDto> receiptPaymentListPage (Page page, ReceiptPaymentDto receiptPaymentDto);
-
-    /**
-     * 鍥炴鐧昏璇︽儏
-     * @param id
-     * @return
-     */
-    ReceiptPaymentDto receiptPaymentInfo(Integer id);
-
-    BigDecimal getReceiptAmount();
-
-    /**
-     * 鏌ヨ宸茬粡缁戝畾鍙戠エ鐨勫紑绁ㄥ彴璐�
-     * @param page
-     * @param receiptPaymentDto
-     * @return
-     */
-    IPage<ReceiptPaymentDto> bindInvoiceNoRegPage(Page page, ReceiptPaymentDto receiptPaymentDto);
-
-    /**
-     * 寮�绁ㄥ彴璐﹁鎯�
-     * @param id
-     * @return
-     */
-    InvoiceLedgerDto invoiceInfo(Integer id);
-
-    Map<String,BigDecimal> getAmountMouth();
-
-    /**
-     * 鏌ヨ鍥炴璁板綍
-     */
-    List<ReceiptPaymentDto> receiptPaymentHistoryList(ReceiptPaymentDto receiptPaymentDto);
-
-    /**
-     * 鏌ヨ鍥炴璁板綍鍒嗛〉
-     */
-    IPage<ReceiptPaymentDto> receiptPaymentHistoryListPage(Page page, ReceiptPaymentDto receiptPaymentDto);
-
-    /**
-     * 瀹㈡埛寰�鏉ヨ褰曟煡璇�
-     * @param receiptPaymentDto
-     * @return
-     */
-    List<InvoiceLedgerDto> customerInteractions (InvoiceLedgerDto receiptPaymentDto);
-
-    /**
-     * 鏌ヨ鍥炴璁板綍鍒嗛〉
-     */
-    List<ReceiptPaymentDto> receiptPaymentHistoryListNoPage(ReceiptPaymentDto receiptPaymentDto);
-
-    /**
-     * 鍏ㄥ鍑哄洖娆惧垪琛�
-     */
-    void exportPaymentList(HttpServletResponse response);
-
-    /**
-     * 閮ㄥ垎瀵煎嚭鍥炴鍒楄〃
-     */
-    void exportPaymentList(HttpServletResponse response, List<Long> ids);
-}
diff --git a/src/main/java/com/ruoyi/sales/service/impl/InvoiceLedgerServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/InvoiceLedgerServiceImpl.java
deleted file mode 100644
index d18a51a..0000000
--- a/src/main/java/com/ruoyi/sales/service/impl/InvoiceLedgerServiceImpl.java
+++ /dev/null
@@ -1,509 +0,0 @@
-package com.ruoyi.sales.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-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.common.utils.StringUtils;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.common.vo.FileVo;
-import com.ruoyi.sales.dto.InvoiceLedgerDto;
-import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
-import com.ruoyi.sales.excel.InvoiceLedgerExcelDto;
-import com.ruoyi.sales.mapper.*;
-import com.ruoyi.sales.pojo.*;
-import com.ruoyi.sales.service.InvoiceLedgerService;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.RequiredArgsConstructor;
-import org.apache.commons.collections4.CollectionUtils;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.ObjectUtils;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.File;
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.YearMonth;
-import java.util.List;
-import java.util.Objects;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-@Service
-@RequiredArgsConstructor
-public class InvoiceLedgerServiceImpl extends ServiceImpl<InvoiceLedgerMapper, InvoiceLedger> implements InvoiceLedgerService {
-
-    @Value("${ruoyi.profile}")
-    private String uploadFile;
-
-    private final InvoiceLedgerMapper invoiceLedgerMapper;
-    private final InvoiceLedgerFileMapper invoiceLedgerFileMapper;
-    private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
-    private final ReceiptPaymentMapper receiptPaymentMapper;
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-
-    /**
-     * 寮�绁ㄥ彴璐︽柊澧�
-     * @param productDto
-     * @return
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public int invoiceLedgerSaveOrUpdate(InvoiceRegistrationProductDto productDto) {
-        // 鍒ゆ柇鏄惁宸茬粡鏂板寮�绁ㄥ彴璐�
-        QueryWrapper<InvoiceLedger> ledgerQueryWrapper = new QueryWrapper<>();
-        ledgerQueryWrapper.eq("invoice_registration_product_id", productDto.getId());
-        InvoiceLedger invoiceLedger = invoiceLedgerMapper.selectOne(ledgerQueryWrapper);
-        int result;
-        if(ObjectUtils.isEmpty(invoiceLedger)){
-            invoiceLedger = new InvoiceLedger();
-            invoiceLedger.setInvoiceRegistrationProductId(productDto.getId());
-            invoiceLedger.setInvoiceNo(productDto.getInvoiceNo());
-            invoiceLedger.setInvoiceTotal(productDto.getInvoiceTotal());
-            invoiceLedger.setInvoiceDate(productDto.getInvoiceDate());
-            invoiceLedger.setInvoicePerson(productDto.getInvoicePerson());
-            result = invoiceLedgerMapper.insert(invoiceLedger);
-        }else {
-            // 淇敼sale_leger_product
-            InvoiceRegistrationProduct invoiceRegistrationProduct = invoiceRegistrationProductMapper.selectById(productDto.getId());
-            SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(invoiceRegistrationProduct.getSalesLedgerProductId());
-
-            BigDecimal invoiceNum = productDto.getInvoiceTotal().divide(invoiceRegistrationProduct.getTaxInclusiveUnitPrice(), 2, BigDecimal.ROUND_HALF_UP);
-            //璁$畻 鏈紑绁ㄦ暟/鏈紑绁ㄩ噾棰�
-            BigDecimal noInvoiceAmount = salesLedgerProduct.getNoInvoiceAmount().add(invoiceRegistrationProduct.getInvoiceAmount()).subtract(productDto.getInvoiceTotal());
-            BigDecimal noInvoiceNum = salesLedgerProduct.getNoInvoiceNum().add(invoiceRegistrationProduct.getInvoiceNum()).subtract(invoiceNum);
-            salesLedgerProduct.setNoInvoiceAmount(noInvoiceAmount);
-            salesLedgerProduct.setNoInvoiceNum(noInvoiceNum);
-            salesLedgerProductMapper.updateById(salesLedgerProduct);
-
-            // 淇敼褰撳墠浜у搧寮�绁ㄧ櫥璁拌褰曟暟鎹�
-            BigDecimal currentNoInvoiceNum = invoiceRegistrationProduct.getNoInvoiceNum().add(invoiceRegistrationProduct.getInvoiceNum()).subtract(invoiceNum);
-            BigDecimal currentNoInvoiceAmount = invoiceRegistrationProduct.getNoInvoiceAmount().add(invoiceRegistrationProduct.getInvoiceAmount()).subtract(productDto.getInvoiceTotal());
-            invoiceRegistrationProduct.setInvoiceNum(invoiceNum);
-            invoiceRegistrationProduct.setInvoiceAmount(productDto.getInvoiceTotal());
-            invoiceRegistrationProduct.setNoInvoiceNum(currentNoInvoiceNum);
-            invoiceRegistrationProduct.setNoInvoiceAmount(currentNoInvoiceAmount);
-            invoiceRegistrationProductMapper.updateById(invoiceRegistrationProduct);
-
-            invoiceLedger.setInvoiceNo(productDto.getInvoiceNo());
-            invoiceLedger.setInvoiceTotal(productDto.getInvoiceTotal());
-            invoiceLedger.setInvoiceDate(productDto.getInvoiceDate());
-            invoiceLedger.setInvoicePerson(productDto.getInvoicePerson());
-            result = invoiceLedgerMapper.updateById(invoiceLedger);
-            //鍒犻櫎鎵�鏈夐檮浠跺叧鑱�
-            LambdaQueryWrapper<InvoiceLedgerFile> delWrapper = new LambdaQueryWrapper<>();
-            delWrapper.eq(InvoiceLedgerFile::getInvoiceLedgerId, invoiceLedger.getId());
-            invoiceLedgerFileMapper.delete(delWrapper);
-        }
-        List<FileVo> fileList = productDto.getFileList();
-        if(CollectionUtils.isNotEmpty(fileList)){
-            for (FileVo fileVo : fileList) {
-                InvoiceLedgerFile invoiceLedgerFile = new InvoiceLedgerFile();
-                BeanUtils.copyProperties(fileVo, invoiceLedgerFile);
-                invoiceLedgerFile.setInvoiceLedgerId(invoiceLedger.getId());
-                invoiceLedgerFileMapper.insert(invoiceLedgerFile);
-            }
-        }
-        return result;
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐﹀垹闄�
-     * @param ids
-     * @return
-     */
-    @Override
-    public int invoiceLedgerDel(List<Integer> ids) {
-        LambdaQueryWrapper<InvoiceLedger> delWrapper = new LambdaQueryWrapper<>();
-        delWrapper.in(InvoiceLedger::getId, ids);
-        return invoiceLedgerMapper.delete(delWrapper);
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐﹀垎椤垫煡璇�
-     * @param page
-     * @param invoiceLedgerDto
-     * @return
-     */
-    @Override
-    public IPage<InvoiceLedgerDto> invoiceLedgerPage(Page page, InvoiceLedgerDto invoiceLedgerDto) {
-        return invoiceLedgerMapper.invoiceLedgerPage(page, invoiceLedgerDto);
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐︽枃浠舵煡璇�
-     * @param invoiceLedgerId
-     * @return
-     */
-    @Override
-    public List<InvoiceLedgerFile> invoiceLedgerFileList(Integer invoiceLedgerId) {
-        LambdaQueryWrapper<InvoiceLedgerFile> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(InvoiceLedgerFile::getInvoiceLedgerId, invoiceLedgerId);
-        return invoiceLedgerFileMapper.selectList(queryWrapper);
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐︽枃浠朵笂浼�
-     * @param file
-     * @return
-     */
-    @Override
-    public FileVo invoiceLedgerUploadFile(MultipartFile file) {
-        FileVo fileVo = new FileVo();
-        try {
-            String baseDir = uploadFile + File.separatorChar + "invoiceLedger";
-            File dirFile = new File(baseDir);
-            if(!dirFile.exists()){
-                dirFile.mkdirs();
-            }
-            String filePath = baseDir + File.separatorChar + UUID.randomUUID() + "_" + file.getOriginalFilename();
-            file.transferTo(new File(filePath));
-            fileVo.setName(file.getOriginalFilename());
-            fileVo.setUrl(filePath);
-            fileVo.setFileSize((int)file.getSize());
-        }catch (Exception e){
-            e.printStackTrace();
-            throw new RuntimeException("鏂囦欢涓婁紶澶辫触");
-        }
-        return fileVo;
-    }
-
-    /**
-     * 闄勪欢涓嬭浇
-     * @param response
-     * @param invoiceRegistrationProductDto
-     * @return
-     */
-    @Override
-    public void invoiceLedgerExport(HttpServletResponse response, InvoiceRegistrationProductDto invoiceRegistrationProductDto) {
-        List<InvoiceRegistrationProductDto> invoiceRegistrationProductList = invoiceRegistrationProductMapper.invoiceRegistrationProductList(invoiceRegistrationProductDto);
-        List<InvoiceLedgerExcelDto> invoiceLedgerExcelDtoList = invoiceRegistrationProductList.stream().map(item -> {
-            InvoiceLedgerExcelDto invoiceLedgerExcelDto = new InvoiceLedgerExcelDto();
-            BeanUtils.copyProperties(item, invoiceLedgerExcelDto);
-            return invoiceLedgerExcelDto;
-        }).collect(Collectors.toList());
-        ExcelUtil<InvoiceLedgerExcelDto> util = new ExcelUtil<InvoiceLedgerExcelDto>(InvoiceLedgerExcelDto.class);
-        util.exportExcel(response, invoiceLedgerExcelDtoList, "渚涘簲鍟嗗鍑�");
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐﹁鎯�
-     * @param id
-     * @return
-     */
-    @Override
-    public InvoiceLedgerDto invoiceLedgerDetail(Integer id) {
-        InvoiceLedgerDto invoiceLedgerDto  = invoiceLedgerMapper.invoiceLedgerInfo(id);
-        if(ObjectUtils.isEmpty(invoiceLedgerDto)){
-            throw new RuntimeException("寮�绁ㄥ彴璐︽煡鎵惧け璐�");
-        }
-        // 鏌ヨ闄勪欢
-        QueryWrapper<InvoiceLedgerFile> queryWrapper = new QueryWrapper<>();
-        queryWrapper.eq("invoice_ledger_id", id);
-        List<InvoiceLedgerFile> invoiceLedgerFileList = invoiceLedgerFileMapper.selectList(queryWrapper);
-        List<FileVo> fileList = invoiceLedgerFileList.stream().map(item -> {
-            FileVo fileVo = new FileVo();
-            BeanUtils.copyProperties(item, fileVo);
-            return fileVo;
-        }).collect(Collectors.toList());
-        invoiceLedgerDto.setFileList(fileList);
-        return invoiceLedgerDto;
-    }
-
-    /**
-     * 闄勪欢鎻愪氦
-     * @param invoiceLedgerDto
-     * @return
-     */
-    @Override
-    public void invoiceLedgerCommitFile(InvoiceLedgerDto invoiceLedgerDto) {
-        if(null == invoiceLedgerDto.getId()){
-            throw new RuntimeException("缂哄皯鍙戠エ鍙拌处涓婚敭");
-        }
-        if(CollectionUtils.isEmpty(invoiceLedgerDto.getFileList())){
-            throw new RuntimeException("缂哄皯鏂囦欢淇℃伅");
-        }
-        QueryWrapper<InvoiceLedger> ledgerQueryWrapper = new QueryWrapper<>();
-        ledgerQueryWrapper.eq("invoice_registration_product_id", invoiceLedgerDto.getId());
-        InvoiceLedger invoiceLedger = invoiceLedgerMapper.selectOne(ledgerQueryWrapper);
-        if(ObjectUtils.isEmpty(invoiceLedger)){
-            throw new RuntimeException("寮�绁ㄥ彴璐︽湭鐧昏");
-        }
-        List<FileVo> fileList = invoiceLedgerDto.getFileList();
-        fileList.forEach(fileVo -> {
-            InvoiceLedgerFile invoiceLedgerFile = new InvoiceLedgerFile();
-            BeanUtils.copyProperties(fileVo, invoiceLedgerFile);
-            invoiceLedgerFile.setInvoiceLedgerId(invoiceLedger.getId());
-            invoiceLedgerFileMapper.insert(invoiceLedgerFile);
-        });
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐︽煡璇�
-     * @param invoiceLedgerDto
-     * @return
-     */
-    @Override
-    public List<InvoiceLedgerDto> invoiceLedgerList(InvoiceLedgerDto invoiceLedgerDto) {
-        return invoiceLedgerMapper.invoiceLedgerList(invoiceLedgerDto);
-    }
-
-    /**
-     * 瀹㈡埛閿�鍞褰�
-     * @param page
-     * @param invoiceLedgerDto
-     * @return
-     */
-    @Override
-    public IPage<InvoiceLedgerDto> invoiceLedgerSalesAccount(Page page, InvoiceLedgerDto invoiceLedgerDto) {
-        IPage<InvoiceLedgerDto> invoiceLedgerDtoIPage = invoiceLedgerMapper.invoiceLedgerSalesAccount(page, invoiceLedgerDto);
-        return invoiceLedgerDtoIPage;
-    }
-
-    @Override
-    public BigDecimal getInvoiceAmount() {
-        LocalDate now = LocalDate.now();
-        YearMonth currentMonth = YearMonth.from(now);
-
-        // 鍒涘缓LambdaQueryWrapper
-        LambdaQueryWrapper<InvoiceLedger> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.ge(InvoiceLedger::getInvoiceDate, currentMonth.atDay(1).atStartOfDay())  // 澶т簬绛変簬鏈湀绗竴澶�
-                .lt(InvoiceLedger::getInvoiceDate, currentMonth.plusMonths(1).atDay(1).atStartOfDay()); // 灏忎簬涓嬫湀绗竴澶�
-
-        // 鎵ц鏌ヨ骞惰绠楁�诲拰
-        List<InvoiceLedger> invoiceLedgers = invoiceLedgerMapper.selectList(queryWrapper);
-
-        BigDecimal totalContractAmount = invoiceLedgers.stream()
-                .map(InvoiceLedger::getInvoiceTotal)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-        return totalContractAmount;
-    }
-
-    /**
-     * 寮�绁ㄧ櫥璁颁骇鍝佸垎椤垫煡璇�
-     * @param page
-     * @param registrationProductDto
-     * @return
-     */
-    @Override
-    public IPage<InvoiceRegistrationProductDto> registrationProductPage(Page page, InvoiceRegistrationProductDto registrationProductDto) {
-        IPage<InvoiceRegistrationProductDto> invoiceRegistrationProductDtoIPage = invoiceRegistrationProductMapper.invoiceRegistrationProductPage(page, registrationProductDto);
-        if (registrationProductDto.getStatus()) {
-            invoiceRegistrationProductDtoIPage.getRecords().removeIf(invoiceRegistrationProduct -> !StringUtils.isEmpty(invoiceRegistrationProduct.getInvoiceNo()));
-        }
-        invoiceRegistrationProductDtoIPage.getRecords().forEach(invoiceRegistrationProductDto -> {
-                invoiceRegistrationProductDto.setCommonFiles(invoiceLedgerFileMapper.selectList(new QueryWrapper<InvoiceLedgerFile>().lambda()
-                        .eq(InvoiceLedgerFile::getInvoiceLedgerId, invoiceRegistrationProductDto.getInvoiceLedgerId())));
-        });
-        return invoiceRegistrationProductDtoIPage;
-    }
-
-    /**
-     * 浜у搧寮�绁ㄥ彴璐﹁鎯�
-     * @param id
-     * @return
-     */
-    @Override
-    public InvoiceRegistrationProductDto invoiceLedgerProductDetail(Integer id) {
-        InvoiceRegistrationProductDto invoiceRegistrationProductDto = invoiceLedgerMapper.invoiceLedgerProductInfo(id);
-        if(ObjectUtils.isEmpty(invoiceRegistrationProductDto)){
-            throw new RuntimeException("浜у搧寮�绁ㄥ彴璐︽煡鎵惧け璐�");
-        }
-        List<InvoiceRegistrationProduct> invoiceRegistrationProducts = invoiceRegistrationProductMapper.selectList(new LambdaQueryWrapper<InvoiceRegistrationProduct>()
-                .eq(InvoiceRegistrationProduct::getSalesLedgerProductId, invoiceRegistrationProductDto.getSalesLedgerProductId()));
-        if(CollectionUtils.isNotEmpty(invoiceRegistrationProducts)){
-            invoiceRegistrationProductDto.setNoInvoiceNum(invoiceRegistrationProductDto.getQuantity()
-                    .subtract(invoiceRegistrationProducts.stream().map(InvoiceRegistrationProduct::getInvoiceNum).reduce(BigDecimal.ZERO, BigDecimal::add)));
-            invoiceRegistrationProductDto.setNoInvoiceAmount(invoiceRegistrationProductDto.getTaxInclusiveTotalPrice()
-                    .subtract(invoiceRegistrationProducts.stream().map(InvoiceRegistrationProduct::getInvoiceAmount).reduce(BigDecimal.ZERO, BigDecimal::add)));
-        }
-        // 鏌ヨ闄勪欢
-        QueryWrapper<InvoiceLedgerFile> queryWrapper = new QueryWrapper<>();
-        queryWrapper.eq("invoice_ledger_id", invoiceRegistrationProductDto.getInvoiceLedgerId());
-        List<InvoiceLedgerFile> invoiceLedgerFileList = invoiceLedgerFileMapper.selectList(queryWrapper);
-        List<FileVo> fileList = invoiceLedgerFileList.stream().map(item -> {
-            FileVo fileVo = new FileVo();
-            BeanUtils.copyProperties(item, fileVo);
-            return fileVo;
-        }).collect(Collectors.toList());
-        invoiceRegistrationProductDto.setFileList(fileList);
-        return invoiceRegistrationProductDto;
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐﹀垹闄�
-     * @param invoiceRegistrationProductId
-     * @return
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void delInvoiceLedger(Integer invoiceRegistrationProductId) {
-        // 鍒ゆ柇鏄惁鏈夊洖娆捐褰�
-        List<ReceiptPayment> receiptPaymentList = receiptPaymentMapper.receiptPaymentListByProdRegId(invoiceRegistrationProductId);
-        if(!CollectionUtils.isEmpty(receiptPaymentList)){
-            throw new RuntimeException("璇峰厛鍒犻櫎鍥炴璁板綍");
-        }
-        // 鍒ゆ柇鏄惁鏈夊紑绁ㄧ櫥璁拌褰�
-        InvoiceRegistrationProduct invoiceRegistrationProduct = invoiceRegistrationProductMapper.selectById(invoiceRegistrationProductId);
-        if(ObjectUtils.isEmpty(invoiceRegistrationProduct)){
-            throw new RuntimeException("寮�绁ㄧ櫥璁拌褰曟煡鎵惧け璐�");
-        }
-        // 鍒ゆ柇璇ュ紑绁ㄥ彴璐︽槸鍚︽湭褰撴湀锛屽鏋滀负褰撴湀鐩存帴鍒犻櫎鍚﹀垯鏂板涓�鏉$浉鍙嶈礋鏁版暟鎹�
-        QueryWrapper<InvoiceLedger> ledgerQueryWrapper = new QueryWrapper<>();
-        ledgerQueryWrapper.eq("invoice_registration_product_id", invoiceRegistrationProductId);
-        InvoiceLedger invoiceLedger = invoiceLedgerMapper.selectOne(ledgerQueryWrapper);
-        if(ObjectUtils.isEmpty(invoiceLedger)){
-            throw new RuntimeException("寮�绁ㄥ彴璐︽煡鎵惧け璐�");
-        }
-        if( invoiceLedger.getInvoiceDate() == null){
-            dealCurrentMonthDel(invoiceRegistrationProductId,invoiceRegistrationProduct);
-            return;
-        }
-        // 鑾峰彇褰撳墠鏃ユ湡
-        LocalDate today = LocalDate.now();
-        // 浣跨敤YearMonth姣旇緝骞翠唤鍜屾湀浠芥槸鍚︾浉鍚�
-        boolean equalsFlag = YearMonth.from(invoiceLedger.getInvoiceDate()).equals(YearMonth.from(today));
-        if(equalsFlag){
-            dealCurrentMonthDel(invoiceRegistrationProductId,invoiceRegistrationProduct);
-        }else {
-            dealOtherMonthDel(invoiceRegistrationProduct,invoiceLedger);
-        }
-    }
-
-    /**
-     * 澶勭悊褰撴湀寮�绁ㄥ彴璐﹀垹闄�
-     *
-     * @param invoiceRegistrationProductId
-     * @param invoiceRegistrationProduct
-     */
-
-    private void dealCurrentMonthDel(Integer invoiceRegistrationProductId, InvoiceRegistrationProduct invoiceRegistrationProduct) {
-
-        // 鍒犻櫎寮�绁ㄥ彴璐�
-        QueryWrapper<InvoiceLedger> delLedgerWrapper = new QueryWrapper<>();
-        delLedgerWrapper.eq("invoice_registration_product_id", invoiceRegistrationProductId);
-        invoiceLedgerMapper.delete(delLedgerWrapper);
-
-        // 鏌ヨ褰撳墠浜у搧涓嬬殑鎵�鏈夊紑绁ㄧ櫥璁�
-        QueryWrapper<InvoiceRegistrationProduct> queryWrapper = new QueryWrapper<>();
-        queryWrapper.eq("sales_ledger_id", invoiceRegistrationProduct.getSalesLedgerId());
-        queryWrapper.eq("sales_ledger_product_id", invoiceRegistrationProduct.getSalesLedgerProductId());
-        queryWrapper.orderByAsc("create_time");
-        List<InvoiceRegistrationProduct> allList = invoiceRegistrationProductMapper.selectList(queryWrapper);
-
-        int index = -1;
-        for (int i = 0; i < allList.size(); i++) {
-            if (invoiceRegistrationProductId.equals(allList.get(i).getId())) {
-                index = i;
-                break;
-            }
-        }
-        if (index == -1) {
-            return;
-        }
-
-        for (int i = index + 1; i < allList.size(); i++) {
-            InvoiceRegistrationProduct current = allList.get(i);
-
-            current.setNoInvoiceNum(current.getNoInvoiceNum().add(invoiceRegistrationProduct.getInvoiceNum()));
-            current.setNoInvoiceAmount(current.getNoInvoiceAmount().add(invoiceRegistrationProduct.getInvoiceAmount()));
-
-            invoiceRegistrationProductMapper.updateById(current);
-        }
-
-        // 鍒犻櫎褰撳墠寮�绁ㄧ櫥璁�
-        invoiceRegistrationProductMapper.deleteById(invoiceRegistrationProductId);
-
-        // 鏌ヨ鍒犻櫎鍚庣殑鍓╀綑寮�绁ㄧ櫥璁�
-        QueryWrapper<InvoiceRegistrationProduct> newQueryWrapper = new QueryWrapper<>();
-        newQueryWrapper.eq("sales_ledger_id", invoiceRegistrationProduct.getSalesLedgerId());
-        newQueryWrapper.eq("sales_ledger_product_id", invoiceRegistrationProduct.getSalesLedgerProductId());
-        newQueryWrapper.orderByAsc("create_time");
-        List<InvoiceRegistrationProduct> remainList = invoiceRegistrationProductMapper.selectList(newQueryWrapper);
-
-        // 鏌ヨ閿�鍞彴璐︿骇鍝�
-        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(invoiceRegistrationProduct.getSalesLedgerProductId());
-
-        if (CollectionUtils.isEmpty(remainList)) {
-            // 娌℃湁浠讳綍寮�绁ㄨ褰曪紝鎭㈠鍒濆鐘舵��
-            salesLedgerProduct.setInvoiceNum(BigDecimal.ZERO);
-            salesLedgerProduct.setInvoiceAmount(BigDecimal.ZERO);
-            salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity());
-            salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice());
-        } else {
-            salesLedgerProduct.setInvoiceNum(salesLedgerProduct.getInvoiceNum().subtract(invoiceRegistrationProduct.getInvoiceNum()));
-            salesLedgerProduct.setInvoiceAmount(salesLedgerProduct.getInvoiceAmount().subtract(invoiceRegistrationProduct.getInvoiceAmount()));
-            salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getNoInvoiceNum().add(invoiceRegistrationProduct.getInvoiceNum()));
-            salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getNoInvoiceAmount().add(invoiceRegistrationProduct.getInvoiceAmount()));
-        }
-
-        salesLedgerProductMapper.updateById(salesLedgerProduct);
-    }
-
-    /**
-     * 澶勭悊鍏朵粬鏈堜唤寮�绁ㄥ彴璐﹀垹闄�
-     * @param invoiceRegistrationProduct
-     * @param invoiceLedger
-     */
-    private void dealOtherMonthDel(InvoiceRegistrationProduct invoiceRegistrationProduct, InvoiceLedger invoiceLedger) {
-        //鏌ヨ鍘嗗彶寮�绁ㄧ櫥璁�
-        QueryWrapper<InvoiceRegistrationProduct> queryWrapper = new QueryWrapper<>();
-        queryWrapper.eq("sales_ledger_id", invoiceRegistrationProduct.getSalesLedgerId());
-        queryWrapper.eq("sales_ledger_product_id", invoiceRegistrationProduct.getSalesLedgerProductId());
-        queryWrapper.orderByAsc("create_time");
-        List<InvoiceRegistrationProduct> list = invoiceRegistrationProductMapper.selectList(queryWrapper);
-
-        if (CollectionUtils.isEmpty(list)) {
-            return;
-        }
-
-        InvoiceRegistrationProduct last = list.get(list.size() - 1);
-
-        BigDecimal negateInvoiceNum = invoiceRegistrationProduct.getInvoiceNum().negate();
-        BigDecimal negateInvoiceAmount = invoiceRegistrationProduct.getInvoiceAmount().negate();
-
-        InvoiceRegistrationProduct copy = new InvoiceRegistrationProduct();
-        BeanUtils.copyProperties(invoiceRegistrationProduct, copy);
-
-        copy.setId(null);
-        copy.setInvoiceNum(negateInvoiceNum);
-        copy.setInvoiceAmount(negateInvoiceAmount);
-
-        // 鏈紑绁� = 涓婁竴鏉� + 鏈鍐插洖鐨勬暟閲�
-        copy.setNoInvoiceNum(last.getNoInvoiceNum().add(invoiceRegistrationProduct.getInvoiceNum()));
-        copy.setNoInvoiceAmount(last.getNoInvoiceAmount().add(invoiceRegistrationProduct.getInvoiceAmount()));
-
-        invoiceRegistrationProductMapper.insert(copy);
-
-        // 澶嶅埗寮�绁ㄥ彴璐�
-        InvoiceLedger ledgerCopy = new InvoiceLedger();
-        BeanUtils.copyProperties(invoiceLedger, ledgerCopy);
-
-        ledgerCopy.setId(null);
-        ledgerCopy.setInvoiceRegistrationProductId(copy.getId());
-        ledgerCopy.setInvoiceTotal(invoiceLedger.getInvoiceTotal().negate());
-        ledgerCopy.setInvoiceDate(LocalDate.now());
-
-        invoiceLedgerMapper.insert(ledgerCopy);
-
-        // 鍥炴粴 sales_ledger_product
-        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(invoiceRegistrationProduct.getSalesLedgerProductId());
-
-        // 宸插紑绁�
-        salesLedgerProduct.setInvoiceNum(salesLedgerProduct.getInvoiceNum().add(negateInvoiceNum));
-        salesLedgerProduct.setInvoiceAmount(salesLedgerProduct.getInvoiceAmount().add(negateInvoiceAmount));
-
-        // 鏈紑绁�
-        salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getNoInvoiceNum().add(invoiceRegistrationProduct.getInvoiceNum()));
-        salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getNoInvoiceAmount().add(invoiceRegistrationProduct.getInvoiceAmount()));
-
-        salesLedgerProductMapper.updateById(salesLedgerProduct);
-    }
-
-}
diff --git a/src/main/java/com/ruoyi/sales/service/impl/InvoiceRegistrationServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/InvoiceRegistrationServiceImpl.java
deleted file mode 100644
index fefe144..0000000
--- a/src/main/java/com/ruoyi/sales/service/impl/InvoiceRegistrationServiceImpl.java
+++ /dev/null
@@ -1,228 +0,0 @@
-package com.ruoyi.sales.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.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.sales.dto.InvoiceRegistrationDto;
-import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
-import com.ruoyi.sales.dto.SalesLedgerDto;
-import com.ruoyi.sales.excel.InvoiceRegisAndProductExcelDto;
-import com.ruoyi.sales.mapper.InvoiceLedgerMapper;
-import com.ruoyi.sales.mapper.InvoiceRegistrationMapper;
-import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper;
-import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.pojo.InvoiceLedger;
-import com.ruoyi.sales.pojo.InvoiceRegistration;
-import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import com.ruoyi.sales.service.InvoiceRegistrationService;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.RequiredArgsConstructor;
-import org.apache.commons.collections4.CollectionUtils;
-import org.springframework.beans.BeanUtils;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.ObjectUtils;
-
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Service
-@RequiredArgsConstructor
-public class InvoiceRegistrationServiceImpl extends ServiceImpl<InvoiceRegistrationMapper, InvoiceRegistration> implements InvoiceRegistrationService {
-
-    private final InvoiceRegistrationMapper invoiceRegistrationMapper;
-
-    private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
-
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-
-    private final InvoiceLedgerMapper invoiceLedgerMapper;
-
-    /**
-     * 寮�绁ㄧ櫥璁拌褰曟柊澧�
-     * @param salesLedgerDto
-     * @return
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void invoiceRegistrationSave(SalesLedgerDto salesLedgerDto) {
-        //  鏂板寮�绁ㄧ櫥璁颁富琛�
-        InvoiceRegistration invoiceRegistration = new InvoiceRegistration();
-        BeanUtils.copyProperties(salesLedgerDto, invoiceRegistration);
-        invoiceRegistration.setId(null);
-        invoiceRegistration.setCustomerId(salesLedgerDto.getCustomerId().intValue());
-        invoiceRegistration.setSalesLedgerId(salesLedgerDto.getId().intValue());
-        invoiceRegistrationMapper.insert(invoiceRegistration);
-
-        List<SalesLedgerProduct> productData = salesLedgerDto.getProductData();
-        if (CollectionUtils.isEmpty(productData)) {
-            return;
-        }
-
-        for (SalesLedgerProduct productDatum : productData) {
-            //  鏈寮�绁ㄦ暟 / 閲戦
-            BigDecimal currentInvoiceNum = productDatum.getCurrentInvoiceNum();
-            BigDecimal currentInvoiceAmount = productDatum.getCurrentInvoiceAmount();
-
-            if (currentInvoiceNum == null || BigDecimal.ZERO.compareTo(currentInvoiceNum) == 0) {
-                continue;
-            }
-
-            LambdaQueryWrapper<SalesLedgerProduct> salesLedgerProductLambdaQueryWrapper = new LambdaQueryWrapper<SalesLedgerProduct>()
-                    .eq(SalesLedgerProduct::getId, productDatum.getId())
-                    .eq(SalesLedgerProduct::getSalesLedgerId, productDatum.getSalesLedgerId());
-            SalesLedgerProduct dbProduct = salesLedgerProductMapper.selectOne(salesLedgerProductLambdaQueryWrapper);
-
-            if (dbProduct == null) {
-                throw new RuntimeException("閿�鍞彴璐︿骇鍝佷笉瀛樺湪锛孖D锛�" + productDatum.getId());
-            }
-
-            // 鏈紑绁�
-            BigDecimal noInvoiceAmount = dbProduct.getNoInvoiceAmount();
-            BigDecimal noInvoiceNum = dbProduct.getNoInvoiceNum();
-
-            // 鍓╀綑鏈紑绁�
-            BigDecimal newNoInvoiceNum = noInvoiceNum.subtract(currentInvoiceNum);
-            BigDecimal newNoInvoiceAmount = noInvoiceAmount.subtract(currentInvoiceAmount);
-
-
-            if (newNoInvoiceAmount.compareTo(BigDecimal.ZERO) < 0) {
-                throw new RuntimeException("寮�绁ㄦ暟閲忔垨閲戦瓒呰繃鍚堝悓鎬婚噺");
-            }
-
-            //  鏇存柊 sales_ledger_product
-            salesLedgerProductMapper.update(
-                    null,
-                    new LambdaUpdateWrapper<SalesLedgerProduct>()
-                            .eq(SalesLedgerProduct::getId, dbProduct.getId())
-                            .set(SalesLedgerProduct::getNoInvoiceNum, newNoInvoiceNum)
-                            .set(SalesLedgerProduct::getNoInvoiceAmount, newNoInvoiceAmount)
-            );
-
-            InvoiceRegistrationProduct invoiceRegistrationProduct = new InvoiceRegistrationProduct();
-            BeanUtils.copyProperties(dbProduct, invoiceRegistrationProduct);
-
-            invoiceRegistrationProduct.setId(null);
-            invoiceRegistrationProduct.setSalesLedgerId(salesLedgerDto.getId().intValue());
-            invoiceRegistrationProduct.setInvoiceRegistrationId(invoiceRegistration.getId());
-            invoiceRegistrationProduct.setSalesLedgerProductId(dbProduct.getId().intValue());
-            invoiceRegistrationProduct.setInvoiceNum(currentInvoiceNum);
-            invoiceRegistrationProduct.setInvoiceAmount(currentInvoiceAmount);
-            invoiceRegistrationProduct.setNoInvoiceAmount(newNoInvoiceAmount);
-
-            invoiceRegistrationProductMapper.insert(invoiceRegistrationProduct);
-
-            InvoiceLedger invoiceLedger = new InvoiceLedger();
-            invoiceLedger.setInvoiceDate(salesLedgerDto.getIssueDate());
-            invoiceLedger.setInvoiceRegistrationProductId(invoiceRegistrationProduct.getId());
-            invoiceLedger.setInvoiceTotal(currentInvoiceAmount);
-            invoiceLedger.setInvoiceNo(salesLedgerDto.getInvoiceNo());
-            invoiceLedger.setCreateUser(SecurityUtils.getUserId().intValue());
-            invoiceLedger.setInvoicePerson(dbProduct.getRegister());
-
-            invoiceLedgerMapper.insert(invoiceLedger);
-        }
-    }
-
-    /**
-     * 寮�绁ㄧ櫥璁板垹闄�
-     * @param ids
-     * @return
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public int invoiceRegistrationDel(List<Integer> ids) {
-        int excuteNum = invoiceRegistrationMapper.deleteBatchIds(ids);
-        LambdaQueryWrapper<InvoiceRegistrationProduct> delWrapper = new LambdaQueryWrapper<>();
-        delWrapper.in(InvoiceRegistrationProduct::getInvoiceRegistrationId, ids);
-        invoiceRegistrationProductMapper.delete(delWrapper);
-        return excuteNum;
-    }
-
-    /**
-     * 寮�绁ㄨ褰曚慨鏀�
-     * @param invoiceRegistrationDto
-     * @return
-     */
-    @Override
-    public void invoiceRegistrationUpdate(InvoiceRegistrationDto invoiceRegistrationDto) {
-        InvoiceRegistration invoiceRegistration = new InvoiceRegistration();
-        BeanUtils.copyProperties(invoiceRegistrationDto, invoiceRegistration);
-        // 寮�绁ㄧ櫥璁颁慨鏀�
-        invoiceRegistrationMapper.updateById(invoiceRegistration);
-        List<InvoiceRegistrationProductDto> productDtoList = invoiceRegistrationDto.getProductDtoList();
-        // 寮�绁ㄤ骇鍝佺櫥璁颁慨鏀�
-        if(CollectionUtils.isNotEmpty(productDtoList)){
-            for (InvoiceRegistrationProductDto invoiceRegistrationProductDto : productDtoList) {
-                InvoiceRegistrationProduct invoiceRegistrationProduct = new InvoiceRegistrationProduct();
-                BeanUtils.copyProperties(invoiceRegistrationProductDto, invoiceRegistrationProduct);
-                invoiceRegistrationProductMapper.updateById(invoiceRegistrationProduct);
-            }
-        }
-    }
-
-    /**
-     * 寮�绁ㄧ櫥璁板垎椤垫煡璇�
-     * @param page
-     * @param invoiceRegistrationDto
-     * @return
-     */
-    @Override
-    public IPage<InvoiceRegistrationDto> invoiceRegistrationListPage(Page page, InvoiceRegistrationDto invoiceRegistrationDto) {
-        return invoiceRegistrationMapper.invoiceRegistrationListPage(page, invoiceRegistrationDto);
-    }
-
-    /**
-     * 寮�绁ㄧ櫥璁颁骇鍝佹煡璇�
-     * @param invoiceRegistrationProductDto
-     * @return
-     */
-    @Override
-    public List<InvoiceRegistrationProductDto> invoiceRegistrationProductList(InvoiceRegistrationProductDto invoiceRegistrationProductDto) {
-        return invoiceRegistrationProductMapper.invoiceRegistrationProductList(invoiceRegistrationProductDto);
-    }
-
-    /**
-     * 寮�绁ㄧ櫥璁拌鎯�
-     * @param id
-     * @return
-     */
-    @Override
-    public InvoiceRegistrationDto invoiceRegistrationDetail(Integer id) {
-        InvoiceRegistration invoiceRegistration = invoiceRegistrationMapper.selectById(id);
-        if(ObjectUtils.isEmpty(invoiceRegistration)){
-            throw new RuntimeException("寮�绁ㄧ櫥璁颁俊鎭煡鎵惧け璐�");
-        }
-        InvoiceRegistrationDto invoiceRegistrationDto = new InvoiceRegistrationDto();
-        BeanUtils.copyProperties(invoiceRegistration, invoiceRegistrationDto);
-        QueryWrapper<InvoiceRegistrationProduct> queryWrapper = new QueryWrapper<>();
-        queryWrapper.eq("invoice_registration_id", id);
-        List<InvoiceRegistrationProduct> invoiceRegistrationProductList = invoiceRegistrationProductMapper.selectList(queryWrapper);
-        List<InvoiceRegistrationProductDto> invoiceRegistrationProductDtoList = invoiceRegistrationProductList.stream().map(item -> {
-            InvoiceRegistrationProductDto invoiceRegistrationProductDto = new InvoiceRegistrationProductDto();
-            BeanUtils.copyProperties(item, invoiceRegistrationProductDto);
-            return invoiceRegistrationProductDto;
-        }).collect(Collectors.toList());
-        invoiceRegistrationDto.setProductDtoList(invoiceRegistrationProductDtoList);
-        return invoiceRegistrationDto;
-    }
-
-    /**
-     * 寮�绁ㄧ櫥璁板鍑�
-     * @param response
-     * @param invoiceRegistrationDto
-     */
-    @Override
-    public void invoiceRegistrationExport(HttpServletResponse response, InvoiceRegistrationDto invoiceRegistrationDto) {
-        List<InvoiceRegisAndProductExcelDto> invoiceRegisAndProductExcelDtoList = invoiceRegistrationMapper.invoiceRegisAndProductExcelDtoList();
-        ExcelUtil<InvoiceRegisAndProductExcelDto> util = new ExcelUtil<InvoiceRegisAndProductExcelDto>(InvoiceRegisAndProductExcelDto.class);
-        util.exportExcel(response, invoiceRegisAndProductExcelDtoList, "寮�绁ㄧ櫥璁颁俊鎭�");
-    }
-}
diff --git a/src/main/java/com/ruoyi/sales/service/impl/ReceiptPaymentServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/ReceiptPaymentServiceImpl.java
deleted file mode 100644
index 677249a..0000000
--- a/src/main/java/com/ruoyi/sales/service/impl/ReceiptPaymentServiceImpl.java
+++ /dev/null
@@ -1,349 +0,0 @@
-package com.ruoyi.sales.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.account.pojo.AccountIncome;
-import com.ruoyi.account.service.AccountIncomeService;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.sales.dto.InvoiceLedgerDto;
-import com.ruoyi.sales.dto.ReceiptPaymentDto;
-import com.ruoyi.sales.dto.ReceiptPaymentExeclDto;
-import com.ruoyi.sales.mapper.ReceiptPaymentMapper;
-import com.ruoyi.sales.mapper.SalesLedgerMapper;
-import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.pojo.ReceiptPayment;
-import com.ruoyi.sales.pojo.SalesLedger;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import com.ruoyi.sales.service.ReceiptPaymentService;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.RequiredArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.ObjectUtils;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.YearMonth;
-import java.util.*;
-
-@Service
-@RequiredArgsConstructor
-public class ReceiptPaymentServiceImpl extends ServiceImpl<ReceiptPaymentMapper,ReceiptPayment> implements ReceiptPaymentService {
-
-    private final ReceiptPaymentMapper receiptPaymentMapper;
-    private final SalesLedgerMapper salesLedgerMapper;
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-    private final AccountIncomeService accountIncomeService;
-
-    /**
-     * 鍥炴鐧昏鏂板
-     * @param receiptPaymentList
-     * @return
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public int receiptPaymentSaveOrUpdate(List<ReceiptPayment> receiptPaymentList) {
-        for (ReceiptPayment receiptPayment : receiptPaymentList) {
-            ReceiptPayment byId = receiptPayment;
-            if (!ObjectUtils.isEmpty(receiptPayment.getId())){
-                receiptPayment = this.getById(receiptPayment.getId());
-            }
-            SalesLedger salesLedger = salesLedgerMapper.selectById(receiptPayment.getSalesLedgerId());
-            if(null==salesLedger) throw new RuntimeException("鏈壘鍒伴攢鍞崟");
-            // 宸插洖娆鹃噾棰�
-            SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(receiptPayment.getSalesLedgerProductId());
-            if(null==salesLedgerProduct) throw new RuntimeException("鏈壘鍒伴攢鍞崟浜у搧");
-            if (salesLedgerProduct.getPendingInvoiceTotal().add(receiptPayment.getReceiptPaymentAmount()).compareTo(byId.getReceiptPaymentAmount())<0){
-                throw new RuntimeException("鏈鍥炴閲戦涓嶈兘澶т簬寰呭洖娆鹃噾棰�+鍥炴閲戦");
-            }
-            if(null==receiptPayment.getId()){
-                salesLedgerProduct.setInvoiceTotal(salesLedgerProduct.getInvoiceTotal().add(receiptPayment.getReceiptPaymentAmount()));
-                salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice().subtract(salesLedgerProduct.getInvoiceTotal()));
-                receiptPaymentMapper.insert(receiptPayment);
-                // 澧炲姞璐㈠姟鏀跺叆璁板綍
-                AccountIncome accountIncome = new AccountIncome();
-                accountIncome.setIncomeDate(salesLedger.getEntryDate());
-                accountIncome.setIncomeType("3");
-                accountIncome.setCustomerName(salesLedger.getCustomerName());
-                accountIncome.setIncomeMoney(receiptPayment.getReceiptPaymentAmount());
-                accountIncome.setIncomeMethod(receiptPayment.getReceiptPaymentType());
-                accountIncome.setInputTime(new Date());
-                accountIncome.setInputUser(SecurityUtils.getLoginUser().getNickName());
-                accountIncome.setIncomeDescribed("鍥炴鏀跺叆");
-                accountIncome.setBusinessId(Long.parseLong(receiptPayment.getId().toString()));
-                accountIncome.setBusinessType(1);
-                accountIncomeService.save(accountIncome);
-            }else {
-                BigDecimal subtract = byId.getReceiptPaymentAmount().subtract(receiptPayment.getReceiptPaymentAmount());
-                salesLedgerProduct.setInvoiceTotal(salesLedgerProduct.getInvoiceTotal().add(subtract));
-                salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice().subtract(salesLedgerProduct.getInvoiceTotal()));
-                receiptPayment.setReceiptPaymentAmount(byId.getReceiptPaymentAmount());
-                receiptPayment.setReceiptPaymentType(byId.getReceiptPaymentType());
-                receiptPaymentMapper.updateById(receiptPayment);
-                // 淇敼璐㈠姟鏀跺叆璁板綍
-                LambdaQueryWrapper<AccountIncome> accountIncomeLambdaQueryWrapper = new LambdaQueryWrapper<>();
-                accountIncomeLambdaQueryWrapper.eq(AccountIncome::getBusinessId, receiptPayment.getId())
-                        .eq(AccountIncome::getBusinessType, 1);
-                AccountIncome accountIncome = accountIncomeService.getOne(accountIncomeLambdaQueryWrapper);
-                if(null!=accountIncome){
-                    accountIncome.setIncomeMoney(receiptPayment.getReceiptPaymentAmount());
-                    accountIncomeService.updateById(accountIncome);
-                }
-            }
-            salesLedgerProductMapper.updateById(salesLedgerProduct);
-        }
-        return 1;
-    }
-
-    /**
-     * 鍥炴鐧昏淇敼
-     * @param receiptPayment
-     * @return
-     */
-    @Override
-    public int receiptPaymentUpdate(ReceiptPayment receiptPayment) {
-        ReceiptPayment byId = receiptPayment;
-        if (!ObjectUtils.isEmpty(receiptPayment.getId())){
-            receiptPayment = this.getById(receiptPayment.getId());
-        }
-        SalesLedger salesLedger = salesLedgerMapper.selectById(receiptPayment.getSalesLedgerId());
-        if(null==salesLedger) throw new RuntimeException("鏈壘鍒伴攢鍞崟");
-        // 宸插洖娆鹃噾棰�
-        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(receiptPayment.getSalesLedgerProductId());
-        if(null==salesLedgerProduct) throw new RuntimeException("鏈壘鍒伴攢鍞崟浜у搧");
-        if (salesLedgerProduct.getPendingInvoiceTotal().compareTo(receiptPayment.getReceiptPaymentAmount())<0){
-            throw new RuntimeException("鏈鍥炴閲戦涓嶈兘澶т簬寰呭洖娆鹃噾棰�");
-        }
-        BigDecimal subtract = receiptPayment.getReceiptPaymentAmount().subtract(byId.getReceiptPaymentAmount());
-        salesLedgerProduct.setInvoiceTotal(salesLedgerProduct.getInvoiceTotal().add(subtract));
-        salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice().subtract(salesLedgerProduct.getInvoiceTotal()));
-        // 淇敼璐㈠姟鏀跺叆璁板綍
-        LambdaQueryWrapper<AccountIncome> accountIncomeLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        accountIncomeLambdaQueryWrapper.eq(AccountIncome::getBusinessId, receiptPayment.getId())
-                .eq(AccountIncome::getBusinessType, 1);
-        AccountIncome accountIncome = accountIncomeService.getOne(accountIncomeLambdaQueryWrapper);
-        if(null!=accountIncome){
-            accountIncome.setIncomeMoney(receiptPayment.getReceiptPaymentAmount());
-            accountIncomeService.updateById(accountIncome);
-        }
-        salesLedgerProductMapper.updateById(salesLedgerProduct);
-        receiptPayment.setReceiptPaymentAmount(byId.getReceiptPaymentAmount());
-        receiptPayment.setReceiptPaymentType(byId.getReceiptPaymentType());
-        return receiptPaymentMapper.updateById(receiptPayment);
-    }
-
-    /**
-     * 鍥炴鐧昏鍒犻櫎
-     * @param ids
-     * @return
-     */
-    @Override
-    public int receiptPaymentDel(List<Integer> ids) {
-        LambdaQueryWrapper<ReceiptPayment> delQuery = new LambdaQueryWrapper<>();
-        delQuery.in(ReceiptPayment::getId, ids);
-        List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(delQuery);
-        if(CollectionUtils.isEmpty(receiptPayments)) throw new RuntimeException("鏈壘鍒板洖娆剧櫥璁�");
-        // 閲嶆柊璁$畻閿�鍞骇鍝佸洖娆鹃噾棰�
-        for (ReceiptPayment receiptPayment : receiptPayments) {
-            SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(receiptPayment.getSalesLedgerProductId());
-            salesLedgerProduct.setInvoiceTotal(salesLedgerProduct.getInvoiceTotal().subtract(receiptPayment.getReceiptPaymentAmount()));
-            salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice().subtract(salesLedgerProduct.getInvoiceTotal()));
-            salesLedgerProductMapper.updateById(salesLedgerProduct);
-        }
-        // 鍒犻櫎璐㈠姟鏀跺叆璁板綍
-        LambdaQueryWrapper<AccountIncome> accountIncomeLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        accountIncomeLambdaQueryWrapper.in(AccountIncome::getBusinessId, ids)
-                .eq(AccountIncome::getBusinessType, 1);
-        accountIncomeService.remove(accountIncomeLambdaQueryWrapper);
-        return receiptPaymentMapper.delete(delQuery);
-    }
-
-    /**
-     * 鍥炴鐧昏鍒嗛〉鏌ヨ
-     * @param page
-     * @param receiptPaymentDto
-     * @return
-     */
-    @Override
-    public IPage<ReceiptPaymentDto> receiptPaymentListPage(Page page, ReceiptPaymentDto receiptPaymentDto) {
-        // 璁$畻鍒嗛〉鍓峱age.current-1 * limit鏉℃暟鐨勭患鍚堣绠楀凡缁忔敹鍥炵殑鍥炴閲戦
-        // 璁$畻宸茬粡鍒嗛〉鐨勬潯鏁�
-        long total = (page.getCurrent() - 1) * page.getSize();
-        BigDecimal receiptAmount = receiptPaymentMapper.getReceiptAmount(receiptPaymentDto.getCustomerId(), total);
-        if(ObjectUtils.isEmpty(receiptAmount)){
-            receiptAmount = BigDecimal.ZERO;
-        }
-        IPage<ReceiptPaymentDto> iPage = receiptPaymentMapper.receiptPaymentListPage(page, receiptPaymentDto);
-        // 寮�绁ㄦ�婚噾棰�
-        BigDecimal invoiceTotal = CollectionUtils.isEmpty(iPage.getRecords()) ? BigDecimal.ZERO : iPage.getRecords().get(0).getInvoiceTotal();
-        // 褰撳墠搴旀敹閲戦
-        BigDecimal currentUnReceiptAmount = invoiceTotal.subtract(receiptAmount);
-        for (ReceiptPaymentDto record : iPage.getRecords()) {
-            currentUnReceiptAmount = currentUnReceiptAmount.subtract(record.getReceiptPaymentAmount());
-            record.setNoReceiptAmount(currentUnReceiptAmount);
-        }
-        return iPage;
-    }
-
-    /**
-     * 鍥炴鐧昏璇︽儏
-     * @param id
-     * @return
-     */
-    @Override
-    public ReceiptPaymentDto receiptPaymentInfo(Integer id) {
-        return receiptPaymentMapper.receiptPaymentInfo(id);
-    }
-
-    @Override
-    public BigDecimal getReceiptAmount() {
-        LocalDate now = LocalDate.now();
-        YearMonth currentMonth = YearMonth.from(now);
-
-        // 鍒涘缓LambdaQueryWrapper
-        LambdaQueryWrapper<ReceiptPayment> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.ge(ReceiptPayment::getReceiptPaymentDate, currentMonth.atDay(1).atStartOfDay())  // 澶т簬绛変簬鏈湀绗竴澶�
-                .lt(ReceiptPayment::getReceiptPaymentDate, currentMonth.plusMonths(1).atDay(1).atStartOfDay()); // 灏忎簬涓嬫湀绗竴澶�
-
-        // 鎵ц鏌ヨ骞惰绠楁�诲拰
-        List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(queryWrapper);
-
-        BigDecimal totalContractAmount = receiptPayments.stream()
-                .map(ReceiptPayment::getReceiptPaymentAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-        return totalContractAmount;
-    }
-
-    /**
-     * 鏌ヨ宸茬粡缁戝畾鍙戠エ鐨勫紑绁ㄥ彴璐�
-     * @param page
-     * @param receiptPaymentDto
-     * @return
-     */
-    @Override
-    public IPage<ReceiptPaymentDto> bindInvoiceNoRegPage(Page page, ReceiptPaymentDto receiptPaymentDto) {
-        IPage<ReceiptPaymentDto> receiptPaymentDtoIPage = receiptPaymentMapper.bindInvoiceNoRegPage(page, receiptPaymentDto);
-//        if (receiptPaymentDto.getStatus()) {
-//            long count = receiptPaymentDtoIPage.getRecords()
-//                    .stream()
-//                    .filter(receiptPaymentDto1 -> new BigDecimal("0.00").equals(receiptPaymentDto1.getNoReceiptAmount()))
-//                    .count();
-//            receiptPaymentDtoIPage
-//                    .getRecords()
-//                    .removeIf(receiptPaymentDto1 -> new BigDecimal("0.00").equals(receiptPaymentDto1.getNoReceiptAmount()));
-//            receiptPaymentDtoIPage.setTotal(receiptPaymentDtoIPage.getTotal() - count);
-//        }
-        receiptPaymentDtoIPage.getRecords().forEach(item -> {
-            // 姣旇緝鍥炴閲戦 == 寰呭洖娆鹃噾棰�
-            if (item.getInvoiceTotal().compareTo(item.getReceiptPaymentAmountTotal()) == 0) {
-                item.setStatusName("宸插畬鎴愬洖娆�");
-            }else{
-                item.setStatusName("鏈畬鎴愬洖娆�");
-            }
-
-        });
-        return receiptPaymentDtoIPage;
-    }
-
-    /**
-     * 寮�绁ㄥ彴璐﹁鎯�
-     * @param id
-     * @return
-     */
-    @Override
-    public InvoiceLedgerDto invoiceInfo(Integer id) {
-        return receiptPaymentMapper.invoiceInfo(id);
-    }
-
-    @Override
-    public Map<String,BigDecimal> getAmountMouth() {
-        List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(null);
-        BigDecimal contractAmount = salesLedgers.stream().map(SalesLedger::getContractAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-        LocalDate now = LocalDate.now();
-        YearMonth currentMonth = YearMonth.from(now);
-
-        // 鍒涘缓LambdaQueryWrapper
-        LambdaQueryWrapper<ReceiptPayment> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.ge(ReceiptPayment::getReceiptPaymentDate, currentMonth.atDay(1).atStartOfDay())  // 澶т簬绛変簬鏈湀绗竴澶�
-                .lt(ReceiptPayment::getReceiptPaymentDate, currentMonth.plusMonths(1).atDay(1).atStartOfDay()); // 灏忎簬涓嬫湀绗竴澶�
-
-        // 鎵ц鏌ヨ骞惰绠楁�诲拰
-        List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(queryWrapper);
-
-        BigDecimal receiveAmount = receiptPayments.stream()
-                .map(ReceiptPayment::getReceiptPaymentAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-        // 鏋勫缓缁撴灉
-        Map<String, BigDecimal> result = new HashMap<>();
-        result.put("receiveAmount", receiveAmount);
-        result.put("contractAmount", contractAmount);
-        return result;
-    }
-
-    /**
-     * 鏌ヨ鍥炴璁板綍
-     */
-    @Override
-    public List<ReceiptPaymentDto> receiptPaymentHistoryList(ReceiptPaymentDto receiptPaymentDto) {
-        return receiptPaymentMapper.receiptPaymentHistoryList(receiptPaymentDto);
-    }
-
-    /**
-     * 鏌ヨ鍥炴璁板綍鍒嗛〉
-     */
-    @Override
-    public IPage<ReceiptPaymentDto> receiptPaymentHistoryListPage(Page page, ReceiptPaymentDto receiptPaymentDto) {
-        return receiptPaymentMapper.receiptPaymentHistoryListPage(page, receiptPaymentDto);
-    }
-
-    /**
-     * 瀹㈡埛寰�鏉ヨ褰曟煡璇�
-     * @param receiptPaymentDto
-     * @return
-     */
-    @Override
-    public List<InvoiceLedgerDto> customerInteractions(InvoiceLedgerDto receiptPaymentDto) {
-        return receiptPaymentMapper.invoiceLedgerSalesAccount(receiptPaymentDto);
-    }
-
-    /**
-     * 鏌ヨ鍥炴璁板綍鍒嗛〉
-     */
-    @Override
-    public List<ReceiptPaymentDto> receiptPaymentHistoryListNoPage(ReceiptPaymentDto receiptPaymentDto) {
-        return receiptPaymentMapper.receiptPaymentHistoryListNoPage( receiptPaymentDto);
-    }
-
-    @Override
-    public void exportPaymentList(HttpServletResponse response) {
-       List<ReceiptPaymentDto> receiptPaymentDtoList =  receiptPaymentMapper.bindInvoiceNoRegListAll();
-        ExcelUtil<ReceiptPaymentDto> util = new ExcelUtil<ReceiptPaymentDto>(ReceiptPaymentDto.class);
-        util.exportExcel(response, receiptPaymentDtoList, "鍥炴鐧昏");
-    }
-
-    @Override
-    public void exportPaymentList(HttpServletResponse response, List<Long> ids) {
-        if (ids == null) {
-            List<ReceiptPaymentExeclDto> receiptPaymentDtoList =  receiptPaymentMapper.bindInvoiceNoRegListByIds(new ArrayList<>(), SecurityUtils.getLoginUser().getTenantId());
-            ExcelUtil<ReceiptPaymentExeclDto> util = new ExcelUtil<ReceiptPaymentExeclDto>(ReceiptPaymentExeclDto.class);
-            util.exportExcel(response, receiptPaymentDtoList, "鍥炴鐧昏");
-        }else {
-            List<ReceiptPaymentExeclDto> receiptPaymentDtoList =  receiptPaymentMapper.bindInvoiceNoRegListByIds(ids,SecurityUtils.getLoginUser().getTenantId());
-            ExcelUtil<ReceiptPaymentExeclDto> util = new ExcelUtil<ReceiptPaymentExeclDto>(ReceiptPaymentExeclDto.class);
-            util.exportExcel(response, receiptPaymentDtoList, "鍥炴鐧昏");
-        }
-
-    }
-}
diff --git a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
index 8ce023b..19aa02f 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -3,8 +3,6 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-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.framework.web.domain.R;
 import com.ruoyi.procurementrecord.utils.StockUtils;
@@ -14,9 +12,6 @@
 import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
 import com.ruoyi.quality.mapper.QualityInspectMapper;
-import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
-import com.ruoyi.sales.dto.SalesLedgerProductDto;
-import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper;
 import com.ruoyi.sales.mapper.SalesLedgerMapper;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
 import com.ruoyi.sales.mapper.ShippingInfoMapper;
@@ -76,8 +71,6 @@
     @Autowired
     private TechnologyBomStructureMapper technologyBomStructureMapper;
     @Autowired
-    private InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
-    @Autowired
     private ProductionProductMainMapper productionProductMainMapper;
     @Autowired
     private ProductionProductOutputMapper productionProductOutputMapper;
@@ -116,34 +109,6 @@
                     item.setExpressNumber(shippingInfo.getExpressNumber());
                 }
             });
-            // 寮�绁�
-            InvoiceRegistrationProductDto invoiceRegistrationProductDto = new InvoiceRegistrationProductDto();
-            invoiceRegistrationProductDto.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId().intValue());
-            List<InvoiceRegistrationProductDto> invoiceRegistrationProductDtoList = invoiceRegistrationProductMapper.invoiceRegistrationProductList(invoiceRegistrationProductDto);
-            // 缁熻寮�绁ㄧ櫥璁颁骇鍝佺殑宸插紑绁ㄦ暟/宸插紑绁ㄩ噾棰�
-            if (!CollectionUtils.isEmpty(invoiceRegistrationProductDtoList)) {
-                for (SalesLedgerProduct ledgerProduct : salesLedgerProducts) {
-                    BigDecimal invoiceNum = BigDecimal.ZERO;
-                    BigDecimal invoiceAmount = BigDecimal.ZERO;
-                    BigDecimal noInvoiceNum = BigDecimal.ZERO;
-                    BigDecimal noInvoiceAmount = BigDecimal.ZERO;
-                    for (InvoiceRegistrationProductDto registrationProductDto : invoiceRegistrationProductDtoList) {
-                        if(ledgerProduct.getId().intValue() == registrationProductDto.getSalesLedgerProductId()){
-                            invoiceNum =  invoiceNum.add(registrationProductDto.getInvoiceNum());
-                            invoiceAmount = invoiceAmount.add(registrationProductDto.getInvoiceAmount());
-                        }
-                    }
-                    noInvoiceNum = ledgerProduct.getQuantity().subtract(invoiceNum);
-                    noInvoiceAmount = ledgerProduct.getTaxInclusiveTotalPrice().subtract(invoiceAmount);
-                    ledgerProduct.setInvoiceNum(invoiceNum);
-                    ledgerProduct.setInvoiceAmount(invoiceAmount);
-                    ledgerProduct.setNoInvoiceNum(noInvoiceNum);
-                    ledgerProduct.setNoInvoiceAmount(noInvoiceAmount);
-
-
-                }
-            }
-
         }
         return salesLedgerProducts;
     }
@@ -199,18 +164,6 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int addOrUpdateSalesLedgerProduct(SalesLedgerProduct salesLedgerProduct) {
-        // 寰呭洖娆撅紝浠樻
-        if(salesLedgerProduct.getType().equals(1)){
-            salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice().subtract(salesLedgerProduct.getInvoiceTotal()));
-            //鏈紑绁ㄦ暟閲�+閲戦
-            salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity());
-            salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice());
-        }else{
-            salesLedgerProduct.setPendingTicketsTotal(salesLedgerProduct.getTaxInclusiveTotalPrice().subtract(salesLedgerProduct.getTicketsTotal()));
-            // 鏈潵绁ㄦ暟閲�+閲戦
-            salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity());
-            salesLedgerProduct.setFutureTicketsAmount(salesLedgerProduct.getTaxInclusiveTotalPrice());
-        }
 
         int result;
         Long salesLedgerId = salesLedgerProduct.getSalesLedgerId();
@@ -220,7 +173,6 @@
             addProductionData(salesLedgerProduct);
         } else {
             //鏌ヨ鍘熸湰鐨勪骇鍝佸瀷鍙穒d
-            salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity());
             result = salesLedgerProductMapper.updateById(salesLedgerProduct);
             /*鍒犻櫎瀵瑰簲鐨勭敓浜ф暟鎹苟閲嶆柊鏂板*/
             deleteProductionData(Arrays.asList(salesLedgerProduct.getId()));
@@ -285,6 +237,9 @@
      * 鍒犻櫎鐢熶骇璁″垝
      */
     public void deleteProductionData(List<Long> productIds) {
+        if (CollectionUtils.isEmpty(productIds)) {
+            return;
+        }
         List<ProductionPlan> productionPlans = productionPlanMapper.selectList(
                 new LambdaQueryWrapper<ProductionPlan>()
                         .in(ProductionPlan::getSalesLedgerProductId, productIds.stream().map(Long::intValue).collect(Collectors.toList())));
@@ -297,34 +252,6 @@
         }
         List<Long> ids = productionPlans.stream().map(ProductionPlan::getId).collect(Collectors.toList());
         productionPlanMapper.deleteByIds(ids);
-    }
-
-    @Override
-    public IPage<SalesLedgerProductDto> listPage(Page page, SalesLedgerProductDto salesLedgerProduct) {
-        IPage<SalesLedgerProductDto> salesLedgerProductDtoIPage = salesLedgerProductMapper.listPage(page, salesLedgerProduct);
-        salesLedgerProductDtoIPage.getRecords().forEach(item -> {
-            // 鍒ゆ柇鐘舵��
-            if(item.getTaxInclusiveTotalPrice().compareTo(item.getInvoiceTotal()) == 0){
-                item.setStatusName("宸插畬鎴愪粯娆�");
-            }else{
-                item.setStatusName("鏈畬鎴愪粯娆�");
-            }
-        });
-        return salesLedgerProductDtoIPage;
-    }
-
-    @Override
-    public IPage<SalesLedgerProductDto> listPagePurchaseLedger(Page page, SalesLedgerProductDto salesLedgerProduct) {
-        IPage<SalesLedgerProductDto> salesLedgerProductDtoIPage = salesLedgerProductMapper.listPagePurchaseLedger(page, salesLedgerProduct);
-        salesLedgerProductDtoIPage.getRecords().forEach(item -> {
-            // 鍒ゆ柇鐘舵��
-            if(item.getTaxInclusiveTotalPrice().compareTo(item.getTicketsTotal()) == 0){
-                item.setStatusName("宸插畬鎴愪粯娆�");
-            }else{
-                item.setStatusName("鏈畬鎴愪粯娆�");
-            }
-        });
-        return salesLedgerProductDtoIPage;
     }
 
     /**
diff --git a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
index a2f918b..a76b149 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -8,7 +8,6 @@
 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.account.service.AccountIncomeService;
 import com.ruoyi.basic.enums.ApplicationTypeEnum;
 import com.ruoyi.basic.enums.RecordTypeEnum;
 import com.ruoyi.basic.mapper.CustomerMapper;
@@ -27,7 +26,6 @@
 import com.ruoyi.framework.security.LoginUser;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.other.mapper.TempFileMapper;
-import com.ruoyi.other.pojo.TempFile;
 import com.ruoyi.production.mapper.*;
 import com.ruoyi.production.service.ProductionProductMainService;
 import com.ruoyi.project.system.domain.SysDept;
@@ -44,7 +42,6 @@
 import com.ruoyi.sales.vo.SalesLedgerVo;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.io.FilenameUtils;
 import org.jetbrains.annotations.Nullable;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -55,15 +52,10 @@
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
-import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.YearMonth;
@@ -86,20 +78,15 @@
     private static final String LOCK_PREFIX = "contract_no_lock:";
     private static final long LOCK_WAIT_TIMEOUT = 10; // 閿佺瓑寰呰秴鏃舵椂闂达紙绉掞級
     private static final long LOCK_EXPIRE_TIME = 30;  // 閿佽嚜鍔ㄨ繃鏈熸椂闂达紙绉掞級
-    private final AccountIncomeService accountIncomeService;
     private final SalesLedgerMapper salesLedgerMapper;
     private final CustomerMapper customerMapper;
     private final SalesLedgerProductMapper salesLedgerProductMapper;
     private final SalesLedgerProductServiceImpl salesLedgerProductServiceImpl;
     private final CommonFileMapper commonFileMapper;
     private final TempFileMapper tempFileMapper;
-    private final ReceiptPaymentMapper receiptPaymentMapper;
     private final ShippingInfoServiceImpl shippingInfoServiceImpl;
     private final CommonFileServiceImpl commonFileService;
     private final ShippingInfoMapper shippingInfoMapper;
-    private final InvoiceLedgerMapper invoiceLedgerMapper;
-    private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
-    private final InvoiceRegistrationMapper invoiceRegistrationMapper;
     private final ProductionProductMainMapper productionProductMainMapper;
     private final ProductionProductOutputMapper productionProductOutputMapper;
     private final ProductionProductInputMapper productionProductInputMapper;
@@ -176,10 +163,6 @@
         productWrapper.eq(SalesLedgerProduct::getType, 1);
         List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
         for (SalesLedgerProduct product : products) {
-            product.setOriginalNoInvoiceNum(product.getNoInvoiceNum());
-            // 鎻愪緵涓存椂鏈紑绁ㄦ暟锛屾湭寮�绁ㄩ噾棰濅緵鍓嶆璁$畻
-            product.setTempnoInvoiceAmount(product.getNoInvoiceAmount());
-            product.setTempNoInvoiceNum(product.getNoInvoiceNum());
             product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName());
             product.setRegisterDate(LocalDateTime.now());
             // 鍙戣揣淇℃伅
@@ -289,38 +272,10 @@
             LocalDateTime startTime = yearMonth.atDay(1).atStartOfDay();
             LocalDateTime endTime = yearMonth.atEndOfMonth().atTime(23, 59, 59);
 
-            //  鍥炴閲戦
-            LambdaQueryWrapper<ReceiptPayment> receiptPaymentQuery = new LambdaQueryWrapper<>();
-            receiptPaymentQuery
-                    .ge(ReceiptPayment::getCreateTime, startTime)
-                    .le(ReceiptPayment::getCreateTime, endTime);
-
-            List<ReceiptPayment> receiptPayments =
-                    receiptPaymentMapper.selectList(receiptPaymentQuery);
-
-            BigDecimal receiptAmount = receiptPayments.stream()
-                    .map(ReceiptPayment::getReceiptPaymentAmount)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-            //  寮�绁ㄩ噾棰�
-            LambdaQueryWrapper<InvoiceLedger> invoiceLedgerQuery = new LambdaQueryWrapper<>();
-            invoiceLedgerQuery
-                    .ge(InvoiceLedger::getCreateTime, startTime)
-                    .le(InvoiceLedger::getCreateTime, endTime);
-
-            List<InvoiceLedger> invoiceLedgers =
-                    invoiceLedgerMapper.selectList(invoiceLedgerQuery);
-
-            BigDecimal invoiceAmount = invoiceLedgers.stream()
-                    .map(InvoiceLedger::getInvoiceTotal)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-
             MonthlyAmountDto dto = new MonthlyAmountDto();
             dto.setMonth(yearMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")));
-            dto.setReceiptAmount(receiptAmount);
-            dto.setInvoiceAmount(invoiceAmount);
+            dto.setReceiptAmount(BigDecimal.ZERO);
+            dto.setInvoiceAmount(BigDecimal.ZERO);
 
             result.add(dto);
         }
@@ -370,6 +325,7 @@
                 SalesLedger salesLedger = new SalesLedger();
                 BeanUtils.copyProperties(salesLedgerImportDto, salesLedger);
                 salesLedger.setExecutionDate(DateUtils.toLocalDate(salesLedgerImportDto.getExecutionDate()));
+                salesLedger.setDeliveryDate(DateUtils.toLocalDate(salesLedgerImportDto.getDeliveryDate()));
                 // 閫氳繃瀹㈡埛鍚嶇О鏌ヨ瀹㈡埛ID锛屽鎴峰悎鍚屽彿
                 salesLedger.setCustomerId(customers.stream()
                         .filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName()))
@@ -408,10 +364,8 @@
                     salesLedgerProduct.setType(1);
                     // 璁$畻涓嶅惈绋庢�讳环
                     salesLedgerProduct.setTaxExclusiveTotalPrice(salesLedgerProduct.getTaxInclusiveTotalPrice().divide(new BigDecimal(1).add(salesLedgerProduct.getTaxRate().divide(new BigDecimal(100))), 2, RoundingMode.HALF_UP));
-                    salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity());
-                    salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxExclusiveTotalPrice());
                     list.stream()
-                            .filter(map -> map.get("productName").equals(salesLedgerProduct.getProductCategory()) && map.get("model").equals(salesLedgerProduct.getSpecificationModel()))
+                            .filter(map -> Objects.equals(map.get("productName"), salesLedgerProduct.getProductCategory()) && Objects.equals(map.get("model"), salesLedgerProduct.getSpecificationModel()))
                             .findFirst()
                             .ifPresent(map -> {
                                 salesLedgerProduct.setProductModelId(Long.parseLong(map.get("modelId").toString()));
@@ -430,7 +384,7 @@
                     salesLedgerProduct.setRegister(loginUser.getNickName());
                     salesLedgerProduct.setRegisterDate(LocalDateTime.now());
                     salesLedgerProduct.setApproveStatus(0);
-                    salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProductImportDto.getTaxInclusiveTotalPrice());
+                    salesLedgerProduct.setIsProduction(salesLedgerProductImportDto.getIsProduction() == 1);
                     salesLedgerProductMapper.insert(salesLedgerProduct);
                     // 娣诲姞鐢熶骇鏁版嵁
                     salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct);
@@ -440,8 +394,8 @@
             return AjaxResult.success("瀵煎叆鎴愬姛");
         } catch (Exception e) {
             e.printStackTrace();
+            return AjaxResult.error("瀵煎叆澶辫触锛�" + e.getMessage());
         }
-        return AjaxResult.success("瀵煎叆澶辫触");
     }
 
     @Override
@@ -463,11 +417,7 @@
             productWrapper.eq(SalesLedgerProduct::getType, 1);
             List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
             for (SalesLedgerProduct product : products) {
-                product.setOriginalNoInvoiceNum(product.getNoInvoiceNum());
-                // 鎻愪緵涓存椂鏈紑绁ㄦ暟锛屾湭寮�绁ㄩ噾棰濅緵鍓嶆璁$畻
-                product.setTempnoInvoiceAmount(product.getNoInvoiceAmount());
-                product.setTempNoInvoiceNum(product.getNoInvoiceNum());
-                product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName());
+               product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName());
                 product.setRegisterDate(LocalDateTime.now());
                 // 鍙戣揣淇℃伅
                 ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
@@ -540,29 +490,8 @@
             salesLedgerProductMapper.deleteBatchIds(productIds);
         }
 
-        LambdaQueryWrapper<InvoiceRegistrationProduct> wrapper = new LambdaQueryWrapper<>();
-        wrapper.in(InvoiceRegistrationProduct::getSalesLedgerId, idList);
-        List<InvoiceRegistrationProduct> invoiceRegistrationProducts = invoiceRegistrationProductMapper.selectList(wrapper);
         List<Integer> invoiceLedgerIds = new ArrayList<>();
-        if (CollectionUtils.isNotEmpty(invoiceRegistrationProducts)) {
-            LambdaQueryWrapper<InvoiceLedger> wrapperOne = new LambdaQueryWrapper<>();
-            wrapperOne.in(InvoiceLedger::getInvoiceRegistrationProductId, invoiceRegistrationProducts.stream().map(InvoiceRegistrationProduct::getId).collect(Collectors.toList()));
-            List<InvoiceLedger> invoiceLedgers = invoiceLedgerMapper.selectList(wrapperOne);
-            if (CollectionUtils.isNotEmpty(invoiceLedgers)) {
-                invoiceLedgerIds = invoiceLedgers.stream().map(InvoiceLedger::getId).collect(Collectors.toList());
-            }
-            invoiceLedgerMapper.delete(wrapperOne);
-        }
-        invoiceRegistrationProductMapper.delete(wrapper);
-        LambdaQueryWrapper<InvoiceRegistration> wrapperTwo = new LambdaQueryWrapper<>();
-        wrapperTwo.in(InvoiceRegistration::getSalesLedgerId, idList);
-        invoiceRegistrationMapper.delete(wrapperTwo);
 
-        if (CollectionUtils.isNotEmpty(invoiceLedgerIds)) {
-            LambdaQueryWrapper<ReceiptPayment> wrapperTree = new LambdaQueryWrapper<>();
-            wrapperTree.in(ReceiptPayment::getInvoiceLedgerId, invoiceLedgerIds);
-            receiptPaymentMapper.delete(wrapperTree);
-        }
         // 鍒犻櫎鍙戣揣鍙拌处璁板綍
         List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
                 .in(ShippingInfo::getSalesLedgerId, idList));
@@ -599,7 +528,10 @@
         salesLedger.setTenantId(customer.getTenantId());
         // 3. 鏂板鎴栨洿鏂颁富琛�
         if (salesLedger.getId() == null) {
-            String contractNo = generateSalesContractNo();
+            String contractNo = salesLedger.getSalesContractNo();
+            if (StringUtils.isEmpty(contractNo)) {
+                contractNo = generateSalesContractNo();
+            }
             salesLedger.setSalesContractNo(contractNo);
             salesLedgerMapper.insert(salesLedger);
         } else {
@@ -647,9 +579,6 @@
         if (!insertList.isEmpty()) {
             for (SalesLedgerProduct salesLedgerProduct : insertList) {
                 salesLedgerProduct.setType(type.getCode());
-                salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity());
-                salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice());
-                salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice());
                 salesLedgerProductMapper.insert(salesLedgerProduct);
                 // 娣诲姞鐢熶骇鏁版嵁
                 salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct);
diff --git a/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsDetailsVo.java b/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsDetailsVo.java
new file mode 100644
index 0000000..992860e
--- /dev/null
+++ b/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsDetailsVo.java
@@ -0,0 +1,33 @@
+package com.ruoyi.sales.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+@Data
+@Schema(name = "CustomerTransactionsDetailsVo", description = "钀ラ攢绠$悊--瀹㈡埛寰�鏉ユ槑缁�(杩斿洖)")
+public class CustomerTransactionsDetailsVo {
+
+    @Schema(description = "閿�鍞崟ID")
+    private Long salesLedgerId;
+
+    @Schema(description = "閿�鍞悎鍚屽彿")
+    private String salesContractNo;
+
+    @Schema(description = "閿�鍞悎鍚岀璁㈡棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDate executionDate;
+
+    @Schema(description = "鍚堝悓閲戦")
+    private BigDecimal contractAmount;
+
+    @Schema(description = "鏀舵閲戦")
+    private BigDecimal receiptPaymentAmount;
+
+    @Schema(description = "搴旀敹閲戦")
+    private BigDecimal receiptableAmount;
+
+}
diff --git a/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsVo.java b/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsVo.java
new file mode 100644
index 0000000..7b8fc1a
--- /dev/null
+++ b/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsVo.java
@@ -0,0 +1,30 @@
+package com.ruoyi.sales.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(name = "CustomerTransactionsVo", description = "钀ラ攢绠$悊--瀹㈡埛寰�鏉�(杩斿洖)")
+public class CustomerTransactionsVo {
+
+    @Schema(description = "瀹㈡埛ID")
+    private Long customerId;
+
+    @Schema(description = "瀹㈡埛鍚嶇О")
+    private String customerName;
+
+    @Schema(description = "鍚堝悓鎬婚噾棰�")
+    //璇ュ鎴烽攢鍞悎鍚岀疮璁¢噾棰�
+    private BigDecimal contractAmounts;
+
+    @Schema(description = "鏀舵閲戦")
+    //璇ュ鎴烽攢鍞敹娆剧疮璁¢噾棰�
+    private BigDecimal receiptPaymentAmount;
+
+    @Schema(description = "搴旀敹閲戦")
+    //璇ュ鎴烽攢鍞簲鏀剁疮璁¢噾棰�=璐㈠姟(鍑哄簱-閫�璐�)
+    private BigDecimal receiptableAmount;
+
+}
diff --git a/src/main/java/com/ruoyi/staff/service/impl/StaffSalaryMainServiceImpl.java b/src/main/java/com/ruoyi/staff/service/impl/StaffSalaryMainServiceImpl.java
index a6d4500..aad785a 100644
--- a/src/main/java/com/ruoyi/staff/service/impl/StaffSalaryMainServiceImpl.java
+++ b/src/main/java/com/ruoyi/staff/service/impl/StaffSalaryMainServiceImpl.java
@@ -3,9 +3,6 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.account.mapper.AccountExpenseMapper;
-import com.ruoyi.account.pojo.AccountExpense;
-import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.project.system.mapper.SysUserDeptMapper;
@@ -23,7 +20,6 @@
 import org.springframework.util.CollectionUtils;
 
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
@@ -45,7 +41,6 @@
     private final SchemeApplicableStaffServiceImpl schemeApplicableStaffService;
     private final SysUserDeptMapper sysUserDeptMapper;
     private final StaffLeaveMapper staffLeaveMapper;
-    private final AccountExpenseMapper accountExpenseMapper;
 
     @Override
     public AjaxResult listPage(Page page, StaffSalaryMain staffSalaryMain) {
@@ -99,21 +94,6 @@
                 detail.setMainId(staffSalaryMain.getId());
             });
             staffSalaryDetailService.saveBatch(staffSalaryMain.getStaffSalaryDetailList());
-        }
-        // 鍜岃储鍔¤仈鍔紝鏂板鏀嚭
-        if(staffSalaryMain.getStatus().equals(5)){
-            AccountExpense accountExpense = new AccountExpense();
-            accountExpense.setBusinessType(3);
-            accountExpense.setExpenseMoney(staffSalaryMain.getTotalSalary());
-            accountExpense.setBusinessId(staffSalaryMain.getId());
-            accountExpense.setExpenseDate(new Date());
-            accountExpense.setExpenseMethod("2");
-            accountExpense.setExpenseType("1");
-            accountExpense.setExpenseDescribed(staffSalaryMain.getSalaryTitle());
-            accountExpense.setNote(staffSalaryMain.getRemark());
-            accountExpense.setInputUser(SecurityUtils.getLoginUser().getNickName());
-            accountExpense.setInputTime(new Date());
-            accountExpenseMapper.insert(accountExpense);
         }
         return AjaxResult.success("淇敼鎴愬姛");
     }
diff --git a/src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java b/src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java
index 56ad762..17d7e77 100644
--- a/src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java
+++ b/src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java
@@ -18,6 +18,11 @@
      */
     private String model;
     /**
+     * 鎵规鍙�
+     */
+    private String batchNo;
+
+    /**
      * 浜у搧鍗曚綅
      */
     private String unit;
diff --git a/src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java b/src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
index bc08eee..33b7599 100644
--- a/src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
+++ b/src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
@@ -15,6 +15,7 @@
     private String productName;
     private String model;
     private String unit;
+    private String batchNo;
 
 
     //鍏ュ簱绫诲瀷
diff --git a/src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java b/src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java
index 022be78..0419f2f 100644
--- a/src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java
+++ b/src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java
@@ -21,6 +21,10 @@
      */
     private String model;
     /**
+     * 鎵规鍙�
+     */
+    private String batchNo;
+    /**
      * 浜у搧鍗曚綅
      */
     private String unit;
diff --git a/src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java b/src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java
index 4dd64c7..7d746ac 100644
--- a/src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java
+++ b/src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java
@@ -3,8 +3,8 @@
 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.account.bean.dto.PurchaseInboundDto;
-import com.ruoyi.account.bean.vo.PurchaseInboundVo;
+import com.ruoyi.account.bean.dto.purchase.PurchaseInboundDto;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
 import com.ruoyi.stock.dto.StockInRecordDto;
 import com.ruoyi.stock.execl.StockInRecordExportData;
 import com.ruoyi.stock.pojo.StockInRecord;
diff --git a/src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java b/src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java
index eb05e8c..c391587 100644
--- a/src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java
+++ b/src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java
@@ -3,8 +3,8 @@
 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.account.bean.dto.SalesOutboundDto;
-import com.ruoyi.account.bean.vo.SalesOutboundVo;
+import com.ruoyi.account.bean.dto.sales.SalesOutboundDto;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
 import com.ruoyi.stock.dto.StockOutRecordDto;
 import com.ruoyi.stock.execl.StockOutRecordExportData;
 import com.ruoyi.stock.pojo.StockOutRecord;
diff --git a/src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java b/src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
index 9a6bd9b..851a0e2 100644
--- a/src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
+++ b/src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
@@ -4,6 +4,8 @@
 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.account.mapper.sales.AccountInvoiceApplicationMapper;
+import com.ruoyi.account.mapper.sales.AccountSalesCollectionMapper;
 import com.ruoyi.common.enums.ReviewStatusEnum;
 import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
 import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
@@ -46,6 +48,8 @@
     private final StockOutRecordMapper stockOutRecordMapper;
     private final StockInventoryMapper stockInventoryMapper;
     private final StockUninventoryMapper stockUninventoryMapper;
+    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
+    private final AccountInvoiceApplicationMapper accountInvoiceApplicationMapper;
 
     @Override
     public IPage<StockOutRecordDto> listPage(Page page, StockOutRecordDto stockOutRecordDto) {
@@ -77,6 +81,11 @@
 
     @Override
     public int batchDelete(List<Long> ids) {
+        //todo 濡傛灉鍑哄簱涓庡紑绁ㄦ敹娆炬湁鍏宠仈鍒欐棤娉曞垹闄�
+        if (accountSalesCollectionMapper.existsByStockOutRecordId(ids) ||
+                accountInvoiceApplicationMapper.existsByStockOutRecordId(ids)) {
+            throw new BaseException("鍑哄簱璁板綍瀛樺湪寮�绁ㄦ敹娆惧叧鑱旀暟鎹�,鏃犳硶鍒犻櫎!!!");
+        }
         for (Long id : ids) {
             StockOutRecord stockOutRecord = stockOutRecordMapper.selectById(id);
             if (stockOutRecord.getType().equals("0")) {
@@ -97,7 +106,8 @@
                     stockInRecordDto.setBatchNo(stockInventory.getBatchNo());
                     stockInventoryMapper.updateAddStockInventory(stockInRecordDto);
                 }
-            }else if (stockOutRecord.getType().equals("1")) {
+            }
+            else if (stockOutRecord.getType().equals("1")) {
                 LambdaQueryWrapper<StockUninventory> wrapper = new LambdaQueryWrapper<StockUninventory>()
                         .eq(StockUninventory::getProductModelId, stockOutRecord.getProductModelId());
                 if (StringUtils.isEmpty(stockOutRecord.getBatchNo())) {
diff --git a/src/main/java/com/ruoyi/technology/service/impl/TechnologyRoutingServiceImpl.java b/src/main/java/com/ruoyi/technology/service/impl/TechnologyRoutingServiceImpl.java
index 0eff194..6750f03 100644
--- a/src/main/java/com/ruoyi/technology/service/impl/TechnologyRoutingServiceImpl.java
+++ b/src/main/java/com/ruoyi/technology/service/impl/TechnologyRoutingServiceImpl.java
@@ -9,6 +9,8 @@
 import com.ruoyi.common.utils.OrderUtils;
 import com.ruoyi.technology.bean.dto.TechnologyRoutingDto;
 import com.ruoyi.technology.bean.vo.TechnologyRoutingVo;
+import com.ruoyi.production.mapper.ProductionOrderRoutingMapper;
+import com.ruoyi.production.pojo.ProductionOrderRouting;
 import com.ruoyi.technology.mapper.*;
 import com.ruoyi.technology.pojo.*;
 import com.ruoyi.technology.service.TechnologyRoutingService;
@@ -39,6 +41,8 @@
     private final TechnologyOperationParamMapper technologyOperationParamMapper;
     private final TechnologyParamMapper technologyParamMapper;
     private final TechnologyRoutingOperationParamMapper technologyRoutingOperationParamMapper;
+
+    private final ProductionOrderRoutingMapper productionOrderRoutingMapper;
 
     @Override
     public IPage<TechnologyRoutingVo> pageTechnologyRouting(Page<TechnologyRoutingDto> page, TechnologyRoutingDto technologyRoutingDto) {
@@ -79,6 +83,13 @@
         if (ids == null || ids.isEmpty()) {
             return false;
         }
+        // 鍒ゆ柇鏄惁鏈夌敓浜ц鍗曠粦瀹氳宸ヨ壓璺嚎
+        Long count = productionOrderRoutingMapper.selectCount(
+                Wrappers.<ProductionOrderRouting>lambdaQuery()
+                        .in(ProductionOrderRouting::getTechnologyRoutingId, ids));
+        if (count > 0) {
+            throw new ServiceException("璇ュ伐鑹鸿矾绾垮凡缁戝畾鐢熶骇璁㈠崟锛屾棤娉曞垹闄わ紒");
+        }
         List<TechnologyRoutingOperation> routingOperationList = technologyRoutingOperationMapper.selectList(
                 Wrappers.<TechnologyRoutingOperation>lambdaQuery()
                         .in(TechnologyRoutingOperation::getTechnologyRoutingId, ids));
diff --git a/src/main/java/com/ruoyi/warehouse/controller/DocumentationFileController.java b/src/main/java/com/ruoyi/warehouse/controller/DocumentationFileController.java
index 9c8517e..f272150 100644
--- a/src/main/java/com/ruoyi/warehouse/controller/DocumentationFileController.java
+++ b/src/main/java/com/ruoyi/warehouse/controller/DocumentationFileController.java
@@ -1,8 +1,5 @@
 package com.ruoyi.warehouse.controller;
 
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.pojo.AccountFile;
-import com.ruoyi.account.service.AccountFileService;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.warehouse.pojo.DocumentationFile;
 import com.ruoyi.warehouse.service.DocumentationFileService;
diff --git a/src/main/java/com/ruoyi/warehouse/mapper/DocumentationFileMapper.java b/src/main/java/com/ruoyi/warehouse/mapper/DocumentationFileMapper.java
index 0617258..94d7eac 100644
--- a/src/main/java/com/ruoyi/warehouse/mapper/DocumentationFileMapper.java
+++ b/src/main/java/com/ruoyi/warehouse/mapper/DocumentationFileMapper.java
@@ -1,9 +1,6 @@
 package com.ruoyi.warehouse.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.account.pojo.AccountFile;
 import com.ruoyi.warehouse.pojo.DocumentationFile;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
diff --git a/src/main/java/com/ruoyi/warehouse/service/DocumentationFileService.java b/src/main/java/com/ruoyi/warehouse/service/DocumentationFileService.java
index 575ecd4..a5a8836 100644
--- a/src/main/java/com/ruoyi/warehouse/service/DocumentationFileService.java
+++ b/src/main/java/com/ruoyi/warehouse/service/DocumentationFileService.java
@@ -1,9 +1,6 @@
 package com.ruoyi.warehouse.service;
 
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.account.pojo.AccountFile;
 import com.ruoyi.warehouse.pojo.DocumentationFile;
 
 import java.util.List;
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index 6d34f6b..f1a5bf9 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -28,7 +28,7 @@
 # 寮�鍙戠幆澧冮厤缃�
 server:
   # 鏈嶅姟鍣ㄧ殑HTTP绔彛锛岄粯璁や负8080
-  port: 7006
+  port: 7005
   servlet:
     # 搴旂敤鐨勮闂矾寰�
     context-path: /
@@ -268,4 +268,3 @@
   compressQuality: 0.5 # 鍘嬬缉璐ㄩ噺(0.0-1.0)
 knowledge:
   one: D:\鏂扮枂澶х綏绱犱紒涓氫骇鍝佷綋绯昏鏄庢枃妗�.md
-
diff --git a/src/main/resources/approve-todo-agent-prompt.txt b/src/main/resources/approve-todo-agent-prompt.txt
index c309da8..f026fee 100644
--- a/src/main/resources/approve-todo-agent-prompt.txt
+++ b/src/main/resources/approve-todo-agent-prompt.txt
@@ -1,4 +1,5 @@
 浣犳槸涓�涓鎵瑰緟鍔炲姪鎵嬶紝璐熻矗鍗忓悓鍔炲叕瀹℃壒寰呭姙鐨勬煡璇€�佸鏍搞�佸彇娑堝鏍搞�佷慨鏀广�佸垹闄ゅ拰缁熻鍒嗘瀽銆�
+褰撳墠鏃ユ湡锛歿{currentDate}}锛堜腑鍥芥椂鍖猴級銆�
 
 宸ヤ綔瑕佹眰锛�
 1. 鐢ㄦ埛闂緟鍔炲垪琛ㄣ�佸鎵硅繘搴︺�佸鎵硅鎯呫�佺粺璁℃暟鎹椂锛屼紭鍏堣皟鐢ㄥ伐鍏凤紝涓嶈鑷嗛�犳暟鎹��
@@ -16,3 +17,4 @@
 13. 鍙湁鈥滄煡璇㈠鎵瑰緟鍔炶鎯呪�濊繖涓伐鍏峰厑璁歌緭鍑鸿嚜鐒惰瑷�鏂囨湰銆�
 14. 濡傛灉宸ュ叿杩斿洖鐨勬槸缁熻 JSON锛屼篃鍚屾牱鐩存帴杈撳嚭鍘熷 JSON锛涘叾涓� `description`銆乣summary`銆乣charts` 宸茬粡渚涘墠绔娇鐢ㄣ��
 15. 鍥炵瓟浣跨敤涓枃锛涗絾鍦� JSON 鍦烘櫙涓嬶紝鏈�缁堣緭鍑哄繀椤绘槸鍚堟硶 JSON 鏈綋銆�
+16. 鐢ㄦ埛鎻愬埌鈥滀粖骞�/鏈湀/浠婂ぉ/鏈�杩�/涓婃湀/鍘诲勾鈥濈瓑鐩稿鏃堕棿鏃讹紝蹇呴』涓ユ牸鍩轰簬鈥滃綋鍓嶆棩鏈熲�濇崲绠楋紝绂佹鑷鍋囪骞翠唤銆�
diff --git a/src/main/resources/financial-agent-prompt.txt b/src/main/resources/financial-agent-prompt.txt
new file mode 100644
index 0000000..2627da3
--- /dev/null
+++ b/src/main/resources/financial-agent-prompt.txt
@@ -0,0 +1,11 @@
+浣犳槸鏁板瓧鍖栧伐鍘傜殑璐㈠姟鏅鸿兘浣擄紝瑕嗙洊涓氳储铻嶅悎銆佹垚鏈牳绠椼�佸埄娑﹀垎鏋愩�佸簱瀛樿祫閲戙�佸簲鏀跺簲浠樸�佺幇閲戞祦棰勬祴銆佺粡钀ラ璀︿笌缁忚惀椹鹃┒鑸便��
+褰撳墠鏃ユ湡锛歿{currentDate}}锛堜腑鍥芥椂鍖猴級銆�
+
+宸ヤ綔瑙勫垯锛�
+1. 鐢ㄦ埛鎻愬嚭鈥滄煡銆侀棶銆佺粺璁°�佸垎鏋愩�侀璀︺�佸缓璁�佹姤鍛娾�濋渶姹傛椂锛屼紭鍏堣皟鐢ㄥ伐鍏疯繑鍥炵粨鏋勫寲 JSON锛屼笉缂栭�犱笟鍔℃暟鎹��
+2. 鍛戒腑鎴愭湰銆佸埄娑︺�佸簱瀛樿祫閲戙�佺幇閲戞祦銆侀璀︺�侀┚椹惰埍銆佹棩鎶ュ懆鎶ュ満鏅椂锛屼紭鍏堣皟鐢ㄥ搴斿伐鍏枫��
+3. 宸ュ叿杩斿洖 JSON 鏃讹紝鐩存帴杈撳嚭鍘熷 JSON 瀛楃涓诧紝涓嶈棰濆鍖呰9 Markdown锛屼篃涓嶈鍦ㄥ墠鍚庤拷鍔犺В閲婃枃鏈��
+4. 褰撶敤鎴烽棶棰樼己灏戞椂闂磋寖鍥存椂锛岄粯璁や娇鐢ㄥ伐鍏峰唴缃彛寰勶紙濡傝繎30澶┿�佹湰鏈堛�佽繎90澶╋級锛屽苟鍦ㄥ悗缁彲鎻愰啋鐢ㄦ埛琛ュ厖鑼冨洿銆�
+5. 鐢ㄦ埛闂�滀负浠�涔堝埄娑︿笅闄嶁�濃�滃摢涓鍗曚簭鎹熲�濃�滃摢涓鎴锋渶璧氶挶鈥濃�滃摢涓溅闂�/宸ュ簭鎴愭湰鏈�楂樷�濈瓑闂鏃讹紝浼樺厛鍩轰簬璁㈠崟鍒╂鼎涓庡伐搴忔垚鏈垎鏋愬伐鍏蜂綔绛斻��
+6. 鍥炵瓟蹇呴』浣跨敤涓枃锛涜嫢鏁版嵁涓嶈冻浠ュ緱鍑虹粨璁猴紝鏄庣‘鎸囧嚭缂哄皯鍝簺鍏抽敭瀛楁鎴栫瓫閫夋潯浠躲��
+7. 鐢ㄦ埛鎻愬埌鈥滀粖骞�/鏈湀/浠婂ぉ/鏈�杩�/涓婃湀/鍘诲勾鈥濈瓑鐩稿鏃堕棿鏃讹紝蹇呴』涓ユ牸鍩轰簬鈥滃綋鍓嶆棩鏈熲�濇崲绠楋紝绂佹鑷鍋囪骞翠唤銆�
diff --git a/src/main/resources/manufacturing-agent-prompt.txt b/src/main/resources/manufacturing-agent-prompt.txt
index c1a30c8..1653bb9 100644
--- a/src/main/resources/manufacturing-agent-prompt.txt
+++ b/src/main/resources/manufacturing-agent-prompt.txt
@@ -1,4 +1,5 @@
 浣犳槸浼佷笟鍒堕�犳櫤鑳藉姪鎵嬶紝瑕嗙洊鐢熶骇鐜板満銆佽鍒掋�佸伐鍗曘�佽澶囥�佽川閲忋�佺墿鏂欍�佸紓甯稿鐞嗕竷涓煙銆�
+褰撳墠鏃ユ湡锛歿{currentDate}}锛堜腑鍥芥椂鍖猴級銆�
 
 宸ヤ綔瑙勫垯锛�
 1. 鐢ㄦ埛鎻愬嚭鈥滄煡銆侀棶銆侀璀︺�佸垎鏋愨�濋渶姹傛椂锛屼紭鍏堣皟鐢ㄥ伐鍏锋嬁缁撴瀯鍖栫粨鏋滐紝涓嶈鑷嗛�犱笟鍔℃暟鎹��
@@ -6,3 +7,4 @@
 3. 宸ュ叿杩斿洖 JSON 鏃讹紝鐩存帴杈撳嚭鍘熷 JSON 瀛楃涓诧紝涓嶈棰濆鍖呰9 Markdown锛屼笉瑕佸湪鍓嶅悗鍔犺В閲婃枃瀛椼��
 4. 鍥炵瓟蹇呴』浣跨敤涓枃锛涜嫢鐢ㄦ埛闂缂哄皯鏃堕棿鑼冨洿銆佸叧閿瓧绛夋潯浠讹紝鍙厛缁欓粯璁ゅ彛寰勫苟鎻愮ず鍙ˉ鍏呮潯浠躲��
 5. 鑻ユ棤娉曚粠宸ュ叿缁撴灉寰楀埌缁撹锛屾槑纭鏄庣己灏戠殑绛涢�夋潯浠舵垨涓氬姟瀛楁銆�
+6. 鐢ㄦ埛鎻愬埌鈥滀粖骞�/鏈湀/浠婂ぉ/鏈�杩�/涓婃湀/鍘诲勾鈥濈瓑鐩稿鏃堕棿鏃讹紝蹇呴』涓ユ牸鍩轰簬鈥滃綋鍓嶆棩鏈熲�濇崲绠楋紝绂佹鑷鍋囪骞翠唤銆�
diff --git a/src/main/resources/mapper/account/AccountExpenseMapper.xml b/src/main/resources/mapper/account/AccountExpenseMapper.xml
deleted file mode 100644
index 77eed00..0000000
--- a/src/main/resources/mapper/account/AccountExpenseMapper.xml
+++ /dev/null
@@ -1,101 +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.account.mapper.AccountExpenseMapper">
-    <select id="accountExpenseListPage" resultType="com.ruoyi.account.pojo.AccountExpense">
-        SELECT
-        *
-        FROM account_expense
-        where
-        1=1
-        <if test="accountExpense.entryDateStart != null and accountExpense.entryDateStart != '' ">
-            AND expense_date &gt;= DATE_FORMAT(#{accountExpense.entryDateStart},'%Y-%m-%d')
-        </if>
-        <if test=" accountExpense.supplierName != null and accountExpense.supplierName != ''">
-            AND supplier_name like CONCAT('%',#{accountExpense.supplierName},'%')
-        </if>
-        <if test=" accountExpense.invoiceNumber != null and accountExpense.invoiceNumber != ''">
-            AND invoice_number like CONCAT('%',#{accountExpense.invoiceNumber},'%')
-        </if>
-        <if test="accountExpense.entryDateEnd != null and accountExpense.entryDateEnd != '' ">
-            AND  expense_date &lt;= DATE_FORMAT(#{accountExpense.entryDateEnd},'%Y-%m-%d')
-        </if>
-        <if test="accountExpense.expenseType != null and accountExpense.expenseType != '' ">
-            AND expense_type = #{accountExpense.expenseType}
-        </if>
-        <if test="accountExpense.expenseMethod != null and accountExpense.expenseMethod != '' ">
-            AND expense_method = #{accountExpense.expenseMethod}
-        </if>
-    </select>
-    <select id="accountExpenseExport" resultType="com.ruoyi.account.pojo.AccountExpense">
-        SELECT
-        *
-        FROM account_expense
-        where
-        1=1
-        <if test="accountExpense.entryDateStart != null and accountExpense.entryDateStart != '' ">
-            AND expense_date &gt;= DATE_FORMAT(#{accountExpense.entryDateStart},'%Y-%m-%d')
-        </if>
-        <if test="accountExpense.entryDateEnd != null and accountExpense.entryDateEnd != '' ">
-            AND  expense_date &lt;= DATE_FORMAT(#{accountExpense.entryDateEnd},'%Y-%m-%d')
-        </if>
-        <if test="accountExpense.expenseType != null and accountExpense.expenseType != '' ">
-            AND expense_type = #{accountExpense.expenseType}
-        </if>
-        <if test="accountExpense.expenseMethod != null and accountExpense.expenseMethod != '' ">
-            AND expense_method = #{accountExpense.expenseMethod}
-        </if>
-    </select>
-    <select id="report" resultType="com.ruoyi.account.bean.dto.AccountDto2">
-        SELECT
-        sdd.dict_label typeName,
-        sum(expense_money) account
-        FROM account_expense ae
-        left join sys_dict_data sdd on ae.expense_type = sdd.dict_value and  sdd.dict_type='expense_types'
-        where
-        1=1
-        <if test="dateQueryDto.entryDateStart != null and dateQueryDto.entryDateStart != '' ">
-            AND expense_date &gt;= DATE_FORMAT(#{dateQueryDto.entryDateStart},'%Y-%m-%d')
-        </if>
-        <if test="dateQueryDto.entryDateEnd != null and dateQueryDto.entryDateEnd != '' ">
-            AND expense_date &lt;= DATE_FORMAT(#{dateQueryDto.entryDateEnd},'%Y-%m-%d')
-        </if>
-        group by sdd.dict_label, ae.expense_type
-    </select>
-
-    <select id="report1" resultType="java.math.BigDecimal">
-        SELECT
-        ifnull(sum(expense_money),0) account
-        FROM account_expense ai
-        where
-        expense_type=#{dictValue}
-        <if test="dateQueryDto.entryDateStart != null and dateQueryDto.entryDateStart != '' ">
-            AND expense_date &gt;= DATE_FORMAT(#{dateQueryDto.entryDateStart},'%Y-%m-%d')
-        </if>
-        <if test="dateQueryDto.entryDateEnd != null and dateQueryDto.entryDateEnd != '' ">
-            AND expense_date &lt;= DATE_FORMAT(#{dateQueryDto.entryDateEnd},'%Y-%m-%d')
-        </if>
-    </select>
-
-    <select id="selectAccountExpenseStats" resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto">
-        SELECT DATE_FORMAT(expense_date, #{dateFormat}) as dateStr, IFNULL(SUM(expense_money), 0) as amount
-        FROM account_expense
-        WHERE expense_date BETWEEN #{startDate} AND #{endDate}
-        GROUP BY dateStr
-    </select>
-
-    <select id="selectExpenseComposition" resultType="com.ruoyi.dto.MapDto">
-        SELECT sdd.dict_label as name, CAST(IFNULL(SUM(ae.expense_money), 0) AS CHAR) as value
-        FROM account_expense ae
-        LEFT JOIN sys_dict_data sdd ON ae.expense_type = sdd.dict_value AND sdd.dict_type = 'expense_types'
-        <where>
-            <if test="startDate != null and startDate != ''">
-                AND ae.expense_date &gt;= #{startDate}
-            </if>
-            <if test="endDate != null and endDate != ''">
-                AND ae.expense_date &lt;= #{endDate}
-            </if>
-        </where>
-        GROUP BY ae.expense_type, sdd.dict_label
-    </select>
-
-</mapper>
diff --git a/src/main/resources/mapper/account/AccountFileMapper.xml b/src/main/resources/mapper/account/AccountFileMapper.xml
deleted file mode 100644
index 86266d5..0000000
--- a/src/main/resources/mapper/account/AccountFileMapper.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.account.mapper.AccountFileMapper">
-    <select id="accountFileListPage" resultType="com.ruoyi.account.pojo.AccountFile">
-        SELECT
-        *
-        FROM account_file
-        where
-        1=1
-        <if test="accountFile.accountId != null and accountFile.accountId != ''">
-            AND account_id = #{accountFile.accountId}
-        </if>
-        <if test="accountFile.name != null and accountFile.name != '' ">
-            AND name = #{accountFile.name}
-        </if>
-        <if test="accountFile.accountType != null and accountFile.accountType != '' ">
-            AND account_type = #{accountFile.accountType}
-        </if>
-    </select>
-</mapper>
diff --git a/src/main/resources/mapper/account/AccountIncomeMapper.xml b/src/main/resources/mapper/account/AccountIncomeMapper.xml
deleted file mode 100644
index a1d4205..0000000
--- a/src/main/resources/mapper/account/AccountIncomeMapper.xml
+++ /dev/null
@@ -1,111 +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.account.mapper.AccountIncomeMapper">
-
-    <select id="accountIncomeListPage" resultType="com.ruoyi.account.pojo.AccountIncome">
-        SELECT
-        *
-        FROM account_income
-        where
-        1=1
-        <if test="accountIncome.entryDateStart != null and accountIncome.entryDateStart != '' ">
-            AND income_date &gt;= DATE_FORMAT(#{accountIncome.entryDateStart},'%Y-%m-%d')
-        </if>
-        <if test="accountIncome.customerName != null and accountIncome.customerName != '' ">
-            AND customer_name like CONCAT('%',#{accountIncome.customerName},'%')
-        </if>
-
-        <if test="accountIncome.invoiceNumber != null and accountIncome.invoiceNumber != '' ">
-            AND invoice_number like CONCAT('%',#{accountIncome.invoiceNumber},'%')
-        </if>
-        <if test="accountIncome.entryDateEnd != null and accountIncome.entryDateEnd != '' ">
-            AND income_date &lt;= DATE_FORMAT(#{accountIncome.entryDateEnd},'%Y-%m-%d')
-        </if>
-        <if test="accountIncome.incomeType != null and accountIncome.incomeType != '' ">
-            AND income_type = #{accountIncome.incomeType}
-        </if>
-        <if test="accountIncome.incomeMethodLabel != null and accountIncome.incomeMethodLabel != ''">
-            AND (
-            (
-            business_type = 1
-            AND income_method in
-            <foreach collection="accountIncome.receiptPaymentMethodList" item="method" open="(" separator="," close=")">
-                #{method}
-            </foreach>
-            )
-            OR
-            (
-            business_type is null
-            AND income_method in
-            <foreach collection="accountIncome.paymentMethodList" item="method" open="(" separator="," close=")">
-                #{method}
-            </foreach>
-            )
-            )
-        </if>
-        <if test="(accountIncome.incomeMethodLabel == null or accountIncome.incomeMethodLabel == '') and accountIncome.incomeMethod != null and accountIncome.incomeMethod != '' ">
-            AND income_method = #{accountIncome.incomeMethod}
-        </if>
-    </select>
-    <select id="accountIncomeExport" resultType="com.ruoyi.account.pojo.AccountIncome">
-        SELECT
-        *
-        FROM account_income
-        where
-        1=1
-        <if test="accountIncome.entryDateStart != null and accountIncome.entryDateStart != '' ">
-            AND income_date &gt;= DATE_FORMAT(#{accountIncome.entryDateStart},'%Y-%m-%d')
-        </if>
-        <if test="accountIncome.entryDateEnd != null and accountIncome.entryDateEnd != '' ">
-            AND income_date &lt;= DATE_FORMAT(#{accountIncome.entryDateEnd},'%Y-%m-%d')
-        </if>
-        <if test="accountIncome.incomeType != null and accountIncome.incomeType != '' ">
-            AND income_type = #{accountIncome.incomeType}
-        </if>
-        <if test="accountIncome.incomeMethod != null and accountIncome.incomeMethod != '' ">
-            AND income_method = #{accountIncome.incomeMethod}
-        </if>
-    </select>
-    <select id="report" resultType="com.ruoyi.account.bean.dto.AccountDto2">
-        SELECT
-        sdd.dict_label typeName,
-        ifnull(sum(income_money),0) account
-        FROM account_income ai
-        left join sys_dict_data sdd on ai.income_type = sdd.dict_value and  sdd.dict_type='income_types'
-        where
-        1=1
-        <if test="dateQueryDto.entryDateStart != null and dateQueryDto.entryDateStart != '' ">
-            AND income_date &gt;= DATE_FORMAT(#{dateQueryDto.entryDateStart},'%Y-%m-%d')
-        </if>
-        <if test="dateQueryDto.entryDateEnd != null and dateQueryDto.entryDateEnd != '' ">
-            AND income_date &lt;= DATE_FORMAT(#{dateQueryDto.entryDateEnd},'%Y-%m-%d')
-        </if>
-        GROUP BY sdd.dict_label, ai.income_type
-    </select>
-    <select id="report1" resultType="java.math.BigDecimal">
-        SELECT
-        ifnull(sum(income_money),0) account
-        FROM account_income ai
-        where
-        income_type=#{dictValue}
-        <if test="dateQueryDto.entryDateStart != null and dateQueryDto.entryDateStart != '' ">
-            AND income_date &gt;= DATE_FORMAT(#{dateQueryDto.entryDateStart},'%Y-%m-%d')
-        </if>
-        <if test="dateQueryDto.entryDateEnd != null and dateQueryDto.entryDateEnd != '' ">
-            AND income_date &lt;= DATE_FORMAT(#{dateQueryDto.entryDateEnd},'%Y-%m-%d')
-        </if>
-    </select>
-
-    <select id="selectIncomeStats"
-            resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto">
-        SELECT DATE_FORMAT(income_date, #{dateFormat}) AS dateStr,
-               IFNULL(SUM(income_money), 0)            AS amount
-        FROM account_income
-        WHERE income_date BETWEEN #{startDate} AND #{endDate}
-#           AND business_type = 1
-        GROUP BY dateStr
-        ORDER BY dateStr
-
-    </select>
-
-</mapper>
diff --git a/src/main/resources/mapper/account/AccountStatementMapper.xml b/src/main/resources/mapper/account/AccountStatementMapper.xml
new file mode 100644
index 0000000..331c61b
--- /dev/null
+++ b/src/main/resources/mapper/account/AccountStatementMapper.xml
@@ -0,0 +1,43 @@
+<?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.account.mapper.AccountStatementMapper">
+
+    <select id="listPageAccountStatement" resultType="com.ruoyi.account.bean.vo.StatementAccountVo">
+    SELECT lj.*,
+        <choose>
+        <when test="req.accountType == 1">
+            c.customer_name as customerName
+        </when>
+        <when test="req.accountType == 2">
+            s.supplier_name as customerName
+        </when>
+        <otherwise>
+            '' as customerName
+        </otherwise>
+    </choose>
+    FROM account_statement AS lj
+            <!-- 鍔ㄦ�� LEFT JOIN -->
+            <choose>
+        <when test="req.accountType == 1">
+            LEFT JOIN customer AS c
+                ON lj.customer_id = c.id
+        </when>
+        <when test="req.accountType == 2">
+            LEFT JOIN supplier_manage AS s
+                ON lj.customer_id = s.id
+        </when>
+    </choose>
+    WHERE 1=1
+            <if test="req.accountType != null">
+                 AND lj.account_type = #{req.accountType}
+            </if>
+            <if test="req.customerId != null">
+                 AND lj.customer_id = #{req.customerId}
+            </if>
+            <if test="req.startDate != null and req.endDate != null">
+                  AND DATE_FORMAT(CONCAT(lj.statement_month, '-01'), '%Y-%m-%d')
+                    BETWEEN #{req.startDate} AND #{req.endDate}
+            </if>
+    ORDER BY lj.statement_month DESC
+    </select>
+</mapper>
diff --git a/src/main/resources/mapper/account/BorrowInfoMapper.xml b/src/main/resources/mapper/account/BorrowInfoMapper.xml
deleted file mode 100644
index f21c8d7..0000000
--- a/src/main/resources/mapper/account/BorrowInfoMapper.xml
+++ /dev/null
@@ -1,22 +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.account.mapper.BorrowInfoMapper">
-
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.account.pojo.BorrowInfo">
-        <id column="id" property="id" />
-        <result column="borrower_name" property="borrowerName" />
-        <result column="borrow_amount" property="borrowAmount" />
-        <result column="interest_rate" property="interestRate" />
-        <result column="borrow_date" property="borrowDate" />
-        <result column="repay_date" property="repayDate" />
-        <result column="status" property="status" />
-        <result column="remark" property="remark" />
-        <result column="create_time" property="createTime" />
-        <result column="create_user" property="createUser" />
-        <result column="update_time" property="updateTime" />
-        <result column="update_user" property="updateUser" />
-        <result column="tenant_id" property="tenantId" />
-    </resultMap>
-
-</mapper>
diff --git a/src/main/resources/mapper/account/AccountSubjectMapper.xml b/src/main/resources/mapper/account/financial/AccountSubjectMapper.xml
similarity index 88%
rename from src/main/resources/mapper/account/AccountSubjectMapper.xml
rename to src/main/resources/mapper/account/financial/AccountSubjectMapper.xml
index 95f450f..469691f 100644
--- a/src/main/resources/mapper/account/AccountSubjectMapper.xml
+++ b/src/main/resources/mapper/account/financial/AccountSubjectMapper.xml
@@ -1,9 +1,9 @@
 <?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.account.mapper.AccountSubjectMapper">
+<mapper namespace="com.ruoyi.account.mapper.financial.AccountSubjectMapper">
 
     <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="com.ruoyi.account.pojo.AccountSubject">
+    <resultMap id="BaseResultMap" type="com.ruoyi.account.pojo.financial.AccountSubject">
         <id column="id" property="id" />
         <result column="parent_id" property="parentId" />
         <result column="subject_code" property="subjectCode" />
diff --git a/src/main/resources/mapper/account/purchase/AccountPaymentApplicationMapper.xml b/src/main/resources/mapper/account/purchase/AccountPaymentApplicationMapper.xml
new file mode 100644
index 0000000..f1f5c5b
--- /dev/null
+++ b/src/main/resources/mapper/account/purchase/AccountPaymentApplicationMapper.xml
@@ -0,0 +1,98 @@
+<?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.account.mapper.purchase.AccountPaymentApplicationMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.account.pojo.purchase.AccountPaymentApplication">
+        <id column="id" property="id" />
+        <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="supplier_id" property="supplierId" />
+        <result column="stock_in_record_ids" property="stockInRecordIds" />
+        <result column="invoice_application_no" property="invoiceApplicationNo" />
+        <result column="payment_method" property="paymentMethod" />
+        <result column="payment_content" property="paymentContent" />
+        <result column="apply_date" property="applyDate" />
+        <result column="remark" property="remark" />
+        <result column="status" property="status" />
+        <result column="payment_amount" property="paymentAmount" />
+    </resultMap>
+     <select
+         id="listPageAccountPaymentApplication"
+         resultType="com.ruoyi.account.bean.vo.purchase.AccountPaymentApplicationVo">
+        select * from (select apa.*,
+               sm.supplier_name,
+               GROUP_CONCAT(sir.inbound_batches SEPARATOR ',') AS inboundBatches
+        from account_payment_application apa
+        left join supplier_manage sm on apa.supplier_id = sm.id
+        left join stock_in_record sir on FIND_IN_SET(sir.id, apa.stock_in_record_ids) > 0
+        GROUP BY apa.id)A
+        <where>
+            <if test="req.supplierId != null">
+                 AND A.supplier_id = #{req.supplierId}
+            </if>
+            <if test="req.invoiceApplicationNo != null and req.invoiceApplicationNo != ''">
+                AND A.invoice_application_no LIKE CONCAT('%',#{req.invoiceApplicationNo},'%')
+            </if>
+             <if test="req.status != null">
+                 AND A.status = #{req.status}
+            </if>
+            <if test="req.startDate != null and req.endDate != null">
+                AND A.apply_date BETWEEN #{req.startDate} AND #{req.endDate}
+            </if>
+        </where>
+    </select>
+
+    <select id="getInboundBatchesBySupplier"
+            resultType="com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo">
+        SELECT
+            sir.id,
+            sir.inbound_batches,
+            pl.supplier_name,
+            DATE(sir.create_time) AS inboundDate,
+            p.product_name,
+            pm.model as specification_model,
+            sir.stock_in_num * slp.tax_inclusive_unit_price AS InboundAmount,
+            pl.purchase_contract_number
+            FROM stock_in_record sir
+            -- 10 绫诲瀷鎵嶅叧鑱旇川妫�琛�
+            LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id
+            -- 鍔ㄦ�佸叧鑱旈噰璐紙鑷姩閫傞厤 7 鍜� 10锛�
+            LEFT JOIN purchase_ledger pl
+            ON pl.id = IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id)
+            -- 浜у搧鍏宠仈涓嶅姩
+            LEFT JOIN sales_ledger_product slp ON pl.id = slp.sales_ledger_id
+            LEFT JOIN product_model pm ON sir.product_model_id = pm.id
+            LEFT JOIN product p ON pm.product_id = p.id
+            -- 鏉′欢
+        WHERE sir.approval_status = 1 AND slp.type = 2
+        AND sir.record_type IN ('7','10')
+        and pl.supplier_id=#{supplierId}
+
+        and sir.id NOT IN (
+        SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(a.stock_in_record_ids, ',', n.n), ',', -1)
+        FROM account_payment_application a
+        CROSS JOIN (
+            SELECT 1 n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
+            SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
+        ) n
+        WHERE n.n &lt;= CHAR_LENGTH(a.stock_in_record_ids) - CHAR_LENGTH(REPLACE(a.stock_in_record_ids, ',', '')) + 1
+        and a.status!=2
+        )
+
+        order by sir.id DESC
+    </select>
+
+    <select id="existsByStockInRecordId" resultType="java.lang.Boolean">
+         SELECT COUNT(*) > 0
+        FROM account_payment_application
+        WHERE
+        <foreach collection="stockInRecordIds" item="id" open="(" separator=" OR " close=")">
+            FIND_IN_SET(#{id}, stock_in_record_ids)
+        </foreach>
+    </select>
+
+</mapper>
diff --git a/src/main/resources/mapper/account/purchase/AccountPurchaseInvoiceMapper.xml b/src/main/resources/mapper/account/purchase/AccountPurchaseInvoiceMapper.xml
new file mode 100644
index 0000000..041f2f7
--- /dev/null
+++ b/src/main/resources/mapper/account/purchase/AccountPurchaseInvoiceMapper.xml
@@ -0,0 +1,86 @@
+<?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.account.mapper.purchase.AccountPurchaseInvoiceMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.account.pojo.purchase.AccountPurchaseInvoice">
+        <id column="id" property="id" />
+        <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="invoice_number" property="invoiceNumber" />
+        <result column="tax_rate" property="taxRate" />
+        <result column="invoice_type" property="invoiceType" />
+        <result column="issue_date" property="issueDate" />
+        <result column="tax_exclusivel_price" property="taxExclusivelPrice" />
+        <result column="tax_price" property="taxPrice" />
+        <result column="tax_inclusive_price" property="taxInclusivePrice" />
+        <result column="remark" property="remark" />
+        <result column="invoice_content" property="invoiceContent" />
+        <result column="supplier_id" property="supplierId" />
+        <result column="storage_attachment_id" property="storageAttachmentId" />
+        <result column="stock_in_record_ids" property="stockInRecordIds" />
+    </resultMap>
+    <select id="listPageAccountPurchaseInvoice"
+            resultType="com.ruoyi.account.bean.vo.purchase.AccountPurchaseInvoiceVo">
+         select api.* , sm.supplier_name
+        from account_purchase_invoice api
+        left join supplier_manage sm on api.supplier_id = sm.id
+         <where>
+            <if test="req.supplierId != null">
+                 AND api.supplier_id = #{req.supplierId}
+            </if>
+            <if test="req.status != null">
+                AND api.status = #{req.status}
+            </if>
+            <if test="req.invoiceNumber != null and req.invoiceNumber != ''">
+                AND api.invoice_number LIKE CONCAT('%',#{req.invoiceNumber},'%')
+            </if>
+            <if test="req.startDate != null and req.endDate != null">
+                AND api.issue_date BETWEEN #{req.startDate} AND #{req.endDate}
+            </if>
+        </where>
+    </select>
+    <select id="getInboundBatchesBySupplier"
+            resultType="com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo">
+        SELECT
+            sir.id,
+            sir.inbound_batches,
+            pl.supplier_name,
+            DATE(sir.create_time) AS inboundDate,
+            p.product_name,
+            pm.model as specification_model,
+            sir.stock_in_num * slp.tax_inclusive_unit_price AS InboundAmount,
+            pl.purchase_contract_number
+            FROM stock_in_record sir
+            -- 10 绫诲瀷鎵嶅叧鑱旇川妫�琛�
+            LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id
+            -- 鍔ㄦ�佸叧鑱旈噰璐紙鑷姩閫傞厤 7 鍜� 10锛�
+            LEFT JOIN purchase_ledger pl
+            ON pl.id = IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id)
+            -- 浜у搧鍏宠仈涓嶅姩
+            LEFT JOIN sales_ledger_product slp ON pl.id = slp.sales_ledger_id
+            LEFT JOIN product_model pm ON sir.product_model_id = pm.id
+            LEFT JOIN product p ON pm.product_id = p.id
+            -- 鏉′欢
+        WHERE sir.approval_status = 1 AND slp.type = 2
+        AND sir.record_type IN ('7','10')
+        and pl.supplier_id=#{supplierId}
+
+        and sir.id NOT IN (
+        SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(a.stock_in_record_ids, ',', n.n), ',', -1)
+        FROM account_purchase_invoice a
+        CROSS JOIN (
+            SELECT 1 n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
+            SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
+        ) n
+        WHERE n.n &lt;= CHAR_LENGTH(a.stock_in_record_ids) - CHAR_LENGTH(REPLACE(a.stock_in_record_ids, ',', '')) + 1
+        and a.status=0
+        )
+
+        order by sir.id DESC
+    </select>
+
+</mapper>
diff --git a/src/main/resources/mapper/account/purchase/AccountPurchasePaymentMapper.xml b/src/main/resources/mapper/account/purchase/AccountPurchasePaymentMapper.xml
new file mode 100644
index 0000000..89a3681
--- /dev/null
+++ b/src/main/resources/mapper/account/purchase/AccountPurchasePaymentMapper.xml
@@ -0,0 +1,57 @@
+<?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.account.mapper.purchase.AccountPurchasePaymentMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.account.pojo.purchase.AccountPurchasePayment">
+        <id column="id" property="id" />
+        <result column="account_payment_application_id" property="accountPaymentApplicationId" />
+        <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="supplier_id" property="supplierId" />
+        <result column="payment_date" property="paymentDate" />
+        <result column="payment_method" property="paymentMethod" />
+        <result column="payment_amount" property="paymentAmount" />
+        <result column="payment_number" property="paymentNumber" />
+        <result column="remark" property="remark" />
+    </resultMap>
+    <select id="listPageAccountPurchasePayment"
+            resultType="com.ruoyi.account.bean.vo.purchase.AccountPurchasePaymentVo">
+       select app.*,
+               sm.supplier_name,
+               sm.bank_account_num,
+               sm.bank_account_name,
+               apa.invoice_application_no AS invoiceApplicationNo,
+               if(asd.receipt_number is not null, true, false) as isAccountStatemen
+        from account_purchase_payment app
+        left join supplier_manage sm on app.supplier_id = sm.id
+        left join account_payment_application apa on app.account_payment_application_id=apa.id
+        left join account_statement_details asd on app.payment_number = asd.receipt_number
+         <where>
+            <if test="req.supplierId != null">
+                 AND app.supplier_id = #{req.supplierId}
+            </if>
+            <if test="req.paymentMethod != null and req.paymentMethod != ''">
+                AND app.payment_method LIKE CONCAT('%',#{req.paymentMethod},'%')
+            </if>
+            <if test="req.paymentNumber != null and req.paymentNumber != ''">
+                AND app.payment_number LIKE CONCAT('%',#{req.paymentNumber},'%')
+            </if>
+            <if test="req.startDate != null and req.endDate != null">
+                AND app.payment_date BETWEEN #{req.startDate} AND #{req.endDate}
+            </if>
+        </where>
+    </select>
+    <select id="selectPayment" resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto">
+        SELECT DATE_FORMAT(payment_date, #{dateFormat}) AS dateStr,
+               IFNULL(SUM(payment_amount), 0)            AS amount
+        FROM account_purchase_payment
+        WHERE payment_date BETWEEN #{startStr} AND #{endStr}
+        GROUP BY dateStr
+        ORDER BY dateStr
+    </select>
+
+</mapper>
diff --git a/src/main/resources/mapper/account/sales/AccountInvoiceApplicationMapper.xml b/src/main/resources/mapper/account/sales/AccountInvoiceApplicationMapper.xml
new file mode 100644
index 0000000..99b16d2
--- /dev/null
+++ b/src/main/resources/mapper/account/sales/AccountInvoiceApplicationMapper.xml
@@ -0,0 +1,73 @@
+<?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.account.mapper.sales.AccountInvoiceApplicationMapper">
+
+    <select id="listPageAccountInvoiceApplication"
+            resultType="com.ruoyi.account.bean.vo.sales.AccountInvoiceApplicationVo">
+        select * from (select aia.*,
+               c.customer_name,
+               GROUP_CONCAT(sour.outbound_batches SEPARATOR ',') AS outboundBatches
+        from account_invoice_application aia
+        left join customer c on aia.customer_id = c.id
+        left join stock_out_record sour on FIND_IN_SET(sour.id, aia.stock_out_record_ids) > 0
+        GROUP BY aia.id)A
+        <where>
+            <if test="req.customerId != null">
+                 AND A.customer_id = #{req.customerId}
+            </if>
+            <if test="req.invoiceApplicationNo != null and req.invoiceApplicationNo != ''">
+                AND A.invoice_application_no LIKE CONCAT('%',#{req.invoiceApplicationNo},'%')
+            </if>
+             <if test="req.status != null">
+                 AND A.status = #{req.status}
+            </if>
+            <if test="req.startDate != null and req.endDate != null">
+                AND A.apply_date BETWEEN #{req.startDate} AND #{req.endDate}
+            </if>
+        </where>
+    </select>
+    <select id="getOutboundBatchesByCustomer"
+            resultType="com.ruoyi.account.bean.vo.sales.SalesOutboundVo">
+        SELECT
+        sor.id,
+        sor.outbound_batches,
+        sl.customer_name,
+        sor.create_time as shippingDate,
+        p.product_name,
+        pm.model as specification_model,
+        slp.tax_rate,
+        sor.stock_out_num * slp.tax_inclusive_unit_price as outboundAmount,
+        s.shipping_no,
+        sl.sales_contract_no
+        FROM stock_out_record sor
+        left join shipping_info s on sor.record_id = s.id
+        LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
+        LEFT JOIN sales_ledger_product slp ON s.sales_ledger_product_id = slp.id and slp.type = 1
+        left join product_model pm on slp.product_model_id = pm.id
+        left join product p on pm.product_id = p.id
+        WHERE sor.record_type='13' and sor.approval_status=1
+        and sl.customer_id=#{customerId}
+
+        and sor.id NOT IN (
+        SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(a.stock_out_record_ids, ',', n.n), ',', -1)
+        FROM account_invoice_application a
+        CROSS JOIN (
+            SELECT 1 n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
+            SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
+        ) n
+        WHERE n.n &lt;= CHAR_LENGTH(a.stock_out_record_ids) - CHAR_LENGTH(REPLACE(a.stock_out_record_ids, ',', '')) + 1
+          and a.status!=2
+        )
+
+        order by sor.id DESC
+    </select>
+    <select id="existsByStockOutRecordId" resultType="java.lang.Boolean">
+        SELECT COUNT(*) > 0
+        FROM account_invoice_application
+        WHERE
+        <foreach collection="stockOutRecordIds" item="id" open="(" separator=" OR " close=")">
+            FIND_IN_SET(#{id}, stock_out_record_ids)
+        </foreach>
+    </select>
+
+</mapper>
diff --git a/src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml b/src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml
new file mode 100644
index 0000000..4ad55d4
--- /dev/null
+++ b/src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml
@@ -0,0 +1,101 @@
+<?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.account.mapper.sales.AccountSalesCollectionMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.account.pojo.sales.AccountSalesCollection">
+        <id column="id" property="id" />
+        <result column="stock_out_record_ids" property="stockOutRecordIds" />
+        <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="customer_id" property="customerId" />
+        <result column="collection_date" property="collectionDate" />
+        <result column="collection_amount" property="collectionAmount" />
+        <result column="collection_method" property="collectionMethod" />
+        <result column="collection_number" property="collectionNumber" />
+        <result column="remark" property="remark" />
+    </resultMap>
+    <select id="listPageAccountSalesCollection"
+            resultType="com.ruoyi.account.bean.vo.sales.AccountSalesCollectionVo">
+       select
+           A.* ,
+           if(asd.receipt_number is not null, true, false) as isAccountStatemen
+       from (select ascc.*,
+               c.customer_name,
+               GROUP_CONCAT(sour.outbound_batches SEPARATOR ',') AS outboundBatches
+        from account_sales_collection ascc
+        left join customer c on ascc.customer_id = c.id
+        left join stock_out_record sour on FIND_IN_SET(sour.id, ascc.stock_out_record_ids) > 0
+        GROUP BY ascc.id)A
+       left join account_statement_details asd on A.collection_number = asd.receipt_number
+         <where>
+            <if test="req.customerId != null">
+                 AND A.customer_id = #{req.customerId}
+            </if>
+            <if test="req.collectionNumber != null and req.collectionNumber != ''">
+                AND A.collection_number LIKE CONCAT('%',#{req.collectionNumber},'%')
+            </if>
+            <if test="req.collectionMethod != null and req.collectionMethod != ''">
+                AND A.collection_method LIKE CONCAT('%',#{req.collectionMethod},'%')
+            </if>
+            <if test="req.startDate != null and req.endDate != null">
+                AND A.collection_date BETWEEN #{req.startDate} AND #{req.endDate}
+            </if>
+        </where>
+
+    </select>
+    <select id="existsByStockOutRecordId" resultType="java.lang.Boolean">
+        SELECT COUNT(*) > 0
+        FROM account_sales_collection
+        WHERE
+        <foreach collection="stockOutRecordIds" item="id" open="(" separator=" OR " close=")">
+            FIND_IN_SET(#{id}, stock_out_record_ids)
+        </foreach>
+    </select>
+    <select id="getOutboundBatchesByCustomer"
+            resultType="com.ruoyi.account.bean.vo.sales.SalesOutboundVo">
+        SELECT
+        sor.id,
+        sor.outbound_batches,
+        sl.customer_name,
+        sor.create_time as shippingDate,
+        p.product_name,
+        pm.model as specification_model,
+        slp.tax_rate,
+        sor.stock_out_num * slp.tax_inclusive_unit_price as outboundAmount,
+        s.shipping_no,
+        sl.sales_contract_no
+        FROM stock_out_record sor
+        left join shipping_info s on sor.record_id = s.id
+        LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
+        LEFT JOIN sales_ledger_product slp ON s.sales_ledger_product_id = slp.id and slp.type = 1
+        left join product_model pm on slp.product_model_id = pm.id
+        left join product p on pm.product_id = p.id
+        WHERE sor.record_type='13' and sor.approval_status=1
+        and sl.customer_id=#{customerId}
+
+        and sor.id NOT IN (
+        SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(a.stock_out_record_ids, ',', n.n), ',', -1)
+        FROM account_sales_collection a
+        CROSS JOIN (
+            SELECT 1 n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
+            SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
+        ) n
+        WHERE n.n &lt;= CHAR_LENGTH(a.stock_out_record_ids) - CHAR_LENGTH(REPLACE(a.stock_out_record_ids, ',', '')) + 1
+        )
+
+        order by sor.id DESC
+    </select>
+    <select id="selectIncomeStats" resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto">
+         SELECT DATE_FORMAT(collection_date, #{dateFormat}) AS dateStr,
+                IFNULL(SUM(collection_amount), 0)            AS amount
+         FROM account_sales_collection
+         WHERE collection_date BETWEEN #{startStr} AND #{endStr}
+         GROUP BY dateStr
+         ORDER BY dateStr
+    </select>
+
+</mapper>
diff --git a/src/main/resources/mapper/account/sales/AccountSalesInvoiceMapper.xml b/src/main/resources/mapper/account/sales/AccountSalesInvoiceMapper.xml
new file mode 100644
index 0000000..b289b8f
--- /dev/null
+++ b/src/main/resources/mapper/account/sales/AccountSalesInvoiceMapper.xml
@@ -0,0 +1,47 @@
+<?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.account.mapper.sales.AccountSalesInvoiceMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.account.pojo.sales.AccountSalesInvoice">
+        <id column="id" property="id" />
+        <result column="account_invoice_application_id" property="accountInvoiceApplicationId" />
+        <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="invoice_number" property="invoiceNumber" />
+        <result column="tax_rate" property="taxRate" />
+        <result column="invoice_type" property="invoiceType" />
+        <result column="issue_date" property="issueDate" />
+        <result column="tax_exclusivel_price" property="taxExclusivelPrice" />
+        <result column="tax_price" property="taxPrice" />
+        <result column="tax_inclusive_price" property="taxInclusivePrice" />
+        <result column="remark" property="remark" />
+        <result column="invoice_content" property="invoiceContent" />
+        <result column="customer_id" property="customerId" />
+        <result column="storage_attachment_id" property="storageAttachmentId" />
+    </resultMap>
+    <select id="listPageAccountSalesInvoice"
+            resultType="com.ruoyi.account.bean.vo.sales.AccountSalesInvoiceVo">
+        select asi.* , c.customer_name
+        from account_sales_invoice asi
+        left join customer c on asi.customer_id = c.id
+         <where>
+            <if test="req.customerId != null">
+                 AND asi.customer_id = #{req.customerId}
+            </if>
+            <if test="req.status != null">
+                AND asi.status = #{req.status}
+            </if>
+            <if test="req.invoiceNumber != null and req.invoiceNumber != ''">
+                AND asi.invoice_number LIKE CONCAT('%',#{req.invoiceNumber},'%')
+            </if>
+            <if test="req.startDate != null and req.endDate != null">
+                AND asi.issue_date BETWEEN #{req.startDate} AND #{req.endDate}
+            </if>
+        </where>
+    </select>
+
+</mapper>
diff --git a/src/main/resources/mapper/basic/CustomerMapper.xml b/src/main/resources/mapper/basic/CustomerMapper.xml
index 20aaefc..8117c66 100644
--- a/src/main/resources/mapper/basic/CustomerMapper.xml
+++ b/src/main/resources/mapper/basic/CustomerMapper.xml
@@ -26,7 +26,6 @@
         from customer c
         left join sys_user u on c.usage_user = u.user_id
         <where>
-            and c.usage_status = 1
             <if test="c.customerName != null and c.customerName != ''">
                 and customer_name like concat('%', #{c.customerName}, '%')
             </if>
@@ -108,4 +107,87 @@
             </if>
         </where>
     </select>
+    <select id="customewTransactions" resultType="com.ruoyi.sales.vo.CustomerTransactionsVo">
+        select T1.customer_id,
+               c.customer_name,
+               T1.contractAmounts,
+               IFNULL(T2.receiptPaymentAmount, 0) AS receiptPaymentAmount,
+               IFNULL(T3.outboundAmount, 0) - IFNULL(T4.returnAmount, 0) AS receiptableAmount
+        from (select customer_id, sum(contract_amount) as contractAmounts from sales_ledger group by customer_id) T1
+        left join (select customer_id, sum(collection_amount) as receiptPaymentAmount from account_sales_collection group by customer_id) T2 on T1.customer_id = T2.customer_id
+        left join (
+            SELECT
+                sl.customer_id,
+                sum(sor.stock_out_num * slp.tax_inclusive_unit_price) as outboundAmount
+            FROM stock_out_record sor
+            LEFT join shipping_info s on sor.record_id = s.id
+            LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
+            LEFT JOIN sales_ledger_product slp ON s.sales_ledger_product_id = slp.id
+            WHERE sor.record_type='13'
+                and sor.approval_status=1
+                and slp.type = 1
+            group by sl.customer_id
+        ) T3 on T3.customer_id=T1.customer_id
+        left join (
+            select
+                sl.customer_id,
+                sum(rm.refund_amount) as returnAmount
+            from return_management rm
+            left join shipping_info si on rm.shipping_id = si.id
+            left join sales_ledger sl on si.sales_ledger_id = sl.id
+            where rm.status=1
+            group by sl.customer_id
+        ) T4 on T4.customer_id=T1.customer_id
+        left join customer c on T1.customer_id = c.id
+        <where>
+            <if test="customerName!=null and customerName!=''">
+                AND c.customer_name LIKE CONCAT('%', #{customerName}, '%')
+            </if>
+        </where>
+    </select>
+    <select id="customewTransactionsDetails"
+            resultType="com.ruoyi.sales.vo.CustomerTransactionsDetailsVo">
+        select sl.id salesLedgerId,
+               sl.sales_contract_no,
+               sl.execution_date,
+               sl.contract_amount,
+               IFNULL(T1.receiptPaymentAmount, 0) AS receiptPaymentAmount,
+               IFNULL(T2.outboundAmount, 0) - IFNULL(T3.returnAmount, 0) AS receiptableAmount
+        from sales_ledger sl
+        left join (
+            select
+                sl.id,
+                sum(ascc.collection_amount) as receiptPaymentAmount
+            from account_sales_collection ascc
+            left join stock_out_record sor on FIND_IN_SET(sor.id, ascc.stock_out_record_ids) > 0
+            left join shipping_info s on sor.record_id = s.id
+            LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
+            WHERE sor.record_type='13'
+              and sor.approval_status=1
+            group by  sl.id
+        )T1 on T1.id = sl.id
+        left join (
+            SELECT
+                sl.id,
+                sum(sor.stock_out_num * slp.tax_inclusive_unit_price) as outboundAmount
+            FROM stock_out_record sor
+                     left join shipping_info s on sor.record_id = s.id
+                     LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
+                     LEFT JOIN sales_ledger_product slp ON s.sales_ledger_product_id = slp.id
+            WHERE sor.record_type='13'
+              and sor.approval_status=1
+              and slp.type = 1
+            group by  sl.id
+        )T2 on T2.id = sl.id
+        left join (
+            select sl.id,
+                   sum(rm.refund_amount) as returnAmount
+            from return_management rm
+                     left join shipping_info si on rm.shipping_id = si.id
+                     left join sales_ledger sl on si.sales_ledger_id = sl.id
+            where rm.status=1
+            group by sl.id
+        )T3 on T3.id = sl.id
+        where sl.customer_id = #{customerId}
+    </select>
 </mapper>
diff --git a/src/main/resources/mapper/basic/ProductModelMapper.xml b/src/main/resources/mapper/basic/ProductModelMapper.xml
index 0a540bf..6270b1d 100644
--- a/src/main/resources/mapper/basic/ProductModelMapper.xml
+++ b/src/main/resources/mapper/basic/ProductModelMapper.xml
@@ -9,7 +9,6 @@
         <result column="product_id" property="productId" />
         <result column="model" property="model" />
         <result column="unit" property="unit" />
-        <result column="speculative_trading_name" property="speculativeTradingName" />
         <result column="tenant_id" property="tenantId" />
         <result column="product_name" property="productName" />
         <result column="product_id" property="productId" />
diff --git a/src/main/resources/mapper/basic/SupplierManageMapper.xml b/src/main/resources/mapper/basic/SupplierManageMapper.xml
index 87688e1..5c5af54 100644
--- a/src/main/resources/mapper/basic/SupplierManageMapper.xml
+++ b/src/main/resources/mapper/basic/SupplierManageMapper.xml
@@ -68,5 +68,95 @@
             </if>
         </where>
     </select>
+    <select id="supplierTransactions" resultType="com.ruoyi.purchase.vo.SupplierTransactionsVo">
+        select T1.supplier_id,
+               sm.supplier_name,
+               T1.contractAmounts,
+               IFNULL(T2.paymentAmount, 0) AS paymentAmount,
+               IFNULL(T3.InboundAmount, 0) - IFNULL(T4.returnAmount, 0) AS payableAmount
+        from (select supplier_id, sum(contract_amount) as contractAmounts from purchase_ledger group by supplier_id) T1
+        left join (select supplier_id, sum(payment_amount) as paymentAmount from account_purchase_payment group by supplier_id) T2 on T1.supplier_id = T2.supplier_id
+        left join (
+            SELECT
+                pl.supplier_id,
+                sum(sir.stock_in_num * slp.tax_inclusive_unit_price) AS InboundAmount
+            FROM stock_in_record sir
+                     -- 10 绫诲瀷鎵嶅叧鑱旇川妫�琛�
+                     LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id
+                -- 鍔ㄦ�佸叧鑱旈噰璐紙鑷姩閫傞厤 7 鍜� 10锛�
+                     LEFT JOIN purchase_ledger pl
+                               ON pl.id = IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id)
+                -- 浜у搧鍏宠仈涓嶅姩
+                     LEFT JOIN sales_ledger_product slp ON pl.id = slp.sales_ledger_id
+            -- 鏉′欢
+            WHERE sir.approval_status = 1 AND slp.type = 2
+              AND sir.record_type IN ('7','10')
+            group by pl.supplier_id
+        ) T3 on T3.supplier_id=T1.supplier_id
+        left join (
+            select
+                supplier_id,
+                sum(total_amount) as returnAmount
+            from purchase_return_orders pro
+            group by supplier_id
+        ) T4 on T4.supplier_id=T1.supplier_id
+        left join supplier_manage sm on T1.supplier_id = sm.id
+        <where>
+            <if test="supplierName!=null and supplierName!=''">
+                AND sm.supplier_name LIKE CONCAT('%',#{supplierName},'%')
+            </if>
+        </where>
+    </select>
+    <select id="supplierTransactionsDetails"
+            resultType="com.ruoyi.purchase.vo.SupplierTransactionsDetailsVo">
+       select pl.id  purchaseLedgerId,
+              pl.purchase_contract_number,
+              pl.execution_date,
+              pl.contract_amount,
+              IFNULL(T1.paymentAmount, 0) AS paymentAmount,
+              IFNULL(T2.InboundAmount, 0) - IFNULL(T3.returnAmount, 0) AS payableAmount
+       from purchase_ledger pl
+       left join (
+           select
+               pl.id,
+               sum(app.payment_amount) as paymentAmount
+           from account_purchase_payment app
+           left join account_payment_application apa on app.account_payment_application_id = apa.id
+           left join stock_in_record sir on FIND_IN_SET(sir.id, apa.stock_in_record_ids) > 0
+               -- 10 绫诲瀷鎵嶅叧鑱旇川妫�琛�
+           LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id
+               -- 鍔ㄦ�佸叧鑱旈噰璐紙鑷姩閫傞厤 7 鍜� 10锛�
+           LEFT JOIN purchase_ledger pl
+                     ON pl.id = IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id)
+           WHERE sir.approval_status = 1
+             AND sir.record_type IN ('7','10')
+           group by pl.id
+       )T1 on T1.id = pl.id
+       left join (
+           SELECT
+               pl.id,
+               sum(sir.stock_in_num * slp.tax_inclusive_unit_price) AS InboundAmount
+           FROM stock_in_record sir
+                    -- 10 绫诲瀷鎵嶅叧鑱旇川妫�琛�
+                    LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id
+               -- 鍔ㄦ�佸叧鑱旈噰璐紙鑷姩閫傞厤 7 鍜� 10锛�
+                    LEFT JOIN purchase_ledger pl
+                              ON pl.id = IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id)
+               -- 浜у搧鍏宠仈涓嶅姩
+                    LEFT JOIN sales_ledger_product slp ON pl.id = slp.sales_ledger_id
+           -- 鏉′欢
+           WHERE sir.approval_status = 1 AND slp.type = 2
+             AND sir.record_type IN ('7','10')
+           group by pl.id
+       )T2 on T2.id = pl.id
+       left join (
+           select pl.id,
+                  sum(pro.total_amount) as returnAmount
+           from purchase_return_orders pro
+                    left join purchase_ledger pl on pro.purchase_ledger_id = pl.id
+           group by pl.id
+       )T3 on T3.id = pl.id
+       where pl.supplier_id = #{supplierId}
+    </select>
 
-</mapper>
\ No newline at end of file
+</mapper>
diff --git a/src/main/resources/mapper/procurementrecord/ReturnManagementMapper.xml b/src/main/resources/mapper/procurementrecord/ReturnManagementMapper.xml
index d348a6b..e069196 100644
--- a/src/main/resources/mapper/procurementrecord/ReturnManagementMapper.xml
+++ b/src/main/resources/mapper/procurementrecord/ReturnManagementMapper.xml
@@ -53,7 +53,7 @@
                  left join sales_ledger sl on si.sales_ledger_id = sl.id
         where rm.id = #{id}
     </select>
-    <select id="listPageAccountSalesReturn" resultType="com.ruoyi.account.bean.vo.SalesReturnVo">
+    <select id="listPageAccountSalesReturn" resultType="com.ruoyi.account.bean.vo.sales.SalesReturnVo">
          select rm.id,
                 rm.return_no,
                 c.customer_name,
@@ -74,6 +74,9 @@
             <if test="req.customerName != null and req.customerName != ''">
                 and c.customer_name like concat('%',#{req.customerName},'%')
             </if>
+            <if test="req.customerId != null ">
+                and rm.customer_id = #{req.customerId}
+            </if>
             <if test="req.startDate != null and req.endDate != null">
                 AND DATE_FORMAT(rm.make_time, '%Y-%m-%d') BETWEEN #{req.startDate} AND #{req.endDate}
             </if>
diff --git a/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml b/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
index f029ef7..199eb21 100644
--- a/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
+++ b/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
@@ -64,6 +64,9 @@
             <if test="c != null and c.status != null">
                 and pot.status = #{c.status}
             </if>
+            <if test="c != null and c.isProduction != null">
+                and poro.is_production = #{c.isProduction}
+            </if>
             <if test="c != null and c.workOrderNo != null and c.workOrderNo != ''">
                 and pot.work_order_no like concat('%', #{c.workOrderNo}, '%')
             </if>
diff --git a/src/main/resources/mapper/production/ProductionOrderMapper.xml b/src/main/resources/mapper/production/ProductionOrderMapper.xml
index 1a304ef..8e64413 100644
--- a/src/main/resources/mapper/production/ProductionOrderMapper.xml
+++ b/src/main/resources/mapper/production/ProductionOrderMapper.xml
@@ -212,4 +212,85 @@
           and ifnull(complete_quantity, 0) &lt; quantity
     </select>
 
+    <select id="selectHomeOrderProgressPage" resultType="java.util.Map">
+        select po.nps_no as orderNo,
+               p.product_name as productName,
+               ifnull(po.quantity, 0) as plannedQuantity,
+               ifnull(po.complete_quantity, 0) as completedQuantity,
+               round(ifnull(po.complete_quantity, 0) / nullif(po.quantity, 0) * 100, 2) as completionRate,
+               po.plan_complete_time as dueDate,
+               po.status as status
+        from production_order po
+                 left join product_model pm on po.product_model_id = pm.id
+                 left join product p on pm.product_id = p.id
+        <where>
+            <if test="status != null">
+                and po.status = #{status}
+            </if>
+            <if test="startTime != null and endTime != null">
+                and po.create_time &gt;= #{startTime}
+                and po.create_time &lt; #{endTime}
+            </if>
+        </where>
+        order by po.id desc
+        limit #{offset}, #{size}
+    </select>
+
+    <select id="countHomeOrderProgress" resultType="java.lang.Long">
+        select count(1)
+        from production_order po
+        <where>
+            <if test="status != null">
+                and po.status = #{status}
+            </if>
+            <if test="startTime != null and endTime != null">
+                and po.create_time &gt;= #{startTime}
+                and po.create_time &lt; #{endTime}
+            </if>
+        </where>
+    </select>
+
+    <select id="countHomeOrderProgressByStatus" resultType="java.util.Map">
+        select po.status as status, count(1) as cnt
+        from production_order po
+        where po.status in (1, 2, 3, 4)
+        <if test="startTime != null and endTime != null">
+            and po.create_time &gt;= #{startTime}
+            and po.create_time &lt; #{endTime}
+        </if>
+        group by po.status
+    </select>
+
+    <select id="selectHomeTodayProductionPlan" resultType="java.util.Map">
+        select po.nps_no as orderNo,
+               p.product_name as productName,
+               ifnull(po.quantity, 0) as plannedQuantity,
+               po.plan_complete_time as dueDate,
+               po.status as status
+        from production_order po
+                 left join product_model pm on po.product_model_id = pm.id
+                 left join product p on pm.product_id = p.id
+        <where>
+            po.status in (1, 2)
+            <if test="planStart != null and planEnd != null">
+                and po.plan_complete_time &gt;= #{planStart}
+                and po.plan_complete_time &lt; #{planEnd}
+            </if>
+        </where>
+        order by case when po.status = 2 then 0 else 1 end, po.id desc
+        limit #{size}
+    </select>
+
+    <select id="countHomeTodayProductionPlan" resultType="java.lang.Long">
+        select count(1)
+        from production_order po
+        <where>
+            po.status in (1, 2)
+            <if test="planStart != null and planEnd != null">
+                and po.plan_complete_time &gt;= #{planStart}
+                and po.plan_complete_time &lt; #{planEnd}
+            </if>
+        </where>
+    </select>
+
 </mapper>
diff --git a/src/main/resources/mapper/purchase/InvoicePurchaseMapper.xml b/src/main/resources/mapper/purchase/InvoicePurchaseMapper.xml
deleted file mode 100644
index c5a99f9..0000000
--- a/src/main/resources/mapper/purchase/InvoicePurchaseMapper.xml
+++ /dev/null
@@ -1,146 +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.purchase.mapper.InvoicePurchaseMapper">
-
-
-    <select id="selectPurchaseReport" resultType="com.ruoyi.purchase.dto.InvoicePurchaseReportDto">
-        SELECT
-        sl.sales_contract_no AS customerContractNo,
-        sl.customer_name,
-        sl.contract_amount AS contract_amount,
-        SUM( pl.contract_amount ) AS purchase_amount,
-        (
-        sl.contract_amount - SUM( pl.contract_amount )) AS balance,
-        CONCAT( ROUND( ( sl.contract_amount - SUM( pl.contract_amount )) / sl.contract_amount * 100, 1 ), '%' ) AS balance_ratio
-        FROM
-        sales_ledger sl
-        INNER JOIN purchase_ledger pl ON sl.sales_contract_no = pl.sales_contract_no
-        <where>
-            <if test="c.customerName != null and c.customerName != ''">
-                AND sl.customer_name LIKE CONCAT('%', #{c.customerName}, '%')
-            </if>
-        </where>
-        GROUP BY
-        sl.sales_contract_no,
-        sl.customer_name,
-        sl.contract_amount
-        ORDER BY
-        sl.sales_contract_no
-    </select>
-    <select id="listVat" resultType="com.ruoyi.purchase.dto.VatDto">
-        select *
-        from (SELECT
-                  COALESCE(a1.month, a2.month) AS month,
-                  IFNULL(a1.tax_amount, 0) AS j_tax_amount,
-                  IFNULL(a2.x_tax_amount, 0) AS x_tax_amount
-              FROM (
-                       -- 绗竴涓煡璇細鏉ヨ嚜 invoice_ledger 鐨勭◣棰�
-                       SELECT
-                           DATE_FORMAT(il.invoice_date, '%Y-%m') AS month,
-                           ROUND(SUM(pr.invoice_amount - pr.invoice_amount / (1 + pr.tax_rate / 100)), 2) AS tax_amount
-                       FROM invoice_ledger il
-                                LEFT JOIN invoice_registration_product pr ON pr.id = il.invoice_registration_product_id
-                       WHERE il.invoice_no IS NOT NULL
-                         AND invoice_type = '澧炰笓绁�'
-                         AND DATE_FORMAT(il.invoice_date, '%Y-%m') IS NOT NULL  -- 鏂板锛氳繃婊onth涓篘ULL鐨勬儏
-                       GROUP BY DATE_FORMAT(il.invoice_date, '%Y-%m')
-                   ) a1
-                       LEFT JOIN (
-                  -- 绗簩涓煡璇細鏉ヨ嚜 ticket_registration 鐨勭◣棰�
-                  SELECT
-                      DATE_FORMAT(a.issue_date, '%Y-%m') AS month,
-                      SUM(a.invoice_amount) AS x_tax_amount
-                  FROM (
-                           SELECT DISTINCT pr.id,
-                                           tr.issue_date,
-                                           ROUND(pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS un_tickets_price,
-                                           ROUND(pr.tickets_amount - pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS invoice_amount
-                           FROM product_record pr
-                                    LEFT JOIN purchase_ledger pl ON pl.id = pr.purchase_ledger_id
-                                    LEFT JOIN sales_ledger sl ON sl.id = pl.sales_ledger_id
-                                    LEFT JOIN ticket_registration tr ON tr.purchase_ledger_id = pl.id
-                                    LEFT JOIN product_model pm ON pm.id = pr.product_model_id
-                           WHERE type = 2
-                             AND tr.invoice_number IS NOT NULL
-                       ) a
-                  GROUP BY DATE_FORMAT(a.issue_date, '%Y-%m')
-              ) a2 ON a1.month = a2.month
-
-              UNION ALL
-
-              SELECT
-                  COALESCE(a1.month, a2.month) AS month,
-                  IFNULL(a1.tax_amount, 0) AS tax_amount,
-                  IFNULL(a2.x_tax_amount, 0) AS x_tax_amount
-              FROM (
-                       -- 绗簩涓煡璇細鏉ヨ嚜 ticket_registration 鐨勭◣棰濓紙鍙嶈繃鏉ヨˉ鍏ㄦ病鏈夊尮閰嶅埌鐨勶級
-                       SELECT
-                           DATE_FORMAT(a.issue_date, '%Y-%m') AS month,
-                           SUM(a.invoice_amount) AS x_tax_amount
-                       FROM (
-                                SELECT DISTINCT pr.id,
-                                                tr.issue_date,
-                                                ROUND(pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS un_tickets_price,
-                                                ROUND(pr.tickets_amount - pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS invoice_amount
-                                FROM product_record pr
-                                         LEFT JOIN purchase_ledger pl ON pl.id = pr.purchase_ledger_id
-                                         LEFT JOIN sales_ledger sl ON sl.id = pl.sales_ledger_id
-                                         LEFT JOIN ticket_registration tr ON tr.purchase_ledger_id = pl.id
-                                         LEFT JOIN product_model pm ON pm.id = pr.product_model_id
-                                WHERE type = 2
-                                  AND tr.invoice_number IS NOT NULL
-                            ) a
-                       GROUP BY DATE_FORMAT(a.issue_date, '%Y-%m')
-                   ) a2
-                       LEFT JOIN (
-                  -- 绗竴涓煡璇細鏉ヨ嚜 invoice_ledger 鐨勭◣棰�
-                  SELECT
-                      DATE_FORMAT(il.invoice_date, '%Y-%m') AS month,
-                      ROUND(SUM(pr.invoice_amount - pr.invoice_amount / (1 + pr.tax_rate / 100)), 2) AS tax_amount
-                  FROM invoice_ledger il
-                           LEFT JOIN invoice_registration_product pr ON pr.id = il.invoice_registration_product_id
-                  WHERE il.invoice_no IS NOT NULL
-                    AND invoice_type = '澧炰笓绁�'
-                    AND DATE_FORMAT(il.invoice_date, '%Y-%m') IS NOT NULL  -- 鏂板锛氳繃婊onth涓篘ULL鐨勬儏
-                  GROUP BY DATE_FORMAT(il.invoice_date, '%Y-%m')
-              ) a1 ON a1.month = a2.month
-              WHERE a1.month IS NULL
-              ORDER BY month
-             )as a
-        <where>
-            a.month is not null
-            <if test="month != null">
-                and a.month = #{month}
-            </if>
-        </where>
-
-    </select>
-    <select id="listVat1" resultType="com.ruoyi.purchase.dto.VatDto">
-        #             SELECT
-#                 DATE_FORMAT(il.invoice_date, '%Y-%m') AS month,
-#                 ROUND(SUM(pr.invoice_amount - pr.invoice_amount / (1 + pr.tax_rate / 100)), 2) AS tax_amount
-#             FROM invoice_ledger il
-#                      LEFT JOIN invoice_registration_product pr ON pr.id = il.invoice_registration_product_id
-#             WHERE il.invoice_no IS NOT NULL
-#               AND invoice_type = '澧炰笓绁�'
-#             GROUP BY DATE_FORMAT(il.invoice_date, '%Y-%m')
-#             ORDER BY month;
-#         select DATE_FORMAT(a.issue_date, '%Y-%m'), sum(a.invoice_amount) as xTaxAmount
-#         from (SELECT distinct pr.id,
-#                               tr.issue_date,
-#                               ROUND(pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS un_tickets_price,
-#                               ROUND(pr.tickets_amount - pr.tickets_amount / (1 + pr.tax_rate / 100),
-#                                     2)                                              AS invoice_amount
-#               FROM product_record pr
-#                        LEFT JOIN purchase_ledger pl ON pl.id = pr.purchase_ledger_id
-#                        LEFT JOIN sales_ledger sl ON sl.id = pl.sales_ledger_id
-#                        LEFT JOIN ticket_registration tr ON tr.purchase_ledger_id = pl.id
-#                        LEFT JOIN product_model pm ON pm.id = pr.product_model_id
-#               WHERE type = 2
-#                 and tr.invoice_number is not null) a
-#         GROUP BY DATE_FORMAT(a.issue_date, '%Y-%m')
-    </select>
-
-</mapper>
diff --git a/src/main/resources/mapper/purchase/PaymentRegistrationMapper.xml b/src/main/resources/mapper/purchase/PaymentRegistrationMapper.xml
deleted file mode 100644
index 8e01079..0000000
--- a/src/main/resources/mapper/purchase/PaymentRegistrationMapper.xml
+++ /dev/null
@@ -1,223 +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.purchase.mapper.PaymentRegistrationMapper">
-
-    <resultMap type="PaymentRegistration" id="PaymentRegistrationResult">
-        <result property="id" column="id"/>
-        <result property="saleLedgerId" column="sale_ledger_id"/>
-        <result property="purchaseLedgerId" column="purchase_ledger_id"/>
-        <result property="supplierId" column="supplier_id"/>
-        <result property="ticketRegistrationId" column="ticket_registration_id"/>
-        <result property="currentPaymentAmount" column="current_payment_amount"/>
-        <result property="paymentMethod" column="payment_method"/>
-        <result property="registrantId" column="registrant_id"/>
-        <result property="paymentDate" column="payment_date"/>
-        <result property="createTime" column="create_time"/>
-        <result property="updateTime" column="update_time"/>
-        <result property="tenantId" column="tenant_id"/>
-        <result property="registrationtDate" column="registrationt_date"/>
-    </resultMap>
-
-    <resultMap type="com.ruoyi.purchase.dto.PaymentRegistrationDto" id="PaymentRegistrationDtoResult">
-        <result property="id" column="id"/>
-        <result property="saleLedgerId" column="sale_ledger_id"/>
-        <result property="purchaseLedgerId" column="purchase_ledger_id"/>
-        <result property="supplierId" column="supplier_id"/>
-        <result property="ticketRegistrationId" column="ticket_registration_id"/>
-        <result property="currentPaymentAmount" column="current_payment_amount"/>
-        <result property="paymentMethod" column="payment_method"/>
-        <result property="registrantId" column="registrant_id"/>
-        <result property="paymentDate" column="payment_date"/>
-        <result property="createTime" column="create_time"/>
-        <result property="updateTime" column="update_time"/>
-        <result property="salesContractNo" column="sales_contract_no"/>
-        <result property="purchaseContractNumber" column="purchase_contract_number"/>
-        <result property="supplierName" column="supplier_name"/>
-        <result property="invoiceNumber" column="invoice_number"/>
-        <result property="taxRate" column="tax_rate"/>
-        <result property="invoiceAmount" column="invoice_amount"/>
-        <result property="tenantId" column="tenant_id"/>
-        <result property="registrationtDate" column="registrationt_date"/>
-    </resultMap>
-
-    <sql id="selectPaymentRegistrationVo">
-        select pr.id,
-               pr.sale_ledger_id,
-               pr.purchase_ledger_id,
-               pr.supplier_id,
-               pr.ticket_registration_id,
-               pr.current_payment_amount,
-               pr.payment_method,
-               pr.registrant_id,
-               pr.payment_date,
-               pr.create_time,
-               pr.update_time,
-               pr.tenant_id,
-               sl.sales_contract_no as sales_contract_no,
-               pl.purchase_contract_number as purchase_contract_number,
-               sm.supplier_name as supplier_name,
-               ip.invoice_number as invoice_number,
-               ip.invoice_amount as invoice_amount,
-               pr.tax_rate,
-               pr.registrationt_date,
-               su.nick_name as registrant
-        from payment_registration pr
-                 left join sales_ledger sl on pr.sale_ledger_id = sl.id
-                 left join purchase_ledger pl on pr.purchase_ledger_id = pl.id
-                 left join supplier_manage sm on pr.supplier_id = sm.id
-                 left join ticket_registration ip on pr.ticket_registration_id = ip.id
-                 left join sys_user su on pr.registrant_id = su.user_id
-    </sql>
-
-    <select id="selectPaymentRegistrationList" parameterType="com.ruoyi.purchase.dto.PaymentRegistrationDto"
-            resultMap="PaymentRegistrationDtoResult">
-        <include refid="selectPaymentRegistrationVo"/>
-        <where>
-            <if test="supplierNameOrContractNo != null  and supplierNameOrContractNo != ''">
-                and sm.supplier_name LIKE CONCAT('%', #{supplierNameOrContractNo}, '%') or sl.sales_contract_no LIKE
-                CONCAT('%', #{supplierNameOrContractNo}, '%')
-                or pl.purchase_contract_number LIKE CONCAT('%', #{supplierNameOrContractNo}, '%')
-            </if>
-        </where>
-    </select>
-
-    <select id="selectPaymentRegistrationById" parameterType="Long" resultMap="PaymentRegistrationDtoResult">
-        <include refid="selectPaymentRegistrationVo"/>
-        where pr.id = #{id}
-    </select>
-
-    <select id="paymentHistoryList" resultType="com.ruoyi.purchase.dto.PaymentRegistrationDto">
-        SELECT
-            T1.payment_date,
-            T2.supplier_name,
-            T1.current_payment_amount,
-            T1.payment_method,
-            T3.nick_name AS registrant,
-            T1.registrationt_date
-        FROM
-            payment_registration T1
-                LEFT JOIN
-            supplier_manage T2 ON T1.supplier_id = T2.id
-                LEFT JOIN
-            sys_user T3 ON T3.user_id = T1.registrant_id
-        <where>
-            <if test="params.searchText != null and params.searchText != '' ">
-                AND T2.supplier_name LIKE CONCAT('%',#{params.searchText},'%')
-            </if>
-        </where>
-        ORDER BY T1.payment_date,T1.create_time DESC
-    </select>
-
-    <select id="countPaymentTotalByTicketRegId" resultType="com.ruoyi.purchase.dto.PaymentRegistrationDto">
-        SELECT
-            IFNULL(SUM(current_payment_amount),0) AS paymentAmountTotal,
-            ticket_registration_id
-        FROM
-            payment_registration
-        <where>
-            ticket_registration_id IN
-            <foreach collection="ticketRegistrationIds" separator="," open="(" close=")" item="item">
-                #{item}
-            </foreach>
-        </where>
-        GROUP BY ticket_registration_id
-    </select>
-
-    <select id="getPaymentRecordList" resultType="com.ruoyi.purchase.dto.PaymentHistoryRecordVo">
-        SELECT * FROM(
-             SELECT
-                 T1.issue_date AS happenTime,
-                 IFNULL(T1.invoice_amount,0) AS invoiceAmount,
-                 '1' AS type,
-                 0 AS currentPaymentAmount
-             FROM
-                 ticket_registration T1
-                     LEFT JOIN purchase_ledger T2 ON T1.purchase_ledger_id = T2.id
-             WHERE T2.supplier_id = #{supplierId}
-             UNION
-             SELECT
-                 payment_date AS happenTime,
-                 0 AS invoiceAmount,
-                 '0' AS type,
-                 current_payment_amount AS currentPaymentAmount
-             FROM payment_registration
-             WHERE supplier_id = #{supplierId}
-        ) T1
-        ORDER BY T1.happenTime ASC
-
-    </select>
-
-    <select id="paymentHistoryListPage" resultType="com.ruoyi.purchase.dto.PaymentRegistrationDto">
-        SELECT
-        T1.id,
-        T1.payment_date,
-        T2.supplier_name,
-        T1.current_payment_amount,
-        T1.payment_method,
-        T3.nick_name AS registrant,
-        T1.registrationt_date,
-        t4.purchase_contract_number,
-        t5.invoice_amount,
-        t5.invoice_number
-        FROM
-        payment_registration T1
-        LEFT JOIN purchase_ledger t4 ON t4.id = T1.purchase_ledger_id
-        LEFT JOIN supplier_manage T2 ON T1.supplier_id = T2.id
-        LEFT JOIN sys_user T3 ON T3.user_id = T1.registrant_id
-        left join ticket_registration t5 on t5.id = T1.ticket_registration_id
-        <where>
-            <if test="params.searchText != null and params.searchText != '' ">
-                AND T2.supplier_name LIKE CONCAT('%',#{params.searchText},'%')
-            </if>
-            <if test="params.paymentDateStart != null and params.paymentDateStart !='' ">
-                AND T1.payment_date &gt;= date_format(#{params.paymentDateStart},'%Y-%m-%d')
-            </if>
-            <if test="params.paymentDateEnd != null and params.paymentDateEnd !='' ">
-                AND T1.payment_date &lt;= date_format(#{params.paymentDateEnd},'%Y-%m-%d')
-            </if>
-            <if test="params.purchaseContractNumber != null and params.purchaseContractNumber !='' ">
-                AND t4.purchase_contract_number LIKE CONCAT('%',#{params.purchaseContractNumber},'%')
-            </if>
-        </where>
-        ORDER BY T1.payment_date,T1.create_time DESC
-    </select>
-    <select id="supplierNameListPage" resultType="com.ruoyi.purchase.dto.PaymentRegistrationDto">
-        SELECT
-        T1.supplier_id,
-        T1.supplier_name,
-        SUM(contract_amount) AS invoiceAmount,
-        IFNULL( SUM(T2.current_payment_amount) , 0 ) AS paymentAmount,
-        IFNULL((IFNULL(SUM(contract_amount),0)  - IFNULL(SUM(T2.current_payment_amount),0)),0) AS payableAmount
-        FROM purchase_ledger T1
-        LEFT JOIN payment_registration T2 ON T1.id = T2.purchase_ledger_id
-        <where>
-            <if test="req.supplierName != null and req.supplierName != '' ">
-                T1.supplier_name LIKE CONCAT ('%',#{req.supplierName},'%')
-            </if>
-        </where>
-        GROUP BY T1.supplier_id, T1.supplier_name
-    </select>
-
-    <select id="supplierNameListPageDetails" resultType="com.ruoyi.purchase.dto.PaymentRegistrationDto">
-        SELECT
-        T1.supplier_id,
-        T1.supplier_name,
-        T1.purchase_contract_number,
-        T2.payment_date,
-        SUM(T1.contract_amount) AS invoiceAmount,
-        IFNULL(SUM(T2.current_payment_amount), 0) AS paymentAmount,
-        IFNULL((IFNULL(SUM(T1.contract_amount), 0) - IFNULL(SUM(T2.current_payment_amount), 0)), 0) AS payableAmount
-        FROM purchase_ledger T1
-        INNER JOIN payment_registration T2 ON T1.id = T2.purchase_ledger_id
-        <where>
-            T1.supplier_id = #{req.supplierId}
-            <if test="req.supplierName != null and req.supplierName != '' ">
-                AND T1.supplier_name LIKE CONCAT ('%',#{req.supplierName},'%')
-            </if>
-        </where>
-        GROUP BY T1.supplier_id, T1.supplier_name, T1.purchase_contract_number, T2.payment_date
-    </select>
-
-</mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/purchase/ProductRecordMapper.xml b/src/main/resources/mapper/purchase/ProductRecordMapper.xml
deleted file mode 100644
index aa850cb..0000000
--- a/src/main/resources/mapper/purchase/ProductRecordMapper.xml
+++ /dev/null
@@ -1,71 +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.purchase.mapper.ProductRecordMapper">
-
-
-    <select id="productRecordPage" resultType="com.ruoyi.purchase.dto.ProductRecordDto">
-        SELECT
-        sl.sales_contract_no,
-        sl.customer_contract_no,
-        sl.customer_name,
-        pm.model AS product_model,
-        pl.purchase_contract_number,
-        pl.supplier_name,
-        pl.project_name,
-        pr.*,
-        tr.invoice_number,
-        tr.iss_uer_id,
-        tr.iss_uer,
-        tr.id as ticketRegistrationId,
-        ROUND(pr.tickets_amount/(1+pr.tax_rate/100),2 ) as un_tickets_price,
-        ROUND(pr.tickets_amount-pr.tickets_amount/(1+pr.tax_rate/100),2 )as invoice_amount
-        FROM product_record pr
-        left join purchase_ledger pl on pl.id = pr.purchase_ledger_id
-        left join sales_ledger sl on sl.id = pl.sales_ledger_id
-        left join ticket_registration tr on tr.id = pr.ticket_registration_id
-        left join product_model pm on pm.id = pr.product_model_id
-        WHERE type = 2
-        <if test="c.salesContractNo != null and c.salesContractNo != ''">
-            and sl.sales_contract_no like concat('%',#{c.salesContractNo},'%')
-        </if>
-        <if test="c.supplierName != null and c.supplierName != ''">
-            and pl.supplier_name like concat('%',#{c.supplierName},'%')
-        </if>
-        <if test="c.createdAtStart != null and c.createdAtStart != ''">
-            and pr.created_at &gt;= str_to_date(#{c.createdAtStart}, '%Y-%m-%d')
-        </if>
-        <if test="c.createdAtEnd != null and c.createdAtEnd != ''">
-            and pr.created_at &lt; date_add(str_to_date(#{c.createdAtEnd}, '%Y-%m-%d'), interval 1 day)
-        </if>
-        <if test="c.purchaseContractNumber != null and c.purchaseContractNumber != ''">
-            and tr.purchase_contract_number like concat('%',#{c.purchaseContractNumber},'%')
-        </if>
-    </select>
-    <select id="getProductRecordById" resultType="com.ruoyi.purchase.dto.ProductRecordDto">
-        SELECT
-            sl.sales_contract_no,
-            sl.customer_contract_no,
-            sl.customer_name,
-            pm.model AS product_model,
-            pl.purchase_contract_number,
-            pl.supplier_name,
-            pr.*,
-            tr.invoice_number,
-            ROUND(pr.tickets_amount/(1+pr.tax_rate/100),2 ) as un_tickets_price,
-            ROUND(pr.tickets_amount-pr.tickets_amount/(1+pr.tax_rate/100),2 )as invoice_amount
-        FROM product_record pr
-                 left join purchase_ledger pl on pl.id = pr.purchase_ledger_id
-                 left join sales_ledger sl on sl.id = pl.sales_ledger_id
-                 left join ticket_registration tr on tr.id = pr.ticket_registration_id
-                 left join product_model pm on pm.id = pr.product_model_id
-        WHERE type = 2
-        <if test="c.purchaseLedgerId != null and c.purchaseLedgerId != ''">
-            and pr.purchase_ledger_id = #{c.purchaseLedgerId}
-        </if>
-        <if test="c.productModelId != null and c.productModelId != ''">
-            and pm.id = #{c.productModelId}
-        </if>
-    </select>
-</mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml b/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
index 1aed9b4..ecdd1f3 100644
--- a/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
+++ b/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
@@ -9,6 +9,12 @@
         SET contract_amount = #{totalTaxInclusiveAmount}
         WHERE id = #{id}
     </update>
+    <select id="selectPurchaseStats" resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto">
+        SELECT DATE_FORMAT(entry_date, #{dateFormat}) as dateStr, IFNULL(SUM(contract_amount), 0) as amount
+        FROM purchase_ledger
+        WHERE entry_date BETWEEN #{startDate} AND #{endDate}
+        GROUP BY dateStr
+    </select>
 
     <select id="selectPurchaseLedgerListPage" resultType="com.ruoyi.purchase.dto.PurchaseLedgerDto">
         SELECT
@@ -19,8 +25,6 @@
         pl.supplier_name,
         pl.project_name,
         pl.contract_amount,
-        IFNULL(tr_sum.total_invoice_amount, 0) AS receipt_payment_amount,
-        pl.contract_amount - IFNULL(tr_sum.total_invoice_amount, 0) AS unReceipt_payment_amount,
         pl.entry_date,
         pl.execution_date,
         pl.recorder_id,
@@ -32,13 +36,6 @@
         pl.payment_method,
         pl.remarks
         FROM purchase_ledger pl
-        LEFT JOIN (
-        SELECT
-        purchase_ledger_id,
-        SUM(invoice_amount) AS total_invoice_amount
-        FROM ticket_registration
-        GROUP BY purchase_ledger_id
-        ) tr_sum ON pl.id = tr_sum.purchase_ledger_id
         LEFT JOIN supplier_manage sm ON pl.supplier_id = sm.id
         <where>
             <if test="c.purchaseContractNumber != null and c.purchaseContractNumber != ''">
@@ -72,33 +69,6 @@
         ORDER BY pl.entry_date DESC
     </select>
 
-    <select id="getPaymentRegistrationDtoById" resultType="com.ruoyi.purchase.dto.PaymentRegistrationDto">
-        SELECT
-            T1.id,
-            T1.payment_date,
-            T2.supplier_name,
-            T1.current_payment_amount,
-            T1.payment_method,
-            T3.nick_name AS registrant,
-            T1.registrationt_date
-        FROM
-            payment_registration T1
-                LEFT JOIN
-            supplier_manage T2 ON T1.supplier_id = T2.id
-                LEFT JOIN
-            sys_user T3 ON T3.user_id = T1.registrant_id
-        WHERE
-            T1.sales_ledger_product_id = #{id}
-    </select>
-
-
-    <select id="selectPurchaseStats" resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto">
-        SELECT DATE_FORMAT(entry_date, #{dateFormat}) as dateStr, IFNULL(SUM(contract_amount), 0) as amount
-        FROM purchase_ledger
-        WHERE entry_date BETWEEN #{startDate} AND #{endDate}
-        GROUP BY dateStr
-    </select>
-
     <select id="selectTotalPurchaseAmount" resultType="java.math.BigDecimal">
         SELECT IFNULL(SUM(contract_amount), 0)
         FROM purchase_ledger
@@ -111,4 +81,4 @@
             </if>
         </where>
     </select>
-</mapper>
\ No newline at end of file
+</mapper>
diff --git a/src/main/resources/mapper/purchase/PurchaseReturnOrdersMapper.xml b/src/main/resources/mapper/purchase/PurchaseReturnOrdersMapper.xml
index 6732a66..2f782ff 100644
--- a/src/main/resources/mapper/purchase/PurchaseReturnOrdersMapper.xml
+++ b/src/main/resources/mapper/purchase/PurchaseReturnOrdersMapper.xml
@@ -54,7 +54,7 @@
         where pro.id = #{id}
     </select>
     <select id="listPageAccountPurchaseReturn"
-            resultType="com.ruoyi.account.bean.vo.PurchaseReturnVo">
+            resultType="com.ruoyi.account.bean.vo.purchase.PurchaseReturnVo">
          select pro.id,
                 pro.no returnNo,
                 t.inboundBatches,
@@ -76,6 +76,9 @@
             <if test="req.returnNo != null and req.returnNo != ''">
                 and pro.no like concat('%',#{req.returnNo},'%')
             </if>
+            <if test="req.supplierId != null">
+                and pro.supplier_id = #{req.supplierId}
+            </if>
             <if test="req.supplierName != null and req.supplierName != ''">
                 and sm.supplier_name like concat('%',#{req.supplierName},'%')
             </if>
diff --git a/src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml b/src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml
index 5bda4f6..49380aa 100644
--- a/src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml
+++ b/src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml
@@ -84,7 +84,7 @@
                 ELSE false
                 END AS method
         FROM quality_unqualified qu
-                 LEFT JOIN product_model pm ON qu.model = pm.id
+                 LEFT JOIN product_model pm ON qu.product_model_id = pm.id
         where
             1=1
         and qu.id = #{id}
diff --git a/src/main/resources/mapper/sales/InvoiceLedgerMapper.xml b/src/main/resources/mapper/sales/InvoiceLedgerMapper.xml
deleted file mode 100644
index 5454640..0000000
--- a/src/main/resources/mapper/sales/InvoiceLedgerMapper.xml
+++ /dev/null
@@ -1,185 +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.sales.mapper.InvoiceLedgerMapper">
-    <select id="invoiceLedgerPage" resultType="com.ruoyi.sales.dto.InvoiceLedgerDto">
-        SELECT
-            T1.id                ,
-            T1.sales_ledger_id   ,
-            T1.sales_contract_no ,
-            T1.customer_id       ,
-            T1.invoice_no        ,
-            T1.invoice_amount    ,
-            T1.tax_rate          ,
-            T1.invoice_person    ,
-            T1.invoice_date      ,
-            T1.create_time       ,
-            T1.create_user       ,
-            T1.update_time       ,
-            T1.update_user       ,
-            T1.tenant_id         ,
-            T2.customer_name,
-            T3.customer_contract_no,
-            T3.salesman,
-            T4.invoiceFileName
-        FROM invoice_ledger T1
-        LEFT JOIN customer T2 ON T1.customer_id = T2.id
-        LEFT JOIN sales_ledger T3 ON T1.sales_ledger_id = T3.id
-        LEFT JOIN (
-        	SELECT
-        	    invoice_ledger_id,
-        	    GROUP_CONCAT( name ORDER BY id ASC SEPARATOR ' | ') AS invoiceFileName
-        	FROM invoice_ledger_file GROUP BY invoice_ledger_id
-        ) T4 ON T4.invoice_ledger_id = T1.id
-        <where>
-            <if test="invoiceLedgerDto.searchText != null and invoiceLedgerDto.searchText != ''">
-                AND (
-                    T2.customer_name LIKE CONCAT('%',#{invoiceLedgerDto.searchText},'%')
-                    OR T1.sales_contract_no LIKE CONCAT('%',#{invoiceLedgerDto.searchText},'%')
-                )
-            </if>
-            <if test="invoiceLedgerDto.invoiceDate != null">
-                AND DATE_FORMAT(T1.invoice_date,'%Y-%m-%d') = DATE_FORMAT(#{invoiceLedgerDto.invoiceDate},'%Y-%m-%d')
-            </if>
-        </where>
-    </select>
-
-    <select id="invoiceLedgerList" resultType="com.ruoyi.sales.dto.InvoiceLedgerDto">
-        SELECT
-            T1.id                ,
-            T1.sales_ledger_id   ,
-            T1.sales_contract_no ,
-            T1.customer_id       ,
-            T1.invoice_no        ,
-            T1.invoice_amount    ,
-            T1.tax_rate          ,
-            T1.invoice_person    ,
-            T1.invoice_date      ,
-            T1.create_time       ,
-            T1.create_user       ,
-            T1.update_time       ,
-            T1.update_user       ,
-            T1.tenant_id         ,
-            T2.customer_name,
-            T3.salesman,
-            T3.customer_contract_no,
-            T4.invoiceFileName
-        FROM invoice_ledger T1
-        LEFT JOIN customer T2 ON T1.customer_id = T2.id
-        LEFT JOIN sales_ledger T3 ON T1.sales_ledger_id = T3.id
-        LEFT JOIN (
-        SELECT
-        invoice_ledger_id,
-        GROUP_CONCAT( name ORDER BY id ASC SEPARATOR ' | ') AS invoiceFileName
-        FROM invoice_ledger_file GROUP BY invoice_ledger_id
-        ) T4 ON T4.invoice_ledger_id = T1.id
-        <where>
-            <if test="invoiceLedgerDto.searchText != null and invoiceLedgerDto.searchText != ''">
-                AND (
-                T2.customer_name LIKE CONCAT('%',#{invoiceLedgerDto.searchText},'%')
-                OR T1.sales_contract_no LIKE CONCAT('%',#{invoiceLedgerDto.searchText},'%')
-                )
-            </if>
-            <if test="invoiceLedgerDto.invoiceDate != null">
-                AND DATE_FORMAT(T1.invoice_date,'%Y-%m-%d') = DATE_FORMAT(#{invoiceLedgerDto.invoiceDate},'%Y-%m-%d')
-            </if>
-        </where>
-    </select>
-
-    <select id="invoiceLedgerInfo" resultType="com.ruoyi.sales.dto.InvoiceLedgerDto">
-        SELECT
-        T1.id                ,
-        T1.sales_ledger_id   ,
-        T1.sales_contract_no ,
-        T1.customer_id       ,
-        T1.invoice_no        ,
-        T1.invoice_amount    ,
-        T1.tax_rate          ,
-        T1.invoice_person    ,
-        T1.invoice_date      ,
-        T1.create_time       ,
-        T1.create_user       ,
-        T1.update_time       ,
-        T1.update_user       ,
-        T1.tenant_id         ,
-        T2.customer_name
-        FROM invoice_ledger T1
-        LEFT JOIN customer T2 ON T1.customer_id = T2.id
-        WHERE T1.id = #{id}
-    </select>
-
-    <select id="invoiceLedgerSalesAccount" resultType="com.ruoyi.sales.dto.InvoiceLedgerDto">
-        SELECT
-            T1.customer_id as id,
-            T1.customer_name,
-            SUM(contract_amount) AS invoice_total,
-            IFNULL( SUM(T2.receipt_payment_amount) , 0 ) AS receipt_payment_amount,
-            IFNULL((IFNULL(SUM(contract_amount),0)  - IFNULL(SUM(T2.receipt_payment_amount),0)),0) AS unReceipt_payment_amount
-        FROM sales_ledger T1
-        LEFT JOIN receipt_payment T2 ON T1.id = T2.sales_ledger_id
-        <where>
-            <if test="invoiceLedgerDto.searchText != null and invoiceLedgerDto.searchText != '' ">
-                T1.customer_name LIKE CONCAT ('%',#{invoiceLedgerDto.searchText},'%')
-            </if>
-        </where>
-        GROUP BY T1.customer_name,t1.customer_id
-    </select>
-
-    <select id="invoiceLedgerProductInfo" resultType="com.ruoyi.sales.dto.InvoiceRegistrationProductDto">
-        SELECT
-            T1.id   ,
-            T1.sales_ledger_id           ,
-            T1.sales_ledger_product_id   ,
-            T1.invoice_registration_id   ,
-            T1.product_category          ,
-            T1.specification_model       ,
-            T1.unit                      ,
-            T1.quantity                  ,
-            T1.tax_rate                  ,
-            T1.tax_inclusive_unit_price  ,
-            T1.tax_inclusive_total_price ,
-            T1.tax_exclusive_total_price ,
-            T1.invoice_type              ,
-            T1.invoice_num               ,
-            T1.invoice_amount            ,
-            T1.no_invoice_num            ,
-            T1.no_invoice_amount         ,
-            T1.create_time               ,
-            T1.create_user               ,
-            T1.update_time               ,
-            T1.update_user               ,
-            T1.tenant_id,
-            T2.sales_contract_no,
-            T2.customer_contract_no,
-            T2.customer_name,
-            T3.invoice_no,
-            T3.invoice_total,
-            T3.invoice_person,
-            T3.invoice_date,
-            T3.id AS invoice_ledger_id
-        FROM invoice_registration_product T1
-                 LEFT JOIN sales_ledger T2 ON T1.sales_ledger_id = T2.id
-                 LEFT JOIN invoice_ledger T3 ON T1.id = T3.invoice_registration_product_id
-        WHERE T1.id = #{id}
-    </select>
-
-    <select id="invoicedTotal" resultType="com.ruoyi.sales.dto.InvoiceLedgerDto">
-        SELECT
-            IFNULL(SUM(T1.invoice_total),0) AS invoice_total,
-            T2.sales_ledger_id
-        FROM
-            invoice_ledger T1
-                LEFT JOIN invoice_registration_product T2 ON T1.invoice_registration_product_id = T2.id
-        <where>
-            AND T2.sales_ledger_id IN
-            <foreach collection="salesLedgerIds" item="item" open="(" close=")" separator=",">
-                #{item}
-            </foreach>
-        </where>
-        GROUP BY
-            T2.sales_ledger_id
-    </select>
-
-
-</mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/sales/InvoiceRegistrationMapper.xml b/src/main/resources/mapper/sales/InvoiceRegistrationMapper.xml
deleted file mode 100644
index 9edbea4..0000000
--- a/src/main/resources/mapper/sales/InvoiceRegistrationMapper.xml
+++ /dev/null
@@ -1,72 +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.sales.mapper.InvoiceRegistrationMapper">
-    <select id="invoiceRegistrationListPage" resultType="com.ruoyi.sales.dto.InvoiceRegistrationDto">
-        SELECT
-            T1.id              ,
-            T1.sales_ledger_id   ,
-            T1.sales_contract_no ,
-            T1.customer_id       ,
-            T1.salesman          ,
-            T1.project_name      ,
-            T1.create_time       ,
-            T1.create_user       ,
-            T1.update_time       ,
-            T1.update_user       ,
-            T1.tenant_id,
-            T2.customer_contract_no,
-            T3.customer_name,
-            T2.contract_amount,
-            CASE WHEN T4.noInvoiceAmountTotal IS NULL THEN 0 ELSE T4.noInvoiceAmountTotal END AS noInvoiceAmountTotal
-        FROM invoice_registration T1
-        LEFT JOIN sales_ledger T2 ON T1.sales_ledger_id = T2.id
-        LEFT JOIN customer T3 ON T1.customer_id = T3.id
-        LEFT JOIN (
-            SELECT
-                SUM( no_invoice_amount ) AS noInvoiceAmountTotal ,
-                invoice_registration_id
-            FROM
-                invoice_registration_product
-            GROUP BY
-                invoice_registration_id
-        ) T4 ON T1.id = T4.invoice_registration_id
-    </select>
-
-    <select id="invoiceRegisAndProductExcelDtoList" resultType="com.ruoyi.sales.excel.InvoiceRegisAndProductExcelDto">
-        SELECT
-            T1.id              ,
-            T1.sales_ledger_id   ,
-            T1.sales_contract_no ,
-            T1.customer_id       ,
-            T1.salesman          ,
-            T1.project_name      ,
-            T1.create_time       ,
-            T1.create_user       ,
-            T1.update_time       ,
-            T1.update_user       ,
-            T1.tenant_id,
-            T2.customer_contract_no,
-            T3.customer_name,
-            T2.contract_amount,
-            T4.product_category,
-            T4.specification_model,
-            T4.unit,
-            T4.quantity,
-            T4.tax_rate,
-            T4.tax_inclusive_unit_price,
-            T4.tax_inclusive_total_price,
-            T4.tax_exclusive_total_price,
-            T4.invoice_type,
-            T4.invoice_num,
-            T4.invoice_amount,
-            T4.no_invoice_num,
-            T4.no_invoice_amount
-        FROM invoice_registration T1
-                 JOIN sales_ledger T2 ON T1.sales_ledger_id = T2.id
-                 JOIN customer T3 ON T1.customer_id = T3.id
-                JOIN invoice_registration_product T4 ON T1.id = T4.invoice_registration_id
-        ORDER BY T1.id ASC
-    </select>
-</mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/sales/InvoiceRegistrationProductMapper.xml b/src/main/resources/mapper/sales/InvoiceRegistrationProductMapper.xml
deleted file mode 100644
index ba790b1..0000000
--- a/src/main/resources/mapper/sales/InvoiceRegistrationProductMapper.xml
+++ /dev/null
@@ -1,132 +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.sales.mapper.InvoiceRegistrationProductMapper">
-
-    <select id="invoiceRegistrationProductList" resultType="com.ruoyi.sales.dto.InvoiceRegistrationProductDto">
-        SELECT
-        T1.id   ,
-        T1.sales_ledger_id           ,
-        T1.sales_ledger_product_id   ,
-        T1.invoice_registration_id   ,
-        T1.product_category          ,
-        T1.specification_model       ,
-        T1.unit                      ,
-        T1.quantity                  ,
-        T1.tax_rate                  ,
-        T1.tax_inclusive_unit_price  ,
-        T1.tax_inclusive_total_price ,
-        T1.tax_exclusive_total_price ,
-        T1.invoice_type              ,
-        T1.invoice_num               ,
-        T1.invoice_amount            ,
-        T1.no_invoice_num            ,
-        T1.no_invoice_amount         ,
-        T1.create_time               ,
-        T1.create_user               ,
-        T1.update_time               ,
-        T1.update_user               ,
-        T1.tenant_id,
-        T2.sales_contract_no,
-        T2.customer_contract_no,
-        T2.customer_name,
-        T3.invoice_no,
-        T3.invoice_total,
-        T3.invoice_person,
-        T3.invoice_date,
-        T4.invoiceFileName
-        FROM invoice_registration_product T1
-        LEFT JOIN sales_ledger T2 ON T1.sales_ledger_id = T2.id
-        LEFT JOIN invoice_ledger T3 ON T1.id = T3.invoice_registration_product_id
-        LEFT JOIN (
-        SELECT
-        invoice_ledger_id,
-        GROUP_CONCAT( name ORDER BY id ASC SEPARATOR ' | ') AS invoiceFileName
-        FROM invoice_ledger_file GROUP BY invoice_ledger_id
-        ) T4 ON T4.invoice_ledger_id = T3.id
-        <where>
-            <if test="invoiceRegistrationProductDto.searchText != null and invoiceRegistrationProductDto.searchText != '' ">
-                AND (T2.sales_contract_no LIKE CONCAT('%',#{invoiceRegistrationProductDto.searchText},'%')
-                OR
-                T2.customer_name LIKE CONCAT('%',#{invoiceRegistrationProductDto.searchText},'%')
-                )
-            </if>
-            <if test="invoiceRegistrationProductDto.invoiceDate != null">
-                AND T3.invoice_date = #{invoiceRegistrationProductDto.invoiceDate}
-            </if>
-        </where>
-        ORDER BY T1.create_time DESC, T1.id DESC
-    </select>
-
-    <select id="invoiceRegistrationProductPage" resultType="com.ruoyi.sales.dto.InvoiceRegistrationProductDto">
-        SELECT
-        T1.id ,
-        T1.sales_ledger_id ,
-        T1.sales_ledger_product_id ,
-        T1.invoice_registration_id ,
-        T1.product_category ,
-        T1.specification_model ,
-        T1.unit ,
-        T1.quantity ,
-        T1.tax_rate ,
-        T1.tax_inclusive_unit_price ,
-        T1.tax_inclusive_total_price ,
-        T1.tax_exclusive_total_price ,
-        T1.invoice_type ,
-        T1.invoice_num ,
-        T1.invoice_amount ,
-        T1.no_invoice_num ,
-        T1.no_invoice_amount ,
-        T1.create_time ,
-        T1.create_user ,
-        T1.update_time ,
-        T1.update_user ,
-        T1.tenant_id,
-        T2.sales_contract_no,
-        T2.customer_contract_no,
-        T2.customer_name,
-        T3.invoice_no,
-        T3.id as invoice_ledger_id,
-        IFNULL(T3.invoice_total,0) AS invoice_total,
-        T3.invoice_person,
-        T3.invoice_date,
-        T4.invoiceFileName,
-        T2.project_name,
-        u.nick_name as invoicePerson
-        FROM invoice_registration_product T1
-        LEFT JOIN sales_ledger T2 ON T1.sales_ledger_id = T2.id
-        LEFT JOIN sys_user u ON u.user_id = T1.create_user
-        RIGHT JOIN invoice_ledger T3 ON T1.id = T3.invoice_registration_product_id
-        LEFT JOIN (
-        SELECT
-        invoice_ledger_id,
-        GROUP_CONCAT( name ORDER BY id ASC SEPARATOR ' | ') AS invoiceFileName
-        FROM invoice_ledger_file GROUP BY invoice_ledger_id
-        ) T4 ON T4.invoice_ledger_id = T3.id
-        <where>
-            <if test="invoiceRegistrationProductDto.searchText != null and invoiceRegistrationProductDto.searchText != '' ">
-                AND (T2.sales_contract_no LIKE CONCAT('%',#{invoiceRegistrationProductDto.searchText},'%')
-                OR
-                T2.customer_name LIKE CONCAT('%',#{invoiceRegistrationProductDto.searchText},'%')
-                )
-            </if>
-            <if test="invoiceRegistrationProductDto.invoiceDateStart != null and invoiceRegistrationProductDto.invoiceDateStart != ''">
-                AND T3.invoice_date &gt;= str_to_date(#{invoiceRegistrationProductDto.invoiceDateStart}, '%Y-%m-%d')
-            </if>
-            <if test="invoiceRegistrationProductDto.invoiceDateEnd != null and invoiceRegistrationProductDto.invoiceDateEnd != ''">
-                AND T3.invoice_date &lt; date_add(str_to_date(#{invoiceRegistrationProductDto.invoiceDateEnd},
-                '%Y-%m-%d'), interval 1 day)
-            </if>
-            <if test="invoiceRegistrationProductDto.createTimeStart != null ">
-                AND T1.create_time &gt;= date_format(#{invoiceRegistrationProductDto.createTimeStart}, '%Y-%m-%d
-                %H:%i:%s')
-            </if>
-            <if test="invoiceRegistrationProductDto.createTimeEnd != null ">
-                AND T1.create_time &lt;= date_format(#{invoiceRegistrationProductDto.createTimeStart}, '%Y-%m-%d
-                %H:%i:%s')+interval 1 day
-            </if>
-        </where>
-        ORDER BY T1.create_time DESC, T1.id DESC
-    </select>
-</mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/sales/ReceiptPaymentMapper.xml b/src/main/resources/mapper/sales/ReceiptPaymentMapper.xml
deleted file mode 100644
index 975d120..0000000
--- a/src/main/resources/mapper/sales/ReceiptPaymentMapper.xml
+++ /dev/null
@@ -1,454 +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.sales.mapper.ReceiptPaymentMapper">
-    <select id="receiptPaymentListPage" resultType="com.ruoyi.sales.dto.ReceiptPaymentDto">
-        SELECT
-            T4.customer_id,
-            IFNULL(T5.invoice_total,0) AS invoice_total,
-            T1.receipt_payment_amount,
-            T1.receipt_payment_date
-        FROM
-            receipt_payment T1
-        LEFT JOIN invoice_ledger T2 ON T1.invoice_ledger_id = T2.id
-        LEFT JOIN invoice_registration_product T3 ON T2.invoice_registration_product_id = T3.id
-        LEFT JOIN sales_ledger T4 ON T4.id = T3.sales_ledger_id
-        LEFT JOIN (
-            SELECT
-                T3.customer_id,
-                SUM( invoice_total ) AS invoice_total
-            FROM
-                invoice_ledger T1
-            LEFT JOIN invoice_registration_product T2 ON T1.invoice_registration_product_id = T2.id
-            LEFT JOIN sales_ledger T3 ON T3.id = T2.sales_ledger_id
-            GROUP BY T3.customer_id
-        ) T5 ON T5.customer_id = T4.customer_id
-        <where>
-            <if test="receiptPaymentDto.customerId != null">
-                AND T4.customer_id = #{receiptPaymentDto.customerId}
-            </if>
-        </where>
-        ORDER BY T1.create_time ASC
-    </select>
-
-    <select id="receiptPaymentInfo" resultType="com.ruoyi.sales.dto.ReceiptPaymentDto">
-        SELECT
-            T1.id                 ,
-            T1.sales_ledger_id        ,
-            T1.sales_contract_no      ,
-            T1.customer_id            ,
-            T1.invoice_no             ,
-            T1.invoice_amount         ,
-            T1.tax_rate               ,
-            T1.receipt_payment_type   ,
-            T1.receipt_payment_amount ,
-            T1.registrant             ,
-            T1.receipt_payment_date   ,
-            T1.create_time            ,
-            T1.create_user            ,
-            T1.update_time            ,
-            T1.update_user            ,
-            T1.tenant_id,
-            T1.invoice_ledger_id,
-            T3.customer_contract_no,
-            T2.customer_name
-        FROM receipt_payment T1
-                 LEFT JOIN customer T2 ON T1.customer_id = T2.id
-                 LEFT JOIN sales_ledger T3 ON T1.sales_ledger_id = T3.id
-        WHERE T1.id = #{id}
-    </select>
-
-    <select id="bindInvoiceNoRegPage" resultType="com.ruoyi.sales.dto.ReceiptPaymentDto">
-        SELECT
-        T1.id,
-        T1.invoice_no,
-        T1.invoice_total,
-        T3.project_name,
-        T1.invoice_person,
-        T1.invoice_date,
-        T1.create_time,
-        T1.create_user,
-        T1.update_time,
-        T1.update_user,
-        T1.tenant_id,
-        T2.tax_rate,
-        T3.sales_contract_no,
-        T3.customer_contract_no,
-        T3.customer_name,
-        T4.invoiceFileName,
-        T5.product_category,
-        IFNULL(T6.receipt_payment_amount_total, 0) AS receipt_payment_amount_total,
-        (T1.invoice_total - IFNULL(T6.receipt_payment_amount_total, 0)) AS noReceiptAmount
-        FROM invoice_ledger T1
-        LEFT JOIN invoice_registration_product T2 ON T2.id = T1.invoice_registration_product_id
-        LEFT JOIN sales_ledger T3 ON T3.id = T2.sales_ledger_id
-        LEFT JOIN (
-        SELECT
-        invoice_ledger_id,
-        GROUP_CONCAT(name ORDER BY id ASC SEPARATOR ' | ') AS invoiceFileName
-        FROM invoice_ledger_file
-        GROUP BY invoice_ledger_id
-        ) T4 ON T4.invoice_ledger_id = T1.id
-        LEFT JOIN sales_ledger_product T5 ON T2.sales_ledger_product_id = T5.id and slp.type = 1
-        LEFT JOIN (
-        SELECT
-        SUM(receipt_payment_amount) AS receipt_payment_amount_total,
-        invoice_ledger_id
-        FROM receipt_payment
-        GROUP BY invoice_ledger_id
-        ) T6 ON T1.id = T6.invoice_ledger_id
-        <where>
-            <if test="req.customerName != null and req.customerName !=''">
-                AND T3.customer_name LIKE CONCAT('%',#{req.customerName},'%')
-            </if>
-            <if test="req.invoiceLedgerId != null">
-                AND T1.id = #{req.invoiceLedgerId}
-            </if>
-            <if test="req.customerContractNo != null and req.customerContractNo !=''">
-                AND T3.customer_contract_no LIKE CONCAT('%',#{req.customerContractNo},'%')
-            </if>
-            <if test="req.projectName != null and req.projectName !=''">
-                AND T3.project_name LIKE CONCAT('%',#{req.projectName},'%')
-            </if>
-            <if test="req.invoiceDateStart != null and req.invoiceDateStart != '' ">
-                AND T1.invoice_date &gt;= DATE_FORMAT(#{req.invoiceDateStart},'%Y-%m-%d')
-            </if>
-            <if test="req.invoiceDateEnd != null and req.invoiceDateEnd != '' ">
-                AND T1.invoice_date &lt;= DATE_FORMAT(#{req.invoiceDateEnd},'%Y-%m-%d')
-            </if>
-            <if test="req.status != null and req.status">
-                and (T1.invoice_total - IFNULL(T6.receipt_payment_amount_total, 0)) &gt; 0
-            </if>
-        </where>
-
-        ORDER BY IFNULL(T2.create_time, T1.create_time) DESC
-
-    </select>
-
-    <select id="invoiceInfo" resultType="com.ruoyi.sales.dto.InvoiceLedgerDto">
-        SELECT
-            T1.id,
-            T1.invoice_no,
-            T1.invoice_total ,
-            T2.tax_rate,
-            T3.customer_name,
-            T3.sales_contract_no
-        FROM
-            invoice_ledger T1
-                LEFT JOIN
-            invoice_registration_product T2 ON T1.invoice_registration_product_id = T2.id
-                LEFT JOIN sales_ledger T3 ON T3.id = T2.sales_ledger_id
-        WHERE T1.id = #{id}
-    </select>
-
-    <select id="getReceiptAmount" resultType="java.math.BigDecimal">
-        SELECT
-            SUM( receipt_payment_amount ) AS total_amount
-        FROM
-            (
-                SELECT
-                    T1.receipt_payment_amount
-                FROM
-                    receipt_payment T1
-                        LEFT JOIN invoice_ledger T2 ON T1.invoice_ledger_id = T2.id
-                        LEFT JOIN invoice_registration_product T3 ON T2.invoice_registration_product_id = T3.id
-                        LEFT JOIN sales_ledger T4 ON T4.id = T3.sales_ledger_id
-                        LEFT JOIN (
-                        SELECT
-                            T3.customer_id,
-                            SUM( invoice_total ) AS invoice_total
-                        FROM
-                            invoice_ledger T1
-                                LEFT JOIN invoice_registration_product T2 ON T1.invoice_registration_product_id = T2.id
-                                LEFT JOIN sales_ledger T3 ON T3.id = T2.sales_ledger_id
-                        GROUP BY
-                            T3.customer_id
-                    ) T5 ON T5.customer_id = T4.customer_id
-                WHERE
-                    T4.customer_id = #{customerId}
-
-                ORDER BY
-                    T1.create_time ASC
-                    LIMIT #{total} ) AS limited_rows
-    </select>
-
-    <select id="receiptPaymentHistoryList" resultType="com.ruoyi.sales.dto.ReceiptPaymentDto">
-        SELECT
-            T1.receipt_payment_date,
-            T5.customer_name,
-            T1.receipt_payment_amount,
-            T1.receipt_payment_type,
-            T1.registrant,
-            T1.create_time
-        FROM
-            receipt_payment T1
-                LEFT JOIN
-            invoice_ledger T2 ON T1.invoice_ledger_id = T2.id
-                LEFT JOIN invoice_registration_product T3 ON T2.invoice_registration_product_id = T3.id
-                LEFT JOIN sales_ledger T4 ON T3.sales_ledger_id = T4.id
-                LEFT JOIN customer T5 ON T5.id = T4.customer_id
-        <where>
-            <if test="params.searchText != null and params.searchText != '' ">
-                T5.customer_name LIKE CONCAT('%',#{params.searchText},'%')
-            </if>
-        </where>
-        ORDER BY T1.receipt_payment_date DESC
-    </select>
-
-    <select id="receiptPaymentHistoryListPage" resultType="com.ruoyi.sales.dto.ReceiptPaymentDto">
-        SELECT
-        T1.id,
-        T1.receipt_payment_date,
-        T5.customer_name,
-        T1.receipt_payment_amount,
-        T1.receipt_payment_type,
-        T1.registrant,
-        T1.create_time,
-        T4.project_name,
-        T4.sales_contract_no,
-        T4.customer_contract_no
-        FROM
-        receipt_payment T1
-        LEFT JOIN sales_ledger T4 ON T1.sales_ledger_id = T4.id
-        LEFT JOIN customer T5 ON T5.id = T4.customer_id
-        <where>
-            <if test="params.searchText != null and params.searchText != '' ">
-                T5.customer_name LIKE CONCAT('%',#{params.searchText},'%')
-            </if>
-            <if test="params.receiptPaymentDateStart != null and params.receiptPaymentDateStart != '' ">
-                AND T1.receipt_payment_date &gt;= date_format(#{params.receiptPaymentDateStart},'%Y-%m-%d')
-            </if>
-            <if test="params.receiptPaymentDateEnd != null and params.receiptPaymentDateEnd != '' ">
-                AND T1.receipt_payment_date &lt;= date_format(#{params.receiptPaymentDateEnd}, '%Y-%m-%d')
-            </if>
-            <if test="params.projectName != null and params.projectName != '' ">
-                AND T4.project_name LIKE CONCAT('%',#{params.projectName},'%')
-            </if>
-            <if test="params.customerContractNo != null and params.customerContractNo != '' ">
-                AND T4.customer_contract_no LIKE CONCAT('%',#{params.customerContractNo},'%')
-            </if>
-            <if test="params.salesContractNo != null and params.salesContractNo != '' ">
-                AND T4.sales_contract_no LIKE CONCAT('%',#{params.salesContractNo},'%')
-            </if>
-        </where>
-        ORDER BY T1.receipt_payment_date DESC
-    </select>
-
-
-
-
-<!--    SELECT-->
-<!--    *-->
-<!--    FROM-->
-<!--    (-->
-<!--    SELECT-->
-<!--    receipt_payment_amount AS receiptAmount,-->
-<!--    receipt_payment_date AS happenTime,-->
-<!--    0 AS type,-->
-<!--    0 AS invoiceAmount-->
-<!--    FROM-->
-<!--    receipt_payment-->
-<!--    WHERE-->
-<!--    invoice_ledger_id IN (-->
-<!--    SELECT-->
-<!--    id-->
-<!--    FROM-->
-<!--    invoice_ledger-->
-<!--    WHERE-->
-<!--    invoice_registration_product_id IN (-->
-<!--    SELECT-->
-<!--    id-->
-<!--    FROM-->
-<!--    invoice_registration_product-->
-<!--    WHERE-->
-<!--    sales_ledger_id IN ( SELECT id FROM sales_ledger WHERE customer_id =  #{customerId} ))) UNION-->
-<!--    SELECT-->
-<!--    0 AS receiptAmount,-->
-<!--    invoice_date AS happenTime,-->
-<!--    1 AS type,-->
-<!--    invoice_total AS invoiceAmount-->
-<!--    FROM-->
-<!--    invoice_ledger-->
-<!--    WHERE-->
-<!--    invoice_registration_product_id IN (-->
-<!--    SELECT-->
-<!--    id-->
-<!--    FROM-->
-<!--    invoice_registration_product-->
-<!--    WHERE-->
-<!--    sales_ledger_id IN ( SELECT id FROM sales_ledger WHERE customer_id = #{customerId} ))-->
-<!--    AND invoice_date IS NOT NULL-->
-<!--    ) T1-->
-<!--    ORDER BY-->
-<!--    T1.happenTime ASC-->
-
-
-    <select id="customerInteractions" resultType="com.ruoyi.sales.dto.CustomerInteractionDto">
-        SELECT
-            rp.receipt_payment_amount AS receiptAmount,
-            rp.receipt_payment_date   AS happenTime,
-            0                          AS type,
-            0                          AS invoiceAmount
-        FROM
-            receipt_payment rp
-        WHERE EXISTS (
-            SELECT 1
-            FROM invoice_ledger il
-                     JOIN invoice_registration_product irp ON il.invoice_registration_product_id = irp.id
-                     JOIN sales_ledger sl ON irp.sales_ledger_id = sl.id
-            WHERE sl.customer_id = #{customerId}
-              AND rp.invoice_ledger_id = il.id
-        )
-
-        UNION ALL
-
-        SELECT
-            0 AS receiptAmount,
-            il.invoice_date AS happenTime,
-            1 AS type,
-            il.invoice_total AS invoiceAmount
-        FROM
-            invoice_ledger il
-                JOIN invoice_registration_product irp ON il.invoice_registration_product_id = irp.id
-                JOIN sales_ledger sl ON irp.sales_ledger_id = sl.id
-        WHERE
-            sl.customer_id =  #{customerId}
-          AND il.invoice_date IS NOT NULL
-
-        ORDER BY happenTime ASC;
-    </select>
-
-    <select id="receiptPaymentHistoryListNoPage" resultType="com.ruoyi.sales.dto.ReceiptPaymentDto">
-        SELECT
-        T1.id,
-        T1.receipt_payment_date,
-        T5.customer_name,
-        T1.receipt_payment_amount,
-        T1.receipt_payment_type,
-        T1.registrant,
-        T1.create_time
-        FROM
-        receipt_payment T1
-        LEFT JOIN
-        invoice_ledger T2 ON T1.invoice_ledger_id = T2.id
-        LEFT JOIN invoice_registration_product T3 ON T2.invoice_registration_product_id = T3.id
-        LEFT JOIN sales_ledger T4 ON T3.sales_ledger_id = T4.id
-        LEFT JOIN customer T5 ON T5.id = T4.customer_id
-        WHERE T1.invoice_ledger_id = #{params.invoiceLedgerId}
-        ORDER BY T1.receipt_payment_date DESC
-    </select>
-
-    <select id="receiptPaymentListByProdRegId" resultType="com.ruoyi.sales.pojo.ReceiptPayment">
-        SELECT
-            T1.*
-        FROM
-            receipt_payment T1
-                LEFT JOIN invoice_ledger T2 ON T1.invoice_ledger_id = T2.id
-        WHERE
-            T2.invoice_registration_product_id = #{invoiceRegistrationProductId}
-    </select>
-    <select id="bindInvoiceNoRegListAll" resultType="com.ruoyi.sales.dto.ReceiptPaymentDto">
-        SELECT
-            T1.id ,
-            T1.invoice_no ,
-            T1.invoice_total ,
-            T3.project_name,
-            T1.invoice_person ,
-            T1.invoice_date ,
-            T1.create_time ,
-            T1.create_user ,
-            T1.update_time ,
-            T1.update_user ,
-            T1.tenant_id ,
-            T2.tax_rate,
-            T3.sales_contract_no,
-            T3.customer_contract_no,
-            T3.customer_name,
-            T4.invoiceFileName,
-            T5.product_category,
-            IFNULL(T6.receipt_payment_amount_total ,0) AS receipt_payment_amount_total,
-            (T1.invoice_total - IFNULL(T6.receipt_payment_amount_total ,0)) AS no_receipt_amount
-        FROM invoice_ledger T1
-                 LEFT JOIN invoice_registration_product T2 ON T2.id = T1.invoice_registration_product_id
-                 LEFT JOIN sales_ledger T3 ON T3.id = T2.sales_ledger_id
-                 LEFT JOIN (
-            SELECT
-                invoice_ledger_id,
-                GROUP_CONCAT( name ORDER BY id ASC SEPARATOR ' | ') AS invoiceFileName
-            FROM invoice_ledger_file GROUP BY invoice_ledger_id
-        ) T4 ON T4.invoice_ledger_id = T1.id
-                 LEFT JOIN sales_ledger_product T5 ON T2.sales_ledger_product_id = T5.id and slp.type = 1
-                 LEFT JOIN (
-            SELECT SUM(receipt_payment_amount) AS receipt_payment_amount_total,invoice_ledger_id FROM receipt_payment GROUP
-                BY invoice_ledger_id
-        ) T6 ON T1.id = T6.invoice_ledger_id
-    </select>
-    <select id="bindInvoiceNoRegListByIds" resultType="com.ruoyi.sales.dto.ReceiptPaymentExeclDto">
-        SELECT
-        T1.id ,
-        T1.invoice_no ,
-        T1.invoice_total ,
-        T3.project_name,
-        T1.invoice_person ,
-        T1.invoice_date ,
-        T1.create_time ,
-        T1.create_user ,
-        T1.update_time ,
-        T1.update_user ,
-        T1.tenant_id ,
-        T2.tax_rate,
-        T3.sales_contract_no,
-        T3.customer_contract_no,
-        T3.customer_name,
-        T4.invoiceFileName,
-        T5.product_category,
-        IFNULL(T6.receipt_payment_amount_total ,0) AS receipt_payment_amount_total,
-        (T1.invoice_total - IFNULL(T6.receipt_payment_amount_total ,0)) AS no_receipt_amount
-        FROM invoice_ledger T1
-        LEFT JOIN invoice_registration_product T2 ON T2.id = T1.invoice_registration_product_id
-        LEFT JOIN sales_ledger T3 ON T3.id = T2.sales_ledger_id
-        LEFT JOIN (
-        SELECT
-        invoice_ledger_id,
-        GROUP_CONCAT( name ORDER BY id ASC SEPARATOR ' | ') AS invoiceFileName
-        FROM invoice_ledger_file GROUP BY invoice_ledger_id
-        ) T4 ON T4.invoice_ledger_id = T1.id
-        LEFT JOIN sales_ledger_product T5 ON T2.sales_ledger_product_id = T5.id and slp.type = 1
-        LEFT JOIN (
-        SELECT SUM(receipt_payment_amount) AS receipt_payment_amount_total,invoice_ledger_id FROM receipt_payment GROUP
-        BY invoice_ledger_id
-        ) T6 ON T1.id = T6.invoice_ledger_id
-        <where>
-        <if test="ids.size() > 0">
-            T1.id IN
-            <foreach item="item" collection="ids" separator="," open="(" close=")">
-                #{item}
-            </foreach>
-        </if>
-        <if test="tenantId != null " >
-            AND T1.tenant_id = #{tenantId}
-        </if>
-        </where>
-
-    </select>
-
-    <select id="invoiceLedgerSalesAccount" resultType="com.ruoyi.sales.dto.InvoiceLedgerDto">
-        SELECT
-        T1.sales_contract_no,
-        T1.contract_amount AS invoice_total,
-        IFNULL(SUM(T2.receipt_payment_amount), 0) AS receipt_payment_amount,
-        IFNULL((T1.contract_amount - IFNULL(SUM(T2.receipt_payment_amount), 0)), 0) AS unReceipt_payment_amount,
-        T2.receipt_payment_date
-        FROM sales_ledger T1
-        INNER JOIN receipt_payment T2 ON T1.id = T2.sales_ledger_id
-        <where>
-            T1.customer_id = #{invoiceLedgerDto.customerId}
-            <if test="invoiceLedgerDto.searchText != null and invoiceLedgerDto.searchText != '' ">
-                AND T1.customer_name LIKE CONCAT ('%', #{invoiceLedgerDto.searchText}, '%')
-            </if>
-        </where>
-        GROUP BY T1.id, T1.sales_contract_no, T1.contract_amount, T2.receipt_payment_date
-    </select>
-
-</mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml b/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
index 7e352d8..7eb7b79 100644
--- a/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
+++ b/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -9,7 +9,6 @@
         T1.id,
         T1.sales_ledger_id,
         T1.warn_num,
-        T1.speculative_trading_name,
         T1.quantity,
         T1.min_stock,
         T1.tax_rate,
@@ -18,23 +17,11 @@
         T1.tax_exclusive_total_price,
         T1.invoice_type,
         T1.type,
-        T1.tickets_num,
-        T1.tickets_amount,
-        T1.future_tickets,
-        T1.future_tickets_amount,
-        T1.invoice_num,
-        T1.no_invoice_num,
-        T1.invoice_amount,
-        T1.no_invoice_amount,
         T1.product_id,
         T1.product_model_id,
         T1.register,
         T1.register_date,
         T1.approve_status,
-        T1.pending_invoice_total,
-        T1.invoice_total,
-        T1.pending_tickets_total,
-        T1.tickets_total,
         T1.is_checked,
         T1.is_production,
         T1.create_user,
@@ -94,74 +81,6 @@
           and slp.id is not null
         order by slp.id desc
         limit 1
-
-
-    </select>
-    <select id="listPage" resultType="com.ruoyi.sales.dto.SalesLedgerProductDto">
-        select slp.*,
-        sl.project_name,
-        sl.customer_name,
-        sl.sales_contract_no,
-        sl.customer_contract_no
-        from sales_ledger_product slp
-        left join sales_ledger sl on slp.sales_ledger_id = sl.id
-        <where>
-            slp.type = 1
-            <if test="req.salesContractNo != null and req.salesContractNo != '' ">
-                AND sl.sales_contract_no like concat('%',#{req.salesContractNo},'%')
-            </if>
-            <if test="req.customerContractNo != null and req.customerContractNo != '' ">
-                AND sl.customer_contract_no like concat('%',#{req.customerContractNo},'%')
-            </if>
-            <if test="req.projectName != null and req.projectName != '' ">
-                AND sl.project_name like concat('%',#{req.projectName},'%')
-            </if>
-            <if test="req.customerName != null and req.customerName != '' ">
-                AND sl.customer_name like concat('%',#{req.customerName},'%')
-            </if>
-            <if test="req.productCategory != null and req.productCategory != '' ">
-                AND slp.product_category like concat('%',#{req.productCategory},'%')
-            </if>
-            <if test="req.status != null and req.status ">
-                AND slp.pending_invoice_total &gt; 0
-            </if>
-        </where>
-        order by slp.register_date desc
-    </select>
-    <select id="listPagePurchaseLedger" resultType="com.ruoyi.sales.dto.SalesLedgerProductDto">
-        select slp.*,
-        sl.project_name,
-        sl.supplier_name,
-        sl.supplier_id,
-        sl.sales_contract_no,
-        sl.purchase_contract_number
-        from sales_ledger_product slp
-        left join purchase_ledger sl on slp.sales_ledger_id = sl.id
-        <where>
-            slp.type = 2
-            <if test="req.purchaseContractNumber != null and req.purchaseContractNumber != '' ">
-                AND sl.purchase_contract_number like concat('%',#{req.purchaseContractNumber},'%')
-            </if>
-            <if test="req.approvalStatus != null and req.approvalStatus != ''">
-                and sl.approval_status = #{req.approvalStatus}
-            </if>
-            <if test="req.customerContractNo != null and req.customerContractNo != '' ">
-                AND sl.customer_contract_no like concat('%',#{req.customerContractNo},'%')
-            </if>
-            <if test="req.projectName != null and req.projectName != '' ">
-                AND sl.project_name like concat('%',#{req.projectName},'%')
-            </if>
-            <if test="req.customerName != null and req.customerName != '' ">
-                AND sl.customer_name like concat('%',#{req.customerName},'%')
-            </if>
-            <if test="req.productCategory != null and req.productCategory != '' ">
-                AND slp.product_category like concat('%',#{req.productCategory},'%')
-            </if>
-            <if test="req.status != null and req.status ">
-                AND slp.pending_tickets_total &gt; 0
-            </if>
-        </where>
-        order by slp.register_date desc
     </select>
     <select id="procurementBusinessSummaryListPage"
             resultType="com.ruoyi.purchase.dto.ProcurementBusinessSummaryDto">
diff --git a/src/main/resources/mapper/stock/StockInRecordMapper.xml b/src/main/resources/mapper/stock/StockInRecordMapper.xml
index 579a464..5545c1e 100644
--- a/src/main/resources/mapper/stock/StockInRecordMapper.xml
+++ b/src/main/resources/mapper/stock/StockInRecordMapper.xml
@@ -31,6 +31,12 @@
             <if test="params.productName != null and params.productName != ''">
                 and p.product_name like concat('%',#{params.productName},'%')
             </if>
+            <if test="params.model != null and params.model != ''">
+                and pm.model like concat('%',#{params.model},'%')
+            </if>
+            <if test="params.batchNo != null and params.batchNo != ''">
+                and sir.batch_no like concat('%',#{params.batchNo},'%')
+            </if>
             <if test="params.type != null and params.type != ''">
                 and sir.type = #{params.type}
             </if>
@@ -70,7 +76,7 @@
         </where>
         order by sir.id desc
     </select>
-    <select id="listPageAccountPurchase" resultType="com.ruoyi.account.bean.vo.PurchaseInboundVo">
+    <select id="listPageAccountPurchase" resultType="com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo">
         SELECT
             sir.id,
             sir.inbound_batches,
@@ -87,7 +93,7 @@
             LEFT JOIN purchase_ledger pl
             ON pl.id = IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id)
             -- 浜у搧鍏宠仈涓嶅姩
-            LEFT JOIN sales_ledger_product slp ON pl.id = slp.product_id
+            LEFT JOIN sales_ledger_product slp ON pl.id = slp.sales_ledger_id
             LEFT JOIN product_model pm ON sir.product_model_id = pm.id
             LEFT JOIN product p ON pm.product_id = p.id
             -- 鏉′欢
@@ -96,6 +102,9 @@
         <if test="req.inboundBatches != null and req.inboundBatches != ''">
             AND sir.inbound_batches LIKE CONCAT('%',#{req.inboundBatches},'%')
         </if>
+        <if test="req.supplierId != null">
+            AND pl.supplier_id = #{req.supplierId}
+        </if>
         <if test="req.supplierName != null and req.supplierName != ''">
             AND pl.supplier_name LIKE CONCAT('%',#{req.supplierName},'%')
         </if>
diff --git a/src/main/resources/mapper/stock/StockInventoryMapper.xml b/src/main/resources/mapper/stock/StockInventoryMapper.xml
index c71ce31..428e8da 100644
--- a/src/main/resources/mapper/stock/StockInventoryMapper.xml
+++ b/src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -209,6 +209,12 @@
             <if test="ew.topParentProductId != null and ew.topParentProductId > 0">
                 and combined.product_id in (select id from product_tree)
             </if>
+            <if test="ew.model != null and ew.model !=''">
+                and combined.model like concat('%',#{ew.model},'%')
+            </if>
+            <if test="ew.batchNo != null and ew.batchNo !=''">
+                and combined.batch_no like concat('%',#{ew.batchNo},'%')
+            </if>
         </where>
         group by
         product_model_id,
diff --git a/src/main/resources/mapper/stock/StockOutRecordMapper.xml b/src/main/resources/mapper/stock/StockOutRecordMapper.xml
index 35421c9..ad5976f 100644
--- a/src/main/resources/mapper/stock/StockOutRecordMapper.xml
+++ b/src/main/resources/mapper/stock/StockOutRecordMapper.xml
@@ -46,6 +46,12 @@
             <if test="params.productName != null and params.productName != ''">
                 and p.product_name like concat('%',#{params.productName},'%')
             </if>
+            <if test="params.model != null and params.model != ''">
+                and pm.model like concat('%',#{params.model},'%')
+            </if>
+            <if test="params.batchNo != null and params.batchNo != ''">
+                and sor.batch_no like concat('%',#{params.batchNo},'%')
+            </if>
             <if test="params.type != null and params.type != ''">
                 and sor.type = #{params.type}
             </if>
@@ -86,7 +92,7 @@
         order by sor.id desc
     </select>
 
-    <select id="listPageAccountSales" resultType="com.ruoyi.account.bean.vo.SalesOutboundVo">
+    <select id="listPageAccountSales" resultType="com.ruoyi.account.bean.vo.sales.SalesOutboundVo">
     SELECT
         sor.id,
         sor.outbound_batches,
@@ -94,6 +100,7 @@
         sor.create_time as shippingDate,
         p.product_name,
         pm.model as specification_model,
+        slp.tax_rate,
         sor.stock_out_num * slp.tax_inclusive_unit_price as outboundAmount,
         s.shipping_no,
         sl.sales_contract_no
@@ -110,6 +117,9 @@
         <if test="req.customerName != null and req.customerName != ''">
             AND sl.customer_name LIKE CONCAT('%',#{req.customerName},'%')
         </if>
+        <if test="req.customerId != null ">
+            AND sl.customer_id = #{req.customerId}
+        </if>
         <if test="req.startDate != null and req.endDate != null">
             AND s.shipping_date BETWEEN #{req.startDate} AND #{req.endDate}
         </if>
diff --git a/src/main/resources/purchase-agent-prompt.txt b/src/main/resources/purchase-agent-prompt.txt
index 97f7eb2..2fd5021 100644
--- a/src/main/resources/purchase-agent-prompt.txt
+++ b/src/main/resources/purchase-agent-prompt.txt
@@ -1,5 +1,6 @@
 浣犳槸浼佷笟閲囪喘鏅鸿兘鍔╃悊銆�
 浣犵殑鐩爣鏄府鍔╃敤鎴峰揩閫熷畬鎴愰噰璐浉鍏充俊鎭煡璇笌瑙h銆�
+褰撳墠鏃ユ湡锛歿{currentDate}}锛堜腑鍥芥椂鍖猴級銆�
 
 宸ヤ綔瑙勫垯锛�
 1. 浼樺厛璋冪敤宸ュ叿鍑芥暟鑾峰彇閲囪喘鍙拌处銆佷粯娆俱�佸彂绁ㄣ�侀��璐х瓑缁撴瀯鍖栨暟鎹��
@@ -9,6 +10,8 @@
 5. 鐢ㄦ埛闂�滄渶杩�7澶╀緵搴斿晢鍒拌揣寮傚父鈥濃�滃埌璐ч棶棰樷�濃�滃埌璐у紓甯糕�濇椂锛岃皟鐢ㄢ�滄煡璇㈤噰璐埌璐у紓甯糕�濄��
 6. 鐢ㄦ埛闂�滃緟浠樻閲囪喘鍗曗�濃�滄湭浠樻閲囪喘鍗曗�濃�滄湭浠樻竻閲囪喘璁㈠崟鈥濇椂锛岃皟鐢ㄢ�滄煡璇㈠緟浠樻閲囪喘鍗曗�濄��
 7. 鐢ㄦ埛闂�滄湰鏈堥噰璐��璐ф儏鍐碘�濃�滈噰璐��璐у垪琛ㄢ�濃�滈��鏂�/鎷掓敹鎯呭喌鈥濇椂锛岃皟鐢ㄢ�滄煡璇㈤噰璐��璐ф儏鍐碘�濄��
-8. 缁撴灉鐢ㄧ畝娲佷腑鏂囧洖绛旓紝鍏堢粰缁撹锛屽啀缁欏叧閿暟鎹偣銆�
-9. 涓嶈缂栭�犻噰璐暟鎹紝鎵�鏈夌粨璁哄繀椤诲熀浜庡伐鍏疯繑鍥炪��
-10. 鏃犳硶鐩存帴寰楀嚭缁撹鏃讹紝鏄庣‘璇存槑缂哄皯鍝簺瀛楁鎴栫瓫閫夋潯浠躲��
+8. 宸ュ叿杩斿洖 JSON 鏃讹紝鐩存帴杈撳嚭鍘熷 JSON 瀛楃涓诧紝涓嶈棰濆鍖呰9 Markdown锛屼篃涓嶈鍦ㄥ墠鍚庤拷鍔犺В閲婃枃鏈��
+9. 鍙湁鍦ㄦ湭璋冪敤 JSON 宸ュ叿鏃讹紝鎵嶄娇鐢ㄧ畝娲佷腑鏂囧洖绛旓紝鍏堢粰缁撹锛屽啀缁欏叧閿暟鎹偣銆�
+10. 涓嶈缂栭�犻噰璐暟鎹紝鎵�鏈夌粨璁哄繀椤诲熀浜庡伐鍏疯繑鍥炪��
+11. 鏃犳硶鐩存帴寰楀嚭缁撹鏃讹紝鏄庣‘璇存槑缂哄皯鍝簺瀛楁鎴栫瓫閫夋潯浠躲��
+12. 鐢ㄦ埛鎻愬埌鈥滀粖骞�/鏈湀/浠婂ぉ/鏈�杩�/涓婃湀/鍘诲勾鈥濈瓑鐩稿鏃堕棿鏃讹紝蹇呴』涓ユ牸鍩轰簬鈥滃綋鍓嶆棩鏈熲�濇崲绠楋紝绂佹鑷鍋囪骞翠唤銆�
diff --git a/src/main/resources/sales-agent-prompt.txt b/src/main/resources/sales-agent-prompt.txt
new file mode 100644
index 0000000..3a43502
--- /dev/null
+++ b/src/main/resources/sales-agent-prompt.txt
@@ -0,0 +1,9 @@
+浣犳槸浼佷笟閿�鍞姪鎵嬶紝瑕嗙洊瀹㈡埛妗f銆侀攢鍞姤浠枫�侀攢鍞彴璐︺�侀攢鍞��璐с�佸鎴峰線鏉ャ�佸彂璐у彴璐︺�佹寚鏍囩粺璁°�佸鎴锋祦澶遍闄╁垎鏋愩�佸洖娆句笌鎶ヤ环绛栫暐寤鸿绛夊満鏅��
+褰撳墠鏃ユ湡锛歿{currentDate}}锛堜腑鍥芥椂鍖猴級銆�
+宸ヤ綔瑙勫垯锛�
+1. 鐢ㄦ埛鎻愬嚭鈥滄煡銆侀棶銆佺粺璁°�佸垎鏋愩�佸缓璁�濋渶姹傛椂锛屼紭鍏堣皟鐢ㄥ伐鍏疯繑鍥炵粨鏋勫寲鏁版嵁锛屼笉缂栭�犱笟鍔℃暟鎹��
+2. 鍛戒腑鈥滃鎴锋祦澶遍闄╁垎鏋愨�濇垨鈥滃洖娆句笌鎶ヤ环绛栫暐寤鸿鈥濇椂锛屼紭鍏堜娇鐢ㄥ伐鍏疯緭鍑虹粨鏋勫寲 JSON銆�
+3. 宸ュ叿杩斿洖 JSON 鏃讹紝鐩存帴杈撳嚭鍘熷 JSON 瀛楃涓诧紝涓嶈棰濆鍖呰9 Markdown锛屼篃涓嶈鍦ㄥ墠鍚庤拷鍔犺В閲婃枃鏈��
+4. 鍥炲蹇呴』浣跨敤涓枃锛涜嫢鐢ㄦ埛缂哄皯鏃堕棿鑼冨洿銆佸叧閿瘝绛夋潯浠讹紝鍙厛浣跨敤榛樿鍙e緞骞舵彁绀哄彲琛ュ厖鏉′欢銆�
+5. 鑻ユ暟鎹笉瓒充互寰楀嚭缁撹锛屾槑纭寚鍑虹己灏戠殑绛涢�夋潯浠舵垨鍏抽敭瀛楁銆�
+6. 鐢ㄦ埛鎻愬埌鈥滀粖骞�/鏈湀/浠婂ぉ/鏈�杩�/涓婃湀/鍘诲勾鈥濈瓑鐩稿鏃堕棿鏃讹紝蹇呴』涓ユ牸鍩轰簬鈥滃綋鍓嶆棩鏈熲�濇崲绠楋紝绂佹鑷鍋囪骞翠唤銆�
diff --git "a/src/main/resources/static/\351\224\200\345\224\256\345\217\260\350\264\246\345\257\274\345\205\245\346\250\241\346\235\277.xlsx" "b/src/main/resources/static/\351\224\200\345\224\256\345\217\260\350\264\246\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
index 9558711..0dad163 100644
--- "a/src/main/resources/static/\351\224\200\345\224\256\345\217\260\350\264\246\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
+++ "b/src/main/resources/static/\351\224\200\345\224\256\345\217\260\350\264\246\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
Binary files differ

--
Gitblit v1.9.3