5 天以前 0d7d874912d0147376826b55667a1deb6547ed91
Merge branch 'dev_New_pro' into dev_宁夏_英泽防锈
已添加12个文件
已重命名23个文件
已修改208个文件
13624 ■■■■■ 文件已修改
doc/20260518_销售助手前端联调文档.md 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/20260520_首页生产看板前端联调文档.md 160 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/20260520_首页生产看板性能优化前端变更文档.md 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/20260521_采购智能体优化前端变更文档.md 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/20260521_首页HomeController接口升级前端变更文档.md 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/bean/dto/financial/AccountSubjectDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/bean/dto/financial/AccountSubjectImportDto.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/bean/dto/purchase/PurchaseInboundDto.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/bean/dto/purchase/PurchaseReturnDto.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/bean/dto/sales/SalesOutboundDto.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/bean/dto/sales/SalesReturnDto.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/bean/vo/financial/AccountSubjectVo.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/bean/vo/purchase/PurchaseInboundVo.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/bean/vo/purchase/PurchaseReturnVo.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/bean/vo/sales/SalesOutboundVo.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/bean/vo/sales/SalesReturnVo.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/controller/AccountExpenseController.java 43 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/controller/AccountFileController.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/controller/AccountIncomeController.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/controller/AccountingController.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/controller/BorrowInfoController.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/controller/financial/AccountSubjectController.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/controller/purchase/AccounPurchaseController.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/controller/sales/AccountSalesController.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/mapper/financial/AccountSubjectMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/pojo/financial/AccountSubject.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/BorrowInfoService.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/financial/AccountPurchaseService.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/impl/BorrowInfoServiceImpl.java 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/impl/financial/AccountSubjectServiceImpl.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/impl/financial/FinVoucherServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchaseServiceImpl.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesServiceImpl.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/purchase/AccountSubjectService.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/sales/AccountSalesService.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/aftersalesservice/controller/AfterSalesNearExpiryController.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/aftersalesservice/controller/AfterSalesServiceController.java 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/aftersalesservice/controller/AfterSalesServiceFileController.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/assistant/ApproveTodoIntentExecutor.java 199 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/assistant/PurchaseIntentExecutor.java 249 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/assistant/SalesAgent.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/assistant/SalesIntentExecutor.java 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/config/SalesAgentConfig.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/controller/PurchaseAiController.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/controller/SalesAiController.java 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/controller/XiaozhiController.java 65 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/service/PurchaseAiService.java 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/tools/ApproveTodoTools.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java 1475 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/ApproveNodeController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/ApproveProcessController.java 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/HolidaySettingsController.java 77 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/KnowledgeBaseController.java 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/NotificationManagementController.java 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/RpaProcessAutomationController.java 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/CustomerFollowUpController.java 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/ProductController.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/SupplierManageController.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/SupplierManageFileController.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/excel/SupplierManageExcelDto.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/SupplierManage.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/IProductModelService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/ISupplierService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/collaborativeApproval/controller/DutyPlanController.java 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/collaborativeApproval/controller/NoticeController.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/collaborativeApproval/controller/NoticeTypeController.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/collaborativeApproval/controller/RulesRegulationsManagementController.java 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/collaborativeApproval/controller/RulesRegulationsManagementFileController.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/collaborativeApproval/controller/SealApplicationManagementController.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/collaborativeApproval/controller/StaffContactsPersonalController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/compensationperformance/controller/CompensationPerformanceController.java 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/customervisits/controller/CustomerVisitsController.java 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/customervisits/service/CustomerVisitsService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/controller/DeviceDefectRecordController.java 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/controller/DeviceLedgerController.java 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/controller/DeviceMaintenanceController.java 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/controller/DeviceMaintenanceFileController.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/controller/DeviceRepairController.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/IDeviceLedgerService.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/IDeviceMaintenanceService.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/IDeviceRepairService.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/impl/DeviceLedgerServiceImpl.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/impl/DeviceMaintenanceServiceImpl.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/impl/DeviceRepairServiceImpl.java 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/equipmentenergyconsumption/controller/ElectricityConsumptionAreaController.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/equipmentenergyconsumption/controller/EnergyPeriodController.java 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/equipmentenergyconsumption/controller/EquipmentEnergyConsumptionController.java 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/equipmentenergyconsumption/service/EquipmentEnergyConsumptionService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/equipmentenergyconsumption/service/impl/EquipmentEnergyConsumptionServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/framework/web/controller/BaseController.java 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/controller/HomeController.java 585 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/lavorissue/controller/LavorIssueController.java 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/measuringinstrumentledger/controller/MeasuringInstrumentLedgerController.java 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/measuringinstrumentledger/controller/MeasuringInstrumentLedgerRecordController.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/measuringinstrumentledger/controller/SparePartsController.java 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/measuringinstrumentledger/controller/SparePartsRequisitionRecordController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/officesupplies/controller/OfficeSuppliesController.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/officesupplies/service/OfficeSuppliesService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/officesupplies/service/impl/OfficeSuppliesServiceImpl.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/GasTankWarningController.java 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/InboundManagementController.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementExceptionRecordController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementPlanController.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementPriceManagementController.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java 76 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordOutController.java 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/ReturnManagementController.java 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/mapper/ReturnManagementMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java 82 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/common/CaptchaController.java 198 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/monitor/controller/CacheController.java 223 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/monitor/controller/ServerController.java 55 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/monitor/controller/SysJobController.java 374 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/monitor/controller/SysJobLogController.java 186 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java 141 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/monitor/controller/SysOperlogController.java 140 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java 165 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysConfigController.java 256 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysDeptController.java 271 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java 241 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java 265 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysLoginController.java 311 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysMenuController.java 276 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java 195 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysPostController.java 268 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysProfileController.java 268 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysRegisterController.java 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysRoleController.java 520 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysUserClientController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysUserController.java 577 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java 508 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/controller/InfoController.java 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/controller/PlanController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/controller/RolesController.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/InvoicePurchaseController.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/PaymentRegistrationController.java 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/ProcurementBusinessSummaryController.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java 43 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerTemplateController.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/PurchaseReturnOrdersController.java 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/TicketRegistrationController.java 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/mapper/PurchaseReturnOrdersMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/IProductRecordService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityInspectController.java 47 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityInspectFileController.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityReportController.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/CommonFileController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/InvoiceLedgerController.java 71 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/InvoiceRegistrationController.java 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/PaymentShippingController.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/ReceiptPaymentController.java 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalesQuotationController.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalespersonManagementController.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesLedgerImportDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesLedgerProductImportDto.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/AnalyticsController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/BankController.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/HolidayApplicationController.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/PersonalAttendanceRecordsController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/SchemeApplicableStaffController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/StaffContractController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/StaffLeaveController.java 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/StaffSalaryMainController.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/StaffSchedulingController.java 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/SchemeApplicableStaffService.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/StaffSalaryMainService.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/impl/SchemeApplicableStaffServiceImpl.java 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/impl/StaffSalaryMainServiceImpl.java 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/controller/StockInRecordController.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/controller/StockOutRecordController.java 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/technology/controller/TechnologyOperationParamController.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/warehouse/controller/DocumentClassificationController.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/warehouse/controller/DocumentationBorrowManagementController.java 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/warehouse/controller/DocumentationController.java 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/warehouse/controller/DocumentationFileController.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/warehouse/controller/WarehouseController.java 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/warehouse/controller/WarehouseGoodsShelvesController.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/warehouse/controller/WarehouseGoodsShelvesRowcolController.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/waterrecord/controller/WaterRecordController.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/waterrecord/service/WaterRecordService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/waterrecord/service/impl/WaterRecordServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-dev.yml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/approve-todo-agent-prompt.txt 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/manufacturing-agent-prompt.txt 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/account/financial/AccountSubjectMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/CustomerMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/procurementrecord/ReturnManagementMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionOperationTaskMapper.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionOrderMapper.xml 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/purchase/PurchaseReturnOrdersMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockInRecordMapper.xml 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockInventoryMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockOutRecordMapper.xml 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/purchase-agent-prompt.txt 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/sales-agent-prompt.txt 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/static/销售台账导入模板.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
doc/20260518_ÏúÊÛÖúÊÖǰ¶ËÁªµ÷Îĵµ.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,188 @@
# é”€å”®åŠ©æ‰‹å‰ç«¯è”è°ƒæ–‡æ¡£ï¼ˆ`/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`(SSE æ–‡æœ¬æµï¼‰ã€‚
- å‘½ä¸­å·¥å…·æ—¶ï¼Œæœ€ç»ˆå†…容为 **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` | å®¢æˆ·æ¡£æ¡ˆï¼ˆç§æµ·/公海) |
| `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. å®¢æˆ·æ¡£æ¡ˆï¼ˆç§æµ·ï¼‰ï¼šç¤ºä¾‹æé—® `查询私海客户档案前10条`
2. å®¢æˆ·æ¡£æ¡ˆï¼ˆå…¬æµ·ï¼‰ï¼šç¤ºä¾‹æé—® `查询公海客户档案`
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 è§£æžå¤±è´¥æ—¶é¡µé¢ç©ºç™½ã€‚
4. ä¸šåŠ¡å±•ç¤ºå­—æ®µå»ºè®®ä¸­æ–‡åŒ–ï¼Œä¸ç›´æŽ¥å±•ç¤ºè‹±æ–‡å­—æ®µ key。
## 9. è”调验收清单
1. èƒ½æ­£å¸¸æµå¼æŽ¥æ”¶ `/sales-ai/chat` å“åº”并拼接文本。
2. èƒ½æŒ‰ `type` æ­£ç¡®æ¸²æŸ“ 9 ç±»ç»“构化结果。
3. èƒ½æ­£ç¡®å±•示“客户流失风险分析”和“回款与报价策略建议”两个重点场景。
4. ä¼šè¯åˆ—表、会话消息、删除会话全链路可用。
5. `memoryId` å¤ç”¨åŽå¯å›žçœ‹åŽ†å²ï¼Œä¸ä¼šä¸²ä¼šè¯ã€‚
doc/20260520_Ê×Ò³Éú²ú¿´°åǰ¶ËÁªµ÷Îĵµ.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`:今日生产计划
所有接口统一返回 `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`:较昨日变化值(可正可负;前端按正负决定箭头方向和颜色)
## 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": "结构件A",
      "plannedQuantity": 1200.00,
      "dueDate": "2026-05-15",
      "status": 2,
      "statusLabel": "进行中"
    }
  ]
}
```
## 6. å‰ç«¯å±•示约定
- ç™¾åˆ†æ¯”字段统一是数值(如 `74.00`),前端自行拼接 `%`。
- æ‰€æœ‰æ•°å€¼ä¿ç•™ä¸¤ä½å°æ•°ã€‚
- `dueDate` å¯èƒ½ä¸º `null`,前端需兜底展示(如 `--`)。
- `compareYesterday` æ­£è´Ÿéƒ½å¯èƒ½å‡ºçŽ°ï¼Œå»ºè®®æŒ‰ `>0` ä¸Šå‡ã€`<0` ä¸‹é™ã€`=0` æŒå¹³å¤„理。
doc/20260520_Ê×Ò³Éú²ú¿´°åÐÔÄÜÓÅ»¯Ç°¶Ë±ä¸üÎĵµ.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,107 @@
# é¦–页生产看板性能优化前端变更文档
更新时间:2026-05-20
适用页面:首页
涉及区块:
1. ç”Ÿäº§è®¢å•进度
2. ä»Šæ—¥ç”Ÿäº§è®¡åˆ’
## 1. æœ¬æ¬¡ä¼˜åŒ–目标
针对大数据量场景(订单数量多、生产历史长)优化查询性能,降低首页接口响应时间和内存占用。
## 2. æ¶‰åŠæŽ¥å£
1. `GET /home/productionOrderProgress`
2. `GET /home/todayProductionPlan`
## 3. å‰ç«¯æ˜¯å¦éœ€è¦æ”¹ä»£ç 
结论:**无强制改动,接口入参与返回结构保持兼容**。
你现有页面可以直接联调,不需要改字段映射。
## 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": "结构件A",
      "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. ç™¾åˆ†æ¯”字段仍为数值,前端继续追加 `%` å±•示。
doc/20260521_²É¹ºÖÇÄÜÌåÓÅ»¯Ç°¶Ë±ä¸üÎĵµ.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,85 @@
# é‡‡è´­æ™ºèƒ½ä½“优化前端变更文档
## 1. å˜æ›´èƒŒæ™¯
本次针对采购智能体做了对齐优化(参考销售/审批/制造智能体):
1. æå‡ `quickPrompts` å‘½ä¸­ç¨³å®šæ€§ã€‚
2. å¢žå¼ºç›¸å¯¹æ—¶é—´è¯†åˆ«ï¼ˆä»Šå¤©/昨天/本周/上周/本月/上月/今年/去年/近N天等)。
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. æ—¶é—´å£å¾„优化
采购智能体现在统一按中国时区动态日期换算相对时间,支持:
- ä»Šå¤©ã€æ˜¨å¤©
- æœ¬å‘¨ã€ä¸Šå‘¨
- æœ¬æœˆã€ä¸Šæœˆ
- ä»Šå¹´ã€å޻年
- è¿‘N天/周/月/年、近半年、近半个月
前端无需改传参,但展示时间范围时请以后端返回 `summary.startDate/endDate/timeRange` ä¸ºå‡†ã€‚
## 6. å‰ç«¯è”调检查清单
1. `chat` æµå¼ç»“果拼接后,优先按 JSON è§£æžã€‚
2. è¦†ç›–新类型 `purchase_intent_not_recognized` çš„ UI å¤„理。
3. å¾…付款页面读取并展示 `summary.totalPendingAmount` ç­‰æ–°å¢žå­—段。
4. éªŒè¯ä»¥ä¸‹å¿«æ·é—®é¢˜å¯ç¨³å®šè¿”回结构化结果:
   - æœ¬æœˆé‡‡è´­é‡‘额排名前十的物料有哪些?
   - å“ªäº›é‡‡è´­è®¢å•还未入库?
   - æœ€è¿‘7天供应商到货异常有哪些?
   - å¸®æˆ‘统计待付款采购单!
   - åˆ—出本月采购退货情况
doc/20260521_Ê×Ò³HomeController½Ó¿ÚÉý¼¶Ç°¶Ë±ä¸üÎĵµ.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` è§£æžï¼›
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. è€é¡µé¢å¯ä¸æ”¹ï¼Œç»§ç»­æ²¿ç”¨åŽŸå‚æ•°ä¹Ÿèƒ½æ­£å¸¸è”è°ƒã€‚
src/main/java/com/ruoyi/account/bean/dto/financial/AccountSubjectDto.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/bean/dto/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;
src/main/java/com/ruoyi/account/bean/dto/financial/AccountSubjectImportDto.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/bean/dto/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;
src/main/java/com/ruoyi/account/bean/dto/purchase/PurchaseInboundDto.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/bean/dto/PurchaseInboundDto.java ÐÞ¸Ä
@@ -1,4 +1,4 @@
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;
src/main/java/com/ruoyi/account/bean/dto/purchase/PurchaseReturnDto.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/bean/dto/PurchaseReturnDto.java ÐÞ¸Ä
@@ -1,4 +1,4 @@
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;
src/main/java/com/ruoyi/account/bean/dto/sales/SalesOutboundDto.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/bean/dto/SalesOutboundDto.java ÐÞ¸Ä
@@ -1,4 +1,4 @@
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;
src/main/java/com/ruoyi/account/bean/dto/sales/SalesReturnDto.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/bean/dto/SalesReturnDto.java ÐÞ¸Ä
@@ -1,4 +1,4 @@
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;
src/main/java/com/ruoyi/account/bean/vo/financial/AccountSubjectVo.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/bean/vo/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;
src/main/java/com/ruoyi/account/bean/vo/purchase/PurchaseInboundVo.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/bean/vo/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;
src/main/java/com/ruoyi/account/bean/vo/purchase/PurchaseReturnVo.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/bean/vo/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;
src/main/java/com/ruoyi/account/bean/vo/sales/SalesOutboundVo.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/bean/vo/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;
src/main/java/com/ruoyi/account/bean/vo/sales/SalesReturnVo.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/bean/vo/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;
src/main/java/com/ruoyi/account/controller/AccountExpenseController.java
@@ -8,7 +8,8 @@
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 com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.Resource;
@@ -25,7 +26,7 @@
@RestController
@RequestMapping("/account/accountExpense")
@Tag(name = "财务管理--支出管理")
public class AccountExpenseController {
public class AccountExpenseController extends BaseController {
    @Resource
    private AccountExpenseService accountExpenseService;
@@ -41,11 +42,11 @@
     */
    @PostMapping("/add")
    @Operation(summary = "新增")
    public AjaxResult add(@RequestBody AccountExpense accountExpense) {
    public R<?> add(@RequestBody AccountExpense accountExpense) {
        accountExpense.setInputTime(new Date());
        LoginUser loginUser = SecurityUtils.getLoginUser();
        accountExpense.setInputUser(loginUser.getNickName());
        return AjaxResult.success(accountExpenseService.save(accountExpense));
        return R.ok(accountExpenseService.save(accountExpense));
    }
    /**
@@ -55,12 +56,12 @@
     */
    @DeleteMapping("/del")
    @Operation(summary = "删除")
    public AjaxResult delQualityInspect(@RequestBody List<Integer> ids) {
    public R<?> delQualityInspect(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        //删除检验单
        return AjaxResult.success(accountExpenseService.removeBatchByIds(ids));
        return R.ok(accountExpenseService.removeBatchByIds(ids));
    }
    /**
@@ -70,8 +71,8 @@
     */
    @PostMapping("/update")
    @Operation(summary = "修改")
    public AjaxResult update(@RequestBody AccountExpense accountExpense) {
        return AjaxResult.success(accountExpenseService.updateById(accountExpense));
    public R<?> update(@RequestBody AccountExpense accountExpense) {
        return R.ok(accountExpenseService.updateById(accountExpense));
    }
    /**
@@ -82,8 +83,8 @@
     */
    @GetMapping("/listPage")
    @Operation(summary = "分页查询")
    public AjaxResult accountExpenseListPage(Page page, AccountExpense accountExpense) {
        return AjaxResult.success(accountExpenseService.accountExpenseListPage(page, accountExpense));
    public R<?> accountExpenseListPage(Page page, AccountExpense accountExpense) {
        return R.ok(accountExpenseService.accountExpenseListPage(page, accountExpense));
    }
    /**
@@ -93,8 +94,8 @@
     */
    @GetMapping("/{id}")
    @Operation(summary = "详情")
    public AjaxResult accountExpenseDetail(@PathVariable("id") Integer id) {
        return AjaxResult.success(accountExpenseService.getById(id));
    public R<?> accountExpenseDetail(@PathVariable("id") Integer id) {
        return R.ok(accountExpenseService.getById(id));
    }
    /**
@@ -115,8 +116,8 @@
     */
    @GetMapping("/report/forms")
    @Operation(summary = "财务报表图表查询")
    public AjaxResult report(DateQueryDto dateQueryDto) {
        return AjaxResult.success(accountExpenseService.report(dateQueryDto));
    public R<?> report(DateQueryDto dateQueryDto) {
        return R.ok(accountExpenseService.report(dateQueryDto));
    }
    /**
@@ -125,8 +126,8 @@
     */
    @GetMapping("/report/analysis")
    @Operation(summary = "财务报表-财务分析")
    public AjaxResult analysis() {
        return AjaxResult.success(accountExpenseService.analysis());
    public R<?> analysis() {
        return R.ok(accountExpenseService.analysis());
    }
    /**
@@ -136,8 +137,8 @@
     */
    @GetMapping("/report/income")
    @Operation(summary = "财务报表图表收入年度查询")
    public AjaxResult reportIncome(ReportDateDto reportDateDto) {
        return AjaxResult.success(accountIncomeService.reportIncome(reportDateDto));
    public R<?> reportIncome(ReportDateDto reportDateDto) {
        return R.ok(accountIncomeService.reportIncome(reportDateDto));
    }
    /**
@@ -147,8 +148,8 @@
     */
    @GetMapping("/report/expense")
    @Operation(summary = "财务报表图表支出年度查询")
    public AjaxResult reportExpense(ReportDateDto reportDateDto) {
        return AjaxResult.success(accountExpenseService.reportExpense(reportDateDto));
    public R<?> reportExpense(ReportDateDto reportDateDto) {
        return R.ok(accountExpenseService.reportExpense(reportDateDto));
    }
src/main/java/com/ruoyi/account/controller/AccountFileController.java
@@ -3,9 +3,8 @@
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 com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.util.CollectionUtils;
@@ -20,7 +19,7 @@
@RestController
@RequestMapping("/account/accountFile")
@Tag(name = "财务附件")
public class AccountFileController {
public class AccountFileController extends BaseController {
    @Resource
@@ -34,8 +33,8 @@
     */
    @PostMapping("/add")
    @Operation(summary = "新增")
    public AjaxResult add(@RequestBody AccountFile accountFile) {
        return AjaxResult.success(accountFileService.save(accountFile));
    public R<?> add(@RequestBody AccountFile accountFile) {
        return R.ok(accountFileService.save(accountFile));
    }
    /**
@@ -45,12 +44,12 @@
     */
    @DeleteMapping("/del")
    @Operation(summary = "删除")
    public AjaxResult delAccountFile(@RequestBody List<Integer> ids) {
    public R<?> delAccountFile(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        //删除检验附件
        return AjaxResult.success(accountFileService.removeBatchByIds(ids));
        return R.ok(accountFileService.removeBatchByIds(ids));
    }
    /**
@@ -61,8 +60,8 @@
     */
    @GetMapping("/listPage")
    @Operation(summary = "分页查询")
    public AjaxResult accountFileListPage(Page page, AccountFile accountFile) {
        return AjaxResult.success(accountFileService.accountFileListPage(page, accountFile));
    public R<?> accountFileListPage(Page page, AccountFile accountFile) {
        return R.ok(accountFileService.accountFileListPage(page, accountFile));
    }
src/main/java/com/ruoyi/account/controller/AccountIncomeController.java
@@ -1,19 +1,12 @@
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 com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.util.CollectionUtils;
@@ -30,7 +23,7 @@
@RestController
@RequestMapping("/account/accountIncome")
@Tag(name = "财务管理--收入管理")
public class AccountIncomeController {
public class AccountIncomeController extends BaseController {
    @Resource
    private AccountIncomeService accountIncomeService;
@@ -43,11 +36,11 @@
     */
    @PostMapping("/add")
    @Operation(summary = "新增")
    public AjaxResult add(@RequestBody AccountIncome accountIncome) {
    public R<?> add(@RequestBody AccountIncome accountIncome) {
        accountIncome.setInputTime(new Date());
        LoginUser loginUser = SecurityUtils.getLoginUser();
        accountIncome.setInputUser(loginUser.getNickName());
        return AjaxResult.success(accountIncomeService.save(accountIncome));
        return R.ok(accountIncomeService.save(accountIncome));
    }
    /**
@@ -57,12 +50,12 @@
     */
    @DeleteMapping("/del")
    @Operation(summary = "删除")
    public AjaxResult delQualityInspect(@RequestBody List<Integer> ids) {
    public R<?> delQualityInspect(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        //删除检验单
        return AjaxResult.success(accountIncomeService.removeBatchByIds(ids));
        return R.ok(accountIncomeService.removeBatchByIds(ids));
    }
    /**
@@ -72,8 +65,8 @@
     */
    @PostMapping("/update")
    @Operation(summary = "修改")
    public AjaxResult update(@RequestBody AccountIncome accountIncome) {
        return AjaxResult.success(accountIncomeService.updateById(accountIncome));
    public R<?> update(@RequestBody AccountIncome accountIncome) {
        return R.ok(accountIncomeService.updateById(accountIncome));
    }
    /**
@@ -84,8 +77,8 @@
     */
    @GetMapping("/listPage")
    @Operation(summary = "分页查询")
    public AjaxResult accountIncomeListPage(Page page, AccountIncome accountIncome) {
        return AjaxResult.success(accountIncomeService.accountIncomeListPage(page, accountIncome));
    public R<?> accountIncomeListPage(Page page, AccountIncome accountIncome) {
        return R.ok(accountIncomeService.accountIncomeListPage(page, accountIncome));
    }
    /**
@@ -95,8 +88,8 @@
     */
    @GetMapping("/{id}")
    @Operation(summary = "详情")
    public AjaxResult accountIncomeDetail(@PathVariable("id") Integer id) {
        return AjaxResult.success(accountIncomeService.getById(id));
    public R<?> accountIncomeDetail(@PathVariable("id") Integer id) {
        return R.ok(accountIncomeService.getById(id));
    }
    /**
src/main/java/com/ruoyi/account/controller/AccountingController.java
@@ -3,7 +3,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.account.service.impl.AccountingServiceImpl;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
@@ -27,19 +27,19 @@
    @Operation(summary = "总计")
    @GetMapping("/total")
    public AjaxResult total(@RequestParam Integer year) {
    public R<?> total(@RequestParam Integer year) {
        return accountingService.total(year);
    }
    @Operation(summary = "设备类型分布")
    @GetMapping("/deviceTypeDistribution")
    public AjaxResult deviceTypeDistribution(@RequestParam Integer year) {
    public R<?> deviceTypeDistribution(@RequestParam Integer year) {
        return accountingService.deviceTypeDistribution(year);
    }
    @Operation(summary = "设备分页查询计算折旧")
    @GetMapping("/calculateDepreciation")
    public AjaxResult calculateDepreciation(Page page, @RequestParam Integer year) {
    public R<?> calculateDepreciation(Page page, @RequestParam Integer year) {
        return accountingService.calculateDepreciation(page,year);
    }
src/main/java/com/ruoyi/account/controller/BorrowInfoController.java
@@ -6,11 +6,11 @@
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 com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
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.*;
@@ -29,13 +29,13 @@
@RestController
@RequestMapping("/borrowInfo")
@AllArgsConstructor
public class BorrowInfoController {
public class BorrowInfoController extends BaseController {
    private BorrowInfoService borrowInfoService;
    @GetMapping("/listPage")
    @Operation(summary = "分页查询")
    public AjaxResult listPage(Page page, BorrowInfo borrowInfo) {
    public R<?> listPage(Page page, BorrowInfo borrowInfo) {
        return borrowInfoService.listPage(page,borrowInfo);
    }
@@ -45,7 +45,7 @@
    @PostMapping("/add")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "新增借款信息", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody BorrowInfo borrowInfo) {
    public R<?> add(@RequestBody BorrowInfo borrowInfo) {
        return borrowInfoService.add(borrowInfo);
    }
@@ -55,7 +55,7 @@
    @PostMapping("/update")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "修改借款信息", businessType = BusinessType.UPDATE)
    public AjaxResult updateBorrowInfo(@RequestBody BorrowInfo borrowInfo) {
    public R<?> updateBorrowInfo(@RequestBody BorrowInfo borrowInfo) {
        return borrowInfoService.updateBorrowInfo(borrowInfo);
    }
@@ -66,7 +66,7 @@
    @DeleteMapping("/delete")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "删除借款信息", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
    public R<?> delete(@RequestBody List<Long> ids) {
        return borrowInfoService.delete(ids);
    }
src/main/java/com/ruoyi/account/controller/financial/AccountSubjectController.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/controller/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;
src/main/java/com/ruoyi/account/controller/purchase/AccounPurchaseController.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/controller/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;
src/main/java/com/ruoyi/account/controller/sales/AccountSalesController.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/controller/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;
src/main/java/com/ruoyi/account/mapper/financial/AccountSubjectMapper.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/mapper/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;
src/main/java/com/ruoyi/account/pojo/financial/AccountSubject.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/pojo/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;
src/main/java/com/ruoyi/account/service/BorrowInfoService.java
@@ -3,7 +3,7 @@
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 com.ruoyi.framework.web.domain.R;
import java.util.List;
@@ -17,11 +17,11 @@
 */
public interface BorrowInfoService extends IService<BorrowInfo> {
    AjaxResult listPage(Page page, BorrowInfo borrowInfo);
    R<?> listPage(Page page, BorrowInfo borrowInfo);
    AjaxResult add(BorrowInfo borrowInfo);
    R<?> add(BorrowInfo borrowInfo);
    AjaxResult updateBorrowInfo(BorrowInfo borrowInfo);
    R<?> updateBorrowInfo(BorrowInfo borrowInfo);
    AjaxResult delete(List<Long> ids);
    R<?> delete(List<Long> ids);
}
src/main/java/com/ruoyi/account/service/financial/AccountPurchaseService.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/service/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;
/**
src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java
@@ -10,7 +10,7 @@
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;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.mapper.CustomStorageMapper;
import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper;
@@ -43,7 +43,7 @@
    private final ProcurementRecordMapper procurementRecordMapper;
    private final ProcurementRecordOutMapper procurementRecordOutMapper;
    public AjaxResult total(Integer year) {
    public R<?> total(Integer year) {
        Map<String,Object> map = new HashMap<>();
        map.put("deprAmount",0); // æŠ˜æ—§é‡‘额
        map.put("deviceTotal",0); // è®¾å¤‡æ€»æ•°
@@ -150,7 +150,7 @@
            });
        }
        map.put("inventoryValue",procurementRecordTotal.add(customStorageTotal));
        return AjaxResult.success( map);
        return R.ok(map);
    }
    /**
@@ -245,7 +245,7 @@
        return totalDepreciation.setScale(2, BigDecimal.ROUND_HALF_UP);
    }
    public AjaxResult deviceTypeDistribution(Integer year) {
    public R<?> deviceTypeDistribution(Integer year) {
        // 2. ç»„装返回VO
       DeviceTypeDistributionVO vo = new DeviceTypeDistributionVO();
       List<DeviceTypeDetail> details = deviceLedgerMapper.getDeviceTypeDistributionByYear( year);
@@ -265,10 +265,10 @@
                   .collect(Collectors.toList()));
           vo.setTotalCount(vo.getCategories().size());
       }
        return AjaxResult.success(vo);
        return R.ok(vo);
    }
    public AjaxResult calculateDepreciation(Page page, Integer year) {
    public R<?> calculateDepreciation(Page page, Integer year) {
        LambdaQueryWrapper<DeviceLedger> deviceLedgerLambdaQueryWrapper = new LambdaQueryWrapper<>();
        deviceLedgerLambdaQueryWrapper.like(DeviceLedger::getCreateTime,year)
                .eq(DeviceLedger::getIsDepr,1);
@@ -277,6 +277,6 @@
            record.setDeprAmount(calculatePreciseDepreciation(record));
            record.setNetValue(record.getTaxIncludingPriceTotal().subtract(record.getDeprAmount()));
        }
        return AjaxResult.success(deviceLedgerIPage);
        return R.ok(deviceLedgerIPage);
    }
}
src/main/java/com/ruoyi/account/service/impl/BorrowInfoServiceImpl.java
@@ -12,7 +12,7 @@
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 com.ruoyi.framework.web.domain.R;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -37,7 +37,7 @@
    private final AccountExpenseService accountExpenseService;
    @Override
    public AjaxResult listPage(Page page, BorrowInfo borrowInfo) {
    public R<?> listPage(Page page, BorrowInfo borrowInfo) {
        LambdaQueryWrapper<BorrowInfo> borrowInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(borrowInfo != null){
            if(StringUtils.isNotEmpty(borrowInfo.getEntryDateStart()) && StringUtils.isNotEmpty(borrowInfo.getEntryDateEnd())){
@@ -51,11 +51,11 @@
                borrowInfoLambdaQueryWrapper.like(BorrowInfo::getBorrowerName, borrowInfo.getBorrowerName());
            }
        }
        return AjaxResult.success(borrowInfoMapper.selectPage(page, borrowInfoLambdaQueryWrapper));
        return R.ok(borrowInfoMapper.selectPage(page, borrowInfoLambdaQueryWrapper));
    }
    @Override
    public AjaxResult add(BorrowInfo borrowInfo) {
    public R<?> add(BorrowInfo borrowInfo) {
        int insert = borrowInfoMapper.insert(borrowInfo);
        if(insert > 0){
            // æ·»åŠ æˆåŠŸï¼Œè¿›å…¥æ”¶å…¥ç®¡ç†
@@ -70,13 +70,13 @@
            accountIncome.setInputTime(DateUtils.getNowDate());
            accountIncome.setInputUser(borrowInfo.getBorrowerName());
            accountIncomeService.save(accountIncome);
            return AjaxResult.success("添加成功");
            return R.ok(null, "添加成功");
        }
        return AjaxResult.success("添加失败");
        return R.ok(null, "添加失败");
    }
    @Override
    public AjaxResult updateBorrowInfo(BorrowInfo borrowInfo) {
    public R<?> updateBorrowInfo(BorrowInfo borrowInfo) {
        int update = borrowInfoMapper.updateById(borrowInfo);
        if(update > 0){
            // ä¿®æ”¹æˆåŠŸï¼Œä¿®æ”¹æ”¶å…¥ç®¡ç†
@@ -103,13 +103,13 @@
                accountExpense.setInputUser(borrowInfo.getBorrowerName());
                accountExpenseService.save(accountExpense);
            }
            return AjaxResult.success("修改成功");
            return R.ok(null, "修改成功");
        }
        return  AjaxResult.success("修改失败");
        return R.ok(null, "修改失败");
    }
    @Override
    public AjaxResult delete(List<Long> ids) {
    public R<?> delete(List<Long> ids) {
        int delete = borrowInfoMapper.deleteBatchIds(ids);
        if(delete > 0){
            // åˆ é™¤æˆåŠŸï¼Œåˆ é™¤æ”¶å…¥ç®¡ç†
@@ -120,8 +120,8 @@
            accountExpenseService.remove(new LambdaQueryWrapper<AccountExpense>()
                    .in(AccountExpense::getBusinessId, ids)
                    .eq(AccountExpense::getBusinessType, 2));
            return AjaxResult.success("删除成功");
            return R.ok(null, "删除成功");
        }
        return  AjaxResult.success("删除失败");
        return R.ok(null, "删除失败");
    }
}
src/main/java/com/ruoyi/account/service/impl/financial/AccountSubjectServiceImpl.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/service/impl/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;
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;
src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchaseServiceImpl.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/service/impl/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;
src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesServiceImpl.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/service/impl/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;
src/main/java/com/ruoyi/account/service/purchase/AccountSubjectService.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/service/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;
src/main/java/com/ruoyi/account/service/sales/AccountSalesService.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/service/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;
/**
src/main/java/com/ruoyi/aftersalesservice/controller/AfterSalesNearExpiryController.java
@@ -7,7 +7,7 @@
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 io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
@@ -36,9 +36,9 @@
    @PostMapping("/add")
    @Operation(summary = "新增临期售后")
    @Log(title = "新增临期售后", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody AfterSalesNearExpiry entity) {
    public R<?> add(@RequestBody AfterSalesNearExpiry entity) {
        afterSalesNearExpiryService.add(entity);
        return AjaxResult.success("添加成功");
        return R.ok(null, "添加成功");
    }
    /**
@@ -47,9 +47,9 @@
    @PostMapping("/update")
    @Operation(summary = "更新临期售后")
    @Log(title = "更新临期售后", businessType = BusinessType.UPDATE)
    public AjaxResult update(@RequestBody AfterSalesNearExpiry entity) {
    public R<?> update(@RequestBody AfterSalesNearExpiry entity) {
        afterSalesNearExpiryService.update(entity);
        return AjaxResult.success("更新成功");
        return R.ok(null, "更新成功");
    }
    /**
@@ -58,9 +58,9 @@
    @DeleteMapping("/delete")
    @Operation(summary = "删除临期售后")
    @Log(title = "删除临期售后", businessType = BusinessType.DELETE)
    public AjaxResult delete(Long[] ids) {
    public R<?> delete(Long[] ids) {
        afterSalesNearExpiryService.delete(ids);
        return AjaxResult.success("删除成功");
        return R.ok(null, "删除成功");
    }
    /**
@@ -69,9 +69,9 @@
    @GetMapping("/listPage")
    @Operation(summary = "分页查询临期售后")
    @Log(title = "分页查询临期售后", businessType = BusinessType.OTHER)
    public AjaxResult listPage(Page<AfterSalesNearExpiry> page, AfterSalesNearExpiry entity) {
    public R<?> listPage(Page<AfterSalesNearExpiry> page, AfterSalesNearExpiry entity) {
        IPage<AfterSalesNearExpiry> listPage = afterSalesNearExpiryService.listPage(page, entity);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
}
src/main/java/com/ruoyi/aftersalesservice/controller/AfterSalesServiceController.java
@@ -10,7 +10,7 @@
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.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.sales.dto.SalesLedgerDto;
@@ -45,9 +45,9 @@
    @GetMapping("/listPage")
    @Operation(summary = "售后服务-分页查询")
    @Log(title = "售后服务-分页查询", businessType = BusinessType.OTHER)
    public AjaxResult listPage(Page page, AfterSalesServiceNewDto afterSalesService) {
    public R<?> listPage(Page page, AfterSalesServiceNewDto afterSalesService) {
        IPage<AfterSalesServiceNewDto> listPage = afterSalesServiceService.listPage(page, afterSalesService);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @Log(title = "售后服务-反馈登记", businessType = BusinessType.EXPORT)
@@ -85,14 +85,14 @@
    @PostMapping("/add")
    @Operation(summary = "售后服务-新增")
    @Log(title = "售后服务-新增", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody AfterSalesServiceNewDto afterSalesServiceNewDto) {
        return afterSalesServiceService.addAfterSalesServiceDto(afterSalesServiceNewDto) ? AjaxResult.success() : AjaxResult.error();
    public R<?> add(@RequestBody AfterSalesServiceNewDto afterSalesServiceNewDto) {
        return afterSalesServiceService.addAfterSalesServiceDto(afterSalesServiceNewDto) ? R.ok() : R.fail();
    }
    @PostMapping("/update")
    @Operation(summary = "售后服务-修改")
    @Log(title = "售后服务-修改", businessType = BusinessType.UPDATE)
    public AjaxResult update(@RequestBody AfterSalesServiceNewDto afterSalesServiceNewDto) {
    public R<?> update(@RequestBody AfterSalesServiceNewDto afterSalesServiceNewDto) {
        if (afterSalesServiceNewDto.getProductModelIdList() != null && afterSalesServiceNewDto.getProductModelIdList().isEmpty() ) {
            String productModelIds = afterSalesServiceNewDto.getProductModelIdList().stream()
                    .map(String::valueOf)
@@ -100,24 +100,24 @@
            afterSalesServiceNewDto.setProductModelIds(productModelIds);
        }
        boolean update = afterSalesServiceService.updateById(afterSalesServiceNewDto);
        return update ? AjaxResult.success() : AjaxResult.error();
        return update ? R.ok() : R.fail();
    }
    @DeleteMapping("/delete")
    @Operation(summary = "售后服务-删除")
    @Log(title = "售后服务-删除", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
    public R<?> delete(@RequestBody List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return AjaxResult.error("请传入要删除的ID");
            return R.fail("请传入要删除的ID");
        }
        boolean delete = afterSalesServiceService.removeByIds(ids);
        return delete ? AjaxResult.success() : AjaxResult.error();
        return delete ? R.ok() : R.fail();
    }
    @PostMapping("/dispose")
    @Operation(summary = "售后服务-处理")
    @Log(title = "售后服务-处理", businessType = BusinessType.UPDATE)
    public AjaxResult dispose(@RequestBody AfterSalesService afterSalesService) {
    public R<?> dispose(@RequestBody AfterSalesService afterSalesService) {
        AfterSalesService byId = afterSalesServiceService.getById(afterSalesService.getId());
        if(byId == null) throw new RuntimeException("未找到该数据");
        if(byId.getStatus().equals(2)) throw new RuntimeException("该数据已处理");
@@ -126,28 +126,28 @@
        afterSalesService.setDisposeNickName(sysUser.getNickName());
        afterSalesService.setStatus(2);
        boolean update = afterSalesServiceService.updateById(afterSalesService);
        return update ? AjaxResult.success() : AjaxResult.error();
        return update ? R.ok() : R.fail();
    }
    @GetMapping("listSalesLedger")
    @Operation(summary = "售后服务-获取销售台账")
    public AjaxResult listSalesLedger(SalesLedgerDto salesLedgerDto, Page page) {
    public R<?> listSalesLedger(SalesLedgerDto salesLedgerDto, Page page) {
        IPage<SalesLedgerDto> list = salesLedgerService.listSalesLedger(salesLedgerDto,page);
        return AjaxResult.success(list);
        return R.ok(list);
    }
    @GetMapping("getById")
    @Operation(summary = "售后服务-根据id获取详情")
    public AjaxResult getById(Long id) {
        return AjaxResult.success(afterSalesServiceService.getAfterSalesServiceNewDtoById(id));
    public R<?> getById(Long id) {
        return R.ok(afterSalesServiceService.getAfterSalesServiceNewDtoById(id));
    }
    @Operation(summary = "售后服务-统计工单情况")
    @GetMapping("count")
    public AjaxResult count() {
        return AjaxResult.success(afterSalesServiceService.countAfterSalesService());
    public R<?> count() {
        return R.ok(afterSalesServiceService.countAfterSalesService());
    }
}
src/main/java/com/ruoyi/aftersalesservice/controller/AfterSalesServiceFileController.java
@@ -6,7 +6,7 @@
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 io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
@@ -34,24 +34,24 @@
    @PostMapping("/upload")
    @Operation(summary = "售后服务-文件上传")
    @Log(title = "售后服务-文件上传", businessType = BusinessType.INSERT)
    public AjaxResult fileUpload(@RequestParam("file") MultipartFile file,
    public R<?> fileUpload(@RequestParam("file") MultipartFile file,
                                 @RequestParam("id") Long afterSalesServiceId) {
        afterSalesServiceFileService.fileUpload(file, afterSalesServiceId);
        return AjaxResult.success("上传成功");
        return R.ok(null, "上传成功");
    }
    @GetMapping("/listPage")
    @Operation(summary = "售后处理-售后附件列表")
    @Log(title = "售后处理-售后附件列表", businessType = BusinessType.OTHER)
    public AjaxResult fileList(Page<AfterSalesServiceFile> page, Long afterSalesServiceId) {
        return AjaxResult.success(afterSalesServiceFileService.fileList(page, afterSalesServiceId));
    public R<?> fileList(Page<AfterSalesServiceFile> page, Long afterSalesServiceId) {
        return R.ok(afterSalesServiceFileService.fileList(page, afterSalesServiceId));
    }
    @DeleteMapping("/del/{fileId}")
    @Operation(summary = "售后处理-删除附件")
    @Log(title = "售后处理-删除附件", businessType = BusinessType.DELETE)
    public AjaxResult delFile(@PathVariable Long fileId) {
    public R<?> delFile(@PathVariable Long fileId) {
        afterSalesServiceFileService.delFile(fileId);
        return AjaxResult.success("删除成功!");
        return R.ok(null, "删除成功!");
    }
}
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);
}
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;
    }
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);
}
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);
}
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) {
    }
}
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);
}
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, "客户档案", "私海", "公海", "客户池")) {
            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 ("查询私海客户档案前10条".equals(normalized)) {
            return salesAgentTools.listCustomerProfiles(memoryId, "private", null, 10);
        }
        if ("查询公海客户档案".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("客户档案", "")
                .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) {
    }
}
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();
    }
}
src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java
@@ -10,7 +10,7 @@
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 com.ruoyi.framework.web.domain.R;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.UserMessage;
import io.swagger.v3.oas.annotations.Operation;
@@ -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,27 +82,32 @@
            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));
    }
    @Operation(summary = "制造会话列表")
    @GetMapping("/history/sessions")
    public AjaxResult listSessions() {
        return success(aiChatSessionService.listCurrentUserSessions(SecurityUtils.getLoginUser()));
    public R<?> listSessions() {
        return R.ok(aiChatSessionService.listCurrentUserSessions(SecurityUtils.getLoginUser()));
    }
    @Operation(summary = "制造会话消息")
    @GetMapping("/history/messages/{memoryId}")
    public AjaxResult listMessages(@PathVariable String memoryId) {
        return success(aiChatSessionService.listCurrentUserMessages(memoryId, SecurityUtils.getLoginUser()));
    public R<?> listMessages(@PathVariable String memoryId) {
        return R.ok(aiChatSessionService.listCurrentUserMessages(memoryId, SecurityUtils.getLoginUser()));
    }
    @Operation(summary = "删除制造会话")
    @DeleteMapping("/history/{memoryId}")
    public AjaxResult deleteSession(@PathVariable String memoryId) {
    public R<?> deleteSession(@PathVariable String memoryId) {
        aiSessionUserContext.remove(memoryId);
        return toAjax(aiChatSessionService.deleteCurrentUserSession(memoryId, SecurityUtils.getLoginUser()));
        aiChatSessionService.deleteCurrentUserSession(memoryId, SecurityUtils.getLoginUser());
        return R.ok();
    }
    private String currentDateForPrompt() {
        return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT);
    }
}
src/main/java/com/ruoyi/ai/controller/PurchaseAiController.java
@@ -6,17 +6,10 @@
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;
@@ -49,28 +42,28 @@
    @Operation(summary = "采购多文件分析确认处理")
    @PostMapping("/analyze-files/confirm")
    public AjaxResult confirmAnalyzeResult(@RequestBody PurchaseAiConfirmRequest request) {
    public R confirmAnalyzeResult(@RequestBody PurchaseAiConfirmRequest request) {
        return purchaseAiService.confirmAnalyzeResult(request);
    }
    @Operation(summary = "采购会话列表")
    @GetMapping("/history/sessions")
    public AjaxResult listSessions() {
    public R listSessions() {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        return success(purchaseAiService.listSessions(loginUser));
        return R.ok(purchaseAiService.listSessions(loginUser));
    }
    @Operation(summary = "采购会话消息")
    @GetMapping("/history/messages/{memoryId}")
    public AjaxResult listMessages(@PathVariable String memoryId) {
    public R listMessages(@PathVariable String memoryId) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        return success(purchaseAiService.listMessages(memoryId, loginUser));
        return R.ok(purchaseAiService.listMessages(memoryId, loginUser));
    }
    @Operation(summary = "删除采购会话")
    @DeleteMapping("/history/{memoryId}")
    public AjaxResult deleteSession(@PathVariable String memoryId) {
    public R deleteSession(@PathVariable String memoryId) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        return toAjax(purchaseAiService.deleteSession(memoryId, loginUser));
        return R.ok(purchaseAiService.deleteSession(memoryId, loginUser));
    }
}
src/main/java/com/ruoyi/ai/controller/SalesAiController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,142 @@
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.R;
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 R<?> listSessions() {
        return R.ok(aiChatSessionService.listCurrentUserSessions(SecurityUtils.getLoginUser()));
    }
    @Operation(summary = "销售助手会话消息")
    @GetMapping("/history/messages/{memoryId}")
    public R<?> listMessages(@PathVariable String memoryId) {
        return R.ok(aiChatSessionService.listCurrentUserMessages(memoryId, SecurityUtils.getLoginUser()));
    }
    @Operation(summary = "删除销售助手会话")
    @DeleteMapping("/history/{memoryId}")
    public R<?> deleteSession(@PathVariable String memoryId) {
        aiSessionUserContext.remove(memoryId);
        aiChatSessionService.deleteCurrentUserSession(memoryId, SecurityUtils.getLoginUser());
        return R.ok();
    }
    private boolean isBusinessDataIntent(String message) {
        if (!StringUtils.hasText(message)) {
            return false;
        }
        String text = message.trim();
        return containsAny(text,
                "查询", "查看", "统计", "分析", "建议", "客户档案", "私海", "公海",
                "销售报价", "销售台账", "销售退货", "客户往来", "发货台账", "回款", "报价", "风险");
    }
    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);
    }
}
src/main/java/com/ruoyi/ai/controller/XiaozhiController.java
@@ -12,23 +12,19 @@
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 com.ruoyi.framework.web.domain.R;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.UserMessage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;
import java.io.IOException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.UUID;
@@ -39,6 +35,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 +88,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));
    }
@@ -143,20 +151,45 @@
    @Operation(summary = "会话列表")
    @GetMapping("/history/sessions")
    public AjaxResult listSessions() {
        return success(aiChatSessionService.listCurrentUserSessions(SecurityUtils.getLoginUser()));
    public R listSessions() {
        return R.ok(aiChatSessionService.listCurrentUserSessions(SecurityUtils.getLoginUser()));
    }
    @Operation(summary = "会话消息")
    @GetMapping("/history/messages/{memoryId}")
    public AjaxResult listMessages(@PathVariable String memoryId) {
        return success(aiChatSessionService.listCurrentUserMessages(memoryId, SecurityUtils.getLoginUser()));
    public R listMessages(@PathVariable String memoryId) {
        return R.ok(aiChatSessionService.listCurrentUserMessages(memoryId, SecurityUtils.getLoginUser()));
    }
    @Operation(summary = "删除会话")
    @DeleteMapping("/history/{memoryId}")
    public AjaxResult deleteSession(@PathVariable String memoryId) {
    public R deleteSession(@PathVariable String memoryId) {
        aiSessionUserContext.remove(memoryId);
        return toAjax(aiChatSessionService.deleteCurrentUserSession(memoryId, SecurityUtils.getLoginUser()));
        return R.ok(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);
    }
}
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;
@@ -17,7 +18,7 @@
import com.ruoyi.basic.service.StorageBlobService;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.purchase.dto.PurchaseLedgerDto;
import com.ruoyi.purchase.dto.PurchaseReturnOrderDto;
import com.ruoyi.purchase.pojo.PaymentRegistration;
@@ -26,13 +27,7 @@
import com.ruoyi.purchase.service.PurchaseReturnOrdersService;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import dev.langchain4j.data.image.Image;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.Content;
import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.TextContent;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.*;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
@@ -47,22 +42,12 @@
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Base64;
import java.util.Arrays;
import java.nio.file.Files;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.UUID;
import java.nio.file.Files;
import java.util.*;
@Service
public class PurchaseAiService {
@@ -71,6 +56,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;
@@ -138,7 +125,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,21 +197,21 @@
                    .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));
    }
    public AjaxResult confirmAnalyzeResult(PurchaseAiConfirmRequest request) {
    public R confirmAnalyzeResult(PurchaseAiConfirmRequest request) {
        if (request == null || !StringUtils.hasText(request.getBusinessType())) {
            return AjaxResult.error("businessType不能为空");
            return R.fail("businessType不能为空");
        }
        if (request.getPayload() == null || request.getPayload().isEmpty()) {
            return AjaxResult.error("payload不能为空");
            return R.fail("payload不能为空");
        }
        try {
@@ -223,10 +220,10 @@
                case "purchase_ledger" -> processPurchaseLedger(request.getPayload());
                case "payment_registration" -> processPaymentRegistration(request.getPayload());
                case "purchase_return_order" -> processPurchaseReturnOrder(request.getPayload());
                default -> AjaxResult.error("暂不支持该业务类型: " + businessType);
                default -> R.fail("暂不支持该业务类型: " + businessType);
            };
        } catch (Exception ex) {
            return AjaxResult.error(toCustomerMessage(ex));
            return R.fail(toCustomerMessage(ex));
        }
    }
@@ -471,6 +468,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 """
                ä½ æ˜¯é‡‡è´­ä¸šåŠ¡æ–‡ä»¶åˆ†æžåŠ©æ‰‹ã€‚è¯·ä¸¥æ ¼æ ¹æ®ç”¨æˆ·ä¸Šä¼ çš„å¤šä¸ªæ–‡ä»¶å’Œç”¨æˆ·è¦æ±‚æå–é‡‡è´­ä¸šåŠ¡æ•°æ®ã€‚
@@ -481,7 +523,7 @@
                è¾“出要求:
                1. åªè¾“出合法 JSON,不要 Markdown,不要额外解释。
                2. JSON é¡¶å±‚字段固定为:
                   - success: boolean
                   - ok: boolean
                   - businessType: purchase_ledger | payment_registration | purchase_return_order | unknown
                   - action: confirm_required
                   - description: ä¸­æ–‡è¯´æ˜Ž
@@ -517,33 +559,33 @@
                """.formatted(message, fileContent);
    }
    private AjaxResult processPurchaseLedger(Map<String, Object> payload) throws Exception {
    private R processPurchaseLedger(Map<String, Object> payload) throws Exception {
        if (payload.containsKey("purchaseLedgers")) {
            return processPurchaseLedgerBatch(payload);
        }
        Map<String, Object> normalizedPayload = normalizePurchaseLedgerMap(payload);
        PurchaseLedgerDto dto = objectMapper.convertValue(normalizedPayload, PurchaseLedgerDto.class);
        AjaxResult ledgerResult = validatePurchaseLedger(dto, 0);
        R ledgerResult = validatePurchaseLedger(dto, 0);
        if (ledgerResult != null) {
            return ledgerResult;
        }
        AjaxResult supplierResult = fillSupplierIdByName(dto);
        R supplierResult = fillSupplierIdByName(dto);
        if (supplierResult != null) {
            return supplierResult;
        }
        AjaxResult productResult = validatePurchaseProducts(dto.getProductData(), 0);
        R productResult = validatePurchaseProducts(dto.getProductData(), 0);
        if (productResult != null) {
            return productResult;
        }
        int result = purchaseLedgerService.addOrEditPurchase(dto);
        return AjaxResult.success("采购台账已处理", result);
        return R.ok( result,"采购台账已处理");
    }
    private AjaxResult processPurchaseLedgerBatch(Map<String, Object> payload) throws Exception {
    private R processPurchaseLedgerBatch(Map<String, Object> payload) throws Exception {
        List<Map<String, Object>> purchaseLedgers = toMapList(payload.get("purchaseLedgers"));
        if (purchaseLedgers.isEmpty()) {
            return AjaxResult.error("purchaseLedgers不能为空");
            return R.fail("purchaseLedgers不能为空");
        }
        List<Map<String, Object>> topLevelProductData = toMapList(payload.get("productData"));
@@ -551,11 +593,11 @@
        for (int i = 0; i < purchaseLedgers.size(); i++) {
            Map<String, Object> ledgerMap = normalizePurchaseLedgerMap(purchaseLedgers.get(i));
            PurchaseLedgerDto dto = objectMapper.convertValue(ledgerMap, PurchaseLedgerDto.class);
            AjaxResult ledgerResult = validatePurchaseLedger(dto, i);
            R ledgerResult = validatePurchaseLedger(dto, i);
            if (ledgerResult != null) {
                return ledgerResult;
            }
            AjaxResult supplierResult = fillSupplierIdByName(dto);
            R supplierResult = fillSupplierIdByName(dto);
            if (supplierResult != null) {
                return supplierResult;
            }
@@ -565,7 +607,7 @@
                products = matchProductsForLedger(ledgerMap, dto, topLevelProductData, purchaseLedgers.size() == 1);
                dto.setProductData(products);
            }
            AjaxResult productResult = validatePurchaseProducts(products, i);
            R productResult = validatePurchaseProducts(products, i);
            if (productResult != null) {
                return productResult;
            }
@@ -580,7 +622,7 @@
            item.put("result", result);
            results.add(item);
        }
        return AjaxResult.success("采购台账已批量处理", results);
        return R.ok( results,"采购台账已批量处理");
    }
    private List<SalesLedgerProduct> matchProductsForLedger(Map<String, Object> ledgerMap,
@@ -786,7 +828,7 @@
        }
    }
    private AjaxResult validatePurchaseProducts(List<SalesLedgerProduct> products, int ledgerIndex) {
    private R validatePurchaseProducts(List<SalesLedgerProduct> products, int ledgerIndex) {
        if (products == null || products.isEmpty()) {
            return null;
        }
@@ -794,34 +836,34 @@
            SalesLedgerProduct product = products.get(i);
            String prefix = "第" + (ledgerIndex + 1) + "个采购台账的第" + (i + 1) + "条产品";
            if (!StringUtils.hasText(product.getProductCategory())) {
                return AjaxResult.error(prefix + "缺少产品名称,请补充后再确认");
                return R.fail(prefix + "缺少产品名称,请补充后再确认");
            }
            if (!StringUtils.hasText(product.getSpecificationModel())) {
                return AjaxResult.error(prefix + "缺少规格型号,请补充后再确认");
                return R.fail(prefix + "缺少规格型号,请补充后再确认");
            }
            if (!StringUtils.hasText(product.getUnit())) {
                return AjaxResult.error(prefix + "缺少单位,请补充后再确认");
                return R.fail(prefix + "缺少单位,请补充后再确认");
            }
            if (product.getQuantity() == null) {
                return AjaxResult.error(prefix + "缺少数量");
                return R.fail(prefix + "缺少数量");
            }
            if (product.getTaxInclusiveUnitPrice() == null) {
                return AjaxResult.error(prefix + "缺少含税单价,请补充后再确认");
                return R.fail(prefix + "缺少含税单价,请补充后再确认");
            }
            if (product.getTaxInclusiveTotalPrice() == null) {
                return AjaxResult.error(prefix + "缺少含税总价,请补充后再确认");
                return R.fail(prefix + "缺少含税总价,请补充后再确认");
            }
        }
        return null;
    }
    private AjaxResult validatePurchaseLedger(PurchaseLedgerDto dto, int ledgerIndex) {
    private R validatePurchaseLedger(PurchaseLedgerDto dto, int ledgerIndex) {
        String prefix = "第" + (ledgerIndex + 1) + "个采购台账";
        if (!StringUtils.hasText(dto.getPurchaseContractNumber())) {
            return AjaxResult.error(prefix + "缺少采购合同号,请补充后再确认");
            return R.fail(prefix + "缺少采购合同号,请补充后再确认");
        }
        if (dto.getSupplierId() == null && !StringUtils.hasText(dto.getSupplierName())) {
            return AjaxResult.error(prefix + "缺少供应商名称,请补充后再确认");
            return R.fail(prefix + "缺少供应商名称,请补充后再确认");
        }
        return null;
    }
@@ -992,25 +1034,25 @@
        return "处理失败:" + message;
    }
    private AjaxResult fillSupplierIdByName(PurchaseLedgerDto dto) {
    private R fillSupplierIdByName(PurchaseLedgerDto dto) {
        if (dto.getSupplierId() != null) {
            return null;
        }
        if (!StringUtils.hasText(dto.getSupplierName())) {
            return AjaxResult.error("供应商ID不能为空;未识别到供应商名称,无法自动匹配供应商ID");
            return R.fail("供应商ID不能为空;未识别到供应商名称,无法自动匹配供应商ID");
        }
        SupplierManage supplier = supplierManageMapper.selectOne(new LambdaQueryWrapper<SupplierManage>()
                .eq(SupplierManage::getSupplierName, dto.getSupplierName().trim())
                .last("limit 1"));
        if (supplier == null) {
            return AjaxResult.error("未找到供应商:" + dto.getSupplierName() + ",请先维护供应商或手动选择供应商ID");
            return R.fail("未找到供应商:" + dto.getSupplierName() + ",请先维护供应商或手动选择供应商ID");
        }
        dto.setSupplierId(supplier.getId());
        return null;
    }
    private AjaxResult processPaymentRegistration(Map<String, Object> payload) {
    private R processPaymentRegistration(Map<String, Object> payload) {
        Object recordsValue = payload.get("records");
        List<PaymentRegistration> records;
        if (recordsValue == null) {
@@ -1020,12 +1062,12 @@
            });
        }
        int result = paymentRegistrationService.insertPaymentRegistration(records);
        return AjaxResult.success("付款登记已处理", result);
        return R.ok( result,"付款登记已处理");
    }
    private AjaxResult processPurchaseReturnOrder(Map<String, Object> payload) {
    private R processPurchaseReturnOrder(Map<String, Object> payload) {
        PurchaseReturnOrderDto dto = objectMapper.convertValue(payload, PurchaseReturnOrderDto.class);
        Boolean result = purchaseReturnOrdersService.add(dto);
        return AjaxResult.success("采购退货单已处理", result);
        return R.ok( result,"采购退货单已处理");
    }
}
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、applicant、approver;related è¡¨ç¤ºå½“前用户相关,applicant è¡¨ç¤ºæˆ‘发起的,approver è¡¨ç¤ºå¾…我处理的", required = false) String scope) {
                            @P(value = "查询范围,可选值:related、applicant、approver;related è¡¨ç¤ºå½“前用户相关,applicant è¡¨ç¤ºæˆ‘发起的,approver è¡¨ç¤ºå¾…我处理的", 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());
src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
@@ -42,6 +42,7 @@
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;
@@ -286,8 +287,24 @@
                .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 = "按时间范围查询采购退货单列表和退货金额。")
@@ -446,6 +463,19 @@
        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));
        }
        return BigDecimal.ZERO;
    }
    private List<PaymentRegistration> queryPayments(LoginUser loginUser, DateRange range) {
        LambdaQueryWrapper<PaymentRegistration> wrapper = new LambdaQueryWrapper<>();
        applyTenantFilter(wrapper, loginUser.getTenantId(), PaymentRegistration::getTenantId);
@@ -484,7 +514,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 +531,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 +584,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) {
src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1475 @@
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.SalesReceiptReturnMapper;
import com.ruoyi.account.pojo.SalesReceiptReturn;
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.dto.InvoiceLedgerDto;
import com.ruoyi.sales.mapper.InvoiceLedgerMapper;
import com.ruoyi.sales.mapper.ReceiptPaymentMapper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesQuotationMapper;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
import com.ruoyi.sales.pojo.ReceiptPayment;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesQuotation;
import com.ruoyi.sales.pojo.ShippingInfo;
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.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
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 ReceiptPaymentMapper receiptPaymentMapper;
    private final InvoiceLedgerMapper invoiceLedgerMapper;
    private final SalesReceiptReturnMapper salesReceiptReturnMapper;
    private final AiSessionUserContext aiSessionUserContext;
    public SalesAgentTools(CustomerMapper customerMapper,
                           SalesLedgerMapper salesLedgerMapper,
                           SalesQuotationMapper salesQuotationMapper,
                           ShippingInfoMapper shippingInfoMapper,
                           ReceiptPaymentMapper receiptPaymentMapper,
                           InvoiceLedgerMapper invoiceLedgerMapper,
                           SalesReceiptReturnMapper salesReceiptReturnMapper,
                           AiSessionUserContext aiSessionUserContext) {
        this.customerMapper = customerMapper;
        this.salesLedgerMapper = salesLedgerMapper;
        this.salesQuotationMapper = salesQuotationMapper;
        this.shippingInfoMapper = shippingInfoMapper;
        this.receiptPaymentMapper = receiptPaymentMapper;
        this.invoiceLedgerMapper = invoiceLedgerMapper;
        this.salesReceiptReturnMapper = salesReceiptReturnMapper;
        this.aiSessionUserContext = aiSessionUserContext;
    }
    @Tool(name = "查询客户档案", value = "按私海/公海类型和关键词查询客户档案列表")
    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<SalesReceiptReturn> wrapper = new LambdaQueryWrapper<>();
        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), SalesReceiptReturn::getDeptId);
        if (StringUtils.hasText(keyword)) {
            wrapper.and(w -> w.like(SalesReceiptReturn::getRefundId, keyword)
                    .or().like(SalesReceiptReturn::getTransactionNo, keyword)
                    .or().like(SalesReceiptReturn::getPaymentAccountName, keyword));
        }
        wrapper.ge(SalesReceiptReturn::getCreateTime, range.start().atStartOfDay())
                .le(SalesReceiptReturn::getCreateTime, range.end().atTime(23, 59, 59))
                .orderByDesc(SalesReceiptReturn::getCreateTime, SalesReceiptReturn::getId)
                .last("limit " + normalizeLimit(limit));
        List<SalesReceiptReturn> rows = defaultList(salesReceiptReturnMapper.selectList(wrapper));
        BigDecimal returnAmount = rows.stream()
                .map(SalesReceiptReturn::getActualAmount)
                .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.getRefundId()));
            map.put("paymentAccount", safe(item.getPaymentAccount()));
            map.put("paymentAccountName", safe(item.getPaymentAccountName()));
            map.put("paymentMethod", item.getPaymentMethod());
            map.put("actualAmount", item.getActualAmount());
            map.put("fee", item.getFee());
            map.put("discountAmount", item.getDiscountAmount());
            map.put("transactionNo", safe(item.getTransactionNo()));
            map.put("createTime", formatDateTime(item.getCreateTime()));
            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);
        LambdaQueryWrapper<ReceiptPayment> wrapper = new LambdaQueryWrapper<>();
        applyTenantFilter(wrapper, loginUser.getTenantId(), ReceiptPayment::getTenantId);
        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ReceiptPayment::getDeptId);
        wrapper.ge(ReceiptPayment::getReceiptPaymentDate, range.start())
                .le(ReceiptPayment::getReceiptPaymentDate, range.end())
                .orderByDesc(ReceiptPayment::getReceiptPaymentDate, ReceiptPayment::getId);
        List<ReceiptPayment> payments = defaultList(receiptPaymentMapper.selectList(wrapper));
        if (payments.isEmpty()) {
            return jsonResponse(true, "sales_customer_interaction_list", "未查询到客户往来记录", rangeSummary(range, 0, keyword), Map.of("items", List.of()), Map.of());
        }
        List<Long> ledgerIds = payments.stream()
                .map(ReceiptPayment::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));
        List<ReceiptPayment> filtered = payments.stream()
                .filter(item -> matchInteractionKeyword(item, ledgerMap.get(item.getSalesLedgerId()), keyword))
                .limit(normalizeLimit(limit))
                .collect(Collectors.toList());
        BigDecimal totalReceiptAmount = filtered.stream()
                .map(ReceiptPayment::getReceiptPaymentAmount)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        List<Map<String, Object>> items = filtered.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("projectName", ledger == null ? "" : safe(ledger.getProjectName()));
            map.put("receiptPaymentDate", formatDate(item.getReceiptPaymentDate()));
            map.put("receiptPaymentAmount", item.getReceiptPaymentAmount());
            map.put("receiptPaymentType", safe(item.getReceiptPaymentType()));
            map.put("registrant", safe(item.getRegistrant()));
            return map;
        }).collect(Collectors.toList());
        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", "已返回客户往来明细", 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);
        List<ReceiptPayment> receipts = queryReceipts(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);
        BigDecimal receivedAmountTotal = receipts.stream()
                .map(ReceiptPayment::getReceiptPaymentAmount)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal pendingAmountTotal = maxZero(contractAmountTotal.subtract(receivedAmountTotal));
        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", receivedAmountTotal);
        summary.put("pendingAmountTotal", pendingAmountTotal);
        Map<String, Object> charts = new LinkedHashMap<>();
        charts.put("amountBarOption", buildAmountBarOption(contractAmountTotal, quotationAmountTotal, receivedAmountTotal, pendingAmountTotal));
        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 "保持正常月度对账与回款确认,维持客户回款节奏。";
        }
        if (metric.getPendingRate().compareTo(new BigDecimal("0.60")) >= 0) {
            return "优先锁定回款计划,按周拆分回款节点并绑定发货条件,避免新增信用敞口。";
        }
        if (metric.getPendingRate().compareTo(new BigDecimal("0.30")) >= 0) {
            return "建议执行双周催收机制,同步财务与业务联合跟进重点合同。";
        }
        return "保持正常催收节奏,按合同节点提前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<ReceiptPayment> queryReceipts(LoginUser loginUser, DateRange range) {
        LambdaQueryWrapper<ReceiptPayment> wrapper = new LambdaQueryWrapper<>();
        applyTenantFilter(wrapper, loginUser.getTenantId(), ReceiptPayment::getTenantId);
        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ReceiptPayment::getDeptId);
        if (range != null) {
            wrapper.ge(ReceiptPayment::getReceiptPaymentDate, range.start())
                    .le(ReceiptPayment::getReceiptPaymentDate, range.end());
        }
        return defaultList(receiptPaymentMapper.selectList(wrapper));
    }
    private List<ReceiptPayment> queryReceiptsByLedgerIds(LoginUser loginUser, List<Long> ledgerIds) {
        if (ledgerIds == null || ledgerIds.isEmpty()) {
            return List.of();
        }
        LambdaQueryWrapper<ReceiptPayment> wrapper = new LambdaQueryWrapper<>();
        applyTenantFilter(wrapper, loginUser.getTenantId(), ReceiptPayment::getTenantId);
        applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ReceiptPayment::getDeptId);
        wrapper.in(ReceiptPayment::getSalesLedgerId, ledgerIds);
        return defaultList(receiptPaymentMapper.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<>();
        for (InvoiceLedgerDto item : defaultList(invoiceLedgerMapper.invoicedTotal(ledgerIds))) {
            if (item.getSalesLedgerId() == null) {
                continue;
            }
            result.merge(item.getSalesLedgerId().longValue(), defaultDecimal(item.getInvoiceTotal()), BigDecimal::add);
        }
        return result;
    }
    private Map<Long, BigDecimal> sumReceiptAmounts(LoginUser loginUser, List<Long> ledgerIds) {
        Map<Long, BigDecimal> result = new HashMap<>();
        for (ReceiptPayment item : queryReceiptsByLedgerIds(loginUser, ledgerIds)) {
            if (item.getSalesLedgerId() == null) {
                continue;
            }
            result.merge(item.getSalesLedgerId(), defaultDecimal(item.getReceiptPaymentAmount()), BigDecimal::add);
        }
        return result;
    }
    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 matchInteractionKeyword(ReceiptPayment payment, SalesLedger ledger, String keyword) {
        if (!StringUtils.hasText(keyword)) {
            return true;
        }
        String text = keyword.trim();
        return safe(payment.getRegistrant()).contains(text)
                || (ledger != null && (safe(ledger.getCustomerName()).contains(text)
                || safe(ledger.getSalesContractNo()).contains(text)
                || safe(ledger.getProjectName()).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 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", "客户合同额TOP5", "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;
        }
    }
}
src/main/java/com/ruoyi/approve/controller/ApproveNodeController.java
@@ -2,7 +2,8 @@
import com.ruoyi.approve.pojo.ApproveNode;
import com.ruoyi.approve.service.IApproveNodeService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
@@ -15,7 +16,7 @@
@RestController
@RequestMapping("/approveNode")
@AllArgsConstructor
public class ApproveNodeController {
public class ApproveNodeController extends BaseController {
    private IApproveNodeService approveNodeService;
@@ -26,8 +27,8 @@
     */
    @GetMapping("/details/{id}")
    @Operation(summary = "流程状态详情")
    public AjaxResult details(@PathVariable String id) {
        return AjaxResult.success(approveNodeService.details(id));
    public R<?> details(@PathVariable String id) {
        return R.ok(approveNodeService.details(id));
    }
    /**
@@ -38,9 +39,9 @@
    @PostMapping("/updateApproveNode")
    @Transactional(rollbackFor = Exception.class)
    @Operation(summary = "审批节点")
    public AjaxResult updateApproveNode(@RequestBody ApproveNode approveNode) throws IOException {
    public R<?> updateApproveNode(@RequestBody ApproveNode approveNode) throws IOException {
        approveNodeService.updateApproveNode(approveNode);
        return AjaxResult.success();
        return R.ok();
    }
    /**
@@ -49,9 +50,9 @@
     * @return
     */
    @PostMapping("/init")
    public AjaxResult init(String id) {
    public R<?> init(String id) {
        approveNodeService.initApproveNodes("",id,1L);
        return AjaxResult.success();
        return R.ok();
    }
}
src/main/java/com/ruoyi/approve/controller/ApproveProcessController.java
@@ -9,7 +9,9 @@
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.project.system.domain.SysDept;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
@@ -25,7 +27,7 @@
@RequestMapping("/approveProcess")
@AllArgsConstructor
@Tag(name = "审批")
public class ApproveProcessController {
public class ApproveProcessController extends BaseController {
    private IApproveProcessService approveProcessService;
    /**、
@@ -33,13 +35,13 @@
     * @return
     */
    @GetMapping("/getDept")
    public AjaxResult getDept() {
    public R<?> getDept() {
        Long userId = SecurityUtils.getUserId();
        LoginUser user = SecurityUtils.getLoginUser();
        Long[] deptIds = SecurityUtils.getDeptId();
        List<SysDept> sysDeptList = approveProcessService.selectDeptListByDeptIds(deptIds);
        return AjaxResult.success(sysDeptList);
        return R.ok(sysDeptList);
    }
    /**
@@ -50,13 +52,13 @@
    @PostMapping("/add")
    @Transactional(rollbackFor = Exception.class)
    @Operation(summary = "添加审批")
    public AjaxResult add(@RequestBody ApproveProcessVO approveProcessVO) throws Exception {
    public R<?> add(@RequestBody ApproveProcessVO approveProcessVO) throws Exception {
        if (approveProcessVO == null) {
            return AjaxResult.warn("参数不能为空");
            return R.fail(HttpStatus.WARN,"参数不能为空");
        }
        approveProcessService.addApprove(approveProcessVO);
        return AjaxResult.success("添加成功");
        return R.ok(null, "添加成功");
    }
    /**
@@ -66,11 +68,11 @@
     */
    @GetMapping("/get")
    @Operation(summary = "审批详情")
    public AjaxResult get(ApproveGetAndUpdateVo approveGetAndUpdateVo){
    public R<?> get(ApproveGetAndUpdateVo approveGetAndUpdateVo){
        if (approveGetAndUpdateVo.getId() == null || approveGetAndUpdateVo.getId().isEmpty()) {
            return AjaxResult.warn("参数不能为空");
            return R.fail(HttpStatus.WARN,"参数不能为空");
        }
        return AjaxResult.success(approveProcessService.getApproveById(approveGetAndUpdateVo.getId()));
        return R.ok(approveProcessService.getApproveById(approveGetAndUpdateVo.getId()));
    }
    /**
@@ -81,12 +83,12 @@
    @PostMapping("/update")
    @Transactional(rollbackFor = Exception.class)
    @Operation(summary = "更新审批")
    public AjaxResult update(@RequestBody ApproveGetAndUpdateVo approveGetAndUpdateVo) throws IOException {
    public R<?> update(@RequestBody ApproveGetAndUpdateVo approveGetAndUpdateVo) throws IOException {
        if (approveGetAndUpdateVo == null) {
            return AjaxResult.warn("参数不能为空");
            return R.fail(HttpStatus.WARN,"参数不能为空");
        }
        approveProcessService.updateByApproveId(approveGetAndUpdateVo);
        return AjaxResult.success("操作成功");
        return R.ok(null, "操作成功");
    }
    /**
     * èŽ·å–å®¡æ‰¹åˆ—è¡¨
@@ -94,8 +96,8 @@
     */
    @GetMapping("/list")
    @Operation(summary = "获取审批列表")
    public AjaxResult list(Page page, ApproveProcess approveProcess) {
        return AjaxResult.success(approveProcessService.listAll(page, approveProcess));
    public R<?> list(Page page, ApproveProcess approveProcess) {
        return R.ok(approveProcessService.listAll(page, approveProcess));
    }
    /**
@@ -106,12 +108,12 @@
    @DeleteMapping("/deleteIds")
    @Operation(summary = "删除审批")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult deleteIds(@RequestBody List<Long> ids) {
    public R<?> deleteIds(@RequestBody List<Long> ids) {
        if (ids == null || ids.size() == 0) {
            return AjaxResult.warn("参数不能为空");
            return R.fail(HttpStatus.WARN,"参数不能为空");
        }
        approveProcessService.delApprove(ids);
        return AjaxResult.success("操作成功");
        return R.ok(null, "操作成功");
    }
    @Operation(summary = "公出管理导出")
src/main/java/com/ruoyi/approve/controller/HolidaySettingsController.java
@@ -7,7 +7,8 @@
import com.ruoyi.approve.mapper.WorkingHoursSettingMapper;
import com.ruoyi.approve.pojo.*;
import com.ruoyi.approve.service.HolidaySettingsService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -17,7 +18,7 @@
@RestController
@RequestMapping("/holidaySettings")
@AllArgsConstructor
public class HolidaySettingsController {
public class HolidaySettingsController extends BaseController {
    private HolidaySettingsService holidaySettingsService;
    private AnnualLeaveSettingMapper annualLeaveSettingMapper;
    private OvertimeSettingMapper overtimeSettingMapper;
@@ -28,70 +29,70 @@
     * @return
     */
    @GetMapping("/getList")
    public AjaxResult getList(@RequestParam(defaultValue = "1") long current,
    public R<?> getList(@RequestParam(defaultValue = "1") long current,
                              @RequestParam(defaultValue = "50") long size, HolidaySettings holidaySettings) {
        Page page = new Page(current, size);
        return AjaxResult.success(holidaySettingsService.listpage(page,holidaySettings));
        return R.ok(holidaySettingsService.listpage(page,holidaySettings));
    }
    /**、
     * å¢žæ·»
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody HolidaySettings holidaySettings){
        return AjaxResult.success(holidaySettingsService.save(holidaySettings));
    public R<?> add(@RequestBody HolidaySettings holidaySettings){
        return R.ok(holidaySettingsService.save(holidaySettings));
    }
    /**
     * æ›´æ–°
     * @return
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestBody HolidaySettings holidaySettings){
        return AjaxResult.success(holidaySettingsService.updateById(holidaySettings));
    public R<?> update(@RequestBody HolidaySettings holidaySettings){
        return R.ok(holidaySettingsService.updateById(holidaySettings));
    }
    /**
     * åˆ é™¤
     * @return
     */
    @DeleteMapping("/delete")
    public AjaxResult delete(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("请传入要删除的ID");
        return AjaxResult.success(holidaySettingsService.removeByIds(ids));
    public R<?> delete(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return R.fail("请传入要删除的ID");
        return R.ok(holidaySettingsService.removeByIds(ids));
    }
    /**、
     * èŽ·å–å¹´å‡è§„åˆ™åˆ—è¡¨
     * @return
     */
    @GetMapping("/getAnnualLeaveSettingList")
    public AjaxResult getAnnualLeaveSettingList(@RequestParam(defaultValue = "1") long current,
    public R<?> getAnnualLeaveSettingList(@RequestParam(defaultValue = "1") long current,
                              @RequestParam(defaultValue = "50") long size, AnnualLeaveSetting annualLeaveSetting) {
        Page page = new Page(current, size);
        return AjaxResult.success(annualLeaveSettingMapper.listPage(page,annualLeaveSetting));
        return R.ok(annualLeaveSettingMapper.listPage(page,annualLeaveSetting));
    }
    /**、
     * å¢žæ·»å¹´å‡è§„则
     * @return
     */
    @PostMapping("/addAnnualLeaveSetting")
    public AjaxResult addAnnualLeaveSetting(@RequestBody AnnualLeaveSetting annualLeaveSetting){
        return AjaxResult.success(annualLeaveSettingMapper.insert(annualLeaveSetting));
    public R<?> addAnnualLeaveSetting(@RequestBody AnnualLeaveSetting annualLeaveSetting){
        return R.ok(annualLeaveSettingMapper.insert(annualLeaveSetting));
    }
    /**、
     * æ›´æ–°å¹´å‡è§„则
     * @return
     */
    @PostMapping("/updateAnnualLeaveSetting")
    public AjaxResult updateAnnualLeaveSetting(@RequestBody AnnualLeaveSetting annualLeaveSetting){
        return AjaxResult.success(annualLeaveSettingMapper.updateById(annualLeaveSetting));
    public R<?> updateAnnualLeaveSetting(@RequestBody AnnualLeaveSetting annualLeaveSetting){
        return R.ok(annualLeaveSettingMapper.updateById(annualLeaveSetting));
    }
    /**、
     * åˆ é™¤å¹´å‡è§„则
     * @return
     */
    @DeleteMapping("/deleteAnnualLeaveSetting")
    public AjaxResult deleteAnnualLeaveSetting(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("请传入要删除的ID");
        return AjaxResult.success(annualLeaveSettingMapper.deleteBatchIds(ids));
    public R<?> deleteAnnualLeaveSetting(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return R.fail("请传入要删除的ID");
        return R.ok(annualLeaveSettingMapper.deleteBatchIds(ids));
    }
    /**、
@@ -99,70 +100,70 @@
     * @return
     */
    @GetMapping("/getOvertimeSettingList")
    public AjaxResult getOvertimeSettingList(@RequestParam(defaultValue = "1") long current,
    public R<?> getOvertimeSettingList(@RequestParam(defaultValue = "1") long current,
                              @RequestParam(defaultValue = "50") long size, OvertimeSetting overtimeSetting) {
        Page page = new Page(current, size);
        return AjaxResult.success(overtimeSettingMapper.listPage(page,overtimeSetting));
        return R.ok(overtimeSettingMapper.listPage(page,overtimeSetting));
    }
    /**、
     * å¢žæ·»åŠ ç­è§„åˆ™
     * @return
     */
    @PostMapping("/addOvertimeSetting")
    public AjaxResult addOvertimeSetting(@RequestBody OvertimeSetting overtimeSetting){
        return AjaxResult.success(overtimeSettingMapper.insert(overtimeSetting));
    public R<?> addOvertimeSetting(@RequestBody OvertimeSetting overtimeSetting){
        return R.ok(overtimeSettingMapper.insert(overtimeSetting));
    }
    /**、
     * æ›´æ–°åŠ ç­è§„åˆ™
     * @return
     */
    @PostMapping("/updateOvertimeSetting")
    public AjaxResult updateOvertimeSetting(@RequestBody OvertimeSetting overtimeSetting){
        return AjaxResult.success(overtimeSettingMapper.updateById(overtimeSetting));
    public R<?> updateOvertimeSetting(@RequestBody OvertimeSetting overtimeSetting){
        return R.ok(overtimeSettingMapper.updateById(overtimeSetting));
    }
    /**、
     * åˆ é™¤åŠ ç­è§„åˆ™
     * @return
     */
    @DeleteMapping("/deleteOvertimeSetting")
    public AjaxResult deleteOvertimeSetting(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("请传入要删除的ID");
        return AjaxResult.success(overtimeSettingMapper.deleteBatchIds(ids));
    public R<?> deleteOvertimeSetting(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return R.fail("请传入要删除的ID");
        return R.ok(overtimeSettingMapper.deleteBatchIds(ids));
    }
    /**、
     * èŽ·å–ä¸Šç­æ—¶é—´è®¾ç½®-班制规则列表
     * @return
     */
    @GetMapping("/getWorkingHoursSettingList")
    public AjaxResult getWorkingHoursSettingList(@RequestParam(defaultValue = "1") long current,
    public R<?> getWorkingHoursSettingList(@RequestParam(defaultValue = "1") long current,
                              @RequestParam(defaultValue = "50") long size, WorkingHoursSetting workingHoursSetting) {
        Page page = new Page(current, size);
        return AjaxResult.success(workingHoursSettingMapper.listPage(page,workingHoursSetting));
        return R.ok(workingHoursSettingMapper.listPage(page,workingHoursSetting));
    }
    /**、
     * å¢žæ·»ç­åˆ¶è§„则
     * @return
     */
    @PostMapping("/addWorkingHoursSetting")
    public AjaxResult addWorkingHoursSetting(@RequestBody WorkingHoursSetting workingHoursSetting){
        return AjaxResult.success(workingHoursSettingMapper.insert(workingHoursSetting));
    public R<?> addWorkingHoursSetting(@RequestBody WorkingHoursSetting workingHoursSetting){
        return R.ok(workingHoursSettingMapper.insert(workingHoursSetting));
    }
    /**、
     * æ›´æ–°ç­åˆ¶è§„则
     * @return
     */
    @PostMapping("/updateWorkingHoursSetting")
    public AjaxResult updateWorkingHoursSetting(@RequestBody WorkingHoursSetting workingHoursSetting){
        return AjaxResult.success(workingHoursSettingMapper.updateById(workingHoursSetting));
    public R<?> updateWorkingHoursSetting(@RequestBody WorkingHoursSetting workingHoursSetting){
        return R.ok(workingHoursSettingMapper.updateById(workingHoursSetting));
    }
    /**、
     * åˆ é™¤ç­åˆ¶è§„则
     * @return
     */
    @DeleteMapping("/deleteWorkingHoursSetting")
    public AjaxResult deleteWorkingHoursSetting(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("请传入要删除的ID");
        return AjaxResult.success(workingHoursSettingMapper.deleteBatchIds(ids));
    public R<?> deleteWorkingHoursSetting(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return R.fail("请传入要删除的ID");
        return R.ok(workingHoursSettingMapper.deleteBatchIds(ids));
    }
src/main/java/com/ruoyi/approve/controller/KnowledgeBaseController.java
@@ -5,7 +5,8 @@
import com.ruoyi.approve.pojo.KnowledgeBase;
import com.ruoyi.approve.service.KnowledgeBaseService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
@@ -18,7 +19,7 @@
@RequestMapping("/knowledgeBase")
@AllArgsConstructor
@Tag(name = "知识库管理")
public class KnowledgeBaseController {
public class KnowledgeBaseController extends BaseController {
    private KnowledgeBaseService knowledgeBaseService;
    /**、
@@ -26,35 +27,35 @@
     * @return
     */
    @GetMapping("/getList")
    public AjaxResult getList(@RequestParam(defaultValue = "1") long current,
    public R<?> getList(@RequestParam(defaultValue = "1") long current,
                              @RequestParam(defaultValue = "10") long size, KnowledgeBase knowledgeBase) {
        Page page = new Page(current, size);
        return AjaxResult.success(knowledgeBaseService.listpage(page,knowledgeBase));
        return R.ok(knowledgeBaseService.listpage(page,knowledgeBase));
    }
    /**、
     * å¢žæ·»
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody KnowledgeBase knowledgeBase){
        return AjaxResult.success(knowledgeBaseService.save(knowledgeBase));
    public R<?> add(@RequestBody KnowledgeBase knowledgeBase){
        return R.ok(knowledgeBaseService.save(knowledgeBase));
    }
    /**
     * æ›´æ–°
     * @return
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestBody KnowledgeBase knowledgeBase){
        return AjaxResult.success(knowledgeBaseService.updateById(knowledgeBase));
    public R<?> update(@RequestBody KnowledgeBase knowledgeBase){
        return R.ok(knowledgeBaseService.updateById(knowledgeBase));
    }
    /**
     * åˆ é™¤
     * @return
     */
    @DeleteMapping("/delete")
    public AjaxResult delete(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("请传入要删除的ID");
        return AjaxResult.success(knowledgeBaseService.removeByIds(ids));
    public R<?> delete(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return R.fail("请传入要删除的ID");
        return R.ok(knowledgeBaseService.removeByIds(ids));
    }
    @Operation(summary = "知识库管理导出")
src/main/java/com/ruoyi/approve/controller/NotificationManagementController.java
@@ -8,7 +8,8 @@
import com.ruoyi.approve.pojo.NotificationManagement;
import com.ruoyi.approve.pojo.OnlineMeeting;
import com.ruoyi.approve.service.NotificationManagementService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -18,7 +19,7 @@
@RestController
@RequestMapping("/notificationManagement")
@AllArgsConstructor
public class NotificationManagementController {
public class NotificationManagementController extends BaseController {
    private NotificationManagementService notificationManagementService ;
    private OnlineMeetingMapper onlineMeetingMapper;
    private FileSharingMapper fileSharingMapper;
@@ -27,35 +28,35 @@
     * @return
     */
    @GetMapping("/getList")
    public AjaxResult getList(@RequestParam(defaultValue = "1") long current,
    public R<?> getList(@RequestParam(defaultValue = "1") long current,
                              @RequestParam(defaultValue = "50") long size, NotificationManagement notificationManagement) {
        Page page = new Page(current, size);
        return AjaxResult.success(notificationManagementService.listpage(page,notificationManagement));
        return R.ok(notificationManagementService.listpage(page,notificationManagement));
    }
    /**、
     * å¢žæ·»
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody NotificationManagement notificationManagement){
        return AjaxResult.success(notificationManagementService.save(notificationManagement));
    public R<?> add(@RequestBody NotificationManagement notificationManagement){
        return R.ok(notificationManagementService.save(notificationManagement));
    }
    /**
     * æ›´æ–°
     * @return
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestBody NotificationManagement notificationManagement){
        return AjaxResult.success(notificationManagementService.updateById(notificationManagement));
    public R<?> update(@RequestBody NotificationManagement notificationManagement){
        return R.ok(notificationManagementService.updateById(notificationManagement));
    }
    /**
     * åˆ é™¤
     * @return
     */
    @DeleteMapping("/delete")
    public AjaxResult delete(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("请传入要删除的ID");
        return AjaxResult.success(notificationManagementService.removeByIds(ids));
    public R<?> delete(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return R.fail("请传入要删除的ID");
        return R.ok(notificationManagementService.removeByIds(ids));
    }
    /**
     *新增会议
@@ -63,16 +64,16 @@
     * @return
     */
    @PostMapping("/addOnlineMeeting")
    public AjaxResult addOnlineMeeting(@RequestBody OnlineMeeting onlineMeeting){
        return AjaxResult.success(onlineMeetingMapper.insert(onlineMeeting));
    public R<?> addOnlineMeeting(@RequestBody OnlineMeeting onlineMeeting){
        return R.ok(onlineMeetingMapper.insert(onlineMeeting));
    }
    /**
     *新增文件共享
     *
     */
    @PostMapping("/addFileSharing")
    public AjaxResult addFileSharing(@RequestBody FileSharing fileSharing){
        return AjaxResult.success(fileSharingMapper.insert(fileSharing));
    public R<?> addFileSharing(@RequestBody FileSharing fileSharing){
        return R.ok(fileSharingMapper.insert(fileSharing));
    }
}
src/main/java/com/ruoyi/approve/controller/RpaProcessAutomationController.java
@@ -5,7 +5,8 @@
import com.ruoyi.approve.pojo.RpaProcessAutomation;
import com.ruoyi.approve.service.RpaProcessAutomationService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
@@ -18,42 +19,42 @@
@RequestMapping("/rpaProcessAutomation")
@AllArgsConstructor
@Tag(name = "RPA流程自动化")
public class RpaProcessAutomationController {
public class RpaProcessAutomationController extends BaseController {
    private RpaProcessAutomationService rpaProcessAutomationService;
    /**、
     * èŽ·å–åˆ—è¡¨
     * @return
     */
    @GetMapping("/getList")
    public AjaxResult getList(@RequestParam(defaultValue = "1") long current,
    public R<?> getList(@RequestParam(defaultValue = "1") long current,
                              @RequestParam(defaultValue = "100") long size, RpaProcessAutomation rpaProcessAutomation) {
        Page page = new Page(current, size);
        return AjaxResult.success(rpaProcessAutomationService.listpage(page,rpaProcessAutomation));
        return R.ok(rpaProcessAutomationService.listpage(page,rpaProcessAutomation));
    }
    /**、
     * å¢žæ·»
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody RpaProcessAutomation rpaProcessAutomation){
        return AjaxResult.success(rpaProcessAutomationService.save(rpaProcessAutomation));
    public R<?> add(@RequestBody RpaProcessAutomation rpaProcessAutomation){
        return R.ok(rpaProcessAutomationService.save(rpaProcessAutomation));
    }
    /**
     * æ›´æ–°
     * @return
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestBody RpaProcessAutomation rpaProcessAutomation){
        return AjaxResult.success(rpaProcessAutomationService.updateById(rpaProcessAutomation));
    public R<?> update(@RequestBody RpaProcessAutomation rpaProcessAutomation){
        return R.ok(rpaProcessAutomationService.updateById(rpaProcessAutomation));
    }
    /**
     * åˆ é™¤
     * @return
     */
    @DeleteMapping("/delete")
    public AjaxResult delete(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("请传入要删除的ID");
        return AjaxResult.success(rpaProcessAutomationService.removeByIds(ids));
    public R<?> delete(@RequestBody List<Long> ids){
        if(CollectionUtils.isEmpty(ids)) return R.fail("请传入要删除的ID");
        return R.ok(rpaProcessAutomationService.removeByIds(ids));
    }
    @Operation(summary = "RPA流程自动化导出")
src/main/java/com/ruoyi/basic/controller/CustomerFollowUpController.java
@@ -11,7 +11,7 @@
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 io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
@@ -55,8 +55,8 @@
     */
    @Operation(summary = "获取客户跟进详细信息")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Integer id) {
        return AjaxResult.success(customerFollowUpService.getFollowUpWithFiles(id));
    public R getInfo(@PathVariable("id") Integer id) {
        return R.ok(customerFollowUpService.getFollowUpWithFiles(id));
    }
    /**
@@ -65,8 +65,8 @@
    @PostMapping("/add")
    @Operation(summary = "新增客户跟进")
    @Log(title = "客户跟进-新增", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody CustomerFollowUp customerFollowUp) {
        return toAjax(customerFollowUpService.insertCustomerFollowUp(customerFollowUp));
    public R<?> add(@RequestBody CustomerFollowUp customerFollowUp) {
        return R.ok();
    }
    /**
@@ -75,8 +75,8 @@
    @PutMapping("/edit")
    @Operation(summary = "修改客户跟进")
    @Log(title = "客户跟进-修改", businessType = BusinessType.UPDATE)
    public AjaxResult edit(@RequestBody CustomerFollowUp customerFollowUp) {
        return toAjax(customerFollowUpService.updateCustomerFollowUp(customerFollowUp));
    public R<?> edit(@RequestBody CustomerFollowUp customerFollowUp) {
        return R.ok();
    }
    /**
@@ -85,8 +85,8 @@
    @Operation(summary = "上传跟进附件")
    @PostMapping("/upload/{followUpId}")
    @Log(title = "客户跟进-上传附件", businessType = BusinessType.INSERT)
    public AjaxResult uploadFiles(@RequestParam("files") List<MultipartFile> files, @PathVariable Integer followUpId) {
        return AjaxResult.success(customerFollowUpService.addFollowUpFiles(files, followUpId));
    public R uploadFiles(@RequestParam("files") List<MultipartFile> files, @PathVariable Integer followUpId) {
        return R.ok(customerFollowUpService.addFollowUpFiles(files, followUpId));
    }
    /**
@@ -95,9 +95,9 @@
    @Operation(summary = "上传附件(复用)")
    @PostMapping("/upload")
    @Log(title = "上传附件(复用)", businessType = BusinessType.INSERT)
    public AjaxResult uploadFiles(@RequestParam("files") List<MultipartFile> files, @RequestParam(required = false) String name) {
    public R uploadFiles(@RequestParam("files") List<MultipartFile> files, @RequestParam(required = false) String name) {
        List<CustomerFollowUpFileDto> uploadedFiles = customerFollowUpService.addFollowUpFiles(files, null);
        return AjaxResult.success(uploadedFiles);
        return R.ok(uploadedFiles);
    }
    /**
@@ -105,8 +105,8 @@
     */
    @Operation(summary = "批量查询附件列表")
    @PostMapping("/file/list")
    public AjaxResult getFileList(@RequestBody List<Long> ids) {
        return AjaxResult.success(customerFollowUpService.getFollowUpFilesByIds(ids));
    public R getFileList(@RequestBody List<Long> ids) {
        return R.ok(customerFollowUpService.getFollowUpFilesByIds(ids));
    }
    /**
@@ -115,9 +115,9 @@
    @Operation(summary = "删除跟进附件")
    @DeleteMapping("/file/{fileId}")
    @Log(title = "客户跟进-删除附件", businessType = BusinessType.DELETE)
    public AjaxResult deleteFile(@PathVariable Integer fileId) {
    public R deleteFile(@PathVariable Integer fileId) {
        customerFollowUpService.deleteFollowUpFile(fileId);
        return AjaxResult.success();
        return R.ok();
    }
    /**
@@ -126,8 +126,8 @@
    @Operation(summary = "删除客户跟进")
    @DeleteMapping("/{id}")
    @Log(title = "客户跟进-删除", businessType = BusinessType.DELETE)
    public AjaxResult remove(@PathVariable Integer id) {
        return toAjax(customerFollowUpService.deleteCustomerFollowUpById(id));
    public R remove(@PathVariable Integer id) {
        return R.ok(customerFollowUpService.deleteCustomerFollowUpById(id));
    }
    /**
@@ -136,8 +136,8 @@
    @Operation(summary = "新增/更新回访提醒")
    @PostMapping("/return-visit")
    @Log(title = "回访提醒-新增/更新", businessType = BusinessType.UPDATE)
    public AjaxResult saveReturnVisit(@RequestBody CustomerReturnVisit customerReturnVisit) {
        return toAjax(customerReturnVisitService.saveOrUpdateReturnVisit(customerReturnVisit));
    public R saveReturnVisit(@RequestBody CustomerReturnVisit customerReturnVisit) {
        return  R.ok(customerReturnVisitService.saveOrUpdateReturnVisit(customerReturnVisit));
    }
    /**
@@ -145,8 +145,8 @@
     */
    @Operation(summary = "获取回访提醒详情")
    @GetMapping("/return-visit/{customerId}")
    public AjaxResult getReturnVisit(@PathVariable Integer customerId) {
        return AjaxResult.success(customerReturnVisitService.getByCustomerId(customerId));
    public R getReturnVisit(@PathVariable Integer customerId) {
        return R.ok(customerReturnVisitService.getByCustomerId(customerId));
    }
    /**
@@ -155,9 +155,9 @@
    @Operation(summary = "标记回访提醒已读")
    @PutMapping("/return-visit/read/{id}")
    @Log(title = "回访提醒-标记已读", businessType = BusinessType.UPDATE)
    public AjaxResult markAsRead(@PathVariable Long id) {
    public R markAsRead(@PathVariable Long id) {
        customerReturnVisitService.markAsRead(id);
        return AjaxResult.success();
        return R.ok();
    }
}
src/main/java/com/ruoyi/basic/controller/ProductController.java
@@ -15,7 +15,7 @@
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.pojo.SalesLedgerProduct;
import com.ruoyi.sales.service.ISalesLedgerProductService;
import io.swagger.v3.oas.annotations.Operation;
@@ -55,8 +55,9 @@
     */
    @Log(title = "产品", businessType = BusinessType.INSERT)
    @PostMapping("/addOrEditProduct")
    public AjaxResult addOrEditProduct(@RequestBody ProductDto productDto) {
        return toAjax(productService.addOrEditProduct(productDto));
    public R<?> addOrEditProduct(@RequestBody ProductDto productDto) {
        productService.addOrEditProduct(productDto);
        return R.ok();
    }
    /**
@@ -64,8 +65,9 @@
     */
    @Log(title = "产品规格型号", businessType = BusinessType.INSERT)
    @PostMapping("/addOrEditProductModel")
    public AjaxResult addOrEditProductModel(@RequestBody ProductModelDto productModelDto) {
        return toAjax(productModelService.addOrEditProductModel(productModelDto));
    public R<?> addOrEditProductModel(@RequestBody ProductModelDto productModelDto) {
        productModelService.addOrEditProductModel(productModelDto);
        return R.ok();
    }
    /**
@@ -73,18 +75,19 @@
     */
    @Log(title = "产品", businessType = BusinessType.DELETE)
    @DeleteMapping("/delProduct")
    public AjaxResult remove(@RequestBody Long[] ids) {
    public R<?> remove(@RequestBody Long[] ids) {
        if (ids == null || ids.length == 0) {
            return AjaxResult.error("请传入要删除的ID");
            return R.fail("请传入要删除的ID");
        }
        // æ£€æŸ¥æ˜¯å¦æœ‰é”€å”®å•†å“è®°å½•关联该产品
        LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SalesLedgerProduct::getProductId, ids);
        List<SalesLedgerProduct> salesLedgerProductList = salesLedgerProductService.list(queryWrapper);
        if (salesLedgerProductList.size() > 0) {
            return AjaxResult.error("该产品存在销售/采购记录,不能删除");
            return R.fail("该产品存在销售/采购记录,不能删除");
        }
        return toAjax(productService.delProductByIds(ids));
        productService.delProductByIds(ids);
        return R.ok();
    }
    /**
@@ -92,18 +95,19 @@
     */
    @Log(title = "产品规格型号", businessType = BusinessType.DELETE)
    @DeleteMapping("/delProductModel")
    public AjaxResult delProductModel(@RequestBody Long[] ids) {
    public R<?> delProductModel(@RequestBody Long[] ids) {
        if (ids == null || ids.length == 0) {
            return AjaxResult.error("请传入要删除的ID");
            return R.fail("请传入要删除的ID");
        }
        // æ£€æŸ¥æ˜¯å¦æœ‰é”€å”®å•†å“è®°å½•关联该产品规格型号
        LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SalesLedgerProduct::getProductModelId, ids);
        List<SalesLedgerProduct> salesLedgerProductList = salesLedgerProductService.list(queryWrapper);
        if (salesLedgerProductList.size() > 0) {
            return AjaxResult.error("该产品规格型号存在销售/采购记录,不能删除");
            return R.fail("该产品规格型号存在销售/采购记录,不能删除");
        }
        return toAjax(productModelService.delProductModel(ids));
        productModelService.delProductModel(ids);
        return R.ok();
    }
    /**
@@ -125,7 +129,7 @@
     */
    @PostMapping("/import")
    @Log(title = "导入产品", businessType = BusinessType.IMPORT)
    public AjaxResult importProductModel(@RequestParam("file") MultipartFile file, Integer productId) {
    public R<?> importProductModel(@RequestParam("file") MultipartFile file, Integer productId) {
        return productModelService.importProductModel(file, productId);
    }
src/main/java/com/ruoyi/basic/controller/SupplierManageController.java
@@ -7,7 +7,7 @@
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 com.ruoyi.framework.web.domain.R;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.springframework.util.CollectionUtils;
@@ -29,9 +29,9 @@
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody SupplierManage supplierManage) {
    public R add(@RequestBody SupplierManage supplierManage) {
        supplierService.saveSupplier(supplierManage);
        return AjaxResult.success();
        return R.ok();
    }
    /**
@@ -40,12 +40,12 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delSupplier(@RequestBody List<Integer> ids) {
    public R delSupplier(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        supplierService.delSupplier(ids);
        return AjaxResult.success();
        return R.ok();
    }
    /**
@@ -54,8 +54,8 @@
     * @return
     */
    @GetMapping("/{id}")
    public AjaxResult supplierDetail(@PathVariable("id") Integer id) {
        return AjaxResult.success(supplierService.supplierDetail(id));
    public R supplierDetail(@PathVariable("id") Integer id) {
        return R.ok(supplierService.supplierDetail(id));
    }
    /**
@@ -64,9 +64,9 @@
     * @return
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestBody SupplierManage supplierManage) {
    public R update(@RequestBody SupplierManage supplierManage) {
        supplierService.supplierUpdate(supplierManage);
        return AjaxResult.success();
        return R.ok();
    }
    /**
@@ -76,8 +76,8 @@
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult supplierListPage(Page page, SupplierManageDto supplierManageDto) {
        return AjaxResult.success(supplierService.supplierListPage(page, supplierManageDto));
    public R supplierListPage(Page page, SupplierManageDto supplierManageDto) {
        return R.ok(supplierService.supplierListPage(page, supplierManageDto));
    }
    /**
@@ -102,12 +102,8 @@
     */
    @PostMapping("/import")
    @Log(title = "供应商导入", businessType = BusinessType.IMPORT)
    public AjaxResult importData(MultipartFile file) {
        Boolean b = supplierService.importData(file);
        if (b) {
            return AjaxResult.success("导入成功");
        }
        return AjaxResult.error("导入失败");
    public R importData(MultipartFile file) throws Exception {
       return supplierService.importData(file);
    }
@@ -116,7 +112,7 @@
     * @return
     */
    @GetMapping("/getOptions")
    public AjaxResult getOptions() {
        return AjaxResult.success(supplierService.list());
    public R getOptions() {
        return R.ok(supplierService.list());
    }
}
src/main/java/com/ruoyi/basic/controller/SupplierManageFileController.java
@@ -3,7 +3,8 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.pojo.SupplierManageFile;
import com.ruoyi.basic.service.SupplierManageFileService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
@@ -15,7 +16,7 @@
 */
@RestController
@RequestMapping("/basic/supplierManageFile")
public class SupplierManageFileController {
public class SupplierManageFileController extends BaseController {
    @Resource
@@ -28,8 +29,8 @@
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody SupplierManageFile supplierManageFile) {
        return AjaxResult.success(supplierManageFileService.save(supplierManageFile));
    public R<?> add(@RequestBody SupplierManageFile supplierManageFile) {
        return R.ok(supplierManageFileService.save(supplierManageFile));
    }
    /**
@@ -38,12 +39,12 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delSupplierManageFile(@RequestBody List<Integer> ids) {
    public R<?> delSupplierManageFile(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        //删除检验附件
        return AjaxResult.success(supplierManageFileService.removeBatchByIds(ids));
        return R.ok(supplierManageFileService.removeBatchByIds(ids));
    }
    /**
@@ -53,8 +54,8 @@
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult supplierManageFileListPage(Page page, SupplierManageFile supplierManageFile) {
        return AjaxResult.success(supplierManageFileService.supplierManageFileListPage(page, supplierManageFile));
    public R<?> supplierManageFileListPage(Page page, SupplierManageFile supplierManageFile) {
        return R.ok(supplierManageFileService.supplierManageFileListPage(page, supplierManageFile));
    }
src/main/java/com/ruoyi/basic/excel/SupplierManageExcelDto.java
@@ -15,6 +15,9 @@
    @Excel(name = "供应商名称")
    private String supplierName;
    @Excel(name = "供应商类型")
    private String supplierType;
    @Excel(name = "纳税人识别号")
    private String taxpayerIdentificationNum;
src/main/java/com/ruoyi/basic/pojo/SupplierManage.java
@@ -20,6 +20,11 @@
    @Excel(name = "供应商名称")
    private String supplierName;
    @Schema(description = "供应商类型")
    @TableField(value = "supplier_type")
    @Excel(name = "供应商类型")
    private String supplierType;
    @Schema(description = "纳税人识别号")
    @Excel(name = "纳税人识别号")
    private String taxpayerIdentificationNum;
@@ -79,10 +84,6 @@
    @Schema(description = "租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    @Schema(description = "供应商类型")
    @TableField(value = "supplier_type")
    private String supplierType;
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
src/main/java/com/ruoyi/basic/service/IProductModelService.java
@@ -6,7 +6,7 @@
import com.ruoyi.basic.dto.ProductDto;
import com.ruoyi.basic.dto.ProductModelDto;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@@ -34,5 +34,5 @@
     */
    IPage<ProductModel> modelListPage(Page page , ProductDto productDto);
    AjaxResult importProductModel(MultipartFile file, Integer productId);
    R<?> importProductModel(MultipartFile file, Integer productId);
}
src/main/java/com/ruoyi/basic/service/ISupplierService.java
@@ -5,7 +5,7 @@
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.framework.web.domain.R;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletResponse;
@@ -56,5 +56,5 @@
     */
    void supplierExport(HttpServletResponse response, SupplierManageDto supplierManageDto);
    Boolean importData(MultipartFile file);
    R importData(MultipartFile file);
}
src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
@@ -17,7 +17,7 @@
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.sales.dto.LossProductModelDto;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
@@ -124,14 +124,14 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult importProductModel(MultipartFile file, Integer productId) {
    public R<?> importProductModel(MultipartFile file, Integer productId) {
        if (productId == null) {
            return AjaxResult.error("请先选择产品再导入规格型号");
            return R.fail("请先选择产品再导入规格型号");
        }
        Product product = productMapper.selectById(productId);
        if (product == null) {
            return AjaxResult.error("选择的产品不存在");
            return R.fail("选择的产品不存在");
        }
        try {
@@ -139,7 +139,7 @@
            List<ProductModel> productModelList = productModelExcelUtil.importExcel(file.getInputStream());
            if (CollectionUtils.isEmpty(productModelList)) {
                return AjaxResult.error("导入数据不能为空");
                return R.fail("导入数据不能为空");
            }
            //  èŽ·å–å½“å‰äº§å“ä¸‹æ‰€æœ‰çš„è§„æ ¼åž‹å·å
@@ -154,13 +154,13 @@
                int rowNum = i + 2;
                if (StringUtils.isEmpty(item.getProductCode())) {
                    return AjaxResult.error("第 " + rowNum + " è¡Œå¯¼å…¥å¤±è´¥: [产品编码] ä¸èƒ½ä¸ºç©º");
                    return R.fail("第 " + rowNum + " è¡Œå¯¼å…¥å¤±è´¥: [产品编码] ä¸èƒ½ä¸ºç©º");
                }
                if (StringUtils.isEmpty(item.getModel())) {
                    return AjaxResult.error("第 " + rowNum + " è¡Œå¯¼å…¥å¤±è´¥: [规格型号] ä¸èƒ½ä¸ºç©º");
                    return R.fail("第 " + rowNum + " è¡Œå¯¼å…¥å¤±è´¥: [规格型号] ä¸èƒ½ä¸ºç©º");
                }
                if (StringUtils.isEmpty(item.getUnit())) {
                    return AjaxResult.error("第 " + rowNum + " è¡Œå¯¼å…¥å¤±è´¥: [单位] ä¸èƒ½ä¸ºç©º");
                    return R.fail("第 " + rowNum + " è¡Œå¯¼å…¥å¤±è´¥: [单位] ä¸èƒ½ä¸ºç©º");
                }
                //  åŽ»é‡,如果已包含该型号,则跳过
@@ -180,9 +180,9 @@
            }
            if (skipCount == 0) {
                return AjaxResult.success(String.format("成功导入 %d æ¡æ•°æ®", waitToSaveList.size()));
                return R.ok(null, String.format("成功导入 %d æ¡æ•°æ®", waitToSaveList.size()));
            } else {
                return AjaxResult.success(String.format("成功导入 %d æ¡ï¼Œè·³è¿‡å·²å­˜åœ¨æ•°æ® %d æ¡", waitToSaveList.size(), skipCount));
                return R.ok(null, String.format("成功导入 %d æ¡ï¼Œè·³è¿‡å·²å­˜åœ¨æ•°æ® %d æ¡", waitToSaveList.size(), skipCount));
            }
        } catch (Exception e) {
            log.error("导入产品规格异常", e);
src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java
@@ -3,6 +3,7 @@
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.basic.dto.SupplierManageDto;
@@ -12,6 +13,8 @@
import com.ruoyi.basic.service.ISupplierService;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.project.system.mapper.SysDictDataMapper;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import jakarta.servlet.http.HttpServletResponse;
@@ -30,6 +33,7 @@
    private final SupplierManageMapper supplierMapper;
    private final PurchaseLedgerMapper purchaseLedgerMapper;
    private final SysDictDataMapper sysDictDataMapper;
    /**
     * ä¾›åº”商新增
@@ -107,13 +111,22 @@
    }
    @Override
    public Boolean importData(MultipartFile file) {
    public R importData(MultipartFile file) {
        try {
            ExcelUtil<SupplierManageExcelDto> util = new ExcelUtil<SupplierManageExcelDto>(SupplierManageExcelDto.class);
            List<SupplierManageExcelDto> list = util.importExcel(file.getInputStream());
            if (CollectionUtils.isEmpty(list)) {
                return R.fail("模板错误或导入数据为空");
            }
            ArrayList<SupplierManage> supplierManages = new ArrayList<>();
            list.stream().forEach(dto -> {
                // ä¾›åº”商类型是否存在 ï¼ˆç”²ä¹™ä¸™ä¸ï¼‰
                String supplierType = dto.getSupplierType();
                if (!supplierType.equals("甲") && !supplierType.equals("乙") && !supplierType.equals("丙") && !supplierType.equals("丁")) {
                    throw new RuntimeException("供应商类型 " + supplierType + " ä¸å­˜åœ¨ï¼");
                }
                SupplierManage supplierManage = new SupplierManage();
                BeanUtils.copyProperties(dto,supplierManage);
                supplierManage.setMaintainTime(LocalDate.now());
@@ -124,10 +137,10 @@
            });
            this.saveOrUpdateBatch(supplierManages);
            return true;
            return R.ok("导入成功");
        }catch (Exception e){
            e.printStackTrace();
            return R.fail(e.getMessage());
        }
        return false;
    }
}
src/main/java/com/ruoyi/collaborativeApproval/controller/DutyPlanController.java
@@ -7,7 +7,8 @@
import com.ruoyi.collaborativeApproval.pojo.RulesRegulationsManagement;
import com.ruoyi.collaborativeApproval.service.DutyPlanService;
import com.ruoyi.common.utils.excel.ExcelUtils;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
@@ -20,39 +21,39 @@
@RestController
@RequestMapping("/dutyPlan")
@AllArgsConstructor
public class DutyPlanController {
public class DutyPlanController extends BaseController {
    private DutyPlanService dutyPlanService;
    @GetMapping("/getList")
    @Operation(summary = "分页查询")
    public AjaxResult listPage(Page page, DutyPlanDTO dutyPlanDTO){
        return AjaxResult.success(dutyPlanService.listPage(page, dutyPlanDTO));
    public R<?> listPage(Page page, DutyPlanDTO dutyPlanDTO){
        return R.ok(dutyPlanService.listPage(page, dutyPlanDTO));
    }
    @GetMapping("/getNum")
    @Operation(summary = "获取等级数据")
    public AjaxResult getNum(){
        return AjaxResult.success(dutyPlanService.getNum());
    public R<?> getNum(){
        return R.ok(dutyPlanService.getNum());
    }
    @PostMapping("/add")
    @Operation(summary = "新增")
    public AjaxResult add(@RequestBody DutyPlan dutyPlan){
        return AjaxResult.success(dutyPlanService.save(dutyPlan));
    public R<?> add(@RequestBody DutyPlan dutyPlan){
        return R.ok(dutyPlanService.save(dutyPlan));
    }
    @PostMapping("/update")
    @Operation(summary = "修改")
    public AjaxResult update(@RequestBody DutyPlan dutyPlan){
        return AjaxResult.success(dutyPlanService.updateById(dutyPlan));
    public R<?> update(@RequestBody DutyPlan dutyPlan){
        return R.ok(dutyPlanService.updateById(dutyPlan));
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除")
    public AjaxResult delete(@RequestBody List<Long> ids){
    public R<?> delete(@RequestBody List<Long> ids){
        if (CollectionUtils.isEmpty(ids)) {
            throw new RuntimeException("请传入要删除的ID");
        }
        return AjaxResult.success(dutyPlanService.removeBatchByIds(ids));
        return R.ok(dutyPlanService.removeBatchByIds(ids));
    }
    @PostMapping("/export")
    @Operation(summary = "导出")
src/main/java/com/ruoyi/collaborativeApproval/controller/NoticeController.java
@@ -9,7 +9,7 @@
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.project.system.service.ISysNoticeService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
@@ -32,27 +32,27 @@
    @GetMapping("/page")
    @Log(title = "分页查询", businessType = BusinessType.OTHER)
    @Operation(summary = "分页查询")
    public AjaxResult listPage(Page page, NoticeDTO noticeDTO){
        return AjaxResult.success(noticeService.listPage(page, noticeDTO));
    public R<?> listPage(Page page, NoticeDTO noticeDTO){
        return R.ok(noticeService.listPage(page, noticeDTO));
    }
    @PostMapping("/add")
    @Log(title = "新增", businessType = BusinessType.INSERT)
    @Operation(summary = "新增")
    public AjaxResult add(@RequestBody NoticeDTO noticeDTO){
    public R<?> add(@RequestBody NoticeDTO noticeDTO){
        if (noticeDTO.getStatus()==1){
            //正式发布通知所有人的消息通知
            sysNoticeService.simpleNoticeAll("通知公告",
                    noticeDTO.getTitle(),
                    "/collaborativeApproval/noticeManagement?type="+noticeDTO.getType());
        }
        return AjaxResult.success(noticeService.save(noticeDTO));
        return R.ok(noticeService.save(noticeDTO));
    }
    @PutMapping("/update")
    @Log(title = "修改", businessType = BusinessType.UPDATE)
    @Operation(summary = "修改")
    public AjaxResult update(@RequestBody NoticeDTO noticeDTO){
    public R<?> update(@RequestBody NoticeDTO noticeDTO){
        if (ObjectUtils.isNotNull(noticeDTO.getStatus()) && noticeDTO.getStatus()==1){
            Notice notice = noticeService.getById(noticeDTO.getId());
            //正式发布通知所有人的消息通知
@@ -60,23 +60,23 @@
                    notice.getTitle(),
                    "/collaborativeApproval/noticeManagement?type="+notice.getType());
        }
        return AjaxResult.success(noticeService.updateById(noticeDTO));
        return R.ok(noticeService.updateById(noticeDTO));
    }
    @DeleteMapping("/{ids}")
    @Log(title = "删除", businessType = BusinessType.DELETE)
    @Operation(summary = "删除")
    public AjaxResult delete(@PathVariable("ids") List<Long> ids){
    public R<?> delete(@PathVariable("ids") List<Long> ids){
        if (CollectionUtils.isEmpty(ids)) {
            throw new RuntimeException("请传入要删除的ID");
        }
        return AjaxResult.success(noticeService.removeBatchByIds(ids));
        return R.ok(noticeService.removeBatchByIds(ids));
    }
    @GetMapping("/count")
    @Log(title = "获取公告数量", businessType = BusinessType.OTHER)
    @Operation(summary = "获取公告数量")
    public AjaxResult count(){
        return AjaxResult.success(noticeService.selectCount());
    public R<?> count(){
        return R.ok(noticeService.selectCount());
    }
}
src/main/java/com/ruoyi/collaborativeApproval/controller/NoticeTypeController.java
@@ -5,7 +5,8 @@
import com.ruoyi.basic.pojo.SupplierManage;
import com.ruoyi.collaborativeApproval.pojo.NoticeType;
import com.ruoyi.collaborativeApproval.service.NoticeTypeService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
@@ -24,7 +25,7 @@
@RestController
@RequestMapping("/noticeType")
@AllArgsConstructor
public class NoticeTypeController {
public class NoticeTypeController extends BaseController {
    private NoticeTypeService noticeTypeService;
@@ -34,8 +35,8 @@
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody NoticeType noticeType) {
        return AjaxResult.success(noticeTypeService.saveOrUpdate(noticeType));
    public R<?> add(@RequestBody NoticeType noticeType) {
        return R.ok(noticeTypeService.saveOrUpdate(noticeType));
    }
    /**
@@ -44,11 +45,11 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delNoticeType(@RequestBody List<Integer> ids) {
    public R<?> delNoticeType(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        return AjaxResult.success(noticeTypeService.removeBatchByIds(ids));
        return R.ok(noticeTypeService.removeBatchByIds(ids));
    }
    /**
@@ -56,8 +57,8 @@
     * @return
     */
    @GetMapping("/list")
    public AjaxResult noticeTypeList() {
        return AjaxResult.success(noticeTypeService.list());
    public R<?> noticeTypeList() {
        return R.ok(noticeTypeService.list());
    }
}
src/main/java/com/ruoyi/collaborativeApproval/controller/RulesRegulationsManagementController.java
@@ -8,7 +8,8 @@
import com.ruoyi.collaborativeApproval.pojo.SealApplicationManagement;
import com.ruoyi.collaborativeApproval.service.RulesRegulationsManagementService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
@@ -23,57 +24,57 @@
@RequestMapping("/rulesRegulationsManagement")
@AllArgsConstructor
@Tag(name = "制度管理")
public class RulesRegulationsManagementController {
public class RulesRegulationsManagementController extends BaseController {
    private RulesRegulationsManagementService rulesRegulationsManagementService;
    private ReadingStatusMapper readingStatusMapper;
    @GetMapping("/getList")
    @Operation(summary = "分页查询")
    public AjaxResult listPage(Page page, RulesRegulationsManagement rulesRegulationsManagement){
        return AjaxResult.success(rulesRegulationsManagementService.listPage(page, rulesRegulationsManagement));
    public R<?> listPage(Page page, RulesRegulationsManagement rulesRegulationsManagement){
        return R.ok(rulesRegulationsManagementService.listPage(page, rulesRegulationsManagement));
    }
    @PostMapping("/add")
    @Operation(summary = "新增")
    public AjaxResult add(@RequestBody RulesRegulationsManagement rulesRegulationsManagement){
    public R<?> add(@RequestBody RulesRegulationsManagement rulesRegulationsManagement){
        rulesRegulationsManagementService.save(rulesRegulationsManagement);
        return AjaxResult.success(rulesRegulationsManagement.getId());
        return R.ok(rulesRegulationsManagement.getId());
    }
    @PostMapping("/update")
    @Operation(summary = "修改")
    public AjaxResult update(@RequestBody RulesRegulationsManagement rulesRegulationsManagement){
        return AjaxResult.success(rulesRegulationsManagementService.updateById(rulesRegulationsManagement));
    public R<?> update(@RequestBody RulesRegulationsManagement rulesRegulationsManagement){
        return R.ok(rulesRegulationsManagementService.updateById(rulesRegulationsManagement));
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除")
    public AjaxResult delete(@PathVariable("ids") List<Long> ids){
    public R<?> delete(@PathVariable("ids") List<Long> ids){
        if (CollectionUtils.isEmpty(ids)) {
            throw new RuntimeException("请传入要删除的ID");
        }
        return AjaxResult.success(rulesRegulationsManagementService.removeBatchByIds(ids));
        return R.ok(rulesRegulationsManagementService.removeBatchByIds(ids));
    }
    //规则查看时新增阅读状态
    @PostMapping("/addReadingStatus")
    @Operation(summary = "新增阅读状态")
    public AjaxResult addReadingStatus(@RequestBody ReadingStatus readingStatus){
        return AjaxResult.success(readingStatusMapper.insert(readingStatus));
    public R<?> addReadingStatus(@RequestBody ReadingStatus readingStatus){
        return R.ok(readingStatusMapper.insert(readingStatus));
    }
    @PostMapping("/updateReadingStatus")
    @Operation(summary = "修改阅读状态")
    public AjaxResult updateReadingStatus(@RequestBody ReadingStatus readingStatus){
        return AjaxResult.success(readingStatusMapper.updateById(readingStatus));
    public R<?> updateReadingStatus(@RequestBody ReadingStatus readingStatus){
        return R.ok(readingStatusMapper.updateById(readingStatus));
    }
    @GetMapping("/getReadingStatusList")
    @Operation(summary = "分页查询阅读状态")
    public AjaxResult listPage(Page page, ReadingStatus readingStatus){
        return AjaxResult.success(readingStatusMapper.selectPage(page,new QueryWrapper<ReadingStatus>(readingStatus)));
    public R<?> listPage(Page page, ReadingStatus readingStatus){
        return R.ok(readingStatusMapper.selectPage(page,new QueryWrapper<ReadingStatus>(readingStatus)));
    }
    @GetMapping("/getReadingStatusByRuleId/{ruleId}")
    @Operation(summary = "根据制度id查询阅读状态")
    public AjaxResult getReadingStatusByRuleId(@PathVariable Long ruleId){
        return AjaxResult.success(readingStatusMapper.selectList(new QueryWrapper<ReadingStatus>().eq("rule_id", ruleId)));
    public R<?> getReadingStatusByRuleId(@PathVariable Long ruleId){
        return R.ok(readingStatusMapper.selectList(new QueryWrapper<ReadingStatus>().eq("rule_id", ruleId)));
    }
    @Operation(summary = "规章制度管理导出")
src/main/java/com/ruoyi/collaborativeApproval/controller/RulesRegulationsManagementFileController.java
@@ -3,7 +3,8 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.collaborativeApproval.pojo.RulesRegulationsManagementFile;
import com.ruoyi.collaborativeApproval.service.RulesRegulationsManagementFileService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.quality.pojo.QualityInspectFile;
import com.ruoyi.quality.service.IQualityInspectFileService;
import org.springframework.util.CollectionUtils;
@@ -22,7 +23,7 @@
 */
@RestController
@RequestMapping("/rulesRegulationsManagementFile")
public class RulesRegulationsManagementFileController {
public class RulesRegulationsManagementFileController extends BaseController {
    @Resource
    private RulesRegulationsManagementFileService rulesRegulationsManagementFileService;
@@ -34,8 +35,8 @@
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody RulesRegulationsManagementFile rulesRegulationsManagementFile) {
        return AjaxResult.success(rulesRegulationsManagementFileService.save(rulesRegulationsManagementFile));
    public R<?> add(@RequestBody RulesRegulationsManagementFile rulesRegulationsManagementFile) {
        return R.ok(rulesRegulationsManagementFileService.save(rulesRegulationsManagementFile));
    }
    /**
@@ -44,12 +45,12 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delQualityUnqualified(@RequestBody List<Integer> ids) {
    public R<?> delQualityUnqualified(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        //删除检验附件
        return AjaxResult.success(rulesRegulationsManagementFileService.removeBatchByIds(ids));
        return R.ok(rulesRegulationsManagementFileService.removeBatchByIds(ids));
    }
    /**
@@ -59,8 +60,8 @@
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult listPage(Page page, RulesRegulationsManagementFile rulesRegulationsManagementFile) {
        return AjaxResult.success(rulesRegulationsManagementFileService.listPage(page, rulesRegulationsManagementFile));
    public R<?> listPage(Page page, RulesRegulationsManagementFile rulesRegulationsManagementFile) {
        return R.ok(rulesRegulationsManagementFileService.listPage(page, rulesRegulationsManagementFile));
    }
}
src/main/java/com/ruoyi/collaborativeApproval/controller/SealApplicationManagementController.java
@@ -11,7 +11,8 @@
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.project.system.service.ISysNoticeService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
@@ -28,20 +29,20 @@
@RestController
@RequestMapping("/sealApplicationManagement")
@Tag(name = "用印申请管理")
public class SealApplicationManagementController {
public class SealApplicationManagementController extends BaseController {
    private SealApplicationManagementService sealApplicationManagementService;
    private ISysNoticeService sysNoticeService;
    private FileUtil fileUtil;
    @GetMapping("/getList")
    @Operation(summary = "分页查询")
    public AjaxResult listPage(Page page, SealApplicationManagement sealApplicationManagement){
        return AjaxResult.success(sealApplicationManagementService.listPage(page,sealApplicationManagement));
    public R<?> listPage(Page page, SealApplicationManagement sealApplicationManagement){
        return R.ok(sealApplicationManagementService.listPage(page,sealApplicationManagement));
    }
    @PostMapping("/add")
    @Operation(summary = "新增")
    public AjaxResult add(@RequestBody SealApplicationManagementDTO sealApplicationManagement){
    public R<?> add(@RequestBody SealApplicationManagementDTO sealApplicationManagement){
        sealApplicationManagementService.save(sealApplicationManagement);
        // 5. ä¿å­˜é”€å”®å°è´¦é™„ä»¶
        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE,
@@ -54,30 +55,30 @@
                +"申请标题:"+sealApplicationManagement.getTitle(),
                Arrays.asList(sealApplicationManagement.getApproveUserId()),
                "/collaborativeApproval/sealManagement?applicationNum="+sealApplicationManagement.getApplicationNum());
        return AjaxResult.success();
        return R.ok();
    }
    @PostMapping("/update")
    @Operation(summary = "修改")
    public AjaxResult update(@RequestBody SealApplicationManagementDTO sealApplicationManagement){
    public R<?> update(@RequestBody SealApplicationManagementDTO sealApplicationManagement){
        // 5. ä¿å­˜é”€å”®å°è´¦é™„ä»¶
        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE,
                RecordTypeEnum.SEAL_APPLICATION_MANAGEMENT,
                sealApplicationManagement.getId(),
                sealApplicationManagement.getStorageBlobDTOs());
        return AjaxResult.success(sealApplicationManagementService.updateById(sealApplicationManagement));
        return R.ok(sealApplicationManagementService.updateById(sealApplicationManagement));
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除")
    public AjaxResult delete(@PathVariable("ids") List<Long> ids){
    public R<?> delete(@PathVariable("ids") List<Long> ids){
        if (CollectionUtils.isEmpty(ids)) {
            throw new RuntimeException("请传入要删除的ID");
        }
        fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.FILE,
                RecordTypeEnum.SEAL_APPLICATION_MANAGEMENT,
                ids);
        return AjaxResult.success(sealApplicationManagementService.removeBatchByIds(ids));
        return R.ok(sealApplicationManagementService.removeBatchByIds(ids));
    }
    @Operation(summary = "用印申请管理导出")
src/main/java/com/ruoyi/collaborativeApproval/controller/StaffContactsPersonalController.java
@@ -4,7 +4,8 @@
import com.ruoyi.collaborativeApproval.dto.StaffContactsPersonalDTO;
import com.ruoyi.collaborativeApproval.pojo.StaffContactsPersonal;
import com.ruoyi.collaborativeApproval.service.StaffContactsPersonalService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
@@ -12,27 +13,27 @@
@RestController
@RequestMapping("/staffContactsPersonal")
@AllArgsConstructor
public class StaffContactsPersonalController {
public class StaffContactsPersonalController extends BaseController {
    private StaffContactsPersonalService staffContactsPersonalService;
    @GetMapping("/getList")
    @Operation(summary = "分页查询")
    public AjaxResult listPage(Page page, StaffContactsPersonalDTO staffContactsPersonalDTO) {
        return AjaxResult.success(staffContactsPersonalService.listPage(page, staffContactsPersonalDTO));
    public R<?> listPage(Page page, StaffContactsPersonalDTO staffContactsPersonalDTO) {
        return R.ok(staffContactsPersonalService.listPage(page, staffContactsPersonalDTO));
    }
    @PostMapping("/add")
    @Operation(summary = "新增")
    public AjaxResult add(@RequestBody StaffContactsPersonal staffContactsPersonal) {
        return AjaxResult.success(staffContactsPersonalService.save(staffContactsPersonal));
    public R<?> add(@RequestBody StaffContactsPersonal staffContactsPersonal) {
        return R.ok(staffContactsPersonalService.save(staffContactsPersonal));
    }
    @DeleteMapping("/delete/{id}")
    @Operation(summary = "删除")
    public AjaxResult delete(@PathVariable("id") Long id) {
    public R<?> delete(@PathVariable("id") Long id) {
//        if (CollectionUtils.isEmpty(id)) {
//            throw new RuntimeException("请传入要删除的ID");
//        }
        return AjaxResult.success(staffContactsPersonalService.removeById(id));
        return R.ok(staffContactsPersonalService.removeById(id));
    }
}
src/main/java/com/ruoyi/compensationperformance/controller/CompensationPerformanceController.java
@@ -8,7 +8,7 @@
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.staff.mapper.StaffOnJobMapper;
import com.ruoyi.staff.pojo.StaffOnJob;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -40,37 +40,37 @@
    @GetMapping("/listPage")
    @Log(title = "薪酬绩效-分页查询", businessType = BusinessType.OTHER)
    @Operation(summary = "薪酬绩效-分页查询")
    public AjaxResult listPage(Page page, String staffName, String payDateStr) {
    public R<?> listPage(Page page, String staffName, String payDateStr) {
        IPage<CompensationPerformance> listPage = compensationPerformanceService.listPage(page, staffName, payDateStr);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @PostMapping("/add")
    @Log(title = "薪酬绩效-添加", businessType = BusinessType.INSERT)
    @Operation(summary = "薪酬绩效-添加")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody CompensationPerformance compensationPerformance) {
    public R<?> add(@RequestBody CompensationPerformance compensationPerformance) {
        boolean save = compensationPerformanceService.save(compensationPerformance);
        return save ? AjaxResult.success("添加成功") : AjaxResult.error("添加失败");
        return save ? R.ok(null, "添加成功") : R.fail("添加失败");
    }
    @PostMapping("/update")
    @Log(title = "薪酬绩效-修改", businessType = BusinessType.UPDATE)
    @Operation(summary = "薪酬绩效-修改")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult update(@RequestBody CompensationPerformance compensationPerformance) {
    public R<?> update(@RequestBody CompensationPerformance compensationPerformance) {
        boolean update = compensationPerformanceService.updateById(compensationPerformance);
        return update ? AjaxResult.success("修改成功") : AjaxResult.error("修改失败");
        return update ? R.ok(null, "修改成功") : R.fail("修改失败");
    }
    @DeleteMapping("/delete")
    @Log(title = "薪酬绩效-删除", businessType = BusinessType.DELETE)
    @Operation(summary = "薪酬绩效-删除")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delete(@RequestBody List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) return AjaxResult.error("请传入要删除的ID");
    public R<?> delete(@RequestBody List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) return R.fail("请传入要删除的ID");
        boolean delete = compensationPerformanceService.removeBatchByIds(ids);
        return delete ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
        return delete ? R.ok(null, "删除成功") : R.fail("删除失败");
    }
    @Log(title = "导出薪资管理列表", businessType = BusinessType.EXPORT)
@@ -91,7 +91,7 @@
    @Log(title = "导入薪资管理列表", businessType = BusinessType.IMPORT)
    @PostMapping("/importData")
    public AjaxResult importData(MultipartFile file) throws Exception {
    public R<?> importData(MultipartFile file) throws Exception {
        ExcelUtil<CompensationPerformance> util = new ExcelUtil<>(CompensationPerformance.class);
        List<CompensationPerformance> list = util.importExcel(file.getInputStream());
        list.forEach(item -> {
@@ -101,7 +101,7 @@
            }
        });
        boolean b = compensationPerformanceService.saveBatch(list);
        return AjaxResult.success(b);
        return R.ok(b);
    }
src/main/java/com/ruoyi/customervisits/controller/CustomerVisitsController.java
@@ -8,7 +8,7 @@
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 io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
@@ -31,46 +31,46 @@
    @GetMapping("/listPage")
    @Log(title = "客户拜访-分页查询", businessType = BusinessType.OTHER)
    @Operation(summary = "客户拜访-分页查询")
    public AjaxResult listPage(Page page, CustomerVisits customerVisits) {
    public R<?> listPage(Page page, CustomerVisits customerVisits) {
        IPage<CustomerVisits> listPage = customerVisitsService.listPage(page, customerVisits);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @Log(title = "客户拜访-添加", businessType = BusinessType.INSERT)
    @Operation(summary = "客户拜访-添加")
    @PostMapping("/add")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody CustomerVisits customerVisits) {
    public R<?> add(@RequestBody CustomerVisits customerVisits) {
        boolean save = customerVisitsService.save(customerVisits);
        if (save) {
            return AjaxResult.success("添加成功");
            return R.ok(null, "添加成功");
        }
        return AjaxResult.error("添加失败");
        return R.fail("添加失败");
    }
    @Log(title = "客户拜访-编辑", businessType = BusinessType.UPDATE)
    @Operation(summary = "客户拜访-编辑")
    @PostMapping("update")
    public AjaxResult updateCustomerVisit(@RequestBody CustomerVisits customerVisits) {
    public R<?> updateCustomerVisit(@RequestBody CustomerVisits customerVisits) {
        boolean updateResult = customerVisitsService.updateCustomerVisit(customerVisits);
        if (updateResult) {
            return AjaxResult.success("编辑成功");
            return R.ok(null, "编辑成功");
        }
        return AjaxResult.error("编辑失败");
        return R.fail("编辑失败");
    }
    @Log(title = "客户拜访-删除", businessType = BusinessType.DELETE)
    @Operation(summary = "客户拜访-删除")
    @DeleteMapping("{customerId}")
    public AjaxResult deleteCustomerVisit(@PathVariable Integer customerId) {
    public R<?> deleteCustomerVisit(@PathVariable Integer customerId) {
        if (customerId == null) {
            return AjaxResult.error("客户ID不能为空");
            return R.fail("客户ID不能为空");
        }
        boolean deleteResult = customerVisitsService.removeById(customerId);
        if (deleteResult) {
            return AjaxResult.success("删除成功");
            return R.ok(null, "删除成功");
        }
        return AjaxResult.error("删除失败");
        return R.fail("删除失败");
    }
}
src/main/java/com/ruoyi/customervisits/service/CustomerVisitsService.java
@@ -4,7 +4,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.customervisits.pojo.CustomerVisits;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
/**
 * @author :yys
src/main/java/com/ruoyi/device/controller/DeviceDefectRecordController.java
@@ -4,7 +4,8 @@
import com.ruoyi.device.dto.DeviceDefectRecordDto;
import com.ruoyi.device.pojo.DeviceDefectRecord;
import com.ruoyi.device.service.DeviceDefectRecordService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
@@ -14,35 +15,35 @@
@RequestMapping("/defect")
@AllArgsConstructor
@RestController
public class DeviceDefectRecordController {
public class DeviceDefectRecordController extends BaseController {
    private DeviceDefectRecordService deviceDefectRecordService;
    @Operation(summary = "设备缺陷记录列表")
    @GetMapping("/page")
    public AjaxResult page(Page page , DeviceDefectRecordDto deviceDefectRecordDto) {
        return AjaxResult.success(deviceDefectRecordService.listPage(page,deviceDefectRecordDto));
    public R<?> page(Page page , DeviceDefectRecordDto deviceDefectRecordDto) {
        return R.ok(deviceDefectRecordService.listPage(page,deviceDefectRecordDto));
    }
    @Operation(summary = "设备id查询设备缺陷记录列表")
    @GetMapping("/find/{deviceLedgerId}")
    public AjaxResult find(@PathVariable Long deviceLedgerId) {
    public R<?> find(@PathVariable Long deviceLedgerId) {
        DeviceDefectRecordDto deviceDefectRecordDto = new DeviceDefectRecordDto();
        deviceDefectRecordDto.setDeviceLedgerId(deviceLedgerId);
        return AjaxResult.success(deviceDefectRecordService.listPage(new Page<>(1,-1),deviceDefectRecordDto));
        return R.ok(deviceDefectRecordService.listPage(new Page<>(1,-1),deviceDefectRecordDto));
    }
    @PostMapping("/add")
    @Operation(summary = "添加设备缺陷记录")
    public AjaxResult add(@RequestBody DeviceDefectRecord deviceDefectRecord) {
        return AjaxResult.success(deviceDefectRecordService.add(deviceDefectRecord));
    public R<?> add(@RequestBody DeviceDefectRecord deviceDefectRecord) {
        return R.ok(deviceDefectRecordService.add(deviceDefectRecord));
    }
    @PostMapping("/update")
    @Operation(summary = "修改设备缺陷记录")
    public AjaxResult update(@RequestBody DeviceDefectRecord deviceDefectRecord) {
        return AjaxResult.success(deviceDefectRecordService.updateByDDR(deviceDefectRecord));
    public R<?> update(@RequestBody DeviceDefectRecord deviceDefectRecord) {
        return R.ok(deviceDefectRecordService.updateByDDR(deviceDefectRecord));
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除设备缺陷记录")
    public AjaxResult delete(@PathVariable Long id) {
        return AjaxResult.success(deviceDefectRecordService.removeById(id));
    public R<?> delete(@PathVariable Long id) {
        return R.ok(deviceDefectRecordService.removeById(id));
    }
}
src/main/java/com/ruoyi/device/controller/DeviceLedgerController.java
@@ -12,7 +12,8 @@
import com.ruoyi.device.pojo.DeviceMaintenance;
import com.ruoyi.device.service.IDeviceLedgerService;
import com.ruoyi.framework.aspectj.lang.annotation.Anonymous;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
@@ -28,7 +29,7 @@
@RequestMapping("/device/ledger")
@RestController
@AllArgsConstructor
public class DeviceLedgerController {
public class DeviceLedgerController extends BaseController {
    private IDeviceLedgerService deviceLedgerService;
    private DeviceLedgerMapper deviceLedgerMapper;
@@ -38,37 +39,37 @@
    @Operation(summary = "设备台账列表")
    @GetMapping("/page")
    public AjaxResult page(Page page , DeviceLedgerDto deviceLedger) {
        return AjaxResult.success(deviceLedgerService.queryPage(page,deviceLedger));
    public R<?> page(Page page , DeviceLedgerDto deviceLedger) {
        return R.ok(deviceLedgerService.queryPage(page,deviceLedger));
    }
    @PostMapping()
    @Operation(summary = "添加设备台账")
    public AjaxResult add(@RequestBody DeviceLedger deviceLedger) {
    public R<?> add(@RequestBody DeviceLedger deviceLedger) {
        return deviceLedgerService.saveDeviceLedger(deviceLedger);
    }
    @Operation(summary = "根据id查询设备台账")
    @GetMapping("/{id}")
    public AjaxResult detail(@PathVariable Long id) {
        return AjaxResult.success(deviceLedgerService.getById(id));
    public R<?> detail(@PathVariable Long id) {
        return R.ok(deviceLedgerService.getById(id));
    }
    @PutMapping ()
    @Operation(summary = "修改设备台账")
    public AjaxResult update(@RequestBody DeviceLedger deviceLedger) {
    public R<?> update(@RequestBody DeviceLedger deviceLedger) {
        return deviceLedgerService.updateDeviceLedger(deviceLedger);
    }
    @DeleteMapping("/{ids}")
    @Operation(summary = "删除设备台账")
    public AjaxResult delete(@PathVariable("ids") ArrayList<Long> ids) {
    public R<?> delete(@PathVariable("ids") ArrayList<Long> ids) {
        boolean b = deviceLedgerService.removeBatchByIds(ids);
        if (!b) {
            return AjaxResult.error("删除失败");
            return R.fail("删除失败");
        }
        return AjaxResult.success();
        return R.ok();
    }
    @PostMapping("export")
@@ -86,32 +87,32 @@
    @PostMapping("/import")
    @Operation(summary = "导入设备台账")
    public AjaxResult importData(MultipartFile file) throws IOException {
    public R<?> importData(MultipartFile file) throws IOException {
        Boolean b = deviceLedgerService.importData(file);
        if (b) {
            return AjaxResult.success("导入成功");
            return R.ok(null, "导入成功");
        }
        return AjaxResult.error("导入失败");
        return R.fail("导入失败");
    }
    @GetMapping("getDeviceLedger")
    @Operation(summary = "获取设备台账")
    public AjaxResult getDeviceLedger( ) {
        return AjaxResult.success(deviceLedgerService.list(new QueryWrapper<DeviceLedger>().lambda()
    public R<?> getDeviceLedger( ) {
        return R.ok(deviceLedgerService.list(new QueryWrapper<DeviceLedger>().lambda()
                .select(DeviceLedger::getId, DeviceLedger::getDeviceName,DeviceLedger::getDeviceModel)));
    }
    @GetMapping("scanDevice")
    @Operation(summary = "获取设备台账")
    @Anonymous
    public AjaxResult scanDevice(Long id) {
    public R<?> scanDevice(Long id) {
        List<DeviceMaintenance> list = deviceMaintenanceMapper.list1(id);
        DeviceLedger deviceLedger = deviceLedgerMapper.selectById1(id);
        if (list.size()>0){
            deviceLedger.setUpdateTime(list.get(0).getMaintenanceActuallyTime());//最后维护时间
        }
        deviceLedger.setCreateTime(deviceLedger.getUpdateTime().plusMonths(1));//下次维护时间
        return AjaxResult.success(deviceLedger);
        return R.ok(deviceLedger);
    }
}
src/main/java/com/ruoyi/device/controller/DeviceMaintenanceController.java
@@ -7,7 +7,8 @@
import com.ruoyi.device.pojo.DeviceMaintenance;
import com.ruoyi.device.service.IDeviceLedgerService;
import com.ruoyi.device.service.IDeviceMaintenanceService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
@@ -20,7 +21,7 @@
@RestController
@RequestMapping("/device/maintenance")
@AllArgsConstructor
public class DeviceMaintenanceController {
public class DeviceMaintenanceController extends BaseController {
    private IDeviceMaintenanceService deviceMaintenanceService;
@@ -28,13 +29,13 @@
    @Operation(summary = "设备保养列表")
    @GetMapping("/page")
    public AjaxResult page(Page page , DeviceMaintenanceDto deviceMaintenanceDto) {
        return AjaxResult.success(deviceMaintenanceService.queryPage(page,deviceMaintenanceDto));
    public R<?> page(Page page , DeviceMaintenanceDto deviceMaintenanceDto) {
        return R.ok(deviceMaintenanceService.queryPage(page,deviceMaintenanceDto));
    }
    @PostMapping()
    @Operation(summary = "添加设备保养")
    public AjaxResult add(@RequestBody DeviceMaintenanceDto deviceMaintenance) {
    public R<?> add(@RequestBody DeviceMaintenanceDto deviceMaintenance) {
        DeviceLedger byId = deviceLedgerService.getById(deviceMaintenance.getDeviceLedgerId());
        deviceMaintenance.setDeviceName(byId.getDeviceName());
        deviceMaintenance.setDeviceModel(byId.getDeviceModel());
@@ -43,13 +44,13 @@
    @Operation(summary = "根据id查询设备保养")
    @GetMapping("/{id}")
    public AjaxResult detail(@PathVariable Long id) {
        return AjaxResult.success(deviceMaintenanceService.detailById(id));
    public R<?> detail(@PathVariable Long id) {
        return R.ok(deviceMaintenanceService.detailById(id));
    }
    @PutMapping ()
    @Operation(summary = "修改设备保养")
    public AjaxResult update(@RequestBody DeviceMaintenanceDto deviceMaintenance) {
    public R<?> update(@RequestBody DeviceMaintenanceDto deviceMaintenance) {
        DeviceLedger byId = deviceLedgerService.getById(deviceMaintenance.getDeviceLedgerId());
        deviceMaintenance.setDeviceName(byId.getDeviceName());
        deviceMaintenance.setDeviceModel(byId.getDeviceModel());
@@ -58,19 +59,19 @@
    @PostMapping ("maintenance")
    @Operation(summary = "修改设备保养")
    public AjaxResult maintenance(@RequestBody DeviceMaintenanceDto deviceMaintenance) {
    public R<?> maintenance(@RequestBody DeviceMaintenanceDto deviceMaintenance) {
        return deviceMaintenanceService.updateDeviceDeviceMaintenance(deviceMaintenance);
    }
    @DeleteMapping("/{ids}")
    @Operation(summary = "删除设备保养")
    public AjaxResult delete(@PathVariable("ids") Long[] ids) {
    public R<?> delete(@PathVariable("ids") Long[] ids) {
        boolean b = deviceMaintenanceService.removeBatchByIds(Arrays.asList(ids));
        if (!b) {
            return AjaxResult.error("删除失败");
            return R.fail("删除失败");
        }
        return AjaxResult.success();
        return R.ok();
    }
    @PostMapping("export")
src/main/java/com/ruoyi/device/controller/DeviceMaintenanceFileController.java
@@ -4,7 +4,8 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.device.pojo.DeviceMaintenanceFile;
import com.ruoyi.device.service.DeviceMaintenanceFileService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
@@ -23,7 +24,7 @@
@RestController
@RequestMapping("/maintenanceTaskFile")
@Tag(name = "设备保养附件")
public class DeviceMaintenanceFileController {
public class DeviceMaintenanceFileController extends BaseController {
    @Resource
    private DeviceMaintenanceFileService deviceMaintenanceFileService;
@@ -35,8 +36,8 @@
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody DeviceMaintenanceFile deviceMaintenanceFile) {
        return AjaxResult.success(deviceMaintenanceFileService.save(deviceMaintenanceFile));
    public R<?> add(@RequestBody DeviceMaintenanceFile deviceMaintenanceFile) {
        return R.ok(deviceMaintenanceFileService.save(deviceMaintenanceFile));
    }
    /**
@@ -45,12 +46,12 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delQualityUnqualified(@RequestBody List<Integer> ids) {
    public R<?> delQualityUnqualified(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        //删除检验附件
        return AjaxResult.success(deviceMaintenanceFileService.removeBatchByIds(ids));
        return R.ok(deviceMaintenanceFileService.removeBatchByIds(ids));
    }
    /**
@@ -60,8 +61,8 @@
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult qualityInspectFileListPage(Page page, DeviceMaintenanceFile deviceMaintenanceFile) {
        return AjaxResult.success(deviceMaintenanceFileService.page(page, Wrappers.<DeviceMaintenanceFile>lambdaQuery().eq(DeviceMaintenanceFile::getDeviceMaintenanceId,deviceMaintenanceFile.getDeviceMaintenanceId())));
    public R<?> qualityInspectFileListPage(Page page, DeviceMaintenanceFile deviceMaintenanceFile) {
        return R.ok(deviceMaintenanceFileService.page(page, Wrappers.<DeviceMaintenanceFile>lambdaQuery().eq(DeviceMaintenanceFile::getDeviceMaintenanceId,deviceMaintenanceFile.getDeviceMaintenanceId())));
    }
src/main/java/com/ruoyi/device/controller/DeviceRepairController.java
@@ -5,7 +5,8 @@
import com.ruoyi.device.dto.DeviceRepairDto;
import com.ruoyi.device.pojo.DeviceRepair;
import com.ruoyi.device.service.IDeviceRepairService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
@@ -18,54 +19,54 @@
@RequestMapping("/device/repair")
@RestController
@AllArgsConstructor
public class DeviceRepairController {
public class DeviceRepairController extends BaseController {
    private IDeviceRepairService deviceRepairService;
    @Operation(summary = "设备报修列表")
    @GetMapping("/page")
    public AjaxResult page(Page page , DeviceRepairDto deviceRepairDto) {
        return AjaxResult.success(deviceRepairService.queryPage(page,deviceRepairDto));
    public R<?> page(Page page , DeviceRepairDto deviceRepairDto) {
        return R.ok(deviceRepairService.queryPage(page,deviceRepairDto));
    }
    @PostMapping()
    @Operation(summary = "添加设备报修")
    public AjaxResult add( @RequestBody DeviceRepairDto deviceRepairDto) {
    public R<?> add( @RequestBody DeviceRepairDto deviceRepairDto) {
        return deviceRepairService.saveDeviceRepair(deviceRepairDto);
    }
    @Operation(summary = "根据id查询设备报修")
    @GetMapping("/{id}")
    public AjaxResult detail(@PathVariable Long id) {
        return AjaxResult.success(deviceRepairService.detailById(id));
    public R<?> detail(@PathVariable Long id) {
        return R.ok(deviceRepairService.detailById(id));
    }
    @PutMapping ()
    @Operation(summary = "修改设备报修")
    public AjaxResult update( @RequestBody DeviceRepairDto deviceRepairDto) {
    public R<?> update( @RequestBody DeviceRepairDto deviceRepairDto) {
        return deviceRepairService.updateDeviceRepair(deviceRepairDto);
    }
    @PostMapping ("/repair")
    @Operation(summary = "设备维修")
    public AjaxResult repair( @RequestBody DeviceRepairDto deviceRepairDto) {
    public R<?> repair( @RequestBody DeviceRepairDto deviceRepairDto) {
        return deviceRepairService.confirmRepair(deviceRepairDto);
    }
    @PostMapping ("/acceptance")
    @Operation(summary = "设备报修验收审批")
    public AjaxResult acceptance(@RequestBody DeviceRepairDto deviceRepairDto) {
    public R<?> acceptance(@RequestBody DeviceRepairDto deviceRepairDto) {
        return deviceRepairService.approveRepairAcceptance(deviceRepairDto);
    }
    @DeleteMapping("/{ids}")
    @Operation(summary = "删除设备报修")
    public AjaxResult delete(@PathVariable("ids") Long[] ids) {
    public R<?> delete(@PathVariable("ids") Long[] ids) {
        boolean b = deviceRepairService.removeBatchByIds(Arrays.asList(ids));
        if (!b) {
            return AjaxResult.error("删除失败");
            return R.fail("删除失败");
        }
        return AjaxResult.success();
        return R.ok();
    }
    @PostMapping("export")
src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java
@@ -6,7 +6,7 @@
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 io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
@@ -31,7 +31,7 @@
    @GetMapping("/listPage")
    @Operation(summary = "设备保养定时任务列表")
    public AjaxResult listPage(Page page, MaintenanceTask maintenanceTask) {
    public R<?> listPage(Page page, MaintenanceTask maintenanceTask) {
        return maintenanceTaskService.listPage(page,maintenanceTask);
    }
@@ -39,21 +39,21 @@
    @PostMapping("/add")
    @Operation(summary = "添加设备保养定时任务")
    @Log(title = "设备保养定时任务", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody MaintenanceTask maintenanceTask) {
    public R<?> add(@RequestBody MaintenanceTask maintenanceTask) {
        return maintenanceTaskService.add(maintenanceTask);
    }
    @PostMapping("/update")
    @Operation(summary = "修改设备保养定时任务")
    @Log(title = "设备保养定时任务", businessType = BusinessType.UPDATE)
    public AjaxResult update(@RequestBody MaintenanceTask maintenanceTask) {
    public R<?> update(@RequestBody MaintenanceTask maintenanceTask) {
        return maintenanceTaskService.updateByMaintenanceTaskId(maintenanceTask);
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除设备保养定时任务")
    @Log(title = "设备保养定时任务", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
    public R<?> delete(@RequestBody List<Long> ids) {
        return maintenanceTaskService.delete(ids);
    }
src/main/java/com/ruoyi/device/service/IDeviceLedgerService.java
@@ -5,7 +5,7 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.device.dto.DeviceLedgerDto;
import com.ruoyi.device.pojo.DeviceLedger;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletResponse;
@@ -14,9 +14,9 @@
public interface IDeviceLedgerService  extends IService<DeviceLedger> {
    IPage<DeviceLedgerDto> queryPage(Page page, DeviceLedgerDto deviceLedger);
    AjaxResult saveDeviceLedger(DeviceLedger deviceLedger);
    R<?> saveDeviceLedger(DeviceLedger deviceLedger);
    AjaxResult updateDeviceLedger(DeviceLedger deviceLedger);
    R<?> updateDeviceLedger(DeviceLedger deviceLedger);
    void export(HttpServletResponse response, Long[] ids);
src/main/java/com/ruoyi/device/service/IDeviceMaintenanceService.java
@@ -6,7 +6,7 @@
import com.ruoyi.device.dto.DeviceMaintenanceDto;
import com.ruoyi.device.pojo.DeviceMaintenance;
import com.ruoyi.device.vo.DeviceMaintenanceVo;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import jakarta.servlet.http.HttpServletResponse;
@@ -14,9 +14,9 @@
    IPage<DeviceMaintenanceDto> queryPage(Page page, DeviceMaintenanceDto deviceMaintenanceDto);
    AjaxResult saveDeviceRepair(DeviceMaintenanceDto deviceMaintenance);
    R<?> saveDeviceRepair(DeviceMaintenanceDto deviceMaintenance);
    AjaxResult updateDeviceDeviceMaintenance(DeviceMaintenanceDto deviceMaintenance);
    R<?> updateDeviceDeviceMaintenance(DeviceMaintenanceDto deviceMaintenance);
    void export(HttpServletResponse response, Long[] ids);
src/main/java/com/ruoyi/device/service/IDeviceRepairService.java
@@ -6,7 +6,7 @@
import com.ruoyi.device.dto.DeviceRepairDto;
import com.ruoyi.device.pojo.DeviceRepair;
import com.ruoyi.device.vo.DeviceRepairVo;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import jakarta.servlet.http.HttpServletResponse;
@@ -15,13 +15,13 @@
    IPage<DeviceRepairVo> queryPage(Page page, DeviceRepairDto deviceRepairDto);
    AjaxResult saveDeviceRepair(DeviceRepairDto deviceRepairDto);
    R<?> saveDeviceRepair(DeviceRepairDto deviceRepairDto);
    AjaxResult updateDeviceRepair(DeviceRepairDto deviceRepairDto);
    R<?> updateDeviceRepair(DeviceRepairDto deviceRepairDto);
    AjaxResult confirmRepair(DeviceRepairDto deviceRepairDto);
    R<?> confirmRepair(DeviceRepairDto deviceRepairDto);
    AjaxResult approveRepairAcceptance(DeviceRepairDto deviceRepairDto);
    R<?> approveRepairAcceptance(DeviceRepairDto deviceRepairDto);
    void export(HttpServletResponse response, Long[] ids);
src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java
@@ -3,7 +3,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.device.pojo.MaintenanceTask;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import java.util.List;
@@ -12,11 +12,11 @@
 * @date : 2025/12/22 14:56
 */
public interface MaintenanceTaskService extends IService<MaintenanceTask> {
    AjaxResult listPage(Page page, MaintenanceTask maintenanceTask);
    R<?> listPage(Page page, MaintenanceTask maintenanceTask);
    AjaxResult add(MaintenanceTask maintenanceTask);
    R<?> add(MaintenanceTask maintenanceTask);
    AjaxResult updateByMaintenanceTaskId(MaintenanceTask maintenanceTask);
    R<?> updateByMaintenanceTaskId(MaintenanceTask maintenanceTask);
    AjaxResult delete(List<Long> ids);
    R<?> delete(List<Long> ids);
}
src/main/java/com/ruoyi/device/service/impl/DeviceLedgerServiceImpl.java
@@ -13,7 +13,7 @@
import com.ruoyi.device.mapper.DeviceLedgerMapper;
import com.ruoyi.device.pojo.DeviceLedger;
import com.ruoyi.device.service.IDeviceLedgerService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import jakarta.servlet.http.HttpServletResponse;
@@ -44,25 +44,25 @@
    }
    @Override
    public AjaxResult saveDeviceLedger(DeviceLedger deviceLedger) {
    public R<?> saveDeviceLedger(DeviceLedger deviceLedger) {
        LambdaQueryWrapper<DeviceLedger> deviceLedgerLambdaQueryWrapper = new LambdaQueryWrapper<>();
        deviceLedgerLambdaQueryWrapper.eq(DeviceLedger::getDeviceName,deviceLedger.getDeviceName());
        if (this.count(deviceLedgerLambdaQueryWrapper) > 0) {
            return AjaxResult.error("设备名称已存在");
            return R.fail("设备名称已存在");
        }
        boolean save = this.save(deviceLedger);
        if (save){
            return AjaxResult.success();
            return R.ok();
        }
        return AjaxResult.error();
        return R.fail();
    }
    @Override
    public AjaxResult updateDeviceLedger(DeviceLedger deviceLedger) {
    public R<?> updateDeviceLedger(DeviceLedger deviceLedger) {
        if (this.updateById(deviceLedger)) {
            return AjaxResult.success();
            return R.ok();
        }
        return AjaxResult.error();
        return R.fail();
    }
    @Override
src/main/java/com/ruoyi/device/service/impl/DeviceMaintenanceServiceImpl.java
@@ -15,7 +15,7 @@
import com.ruoyi.device.service.IDeviceMaintenanceService;
import com.ruoyi.device.vo.DeviceMaintenanceVo;
import com.ruoyi.device.vo.DeviceRepairVo;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.measuringinstrumentledger.mapper.SparePartsMapper;
import com.ruoyi.measuringinstrumentledger.pojo.SpareParts;
import com.ruoyi.measuringinstrumentledger.pojo.SparePartsRequisitionRecord;
@@ -48,19 +48,19 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult saveDeviceRepair(DeviceMaintenanceDto deviceMaintenance) {
    public R<?> saveDeviceRepair(DeviceMaintenanceDto deviceMaintenance) {
        boolean save = this.save(deviceMaintenance);
        if (save){
            // å¤„理图片上传
            fileUtil.saveStorageAttachmentByRecordTypeAndRecordId("file", RecordTypeEnum.DEVICE_MAINTENANCE, deviceMaintenance.getId(), deviceMaintenance.getStorageBlobDTOs());
            return AjaxResult.success();
            return R.ok();
        }
        return AjaxResult.error();
        return R.fail();
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult updateDeviceDeviceMaintenance(DeviceMaintenanceDto deviceMaintenance) {
    public R<?> updateDeviceDeviceMaintenance(DeviceMaintenanceDto deviceMaintenance) {
        DeviceMaintenance oldDeviceMaintenance = this.getById(deviceMaintenance.getId());
        // å¤„理备件使用情况
        if (com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(deviceMaintenance.getSparePartsUseList())) {
@@ -85,7 +85,7 @@
                        record.setQuantity(sparePartUse.getQuantity());
                        sparePartsRequisitionRecordService.save(record);
                    } else {
                        return AjaxResult.error("备件 " + spareParts.getName() + " æ•°é‡ä¸è¶³");
                        return R.fail("备件 " + spareParts.getName() + " æ•°é‡ä¸è¶³");
                    }
                }
            }
@@ -98,9 +98,9 @@
        if (this.updateById(deviceMaintenance)) {
            // å¤„理图片上传
            fileUtil.saveStorageAttachmentByRecordTypeAndRecordId("file", RecordTypeEnum.DEVICE_MAINTENANCE, deviceMaintenance.getId(), deviceMaintenance.getStorageBlobDTOs());
            return AjaxResult.success();
            return R.ok();
        }
        return AjaxResult.error();
        return R.fail();
    }
    @Override
src/main/java/com/ruoyi/device/service/impl/DeviceRepairServiceImpl.java
@@ -18,7 +18,7 @@
import com.ruoyi.device.service.IDeviceLedgerService;
import com.ruoyi.device.service.IDeviceRepairService;
import com.ruoyi.device.vo.DeviceRepairVo;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.measuringinstrumentledger.mapper.SparePartsMapper;
import com.ruoyi.measuringinstrumentledger.pojo.SpareParts;
import com.ruoyi.measuringinstrumentledger.pojo.SparePartsRequisitionRecord;
@@ -63,7 +63,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult saveDeviceRepair(DeviceRepairDto deviceRepairDto) {
    public R<?> saveDeviceRepair(DeviceRepairDto deviceRepairDto) {
        DeviceLedger byId = deviceLedgerService.getById(deviceRepairDto.getDeviceLedgerId());
        deviceRepairDto.setDeviceName(byId.getDeviceName());
        deviceRepairDto.setDeviceModel(byId.getDeviceModel());
@@ -74,23 +74,23 @@
        if (save) {
            // å¤„理图片上传
            fileUtil.saveStorageAttachmentByRecordTypeAndRecordId("file", RecordTypeEnum.DEVICE_REPAIR, deviceRepairDto.getId(), deviceRepairDto.getStorageBlobDTOs());
            return AjaxResult.success();
            return R.ok();
        }
        return AjaxResult.error("保存失败");
        return R.fail("保存失败");
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult updateDeviceRepair(DeviceRepairDto deviceRepairDto) {
    public R<?> updateDeviceRepair(DeviceRepairDto deviceRepairDto) {
        DeviceRepair oldDeviceRepair = this.getById(deviceRepairDto.getId());
        if (oldDeviceRepair == null) {
            return AjaxResult.error("报修记录不存在");
            return R.fail("报修记录不存在");
        }
        if (deviceRepairDto.getStatus() != null
                && deviceRepairDto.getStatus() == STATUS_COMPLETED
                && (oldDeviceRepair.getStatus() == null
                || oldDeviceRepair.getStatus() != STATUS_COMPLETED)) {
            return AjaxResult.error("请先提交验收审批,验收通过后才可完结");
            return R.fail("请先提交验收审批,验收通过后才可完结");
        }
        // å¤„理备件使用情况
        if (CollectionUtils.isNotEmpty(deviceRepairDto.getSparePartsUseList())) {
@@ -115,7 +115,7 @@
                        record.setQuantity(sparePartUse.getQuantity());
                        sparePartsRequisitionRecordService.save(record);
                    } else {
                        return AjaxResult.error("备件 " + spareParts.getName() + " æ•°é‡ä¸è¶³");
                        return R.fail("备件 " + spareParts.getName() + " æ•°é‡ä¸è¶³");
                    }
                }
            }
@@ -142,23 +142,23 @@
            if (deviceRepairDto.getStorageBlobDTOs() != null) {
                fileUtil.saveStorageAttachmentByRecordTypeAndRecordId("file", RecordTypeEnum.DEVICE_REPAIR, id, deviceRepairDto.getStorageBlobDTOs());
            }
            return AjaxResult.success();
            return R.ok();
        }
        return AjaxResult.error();
        return R.fail();
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult confirmRepair(DeviceRepairDto deviceRepairDto) {
    public R<?> confirmRepair(DeviceRepairDto deviceRepairDto) {
        DeviceRepair oldDeviceRepair = this.getById(deviceRepairDto.getId());
        if (oldDeviceRepair == null) {
            return AjaxResult.error("报修记录不存在");
            return R.fail("报修记录不存在");
        }
        if (oldDeviceRepair.getStatus() != null && oldDeviceRepair.getStatus() == STATUS_COMPLETED) {
            return AjaxResult.error("该报修已完结,不能重复确认维修");
            return R.fail("该报修已完结,不能重复确认维修");
        }
        if (oldDeviceRepair.getStatus() != null && oldDeviceRepair.getStatus() == STATUS_PENDING_ACCEPTANCE) {
            return AjaxResult.error("该报修已提交验收审批");
            return R.fail("该报修已提交验收审批");
        }
        deviceRepairDto.setStatus(STATUS_PENDING_ACCEPTANCE);
        return updateDeviceRepair(deviceRepairDto);
@@ -166,25 +166,25 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult approveRepairAcceptance(DeviceRepairDto deviceRepairDto) {
    public R<?> approveRepairAcceptance(DeviceRepairDto deviceRepairDto) {
        if (deviceRepairDto.getId() == null) {
            return AjaxResult.error("报修记录id不能为空");
            return R.fail("报修记录id不能为空");
        }
        DeviceRepair oldDeviceRepair = this.getById(deviceRepairDto.getId());
        if (oldDeviceRepair == null) {
            return AjaxResult.error("报修记录不存在");
            return R.fail("报修记录不存在");
        }
        if (oldDeviceRepair.getStatus() == null || oldDeviceRepair.getStatus() != STATUS_PENDING_ACCEPTANCE) {
            return AjaxResult.error("该报修未进入待验收状态,不能审批");
            return R.fail("该报修未进入待验收状态,不能审批");
        }
        if (StringUtils.isBlank(deviceRepairDto.getAcceptanceName())) {
            return AjaxResult.error("验收人不能为空");
            return R.fail("验收人不能为空");
        }
        if (deviceRepairDto.getAcceptanceTime() == null) {
            return AjaxResult.error("验收时间不能为空");
            return R.fail("验收时间不能为空");
        }
        if (StringUtils.isBlank(deviceRepairDto.getAcceptanceRemark())) {
            return AjaxResult.error("验收备注不能为空");
            return R.fail("验收备注不能为空");
        }
        DeviceRepair update = new DeviceRepair();
@@ -194,9 +194,9 @@
        update.setAcceptanceRemark(deviceRepairDto.getAcceptanceRemark());
        update.setStatus(STATUS_COMPLETED);
        if (this.updateById(update)) {
            return AjaxResult.success();
            return R.ok();
        }
        return AjaxResult.error("验收审批失败");
        return R.fail("验收审批失败");
    }
    @Override
src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java
@@ -6,7 +6,8 @@
import com.ruoyi.device.mapper.MaintenanceTaskMapper;
import com.ruoyi.device.pojo.MaintenanceTask;
import com.ruoyi.device.service.MaintenanceTaskService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.inspectiontask.pojo.TimingTask;
import com.ruoyi.inspectiontask.service.impl.TimingTaskServiceImpl;
import com.ruoyi.project.system.domain.SysUser;
@@ -33,11 +34,11 @@
    private final MaintenanceTaskScheduler maintenanceTaskScheduler;
    @Override
    public AjaxResult listPage(Page page, MaintenanceTask maintenanceTask) {
    public R<?> listPage(Page page, MaintenanceTask maintenanceTask) {
        Page<MaintenanceTask> taskPage = maintenanceTaskMapper.selectPage(page, null);
        // 2. å¦‚果没有数据,直接返回空分页
        if (taskPage.getRecords().isEmpty()) {
            return AjaxResult.success(taskPage);
            return R.ok(taskPage);
        }
        // 3. æ”¶é›†æ‰€æœ‰éœ€è¦æŸ¥è¯¢çš„用户ID
@@ -62,11 +63,11 @@
                task.setRegistrant(userNickNameMap.getOrDefault(task.getRegistrantId(), "未知用户"));
            }
        });
        return AjaxResult.success(taskPage);
        return R.ok(taskPage);
    }
    @Override
    public AjaxResult add(MaintenanceTask maintenanceTask) {
    public R<?> add(MaintenanceTask maintenanceTask) {
        maintenanceTask.setActive(true);
        // è®¡ç®—首次执行时间
        TimingTask task = new TimingTask();
@@ -78,31 +79,31 @@
        if (insert > 0) {
            maintenanceTaskScheduler.scheduleMaintenanceTask(maintenanceTask);
        }
        return AjaxResult.success("添加成功");
        return R.ok(null, "添加成功");
    }
    @Override
    public AjaxResult updateByMaintenanceTaskId(MaintenanceTask maintenanceTask) {
    public R<?> updateByMaintenanceTaskId(MaintenanceTask maintenanceTask) {
        MaintenanceTask maintenanceTask1 = maintenanceTaskMapper.selectById(maintenanceTask.getId());
        if (maintenanceTask1 == null) {
            return AjaxResult.warn("没有此数据");
            return R.fail(HttpStatus.WARN, "没有此数据");
        }
        BeanUtils.copyProperties(maintenanceTask, maintenanceTask1);
        int update = maintenanceTaskMapper.updateById(maintenanceTask1);
        if (update > 0) {
            maintenanceTaskScheduler.rescheduleMaintenanceTask(maintenanceTask1);
        }
        return AjaxResult.success("更新成功");
        return R.ok(null, "更新成功");
    }
    @Override
    public AjaxResult delete(List<Long> ids) {
    public R<?> delete(List<Long> ids) {
        int delete = maintenanceTaskMapper.deleteBatchIds(ids);
        if (delete > 0) {
            ids.forEach(id -> {
                maintenanceTaskScheduler.unscheduleMaintenanceTask(id);
            });
        }
        return AjaxResult.success("删除成功");
        return R.ok(null, "删除成功");
    }
}
src/main/java/com/ruoyi/equipmentenergyconsumption/controller/ElectricityConsumptionAreaController.java
@@ -8,7 +8,7 @@
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 io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
@@ -36,26 +36,26 @@
    @GetMapping("/listPage")
    @Operation(summary = "用电区域-分页查询")
    @Log(title = "用电区域-分页查询", businessType = BusinessType.OTHER)
    public AjaxResult listPage(Page page, ElectricityConsumptionArea electricityConsumptionArea) {
    public R<?> listPage(Page page, ElectricityConsumptionArea electricityConsumptionArea) {
        IPage<ElectricityConsumptionArea> listPage = electricityConsumptionAreaService.listPage(page, electricityConsumptionArea);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @PostMapping("/add")
    @Operation(summary = "用电区域-新增")
    @Log(title = "用电区域-新增", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody ElectricityConsumptionArea electricityConsumptionArea) {
    public R<?> add(@RequestBody ElectricityConsumptionArea electricityConsumptionArea) {
        boolean save = electricityConsumptionAreaService.saveOrUpdate(electricityConsumptionArea);
        return save ? AjaxResult.success() : AjaxResult.error();
        return save ? R.ok() : R.fail();
    }
    @DeleteMapping("/delete")
    @Operation(summary = "用电区域-删除")
    @Log(title = "用电区域-删除", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("请选择至少一条数据");
    public R<?> delete(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)) return R.fail("请选择至少一条数据");
        boolean remove = electricityConsumptionAreaService.removeBatchByIds(ids);
        return remove ? AjaxResult.success() : AjaxResult.error();
        return remove ? R.ok() : R.fail();
    }
}
src/main/java/com/ruoyi/equipmentenergyconsumption/controller/EnergyPeriodController.java
@@ -8,7 +8,7 @@
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 io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
@@ -28,42 +28,42 @@
    @GetMapping("/listPage")
    @Operation(summary = "用电时段-分页查询")
    @Log(title = "用电时段-分页查询", businessType = BusinessType.OTHER)
    public AjaxResult listPage(Page page, EnergyPeriod energyPeriod) {
    public R<?> listPage(Page page, EnergyPeriod energyPeriod) {
        IPage<EnergyPeriod> listPage = energyPeriodService.listPage(page, energyPeriod);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @PostMapping("/add")
    @Operation(summary = "用电时段-新增")
    @Log(title = "用电时段-新增", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody EnergyPeriod energyPeriod) {
    public R<?> add(@RequestBody EnergyPeriod energyPeriod) {
        boolean save = energyPeriodService.save(energyPeriod);
        return save ? AjaxResult.success() : AjaxResult.error();
        return save ? R.ok() : R.fail();
    }
    @PostMapping("/addBatch")
    @Operation(summary = "用电时段-批量新增")
    @Log(title = "用电时段-批量新增", businessType = BusinessType.INSERT)
    public AjaxResult addBatch(@RequestBody List<EnergyPeriod> energyPeriods) {
    public R<?> addBatch(@RequestBody List<EnergyPeriod> energyPeriods) {
        boolean save = energyPeriodService.saveBatch(energyPeriods);
        return save ? AjaxResult.success() : AjaxResult.error();
        return save ? R.ok() : R.fail();
    }
    @PostMapping("/update")
    @Operation(summary = "用电时段-修改")
    @Log(title = "用电时段-修改", businessType = BusinessType.UPDATE)
    public AjaxResult update(@RequestBody EnergyPeriod energyPeriod) {
    public R<?> update(@RequestBody EnergyPeriod energyPeriod) {
        boolean update = energyPeriodService.updateById(energyPeriod);
        return update ? AjaxResult.success() : AjaxResult.error();
        return update ? R.ok() : R.fail();
    }
    @DeleteMapping("/delete")
    @Operation(summary = "用电时段-删除")
    @Log(title = "用电时段-删除", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) return AjaxResult.error("请选择至少一条数据");
    public R<?> delete(@RequestBody List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) return R.fail("请选择至少一条数据");
        boolean remove = energyPeriodService.removeBatchByIds(ids);
        return remove ? AjaxResult.success() : AjaxResult.error("删除失败");
        return remove ? R.ok() : R.fail("删除失败");
    }
src/main/java/com/ruoyi/equipmentenergyconsumption/controller/EquipmentEnergyConsumptionController.java
@@ -12,7 +12,7 @@
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 io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
@@ -41,50 +41,50 @@
    @GetMapping("/listPage")
    @Operation(summary = "设备能耗-分页查询")
    @Log(title = "设备能耗-分页查询", businessType = BusinessType.OTHER)
    public AjaxResult listPage(Page page, EquipmentEnergyConsumption equipmentEnergyConsumption) {
    public R<?> listPage(Page page, EquipmentEnergyConsumption equipmentEnergyConsumption) {
        IPage<EquipmentEnergyConsumption> listPage = equipmentEnergyConsumptionService.listPage(page, equipmentEnergyConsumption);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @GetMapping("/deviceList")
    @Operation(summary = "设备台账-查询")
    @Log(title = "设备台账-查询", businessType = BusinessType.OTHER)
    public AjaxResult deviceList(DeviceLedger deviceLedger) {
    public R<?> deviceList(DeviceLedger deviceLedger) {
        List<DeviceLedger> listPage = equipmentEnergyConsumptionService.deviceList(deviceLedger);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @PostMapping("/add")
    @Operation(summary = "设备能耗-新增")
    @Log(title = "设备能耗-新增", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody EquipmentEnergyConsumption equipmentEnergyConsumption) {
    public R<?> add(@RequestBody EquipmentEnergyConsumption equipmentEnergyConsumption) {
        boolean save = equipmentEnergyConsumptionService.save(equipmentEnergyConsumption);
        return save ? AjaxResult.success() : AjaxResult.error();
        return save ? R.ok() : R.fail();
    }
    @PostMapping("/addBatch")
    @Operation(summary = "设备能耗-批量新增")
    @Log(title = "设备能耗-批量新增", businessType = BusinessType.INSERT)
    public AjaxResult addBatch(@RequestBody List<EquipmentEnergyConsumption> list) {
    public R<?> addBatch(@RequestBody List<EquipmentEnergyConsumption> list) {
        boolean save = equipmentEnergyConsumptionService.saveBatch(list);
        return save ? AjaxResult.success() : AjaxResult.error();
        return save ? R.ok() : R.fail();
    }
    @PostMapping("/update")
    @Operation(summary = "设备能耗-修改")
    @Log(title = "设备能耗-修改", businessType = BusinessType.UPDATE)
    public AjaxResult update(@RequestBody EquipmentEnergyConsumption equipmentEnergyConsumption) {
    public R<?> update(@RequestBody EquipmentEnergyConsumption equipmentEnergyConsumption) {
        boolean update = equipmentEnergyConsumptionService.updateById(equipmentEnergyConsumption);
        return update ? AjaxResult.success() : AjaxResult.error();
        return update ? R.ok() : R.fail();
    }
    @DeleteMapping("/delete")
    @Operation(summary = "设备能耗-删除")
    @Log(title = "设备能耗-删除", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("请选择至少一条数据");
    public R<?> delete(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)) return R.fail("请选择至少一条数据");
        boolean remove = equipmentEnergyConsumptionService.removeBatchByIds(ids);
        return remove ? AjaxResult.success() : AjaxResult.error();
        return remove ? R.ok() : R.fail();
    }
    /**
@@ -93,7 +93,7 @@
    @Log(title = "导入设备能耗", businessType = BusinessType.IMPORT)
    @PostMapping("/importData")
    @Operation(summary = "导入设备能耗")
    public AjaxResult importData(MultipartFile file) throws Exception {
    public R<?> importData(MultipartFile file) throws Exception {
        return equipmentEnergyConsumptionService.importData(file);
    }
@@ -114,9 +114,9 @@
    @GetMapping("/listPageByTrend")
    @Operation(summary = "设备能耗-能源趋势-分页查询")
    @Log(title = "设备能耗-能源趋势-分页查询", businessType = BusinessType.OTHER)
    public AjaxResult listPageByTrend(Page page, EquipmentEnergyConsumption equipmentEnergyConsumption) {
    public R<?> listPageByTrend(Page page, EquipmentEnergyConsumption equipmentEnergyConsumption) {
        IPage<EquipmentEnergyConsumption> listPage = equipmentEnergyConsumptionService.listPageByTrend(page, equipmentEnergyConsumption);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    /**
src/main/java/com/ruoyi/equipmentenergyconsumption/service/EquipmentEnergyConsumptionService.java
@@ -5,7 +5,7 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.device.pojo.DeviceLedger;
import com.ruoyi.equipmentenergyconsumption.pojo.EquipmentEnergyConsumption;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@@ -19,7 +19,7 @@
    IPage<EquipmentEnergyConsumption> listPage(Page page, EquipmentEnergyConsumption equipmentEnergyConsumption);
    AjaxResult importData(MultipartFile file);
    R<?> importData(MultipartFile file);
    IPage<EquipmentEnergyConsumption> listPageByTrend(Page page, EquipmentEnergyConsumption equipmentEnergyConsumption);
src/main/java/com/ruoyi/equipmentenergyconsumption/service/impl/EquipmentEnergyConsumptionServiceImpl.java
@@ -10,7 +10,8 @@
import com.ruoyi.equipmentenergyconsumption.mapper.EquipmentEnergyConsumptionMapper;
import com.ruoyi.equipmentenergyconsumption.pojo.EquipmentEnergyConsumption;
import com.ruoyi.equipmentenergyconsumption.service.EquipmentEnergyConsumptionService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.framework.web.domain.R;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -41,18 +42,18 @@
    }
    @Override
    public AjaxResult importData(MultipartFile file) {
    public R<?> importData(MultipartFile file) {
        try {
            ExcelUtil<EquipmentEnergyConsumption> util = new ExcelUtil<EquipmentEnergyConsumption>(EquipmentEnergyConsumption.class);
            List<EquipmentEnergyConsumption> userList = util.importExcel(file.getInputStream());
            if(CollectionUtils.isEmpty(userList)){
                return AjaxResult.warn("模板错误或导入数据为空");
                return R.fail(HttpStatus.WARN, "模板错误或导入数据为空");
            }
            this.saveOrUpdateBatch(userList);
            return AjaxResult.success(true);
            return R.ok(true);
        }catch (Exception e){
            e.printStackTrace();
            return AjaxResult.error("导入失败");
            return R.fail("导入失败");
        }
    }
src/main/java/com/ruoyi/framework/web/controller/BaseController.java
@@ -16,7 +16,7 @@
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.sql.SqlUtil;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.framework.web.page.PageDomain;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.framework.web.page.TableSupport;
@@ -93,69 +93,69 @@
    /**
     * è¿”回成功
     */
    public AjaxResult success()
    public R<?> success()
    {
        return AjaxResult.success();
        return R.ok();
    }
    /**
     * è¿”回成功消息
     */
    public AjaxResult success(String message)
    public R<?> success(String message)
    {
        return AjaxResult.success(message);
        return R.ok(null, message);
    }
    /**
     * è¿”回成功消息
     */
    public AjaxResult success(Object data)
    public R<?> success(Object data)
    {
        return AjaxResult.success(data);
        return R.ok(data);
    }
    /**
     * è¿”回失败消息
     */
    public AjaxResult error()
    public R<?> error()
    {
        return AjaxResult.error();
        return R.fail();
    }
    /**
     * è¿”回失败消息
     */
    public AjaxResult error(String message)
    public R<?> error(String message)
    {
        return AjaxResult.error(message);
        return R.fail(message);
    }
    /**
     * è¿”回警告消息
     */
    public AjaxResult warn(String message)
    public R<?> warn(String message)
    {
        return AjaxResult.warn(message);
        return R.fail(HttpStatus.WARN, message);
    }
    /**
     * å“åº”返回结果
     *
     *
     * @param rows å½±å“è¡Œæ•°
     * @return æ“ä½œç»“æžœ
     */
    protected AjaxResult toAjax(int rows)
    protected R<?> toAjax(int rows)
    {
        return rows > 0 ? AjaxResult.success() : AjaxResult.error();
        return rows > 0 ? R.ok() : R.fail();
    }
    /**
     * å“åº”返回结果
     *
     *
     * @param result ç»“æžœ
     * @return æ“ä½œç»“æžœ
     */
    protected AjaxResult toAjax(boolean result)
    protected R<?> toAjax(boolean result)
    {
        return result ? success() : error();
    }
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,20 @@
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;
/**
 * @author :yys
@@ -32,293 +50,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);
    }
}
src/main/java/com/ruoyi/lavorissue/controller/LavorIssueController.java
@@ -11,7 +11,7 @@
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.lavorissue.dto.StatisticsLaborIssue;
import com.ruoyi.lavorissue.mapper.LavorIssueMapper;
import com.ruoyi.lavorissue.pojo.LaborIssue;
@@ -52,24 +52,24 @@
    @GetMapping("/listPage")
    @Log(title = "劳保发放-分页查询", businessType = BusinessType.OTHER)
    @Operation(summary = "劳保发放-分页查询")
    public AjaxResult listPage(Page page, LaborIssue laborIssue){
    public R<?> listPage(Page page, LaborIssue laborIssue){
        IPage<LaborIssue> listPage = laborIssueService.listPage(page, laborIssue);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @GetMapping("/statisticsList")
    @Log(title = "劳保发放-统计查询", businessType = BusinessType.OTHER)
    @Operation(summary = "劳保发放-统计查询")
    public AjaxResult statisticsList(LaborIssue laborIssue){
    public R<?> statisticsList(LaborIssue laborIssue){
        List<Map<String, Object>> listPage = laborIssueService.statisticsList(laborIssue);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @PostMapping("/add")
    @Log(title = "劳保发放-添加", businessType = BusinessType.INSERT)
    @Operation(summary = "劳保发放-添加")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody LaborIssue laborIssue){
    public R<?> add(@RequestBody LaborIssue laborIssue){
        String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        StartAndEndDateDto dateTime = DailyRedisCounter.getDateTime();
        Long approveId = lavorIssueMapper.selectCount(new LambdaQueryWrapper<LaborIssue>()
@@ -84,32 +84,32 @@
            laborIssue.setOrderNo(String.format("%03d", l + 1));
        }
        boolean save = laborIssueService.save(laborIssue);
        return save ? AjaxResult.success() : AjaxResult.error();
        return save ? R.ok() : R.fail();
    }
    @PostMapping("/update")
    @Log(title = "劳保发放-修改", businessType = BusinessType.UPDATE)
    @Operation(summary = "劳保发放-修改")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult update(@RequestBody LaborIssue laborIssue){
    public R<?> update(@RequestBody LaborIssue laborIssue){
        boolean update = laborIssueService.updateById(laborIssue);
        return update ? AjaxResult.success() : AjaxResult.error();
        return update ? R.ok() : R.fail();
    }
    @DeleteMapping("/delete")
    @Log(title = "劳保发放-删除", businessType = BusinessType.DELETE)
    @Operation(summary = "劳保发放-删除")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delete(@RequestBody List<Long> ids){
    public R<?> delete(@RequestBody List<Long> ids){
        boolean delete = laborIssueService.removeBatchByIds(ids);
        return delete ? AjaxResult.success() : AjaxResult.error();
        return delete ? R.ok() : R.fail();
    }
    @GetMapping("/statistics")
    @Operation(summary = "劳保发放-统计")
    public AjaxResult statistics(StatisticsLaborIssue req) throws Exception {
    public R<?> statistics(StatisticsLaborIssue req) throws Exception {
        StatisticsLaborIssue statisticsLaborIssue = laborIssueService.statistics(req);
        return AjaxResult.success(statisticsLaborIssue);
        return R.ok(statisticsLaborIssue);
    }
src/main/java/com/ruoyi/measuringinstrumentledger/controller/MeasuringInstrumentLedgerController.java
@@ -6,7 +6,7 @@
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.measuringinstrumentledger.dto.MeasuringInstrumentLedgerDto;
import com.ruoyi.measuringinstrumentledger.mapper.MeasuringInstrumentLedgerRecordMapper;
import com.ruoyi.measuringinstrumentledger.pojo.MeasuringInstrumentLedger;
@@ -43,9 +43,9 @@
    @GetMapping("/listPage")
    @Operation(summary = "计量器具台账-分页查询")
    @Log(title = "计量器具台账-分页查询", businessType = BusinessType.OTHER)
    public AjaxResult listPage(Page page, MeasuringInstrumentLedger measuringInstrumentLedger) {
    public R<?> listPage(Page page, MeasuringInstrumentLedger measuringInstrumentLedger) {
        IPage<MeasuringInstrumentLedger> listPage = measuringInstrumentLedgerService.listPage(page, measuringInstrumentLedger);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
@@ -53,59 +53,59 @@
    @Operation(summary = "计量器具台账-新增")
    @Log(title = "计量器具台账-新增", businessType = BusinessType.INSERT)
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody MeasuringInstrumentLedger measuringInstrumentLedger) throws IOException {
    public R<?> add(@RequestBody MeasuringInstrumentLedger measuringInstrumentLedger) throws IOException {
        boolean save = measuringInstrumentLedgerService.add(measuringInstrumentLedger);
        if (save) {
            return AjaxResult.success();
            return R.ok();
        }
        return AjaxResult.error();
        return R.fail();
    }
    @PostMapping("/update")
    @Operation(summary = "计量器具台账-修改")
    @Log(title = "计量器具台账-修改", businessType = BusinessType.UPDATE)
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult update(@RequestBody MeasuringInstrumentLedger measuringInstrumentLedger) {
    public R<?> update(@RequestBody MeasuringInstrumentLedger measuringInstrumentLedger) {
        SysUser sysUser = sysUserMapper.selectUserById(measuringInstrumentLedger.getUserId());
        if (sysUser == null) {
            return AjaxResult.error("用户不存在");
            return R.fail("用户不存在");
        }
        measuringInstrumentLedger.setUserName(sysUser.getUserName());
        boolean update = measuringInstrumentLedgerService.updateById(measuringInstrumentLedger);
        if (update) {
            return AjaxResult.success();
            return R.ok();
        }
        return AjaxResult.error();
        return R.fail();
    }
    @DeleteMapping("/delete")
    @Operation(summary = "计量器具台账-删除")
    @Log(title = "计量器具台账-删除", businessType = BusinessType.DELETE)
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delete(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("请选择至少一条数据");
    public R<?> delete(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)) return R.fail("请选择至少一条数据");
        for (Long id : ids) {
            LambdaQueryWrapper<MeasuringInstrumentLedgerRecord> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(MeasuringInstrumentLedgerRecord::getMeasuringInstrumentLedgerId,id);
            List<MeasuringInstrumentLedgerRecord> measuringInstrumentLedgerRecords = measuringInstrumentLedgerRecordMapper.selectList(queryWrapper);
            if(!CollectionUtils.isEmpty(measuringInstrumentLedgerRecords)){
                return AjaxResult.error("请先删除选中计量器具台账下的所有检定记录");
                return R.fail("请先删除选中计量器具台账下的所有检定记录");
            }
        }
        boolean delete = measuringInstrumentLedgerService.removeBatchByIds(ids);
        if (delete) {
            return AjaxResult.success();
            return R.ok();
        }
        return AjaxResult.error();
        return R.fail();
    }
    @PostMapping("/verifying")
    @Operation(summary = "计量器具台账-检定")
    @Log(title = "计量器具台账-检定", businessType = BusinessType.UPDATE)
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult verifying(@RequestBody MeasuringInstrumentLedgerDto measuringInstrumentLedger) throws IOException {
    public R<?> verifying(@RequestBody MeasuringInstrumentLedgerDto measuringInstrumentLedger) throws IOException {
        boolean update = measuringInstrumentLedgerService.verifying(measuringInstrumentLedger);
        return update ? AjaxResult.success("检定成功") : AjaxResult.error("检定失败");
        return update ? R.ok(null, "检定成功") : R.fail("检定失败");
    }
    /**
src/main/java/com/ruoyi/measuringinstrumentledger/controller/MeasuringInstrumentLedgerRecordController.java
@@ -5,7 +5,7 @@
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.measuringinstrumentledger.pojo.MeasuringInstrumentLedgerRecord;
import com.ruoyi.measuringinstrumentledger.service.MeasuringInstrumentLedgerRecordService;
import io.jsonwebtoken.lang.Collections;
@@ -36,29 +36,29 @@
    @GetMapping("/listPage")
    @Operation(summary = "计量器具台账记录-分页查询")
    @Log(title = "计量器具台账记录-分页查询", businessType = BusinessType.OTHER)
    public AjaxResult listPage(Page page, MeasuringInstrumentLedgerRecord measuringInstrumentLedgerRecord){
    public R<?> listPage(Page page, MeasuringInstrumentLedgerRecord measuringInstrumentLedgerRecord){
        IPage<MeasuringInstrumentLedgerRecord> listPage = measuringInstrumentLedgerRecordService.listPage(page, measuringInstrumentLedgerRecord);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @PostMapping("/update")
    @Operation(summary = "计量器具台账记录-修改")
    @Log(title = "计量器具台账记录-修改", businessType = BusinessType.UPDATE)
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult update(@RequestBody MeasuringInstrumentLedgerRecord measuringInstrumentLedgerRecord) throws IOException {
    public R<?> update(@RequestBody MeasuringInstrumentLedgerRecord measuringInstrumentLedgerRecord) throws IOException {
        boolean update = measuringInstrumentLedgerRecordService.updateMeasuringInstrumentLedgerRecord(measuringInstrumentLedgerRecord);
        if (update) {
            return AjaxResult.success();
            return R.ok();
        }
        return AjaxResult.error();
        return R.fail();
    }
    @DeleteMapping("/delete")
    @Operation(summary = "计量器具台账记录-删除")
    @Log(title = "计量器具台账记录-删除", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
        if(Collections.isEmpty(ids)) return AjaxResult.error("请选择要删除的数据");
        return AjaxResult.success(measuringInstrumentLedgerRecordService.removeBatchByIds(ids));
    public R<?> delete(@RequestBody List<Long> ids) {
        if(Collections.isEmpty(ids)) return R.fail("请选择要删除的数据");
        return R.ok(measuringInstrumentLedgerRecordService.removeBatchByIds(ids));
    }
    /**
src/main/java/com/ruoyi/measuringinstrumentledger/controller/SparePartsController.java
@@ -5,7 +5,8 @@
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.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.measuringinstrumentledger.dto.SparePartsDto;
import com.ruoyi.measuringinstrumentledger.pojo.SpareParts;
import com.ruoyi.measuringinstrumentledger.service.SparePartsService;
@@ -21,19 +22,19 @@
@RequestMapping("/spareParts")
@Tag(name = "备件分类接口")
@AllArgsConstructor
public class SparePartsController {
public class SparePartsController extends BaseController {
    private SparePartsService sparePartsService;
    @GetMapping("/getTree")
    @Operation(summary = "备件分类-树结构")
    public AjaxResult getTree(){
    public R<?> getTree(){
        List<SparePartsDto> tree = sparePartsService.getTree();
        return AjaxResult.success(tree);
        return R.ok(tree);
    }
    @GetMapping("/listPage")
    @Operation(summary = "备件分类-分页查询")
    public AjaxResult listPage(Page page, SpareParts spareParts){
    public R<?> listPage(Page page, SpareParts spareParts){
        IPage<SparePartsDto> listPage = sparePartsService.listPage(page, spareParts);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
//    @GetMapping("/list")
//    @Operation(summary = "备件分类-查询所有")
@@ -43,20 +44,20 @@
    @PostMapping("/add")
    @Operation(summary = "备件分类-添加")
    @Log(title = "备件分类-添加", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody SpareParts spareParts){
        return AjaxResult.success(sparePartsService.save(spareParts));
    public R<?> add(@RequestBody SpareParts spareParts){
        return R.ok(sparePartsService.save(spareParts));
    }
    @PostMapping("/update")
    @Operation(summary = "备件分类-更新")
    @Log(title = "备件分类-更新", businessType = BusinessType.UPDATE)
    public AjaxResult update(@RequestBody SpareParts spareParts){
        return AjaxResult.success(sparePartsService.updateById(spareParts));
    public R<?> update(@RequestBody SpareParts spareParts){
        return R.ok(sparePartsService.updateById(spareParts));
    }
    @DeleteMapping("/delete/{id}")
    @Operation(summary = "备件分类-删除")
    @Log(title = "备件分类-删除", businessType = BusinessType.DELETE)
    public AjaxResult delete(@PathVariable Long id){
        return AjaxResult.success(sparePartsService.removeById(id));
    public R<?> delete(@PathVariable Long id){
        return R.ok(sparePartsService.removeById(id));
    }
}
src/main/java/com/ruoyi/measuringinstrumentledger/controller/SparePartsRequisitionRecordController.java
@@ -2,7 +2,8 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.measuringinstrumentledger.dto.SparePartsRequisitionRecordDto;
import com.ruoyi.measuringinstrumentledger.service.SparePartsRequisitionRecordService;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -24,13 +25,13 @@
@RequestMapping("/sparePartsRequisitionRecord")
@Tag(name = "备件领用记录接口")
@AllArgsConstructor
public class SparePartsRequisitionRecordController {
public class SparePartsRequisitionRecordController extends BaseController {
    private SparePartsRequisitionRecordService sparePartsRequisitionRecordService;
    @GetMapping("/listPage")
    @Operation(summary = "备件分类-分页查询")
    public AjaxResult listPage(Page page, SparePartsRequisitionRecordDto sparePartsRequisitionRecordDto){
    public R<?> listPage(Page page, SparePartsRequisitionRecordDto sparePartsRequisitionRecordDto){
        IPage<SparePartsRequisitionRecordDto> listPage = sparePartsRequisitionRecordService.listPage(page, sparePartsRequisitionRecordDto);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
}
src/main/java/com/ruoyi/officesupplies/controller/OfficeSuppliesController.java
@@ -7,7 +7,7 @@
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.officesupplies.pojo.OfficeSupplies;
import com.ruoyi.officesupplies.service.OfficeSuppliesService;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -38,14 +38,14 @@
    @GetMapping("/listPage")
    @Operation(summary = "办公物资-分页查询")
    public AjaxResult listPage(Page page, OfficeSupplies officeSupplies) {
    public R<?> listPage(Page page, OfficeSupplies officeSupplies) {
        return officeSuppliesService.listPage(page, officeSupplies);
    }
    @PostMapping("/add")
    @Operation(summary = "办公物资-添加")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody OfficeSupplies officeSupplies) {
    public R<?> add(@RequestBody OfficeSupplies officeSupplies) {
        // æŒ‰ç…§å½“前时间yyyyMMdd + å½“天新增数量 + 1生成编号
        // èŽ·å–å½“å¤©æ–°å¢žæ•°é‡
        long count = officeSuppliesService.count(new LambdaQueryWrapper<OfficeSupplies>()
@@ -55,22 +55,22 @@
        officeSupplies.setCode(code);
        officeSupplies.setStatus(1);
        officeSupplies.setApplyTime(new Date());
        return officeSuppliesService.save(officeSupplies) ? success() : error();
        return officeSuppliesService.save(officeSupplies) ? R.ok() : R.fail();
    }
    @PostMapping("/update")
    @Operation(summary = "办公物资-修改")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult update(@RequestBody OfficeSupplies officeSupplies) {
        return officeSuppliesService.updateById(officeSupplies) ? success() : error();
    public R<?> update(@RequestBody OfficeSupplies officeSupplies) {
        return officeSuppliesService.updateById(officeSupplies) ? R.ok() : R.fail();
    }
    @DeleteMapping("/delete")
    @Operation(summary = "办公物资-删除")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delete(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("请传入要删除的ID");
        return officeSuppliesService.removeBatchByIds(ids) ? success() : error();
    public R<?> delete(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)) return R.fail("请传入要删除的ID");
        return officeSuppliesService.removeBatchByIds(ids) ? R.ok() : R.fail();
    }
    /**
src/main/java/com/ruoyi/officesupplies/service/OfficeSuppliesService.java
@@ -2,7 +2,7 @@
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.framework.web.domain.R;
import com.ruoyi.officesupplies.pojo.OfficeSupplies;
/**
@@ -18,5 +18,5 @@
     * @param officeSupplies
     * @return
     */
    AjaxResult listPage(Page page, OfficeSupplies officeSupplies);
    R<?> listPage(Page page, OfficeSupplies officeSupplies);
}
src/main/java/com/ruoyi/officesupplies/service/impl/OfficeSuppliesServiceImpl.java
@@ -3,7 +3,7 @@
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.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.officesupplies.mapper.OfficeSuppliesMapper;
import com.ruoyi.officesupplies.pojo.OfficeSupplies;
import com.ruoyi.officesupplies.service.OfficeSuppliesService;
@@ -23,8 +23,8 @@
    private final OfficeSuppliesMapper officeSuppliesMapper;
    @Override
    public AjaxResult listPage(Page page, OfficeSupplies officeSupplies) {
    public R<?> listPage(Page page, OfficeSupplies officeSupplies) {
        IPage<OfficeSupplies> list = officeSuppliesMapper.listPage(page, officeSupplies);
        return AjaxResult.success(list);
        return R.ok(list);
    }
}
src/main/java/com/ruoyi/procurementrecord/controller/GasTankWarningController.java
@@ -3,7 +3,8 @@
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.pojo.GasTankWarning;
import com.ruoyi.procurementrecord.service.GasTankWarningService;
import jakarta.servlet.http.HttpServletResponse;
@@ -15,28 +16,28 @@
@RestController
@RequestMapping("/gasTankWarning")
@AllArgsConstructor
public class GasTankWarningController {
public class GasTankWarningController extends BaseController {
    private GasTankWarningService gasTankWarningService;
    @GetMapping("/listPage")
    public AjaxResult listPage(Page page, GasTankWarning gasTankWarning) {
        return AjaxResult.success(gasTankWarningService.listPage(page, gasTankWarning));
    public R<?> listPage(Page page, GasTankWarning gasTankWarning) {
        return R.ok(gasTankWarningService.listPage(page, gasTankWarning));
    }
    @PostMapping("/add")
    public AjaxResult add(@RequestBody GasTankWarning gasTankWarning) {
        return AjaxResult.success(gasTankWarningService.save(gasTankWarning));
    public R<?> add(@RequestBody GasTankWarning gasTankWarning) {
        return R.ok(gasTankWarningService.save(gasTankWarning));
    }
    @PostMapping("update")
    public AjaxResult update(@RequestBody GasTankWarning gasTankWarning) {
        return AjaxResult.success(gasTankWarningService.updateById(gasTankWarning));
    public R<?> update(@RequestBody GasTankWarning gasTankWarning) {
        return R.ok(gasTankWarningService.updateById(gasTankWarning));
    }
    @DeleteMapping("delete")
    public AjaxResult delete(@RequestBody List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) return AjaxResult.error("请传入要删除的ID");
        return AjaxResult.success(gasTankWarningService.removeByIds(ids));
    public R<?> delete(@RequestBody List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) return R.fail("请传入要删除的ID");
        return R.ok(gasTankWarningService.removeByIds(ids));
    }
    //导出
src/main/java/com/ruoyi/procurementrecord/controller/InboundManagementController.java
@@ -4,7 +4,7 @@
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.pojo.InboundManagement;
import com.ruoyi.procurementrecord.service.InboundManagementService;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -30,35 +30,35 @@
    @GetMapping("/listPage")
    @Operation(summary = "到货管理-查询")
    public AjaxResult listPage(Page page, InboundManagement inboundManagement) {
    public R<?> listPage(Page page, InboundManagement inboundManagement) {
        IPage<InboundManagement> result = inboundManagementService.listPage(page, inboundManagement);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @PostMapping("/add")
    @Operation(summary = "到货管理-添加")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody InboundManagement inboundManagement) {
    public R<?> add(@RequestBody InboundManagement inboundManagement) {
        inboundManagement.setArrivalTime(new Date());
        boolean result = inboundManagementService.save(inboundManagement);
        return result ? AjaxResult.success() : AjaxResult.error();
        return result ? R.ok() : R.fail();
    }
    @PostMapping("/update")
    @Operation(summary = "到货管理-修改")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult update(@RequestBody InboundManagement inboundManagement) {
    public R<?> update(@RequestBody InboundManagement inboundManagement) {
        boolean result = inboundManagementService.updateById(inboundManagement);
        return result ? AjaxResult.success() : AjaxResult.error();
        return result ? R.ok() : R.fail();
    }
    @DeleteMapping("/del")
    @Operation(summary = "到货管理-删除")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult del(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("请选择至少一条数据");
    public R<?> del(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)) return R.fail("请选择至少一条数据");
        boolean result = inboundManagementService.removeByIds(ids);
        return result ? AjaxResult.success() : AjaxResult.error();
        return result ? R.ok() : R.fail();
    }
}
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementExceptionRecordController.java
@@ -1,7 +1,7 @@
package com.ruoyi.procurementrecord.controller;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.mapper.ProcurementExceptionRecordMapper;
import com.ruoyi.procurementrecord.pojo.ProcurementExceptionRecord;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -23,13 +23,13 @@
    @PostMapping("/add")
    @Transactional
    public AjaxResult add(@RequestBody ProcurementExceptionRecord procurementExceptionRecord) {
        return AjaxResult.success(procurementExceptionRecordMapper.insert(procurementExceptionRecord));
    public R<?> add(@RequestBody ProcurementExceptionRecord procurementExceptionRecord) {
        return R.ok(procurementExceptionRecordMapper.insert(procurementExceptionRecord));
    }
    @PostMapping("/update")
    @Transactional
    public AjaxResult updatePro(@RequestBody ProcurementExceptionRecord procurementExceptionRecord) {
        return AjaxResult.success(procurementExceptionRecordMapper.updateById(procurementExceptionRecord));
    public R<?> updatePro(@RequestBody ProcurementExceptionRecord procurementExceptionRecord) {
        return R.ok(procurementExceptionRecordMapper.updateById(procurementExceptionRecord));
    }
}
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementPlanController.java
@@ -3,7 +3,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.pojo.ProcurementPlan;
import com.ruoyi.procurementrecord.service.ProcurementPlanService;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -28,30 +28,30 @@
    @RequestMapping("/listPage")
    @Operation(summary = "采购计划-查询")
    public AjaxResult listPage(Page page, ProcurementPlan procurementPlan){
    public R<?> listPage(Page page, ProcurementPlan procurementPlan){
        IPage<ProcurementPlan> result = procurementPlanService.listPage(page, procurementPlan);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @PostMapping("/add")
    @Operation(summary = "采购计划-添加")
    public AjaxResult add(@RequestBody ProcurementPlan procurementPlan){
    public R<?> add(@RequestBody ProcurementPlan procurementPlan){
        boolean result = procurementPlanService.save(procurementPlan);
        return result ? AjaxResult.success() : AjaxResult.error();
        return result ? R.ok() : R.fail();
    }
    @PostMapping("/update")
    @Operation(summary = "采购计划-修改")
    public AjaxResult update(@RequestBody ProcurementPlan procurementPlan){
    public R<?> update(@RequestBody ProcurementPlan procurementPlan){
        boolean result = procurementPlanService.updateById(procurementPlan);
        return result ? AjaxResult.success() : AjaxResult.error();
        return result ? R.ok() : R.fail();
    }
    @DeleteMapping("/del")
    @Operation(summary = "采购计划-删除")
    public AjaxResult del(@RequestBody List<Long> ids){
    public R<?> del(@RequestBody List<Long> ids){
        boolean result = procurementPlanService.removeByIds(ids);
        return result ? AjaxResult.success() : AjaxResult.error();
        return result ? R.ok() : R.fail();
    }
    /**
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementPriceManagementController.java
@@ -3,7 +3,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.pojo.ProcurementPriceManagement;
import com.ruoyi.procurementrecord.service.ProcurementPriceManagementService;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -29,36 +29,36 @@
    @GetMapping("/listPage")
    @Operation(summary = "采购价格管理-查询")
    public AjaxResult listPage(Page page, ProcurementPriceManagement procurementPriceManagement){
    public R<?> listPage(Page page, ProcurementPriceManagement procurementPriceManagement){
        IPage<ProcurementPriceManagement> result = procurementPriceManagementService.listPage(page, procurementPriceManagement);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @PostMapping("/add")
    @Operation(summary = "采购价格管理-添加")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody ProcurementPriceManagement procurementPriceManagement){
    public R<?> add(@RequestBody ProcurementPriceManagement procurementPriceManagement){
        boolean result = procurementPriceManagementService.save(procurementPriceManagement);
        return result ? AjaxResult.success() : AjaxResult.error();
        return result ? R.ok() : R.fail();
    }
    @PostMapping("/update")
    @Operation(summary = "采购价格管理-修改")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult update(@RequestBody ProcurementPriceManagement procurementPriceManagement){
    public R<?> update(@RequestBody ProcurementPriceManagement procurementPriceManagement){
        boolean result = procurementPriceManagementService.updateById(procurementPriceManagement);
        return result ? AjaxResult.success() : AjaxResult.error();
        return result ? R.ok() : R.fail();
    }
    @DeleteMapping("/del")
    @Operation(summary = "采购价格管理-删除")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delete(@RequestBody List<Long> ids){
    public R<?> delete(@RequestBody List<Long> ids){
        if (ids == null || ids.isEmpty()) {
            return AjaxResult.error("请传入要删除的ID");
            return R.fail("请传入要删除的ID");
        }
        boolean result = procurementPriceManagementService.removeByIds(ids);
        return result ? AjaxResult.success() : AjaxResult.error();
        return result ? R.ok() : R.fail();
    }
    /**
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java
@@ -7,7 +7,7 @@
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.procurementrecord.bean.dto.*;
import com.ruoyi.procurementrecord.mapper.CustomStorageMapper;
import com.ruoyi.procurementrecord.pojo.CustomStorage;
@@ -44,139 +44,139 @@
     */
    @GetMapping("/getProcurementAmount")
    @Operation(summary = "通过销售产品id获取入库数量")
    public AjaxResult getProcurementAmount(@RequestParam("salesProductId") Long salesProductId) {
        return AjaxResult.success(procurementRecordService.getProcurementAmount(salesProductId));
    public R<?> getProcurementAmount(@RequestParam("salesProductId") Long salesProductId) {
        return R.ok(procurementRecordService.getProcurementAmount(salesProductId));
    }
    @GetMapping("/productlist")
    @Log(title = "采购入库-入库管理-新增入库查询", businessType = BusinessType.OTHER)
    public AjaxResult list(ProcurementDto procurementDto) {
    public R<?> list(ProcurementDto procurementDto) {
        List<ProcurementDto> result = procurementRecordService.listProcurementBySalesLedgerId(procurementDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @PostMapping("/add")
    @Log(title = "采购入库-入库管理-新增入库", businessType = BusinessType.INSERT)
    @Transactional
    public AjaxResult add(@RequestBody ProcurementAddDto procurementDto) {
    public R<?> add(@RequestBody ProcurementAddDto procurementDto) {
        procurementDto.setType(1);
        procurementDto.setTypeName("采购入库");
        return AjaxResult.success(procurementRecordService.add(procurementDto));
        return R.ok(procurementRecordService.add(procurementDto));
    }
    @PostMapping("/addCustom")
    @Log(title = "自定义入库-入库管理-新增入库", businessType = BusinessType.INSERT)
    @Transactional
    public AjaxResult addCustom(@RequestBody List<CustomStorage> customStorage) {
    public R<?> addCustom(@RequestBody List<CustomStorage> customStorage) {
        return procurementRecordService.addCustom(customStorage);
    }
    @PostMapping("/updateCustom")
    @Log(title = "自定义入库-入库管理-修改入库", businessType = BusinessType.UPDATE)
    @Transactional
    public AjaxResult updateCustom(@RequestBody CustomStorage customStorage) {
    public R<?> updateCustom(@RequestBody CustomStorage customStorage) {
        return procurementRecordService.updateCustom(customStorage);
    }
    @Delete("/delteCustom")
    @Log(title = "自定义入库-入库管理-删除入库", businessType = BusinessType.DELETE)
    @Transactional
    public AjaxResult deleteCustom(@RequestBody List<Long> ids) {
    public R<?> deleteCustom(@RequestBody List<Long> ids) {
        return procurementRecordService.deleteCustom(ids);
    }
    @PostMapping("/update")
    @Log(title = "采购入库-入库管理-修改入库", businessType = BusinessType.UPDATE)
    @Transactional
    public AjaxResult updatePro(@RequestBody ProcurementUpdateDto procurementDto) {
        return AjaxResult.success(procurementRecordService.updatePro(procurementDto));
    public R<?> updatePro(@RequestBody ProcurementUpdateDto procurementDto) {
        return R.ok(procurementRecordService.updatePro(procurementDto));
    }
    @PostMapping("/updateManagement")
    @Log(title = "成品入库-库存台账-修改", businessType = BusinessType.UPDATE)
    @Transactional
    public AjaxResult updateManagement(@RequestBody ProcurementManagementUpdateDto procurementDto) {
        return AjaxResult.success(procurementRecordService.updateManagement(procurementDto));
    public R<?> updateManagement(@RequestBody ProcurementManagementUpdateDto procurementDto) {
        return R.ok(procurementRecordService.updateManagement(procurementDto));
    }
    @PostMapping("/updateManagementByCustom")
    @Log(title = "自定义入库-库存台账-修改", businessType = BusinessType.UPDATE)
    @Transactional
    public AjaxResult updateManagementByCustom(@RequestBody ProcurementManagementUpdateDto procurementDto) {
        return AjaxResult.success(procurementRecordService.updateManagementByCustom(procurementDto));
    public R<?> updateManagementByCustom(@RequestBody ProcurementManagementUpdateDto procurementDto) {
        return R.ok(procurementRecordService.updateManagementByCustom(procurementDto));
    }
    @PostMapping("/del")
    @Log(title = "采购入库-入库管理-删除入库", businessType = BusinessType.DELETE)
    @Transactional
    public AjaxResult deletePro(@RequestBody ProcurementUpdateDto procurementDto) {
        return AjaxResult.success(procurementRecordService.deletePro(procurementDto));
    public R<?> deletePro(@RequestBody ProcurementUpdateDto procurementDto) {
        return R.ok(procurementRecordService.deletePro(procurementDto));
    }
    @GetMapping("/listPage")
    @Log(title = "采购入库-入库管理-入库查询", businessType = BusinessType.OTHER)
    @Operation(summary = "入库查询")
    public AjaxResult listPage(Page page, ProcurementPageDto procurementDto) {
    public R<?> listPage(Page page, ProcurementPageDto procurementDto) {
        IPage<ProcurementPageDto> result = procurementRecordService.listPage(page, procurementDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @GetMapping("/listReport")
    @Operation(summary = "查询库存图表数据")
    public AjaxResult listReport() {
        return AjaxResult.success(procurementRecordService.getReportList());
    public R<?> listReport() {
        return R.ok(procurementRecordService.getReportList());
    }
    @GetMapping("/listPageByProduction")
    @Log(title = "生产入库-入库管理-入库查询", businessType = BusinessType.OTHER)
    @Operation(summary = "入库查询")
    public AjaxResult listPageByProduction(Page page, ProcurementPageDto procurementDto) {
    public R<?> listPageByProduction(Page page, ProcurementPageDto procurementDto) {
        IPage<ProcurementPageDto> result = procurementRecordService.listPageByProduction(page, procurementDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @GetMapping("/listPageByProductProduction")
    @Log(title = "生产入库-入库管理-生产入库查询", businessType = BusinessType.OTHER)
    @Operation(summary = "入库查询")
    public AjaxResult listPageByProductProduction(Page page, ProcurementPageDto procurementDto) {
    public R<?> listPageByProductProduction(Page page, ProcurementPageDto procurementDto) {
        IPage<ProcurementPageDto> result = procurementRecordService.listPageByProductProduction(page, procurementDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @GetMapping("/listPageByCustom")
    @Log(title = "自定义入库-入库管理-入库查询", businessType = BusinessType.OTHER)
    @Operation(summary = "入库查询")
    public AjaxResult listPageByCustom(Page page, CustomStorage customStorage) {
    public R<?> listPageByCustom(Page page, CustomStorage customStorage) {
        IPage<CustomStorage> result = procurementRecordService.listPageByCustom(page, customStorage);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @GetMapping("/listPageCopy")
    @Log(title = "采购入库-库存管理-分页查询", businessType = BusinessType.OTHER)
    public AjaxResult listPageCopy(Page page, ProcurementPageDto procurementDto) {
    public R<?> listPageCopy(Page page, ProcurementPageDto procurementDto) {
        IPage<ProcurementPageDtoCopy> result = procurementRecordService.listPageCopy(page, procurementDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @GetMapping("/listPageCopyByProduction")
    @Log(title = "生产入库-库存管理-分页查询", businessType = BusinessType.OTHER)
    public AjaxResult listPageCopyByProduction(Page page, ProcurementPageDto procurementDto) {
    public R<?> listPageCopyByProduction(Page page, ProcurementPageDto procurementDto) {
        IPage<ProcurementPageDtoCopy> result = procurementRecordService.listPageCopyByProduction(page, procurementDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @GetMapping("/listPageCopyByCustom")
    @Log(title = "自定义入库-库存管理-分页查询", businessType = BusinessType.OTHER)
    public AjaxResult listPageCopyByCustom(Page page, CustomStorage customStorage) {
    public R<?> listPageCopyByCustom(Page page, CustomStorage customStorage) {
        IPage<CustomStorage> result = procurementRecordService.listPageCopyByCustom(page, customStorage);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @GetMapping("/getReportList")
    @Log(title = "库存报表查询", businessType = BusinessType.OTHER)
    public AjaxResult getReportList(Page page, ProcurementPageDto procurementDto) {
        return AjaxResult.success(procurementRecordService.getReportList(page, procurementDto));
    public R<?> getReportList(Page page, ProcurementPageDto procurementDto) {
        return R.ok(procurementRecordService.getReportList(page, procurementDto));
    }
    /**
@@ -244,8 +244,8 @@
    @GetMapping("/listPageProductionStock")
    @Log(title = "库存管理-成品库存", businessType = BusinessType.OTHER)
    public AjaxResult listPageProductionStock(Page page, ProcurementPageDto procurementDto) {
    public R<?> listPageProductionStock(Page page, ProcurementPageDto procurementDto) {
        IPage<ProductModel> result = procurementRecordService.listPageProductionStock(page, procurementDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
}
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordOutController.java
@@ -6,7 +6,7 @@
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.procurementrecord.bean.dto.ProcurementRecordOutAdd;
import com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto;
import com.ruoyi.procurementrecord.bean.dto.ProcurementUpdateDto;
@@ -34,42 +34,42 @@
    @PostMapping("/stockout")
    @Log(title = "采购出库-出库管理-出库", businessType = BusinessType.INSERT)
    public AjaxResult stockout(@RequestBody ProcurementRecordOutAdd procurementRecordOutAdd) {
        return AjaxResult.success(procurementRecordOutService.stockout(procurementRecordOutAdd));
    public R<?> stockout(@RequestBody ProcurementRecordOutAdd procurementRecordOutAdd) {
        return R.ok(procurementRecordOutService.stockout(procurementRecordOutAdd));
    }
    @GetMapping("/listPage")
    @Log(title = "采购出库-出库台账-出库查询", businessType = BusinessType.OTHER)
    public AjaxResult listPage(Page page, ProcurementRecordOutPageDto procurementDto) {
    public R<?> listPage(Page page, ProcurementRecordOutPageDto procurementDto) {
        IPage<ProcurementRecordOutPageDto> result = procurementRecordOutService.listPage(page, procurementDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @GetMapping("/listPageByProduct")
    @Log(title = "生产出库-出库台账-出库查询", businessType = BusinessType.OTHER)
    public AjaxResult listPageByProduct(Page page, ProcurementRecordOutPageDto procurementDto) {
    public R<?> listPageByProduct(Page page, ProcurementRecordOutPageDto procurementDto) {
        IPage<ProcurementRecordOutPageDto> result = procurementRecordOutService.listPageByProduct(page, procurementDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @GetMapping("/listPageBySemiProduct")
    @Log(title = "生产出库-出库台账-出库查询", businessType = BusinessType.OTHER)
    public AjaxResult listPageBySemiProduct(Page page, ProcurementRecordOutPageDto procurementDto) {
    public R<?> listPageBySemiProduct(Page page, ProcurementRecordOutPageDto procurementDto) {
        IPage<ProcurementRecordOutPageDto> result = procurementRecordOutService.listPageBySemiProduct(page, procurementDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @GetMapping("/listPageByCustom")
    @Log(title = "自定义出库-出库台账-出库查询", businessType = BusinessType.OTHER)
    public AjaxResult listPageByCustom(Page page, ProcurementRecordOutPageDto procurementDto) {
    public R<?> listPageByCustom(Page page, ProcurementRecordOutPageDto procurementDto) {
        IPage<ProcurementRecordOutPageDto> result = procurementRecordOutService.listPageByCustom(page, procurementDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @PostMapping("/del")
    @Log(title = "采购出库-出库台账-删除出库", businessType = BusinessType.DELETE)
    public AjaxResult deletePro(@RequestBody ProcurementUpdateDto procurementDto) {
        return AjaxResult.success(procurementRecordOutService.deletePro(procurementDto));
    public R<?> deletePro(@RequestBody ProcurementUpdateDto procurementDto) {
        return R.ok(procurementRecordOutService.deletePro(procurementDto));
    }
    /**
src/main/java/com/ruoyi/procurementrecord/controller/ReturnManagementController.java
@@ -5,7 +5,7 @@
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.bean.dto.ReturnManagementDto;
import com.ruoyi.procurementrecord.bean.vo.ShippingInfoVo;
import com.ruoyi.procurementrecord.pojo.ReturnSaleProduct;
@@ -34,58 +34,58 @@
    @GetMapping("/listPage")
    @Operation(summary = "销售退货-查询")
    public AjaxResult listPage(Page page, ReturnManagementDto returnManagement) {
    public R<?> listPage(Page page, ReturnManagementDto returnManagement) {
        IPage<ReturnManagementDto> result = returnManagementService.listPage(page, returnManagement);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @PostMapping("/add")
    @Operation(summary = "销售退货-添加")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody ReturnManagementDto returnManagementDto) {
        return returnManagementService.addReturnManagementDto(returnManagementDto) ? success() : error();
    public R<?> add(@RequestBody ReturnManagementDto returnManagementDto) {
        return returnManagementService.addReturnManagementDto(returnManagementDto) ? R.ok() : R.fail();
    }
    @PostMapping("/update")
    @Operation(summary = "销售退货-修改")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult update(@RequestBody ReturnManagementDto returnManagementDto) {
        return returnManagementService.updateReturnManagementDto(returnManagementDto) ? success() : error();
    public R<?> update(@RequestBody ReturnManagementDto returnManagementDto) {
        return returnManagementService.updateReturnManagementDto(returnManagementDto) ? R.ok() : R.fail();
    }
    @Operation(summary = "销售退货-处理退货单")
    @GetMapping("/handle")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult handle(Long returnManagementId) {
        return returnManagementService.handle(returnManagementId) ? success() : error();
    public R<?> handle(Long returnManagementId) {
        return returnManagementService.handle(returnManagementId) ? R.ok() : R.fail();
    }
    @DeleteMapping("/del")
    @Operation(summary = "销售退货-删除")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult del(@RequestBody List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) return error("请选择至少一条数据");
    public R<?> del(@RequestBody List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) return R.fail("请选择至少一条数据");
        returnSaleProductService.remove(new QueryWrapper<ReturnSaleProduct>()
                .lambda()
                .in(ReturnSaleProduct::getReturnManagementId, ids));
        boolean result = returnManagementService.removeByIds(ids);
        return result ? success() : error();
        return result ? R.ok() : R.fail();
    }
    @GetMapping("/getById")
    @Operation(summary = "销售退货-根据id查询")
    public AjaxResult getById(Long returnManagementId) {
    public R<?> getById(Long returnManagementId) {
        ReturnManagementDto returnManagementDto = returnManagementService.getReturnManagementDtoById(returnManagementId);
        return success(returnManagementDto);
        return R.ok(returnManagementDto);
    }
    @GetMapping("/getByShippingId")
    @Operation(summary = "销售退货-根据发货单查询销售订单以及出库的产品信息")
    public AjaxResult getByShippingId(Long shippingId) {
    public R<?> getByShippingId(Long shippingId) {
        ShippingInfoVo shippingInfoVo = returnManagementService.getReturnManagementDtoByShippingIdId(shippingId);
        return success(shippingInfoVo);
        return R.ok(shippingInfoVo);
    }
}
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;
src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java
@@ -4,7 +4,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.bean.dto.*;
import com.ruoyi.procurementrecord.pojo.CustomStorage;
import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
@@ -43,7 +43,7 @@
    IPage<ProcurementPageDto> listPageByProduction(Page page, ProcurementPageDto procurementDto);
    AjaxResult addCustom(List<CustomStorage> customStorage);
    R<?> addCustom(List<CustomStorage> customStorage);
    IPage<CustomStorage> listPageByCustom(Page page, CustomStorage customStorage);
@@ -51,9 +51,9 @@
    IPage<CustomStorage> listPageCopyByCustom(Page page, CustomStorage customStorage);
    AjaxResult updateCustom(CustomStorage customStorage);
    R<?> updateCustom(CustomStorage customStorage);
    AjaxResult deleteCustom(List<Long> ids);
    R<?> deleteCustom(List<Long> ids);
    int updateManagementByCustom(ProcurementManagementUpdateDto procurementDto);
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java
@@ -11,7 +11,7 @@
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.bean.dto.*;
import com.ruoyi.procurementrecord.mapper.CustomStorageMapper;
import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
@@ -525,10 +525,10 @@
    private final CustomStorageMapper customStorageMapper;
    @Override
    public AjaxResult addCustom(List<CustomStorage> customStorage) {
    public R<?> addCustom(List<CustomStorage> customStorage) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if(CollectionUtils.isEmpty(customStorage)){
            return AjaxResult.error("数据不能为空");
            return R.fail("数据不能为空");
        }
        customStorage.forEach(item -> {
            // æŸ¥è¯¢é‡‡è´­å…¥åº“数量
@@ -538,7 +538,7 @@
            item.setCode(OrderUtils.countTodayByCreateTime(customStorageMapper, "", "code"));
            customStorageMapper.insert(item);
        });
        return AjaxResult.success("自定义入库成功");
        return R.ok(null, "自定义入库成功");
    }
    @Override
@@ -716,13 +716,13 @@
    }
    @Override
    public AjaxResult updateCustom(CustomStorage customStorage) {
        return AjaxResult.success(customStorageMapper.updateById(customStorage));
    public R<?> updateCustom(CustomStorage customStorage) {
        return R.ok(customStorageMapper.updateById(customStorage));
    }
    @Override
    public AjaxResult deleteCustom(List<Long> ids) {
        return AjaxResult.success(customStorageMapper.deleteBatchIds(ids));
    public R<?> deleteCustom(List<Long> ids) {
        return R.ok(customStorageMapper.deleteBatchIds(ids));
    }
    @Override
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;
}
src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java
@@ -39,7 +39,7 @@
    @PostMapping("/updateRouteItem")
    @Operation(summary = "修改生产订单的工艺路线详情")
    public R updateRouteItem(@RequestBody ProductionOrderRoutingOperation productionOrderRoutingOperation) {
        return R.ok(productionOrderRoutingOperationService.updateById(productionOrderRoutingOperation));
        return R.ok(productionOrderRoutingOperationService.updateRouteItem(productionOrderRoutingOperation));
    }
    @DeleteMapping("/deleteRouteItem/{id}")
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);
}
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);
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;
@@ -291,8 +292,15 @@
                                            ProductionOrderBom orderBom,
                                            List<ProductionBomStructure> structureList,
                                            Long rootProductModelId) {
        // é‡æ–°æŸ¥è¯¢BOM结构,按子节点优先排序
        List<ProductionBomStructure> routingStructureList = this.list(
                Wrappers.<ProductionBomStructure>lambdaQuery()
                        .eq(ProductionBomStructure::getProductionOrderBomId, orderBom.getId())
                        .orderByDesc(ProductionBomStructure::getParentId)
                        .orderByAsc(ProductionBomStructure::getId));
        ProductionOrderRouting orderRouting = getOrCreateOrderRoutingSnapshot(productionOrderId, productionOrder, orderBom, rootProductModelId);
        List<ProductionOrderRoutingOperation> desiredOperationList = buildDesiredRoutingOperationList(structureList, rootProductModelId);
        List<ProductionOrderRoutingOperation> desiredOperationList = buildDesiredRoutingOperationList(routingStructureList, rootProductModelId);
        List<ProductionOrderRoutingOperation> existingOperationList = productionOrderRoutingOperationMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                        .eq(ProductionOrderRoutingOperation::getOrderRoutingId, orderRouting.getId())
@@ -310,7 +318,7 @@
            if (matchedOperation == null) {
                matchedOperation = insertRoutingOperationSnapshot(orderRouting.getId(), productionOrderId, desiredOperation);
            } else {
                updateRoutingOperationSnapshotIfNecessary(desiredOperation, orderRouting.getId(), productionOrderId, matchedOperation);
                updateRoutingOperationSnapshotIfNecessary(matchedOperation, orderRouting.getId(), productionOrderId, desiredOperation);
            }
            finalOperationList.add(matchedOperation);
        }
@@ -381,14 +389,14 @@
        Map<Long, ProductionBomStructure> structureById = structureList.stream()
                .filter(item -> item != null && item.getId() != null)
                .collect(Collectors.toMap(ProductionBomStructure::getId, item -> item, (left, right) -> left));
        // æž„建父-子映射关系
        Map<Long, List<ProductionBomStructure>> treeMap = buildParentChildMap(structureList);
        // ä½¿ç”¨åŽåºéåŽ†æž„å»ºæ“ä½œåˆ—è¡¨ï¼ˆå…ˆå­åŽçˆ¶ï¼Œç¡®ä¿å·¥è‰ºè·¯çº¿é¡ºåºæ­£ç¡®ï¼‰
        Map<String, ProductionBomStructure> uniqueOperationMap = new LinkedHashMap<>();
        for (ProductionBomStructure bomStructure : structureList) {
            if (bomStructure == null || bomStructure.getTechnologyOperationId() == null) {
                continue;
            }
            Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId);
            uniqueOperationMap.putIfAbsent(buildBomOperationDedupKey(bomStructure, outputProductModelId), bomStructure);
        }
        buildOperationListPostOrder(null, treeMap, uniqueOperationMap, structureById, rootProductModelId);
        List<ProductionOrderRoutingOperation> desiredOperationList = new ArrayList<>();
        int dragSort = 1;
        for (ProductionBomStructure bomStructure : uniqueOperationMap.values()) {
@@ -405,6 +413,52 @@
            desiredOperationList.add(routingOperation);
        }
        return desiredOperationList;
    }
    private Map<Long, List<ProductionBomStructure>> buildParentChildMap(List<ProductionBomStructure> structureList) {
        Map<Long, List<ProductionBomStructure>> treeMap = new LinkedHashMap<>();
        Map<Long, Integer> childCountMap = new HashMap<>();
        // ç¬¬ä¸€éï¼šç»Ÿè®¡æ¯ä¸ªèŠ‚ç‚¹çš„å­èŠ‚ç‚¹æ•°é‡ï¼ŒåŒæ—¶æž„å»ºåˆå§‹æ˜ å°„
        for (ProductionBomStructure structure : structureList) {
            if (structure == null) continue;
            Long parentId = structure.getParentId();
            childCountMap.merge(parentId, 1, Integer::sum);  // ç»Ÿè®¡æ¯ä¸ªçˆ¶èŠ‚ç‚¹æœ‰å¤šå°‘ä¸ªå­èŠ‚ç‚¹
            treeMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(structure);
        }
        // ç¬¬äºŒéï¼šå¯¹æ¯ä¸ªçˆ¶èŠ‚ç‚¹ä¸‹çš„å­èŠ‚ç‚¹æŒ‰å­èŠ‚ç‚¹æ•°é‡å€’åºæŽ’åºï¼ˆæœ‰å­èŠ‚ç‚¹çš„ä¼˜å…ˆï¼‰
        for (Map.Entry<Long, List<ProductionBomStructure>> entry : treeMap.entrySet()) {
            List<ProductionBomStructure> children = entry.getValue();
            children.sort((a, b) -> {
                int countA = childCountMap.getOrDefault(a.getId(), 0);
                int countB = childCountMap.getOrDefault(b.getId(), 0);
                return Integer.compare(countB, countA);  // å­èŠ‚ç‚¹å¤šçš„æŽ’å‰é¢
            });
        }
        return treeMap;
    }
    private void buildOperationListPostOrder(Long parentId,
                                             Map<Long, List<ProductionBomStructure>> treeMap,
                                             Map<String, ProductionBomStructure> uniqueOperationMap,
                                             Map<Long, ProductionBomStructure> structureById,
                                             Long rootProductModelId) {
        List<ProductionBomStructure> children = treeMap.get(parentId);
        if (children == null || children.isEmpty()) {
            return;
        }
        for (ProductionBomStructure child : children) {
            // å…ˆé€’归处理子节点
            buildOperationListPostOrder(child.getId(), treeMap, uniqueOperationMap, structureById, rootProductModelId);
            // å†å¤„理当前节点
            if (child.getTechnologyOperationId() != null) {
                Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(child, structureById), rootProductModelId);
                uniqueOperationMap.putIfAbsent(buildBomOperationDedupKey(child, outputProductModelId), child);
            }
        }
    }
    private Map<String, Deque<ProductionOrderRoutingOperation>> buildExistingRoutingOperationBucketMap(List<ProductionOrderRoutingOperation> existingOperationList) {
@@ -482,6 +536,12 @@
        if (!Objects.equals(currentOperation.getIsProduction(), desiredOperation.getIsProduction())) {
            update.setIsProduction(desiredOperation.getIsProduction());
            currentOperation.setIsProduction(desiredOperation.getIsProduction());
            changed = true;
        }
        // æ›´æ–° dragSort å­—段,确保工艺路线顺序正确
        if (!Objects.equals(currentOperation.getDragSort(), desiredOperation.getDragSort())) {
            update.setDragSort(desiredOperation.getDragSort());
            currentOperation.setDragSort(desiredOperation.getDragSort());
            changed = true;
        }
        if (!Objects.equals(currentOperation.getType(), desiredOperation.getType())) {
@@ -744,8 +804,8 @@
            return;
        }
        for (ProductionBomStructureDto node : source) {
            flattenTree(node.getChildren(), result);  // å…ˆé€’归添加子节点
            result.add(node);
            flattenTree(node.getChildren(), result);
        }
    }
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()));
                // ç¡®å®šæ ¹äº§å“è§„æ ¼ID
                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
@@ -182,4 +283,24 @@
        }
        return 0;
    }
    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);
    }
}
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);
    }
    /**
     * è§£æžå·¥åºè¾“出节点
     */
    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;
    }
    /**
     * è§£æžè¾“出产品规格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;
    }
}
src/main/java/com/ruoyi/project/common/CaptchaController.java
@@ -1,98 +1,100 @@
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.R;
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.HashMap;
import java.util.Map;
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 R<?> getCode(HttpServletResponse response) throws IOException
    {
        Map<String, Object> map = new HashMap<>();
        boolean captchaEnabled = configService.selectCaptchaEnabled();
        map.put("captchaEnabled", captchaEnabled);
        if (!captchaEnabled)
        {
            return R.ok(map);
        }
        // ä¿å­˜éªŒè¯ç ä¿¡æ¯
        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 R.fail(e.getMessage());
        }
        map.put("uuid", uuid);
        map.put("img", Base64.encode(os.toByteArray()));
        return R.ok(map);
    }
}
src/main/java/com/ruoyi/project/monitor/controller/CacheController.java
@@ -1,111 +1,112 @@
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.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
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 extends BaseController
{
    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 R<?> 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 R.ok(result);
    }
    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
    @GetMapping("/getNames")
    public R<?> cache()
    {
        return R.ok(caches);
    }
    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
    @GetMapping("/getKeys/{cacheName}")
    public R<?> getCacheKeys(@PathVariable String cacheName)
    {
        Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
        return R.ok(new TreeSet<>(cacheKeys));
    }
    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
    @GetMapping("/getValue/{cacheName}/{cacheKey}")
    public R<?> getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
    {
        String cacheValue = redisTemplate.opsForValue().get(cacheKey);
        SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
        return R.ok(sysCache);
    }
    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
    @DeleteMapping("/clearCacheName/{cacheName}")
    public R<?> clearCacheName(@PathVariable String cacheName)
    {
        Collection<String> cacheKeys = redisTemplate.keys(cacheName + "*");
        redisTemplate.delete(cacheKeys);
        return R.ok();
    }
    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
    @DeleteMapping("/clearCacheKey/{cacheKey}")
    public R<?> clearCacheKey(@PathVariable String cacheKey)
    {
        redisTemplate.delete(cacheKey);
        return R.ok();
    }
    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
    @DeleteMapping("/clearCacheAll")
    public R<?> clearCacheAll()
    {
        Collection<String> cacheKeys = redisTemplate.keys("*");
        redisTemplate.delete(cacheKeys);
        return R.ok();
    }
}
src/main/java/com/ruoyi/project/monitor/controller/ServerController.java
@@ -1,27 +1,28 @@
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 com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.framework.web.domain.Server;
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;
/**
 * æœåŠ¡å™¨ç›‘æŽ§
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/monitor/server")
public class ServerController extends BaseController
{
    @PreAuthorize("@ss.hasPermi('monitor:server:list')")
    @GetMapping()
    public R<?> getInfo() throws Exception
    {
        Server server = new Server();
        server.copyTo();
        return R.ok(server);
    }
}
src/main/java/com/ruoyi/project/monitor/controller/SysJobController.java
@@ -1,186 +1,188 @@
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() + "'失败,Cron表达式不正确");
        }
        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() + "'失败,Cron表达式不正确");
        }
        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.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.R;
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 R<?> getInfo(@PathVariable("jobId") Long jobId)
    {
        return R.ok(jobService.selectJobById(jobId));
    }
    /**
     * æ–°å¢žå®šæ—¶ä»»åŠ¡
     */
    @PreAuthorize("@ss.hasPermi('monitor:job:add')")
    @Log(title = "定时任务", businessType = BusinessType.INSERT)
    @PostMapping
    public R<?> add(@RequestBody SysJob job) throws SchedulerException, TaskException
    {
        if (!CronUtils.isValid(job.getCronExpression()))
        {
            return R.fail("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确");
        }
        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
        {
            return R.fail("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
        }
        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
        {
            return R.fail("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
        }
        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
        {
            return R.fail("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
        }
        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
        {
            return R.fail("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
        }
        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
        {
            return R.fail("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
        }
        job.setCreateBy(getUsername());
        jobService.insertJob(job);
        return R.ok();
    }
    /**
     * ä¿®æ”¹å®šæ—¶ä»»åŠ¡
     */
    @PreAuthorize("@ss.hasPermi('monitor:job:edit')")
    @Log(title = "定时任务", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<?> edit(@RequestBody SysJob job) throws SchedulerException, TaskException
    {
        if (!CronUtils.isValid(job.getCronExpression()))
        {
            return R.fail("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确");
        }
        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
        {
            return R.fail("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
        }
        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
        {
            return R.fail("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
        }
        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
        {
            return R.fail("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
        }
        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
        {
            return R.fail("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
        }
        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
        {
            return R.fail("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
        }
        job.setUpdateBy(getUsername());
        jobService.updateJob(job);
        return R.ok();
    }
    /**
     * å®šæ—¶ä»»åŠ¡çŠ¶æ€ä¿®æ”¹
     */
    @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')")
    @Log(title = "定时任务", businessType = BusinessType.UPDATE)
    @PutMapping("/changeStatus")
    public R<?> changeStatus(@RequestBody SysJob job) throws SchedulerException
    {
        SysJob newJob = jobService.selectJobById(job.getJobId());
        newJob.setStatus(job.getStatus());
        jobService.changeStatus(newJob);
        return R.ok();
    }
    /**
     * å®šæ—¶ä»»åŠ¡ç«‹å³æ‰§è¡Œä¸€æ¬¡
     */
    @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')")
    @Log(title = "定时任务", businessType = BusinessType.UPDATE)
    @PutMapping("/run")
    public R<?> run(@RequestBody SysJob job) throws SchedulerException
    {
        boolean result = jobService.run(job);
        return result ? R.ok() : R.fail("任务不存在或已过期!");
    }
    /**
     * åˆ é™¤å®šæ—¶ä»»åŠ¡
     */
    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
    @Log(title = "定时任务", businessType = BusinessType.DELETE)
    @DeleteMapping("/{jobIds}")
    public R<?> remove(@PathVariable Long[] jobIds) throws SchedulerException
    {
        jobService.deleteJobByIds(jobIds);
        return R.ok();
    }
}
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.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.R;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.monitor.domain.SysJobLog;
import com.ruoyi.project.monitor.service.ISysJobLogService;
import org.springframework.security.access.prepost.PreAuthorize;
/**
 * è°ƒåº¦æ—¥å¿—操作处理
 *
 * @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 R<?> getInfo(@PathVariable Long jobLogId)
    {
        return R.ok(jobLogService.selectJobLogById(jobLogId));
    }
    /**
     * åˆ é™¤å®šæ—¶ä»»åŠ¡è°ƒåº¦æ—¥å¿—
     */
    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
    @Log(title = "定时任务调度日志", businessType = BusinessType.DELETE)
    @DeleteMapping("/{jobLogIds}")
    public R<?> remove(@PathVariable Long[] jobLogIds)
    {
        jobLogService.deleteJobLogByIds(jobLogIds);
        return R.ok();
    }
    /**
     * æ¸…空定时任务调度日志
     */
    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
    @Log(title = "调度日志", businessType = BusinessType.CLEAN)
    @DeleteMapping("/clean")
    public R<?> clean()
    {
        jobLogService.cleanJobLog();
        return R.ok();
    }
}
src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java
@@ -1,70 +1,71 @@
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 = "账户解锁", 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.framework.web.domain.R;
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.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 R<?> remove(@PathVariable Long[] infoIds) {
        logininforService.deleteLogininforByIds(infoIds);
        return R.ok();
    }
    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
    @Log(title = "登录日志", businessType = BusinessType.CLEAN)
    @DeleteMapping("/clean")
    public R<?> clean() {
        logininforService.cleanLogininfor();
        return R.ok();
    }
    @PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
    @Log(title = "账户解锁", businessType = BusinessType.OTHER)
    @GetMapping("/unlock/{userName}")
    public R<?> unlock(@PathVariable("userName") String userName) {
        passwordService.clearLoginRecordCache(userName);
        return R.ok();
    }
}
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.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.R;
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 R<?> remove(@PathVariable Long[] operIds)
    {
        operLogService.deleteOperLogByIds(operIds);
        return R.ok();
    }
    @Log(title = "操作日志", businessType = BusinessType.CLEAN)
    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
    @DeleteMapping("/clean")
    public R<?> clean()
    {
        operLogService.cleanOperLog();
        return R.ok();
    }
}
src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java
@@ -1,83 +1,82 @@
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 com.ruoyi.framework.web.domain.R;
import lombok.AllArgsConstructor;
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.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 R<?> forceLogout(@PathVariable String tokenId)
    {
        redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
        return R.ok();
    }
}
src/main/java/com/ruoyi/project/system/controller/SysConfigController.java
@@ -1,127 +1,129 @@
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 java.util.List;
import com.ruoyi.framework.web.domain.R;
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.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.*;
/**
 * å‚数配置 ä¿¡æ¯æ“ä½œå¤„理
 *
 * @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 R<?> getInfo(@PathVariable Long configId)
    {
        return R.ok(configService.selectConfigById(configId));
    }
    /**
     * æ ¹æ®å‚数键名查询参数值
     */
    @GetMapping(value = "/configKey/{configKey}")
    public R<?> getConfigKey(@PathVariable String configKey)
    {
        return R.ok(configService.selectConfigByKey(configKey));
    }
    /**
     * æ–°å¢žå‚数配置
     */
    @PreAuthorize("@ss.hasPermi('system:config:add')")
    @Log(title = "参数管理", businessType = BusinessType.INSERT)
    @PostMapping
    public R<?> add(@Validated @RequestBody SysConfig config)
    {
        if (!configService.checkConfigKeyUnique(config))
        {
            return R.fail("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
        }
        config.setCreateBy(getUsername());
        configService.insertConfig(config);
        return R.ok();
    }
    /**
     * ä¿®æ”¹å‚数配置
     */
    @PreAuthorize("@ss.hasPermi('system:config:edit')")
    @Log(title = "参数管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<?> edit(@Validated @RequestBody SysConfig config)
    {
        if (!configService.checkConfigKeyUnique(config))
        {
            return R.fail("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
        }
        config.setUpdateBy(getUsername());
        configService.updateConfig(config);
        return R.ok();
    }
    /**
     * åˆ é™¤å‚数配置
     */
    @PreAuthorize("@ss.hasPermi('system:config:remove')")
    @Log(title = "参数管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{configIds}")
    public R<?> remove(@PathVariable Long[] configIds)
    {
        configService.deleteConfigByIds(configIds);
        return R.ok();
    }
    /**
     * åˆ·æ–°å‚数缓存
     */
    @PreAuthorize("@ss.hasPermi('system:config:remove')")
    @Log(title = "参数管理", businessType = BusinessType.CLEAN)
    @DeleteMapping("/refreshCache")
    public R<?> refreshCache()
    {
        configService.resetConfigCache();
        return R.ok();
    }
}
src/main/java/com/ruoyi/project/system/controller/SysDeptController.java
@@ -1,134 +1,137 @@
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 com.ruoyi.common.constant.HttpStatus;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.ArrayUtils;
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.R;
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 R<?> list(SysDept dept)
    {
        List<SysDept> depts = deptService.selectDeptList(dept);
        return R.ok(depts);
    }
    /**
     * æŸ¥è¯¢éƒ¨é—¨åˆ—表(排除节点)
     */
    @PreAuthorize("@ss.hasPermi('system:dept:list')")
    @GetMapping("/list/exclude/{deptId}")
    public R<?> 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 R.ok(depts);
    }
    /**
     * æ ¹æ®éƒ¨é—¨ç¼–号获取详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:dept:query')")
    @GetMapping(value = "/{deptId}")
    public R<?> getInfo(@PathVariable Long deptId)
    {
        deptService.checkDeptDataScope(deptId);
        return R.ok(deptService.selectDeptById(deptId));
    }
    /**
     * æ–°å¢žéƒ¨é—¨
     */
    @PreAuthorize("@ss.hasPermi('system:dept:add')")
    @Log(title = "部门管理", businessType = BusinessType.INSERT)
    @PostMapping
    public R<?> add(@Validated @RequestBody SysDept dept)
    {
        if (!deptService.checkDeptNameUnique(dept))
        {
            return R.fail("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
        }
        dept.setCreateBy(getUsername());
        deptService.insertDept(dept);
        return R.ok();
    }
    /**
     * ä¿®æ”¹éƒ¨é—¨
     */
    @PreAuthorize("@ss.hasPermi('system:dept:edit')")
    @Log(title = "部门管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<?> edit(@Validated @RequestBody SysDept dept)
    {
        Long deptId = dept.getDeptId();
        deptService.checkDeptDataScope(deptId);
        if (!deptService.checkDeptNameUnique(dept))
        {
            return R.fail("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
        }
        else if (dept.getParentId().equals(deptId))
        {
            return R.fail("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
        }
        else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
        {
            return R.fail("该部门包含未停用的子部门!");
        }
        dept.setUpdateBy(getUsername());
        deptService.updateDept(dept);
        return R.ok();
    }
    /**
     * åˆ é™¤éƒ¨é—¨
     */
    @PreAuthorize("@ss.hasPermi('system:dept:remove')")
    @Log(title = "部门管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{deptId}")
    public R<?> remove(@PathVariable Long deptId)
    {
        if (deptService.hasChildByDeptId(deptId))
        {
            return R.fail(HttpStatus.WARN, "存在下级部门,不允许删除");
        }
        if (deptService.checkDeptExistUser(deptId))
        {
            return R.fail(HttpStatus.WARN, "部门存在用户,不允许删除");
        }
        deptService.checkDeptDataScope(deptId);
        deptService.deleteDeptById(deptId);
        return R.ok();
    }
}
src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java
@@ -1,120 +1,121 @@
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.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.R;
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 R<?> getInfo(@PathVariable Long dictCode)
    {
        return R.ok(dictDataService.selectDictDataById(dictCode));
    }
    /**
     * æ ¹æ®å­—典类型查询字典数据信息
     */
    @GetMapping(value = "/type/{dictType}")
    public R<?> dictType(@PathVariable String dictType)
    {
        List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
        if (StringUtils.isNull(data))
        {
            data = new ArrayList<SysDictData>();
        }
        return R.ok(data);
    }
    /**
     * æ–°å¢žå­—典类型
     */
    @PreAuthorize("@ss.hasPermi('system:dict:add')")
    @Log(title = "字典数据", businessType = BusinessType.INSERT)
    @PostMapping
    public R<?> add(@Validated @RequestBody SysDictData dict)
    {
        dict.setCreateBy(getUsername());
        dictDataService.insertDictData(dict);
        return R.ok();
    }
    /**
     * ä¿®æ”¹ä¿å­˜å­—典类型
     */
    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
    @Log(title = "字典数据", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<?> edit(@Validated @RequestBody SysDictData dict)
    {
        dict.setUpdateBy(getUsername());
        dictDataService.updateDictData(dict);
        return R.ok();
    }
    /**
     * åˆ é™¤å­—典类型
     */
    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
    @Log(title = "字典类型", businessType = BusinessType.DELETE)
    @DeleteMapping("/{dictCodes}")
    public R<?> remove(@PathVariable Long[] dictCodes)
    {
        dictDataService.deleteDictDataByIds(dictCodes);
        return R.ok();
    }
}
src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java
@@ -1,132 +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.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.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.R;
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 R<?> getInfo(@PathVariable Long dictId)
    {
        return R.ok(dictTypeService.selectDictTypeById(dictId));
    }
    /**
     * æ–°å¢žå­—典类型
     */
    @PreAuthorize("@ss.hasPermi('system:dict:add')")
    @Log(title = "字典类型", businessType = BusinessType.INSERT)
    @PostMapping
    public R<?> add(@Validated @RequestBody SysDictType dict)
    {
        if (!dictTypeService.checkDictTypeUnique(dict))
        {
            return R.fail("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
        }
        dict.setCreateBy(getUsername());
        dictTypeService.insertDictType(dict);
        return R.ok();
    }
    /**
     * ä¿®æ”¹å­—典类型
     */
    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
    @Log(title = "字典类型", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<?> edit(@Validated @RequestBody SysDictType dict)
    {
        if (!dictTypeService.checkDictTypeUnique(dict))
        {
            return R.fail("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
        }
        dict.setUpdateBy(getUsername());
        dictTypeService.updateDictType(dict);
        return R.ok();
    }
    /**
     * åˆ é™¤å­—典类型
     */
    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
    @Log(title = "字典类型", businessType = BusinessType.DELETE)
    @DeleteMapping("/{dictIds}")
    public R<?> remove(@PathVariable Long[] dictIds)
    {
        dictTypeService.deleteDictTypeByIds(dictIds);
        return R.ok();
    }
    /**
     * åˆ·æ–°å­—典缓存
     */
    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
    @Log(title = "字典类型", businessType = BusinessType.CLEAN)
    @DeleteMapping("/refreshCache")
    public R<?> refreshCache()
    {
        dictTypeService.resetDictCache();
        return R.ok();
    }
    /**
     * èŽ·å–å­—å…¸é€‰æ‹©æ¡†åˆ—è¡¨
     */
    @GetMapping("/optionselect")
    public R<?> optionselect()
    {
        List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
        return R.ok(dictTypes);
    }
}
src/main/java/com/ruoyi/project/system/controller/SysLoginController.java
@@ -1,155 +1,156 @@
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.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
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.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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
 * ç™»å½•验证
 *
 * @author ruoyi
 */
@RestController
@AllArgsConstructor
public class SysLoginController extends BaseController
{
    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 R<?> login(@RequestBody LoginBody loginBody)
    {
        // ç”Ÿæˆä»¤ç‰Œ
        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
                loginBody.getUuid());
        Map<String, Object> map = new HashMap<>();
        map.put(Constants.TOKEN, token);
        return R.ok(map);
    }
    /**
     * èŽ·å–ç”¨æˆ·ä¿¡æ¯
     *
     * @return ç”¨æˆ·ä¿¡æ¯
     */
    @GetMapping("/getInfo")
    public R<?> 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);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("user", user);
        map.put("aiEnabled", loginUser.getAiEnabled());
        map.put("roles", roles);
        map.put("permissions", permissions);
        return R.ok(map);
    }
    /**
     * èŽ·å–è·¯ç”±ä¿¡æ¯
     *
     * @return è·¯ç”±ä¿¡æ¯
     */
    @GetMapping("getRouters")
    public R<?> getRouters()
    {
        Long userId = SecurityUtils.getUserId();
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        return R.ok(menuService.buildMenus(menus));
    }
    @PostMapping("/loginCheck")
    public R<?> loginCheck(@RequestBody LoginBody loginBody)
    {
        try {
            Long userId = loginService.loginCheck(loginBody.getUsername(), loginBody.getPassword());
            return R.ok(userId);
        }catch (Exception e) {
            return R.fail(e.getMessage());
        }
    }
    @GetMapping("/userLoginFacotryList")
    public R<?> 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 R.ok(uniqueList);
    }
    /**
     * é€‰æ‹©å…¬å¸ç™»å½•
     *
     * @param loginBody ç™»å½•信息
     * @return ç»“æžœ
     */
    @PostMapping("/loginCheckFactory")
    public R<?> loginCheckFactory(@RequestBody LoginBody loginBody)
    {
        // ç”Ÿæˆä»¤ç‰Œ
        String token = loginService.loginCheckFactory(loginBody.getUsername(), loginBody.getPassword(),loginBody.getFactoryId());
        Map<String, Object> map = new HashMap<>();
        map.put(Constants.TOKEN, token);
        return R.ok(map);
    }
}
src/main/java/com/ruoyi/project/system/controller/SysMenuController.java
@@ -1,136 +1,142 @@
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() + "'失败,地址必须以http(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() + "'失败,地址必须以http(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.HttpStatus;
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.R;
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.HashMap;
import java.util.List;
import java.util.Map;
/**
 * èœå•信息
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/system/menu")
@AllArgsConstructor
public class SysMenuController extends BaseController
{
    private ISysMenuService menuService;
    /**
     * èŽ·å–èœå•åˆ—è¡¨
     */
    @PreAuthorize("@ss.hasPermi('system:menu:list')")
    @GetMapping("/list")
    public R<?> list(SysMenu menu)
    {
        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
        return R.ok(menus);
    }
    /**
     * æ ¹æ®èœå•编号获取详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:menu:query')")
    @GetMapping(value = "/{menuId}")
    public R<?> getInfo(@PathVariable Long menuId)
    {
        return R.ok(menuService.selectMenuById(menuId));
    }
    /**
     * èŽ·å–èœå•ä¸‹æ‹‰æ ‘åˆ—è¡¨
     */
    @GetMapping("/treeselect")
    public R<?> treeselect(SysMenu menu)
    {
        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
        return R.ok(menuService.buildMenuTreeSelect(menus));
    }
    /**
     * åŠ è½½å¯¹åº”è§’è‰²èœå•åˆ—è¡¨æ ‘
     */
    @GetMapping(value = "/roleMenuTreeselect/{roleId}")
    public R<?> roleMenuTreeselect(@PathVariable("roleId") Long roleId)
    {
        List<SysMenu> menus = menuService.selectMenuList(getUserId());
        Map<String, Object> map = new HashMap<>();
        map.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
        map.put("menus", menuService.buildMenuTreeSelect(menus));
        return R.ok(map);
    }
    /**
     * æ–°å¢žèœå•
     */
    @PreAuthorize("@ss.hasPermi('system:menu:add')")
    @Log(title = "菜单管理", businessType = BusinessType.INSERT)
    @PostMapping
    public R<?> add(@Validated @RequestBody SysMenu menu)
    {
        if (!menuService.checkMenuNameUnique(menu))
        {
            return R.fail("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
        }
        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
        {
            return R.fail("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
        }
        menu.setCreateBy(getUsername());
        menuService.insertMenu(menu);
        return R.ok();
    }
    /**
     * ä¿®æ”¹èœå•
     */
    @PreAuthorize("@ss.hasPermi('system:menu:edit')")
    @Log(title = "菜单管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<?> edit(@Validated @RequestBody SysMenu menu)
    {
        if (!menuService.checkMenuNameUnique(menu))
        {
            return R.fail("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
        }
        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
        {
            return R.fail("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
        }
        else if (menu.getMenuId().equals(menu.getParentId()))
        {
            return R.fail("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
        }
        menu.setUpdateBy(getUsername());
        menuService.updateMenu(menu);
        return R.ok();
    }
    /**
     * åˆ é™¤èœå•
     */
    @PreAuthorize("@ss.hasPermi('system:menu:remove')")
    @Log(title = "菜单管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{menuId}")
    public R<?> remove(@PathVariable("menuId") Long menuId)
    {
        if (menuService.hasChildByMenuId(menuId))
        {
            return R.fail(HttpStatus.WARN, "存在子菜单,不允许删除");
        }
        if (menuService.checkMenuExistRole(menuId))
        {
            return R.fail(HttpStatus.WARN, "菜单已分配,不允许删除");
        }
        menuService.deleteMenuById(menuId);
        return R.ok();
    }
}
src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java
@@ -1,96 +1,99 @@
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 = "移动端根据消息ID进行已读")
    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.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 R<?> getInfo(@PathVariable Long noticeId) {
        return R.ok(noticeService.selectNoticeById(noticeId));
    }
    /**
     * æ–°å¢žé€šçŸ¥å…¬å‘Š
     */
    @PostMapping
    public R<?> add(@Validated @RequestBody SysNotice notice) {
        noticeService.insertNotice(notice);
        return R.ok();
    }
    /**
     * ä¿®æ”¹é€šçŸ¥å…¬å‘Š
     */
    @PutMapping
    public R<?> edit(@Validated @RequestBody SysNotice notice) {
        noticeService.updateNotice(notice);
        return R.ok();
    }
    /**
     * åˆ é™¤é€šçŸ¥å…¬å‘Š
     */
    @DeleteMapping("/{noticeIds}")
    public R<?> remove(@PathVariable Long[] noticeIds) {
        noticeService.deleteNoticeByIds(noticeIds);
        return R.ok();
    }
    /**
     * ä¸€é”®å·²è¯»
     */
    @PostMapping("/readAll")
    public R<?> readAll() {
        noticeService.readAll();
        return R.ok();
    }
    @PostMapping("appReadNotice")
    @Operation(summary = "移动端根据消息ID进行已读")
    public R<?> appReadNotice(@RequestParam("noticeId") Long noticeId) {
        noticeService.appReadNotice(noticeId);
        return R.ok();
    }
}
src/main/java/com/ruoyi/project/system/controller/SysPostController.java
@@ -1,133 +1,135 @@
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.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.R;
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 R<?> getInfo(@PathVariable Long postId)
    {
        return R.ok(postService.selectPostById(postId));
    }
    /**
     * æ–°å¢žå²—位
     */
    @PreAuthorize("@ss.hasPermi('system:post:add')")
    @Log(title = "岗位管理", businessType = BusinessType.INSERT)
    @PostMapping
    public R<?> add(@Validated @RequestBody SysPost post)
    {
        if (!postService.checkPostNameUnique(post))
        {
            return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
        }
        else if (!postService.checkPostCodeUnique(post))
        {
            return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
        }
        post.setCreateBy(getUsername());
        postService.insertPost(post);
        return R.ok();
    }
    /**
     * ä¿®æ”¹å²—位
     */
    @PreAuthorize("@ss.hasPermi('system:post:edit')")
    @Log(title = "岗位管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<?> edit(@Validated @RequestBody SysPost post)
    {
        if (!postService.checkPostNameUnique(post))
        {
            return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
        }
        else if (!postService.checkPostCodeUnique(post))
        {
            return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
        }
        post.setUpdateBy(getUsername());
        postService.updatePost(post);
        return R.ok();
    }
    /**
     * åˆ é™¤å²—位
     */
    @PreAuthorize("@ss.hasPermi('system:post:remove')")
    @Log(title = "岗位管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{postIds}")
    public R<?> remove(@PathVariable Long[] postIds)
    {
        postService.deletePostByIds(postIds);
        return R.ok();
    }
    /**
     * èŽ·å–å²—ä½é€‰æ‹©æ¡†åˆ—è¡¨
     */
    @GetMapping("/optionselect")
    public R<?> optionselect()
    {
        List<SysPost> posts = postService.selectPostAll();
        return R.ok(posts);
    }
}
src/main/java/com/ruoyi/project/system/controller/SysProfileController.java
@@ -1,133 +1,135 @@
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 java.util.HashMap;
import java.util.Map;
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.R;
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;
/**
 * ä¸ªäººä¿¡æ¯ ä¸šåŠ¡å¤„ç†
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/system/user/profile")
@AllArgsConstructor
public class SysProfileController extends BaseController
{
    private ISysUserService userService;
    private TokenService tokenService;
    /**
     * ä¸ªäººä¿¡æ¯
     */
    @GetMapping
    public R<?> profile()
    {
        LoginUser loginUser = getLoginUser();
        SysUser user = loginUser.getUser();
        Map<String, Object> map = new HashMap<>();
        map.put("data", user);
        map.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
        map.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
        return R.ok(map);
    }
    /**
     * ä¿®æ”¹ç”¨æˆ·
     */
    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<?> 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 R.fail("修改用户'" + loginUser.getUsername() + "'失败,手机号码已存在");
        }
        if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
        {
            return R.fail("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在");
        }
        if (userService.updateUserProfile(currentUser) > 0)
        {
            // æ›´æ–°ç¼“存用户信息
            tokenService.setLoginUser(loginUser);
            return R.ok();
        }
        return R.fail("修改个人信息异常,请联系管理员");
    }
    /**
     * é‡ç½®å¯†ç 
     */
    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
    @PutMapping("/updatePwd")
    public R<?> 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 R.fail("修改密码失败,旧密码错误");
        }
        if (SecurityUtils.matchesPassword(newPassword, password))
        {
            return R.fail("新密码不能与旧密码相同");
        }
        newPassword = SecurityUtils.encryptPassword(newPassword);
        if (userService.resetUserPwd(userName, newPassword) > 0)
        {
            // æ›´æ–°ç¼“存用户密码
            loginUser.getUser().setPassword(newPassword);
            tokenService.setLoginUser(loginUser);
            return R.ok();
        }
        return R.fail("修改密码异常,请联系管理员");
    }
    /**
     * å¤´åƒä¸Šä¼ 
     */
    @Log(title = "用户头像", businessType = BusinessType.UPDATE)
    @PostMapping("/avatar")
    public R<?> 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))
            {
                // æ›´æ–°ç¼“存用户头像
                loginUser.getUser().setAvatar(avatar);
                tokenService.setLoginUser(loginUser);
                Map<String, Object> map = new HashMap<>();
                map.put("imgUrl", avatar);
                return R.ok(map);
            }
        }
        return R.fail("上传图片异常,请联系管理员");
    }
}
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.R;
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 R<?> register(@RequestBody RegisterBody user) {
        if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
            return R.fail("当前系统没有开启注册功能!");
        }
        String msg = registerService.register(user);
        return StringUtils.isEmpty(msg) ? R.ok() : R.fail(msg);
    }
}
src/main/java/com/ruoyi/project/system/controller/SysRoleController.java
@@ -1,255 +1,265 @@
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.HashMap;
import java.util.List;
import java.util.Map;
import jakarta.servlet.http.HttpServletResponse;
import com.ruoyi.framework.web.domain.R;
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.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.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;
/**
 * è§’色信息
 *
 * @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 R<?> getInfo(@PathVariable Long roleId)
    {
        roleService.checkRoleDataScope(roleId);
        return R.ok(roleService.selectRoleById(roleId));
    }
    /**
     * æ–°å¢žè§’色
     */
    @PreAuthorize("@ss.hasPermi('system:role:add')")
    @Log(title = "角色管理", businessType = BusinessType.INSERT)
    @PostMapping
    public R<?> add(@Validated @RequestBody SysRole role)
    {
        if (!roleService.checkRoleNameUnique(role))
        {
            return R.fail("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
        }
        else if (!roleService.checkRoleKeyUnique(role))
        {
            return R.fail("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
        }
        role.setCreateBy(getUsername());
        roleService.insertRole(role);
        return R.ok();
    }
    /**
     * ä¿®æ”¹ä¿å­˜è§’色
     */
    @PreAuthorize("@ss.hasPermi('system:role:edit')")
    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<?> edit(@Validated @RequestBody SysRole role)
    {
        roleService.checkRoleAllowed(role);
        roleService.checkRoleDataScope(role.getRoleId());
        if (!roleService.checkRoleNameUnique(role))
        {
            return R.fail("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
        }
        else if (!roleService.checkRoleKeyUnique(role))
        {
            return R.fail("修改角色'" + 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 R.ok();
        }
        return R.fail("修改角色'" + role.getRoleName() + "'失败,请联系管理员");
    }
    /**
     * ä¿®æ”¹ä¿å­˜æ•°æ®æƒé™
     */
    @PreAuthorize("@ss.hasPermi('system:role:edit')")
    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
    @PutMapping("/dataScope")
    public R<?> dataScope(@RequestBody SysRole role)
    {
        roleService.checkRoleAllowed(role);
        roleService.checkRoleDataScope(role.getRoleId());
        roleService.authDataScope(role);
        return R.ok();
    }
    /**
     * çŠ¶æ€ä¿®æ”¹
     */
    @PreAuthorize("@ss.hasPermi('system:role:edit')")
    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
    @PutMapping("/changeStatus")
    public R<?> changeStatus(@RequestBody SysRole role)
    {
        roleService.checkRoleAllowed(role);
        roleService.checkRoleDataScope(role.getRoleId());
        role.setUpdateBy(getUsername());
        roleService.updateRoleStatus(role);
        return R.ok();
    }
    /**
     * åˆ é™¤è§’色
     */
    @PreAuthorize("@ss.hasPermi('system:role:remove')")
    @Log(title = "角色管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{roleIds}")
    public R<?> remove(@PathVariable Long[] roleIds)
    {
        roleService.deleteRoleByIds(roleIds);
        return R.ok();
    }
    /**
     * èŽ·å–è§’è‰²é€‰æ‹©æ¡†åˆ—è¡¨
     */
    @PreAuthorize("@ss.hasPermi('system:role:query')")
    @GetMapping("/optionselect")
    public R<?> optionselect()
    {
        return R.ok(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 R<?> cancelAuthUser(@RequestBody SysUserRole userRole)
    {
        roleService.deleteAuthUser(userRole);
        return R.ok();
    }
    /**
     * æ‰¹é‡å–消授权用户
     */
    @PreAuthorize("@ss.hasPermi('system:role:edit')")
    @Log(title = "角色管理", businessType = BusinessType.GRANT)
    @PutMapping("/authUser/cancelAll")
    public R<?> cancelAuthUserAll(Long roleId, Long[] userIds)
    {
        roleService.deleteAuthUsers(roleId, userIds);
        return R.ok();
    }
    /**
     * æ‰¹é‡é€‰æ‹©ç”¨æˆ·æŽˆæƒ
     */
    @PreAuthorize("@ss.hasPermi('system:role:edit')")
    @Log(title = "角色管理", businessType = BusinessType.GRANT)
    @PutMapping("/authUser/selectAll")
    public R<?> selectAuthUserAll(Long roleId, Long[] userIds)
    {
        roleService.checkRoleDataScope(roleId);
        roleService.insertAuthUsers(roleId, userIds);
        return R.ok();
    }
    /**
     * èŽ·å–å¯¹åº”è§’è‰²éƒ¨é—¨æ ‘åˆ—è¡¨
     */
    @PreAuthorize("@ss.hasPermi('system:role:query')")
    @GetMapping(value = "/deptTree/{roleId}")
    public R<?> deptTree(@PathVariable("roleId") Long roleId)
    {
        Map<String, Object> map = new HashMap<>();
        map.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
        map.put("depts", deptService.selectDeptTreeList(new SysDept()));
        return R.ok(map);
    }
}
src/main/java/com/ruoyi/project/system/controller/SysUserClientController.java
@@ -2,15 +2,13 @@
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.project.system.domain.GetuiConfig;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.project.system.domain.SysUserClient;
import com.ruoyi.project.system.service.SysUserClientService;
import com.ruoyi.common.utils.SecurityUtils;
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.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -36,10 +34,10 @@
     */
    @PostMapping("/addOrUpdateClientId")
    @Operation(summary = "添加/更新用户cid")
    public AjaxResult addOrUpdateClientId(@RequestBody SysUserClient sysUserClient) {
    public R<?> addOrUpdateClientId(@RequestBody SysUserClient sysUserClient) {
        Long userId = SecurityUtils.getUserId();
        sysUserClient.setUserId(userId);
        boolean result = sysUserClientService.addOrUpdateClientId(sysUserClient);
        return result ? success() : error("设备绑定失败");
        return result ? R.ok() : R.fail("设备绑定失败");
    }
}
src/main/java/com/ruoyi/project/system/controller/SysUserController.java
@@ -1,292 +1,285 @@
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 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.R;
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.vo.SysUserDeptVo;
import com.ruoyi.project.system.service.*;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * ç”¨æˆ·ä¿¡æ¯
 *
 * @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 R<?> listAll(SysUser user)
    {
        List<SysUser> list = userService.selectUserList(user);
        return R.ok(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 R<?> 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 R.ok(null, 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 R<?> getInfo(@PathVariable(value = "userId", required = false) Long userId)
    {
        Map<String, Object> map = new HashMap<>();
        if (StringUtils.isNotNull(userId))
        {
            userService.checkUserDataScope(userId);
            SysUser sysUser = userService.selectUserById(userId);
            map.put("data", sysUser);
            map.put("postIds", postService.selectPostListByUserId(userId));
            map.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
        }
        List<SysRole> roles = roleService.selectRoleAll();
        map.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
        map.put("posts", postService.selectPostAll());
        SysUserDeptVo sysUserDeptVo = new SysUserDeptVo();
        sysUserDeptVo.setUserId(userId);
        List<SysUserDeptVo> sysUserDeptVos = userDeptService.userLoginFacotryList(sysUserDeptVo);
        map.put("deptIds",sysUserDeptVos.stream().map(SysUserDeptVo::getDeptId).collect(Collectors.toList()));
        return R.ok(map);
    }
    /**
     * æ–°å¢žç”¨æˆ·
     */
    @PreAuthorize("@ss.hasPermi('system:user:add')")
    @Log(title = "用户管理", businessType = BusinessType.INSERT)
    @PostMapping
    public R<?> add(@Validated @RequestBody SysUser user)
    {
        roleService.checkRoleDataScope(user.getRoleIds());
        if (!userService.checkUserNameUnique(user))
        {
            return R.fail("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
        }
        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
        {
            return R.fail("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
        }
        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
        {
            return R.fail("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
        }
        user.setCreateBy(getUsername());
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        user.setTenantId(user.getDeptId());
        return R.ok(userService.insertUser(user));
    }
    /**
     * ä¿®æ”¹ç”¨æˆ·
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<?> edit(@Validated @RequestBody SysUser user)
    {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        roleService.checkRoleDataScope(user.getRoleIds());
        if (!userService.checkUserNameUnique(user))
        {
            return R.fail("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
        }
        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
        {
            return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
        }
        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
        {
            return R.fail("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
        }
        user.setUpdateBy(getUsername());
        userService.bindUserDept(user);
        return R.ok(userService.updateUser(user));
    }
    /**
     * åˆ é™¤ç”¨æˆ·
     */
    @PreAuthorize("@ss.hasPermi('system:user:remove')")
    @Log(title = "用户管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{userIds}")
    public R<?> remove(@PathVariable Long[] userIds)
    {
        if (ArrayUtils.contains(userIds, getUserId()))
        {
            return R.fail("当前用户不能删除");
        }
        return R.ok(userService.deleteUserByIds(userIds)) ;
    }
    /**
     * é‡ç½®å¯†ç 
     */
    @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/resetPwd")
    public R<?> resetPwd(@RequestBody SysUser user)
    {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        user.setUpdateBy(getUsername());
        return R.ok(userService.resetPwd(user));
    }
    /**
     * çŠ¶æ€ä¿®æ”¹
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/changeStatus")
    public R<?> changeStatus(@RequestBody SysUser user)
    {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        user.setUpdateBy(getUsername());
        return R.ok(userService.updateUserStatus(user)) ;
    }
    /**
     * æ ¹æ®ç”¨æˆ·ç¼–号获取授权角色
     */
    @PreAuthorize("@ss.hasPermi('system:user:query')")
    @GetMapping("/authRole/{userId}")
    public R<?> authRole(@PathVariable("userId") Long userId)
    {
        SysUser user = userService.selectUserById(userId);
        List<SysRole> roles = roleService.selectRolesByUserId(userId);
        Map<String, Object> map = new HashMap<>();
        map.put("user", user);
        map.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
        return R.ok(map);
    }
    /**
     * ç”¨æˆ·æŽˆæƒè§’色
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.GRANT)
    @PutMapping("/authRole")
    public R<?> insertAuthRole(Long userId, Long[] roleIds)
    {
        userService.checkUserDataScope(userId);
        roleService.checkRoleDataScope(roleIds);
        userService.insertUserAuth(userId, roleIds);
        return R.ok();
    }
    /**
     * èŽ·å–éƒ¨é—¨æ ‘åˆ—è¡¨
     */
    @PreAuthorize("@ss.hasPermi('system:user:list')")
    @GetMapping("/deptTree")
    public R<?> deptTree(SysDept dept)
    {
        return R.ok(deptService.selectDeptTreeList(dept));
    }
    /**
     * ä¸åˆ†é¡µç”¨æˆ·æŸ¥è¯¢
     * @param user
     * @return
     */
    @GetMapping("/userListNoPage")
    public R<?> userListNoPage(SysUser user){
        List<SysUser> sysUserList = userService.userListNoPage(user);
        return R.ok(sysUserList);
    }
    /**
     * æŸ¥è¯¢å½“前用户公司下所有用户
     * @param user
     * @return
     */
    @GetMapping("/userListNoPageByTenantId")
    public R<?> userListNoPageByTenantId(SysUser user){
        //获取登录用户信息
        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
        user.setTenantId(loginUser.getTenantId());
        List<SysUser> sysUserList = userService.userListNoPage(user);
        return R.ok(sysUserList);
    }
}
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;
/**
 * ä»£ç ç”Ÿæˆ æ“ä½œå¤„理
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/tool/gen")
@AllArgsConstructor
public class GenController extends BaseController
{
    private IGenTableService genTableService;
    private IGenTableColumnService genTableColumnService;
    /**
     * æŸ¥è¯¢ä»£ç ç”Ÿæˆåˆ—表
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
    @GetMapping("/list")
    public TableDataInfo genList(GenTable genTable)
    {
        startPage();
        List<GenTable> list = genTableService.selectGenTableList(genTable);
        return getDataTable(list);
    }
    /**
     * èŽ·å–ä»£ç ç”Ÿæˆä¿¡æ¯
     */
    @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 = "代码生成", 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("创建表结构异常");
        }
    }
    /**
     * ä¿®æ”¹ä¿å­˜ä»£ç ç”Ÿæˆä¸šåŠ¡
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
    @Log(title = "代码生成", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult editSave(@Validated @RequestBody GenTable genTable)
    {
        genTableService.validateEdit(genTable);
        genTableService.updateGenTable(genTable);
        return success();
    }
    /**
     * åˆ é™¤ä»£ç ç”Ÿæˆ
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:remove')")
    @Log(title = "代码生成", businessType = BusinessType.DELETE)
    @DeleteMapping("/{tableIds}")
    public AjaxResult remove(@PathVariable Long[] tableIds)
    {
        genTableService.deleteGenTableByIds(tableIds);
        return success();
    }
    /**
     * é¢„览代码
     */
    @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);
    }
    /**
     * ç”Ÿæˆä»£ç ï¼ˆä¸‹è½½æ–¹å¼ï¼‰
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
    @Log(title = "代码生成", 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);
    }
    /**
     * ç”Ÿæˆä»£ç ï¼ˆè‡ªå®šä¹‰è·¯å¾„)
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
    @Log(title = "代码生成", 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 = "代码生成", businessType = BusinessType.UPDATE)
    @GetMapping("/synchDb/{tableName}")
    public AjaxResult synchDb(@PathVariable("tableName") String tableName)
    {
        genTableService.synchDb(tableName);
        return success();
    }
    /**
     * æ‰¹é‡ç”Ÿæˆä»£ç 
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
    @Log(title = "代码生成", 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.R;
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;
/**
 * ä»£ç ç”Ÿæˆ æ“ä½œå¤„理
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/tool/gen")
@AllArgsConstructor
public class GenController extends BaseController
{
    private IGenTableService genTableService;
    private IGenTableColumnService genTableColumnService;
    /**
     * æŸ¥è¯¢ä»£ç ç”Ÿæˆåˆ—表
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
    @GetMapping("/list")
    public TableDataInfo genList(GenTable genTable)
    {
        startPage();
        List<GenTable> list = genTableService.selectGenTableList(genTable);
        return getDataTable(list);
    }
    /**
     * èŽ·å–ä»£ç ç”Ÿæˆä¿¡æ¯
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:query')")
    @GetMapping(value = "/{talbleId}")
    public R<?> 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 R.ok(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 = "代码生成", businessType = BusinessType.IMPORT)
    @PostMapping("/importTable")
    public R<?> importTableSave(String tables)
    {
        String[] tableNames = Convert.toStrArray(tables);
        // æŸ¥è¯¢è¡¨ä¿¡æ¯
        List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);
        genTableService.importGenTable(tableList, SecurityUtils.getUsername());
        return R.ok();
    }
    /**
     * åˆ›å»ºè¡¨ç»“构(保存)
     */
    @PreAuthorize("@ss.hasRole('admin')")
    @Log(title = "创建表", businessType = BusinessType.OTHER)
    @PostMapping("/createTable")
    public R<?> 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 R.ok();
        }
        catch (Exception e)
        {
            logger.error(e.getMessage(), e);
            return R.fail("创建表结构异常");
        }
    }
    /**
     * ä¿®æ”¹ä¿å­˜ä»£ç ç”Ÿæˆä¸šåŠ¡
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
    @Log(title = "代码生成", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<?> editSave(@Validated @RequestBody GenTable genTable)
    {
        genTableService.validateEdit(genTable);
        genTableService.updateGenTable(genTable);
        return R.ok();
    }
    /**
     * åˆ é™¤ä»£ç ç”Ÿæˆ
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:remove')")
    @Log(title = "代码生成", businessType = BusinessType.DELETE)
    @DeleteMapping("/{tableIds}")
    public R<?> remove(@PathVariable Long[] tableIds)
    {
        genTableService.deleteGenTableByIds(tableIds);
        return R.ok();
    }
    /**
     * é¢„览代码
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:preview')")
    @GetMapping("/preview/{tableId}")
    public R<?> preview(@PathVariable("tableId") Long tableId) throws IOException
    {
        Map<String, String> dataMap = genTableService.previewCode(tableId);
        return R.ok(dataMap);
    }
    /**
     * ç”Ÿæˆä»£ç ï¼ˆä¸‹è½½æ–¹å¼ï¼‰
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
    @Log(title = "代码生成", 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);
    }
    /**
     * ç”Ÿæˆä»£ç ï¼ˆè‡ªå®šä¹‰è·¯å¾„)
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
    @Log(title = "代码生成", businessType = BusinessType.GENCODE)
    @GetMapping("/genCode/{tableName}")
    public R<?> genCode(@PathVariable("tableName") String tableName)
    {
        if (!GenConfig.isAllowOverwrite())
        {
            return R.fail("【系统预设】不允许生成文件覆盖到本地");
        }
        genTableService.generatorCode(tableName);
        return R.ok();
    }
    /**
     * åŒæ­¥æ•°æ®åº“
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
    @Log(title = "代码生成", businessType = BusinessType.UPDATE)
    @GetMapping("/synchDb/{tableName}")
    public R<?> synchDb(@PathVariable("tableName") String tableName)
    {
        genTableService.synchDb(tableName);
        return R.ok();
    }
    /**
     * æ‰¹é‡ç”Ÿæˆä»£ç 
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
    @Log(title = "代码生成", 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());
    }
}
src/main/java/com/ruoyi/projectManagement/controller/InfoController.java
@@ -1,6 +1,7 @@
package com.ruoyi.projectManagement.controller;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.projectManagement.dto.InfoStageDto;
import com.ruoyi.projectManagement.dto.UpdateStateInfo;
import com.ruoyi.projectManagement.service.InfoService;
@@ -24,63 +25,63 @@
@RequestMapping("/projectManagement/info")
@Tag(name = "项目管理信息表(项目管理类型)")
@RequiredArgsConstructor
public class InfoController {
public class InfoController extends BaseController {
    private final InfoService infoService;
    private final InfoStageHandleService infoStageHandleService;
    @PostMapping("/save")
    @Operation(summary = "保存")
    public AjaxResult save(@RequestBody @Valid SaveInfoVo saveInfoVo) {
    public R<?> save(@RequestBody @Valid SaveInfoVo saveInfoVo) {
        infoService.save(saveInfoVo);
        return AjaxResult.success();
        return R.ok();
    }
    @PostMapping("/updateStatus")
    @Operation(summary = "修改状态")
    public AjaxResult updateStatus(@RequestBody @Valid UpdateStateInfo updateStateInfo){
    public R<?> updateStatus(@RequestBody @Valid UpdateStateInfo updateStateInfo){
        infoService.updateStatus(updateStateInfo);
        return AjaxResult.success();
        return R.ok();
    }
    @PostMapping("/delete/{id}")
    @Operation(summary = "删除")
    public AjaxResult delete(@PathVariable Long id) {
    public R<?> delete(@PathVariable Long id) {
        infoService.deleteInfo(id);
        return AjaxResult.success();
        return R.ok();
    }
    @PostMapping("/listPage")
    @Operation(summary = "分页列表")
    public AjaxResult listPage(@RequestBody @Valid SearchInfoVo vo) {
        return AjaxResult.success(infoService.searchListInfo(vo));
    public R<?> listPage(@RequestBody @Valid SearchInfoVo vo) {
        return R.ok(infoService.searchListInfo(vo));
    }
    @PostMapping("/{id}")
    @Operation(summary = "详情")
    public AjaxResult getInfoById(@PathVariable Long id) {
        return AjaxResult.success(infoService.getInfoById(id));
    public R<?> getInfoById(@PathVariable Long id) {
        return R.ok(infoService.getInfoById(id));
    }
    @PostMapping("/saveStage")
    @Operation(summary = "保存阶段")
    public AjaxResult saveStage(@RequestBody @Valid SaveInfoStageVo dto) {
    public R<?> saveStage(@RequestBody @Valid SaveInfoStageVo dto) {
        infoStageHandleService.save(dto);
        return AjaxResult.success();
        return R.ok();
    }
    @PostMapping("/listStage/{id}")
    @Operation(summary = "列表阶段")
    public AjaxResult listStage(@PathVariable Long id) {
        return AjaxResult.success(infoStageHandleService.getListVoByInfoId(id));
    public R<?> listStage(@PathVariable Long id) {
        return R.ok(infoStageHandleService.getListVoByInfoId(id));
    }
    @PostMapping("/deleteStage/{id}")
    @Operation(summary = "删除阶段")
    public AjaxResult deleteStage(@PathVariable Long id) {
    public R<?> deleteStage(@PathVariable Long id) {
        infoStageHandleService.deleteById(id);
        return AjaxResult.success();
        return R.ok();
    }
src/main/java/com/ruoyi/projectManagement/controller/PlanController.java
@@ -1,6 +1,7 @@
package com.ruoyi.projectManagement.controller;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.projectManagement.service.PlanService;
import com.ruoyi.projectManagement.vo.SavePlanNodeVo;
import com.ruoyi.projectManagement.vo.SavePlanVo;
@@ -22,28 +23,28 @@
@RequestMapping("/projectManagement/plan")
@Tag(name = "项目管理计划表(项目管理类型)")
@RequiredArgsConstructor
public class PlanController {
public class PlanController extends BaseController {
    private final PlanService planService;
    @PostMapping("/save")
    @Operation(summary = "保存")
    public AjaxResult save(@RequestBody @Valid SavePlanVo savePlanVo) {
    public R<?> save(@RequestBody @Valid SavePlanVo savePlanVo) {
        planService.savePlan(savePlanVo);
        return AjaxResult.success();
        return R.ok();
    }
    @PostMapping("/delete/{id}")
    @Operation(summary = "删除")
    public AjaxResult delete(@PathVariable Long id) {
    public R<?> delete(@PathVariable Long id) {
        planService.deletePlan(id);
        return AjaxResult.success();
        return R.ok();
    }
    @PostMapping("/listPage")
    @Operation(summary = "分页列表")
    public AjaxResult listPage(@RequestBody SearchPlanVo searchPlanVo) {
        return AjaxResult.success(planService.searchPlan(searchPlanVo));
    public R<?> listPage(@RequestBody SearchPlanVo searchPlanVo) {
        return R.ok(planService.searchPlan(searchPlanVo));
    }
}
src/main/java/com/ruoyi/projectManagement/controller/RolesController.java
@@ -4,7 +4,8 @@
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.projectManagement.dto.RoleDto;
import com.ruoyi.projectManagement.mapper.RolesMapper;
import com.ruoyi.projectManagement.pojo.Roles;
@@ -20,41 +21,41 @@
@AllArgsConstructor
@RequestMapping("/projectManagement/roles")
@Tag(name = "")
public class RolesController {
public class RolesController extends BaseController {
    private RolesService rolesservice;
    private RolesMapper rolesMapper;
    @GetMapping("/listPage")
    @Operation(summary = "分页查询所有")
    public AjaxResult listPage(Page<Roles> page, Roles roles) {
        return AjaxResult.success(rolesservice.listPage(page, roles));
    public R<?> listPage(Page<Roles> page, Roles roles) {
        return R.ok(rolesservice.listPage(page, roles));
    }
    @PostMapping("/add")
    @Operation(summary = "新增")
    public AjaxResult add(@RequestBody RoleDto roleDto) {
    public R<?> add(@RequestBody RoleDto roleDto) {
        if (roleDto.getIsDefaultNo()) {
            roleDto.setNo(OrderUtils.countTodayByCreateTime(rolesMapper, "XMJS","no"));
        }
        return AjaxResult.success(rolesservice.save(roleDto));
        return R.ok(rolesservice.save(roleDto));
    }
    @PostMapping("/update")
    @Operation(summary = "修改")
    public AjaxResult update(@RequestBody Roles roles) {
        return AjaxResult.success(rolesservice.updateById(roles));
    public R<?> update(@RequestBody Roles roles) {
        return R.ok(rolesservice.updateById(roles));
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除")
    public AjaxResult delete(@RequestBody List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) return AjaxResult.error("请传入要删除的ID");
        return AjaxResult.success(rolesservice.removeBatchByIds(ids));
    public R<?> delete(@RequestBody List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) return R.fail("请传入要删除的ID");
        return R.ok(rolesservice.removeBatchByIds(ids));
    }
    @PostMapping("/listSimpleRole")
    public AjaxResult listSimpleRole() {
        return AjaxResult.success(rolesservice.listSimpleRole());
    public R<?> listSimpleRole() {
        return R.ok(rolesservice.listSimpleRole());
    }
}
src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java
@@ -5,7 +5,8 @@
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 com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.purchase.dto.InvoicePurchaseReportDto;
import com.ruoyi.purchase.dto.VatDto;
import com.ruoyi.purchase.pojo.InvoicePurchase;
@@ -27,15 +28,15 @@
@Tag(name = "采购报表")
@RequestMapping("/purchase/report")
@AllArgsConstructor
public class AccountingReportController {
public class AccountingReportController extends BaseController {
    private IInvoicePurchaseService invoicePurchaseService;
    @GetMapping("/list")
    @Log(title = "采购报表-项目利润", businessType = BusinessType.OTHER)
    public AjaxResult list(Page page, InvoicePurchaseReportDto invoicePurchaseReportDto) {
    public R<?> list(Page page, InvoicePurchaseReportDto invoicePurchaseReportDto) {
        IPage<InvoicePurchaseReportDto> result =invoicePurchaseService.listPurchaseReport(page, invoicePurchaseReportDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @Log(title = "采购报表-项目利润导出", businessType = BusinessType.EXPORT)
@@ -51,9 +52,9 @@
    @Log(title = "采购报表-增值税比对", businessType = BusinessType.OTHER)
    @GetMapping("/listVat")
    public AjaxResult listVat(Page page,String month) {
    public R<?> listVat(Page page,String month) {
        IPage<VatDto> result = invoicePurchaseService.listVat(page, month);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @Log(title = "采购报表-增值税比对", businessType = BusinessType.EXPORT)
src/main/java/com/ruoyi/purchase/controller/InvoicePurchaseController.java
@@ -4,7 +4,7 @@
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.framework.web.page.TableDataInfo;
import com.ruoyi.purchase.dto.InvoicePurchaseDto;
import com.ruoyi.purchase.pojo.InvoicePurchase;
@@ -66,8 +66,9 @@
     */
    @Log(title = "发票信息", businessType = BusinessType.INSERT)
    @PostMapping("/addOrUpdateInvoice")
    public AjaxResult addOrUpdateInvoice(@RequestBody InvoicePurchaseDto invoicePurchaseDto) throws IOException {
        return toAjax(invoicePurchaseService.addOrUpdateInvoice(invoicePurchaseDto));
    public R<?> addOrUpdateInvoice(@RequestBody InvoicePurchaseDto invoicePurchaseDto) throws IOException {
        invoicePurchaseService.addOrUpdateInvoice(invoicePurchaseDto);
        return R.ok();
    }
    /**
@@ -75,8 +76,9 @@
     */
    @Log(title = "发票信息", businessType = BusinessType.DELETE)
    @DeleteMapping("/delInvoice")
    public AjaxResult remove(@RequestBody Long[] ids) {
        return toAjax(invoicePurchaseService.delInvoice(ids));
    public R<?> remove(@RequestBody Long[] ids) {
        invoicePurchaseService.delInvoice(ids);
        return R.ok();
    }
}
src/main/java/com/ruoyi/purchase/controller/PaymentRegistrationController.java
@@ -6,7 +6,7 @@
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.framework.web.page.TableDataInfo;
import com.ruoyi.purchase.dto.PaymentHistoryRecordVo;
import com.ruoyi.purchase.dto.PaymentLedgerDto;
@@ -62,8 +62,8 @@
     * èŽ·å–ä»˜æ¬¾ç™»è®°è¯¦ç»†ä¿¡æ¯
     */
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(paymentRegistrationService.selectPaymentRegistrationById(id));
    public R<?> getInfo(@PathVariable("id") Long id) {
        return R.ok(paymentRegistrationService.selectPaymentRegistrationById(id));
    }
    /**
@@ -72,8 +72,9 @@
    @Log(title = "付款登记", businessType = BusinessType.INSERT)
    @PostMapping
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody List<PaymentRegistration>  paymentRegistration) {
        return toAjax(paymentRegistrationService.insertPaymentRegistration(paymentRegistration));
    public R<?> add(@RequestBody List<PaymentRegistration>  paymentRegistration) {
        paymentRegistrationService.insertPaymentRegistration(paymentRegistration);
        return R.ok();
    }
    /**
@@ -82,8 +83,9 @@
    @Log(title = "付款登记", businessType = BusinessType.UPDATE)
    @PutMapping
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult edit(@RequestBody PaymentRegistration paymentRegistration) {
        return toAjax(paymentRegistrationService.updatePaymentRegistration(paymentRegistration));
    public R<?> edit(@RequestBody PaymentRegistration paymentRegistration) {
        paymentRegistrationService.updatePaymentRegistration(paymentRegistration);
        return R.ok();
    }
    /**
@@ -91,8 +93,9 @@
     */
    @Log(title = "付款登记", businessType = BusinessType.DELETE)
    @DeleteMapping("/del")
    public AjaxResult remove(@RequestBody Long[] ids) {
        return toAjax(paymentRegistrationService.deletePaymentRegistrationByIds(ids));
    public R<?> remove(@RequestBody Long[] ids) {
        paymentRegistrationService.deletePaymentRegistrationByIds(ids);
        return R.ok();
    }
    /**
@@ -100,51 +103,52 @@
     */
    @Log(title = "付款登记", businessType = BusinessType.DELETE)
    @DeleteMapping("/delete")
    public AjaxResult delete(@RequestBody Long[] ids) {
        return toAjax(paymentRegistrationService.delete(ids));
    public R<?> delete(@RequestBody Long[] ids) {
        paymentRegistrationService.delete(ids);
        return R.ok();
    }
    /**
     * èŽ·å–ä»˜æ¬¾ç™»è®°è¯¦ç»†ä¿¡æ¯
     */
    @GetMapping(value = "/byPurchaseId/{id}")
    public AjaxResult getPurchaseInfo(@PathVariable("id") Long id) {
        return success(paymentRegistrationService.selectPaymentRegistrationByPurchaseId(id));
    public R<?> getPurchaseInfo(@PathVariable("id") Long id) {
        return R.ok(paymentRegistrationService.selectPaymentRegistrationByPurchaseId(id));
    }
    /**
     * èŽ·å–ä»˜æ¬¾ç™»è®°è¯¦ç»†ä¿¡æ¯
     */
    @GetMapping(value = "/paymentLedgerList")
    public AjaxResult paymentLedgerList(PaymentLedgerDto paymentLedgerDto, Page page,
    public R<?> paymentLedgerList(PaymentLedgerDto paymentLedgerDto, Page page,
                                        Integer detailPageNum,
                                        Integer detailPageSize) {
        IPage<Map<String, Object>> mapIPage = paymentRegistrationService.selectPaymentLedgerList(paymentLedgerDto, page, detailPageNum, detailPageSize);
        return success(mapIPage);
        return R.ok(mapIPage);
    }
    /**
     * ä¾›åº”商往来分页接口
     */
    @GetMapping("/supplierNameListPage")
    public AjaxResult supplierNameListPage(PaymentLedgerDto paymentLedgerDto, Page page){
        return success(paymentRegistrationService.supplierNameListPage(page,paymentLedgerDto));
    public R<?> supplierNameListPage(PaymentLedgerDto paymentLedgerDto, Page page){
        return R.ok(paymentRegistrationService.supplierNameListPage(page,paymentLedgerDto));
    }
    /**
     * ä¾›åº”商往来分页接口
     */
    @GetMapping("/supplierNameListPageDetails")
    public AjaxResult supplierNameListPageDetails(PaymentLedgerDto paymentLedgerDto){
        return success(paymentRegistrationService.supplierNameListPageDetails(paymentLedgerDto));
    public R<?> supplierNameListPageDetails(PaymentLedgerDto paymentLedgerDto){
        return R.ok(paymentRegistrationService.supplierNameListPageDetails(paymentLedgerDto));
    }
    /**
     * èŽ·å–æœ¬æœˆåº”ä»˜ä¿¡æ¯
     */
    @GetMapping(value = "/paymentMonthList")
    public AjaxResult paymentMonthList() {
        return success(paymentRegistrationService.paymentMonthList());
    public R<?> paymentMonthList() {
        return R.ok(paymentRegistrationService.paymentMonthList());
    }
    /**
@@ -166,9 +170,9 @@
     * @return
     */
    @GetMapping("/getPaymentRecordList/{supplierId}")
    public AjaxResult getPaymentRecordList(@PathVariable Long supplierId) {
    public R<?> getPaymentRecordList(@PathVariable Long supplierId) {
        List<PaymentHistoryRecordVo> paymentRecordList = paymentRegistrationService.getPaymentRecordList(supplierId);
        return success(paymentRecordList);
        return R.ok(paymentRecordList);
    }
    /**
src/main/java/com/ruoyi/purchase/controller/ProcurementBusinessSummaryController.java
@@ -6,7 +6,7 @@
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.purchase.dto.ProcurementBusinessSummaryDto;
import com.ruoyi.purchase.service.impl.ProcurementBusinessSummaryServiceImpl;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -31,8 +31,8 @@
    private ProcurementBusinessSummaryServiceImpl procurementBusinessSummaryService;
    @GetMapping("/listPage")
    public AjaxResult listPage(Page page, ProcurementBusinessSummaryDto procurementBusinessSummaryDto) {
        return AjaxResult.success(procurementBusinessSummaryService.listPage(page, procurementBusinessSummaryDto));
    public R<?> listPage(Page page, ProcurementBusinessSummaryDto procurementBusinessSummaryDto) {
        return R.ok(procurementBusinessSummaryService.listPage(page, procurementBusinessSummaryDto));
    }
    /**
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
@@ -8,7 +8,7 @@
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.framework.web.page.TableDataInfo;
import com.ruoyi.purchase.dto.PurchaseLedgerDto;
import com.ruoyi.purchase.mapper.PurchaseLedgerTemplateMapper;
@@ -67,7 +67,7 @@
    @Log(title = "导入采购台账", businessType = BusinessType.INSERT)
    @PostMapping("/import")
    @Operation(summary = "导入采购台账")
    public AjaxResult importData(@RequestParam("file")
    public R<?> importData(@RequestParam("file")
                                 @ApiParam(value = "Excel文件", required = true)
                                         MultipartFile file) {
        return purchaseLedgerService.importData(file);
@@ -151,8 +151,9 @@
     */
    @Log(title = "采购台账", businessType = BusinessType.INSERT)
    @PostMapping("/addOrEditPurchase")
    public AjaxResult addOrEditPurchase(@RequestBody PurchaseLedgerDto purchaseLedgerDto) throws Exception {
        return toAjax(purchaseLedgerService.addOrEditPurchase(purchaseLedgerDto));
    public R<?> addOrEditPurchase(@RequestBody PurchaseLedgerDto purchaseLedgerDto) throws Exception {
        purchaseLedgerService.addOrEditPurchase(purchaseLedgerDto);
        return R.ok();
    }
    /**
@@ -160,7 +161,7 @@
     */
    @Operation(summary = "/查询采购模板")
    @GetMapping("/getPurchaseTemplateList")
    public AjaxResult getPurchaseTemplateList() {
    public R<?> getPurchaseTemplateList() {
        List<PurchaseLedgerTemplate>  purchaseLedgers = purchaseLedgerTemplateMapper.selectList(null);
        purchaseLedgers.forEach(purchaseLedgerDto1 -> {
            LambdaQueryWrapper<SalesLedgerProductTemplate> queryWrapper = new LambdaQueryWrapper<>();
@@ -171,14 +172,15 @@
                purchaseLedgerDto1.setProductList(list);
            }
        });
        return AjaxResult.success(purchaseLedgers);
        return R.ok(purchaseLedgers);
    }
    /**
     * ä¿®æ”¹é‡‡è´­å°è´¦å®¡æ‰¹çŠ¶æ€
     */
    @PostMapping("/updateApprovalStatus")
    public AjaxResult addOrEditPurchase(@RequestBody PurchaseLedger purchaseLedger){
        return toAjax(purchaseLedgerService.updateById(purchaseLedger));
    public R<?> addOrEditPurchase(@RequestBody PurchaseLedger purchaseLedger){
        purchaseLedgerService.updateById(purchaseLedger);
        return R.ok();
    }
    /**
     * æŸ¥è¯¢é‡‡è´­å°è´¦å’Œäº§å“çˆ¶å­åˆ—表
@@ -201,8 +203,9 @@
     */
    @Log(title = "采购台账", businessType = BusinessType.DELETE)
    @DeleteMapping("/delPurchase")
    public AjaxResult remove(@RequestBody Long[] ids) {
        return toAjax(purchaseLedgerService.deletePurchaseLedgerByIds(ids));
    public R<?> remove(@RequestBody Long[] ids) {
        purchaseLedgerService.deletePurchaseLedgerByIds(ids);
        return R.ok();
    }
    /**
@@ -218,8 +221,8 @@
     * æ ¹æ®é”€å”®åˆåŒæŸ¥è¯¢äº§å“ä¿¡æ¯
     */
    @GetMapping("/getProductBySalesNo")
    public AjaxResult getProductBySalesNo(Long id) {
        return AjaxResult.success(purchaseLedgerService.getProductBySalesNo(id));
    public R<?> getProductBySalesNo(Long id) {
        return R.ok(purchaseLedgerService.getProductBySalesNo(id));
    }
    /**
@@ -234,8 +237,8 @@
     * æ ¹æ®id查询采购合同号
     */
    @GetMapping("/getPurchaseNoById")
    public AjaxResult getPurchaseNoById(Long id) {
        return AjaxResult.success(purchaseLedgerService.getPurchaseNoById(id));
    public R<?> getPurchaseNoById(Long id) {
        return R.ok(purchaseLedgerService.getPurchaseNoById(id));
    }
    /**
@@ -250,22 +253,22 @@
     * æ ¹æ®é‡‡è´­åˆåŒå·æŸ¥è¯¢äº§å“
     */
    @GetMapping("/getInfo")
    public AjaxResult getInfo(PurchaseLedgerDto purchaseLedgerDto) {
        return AjaxResult.success(purchaseLedgerService.getInfo(purchaseLedgerDto));
    public R<?> getInfo(PurchaseLedgerDto purchaseLedgerDto) {
        return R.ok(purchaseLedgerService.getInfo(purchaseLedgerDto));
    }
    /**
     * æŸ¥è¯¢é‡‡è´­å°è´¦åˆ—表
     */
    @GetMapping("/listPage")
    public AjaxResult listPage(Page page, PurchaseLedgerDto purchaseLedger) {
        return AjaxResult.success(purchaseLedgerService.selectPurchaseLedgerListPage(page, purchaseLedger));
    public R<?> listPage(Page page, PurchaseLedgerDto purchaseLedger) {
        return R.ok(purchaseLedgerService.selectPurchaseLedgerListPage(page, purchaseLedger));
    }
    @Operation(summary = "生成采购序列号")
    @GetMapping("/createPurchaseNo")
    @Log(title = "生成采购序列号", businessType = BusinessType.OTHER)
    public AjaxResult createPurchaseNo() {
        return AjaxResult.success("生成成功",purchaseLedgerService.getPurchaseNo());
    public R<?> createPurchaseNo() {
        return R.ok(purchaseLedgerService.getPurchaseNo(), "生成成功");
    }
}
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerTemplateController.java
@@ -4,7 +4,8 @@
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.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.purchase.dto.PurchaseLedgerDto;
import com.ruoyi.purchase.mapper.PurchaseLedgerTemplateMapper;
import com.ruoyi.purchase.mapper.SalesLedgerProductTemplateMapper;
@@ -31,7 +32,7 @@
@RequestMapping("/purchaseLedgerTemplate")
@Tag(name = "采购台账模板")
@AllArgsConstructor
public class PurchaseLedgerTemplateController {
public class PurchaseLedgerTemplateController extends BaseController {
    private PurchaseLedgerTemplateMapper purchaseLedgerTemplateMapper;
    private SalesLedgerProductTemplateMapper salesLedgerProductTemplateMapper;
@@ -39,7 +40,7 @@
    @PostMapping("/add")
    @Log(title = "添加采购台账模板", businessType = BusinessType.INSERT)
    @Operation(summary = "添加采购台账模板")
    public AjaxResult add(@RequestBody PurchaseLedgerDto purchaseLedgerDto) {
    public R<?> add(@RequestBody PurchaseLedgerDto purchaseLedgerDto) {
        // é‡‡è´­æ¨¡æ¿
        if(StringUtils.isNotEmpty(purchaseLedgerDto.getTemplateName())){
            // æ¨¡æ¿åç§°ä¸èƒ½é‡å¤ï¼Œæœ‰é‡å¤å°±ä¸éœ€è¦æ–°å¢žäº†
@@ -63,24 +64,24 @@
                });
            }
        }
        return AjaxResult.success();
        return R.ok();
    }
    @DeleteMapping("/delete")
    @Log(title = "采购台账模板", businessType = BusinessType.DELETE)
    @Operation(summary = "删除采购台账模板")
    public AjaxResult delete(@RequestBody List<Long> id) {
        if(CollectionUtils.isEmpty(id)) return AjaxResult.error("请选择要删除的采购台账模板");
    public R<?> delete(@RequestBody List<Long> id) {
        if(CollectionUtils.isEmpty(id)) return R.fail("请选择要删除的采购台账模板");
        int result = purchaseLedgerTemplateMapper.deleteBatchIds(id);
        salesLedgerProductTemplateMapper.delete(new LambdaQueryWrapper<SalesLedgerProductTemplate>()
                .in(SalesLedgerProductTemplate::getSalesLedgerId, id));
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @PostMapping("/update")
    @Log(title = "修改采购台账模板", businessType = BusinessType.UPDATE)
    @Operation(summary = "修改采购台账模板")
    public AjaxResult update(@RequestBody PurchaseLedgerDto purchaseLedgerDto) {
    public R<?> update(@RequestBody PurchaseLedgerDto purchaseLedgerDto) {
        // æ¨¡æ¿åç§°ä¸èƒ½é‡å¤ï¼Œæœ‰é‡å¤å°±ä¸éœ€è¦æ–°å¢žäº†
        PurchaseLedgerTemplate purchaseLedgerTemplate = purchaseLedgerTemplateMapper
                .selectOne(new LambdaQueryWrapper<PurchaseLedgerTemplate>()
@@ -102,7 +103,7 @@
                salesLedgerProductTemplateMapper.insert(salesLedgerProductTemplate);
            });
        }
        return AjaxResult.success();
        return R.ok();
    }
}
src/main/java/com/ruoyi/purchase/controller/PurchaseReturnOrdersController.java
@@ -4,7 +4,8 @@
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.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.purchase.dto.PurchaseReturnOrderDto;
import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper;
import com.ruoyi.purchase.service.PurchaseReturnOrdersService;
@@ -28,43 +29,43 @@
@RequestMapping("/purchaseReturnOrders")
@Tag(name = "采购退货单")
@AllArgsConstructor
public class PurchaseReturnOrdersController {
public class PurchaseReturnOrdersController extends BaseController {
    private PurchaseReturnOrdersService purchaseReturnOrdersService;
    private PurchaseReturnOrdersMapper purchaseReturnOrdersMapper;
    @GetMapping("/listPage")
    public AjaxResult listPage(Page page, PurchaseReturnOrderDto purchaseReturnOrderDto) {
        return AjaxResult.success(purchaseReturnOrdersService.listPage(page, purchaseReturnOrderDto));
    public R<?> listPage(Page page, PurchaseReturnOrderDto purchaseReturnOrderDto) {
        return R.ok(purchaseReturnOrdersService.listPage(page, purchaseReturnOrderDto));
    }
    // æ–°å¢ž
    @Log(title = "采购退货单", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    public AjaxResult add(@RequestBody PurchaseReturnOrderDto purchaseReturnOrderDto) throws Exception {
    public R<?> add(@RequestBody PurchaseReturnOrderDto purchaseReturnOrderDto) throws Exception {
        if (purchaseReturnOrderDto.getIsDefaultNo()) {
            purchaseReturnOrderDto.setNo(OrderUtils.countTodayByCreateTime(purchaseReturnOrdersMapper, "CGTL", "no"));
        }
        return AjaxResult.success(purchaseReturnOrdersService.add(purchaseReturnOrderDto));
        return R.ok(purchaseReturnOrdersService.add(purchaseReturnOrderDto));
    }
    @GetMapping("/selectById/{id}")
    public AjaxResult selectById(@PathVariable Long id) {
        return AjaxResult.success(purchaseReturnOrdersService.getPurchaseReturnOrderDtoById(id));
    public R<?> selectById(@PathVariable Long id) {
        return R.ok(purchaseReturnOrdersService.getPurchaseReturnOrderDtoById(id));
    }
    @PostMapping("/deleteById/{id}")
    public AjaxResult deleteById(@PathVariable Long id) {
    public R<?> deleteById(@PathVariable Long id) {
        purchaseReturnOrdersService.deleteById(id);
        return AjaxResult.success();
        return R.ok();
    }
    @GetMapping("/getByPurchaseLedgerId")
    @Operation(summary = "采购退货-根据采购订单id查询采购订单对应的入库产品信息")
    public AjaxResult getByPurchaseLedgerId(Long purchaseLedgerId) {
    public R<?> getByPurchaseLedgerId(Long purchaseLedgerId) {
        List<PurchaseStockInProductVo> purchaseStockInProductVos = purchaseReturnOrdersService.getByPurchaseLedgerId(purchaseLedgerId);
        return AjaxResult.success(purchaseStockInProductVos);
        return R.ok(purchaseStockInProductVos);
    }
src/main/java/com/ruoyi/purchase/controller/TicketRegistrationController.java
@@ -6,7 +6,7 @@
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.framework.web.page.TableDataInfo;
import com.ruoyi.purchase.dto.PaymentRegistrationDto;
import com.ruoyi.purchase.dto.ProductRecordDto;
@@ -70,23 +70,24 @@
    @Operation(summary = "根据id查询付款流水")
    @GetMapping("/getPaymentRegistrationById")
    public AjaxResult getPaymentRegistrationById(Long id) {
    public R<?> getPaymentRegistrationById(Long id) {
        PaymentRegistration byId = paymentRegistrationService.getById(id);
        return AjaxResult.success(byId);
        return R.ok(byId);
    }
    @Operation(summary = "修改付款流水")
    @PutMapping("/updatePaymentRegistration")
    @Log(title = "修改付款流水", businessType = BusinessType.UPDATE)
    public AjaxResult updatePaymentRegistration(@RequestBody PaymentRegistration paymentRegistratio) {
        return AjaxResult.success(paymentRegistrationService.updatePaymentRegistration(paymentRegistratio));
    public R<?> updatePaymentRegistration(@RequestBody PaymentRegistration paymentRegistratio) {
        return R.ok(paymentRegistrationService.updatePaymentRegistration(paymentRegistratio));
    }
    @Operation(summary = "删除付款流水")
    @DeleteMapping("/delPaymentRegistration")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delPaymentRegistration(@RequestBody List<Long> id) {
        return toAjax(paymentRegistrationService.delPaymentRegistration(id));
    public R<?> delPaymentRegistration(@RequestBody List<Long> id) {
        paymentRegistrationService.delPaymentRegistration(id);
        return R.ok();
    }
    /**
@@ -126,26 +127,26 @@
    @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("请选择要保存的记录");
    public R<?> addOrUpdateRegistration(@RequestBody List<TicketRegistrationDto> ticketRegistrationDto) throws IOException {
        if(CollectionUtils.isEmpty(ticketRegistrationDto)) return R.fail("请选择要保存的记录");
        for (TicketRegistrationDto ticketRegistrationDto1 : ticketRegistrationDto) {
            ticketRegistrationService.addOrUpdateRegistration(ticketRegistrationDto1);
        }
        return toAjax(1);
        return R.ok();
    }
    @PostMapping("/getProductRecordById")
    public AjaxResult getProductRecordById(@RequestBody ProductRecordDto productRecordDto) {
    public R<?> getProductRecordById(@RequestBody ProductRecordDto productRecordDto) {
        if (productRecordDto.getId() == null) {
            return AjaxResult.error("参数错误");
            return R.fail("参数错误");
        }
        return AjaxResult.success(productRecordService.getProductRecordById(productRecordDto));
        return R.ok(productRecordService.getProductRecordById(productRecordDto));
    }
    @Schema(description = "修改来票登记")
    @PostMapping("/updateRegistration")
    public AjaxResult updateRegistration(@RequestBody ProductRecordDto productRecordDto) {
    public R<?> updateRegistration(@RequestBody ProductRecordDto productRecordDto) {
        return productRecordService.updateRecord(productRecordDto);
    }
@@ -156,8 +157,9 @@
    @Log(title = "删除来票登记(来票台账)", businessType = BusinessType.DELETE)
    @DeleteMapping("/delRegistration")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delRegistration(@RequestBody Long[] ids) {
        return toAjax(ticketRegistrationService.delRegistration(ids));
    public R<?> delRegistration(@RequestBody Long[] ids) {
        ticketRegistrationService.delRegistration(ids);
        return R.ok();
    }
    /**
@@ -173,18 +175,18 @@
     * åˆ†é¡µæŸ¥è¯¢äº§å“ä¿¡æ¯å¼€ç¥¨è®°å½•列表
     */
    @GetMapping("/productRecordPage")
    public AjaxResult productRecordPage(Page page, TicketRegistrationDto ticketRegistrationDto) {
    public R<?> productRecordPage(Page page, TicketRegistrationDto ticketRegistrationDto) {
        IPage<ProductRecordDto> list = productRecordService.productRecordPage(page,ticketRegistrationDto);
        return AjaxResult.success(list);
        return R.ok(list);
    }
    /**
     * æŸ¥è¯¢å‘票号
     */
    @GetMapping("/getTicketNo")
    public AjaxResult getTicketNo(TicketRegistrationDto ticketRegistrationDto) {
        return AjaxResult.success(ticketRegistrationService.getTicketNo(ticketRegistrationDto));
    public R<?> getTicketNo(TicketRegistrationDto ticketRegistrationDto) {
        return R.ok(ticketRegistrationService.getTicketNo(ticketRegistrationDto));
    }
    /**
@@ -197,8 +199,8 @@
    @Schema(description = "根据id查询来漂登记")
    @GetMapping("/getPuargeById")
    public AjaxResult getPuargeById(Long id) {
        return AjaxResult.success(ticketRegistrationService.getPuargeById( id));
    public R<?> getPuargeById(Long id) {
        return R.ok(ticketRegistrationService.getPuargeById( id));
    }
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;
src/main/java/com/ruoyi/purchase/service/IProductRecordService.java
@@ -3,7 +3,7 @@
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.framework.web.domain.R;
import com.ruoyi.purchase.dto.ProductRecordDto;
import com.ruoyi.purchase.dto.TicketRegistrationDto;
import com.ruoyi.purchase.pojo.ProductRecord;
@@ -22,7 +22,7 @@
    IPage<ProductRecordDto> productRecordPage(Page page, TicketRegistrationDto ticketRegistrationDto);
    AjaxResult updateRecord(ProductRecordDto productRecordDto);
    R<?> updateRecord(ProductRecordDto productRecordDto);
    ProductRecordDto getProductRecordById(ProductRecordDto productRecordDto);
}
src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
@@ -3,7 +3,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.purchase.dto.PurchaseLedgerDto;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
@@ -44,7 +44,7 @@
    String getPurchaseNo();
    AjaxResult importData(MultipartFile file);
    R<?> importData(MultipartFile file);
    PurchaseLedgerDto getPurchaseByCode(PurchaseLedgerDto purchaseLedgerDto);
}
src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java
@@ -6,7 +6,7 @@
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.framework.web.domain.R;
import com.ruoyi.purchase.dto.ProductRecordDto;
import com.ruoyi.purchase.dto.TicketRegistrationDto;
import com.ruoyi.purchase.mapper.ProductRecordMapper;
@@ -67,9 +67,9 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult updateRecord(ProductRecordDto productRecordDto) {
    public R<?> updateRecord(ProductRecordDto productRecordDto) {
        ProductRecord productRecord = productRecordMapper.selectById(productRecordDto.getId());
        if (productRecord == null) return AjaxResult.error("记录不存在");
        if (productRecord == null) return R.fail("记录不存在");
        //  æ›´æ–°äº§å“å°è´¦
        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(productRecord.getSaleLedgerProjectId());
@@ -110,7 +110,7 @@
        productRecord.setFutureTicketsAmount(productRecord.getFutureTickets().multiply(productRecord.getTaxInclusiveUnitPrice()));
        productRecordMapper.updateById(productRecord);
        return AjaxResult.success("修改成功");
        return R.ok(null, "修改成功");
    }
    @Override
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -24,7 +24,7 @@
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.other.mapper.TempFileMapper;
import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
@@ -534,18 +534,18 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult importData(MultipartFile file) {
    public R<?> importData(MultipartFile file) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        try {
            InputStream inputStream = file.getInputStream();
            ExcelUtil<PurchaseLedgerImportDto> salesLedgerImportDtoExcelUtil = new ExcelUtil<>(PurchaseLedgerImportDto.class);
            Map<String, List<PurchaseLedgerImportDto>> stringListMap = salesLedgerImportDtoExcelUtil.importExcelMultiSheet(Arrays.asList("采购台账数据", "采购产品数据"), inputStream, 0);
            if (CollectionUtils.isEmpty(stringListMap)) return AjaxResult.error("采购表格为空!");
            if (CollectionUtils.isEmpty(stringListMap)) return R.fail("采购表格为空!");
            // ä¸šåŠ¡å±‚åˆå¹¶
            List<PurchaseLedgerImportDto> salesLedgerImportDtoList = stringListMap.get("采购台账数据");
            if (CollectionUtils.isEmpty(salesLedgerImportDtoList)) return AjaxResult.error("采购台账数据为空!");
            if (CollectionUtils.isEmpty(salesLedgerImportDtoList)) return R.fail("采购台账数据为空!");
            List<PurchaseLedgerImportDto> salesLedgerProductImportDtoList = stringListMap.get("采购产品数据");
            if (CollectionUtils.isEmpty(salesLedgerProductImportDtoList)) return AjaxResult.error("采购产品数据为空!");
            if (CollectionUtils.isEmpty(salesLedgerProductImportDtoList)) return R.fail("采购产品数据为空!");
            // ä¾›åº”商数据
            List<SupplierManage> customers = supplierManageMapper.selectList(new LambdaQueryWrapper<SupplierManage>().in(SupplierManage::getSupplierName,
                    salesLedgerImportDtoList.stream().map(PurchaseLedgerImportDto::getSupplierName).collect(Collectors.toList())));
@@ -640,11 +640,11 @@
                addApproveByPurchase(loginUser,salesLedger);
            }
            return AjaxResult.success("导入成功");
            return R.ok(null, "导入成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return AjaxResult.success("导入失败");
        return R.ok(null, "导入失败");
    }
    @Override
src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java
@@ -29,13 +29,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>
@@ -122,9 +120,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())));
        purchaseReturnOrderProducts.stream().forEach(purchaseReturnOrderProducts1 -> {
            stockUtils.deleteStockOutRecord(purchaseReturnOrderProducts1.getId(),StockOutQualifiedRecordTypeEnum.PURCHASE_RETURN_STOCK_OUT.getCode());
        });
        // è´¢åŠ¡
        LambdaUpdateWrapper<AccountIncome> updateWrapperAccountIncome = new LambdaUpdateWrapper<>();
        updateWrapperAccountIncome.eq(AccountIncome::getBusinessId, id);
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,6 +12,7 @@
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 lombok.AllArgsConstructor;
import org.springframework.util.CollectionUtils;
@@ -37,8 +40,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 +53,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 +73,7 @@
        qualityInspectFileService.remove(Wrappers.<QualityInspectFile>lambdaQuery()
                .in(QualityInspectFile::getInspectId, ids));
        //删除检验单
        return AjaxResult.success(qualityInspectService.removeBatchByIds(ids));
        return R.ok(qualityInspectService.removeBatchByIds(ids));
    }
    /**
@@ -76,8 +83,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 +96,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 +110,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 +123,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 +136,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(@RequestBody QualityInspect qualityInspect) {
        return R.ok(qualityInspectService.submit(qualityInspect));
    }
    /**
@@ -132,6 +149,8 @@
     * @param qualityInspect
     */
    @PostMapping("/down")
    @Operation(summary = "下载检验")
    @Log(title = "下载检验", businessType = BusinessType.OTHER)
    public void down(HttpServletResponse response, @RequestBody QualityInspect qualityInspect) {
        qualityInspectService.down(response, qualityInspect);
    }
src/main/java/com/ruoyi/quality/controller/QualityInspectFileController.java
@@ -2,7 +2,7 @@
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.web.domain.R;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityInspectFile;
import com.ruoyi.quality.pojo.QualityInspectParam;
@@ -34,8 +34,8 @@
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody QualityInspectFile qualityInspectFile) {
        return AjaxResult.success(qualityInspectFileService.save(qualityInspectFile));
    public R<?> add(@RequestBody QualityInspectFile qualityInspectFile) {
        return R.ok(qualityInspectFileService.save(qualityInspectFile));
    }
    /**
@@ -44,12 +44,12 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delQualityUnqualified(@RequestBody List<Integer> ids) {
    public R<?> delQualityUnqualified(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        //删除检验附件
        return AjaxResult.success(qualityInspectFileService.removeBatchByIds(ids));
        return R.ok(qualityInspectFileService.removeBatchByIds(ids));
    }
    /**
@@ -59,8 +59,8 @@
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult qualityInspectFileListPage(Page page, QualityInspectFile qualityInspectFile) {
        return AjaxResult.success(qualityInspectFileService.qualityInspectFileListPage(page, qualityInspectFile));
    public R<?> qualityInspectFileListPage(Page page, QualityInspectFile qualityInspectFile) {
        return R.ok(qualityInspectFileService.qualityInspectFileListPage(page, qualityInspectFile));
    }
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));
    }
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));
    }
}
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));
    }
}
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 = "根据检测标准id查询相关的检验标准参数")
    @Log(title = "根据检测标准id查询相关的检验标准参数", businessType = BusinessType.OTHER)
    public R<?> getQualityTestStandardParamByTestStandardId(Long testStandardId) {
        return R.ok(qualityTestStandardParamService.list(Wrappers.<QualityTestStandardParam>lambdaQuery().eq(QualityTestStandardParam::getTestStandardId, testStandardId)));
    }
}
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)));
    }
}
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));
    }
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;
}
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -121,10 +121,12 @@
            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 + "这些指标中存在不合格");//不合格现象
            qualityUnqualified.setInspectId(qualityInspect.getId());
            qualityUnqualified.setId(null);
            qualityUnqualifiedMapper.insert(qualityUnqualified);
        }
src/main/java/com/ruoyi/sales/controller/CommonFileController.java
@@ -3,7 +3,7 @@
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.service.ICommonFileService;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -26,11 +26,12 @@
     */
    @Log(title = "附件删除", businessType = BusinessType.DELETE)
    @DeleteMapping("/delCommonFile")
    public AjaxResult delCommonFile(@RequestBody Long[] ids) {
    public R<?> delCommonFile(@RequestBody Long[] ids) {
        if (ids == null || ids.length == 0) {
            return AjaxResult.error("请传入要删除的ID");
            return R.fail("请传入要删除的ID");
        }
        return toAjax(commonFileService.delCommonFileByIds(ids));
        commonFileService.delCommonFileByIds(ids);
        return R.ok();
    }
    public void migrateTempFilesToFormal(Long businessId, List<String> tempFileIds) throws IOException{
src/main/java/com/ruoyi/sales/controller/InvoiceLedgerController.java
@@ -3,7 +3,8 @@
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.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.sales.dto.InvoiceLedgerDto;
import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
import com.ruoyi.sales.mapper.InvoiceLedgerFileMapper;
@@ -20,7 +21,7 @@
@RestController
@RequestMapping("/invoiceLedger")
@AllArgsConstructor
public class InvoiceLedgerController {
public class InvoiceLedgerController extends BaseController {
    private InvoiceLedgerService invoiceLedgerService;
    private InvoiceLedgerFileMapper invoiceLedgerFileMapper;
@@ -31,9 +32,9 @@
     * @return
     */
    @PostMapping("/saveOrUpdate")
    public AjaxResult invoiceLedgerSaveOrUpdate(@RequestBody InvoiceRegistrationProductDto productDto) {
    public R<?> invoiceLedgerSaveOrUpdate(@RequestBody InvoiceRegistrationProductDto productDto) {
        invoiceLedgerService.invoiceLedgerSaveOrUpdate(productDto);
        return AjaxResult.success();
        return R.ok();
    }
    /**
@@ -42,9 +43,9 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult invoiceLedgerDel(@RequestBody List<Integer> ids) {
    public R<?> invoiceLedgerDel(@RequestBody List<Integer> ids) {
        invoiceLedgerService.invoiceLedgerDel(ids);
        return AjaxResult.success();
        return R.ok();
    }
    /**
@@ -54,8 +55,8 @@
     * @return
     */
    @GetMapping("/page")
    public AjaxResult invoiceLedgerPage(Page page, InvoiceLedgerDto invoiceLedgerDto) {
        return AjaxResult.success(invoiceLedgerService.invoiceLedgerPage(page, invoiceLedgerDto));
    public R<?> invoiceLedgerPage(Page page, InvoiceLedgerDto invoiceLedgerDto) {
        return R.ok(invoiceLedgerService.invoiceLedgerPage(page, invoiceLedgerDto));
    }
    /**
@@ -64,8 +65,8 @@
     * @return
     */
    @GetMapping("/fileList")
    public AjaxResult invoiceLedgerFileList(Integer invoiceLedgerId) {
        return AjaxResult.success(invoiceLedgerService.invoiceLedgerFileList(invoiceLedgerId));
    public R<?> invoiceLedgerFileList(Integer invoiceLedgerId) {
        return R.ok(invoiceLedgerService.invoiceLedgerFileList(invoiceLedgerId));
    }
    /**
@@ -73,10 +74,10 @@
     */
    @DeleteMapping("/delFile")
    @Log(title = "开票台账", businessType = BusinessType.DELETE)
    public AjaxResult invoiceLedgerDelFile(@RequestBody List<Integer> ids) {
        if(Collections.isEmpty(ids)) return AjaxResult.error("请选择要删除的文件");
    public R<?> invoiceLedgerDelFile(@RequestBody List<Integer> ids) {
        if(Collections.isEmpty(ids)) return R.fail("请选择要删除的文件");
        invoiceLedgerFileMapper.deleteBatchIds(ids);
        return AjaxResult.success();
        return R.ok();
    }
@@ -87,11 +88,11 @@
     * @return
     */
    @PostMapping("/uploadFile")
    public AjaxResult invoiceLedgerUploadFile(MultipartFile file) {
    public R<?> invoiceLedgerUploadFile(MultipartFile file) {
        try {
            return AjaxResult.success(invoiceLedgerService.invoiceLedgerUploadFile(file));
            return R.ok(invoiceLedgerService.invoiceLedgerUploadFile(file));
        }catch (Exception e) {
            return AjaxResult.error(e.getMessage());
            return R.fail(e.getMessage());
        }
    }
@@ -112,8 +113,8 @@
     * @return
     */
    @GetMapping("/info")
    public AjaxResult invoiceLedgerInfo(Integer id) {
        return AjaxResult.success(invoiceLedgerService.invoiceLedgerDetail(id));
    public R<?> invoiceLedgerInfo(Integer id) {
        return R.ok(invoiceLedgerService.invoiceLedgerDetail(id));
    }
    /**
@@ -122,12 +123,12 @@
     * @return
     */
    @PostMapping("/commitFile")
    public AjaxResult invoiceLedgerCommitFile(@RequestBody InvoiceLedgerDto invoiceLedgerDto) {
    public R<?> invoiceLedgerCommitFile(@RequestBody InvoiceLedgerDto invoiceLedgerDto) {
        try {
            invoiceLedgerService.invoiceLedgerCommitFile(invoiceLedgerDto);
            return AjaxResult.success();
            return R.ok();
        }catch (Exception e) {
            return AjaxResult.error(e.getMessage());
            return R.fail(e.getMessage());
        }
    }
@@ -137,8 +138,8 @@
     * @return
     */
    @GetMapping("/list")
    public AjaxResult invoiceLedgerList(InvoiceLedgerDto invoiceLedgerDto) {
        return AjaxResult.success(invoiceLedgerService.invoiceLedgerList(invoiceLedgerDto));
    public R<?> invoiceLedgerList(InvoiceLedgerDto invoiceLedgerDto) {
        return R.ok(invoiceLedgerService.invoiceLedgerList(invoiceLedgerDto));
    }
    /**
@@ -148,20 +149,20 @@
     * @return
     */
    @GetMapping("/salesAccount")
    public AjaxResult invoiceLedgerSalesAccount(Page page, InvoiceLedgerDto invoiceLedgerDto) {
        return AjaxResult.success(invoiceLedgerService.invoiceLedgerSalesAccount(page,invoiceLedgerDto));
    public R<?> invoiceLedgerSalesAccount(Page page, InvoiceLedgerDto invoiceLedgerDto) {
        return R.ok(invoiceLedgerService.invoiceLedgerSalesAccount(page,invoiceLedgerDto));
    }
    /**
     * æœ¬æœˆå¼€ç¥¨é‡‘额
     */
    @GetMapping("/getInvoiceAmount")
    public AjaxResult getInvoiceAmount() {
    public R<?> getInvoiceAmount() {
        try {
            BigDecimal amount = invoiceLedgerService.getInvoiceAmount();
            return AjaxResult.success(amount != null ? amount : BigDecimal.ZERO);
            return R.ok(amount != null ? amount : BigDecimal.ZERO);
        } catch (Exception e) {
            return AjaxResult.error("获取开票金额失败:" + e.getMessage());
            return R.fail("获取开票金额失败:" + e.getMessage());
        }
    }
@@ -172,9 +173,9 @@
     * @return
     */
    @GetMapping("/registrationProductPage")
    public AjaxResult registrationProductPage(Page page, InvoiceRegistrationProductDto registrationProductDto) {
    public R<?> registrationProductPage(Page page, InvoiceRegistrationProductDto registrationProductDto) {
        return AjaxResult.success(invoiceLedgerService.registrationProductPage(page,registrationProductDto));
        return R.ok(invoiceLedgerService.registrationProductPage(page,registrationProductDto));
    }
    /**
@@ -183,8 +184,8 @@
     * @return
     */
    @GetMapping("/invoiceLedgerProductInfo")
    public AjaxResult invoiceLedgerProductDetail(Integer id) {
        return AjaxResult.success(invoiceLedgerService.invoiceLedgerProductDetail(id));
    public R<?> invoiceLedgerProductDetail(Integer id) {
        return R.ok(invoiceLedgerService.invoiceLedgerProductDetail(id));
    }
    /**
@@ -193,12 +194,12 @@
     * @return
     */
    @DeleteMapping("delInvoiceLedger/{invoiceRegistrationProductId}")
    public AjaxResult delInvoiceLedger(@PathVariable Integer invoiceRegistrationProductId) {
    public R<?> delInvoiceLedger(@PathVariable Integer invoiceRegistrationProductId) {
        try {
            invoiceLedgerService.delInvoiceLedger(invoiceRegistrationProductId);
            return AjaxResult.success();
            return R.ok();
        }catch (Exception e) {
            return AjaxResult.error(e.getMessage());
            return R.fail(e.getMessage());
        }
    }
src/main/java/com/ruoyi/sales/controller/InvoiceRegistrationController.java
@@ -2,7 +2,8 @@
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.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.sales.dto.InvoiceRegistrationDto;
import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
import com.ruoyi.sales.dto.SalesLedgerDto;
@@ -18,7 +19,7 @@
@RestController
@RequestMapping("/invoiceRegistration")
@AllArgsConstructor
public class InvoiceRegistrationController {
public class InvoiceRegistrationController extends BaseController {
    private InvoiceRegistrationService invoiceRegistrationService;
@@ -30,13 +31,13 @@
    @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("请选择要保存的记录");
    public R<?> invoiceRegistrationSave(@RequestBody List<SalesLedgerDto> salesLedgerDto) {
        if(Collections.isEmpty(salesLedgerDto)) return R.fail("请选择要保存的记录");
        salesLedgerDto.forEach(item ->{
            invoiceRegistrationService.invoiceRegistrationSave(item);
        });
        return AjaxResult.success();
        return R.ok();
    }
    /**
@@ -45,9 +46,9 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult invoiceRegistrationDel(@RequestBody  List<Integer> ids) {
    public R<?> invoiceRegistrationDel(@RequestBody  List<Integer> ids) {
        invoiceRegistrationService.invoiceRegistrationDel(ids);
        return AjaxResult.success();
        return R.ok();
    }
    /**
@@ -56,9 +57,9 @@
     * @return
     */
    @PostMapping("/update")
    public AjaxResult invoiceRegistrationUpdate(@RequestBody InvoiceRegistrationDto invoiceRegistrationDto) {
    public R<?> invoiceRegistrationUpdate(@RequestBody InvoiceRegistrationDto invoiceRegistrationDto) {
        invoiceRegistrationService.invoiceRegistrationUpdate(invoiceRegistrationDto);
        return AjaxResult.success();
        return R.ok();
    }
    /**
@@ -68,8 +69,8 @@
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult invoiceRegistrationListPage(Page page, InvoiceRegistrationDto invoiceRegistrationDto) {
        return AjaxResult.success(invoiceRegistrationService.invoiceRegistrationListPage(page, invoiceRegistrationDto));
    public R<?> invoiceRegistrationListPage(Page page, InvoiceRegistrationDto invoiceRegistrationDto) {
        return R.ok(invoiceRegistrationService.invoiceRegistrationListPage(page, invoiceRegistrationDto));
    }
    /**
@@ -78,8 +79,8 @@
     * @return
     */
    @GetMapping("/productList")
    public AjaxResult invoiceRegistrationProductList(InvoiceRegistrationProductDto invoiceRegistrationProductDto) {
        return AjaxResult.success(invoiceRegistrationService.invoiceRegistrationProductList(invoiceRegistrationProductDto));
    public R<?> invoiceRegistrationProductList(InvoiceRegistrationProductDto invoiceRegistrationProductDto) {
        return R.ok(invoiceRegistrationService.invoiceRegistrationProductList(invoiceRegistrationProductDto));
    }
    /**
@@ -88,8 +89,8 @@
     * @return
     */
    @GetMapping("/detail")
    public AjaxResult invoiceRegistrationDetail(Integer id) {
        return AjaxResult.success(invoiceRegistrationService.invoiceRegistrationDetail(id));
    public R<?> invoiceRegistrationDetail(Integer id) {
        return R.ok(invoiceRegistrationService.invoiceRegistrationDetail(id));
    }
    /**
src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java
@@ -1,7 +1,7 @@
package com.ruoyi.sales.controller;
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;
@@ -25,13 +25,13 @@
    @Operation(summary = "头部总计")
    @GetMapping("/total")
    public AjaxResult total() {
    public R<?> total() {
        return metricStatisticsService.total();
    }
    @Operation(summary = "统计表")
    @GetMapping("/statisticsTable")
    public AjaxResult statisticsTable(StatisticsTableDto statisticsTableDto) {
    public R<?> statisticsTable(StatisticsTableDto statisticsTableDto) {
        return metricStatisticsService.statisticsTable(statisticsTableDto);
    }
src/main/java/com/ruoyi/sales/controller/PaymentShippingController.java
@@ -5,7 +5,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.OrderUtils;
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.mapper.PaymentShippingMapper;
import com.ruoyi.sales.pojo.PaymentShipping;
import com.ruoyi.sales.service.PaymentShippingService;
@@ -32,37 +32,37 @@
    @GetMapping("/listPage")
    @Operation(summary = "分页查询支付与发货信息")
    public AjaxResult listPage(Page page, PaymentShipping paymentShipping) {
    public R<?> listPage(Page page, PaymentShipping paymentShipping) {
        IPage<PaymentShipping> listPage = paymentShippingService.listPage(page, paymentShipping);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @PostMapping("/add")
    @Operation(summary = "添加支付与发货信息")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody PaymentShipping paymentShipping) {
    public R<?> add(@RequestBody PaymentShipping paymentShipping) {
        String ord = OrderUtils.countTodayByCreateTime(paymentShippingMapper, "ORD","order_no");
        paymentShipping.setOrderNo(ord);
        boolean save = paymentShippingService.save(paymentShipping);
        return save ? success() : error();
        return save ? R.ok() : R.fail();
    }
    @PostMapping("/update")
    @Operation(summary = "修改支付与发货信息")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult update(@RequestBody PaymentShipping paymentShipping) {
    public R<?> update(@RequestBody PaymentShipping paymentShipping) {
        boolean update = paymentShippingService.updateById(paymentShipping);
        return update ? success() : error();
        return update ? R.ok() : R.fail();
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除支付与发货信息")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delete(@RequestBody List<Long> ids){
    public R<?> delete(@RequestBody List<Long> ids){
        if (CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请传入要删除的ID");
            return R.fail("请传入要删除的ID");
        }
        return AjaxResult.success(paymentShippingService.removeByIds(ids));
        return R.ok(paymentShippingService.removeByIds(ids));
    }
}
src/main/java/com/ruoyi/sales/controller/ReceiptPaymentController.java
@@ -7,7 +7,7 @@
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.framework.web.page.TableDataInfo;
import com.ruoyi.sales.dto.InvoiceLedgerDto;
import com.ruoyi.sales.dto.ReceiptPaymentDto;
@@ -39,9 +39,9 @@
     * @return
     */
    @PostMapping("/saveOrUpdate")
    public AjaxResult receiptPaymentSaveOrUpdate (@RequestBody List<ReceiptPayment> receiptPayment) {
    public R<?> receiptPaymentSaveOrUpdate (@RequestBody List<ReceiptPayment> receiptPayment) {
        receiptPaymentService.receiptPaymentSaveOrUpdate(receiptPayment);
        return AjaxResult.success();
        return R.ok();
    }
    /**
@@ -51,8 +51,8 @@
     */
    @PostMapping("/update")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult receiptPaymentUpdate (@RequestBody ReceiptPayment receiptPayment) {
        return AjaxResult.success(receiptPaymentService.receiptPaymentUpdate(receiptPayment));
    public R<?> receiptPaymentUpdate (@RequestBody ReceiptPayment receiptPayment) {
        return R.ok(receiptPaymentService.receiptPaymentUpdate(receiptPayment));
    }
    /**
@@ -62,8 +62,8 @@
     */
    @DeleteMapping("/del")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult receiptPaymentDel (@RequestBody List<Integer> ids) {
        return AjaxResult.success(receiptPaymentService.receiptPaymentDel(ids));
    public R<?> receiptPaymentDel (@RequestBody List<Integer> ids) {
        return R.ok(receiptPaymentService.receiptPaymentDel(ids));
    }
    /**
@@ -72,8 +72,8 @@
     * @return
     */
    @GetMapping("/customerInteractions")
    public AjaxResult customerInteractions (InvoiceLedgerDto receiptPaymentDto) {
        return AjaxResult.success(receiptPaymentService.customerInteractions(receiptPaymentDto));
    public R<?> customerInteractions (InvoiceLedgerDto receiptPaymentDto) {
        return R.ok(receiptPaymentService.customerInteractions(receiptPaymentDto));
    }
    /**
@@ -82,20 +82,20 @@
     * @return
     */
    @GetMapping("/info")
    public AjaxResult receiptPaymentInfo (Integer id) {
        return AjaxResult.success(receiptPaymentService.receiptPaymentInfo(id));
    public R<?> receiptPaymentInfo (Integer id) {
        return R.ok(receiptPaymentService.receiptPaymentInfo(id));
    }
    /**
     * æœ¬æœˆå›žæ¬¾é‡‘额
     */
    @GetMapping("/getReceiptAmount")
    public AjaxResult getReceiptAmount() {
    public R<?> getReceiptAmount() {
        try {
            BigDecimal receiptAmount = receiptPaymentService.getReceiptAmount();
            return AjaxResult.success(receiptAmount != null ? receiptAmount : BigDecimal.ZERO);
            return R.ok(receiptAmount != null ? receiptAmount : BigDecimal.ZERO);
        } catch (Exception e) {
            return AjaxResult.error("获取回款金额失败:" + e.getMessage());
            return R.fail("获取回款金额失败:" + e.getMessage());
        }
    }
@@ -106,8 +106,8 @@
     * @return
     */
    @GetMapping("/bindInvoiceNoRegPage")
    public AjaxResult bindInvoiceNoRegPage(Page page, ReceiptPaymentDto receiptPaymentDto) {
        return AjaxResult.success(receiptPaymentService.bindInvoiceNoRegPage(page,receiptPaymentDto));
    public R<?> bindInvoiceNoRegPage(Page page, ReceiptPaymentDto receiptPaymentDto) {
        return R.ok(receiptPaymentService.bindInvoiceNoRegPage(page,receiptPaymentDto));
    }
    @Schema(description = "导出回款登记")
@@ -131,16 +131,16 @@
     * @return
     */
    @GetMapping("/invoiceInfo")
    public AjaxResult invoiceInfo (Integer id) {
        return AjaxResult.success(receiptPaymentService.invoiceInfo(id));
    public R<?> invoiceInfo (Integer id) {
        return R.ok(receiptPaymentService.invoiceInfo(id));
    }
    /**
     * æœ¬æœˆåº”æ”¶,回款金额
     */
    @GetMapping("/getAmountMouth")
    public AjaxResult getAmountMouth() {
        return  AjaxResult.success(receiptPaymentService.getAmountMouth());
    public R<?> getAmountMouth() {
        return  R.ok(receiptPaymentService.getAmountMouth());
    }
    /**
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
@@ -10,7 +10,6 @@
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.framework.web.page.TableDataInfo;
import com.ruoyi.sales.dto.InvoiceLedgerDto;
@@ -67,7 +66,7 @@
    @Log(title = "导入销售台账", businessType = BusinessType.INSERT)
    @PostMapping("/import")
    @Operation(summary = "导入销售台账")
    public AjaxResult importData(@RequestParam("file")
    public R<?> importData(@RequestParam("file")
                                 @ApiParam(value = "Excel文件", required = true)
                                 MultipartFile file) {
        return salesLedgerService.importData(file);
@@ -183,8 +182,9 @@
     */
    @Log(title = "销售台账", businessType = BusinessType.INSERT)
    @PostMapping("/addOrUpdateSalesLedger")
    public AjaxResult add(@RequestBody SalesLedgerDto salesLedgerDto) {
        return toAjax(salesLedgerService.addOrUpdateSalesLedger(salesLedgerDto));
    public R<?> add(@RequestBody SalesLedgerDto salesLedgerDto) {
        salesLedgerService.addOrUpdateSalesLedger(salesLedgerDto);
        return R.ok();
    }
    /**
@@ -192,11 +192,12 @@
     */
    @Log(title = "销售台账", businessType = BusinessType.DELETE)
    @DeleteMapping("/delLedger")
    public AjaxResult remove(@RequestBody Long[] ids) {
    public R<?> remove(@RequestBody Long[] ids) {
        if (ids == null || ids.length == 0) {
            return AjaxResult.error("请传入要删除的ID");
            return R.fail("请传入要删除的ID");
        }
        return toAjax(salesLedgerService.deleteSalesLedgerByIds(ids));
        salesLedgerService.deleteSalesLedgerByIds(ids);
        return R.ok();
    }
    /**
@@ -206,9 +207,9 @@
     * @return
     */
    @GetMapping("/listNoPage")
    public AjaxResult listNoPage(SalesLedgerDto salesLedgerDto) {
    public R<?> listNoPage(SalesLedgerDto salesLedgerDto) {
        List<SalesLedger> list = salesLedgerService.selectSalesLedgerList(salesLedgerDto);
        return AjaxResult.success(list);
        return R.ok(list);
    }
    /**
@@ -216,23 +217,24 @@
     */
    @Log(title = "销售台账附件删除", businessType = BusinessType.DELETE)
    @DeleteMapping("/delLedgerFile")
    public AjaxResult delLedgerFile(@RequestBody Long[] ids) {
    public R<?> delLedgerFile(@RequestBody Long[] ids) {
        if (ids == null || ids.length == 0) {
            return AjaxResult.error("请传入要删除的ID");
            return R.fail("请传入要删除的ID");
        }
        return toAjax(commonFileService.deleteSalesLedgerByIds(ids));
        commonFileService.deleteSalesLedgerByIds(ids);
        return R.ok();
    }
    /**
     * æœ¬æœˆé”€å”®åˆåŒé‡‘额
     */
    @GetMapping("/getContractAmount")
    public AjaxResult getContractAmount() {
    public R<?> getContractAmount() {
        try {
            BigDecimal contractAmount = salesLedgerService.getContractAmount();
            return AjaxResult.success(contractAmount != null ? contractAmount : BigDecimal.ZERO);
            return R.ok(contractAmount != null ? contractAmount : BigDecimal.ZERO);
        } catch (Exception e) {
            return AjaxResult.error("获取合同金额失败:" + e.getMessage());
            return R.fail("获取合同金额失败:" + e.getMessage());
        }
    }
@@ -240,16 +242,16 @@
     * å®¢æˆ·åˆåŒé‡‘额TOP5统计
     */
    @GetMapping("/getTopFiveList")
    public AjaxResult getTopFiveList() {
        return AjaxResult.success(salesLedgerService.getTopFiveList());
    public R<?> getTopFiveList() {
        return R.ok(salesLedgerService.getTopFiveList());
    }
    /**
     * è¿‘半年开票,回款金额
     */
    @GetMapping("/getAmountHalfYear")
    public AjaxResult getAmountHalfYear(@RequestParam(value = "type",defaultValue = "1") Integer type) {
        return AjaxResult.success(salesLedgerService.getAmountHalfYear(type));
    public R<?> getAmountHalfYear(@RequestParam(value = "type",defaultValue = "1") Integer type) {
        return R.ok(salesLedgerService.getAmountHalfYear(type));
    }
    /**
src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
@@ -7,7 +7,6 @@
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.procurementrecord.service.ProcurementRecordService;
import com.ruoyi.procurementrecord.utils.StockUtils;
@@ -46,9 +45,9 @@
     * å›žæ¬¾ç™»è®°åˆ†é¡µæŸ¥è¯¢
     */
    @GetMapping("/listPageSalesLedger")
    public AjaxResult listPage(Page page, SalesLedgerProductDto salesLedgerProduct) {
    public R<?> listPageSalesLedger(Page page, SalesLedgerProductDto salesLedgerProduct) {
        IPage<SalesLedgerProductDto> list = salesLedgerProductService.listPage(page,salesLedgerProduct);
        return AjaxResult.success(list);
        return R.ok(list);
    }
@@ -56,9 +55,9 @@
     * ä»˜æ¬¾ç™»è®°åˆ†é¡µæŸ¥è¯¢
     */
    @GetMapping("/listPagePurchaseLedger")
    public AjaxResult listPagePurchaseLedger(Page page, SalesLedgerProductDto salesLedgerProduct) {
    public R<?> listPagePurchaseLedger(Page page, SalesLedgerProductDto salesLedgerProduct) {
        IPage<SalesLedgerProductDto> list = salesLedgerProductService.listPagePurchaseLedger(page,salesLedgerProduct);
        return AjaxResult.success(list);
        return R.ok(list);
    }
@@ -66,10 +65,10 @@
     * æŸ¥è¯¢äº§å“ä¿¡æ¯åˆ—表
     */
    @GetMapping("/list")
    public AjaxResult list(SalesLedgerProduct salesLedgerProduct) {
    public R<?> list(SalesLedgerProduct salesLedgerProduct) {
        List<SalesLedgerProduct> list = salesLedgerProductService.selectSalesLedgerProductList(salesLedgerProduct);
        if (CollUtil.isEmpty(list)) {
            return AjaxResult.success(list);
            return R.ok(list);
        }
        List<Long> productIds = list.stream().map(SalesLedgerProduct::getProductModelId).collect(Collectors.toList());
        List<SimpleReturnOrderGroupDto> groupListByProductIds = purchaseReturnOrderProductsMapper.getReturnOrderGroupListByProductIds(productIds);
@@ -94,7 +93,7 @@
            item.setReturnQuality(returnQuality);
            item.setAvailableQuality(item.getQuantity().subtract(returnQuality));
        });
        return AjaxResult.success(list);
        return R.ok(list);
    }
    /**
@@ -113,9 +112,9 @@
     * èŽ·å–äº§å“ä¿¡æ¯è¯¦ç»†ä¿¡æ¯
     */
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id)
    public R<?> getInfo(@PathVariable("id") Long id)
    {
        return success(salesLedgerProductService.selectSalesLedgerProductById(id));
        return R.ok(salesLedgerProductService.selectSalesLedgerProductById(id));
    }
    /**
@@ -123,9 +122,10 @@
     */
    @Log(title = "产品信息", businessType = BusinessType.INSERT)
    @PostMapping  ("/addOrUpdateSalesLedgerProduct")
    public AjaxResult add(@RequestBody SalesLedgerProduct salesLedgerProduct)
    public R<?> add(@RequestBody SalesLedgerProduct salesLedgerProduct)
    {
        return toAjax(salesLedgerProductService.addOrUpdateSalesLedgerProduct(salesLedgerProduct));
        salesLedgerProductService.addOrUpdateSalesLedgerProduct(salesLedgerProduct);
        return R.ok();
    }
    /**
@@ -133,12 +133,13 @@
     */
    @Log(title = "产品信息", businessType = BusinessType.DELETE)
    @DeleteMapping("/delProduct")
    public AjaxResult remove(@RequestBody Long[] ids)
    public R<?> remove(@RequestBody Long[] ids)
    {
        if (ids == null || ids.length == 0) {
            return AjaxResult.error("请传入要删除的ID");
            return R.fail("请传入要删除的ID");
        }
        return toAjax(salesLedgerProductService.deleteSalesLedgerProductByIds(ids));
        salesLedgerProductService.deleteSalesLedgerProductByIds(ids);
        return R.ok();
    }
    //根据产品id获取bom判断库存是否充足
src/main/java/com/ruoyi/sales/controller/SalesQuotationController.java
@@ -3,7 +3,8 @@
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.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.sales.dto.SalesQuotationDto;
import com.ruoyi.sales.service.SalesQuotationService;
import jakarta.servlet.http.HttpServletResponse;
@@ -13,11 +14,11 @@
@RestController
@RequestMapping("/sales/quotation")
@AllArgsConstructor
public class SalesQuotationController {
public class SalesQuotationController extends BaseController {
    private final SalesQuotationService salesQuotationService;
    @GetMapping("/list")
    public AjaxResult getList(Page page, SalesQuotationDto salesQuotationDto) {
        return AjaxResult.success(salesQuotationService.listPage(page, salesQuotationDto));
    public R<?> getList(Page page, SalesQuotationDto salesQuotationDto) {
        return R.ok(salesQuotationService.listPage(page, salesQuotationDto));
    }
@@ -32,15 +33,15 @@
    @PostMapping("/add")
    public AjaxResult add(@RequestBody SalesQuotationDto salesQuotationDto) {
        return AjaxResult.success(salesQuotationService.add(salesQuotationDto));
    public R<?> add(@RequestBody SalesQuotationDto salesQuotationDto) {
        return R.ok(salesQuotationService.add(salesQuotationDto));
    }
    @PostMapping("/update")
    public AjaxResult update(@RequestBody SalesQuotationDto salesQuotationDto) {
        return AjaxResult.success(salesQuotationService.edit(salesQuotationDto));
    public R<?> update(@RequestBody SalesQuotationDto salesQuotationDto) {
        return R.ok(salesQuotationService.edit(salesQuotationDto));
    }
    @DeleteMapping("/delete")
    public AjaxResult delete(@RequestBody Long id) {
        return AjaxResult.success(salesQuotationService.delete(id));
    public R<?> delete(@RequestBody Long id) {
        return R.ok(salesQuotationService.delete(id));
    }
}
src/main/java/com/ruoyi/sales/controller/SalespersonManagementController.java
@@ -3,7 +3,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.pojo.SalespersonManagement;
import com.ruoyi.sales.service.SalespersonManagementService;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -28,36 +28,36 @@
    @GetMapping("/listPage")
    @Operation(summary = "分页查询业务员信息")
    public AjaxResult listPage(Page page, SalespersonManagement salespersonManagement) {
    public R<?> listPage(Page page, SalespersonManagement salespersonManagement) {
        IPage<SalespersonManagement> listPage = salespersonManagementService.listPage(page, salespersonManagement);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @PostMapping("/add")
    @Operation(summary = "添加业务员信息")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody SalespersonManagement salespersonManagement) {
    public R<?> add(@RequestBody SalespersonManagement salespersonManagement) {
        boolean save = salespersonManagementService.save(salespersonManagement);
        return save ? AjaxResult.success() : AjaxResult.error();
        return save ? R.ok() : R.fail();
    }
    @PostMapping("/update")
    @Operation(summary = "修改业务员信息")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult update(@RequestBody SalespersonManagement salespersonManagement) {
    public R<?> update(@RequestBody SalespersonManagement salespersonManagement) {
        boolean update = salespersonManagementService.updateById(salespersonManagement);
        return update ? AjaxResult.success() : AjaxResult.error();
        return update ? R.ok() : R.fail();
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除业务员信息")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delete(@RequestBody List<Long> ids) {
    public R<?> delete(@RequestBody List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return AjaxResult.error("请传入要删除的ID");
            return R.fail("请传入要删除的ID");
        }
        boolean delete = salespersonManagementService.removeByIds(ids);
        return delete ? AjaxResult.success() : AjaxResult.error();
        return delete ? R.ok() : R.fail();
    }
}
src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java
@@ -11,7 +11,6 @@
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
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.domain.R;
import com.ruoyi.sales.dto.ShippingInfoDto;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
@@ -45,16 +44,16 @@
    @GetMapping("/listPage")
    @Operation(summary = "发货信息列表")
    public AjaxResult listPage(Page page, ShippingInfo req) {
    public R<?> listPage(Page page, ShippingInfo req) {
        IPage<ShippingInfoDto> listPage = shippingInfoService.listPage(page,req);
        return AjaxResult.success(listPage);
        return R.ok(listPage);
    }
    @PostMapping("/add")
    @Operation(summary = "添加发货信息")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "发货信息管理", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody ShippingInfoDto req) throws Exception {
    public R<?> add(@RequestBody ShippingInfoDto req) throws Exception {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String sh = OrderUtils.countTodayByCreateTime(shippingInfoMapper, "SH","shipping_no");
        // å‘货审批
@@ -70,37 +69,37 @@
        req.setShippingNo(sh);
        req.setStatus("待审核");
        boolean save = shippingInfoService.add(req);
        return save ? AjaxResult.success() : AjaxResult.error();
        return save ? R.ok() : R.fail();
    }
    @Operation(summary = "发货扣库存")
    @PostMapping("/deductStock")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "发货信息管理", businessType = BusinessType.UPDATE)
    public AjaxResult deductStock(@RequestBody ShippingInfoDto req) throws IOException {
        return shippingInfoService.deductStock( req) ? AjaxResult.success() : AjaxResult.error();
    public R<?> deductStock(@RequestBody ShippingInfoDto req) throws IOException {
        return shippingInfoService.deductStock( req) ? R.ok() : R.fail();
    }
    @PostMapping("/update")
    @Operation(summary = "修改发货信息")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "发货信息管理", businessType = BusinessType.UPDATE)
    public AjaxResult update(@RequestBody ShippingInfo req) {
    public R<?> update(@RequestBody ShippingInfo req) {
        ShippingInfo byId = shippingInfoService.getById(req.getId());
        if (byId == null) {
            return AjaxResult.error("发货信息不存在");
            return R.fail("发货信息不存在");
        }
        boolean update = shippingInfoService.updateById(req);
        return update ? AjaxResult.success() : AjaxResult.error();
        return update ? R.ok() : R.fail();
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除发货信息")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "发货信息管理", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
    public R<?> delete(@RequestBody List<Long> ids) {
        return shippingInfoService.delete(ids) ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
        return shippingInfoService.delete(ids) ? R.ok("删除成功") : R.fail("删除失败");
    }
    /**
@@ -117,8 +116,8 @@
    @GetMapping("/getByCustomerName")
    @Operation(summary = "通过客户名称查询关联的发货单号")
    public AjaxResult getByCustomerName(String customerName) {
        return AjaxResult.success(shippingInfoService.getShippingInfoByCustomerName(customerName));
    public R<?> getByCustomerName(String customerName) {
        return R.ok(shippingInfoService.getShippingInfoByCustomerName(customerName));
    }
    @GetMapping("/getDateil/{id}")
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;
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;
}
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
@@ -5,7 +5,7 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.aftersalesservice.pojo.AfterSalesService;
import com.ruoyi.common.enums.SaleEnum;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.sales.dto.LossProductModelDto;
import com.ruoyi.sales.dto.MonthlyAmountDto;
import com.ruoyi.sales.dto.SalesLedgerDto;
@@ -50,7 +50,7 @@
    IPage<SalesLedgerVo> selectSalesLedgerListPage(Page page, SalesLedgerDto salesLedgerDto);
    AjaxResult importData(MultipartFile file);
    R<?> importData(MultipartFile file);
    List<LossProductModelDto> getSalesLedgerWithProductsLoss(Long salesLedgerId);
src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java
@@ -2,7 +2,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.sales.dto.SalesTrendDto;
import com.ruoyi.sales.dto.StatisticsTableDto;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
@@ -32,9 +32,9 @@
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    private final ShippingInfoMapper shippingInfoMapper;
    public AjaxResult total() {
    public R<?> total() {
        List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(null);
        if(CollectionUtils.isEmpty(salesLedgers)) return AjaxResult.success(salesLedgers);
        if(CollectionUtils.isEmpty(salesLedgers)) return R.ok(salesLedgers);
        Map<String, Object> map = new HashMap<>();
        // é”€å”®é¢
        map.put("contractAmountTotal", salesLedgers.stream().map(SalesLedger::getContractAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
@@ -44,16 +44,16 @@
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
                .eq(SalesLedgerProduct::getType, 1));
        map.put("shipRate", "0%");
        if(CollectionUtils.isEmpty(salesLedgerProducts)) return AjaxResult.success(map);
        if(CollectionUtils.isEmpty(salesLedgerProducts)) return R.ok(map);
        // å‘货数量
        long count = shippingInfoMapper.selectCount(new LambdaQueryWrapper<ShippingInfo>()
                .in(ShippingInfo::getSalesLedgerProductId, salesLedgerProducts.stream().map(SalesLedgerProduct::getId).collect(Collectors.toList()))
                .eq(ShippingInfo::getStatus,"已发货"));
        map.put("shipRate", String.format("%.2f", count * 100.0 / salesLedgerProducts.size()) + "%");
        return AjaxResult.success(map);
        return R.ok(map);
    }
    public AjaxResult statisticsTable(StatisticsTableDto statisticsTableDto) {
    public R<?> statisticsTable(StatisticsTableDto statisticsTableDto) {
        Map<String, Object> map = new HashMap<>();
        Calendar calendar = Calendar.getInstance();
@@ -123,6 +123,6 @@
        map.put("orderCountList", orderCountList);
        map.put("salesAmountList", salesAmountList);
        map.put("shippingRateList", shippingRateList);
        return AjaxResult.success(map);
        return R.ok(map);
    }
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -285,6 +285,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())));
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -1,6 +1,7 @@
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.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
@@ -25,10 +26,11 @@
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.other.mapper.TempFileMapper;
import com.ruoyi.other.pojo.TempFile;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.mapper.ProductionProductInputMapper;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.mapper.ProductionProductOutputMapper;
import com.ruoyi.production.service.ProductionProductMainService;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysUser;
@@ -44,7 +46,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 +56,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;
@@ -335,21 +331,29 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult importData(MultipartFile file) {
    public R<?> importData(MultipartFile file) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        try {
            InputStream inputStream = file.getInputStream();
            ExcelUtil<SalesLedgerImportDto> salesLedgerImportDtoExcelUtil = new ExcelUtil<>(SalesLedgerImportDto.class);
            Map<String, List<SalesLedgerImportDto>> stringListMap = salesLedgerImportDtoExcelUtil.importExcelMultiSheet(Arrays.asList("销售台账数据", "销售产品数据"), inputStream, 0);
            if (CollectionUtils.isEmpty(stringListMap)) return AjaxResult.error("销售表格为空!");
            if (CollectionUtils.isEmpty(stringListMap)) return R.fail("销售表格为空!");
            // ä¸šåŠ¡å±‚åˆå¹¶
            List<SalesLedgerImportDto> salesLedgerImportDtoList = stringListMap.get("销售台账数据");
            if (CollectionUtils.isEmpty(salesLedgerImportDtoList)) return AjaxResult.error("销售台账数据为空!");
            if (CollectionUtils.isEmpty(salesLedgerImportDtoList)) return R.fail("销售台账数据为空!");
            List<SalesLedgerImportDto> salesLedgerProductImportDtoList = stringListMap.get("销售产品数据");
            if (CollectionUtils.isEmpty(salesLedgerProductImportDtoList)) return AjaxResult.error("销售产品数据为空!");
            // å®¢æˆ·æ•°æ®
            List<Customer> customers = customerMapper.selectList(new LambdaQueryWrapper<Customer>().in(Customer::getCustomerName,
                    salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getCustomerName).collect(Collectors.toList())));
            if (CollectionUtils.isEmpty(salesLedgerProductImportDtoList)) return R.fail("销售产品数据为空!");
            // å®¢æˆ·æ•°æ® - å‚考 listPage æŸ¥è¯¢ç§æµ·å®¢æˆ·ï¼ˆtype = 0)
            // type = 0(私海客户)或者 type = 1(公海客户)且已被分配,并且是自己领用、自己创建或者共享给自己的客户
            Long loginUserId = loginUser.getUser().getUserId();
            List<Customer> customers = customerMapper.selectList(new QueryWrapper<Customer>()
                    .in("customer_name", salesLedgerImportDtoList.stream()
                            .map(SalesLedgerImportDto::getCustomerName).collect(Collectors.toList()))
                    .and(wrapper -> wrapper.eq("type", 0)
                            .or(wrapper2 -> wrapper2.eq("type", 1).eq("is_assigned", 1)))
                    .and(wrapper -> wrapper.eq("usage_user", loginUserId)
                            .or(wrapper2 -> wrapper2.eq("create_user", loginUserId)
                                    .or(wrapper3 -> wrapper3.exists("select 1 from customer_user cu where cu.customer_id = customer.id and cu.user_id = " + loginUserId)))));
//            // è§„格型号数据
//            List<ProductModel> productModels = productModelMapper.selectList(new LambdaQueryWrapper<ProductModel>().in(ProductModel::getModel,
//                    salesLedgerProductImportDtoList.stream().map(SalesLedgerImportDto::getSpecificationModel).collect(Collectors.toList())));
@@ -370,17 +374,16 @@
                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()
                Optional<Customer> customerOptional = customers.stream()
                        .filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName()))
                        .findFirst()
                        .map(Customer::getId)
                        .orElse(null));
                salesLedger.setCustomerContractNo(customers.stream()
                        .filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName()))
                        .findFirst()
                        .map(Customer::getTaxpayerIdentificationNumber)
                        .orElse(null));
                        .findFirst();
                if (customerOptional.isEmpty()) {
                    throw new RuntimeException("客户:" + salesLedger.getCustomerName() + "不存在!或者非私海用户");
                }
                salesLedger.setCustomerId(customerOptional.get().getId());
                salesLedger.setCustomerContractNo(customerOptional.get().getTaxpayerIdentificationNumber());
                Long aLong = sysUsers.stream()
                        .filter(sysUser -> sysUser.getNickName().equals(salesLedger.getEntryPerson()))
                        .findFirst()
@@ -410,13 +413,16 @@
                    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()))
                            .findFirst()
                            .ifPresent(map -> {
                                salesLedgerProduct.setProductModelId(Long.parseLong(map.get("modelId").toString()));
                                salesLedgerProduct.setProductId(Long.parseLong(map.get("id").toString()));
                            });
                    // æ ¡éªŒäº§å“è§„格是否存在
                    Optional<Map<String, Object>> productModelOptional = list.stream()
                            .filter(map -> Objects.equals(map.get("productName"), salesLedgerProduct.getProductCategory()) && Objects.equals(map.get("model"), salesLedgerProduct.getSpecificationModel()))
                            .findFirst();
                    if (productModelOptional.isEmpty()) {
                        throw new RuntimeException("产品大类:" + salesLedgerProduct.getProductCategory() + ",规格型号:" + salesLedgerProduct.getSpecificationModel() + "不存在!");
                    }
                    Map<String, Object> productModelMap = productModelOptional.get();
                    salesLedgerProduct.setProductModelId(Long.parseLong(productModelMap.get("modelId").toString()));
                    salesLedgerProduct.setProductId(Long.parseLong(productModelMap.get("id").toString()));
//                    salesLedgerProduct.setProductId(productList.stream()
//                            .filter(product -> product.getProductName().equals(salesLedgerProduct.getProductCategory()))
//                            .findFirst()
@@ -431,17 +437,18 @@
                    salesLedgerProduct.setRegisterDate(LocalDateTime.now());
                    salesLedgerProduct.setApproveStatus(0);
                    salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProductImportDto.getTaxInclusiveTotalPrice());
                    salesLedgerProduct.setIsProduction(salesLedgerProductImportDto.getIsProduction() == 1);
                    salesLedgerProductMapper.insert(salesLedgerProduct);
                    // æ·»åŠ ç”Ÿäº§æ•°æ®
                    salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct);
                }
            }
            return AjaxResult.success("导入成功");
            return R.ok(null, "导入成功");
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("导入失败:" + e.getMessage());
        }
        return AjaxResult.success("导入失败");
    }
    @Override
@@ -599,7 +606,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 {
src/main/java/com/ruoyi/staff/controller/AnalyticsController.java
@@ -1,6 +1,7 @@
package com.ruoyi.staff.controller;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.staff.service.AnalyticsService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -10,23 +11,23 @@
@RestController
@RequestMapping("/staff/analytics")
public class AnalyticsController {
public class AnalyticsController extends BaseController {
    @Resource
    private AnalyticsService analyticsService;
    @GetMapping("/reason")
    public AjaxResult staffLeaveReasonAnalytics() {
        return AjaxResult.success(analyticsService.staffLeaveReasonAnalytics());
    public R<?> staffLeaveReasonAnalytics() {
        return R.ok(analyticsService.staffLeaveReasonAnalytics());
    }
    @GetMapping("/monthly_turnover_rate")
    public AjaxResult getMonthlyTurnoverRateFor12Months() {
        return AjaxResult.success(analyticsService.getMonthlyTurnoverRateFor12Months());
    public R<?> getMonthlyTurnoverRateFor12Months() {
        return R.ok(analyticsService.getMonthlyTurnoverRateFor12Months());
    }
    @GetMapping("/total_statistic")
    public AjaxResult getTotalStatistic() {
        return AjaxResult.success(analyticsService.getTotalStatistic());
    public R<?> getTotalStatistic() {
        return R.ok(analyticsService.getTotalStatistic());
    }
}
src/main/java/com/ruoyi/staff/controller/BankController.java
@@ -2,7 +2,8 @@
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.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.staff.pojo.Bank;
import com.ruoyi.staff.service.BankService;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -25,37 +26,37 @@
@RestController
@RequestMapping("/bank")
@AllArgsConstructor
public class BankController {
public class BankController extends BaseController {
    private BankService bankService;
    @GetMapping("/list")
    public AjaxResult list() {
        return AjaxResult.success(bankService.list());
    public R<?> list() {
        return R.ok(bankService.list());
    }
    @PostMapping("/add")
    @Operation(summary = "新增银行管理表")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "银行管理表", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody Bank bank) {
        return AjaxResult.success(bankService.save(bank));
    public R<?> add(@RequestBody Bank bank) {
        return R.ok(bankService.save(bank));
    }
    @PostMapping("/update")
    @Operation(summary = "更新银行管理表")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "银行管理表", businessType = BusinessType.UPDATE)
    public AjaxResult update(@RequestBody Bank bank) {
        return AjaxResult.success(bankService.updateById(bank));
    public R<?> update(@RequestBody Bank bank) {
        return R.ok(bankService.updateById(bank));
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除银行管理表")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "银行管理表", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
        return AjaxResult.success(bankService.removeBatchByIds(ids));
    public R<?> delete(@RequestBody List<Long> ids) {
        return R.ok(bankService.removeBatchByIds(ids));
    }
}
src/main/java/com/ruoyi/staff/controller/HolidayApplicationController.java
@@ -1,7 +1,8 @@
package com.ruoyi.staff.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.staff.pojo.HolidayApplication;
import com.ruoyi.staff.service.HolidayApplicationService;
import lombok.AllArgsConstructor;
@@ -10,35 +11,35 @@
@RestController
@RequestMapping("/staff/holidayApplication")
@AllArgsConstructor
public class HolidayApplicationController {
public class HolidayApplicationController extends BaseController {
    private HolidayApplicationService holidayApplicationService;
    /**
     * è¯·å‡ç”³è¯·åˆ†é¡µæŸ¥è¯¢
     */
    @GetMapping("/listPage")
    public AjaxResult listPage(Page page, HolidayApplication holidayApplication){
        return AjaxResult.success(holidayApplicationService.listPage(page, holidayApplication));
    public R<?> listPage(Page page, HolidayApplication holidayApplication){
        return R.ok(holidayApplicationService.listPage(page, holidayApplication));
    }
    /**
     * æ–°å¢žè¯·å‡ç”³è¯·
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody HolidayApplication holidayApplication){
        return AjaxResult.success(holidayApplicationService.save(holidayApplication));
    public R<?> add(@RequestBody HolidayApplication holidayApplication){
        return R.ok(holidayApplicationService.save(holidayApplication));
    }
    /**
     * ä¿®æ”¹è¯·å‡ç”³è¯·
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestBody HolidayApplication holidayApplication){
        return AjaxResult.success(holidayApplicationService.updateById(holidayApplication));
    public R<?> update(@RequestBody HolidayApplication holidayApplication){
        return R.ok(holidayApplicationService.updateById(holidayApplication));
    }
    /**
     * åˆ é™¤è¯·å‡ç”³è¯·
     */
    @DeleteMapping("/delete/{id}")
    public AjaxResult delete(@PathVariable("id") Long id){
        return AjaxResult.success(holidayApplicationService.removeById(id));
    public R<?> delete(@PathVariable("id") Long id){
        return R.ok(holidayApplicationService.removeById(id));
    }
}
src/main/java/com/ruoyi/staff/controller/PersonalAttendanceRecordsController.java
@@ -1,7 +1,8 @@
package com.ruoyi.staff.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.staff.dto.PersonalAttendanceRecordsDto;
import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
import com.ruoyi.staff.service.PersonalAttendanceRecordsService;
@@ -23,26 +24,26 @@
@RestController
@RequestMapping("/personalAttendanceRecords")
@Tag(name = "人员打卡签到")
public class PersonalAttendanceRecordsController {
public class PersonalAttendanceRecordsController extends BaseController {
    @Resource
    private PersonalAttendanceRecordsService personalAttendanceRecordsService;
    @Operation(summary = "新增打卡签到")
    @PostMapping("")
    public AjaxResult add(@RequestBody PersonalAttendanceRecordsDto personalAttendanceRecordsDto){
        return AjaxResult.success(personalAttendanceRecordsService.add(personalAttendanceRecordsDto));
    public R<?> add(@RequestBody PersonalAttendanceRecordsDto personalAttendanceRecordsDto){
        return R.ok(personalAttendanceRecordsService.add(personalAttendanceRecordsDto));
    }
    @Operation(summary = "分页查询打卡签到")
    @GetMapping("/listPage")
    public AjaxResult listPage(Page page, PersonalAttendanceRecordsDto personalAttendanceRecordsDto){
        return AjaxResult.success(personalAttendanceRecordsService.listPage(page, personalAttendanceRecordsDto));
    public R<?> listPage(Page page, PersonalAttendanceRecordsDto personalAttendanceRecordsDto){
        return R.ok(personalAttendanceRecordsService.listPage(page, personalAttendanceRecordsDto));
    }
    @Operation(summary = "获取当前人的考勤相关数据")
    @GetMapping("/today")
    public AjaxResult todayInfo(PersonalAttendanceRecordsDto personalAttendanceRecordsDto){
        return AjaxResult.success(personalAttendanceRecordsService.todayInfo(personalAttendanceRecordsDto));
    public R<?> todayInfo(PersonalAttendanceRecordsDto personalAttendanceRecordsDto){
        return R.ok(personalAttendanceRecordsService.todayInfo(personalAttendanceRecordsDto));
    }
    @Operation(summary = "导出打卡签到")
src/main/java/com/ruoyi/staff/controller/SchemeApplicableStaffController.java
@@ -4,7 +4,7 @@
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.staff.pojo.SchemeApplicableStaff;
import com.ruoyi.staff.service.SchemeApplicableStaffService;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -34,7 +34,7 @@
    @GetMapping("/listPage")
    @Operation(summary = "分页查询")
    public AjaxResult listPage(Page page, SchemeApplicableStaff schemeApplicableStaff) {
    public R<?> listPage(Page page, SchemeApplicableStaff schemeApplicableStaff) {
        return schemeApplicableStaffService.listPage(page,schemeApplicableStaff);
    }
@@ -42,7 +42,7 @@
    @Operation(summary = "添加")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "社保方案适用人员表", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody SchemeApplicableStaff schemeApplicableStaff) {
    public R<?> add(@RequestBody SchemeApplicableStaff schemeApplicableStaff) {
        return schemeApplicableStaffService.add(schemeApplicableStaff);
    }
@@ -50,7 +50,7 @@
    @Operation(summary = "修改")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "社保方案适用人员表", businessType = BusinessType.UPDATE)
    public AjaxResult updateSchemeApplicableStaff(@RequestBody SchemeApplicableStaff schemeApplicableStaff) {
    public R<?> updateSchemeApplicableStaff(@RequestBody SchemeApplicableStaff schemeApplicableStaff) {
        return schemeApplicableStaffService.updateSchemeApplicableStaff(schemeApplicableStaff);
    }
@@ -58,7 +58,7 @@
    @Operation(summary = "删除")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "社保方案适用人员表", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
    public R<?> delete(@RequestBody List<Long> ids) {
        return schemeApplicableStaffService.delete(ids);
    }
src/main/java/com/ruoyi/staff/controller/StaffContractController.java
@@ -1,7 +1,8 @@
package com.ruoyi.staff.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.staff.pojo.StaffContract;
import com.ruoyi.staff.service.StaffContractService;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -15,7 +16,7 @@
@RestController
@RequestMapping("/staff/staffContract")
@Tag(name = "员工台账/合同管理")
public class StaffContractController {
public class StaffContractController extends BaseController {
    @Resource
    private StaffContractService staffContractService;
@@ -28,7 +29,7 @@
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult staffContractListPage(Page page, StaffContract staffContract) {
        return AjaxResult.success(staffContractService.staffContractListPage(page, staffContract));
    public R<?> staffContractListPage(Page page, StaffContract staffContract) {
        return R.ok(staffContractService.staffContractListPage(page, staffContract));
    }
}
src/main/java/com/ruoyi/staff/controller/StaffLeaveController.java
@@ -1,7 +1,8 @@
package com.ruoyi.staff.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.staff.dto.StaffLeaveDto;
import com.ruoyi.staff.service.StaffLeaveService;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -18,7 +19,7 @@
@RestController
@RequestMapping("/staff/staffLeave")
@Tag(name = "员工离职")
public class StaffLeaveController {
public class StaffLeaveController extends BaseController {
    @Resource
    private StaffLeaveService staffLeaveService;
    /**
@@ -28,8 +29,8 @@
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult staffLeaveListPage(Page page, StaffLeaveDto staffLeaveDto) {
        return AjaxResult.success(staffLeaveService.staffLeaveListPage(page, staffLeaveDto));
    public R<?> staffLeaveListPage(Page page, StaffLeaveDto staffLeaveDto) {
        return R.ok(staffLeaveService.staffLeaveListPage(page, staffLeaveDto));
    }
    /**
@@ -38,8 +39,8 @@
     * @return
     */
    @PostMapping("")
    public AjaxResult add(@RequestBody StaffLeaveDto staffLeaveDto) {
        return AjaxResult.success(staffLeaveService.add(staffLeaveDto));
    public R<?> add(@RequestBody StaffLeaveDto staffLeaveDto) {
        return R.ok(staffLeaveService.add(staffLeaveDto));
    }
    /**
@@ -49,8 +50,8 @@
     * @return
     */
    @PutMapping("/{id}")
    public AjaxResult update(@PathVariable("id") Long id, @RequestBody StaffLeaveDto staffLeaveDto) {
        return AjaxResult.success(staffLeaveService.update(id, staffLeaveDto));
    public R<?> update(@PathVariable("id") Long id, @RequestBody StaffLeaveDto staffLeaveDto) {
        return R.ok(staffLeaveService.update(id, staffLeaveDto));
    }
    /**
@@ -59,11 +60,11 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult del(@RequestBody List<Integer> ids) {
    public R<?> del(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        return AjaxResult.success(staffLeaveService.del(ids));
        return R.ok(staffLeaveService.del(ids));
    }
    /**
src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java
@@ -4,7 +4,8 @@
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 com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.staff.dto.StaffOnJobDto;
import com.ruoyi.staff.dto.StaffOnJobExcelDto;
import com.ruoyi.staff.pojo.StaffContract;
@@ -26,7 +27,7 @@
@RestController
@RequestMapping("/staff/staffOnJob")
@Tag(name = "员工台账")
public class StaffOnJobController {
public class StaffOnJobController extends BaseController {
    @Resource
    private IStaffOnJobService staffOnJobService;
@@ -39,8 +40,8 @@
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult staffOnJobListPage(Page page, StaffOnJob staffOnJob) {
        return AjaxResult.success(staffOnJobService.staffOnJobListPage(page, staffOnJob));
    public R<?> staffOnJobListPage(Page page, StaffOnJob staffOnJob) {
        return R.ok(staffOnJobService.staffOnJobListPage(page, staffOnJob));
    }
    /**
@@ -48,8 +49,8 @@
     * @return
     */
    @GetMapping("/list")
    public AjaxResult staffOnJobList(StaffOnJob staffOnJob) {
        return AjaxResult.success(staffOnJobService.staffOnJobList(staffOnJob));
    public R<?> staffOnJobList(StaffOnJob staffOnJob) {
        return R.ok(staffOnJobService.staffOnJobList(staffOnJob));
    }
    /**
@@ -58,8 +59,8 @@
     * @return
     */
    @PostMapping("")
    public AjaxResult add(@RequestBody StaffOnJobDto staffOnJob) {
        return AjaxResult.success(staffOnJobService.add(staffOnJob));
    public R<?> add(@RequestBody StaffOnJobDto staffOnJob) {
        return R.ok(staffOnJobService.add(staffOnJob));
    }
    /**
@@ -68,8 +69,8 @@
     * @return
     */
    @PutMapping("/{id}")
    public AjaxResult update(@PathVariable("id") Long id, @RequestBody StaffOnJobDto staffOnJobDto) {
        return AjaxResult.success(staffOnJobService.update(id, staffOnJobDto));
    public R<?> update(@PathVariable("id") Long id, @RequestBody StaffOnJobDto staffOnJobDto) {
        return R.ok(staffOnJobService.update(id, staffOnJobDto));
    }
    /**
@@ -78,11 +79,11 @@
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delStaffOnJobs(@RequestBody List<Integer> ids) {
    public R<?> delStaffOnJobs(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        return AjaxResult.success(staffOnJobService.delStaffOnJobs(ids));
        return R.ok(staffOnJobService.delStaffOnJobs(ids));
    }
    /**
@@ -91,8 +92,8 @@
     * @return
     */
    @GetMapping("/{id}")
    public AjaxResult staffOnJobDetail(@PathVariable("id") Long id) {
        return AjaxResult.success(staffOnJobService.staffOnJobDetail(id));
    public R<?> staffOnJobDetail(@PathVariable("id") Long id) {
        return R.ok(staffOnJobService.staffOnJobDetail(id));
    }
    /**
@@ -102,8 +103,8 @@
     * @return
     */
    @PostMapping("/renewContract/{id}")
    public AjaxResult renewContract(@PathVariable Long id, @RequestBody StaffContract staffContract) {
        return AjaxResult.success(staffOnJobService.renewContract(id, staffContract));
    public R<?> renewContract(@PathVariable Long id, @RequestBody StaffContract staffContract) {
        return R.ok(staffOnJobService.renewContract(id, staffContract));
    }
    @Operation(summary = "下载模板")
@@ -118,12 +119,12 @@
     */
    @PostMapping("/import")
    @Log(title = "在职员工导入", businessType = BusinessType.IMPORT)
    public AjaxResult importData(@RequestPart("file") MultipartFile file) {
    public R<?> importData(@RequestPart("file") MultipartFile file) {
        Boolean b = staffOnJobService.importData(file);
        if (b) {
            return AjaxResult.success("导入成功");
            return R.ok(null, "导入成功");
        }
        return AjaxResult.error("导入失败");
        return R.fail("导入失败");
    }
    /**
@@ -143,8 +144,8 @@
     */
    @PostMapping("/exportCopy")
    @Operation(summary = "word模板合同在职员工导出")
    public AjaxResult exportCopy(HttpServletResponse response,@RequestBody StaffOnJob staffOnJob) throws Exception{
       return AjaxResult.success(staffOnJobService.exportCopy(response, staffOnJob));
    public R<?> exportCopy(HttpServletResponse response,@RequestBody StaffOnJob staffOnJob) throws Exception{
       return R.ok(staffOnJobService.exportCopy(response, staffOnJob));
    }
src/main/java/com/ruoyi/staff/controller/StaffSalaryMainController.java
@@ -3,7 +3,8 @@
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.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.staff.dto.CalculateSalaryDto;
import com.ruoyi.staff.pojo.StaffSalaryMain;
import com.ruoyi.staff.service.StaffSalaryMainService;
@@ -27,19 +28,19 @@
@RestController
@RequestMapping("/staffSalaryMain")
@AllArgsConstructor
public class StaffSalaryMainController {
public class StaffSalaryMainController extends BaseController {
    private StaffSalaryMainService staffSalaryMainService;
    @GetMapping("/listPage")
    @Operation(summary = "员工工资主表分页查询")
    public AjaxResult listPage(Page page, StaffSalaryMain staffSalaryMain) {
    public R<?> listPage(Page page, StaffSalaryMain staffSalaryMain) {
        return staffSalaryMainService.listPage(page, staffSalaryMain);
    }
    @Operation(summary = "通过部门ids获取用户信息计算每个员工的工资")
    @PostMapping("/calculateSalary")
    public AjaxResult calculateSalary(@RequestBody CalculateSalaryDto calculateSalaryDto) {
    public R<?> calculateSalary(@RequestBody CalculateSalaryDto calculateSalaryDto) {
        return staffSalaryMainService.calculateSalary(calculateSalaryDto);
    }
@@ -47,7 +48,7 @@
    @Operation(summary = "新建工资表")
    @Log(title = "新建工资表", businessType = BusinessType.INSERT)
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@RequestBody StaffSalaryMain staffSalaryMain) {
    public R<?> add(@RequestBody StaffSalaryMain staffSalaryMain) {
        return staffSalaryMainService.add(staffSalaryMain);
    }
@@ -55,7 +56,7 @@
    @Operation(summary = "修改工资表")
    @Log(title = "修改工资表", businessType = BusinessType.UPDATE)
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult updateStaffSalaryMain(@RequestBody StaffSalaryMain staffSalaryMain) {
    public R<?> updateStaffSalaryMain(@RequestBody StaffSalaryMain staffSalaryMain) {
        return staffSalaryMainService.updateStaffSalaryMain(staffSalaryMain);
    }
@@ -63,7 +64,7 @@
    @Operation(summary = "删除工资表")
    @Log(title = "删除工资表", businessType = BusinessType.DELETE)
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delete(@RequestBody List<Long> ids) {
    public R<?> delete(@RequestBody List<Long> ids) {
        return staffSalaryMainService.delete(ids);
    }
src/main/java/com/ruoyi/staff/controller/StaffSchedulingController.java
@@ -5,7 +5,8 @@
import com.ruoyi.compensationperformance.pojo.CompensationPerformance;
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.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.staff.dto.SaveStaffSchedulingDto;
import com.ruoyi.staff.dto.StaffSchedulingDto;
import com.ruoyi.staff.service.StaffSchedulingService;
@@ -26,39 +27,39 @@
@RestController
@RequestMapping("/staff/staffScheduling")
@RequiredArgsConstructor
public class StaffSchedulingController {
public class StaffSchedulingController extends BaseController {
    private final StaffSchedulingService staffSchedulingService;
    @PostMapping("/listPage")
    public AjaxResult listPage(@RequestBody SearchSchedulingVo vo){
       return AjaxResult.success(staffSchedulingService.listPage(vo));
    public R<?> listPage(@RequestBody SearchSchedulingVo vo){
       return R.ok(staffSchedulingService.listPage(vo));
    }
    @PostMapping("/save")
    public AjaxResult save(@RequestBody @Validated SaveStaffSchedulingDto saveStaffSchedulingDto){
    public R<?> save(@RequestBody @Validated SaveStaffSchedulingDto saveStaffSchedulingDto){
        staffSchedulingService.saveStaffScheduling(saveStaffSchedulingDto);
        return AjaxResult.success();
        return R.ok();
    }
    @DeleteMapping("/delByIds")
    public AjaxResult delByIds(@RequestBody List<Integer> ids){
    public R<?> delByIds(@RequestBody List<Integer> ids){
        staffSchedulingService.removeByIds(ids);
        return AjaxResult.success();
        return R.ok();
    }
    @DeleteMapping("/del/{id}")
    public AjaxResult del(@PathVariable("id") Integer id){
    public R<?> del(@PathVariable("id") Integer id){
        staffSchedulingService.removeById(id);
        return AjaxResult.success();
        return R.ok();
    }
    /**
     * èŽ·å–å½“å‰ç”¨æˆ·æœ€æ–°æŽ’ç­è®°å½•
     */
    @GetMapping("/getCurrentUserLatestScheduling")
    public AjaxResult getCurrentUserLatestScheduling(){
        return AjaxResult.success(staffSchedulingService.getCurrentUserLatestScheduling());
    public R<?> getCurrentUserLatestScheduling(){
        return R.ok(staffSchedulingService.getCurrentUserLatestScheduling());
    }
    @Log(title = "导出人员排班列表", businessType = BusinessType.EXPORT)
src/main/java/com/ruoyi/staff/service/SchemeApplicableStaffService.java
@@ -1,7 +1,7 @@
package com.ruoyi.staff.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.staff.pojo.SchemeApplicableStaff;
import com.baomidou.mybatisplus.extension.service.IService;
@@ -17,11 +17,11 @@
 */
public interface SchemeApplicableStaffService extends IService<SchemeApplicableStaff> {
    AjaxResult listPage(Page page, SchemeApplicableStaff schemeApplicableStaff);
    R<?> listPage(Page page, SchemeApplicableStaff schemeApplicableStaff);
    AjaxResult add(SchemeApplicableStaff schemeApplicableStaff);
    R<?> add(SchemeApplicableStaff schemeApplicableStaff);
    AjaxResult updateSchemeApplicableStaff(SchemeApplicableStaff schemeApplicableStaff);
    R<?> updateSchemeApplicableStaff(SchemeApplicableStaff schemeApplicableStaff);
    AjaxResult delete(List<Long> ids);
    R<?> delete(List<Long> ids);
}
src/main/java/com/ruoyi/staff/service/StaffSalaryMainService.java
@@ -1,7 +1,7 @@
package com.ruoyi.staff.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.staff.dto.CalculateSalaryDto;
import com.ruoyi.staff.pojo.StaffSalaryMain;
import com.baomidou.mybatisplus.extension.service.IService;
@@ -18,13 +18,13 @@
 */
public interface StaffSalaryMainService extends IService<StaffSalaryMain> {
    AjaxResult listPage(Page page, StaffSalaryMain staffSalaryMain);
    R listPage(Page page, StaffSalaryMain staffSalaryMain);
    AjaxResult add(StaffSalaryMain staffSalaryMain);
    R<?> add(StaffSalaryMain staffSalaryMain);
    AjaxResult updateStaffSalaryMain(StaffSalaryMain staffSalaryMain);
    R<?> updateStaffSalaryMain(StaffSalaryMain staffSalaryMain);
    AjaxResult delete(List<Long> ids);
    R<?> delete(List<Long> ids);
    AjaxResult calculateSalary(CalculateSalaryDto calculateSalaryDto);
    R<?> calculateSalary(CalculateSalaryDto calculateSalaryDto);
}
src/main/java/com/ruoyi/staff/service/impl/SchemeApplicableStaffServiceImpl.java
@@ -4,7 +4,7 @@
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.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.bean.dto.UserAccountDto;
import com.ruoyi.production.bean.dto.UserProductionAccountingDto;
import com.ruoyi.production.service.SalesLedgerProductionAccountingService;
@@ -52,7 +52,7 @@
    @Override
    public AjaxResult listPage(Page page, SchemeApplicableStaff schemeApplicableStaff) {
    public R<?> listPage(Page page, SchemeApplicableStaff schemeApplicableStaff) {
        LambdaQueryWrapper<SchemeApplicableStaff> schemeApplicableStaffLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(schemeApplicableStaff != null){
            if(StringUtils.isNotEmpty(schemeApplicableStaff.getTitle())){
@@ -62,7 +62,7 @@
        Page<SchemeApplicableStaff> page1 = schemeApplicableStaffMapper.selectPage(page, schemeApplicableStaffLambdaQueryWrapper);
        List<Long> collect = page1.getRecords().stream().map(SchemeApplicableStaff::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(collect)){
            return AjaxResult.success(page1);
            return R.ok(page1);
        }
        List<SchemeInsuranceDetail> schemeInsuranceDetails = schemeInsuranceDetailMapper
                .selectList(new LambdaQueryWrapper<SchemeInsuranceDetail>()
@@ -82,7 +82,7 @@
                item.setDeptNames(sysDepts.stream().map(SysDept::getDeptName).collect(Collectors.joining(",")));
            }
        });
        return AjaxResult.success(page1);
        return R.ok(page1);
    }
    public void setSchemeApplicableStaffUserInfo(SchemeApplicableStaff schemeApplicableStaff) {
@@ -103,12 +103,12 @@
    }
    @Override
    public AjaxResult add(SchemeApplicableStaff schemeApplicableStaff) {
    public R<?> add(SchemeApplicableStaff schemeApplicableStaff) {
        if(schemeApplicableStaff == null){
            return AjaxResult.error("参数错误");
            return R.fail("参数错误");
        }
        if(CollectionUtils.isEmpty(schemeApplicableStaff.getSchemeInsuranceDetailList())){
            return AjaxResult.error("请选择方案明细");
            return R.fail("请选择方案明细");
        }
        setSchemeApplicableStaffUserInfo(schemeApplicableStaff); //根据部门设置用户信息
        int insert = schemeApplicableStaffMapper.insert(schemeApplicableStaff);
@@ -116,13 +116,13 @@
            item.setSchemeId(schemeApplicableStaff.getId());
            schemeInsuranceDetailMapper.insert(item);
        });
        return AjaxResult.success(insert);
        return R.ok(insert);
    }
    @Override
    public AjaxResult updateSchemeApplicableStaff(SchemeApplicableStaff schemeApplicableStaff) {
    public R<?> updateSchemeApplicableStaff(SchemeApplicableStaff schemeApplicableStaff) {
        if(schemeApplicableStaff == null){
            return AjaxResult.error("参数错误");
            return R.fail("参数错误");
        }
        setSchemeApplicableStaffUserInfo(schemeApplicableStaff); //根据部门设置用户信息
        int update = schemeApplicableStaffMapper.updateById(schemeApplicableStaff);
@@ -133,18 +133,18 @@
            item.setSchemeId(schemeApplicableStaff.getId());
            schemeInsuranceDetailMapper.insert(item);
        });
        return AjaxResult.success(update);
        return R.ok(update);
    }
    @Override
    public AjaxResult delete(List<Long> ids) {
    public R<?> delete(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return AjaxResult.error("参数错误");
            return R.fail("参数错误");
        }
        int delete = schemeApplicableStaffMapper.deleteBatchIds(ids);
        schemeInsuranceDetailMapper.delete(new LambdaQueryWrapper<SchemeInsuranceDetail>()
                .in(SchemeInsuranceDetail::getSchemeId, ids));
        return AjaxResult.success(delete);
        return R.ok(delete);
    }
    /**
src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
@@ -1,12 +1,13 @@
package com.ruoyi.staff.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.common.exception.base.BaseException;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.dto.WordDateDto;
import com.ruoyi.project.system.domain.SysDept;
@@ -46,7 +47,7 @@
@RequiredArgsConstructor
@Service
public class StaffOnJobServiceImpl extends ServiceImpl<StaffOnJobMapper, StaffOnJob>  implements IStaffOnJobService {
public class StaffOnJobServiceImpl extends ServiceImpl<StaffOnJobMapper, StaffOnJob> implements IStaffOnJobService {
    private final StaffOnJobMapper staffOnJobMapper;
    private final SysDeptMapper sysDeptMapper;
@@ -64,22 +65,22 @@
    private final StaffEmergencyContactMapper staffEmergencyContactMapper;
    private final StaffEmergencyContactServiceImpl staffEmergencyContactServiceImpl;
    //在职员工台账分页查询
    // åœ¨èŒå‘˜å·¥å°è´¦åˆ†é¡µæŸ¥è¯¢
    @Override
    public IPage<StaffOnJobDto> staffOnJobListPage(Page page, StaffOnJob staffOnJob) {
        return staffOnJobMapper.staffOnJobListPage(page,staffOnJob);
        return staffOnJobMapper.staffOnJobListPage(page, staffOnJob);
    }
    //新增入职
    // æ–°å¢žå…¥èŒ
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int add(StaffOnJobDto staffOnJobPrams) {
        String[] ignoreProperties = {"id"};//排除id属性
        String[] ignoreProperties = { "id" };// æŽ’除id属性
        // åˆ¤æ–­ç¼–号是否存在
        List<StaffOnJob> staffOnJobs = staffOnJobMapper.selectList(Wrappers.<StaffOnJob>lambdaQuery().eq(StaffOnJob::getStaffNo, staffOnJobPrams.getStaffNo()));
        if (staffOnJobs != null && !staffOnJobs.isEmpty()){
            throw new BaseException("编号为"+staffOnJobPrams.getStaffNo()+"的员工已经存在,无法新增!!!");
        List<StaffOnJob> staffOnJobs = staffOnJobMapper.selectList(
                Wrappers.<StaffOnJob>lambdaQuery().eq(StaffOnJob::getStaffNo, staffOnJobPrams.getStaffNo()));
        if (staffOnJobs != null && !staffOnJobs.isEmpty()) {
            throw new BaseException("编号为" + staffOnJobPrams.getStaffNo() + "的员工已经存在,无法新增!!!");
        }
        // åˆ›å»ºå…¥èŒæ•°æ®
@@ -88,23 +89,23 @@
        staffOnJobMapper.insert(staffOnJobPrams);
        // æŸ¥è¯¢ç”¨æˆ·æ˜¯å¦å·²ç»æ–°å¢ž
        SysUser sysUser = sysUserService.selectUserById(staffOnJobPrams.getId());
        if(sysUser == null){
        if (sysUser == null) {
            SysUser sysUser1 = new SysUser();
            sysUser1.setUserName(staffOnJobPrams.getStaffNo());
            sysUser1.setNickName(staffOnJobPrams.getStaffName());
            String s = SecurityUtils.encryptPassword("123456");
            sysUser1.setPassword(s);
            if(staffOnJobPrams.getSysPostId() != null){
                Long[] posts = new Long[]{staffOnJobPrams.getSysPostId().longValue()};
            if (staffOnJobPrams.getSysPostId() != null) {
                Long[] posts = new Long[] { staffOnJobPrams.getSysPostId().longValue() };
                sysUser1.setPostIds(posts);
            }
            sysUser1.setRoleIds(new Long[]{staffOnJobPrams.getRoleId()});
            sysUser1.setDeptIds(new  Long[]{staffOnJobPrams.getSysDeptId()});
            sysUser1.setRoleIds(new Long[] { staffOnJobPrams.getRoleId() });
            sysUser1.setDeptIds(new Long[] { staffOnJobPrams.getSysDeptId() });
            sysUser1.setStatus("0");
            sysUserService.insertUser(sysUser1);
        }
        // ç»‘定子表数据
        bingingStaffOnJobExtra(staffOnJobPrams.getId(),staffOnJobPrams);
        bingingStaffOnJobExtra(staffOnJobPrams.getId(), staffOnJobPrams);
        // åˆ›å»ºåˆåŒè®°å½•
        StaffContract staffContract = new StaffContract();
        staffContract.setStaffOnJobId(staffOnJobPrams.getId());
@@ -114,32 +115,32 @@
        return staffContractMapper.insert(staffContract);
    }
    //更新入职信息
    // æ›´æ–°å…¥èŒä¿¡æ¯
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int update(Long id, StaffOnJobDto staffOnJobParams) {
        // åˆ¤æ–­å¯¹è±¡æ˜¯å¦å­˜åœ¨
        StaffOnJob job = staffOnJobMapper.selectById(id);
        if (job == null){
            throw new BaseException("编号为"+staffOnJobParams.getStaffNo()+"的员工不存在,无法更新!!!");
        if (job == null) {
            throw new BaseException("编号为" + staffOnJobParams.getStaffNo() + "的员工不存在,无法更新!!!");
        }
        String[] ignoreProperties = {"id"};//排除更新属性
        String[] ignoreProperties = { "id" };// æŽ’除更新属性
        // èŽ·å–æœ€æ–°åˆåŒæ•°æ®ï¼Œå¹¶ä¸”æ›´æ–°
        StaffContract contract = staffContractMapper.selectOne(Wrappers.<StaffContract>lambdaQuery()
                .eq(StaffContract::getStaffOnJobId, id)
                .last("limit 1")
                .orderByDesc(StaffContract::getId));
        if (contract != null){
            BeanUtils.copyProperties(staffOnJobParams,contract,ignoreProperties);
        if (contract != null) {
            BeanUtils.copyProperties(staffOnJobParams, contract, ignoreProperties);
            staffContractMapper.updateById(contract);
        }
        // åˆ é™¤æ‰€æœ‰å­è¡¨æ•°æ®
        delStaffOnJobExtra(Arrays.asList(id));
        // ç»‘定子表数据
        bingingStaffOnJobExtra(id,staffOnJobParams);
        bingingStaffOnJobExtra(id, staffOnJobParams);
        // æ›´æ–°å‘˜å·¥æ•°æ®
        staffOnJobParams.setContractExpireTime(staffOnJobParams.getContractEndTime());
        return staffOnJobMapper.updateById(staffOnJobParams);
@@ -147,26 +148,27 @@
    /**
     * ç»‘定员工子表数据
     *
     * @param staffOnJobPrams
     * @param id
     */
    public void bingingStaffOnJobExtra(Long id,StaffOnJob staffOnJobPrams) {
    public void bingingStaffOnJobExtra(Long id, StaffOnJob staffOnJobPrams) {
        // æ–°å¢žæ•™è‚²ç»åކ
        if(CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffEducationList())){
        if (CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffEducationList())) {
            staffOnJobPrams.getStaffEducationList().stream()
                    .filter(Objects::nonNull) // è¿‡æ»¤null对象,避免空指针
                    .forEach(staff -> staff.setStaffOnJobId(id)); // èµ‹å€¼
            staffEducationService.saveBatch(staffOnJobPrams.getStaffEducationList());
        }
        // æ–°å¢žå·¥ä½œç»åކ
        if(CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffWorkExperienceList())){
        if (CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffWorkExperienceList())) {
            staffOnJobPrams.getStaffWorkExperienceList().stream()
                    .filter(Objects::nonNull) // è¿‡æ»¤null对象,避免空指针
                    .forEach(staff -> staff.setStaffOnJobId(id)); // èµ‹å€¼
            staffWorkExperienceServiceImpl.saveBatch(staffOnJobPrams.getStaffWorkExperienceList());
        }
        // æ–°å¢žç´§æ€¥è”系人
        if(CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffEmergencyContactList())){
        if (CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffEmergencyContactList())) {
            staffOnJobPrams.getStaffEmergencyContactList().stream()
                    .filter(Objects::nonNull) // è¿‡æ»¤null对象,避免空指针
                    .forEach(staff -> staff.setStaffOnJobId(id)); // èµ‹å€¼
@@ -174,27 +176,30 @@
        }
    }
    /**
     * é€šè¿‡å‘˜å·¥id删除教育经历,工作经历,紧急联系人
     *
     * @param ids
     * @return
     */
    public void delStaffOnJobExtra(List<Long> ids) {
        // åˆ é™¤æ•™è‚²ç»åކ
        staffEducationService.remove(Wrappers.<StaffEducation>lambdaQuery().in(StaffEducation::getStaffOnJobId,ids));
        staffEducationService.remove(Wrappers.<StaffEducation>lambdaQuery().in(StaffEducation::getStaffOnJobId, ids));
        // åˆ é™¤å·¥ä½œç»åކ
        staffWorkExperienceServiceImpl.remove(Wrappers.<StaffWorkExperience>lambdaQuery().in(StaffWorkExperience::getStaffOnJobId,ids));
        staffWorkExperienceServiceImpl
                .remove(Wrappers.<StaffWorkExperience>lambdaQuery().in(StaffWorkExperience::getStaffOnJobId, ids));
        // åˆ é™¤ç´§æ€¥è”系人
        staffEmergencyContactServiceImpl.remove(Wrappers.<StaffEmergencyContact>lambdaQuery().in(StaffEmergencyContact::getStaffOnJobId,ids));
        staffEmergencyContactServiceImpl
                .remove(Wrappers.<StaffEmergencyContact>lambdaQuery().in(StaffEmergencyContact::getStaffOnJobId, ids));
    }
    //删除入职
    // åˆ é™¤å…¥èŒ
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int delStaffOnJobs(List<Integer> ids) {
        List<StaffOnJob> staffOnJobs = staffOnJobMapper.selectList(Wrappers.<StaffOnJob>lambdaQuery().in(StaffOnJob::getId, ids));
        if(CollectionUtils.isEmpty(staffOnJobs)){
        List<StaffOnJob> staffOnJobs = staffOnJobMapper
                .selectList(Wrappers.<StaffOnJob>lambdaQuery().in(StaffOnJob::getId, ids));
        if (CollectionUtils.isEmpty(staffOnJobs)) {
            throw new BaseException("该员工不存在,无法删除!!!");
        }
        // åˆ é™¤å…¥èŒæ•°æ®
@@ -202,11 +207,13 @@
        // åˆ é™¤ç¦»èŒæ•°æ®
        staffLeaveMapper.delete(Wrappers.<StaffLeave>lambdaQuery().in(StaffLeave::getStaffOnJobId, ids));
        // åˆ é™¤æ‰“卡记录
        personalAttendanceRecordsMapper.delete(Wrappers.<PersonalAttendanceRecords>lambdaQuery().in(PersonalAttendanceRecords::getStaffOnJobId, ids));
        personalAttendanceRecordsMapper.delete(
                Wrappers.<PersonalAttendanceRecords>lambdaQuery().in(PersonalAttendanceRecords::getStaffOnJobId, ids));
        // åˆ é™¤ç”¨æˆ·æ•°æ®
        List<SysUser> sysUsers = sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery()
                .in(SysUser::getUserName, staffOnJobs.stream().map(StaffOnJob::getStaffNo).collect(Collectors.toList())));
        if(CollectionUtils.isNotEmpty(sysUsers)){
                .in(SysUser::getUserName,
                        staffOnJobs.stream().map(StaffOnJob::getStaffNo).collect(Collectors.toList())));
        if (CollectionUtils.isNotEmpty(sysUsers)) {
            Long[] longs = sysUsers.stream().map(SysUser::getUserId).toArray(Long[]::new);
            sysUserService.deleteUserByIds(longs);
        }
@@ -214,7 +221,8 @@
        delStaffOnJobExtra(ids.stream().map(Integer::longValue).collect(Collectors.toList()));
        // åˆ é™¤åˆåŒæ•°æ®
        return staffContractMapper.delete(Wrappers.<StaffContract>lambdaQuery().in(StaffContract::getStaffOnJobId, ids));
        return staffContractMapper
                .delete(Wrappers.<StaffContract>lambdaQuery().in(StaffContract::getStaffOnJobId, ids));
    }
    // ç»­ç­¾åˆåŒ
@@ -223,7 +231,7 @@
    public int renewContract(Long id, StaffContract staffContract) {
        // åˆ¤æ–­å¯¹è±¡æ˜¯å¦å­˜åœ¨
        StaffOnJob job = staffOnJobMapper.selectById(id);
        if (job == null){
        if (job == null) {
            throw new BaseException("该员工不存在,无法更新!!!");
        }
@@ -241,10 +249,10 @@
        return 0;
    }
    //在职员工详情
    // åœ¨èŒå‘˜å·¥è¯¦æƒ…
    @Override
    public StaffOnJobDto staffOnJobDetail(Long id) {
        StaffOnJob staffOnJob  = staffOnJobMapper.selectById(id);
        StaffOnJob staffOnJob = staffOnJobMapper.selectById(id);
        if (staffOnJob == null) {
            throw new IllegalArgumentException("该员工不存在");
        }
@@ -264,7 +272,7 @@
                .eq(StaffContract::getStaffOnJobId, staffOnJob.getId())
                .last("limit 1")
                .orderByDesc(StaffContract::getId));
        if (contract != null){
        if (contract != null) {
            staffOnJobDto.setContractTerm(contract.getContractTerm());
            staffOnJobDto.setContractStartTime(contract.getContractStartTime());
            staffOnJobDto.setContractEndTime(contract.getContractEndTime());
@@ -272,14 +280,16 @@
        // èŽ·å–å­è¡¨æ•°æ®
        staffOnJobDto.setStaffEducationList(staffEducationMapper.selectList(Wrappers.<StaffEducation>lambdaQuery()
                .eq(StaffEducation::getStaffOnJobId, staffOnJob.getId())));
        staffOnJobDto.setStaffWorkExperienceList(staffWorkExperienceMapper.selectList(Wrappers.<StaffWorkExperience>lambdaQuery()
                .eq(StaffWorkExperience::getStaffOnJobId, staffOnJob.getId())));
        staffOnJobDto.setStaffEmergencyContactList(staffEmergencyContactMapper.selectList(Wrappers.<StaffEmergencyContact>lambdaQuery()
                .eq(StaffEmergencyContact::getStaffOnJobId, staffOnJob.getId())));
        staffOnJobDto.setStaffWorkExperienceList(
                staffWorkExperienceMapper.selectList(Wrappers.<StaffWorkExperience>lambdaQuery()
                        .eq(StaffWorkExperience::getStaffOnJobId, staffOnJob.getId())));
        staffOnJobDto.setStaffEmergencyContactList(
                staffEmergencyContactMapper.selectList(Wrappers.<StaffEmergencyContact>lambdaQuery()
                        .eq(StaffEmergencyContact::getStaffOnJobId, staffOnJob.getId())));
        return staffOnJobDto;
    }
    //在职员工导出
    // åœ¨èŒå‘˜å·¥å¯¼å‡º
    @Override
    public void staffOnJobExport(HttpServletResponse response, StaffOnJob staffOnJob) {
        List<StaffOnJobDto> staffOnJobs = staffOnJobMapper.staffOnJobList(staffOnJob);
@@ -298,39 +308,62 @@
        try {
            ExcelUtil<StaffOnJobExcelDto> util = new ExcelUtil<>(StaffOnJobExcelDto.class);
            List<StaffOnJobExcelDto> staffOnJobs = util.importExcel(file.getInputStream());
            if (CollectionUtils.isEmpty(staffOnJobs)){
            if (CollectionUtils.isEmpty(staffOnJobs)) {
                return false;
            }
            // èŽ·å–æ‰€æœ‰éƒ¨é—¨æ•°æ®
            List<SysDept> sysDepts = sysDeptMapper.selectList(Wrappers.<SysDept>lambdaQuery().eq(SysDept::getDelFlag, 0));
            List<SysDept> sysDepts = sysDeptMapper
                    .selectList(Wrappers.<SysDept>lambdaQuery().eq(SysDept::getDelFlag, 0));
            // èŽ·å–æ‰€æœ‰è§’è‰²æ•°æ®
            List<SysRole> sysRoles = sysRoleMapper.selectRoleAll();
            staffOnJobs.forEach(staffOnJob -> {
                // å¤„理合同期限数据格式
                if (staffOnJob.getContractTerm() != null && !staffOnJob.getContractTerm().trim().isEmpty()) {
                    String term = staffOnJob.getContractTerm().trim();
                    try {
                        Integer.parseInt(term);
                    } catch (NumberFormatException e) {
                        throw new ServiceException("员工[" + staffOnJob.getStaffName() + "]的合同期限["
                                + staffOnJob.getContractTerm() + "]格式不正确,必须为纯数字(如: 1, 2, 3)");
                    }
                }
                StaffOnJobDto staffOnJobDto = new StaffOnJobDto();
                BeanUtils.copyProperties(staffOnJob, staffOnJobDto);
                // é€šè¿‡åç§°èŽ·å–éƒ¨é—¨id
                staffOnJobDto.setSysDeptId(// ... existing code ...
                        sysDepts.stream()
                            .filter(dept -> dept.getDeptName() != null && dept.getDeptName().equals(staffOnJob.getSysDeptName()))
                            .findFirst()
                            .map(SysDept::getDeptId)
                            .orElse(null)
                        );
                Long deptId = sysDepts.stream()
                        .filter(dept -> dept.getDeptName() != null
                                && dept.getDeptName().equals(staffOnJob.getSysDeptName()))
                        .findFirst()
                        .map(SysDept::getDeptId)
                        .orElse(null);
                if (deptId == null) {
                    throw new ServiceException(
                            "员工[" + staffOnJob.getStaffName() + "]的部门[" + staffOnJob.getSysDeptName() + "]不存在,请检查数据");
                }
                staffOnJobDto.setSysDeptId(deptId);
                // é€šè¿‡åç§°èŽ·å–è§’è‰²id
                staffOnJobDto.setRoleId(sysRoles.stream()
                        .filter(role -> role.getRoleName() != null && role.getRoleName().equals(staffOnJob.getRoleName()))
                Long roleId = sysRoles.stream()
                        .filter(role -> role.getRoleName() != null
                                && role.getRoleName().equals(staffOnJob.getRoleName()))
                        .findFirst()
                        .map(SysRole::getRoleId)
                        .orElse( null));
                add(staffOnJobDto);
                        .orElse(null);
                if (roleId == null) {
                    throw new ServiceException(
                            "员工[" + staffOnJob.getStaffName() + "]的角色[" + staffOnJob.getRoleName() + "]不存在,请检查数据");
                }
                staffOnJobDto.setRoleId(roleId);
                SpringUtils.getAopProxy(this).add(staffOnJobDto);
            });
            return true;
        } catch (ServiceException | BaseException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
            log.error("员工台账导入失败 : " + e.getMessage());
            throw new ServiceException("导入失败: " + e.getMessage());
        }
    }
    @Override
    public String exportCopy(HttpServletResponse response, StaffOnJob staffOnJob) throws Exception {
@@ -339,7 +372,7 @@
        // è®¾ç½®æ¨¡æ¿æ–‡ä»¶æ‰€åœ¨ç›®å½•(绝对路径,例如:/templates/)
        cfg.setClassForTemplateLoading(StaffOnJobServiceImpl.class, "/static");
        cfg.setDefaultEncoding("UTF-8");
        //2.定义需要填充的变里
        // 2.定义需要填充的变里
        // â‘  æž„造员工信息(实际项目中可从数据库/Excel读取)
        WordDateDto staff = new WordDateDto();
        BeanUtils.copyProperties(staffOnJob, staff);
@@ -349,7 +382,7 @@
        Instant instant = staff.getContractExpireTime().toInstant();
        // ä¹Ÿå¯ä»¥æŒ‡å®šå…·ä½“时区,例如Asia/Shanghai:
        LocalDate localDate = instant.atZone(ZoneId.of("Asia/Shanghai")).toLocalDate();  // åˆåŒç»“束时间
        LocalDate localDate = instant.atZone(ZoneId.of("Asia/Shanghai")).toLocalDate(); // åˆåŒç»“束时间
        LocalDate localDate1 = localDate.minusYears(Integer.parseInt(staff.getContractTerm()));// åˆåŒå¼€å§‹æ—¶é—´
        // ç­¾è®¢æ—¥æœŸè½¬æ¢lcoaldate
@@ -362,7 +395,7 @@
        staff.setQyear(localDate2.getYear() + "");
        staff.setQmoth(localDate2.getMonthValue() + "");
        staff.setQday(localDate2.getDayOfMonth() + "");
        if(staff.getDateSelect().equals("A")){
        if (staff.getDateSelect().equals("A")) {
            staff.setSyear(localDate1.getYear() + "");
            staff.setSmoth(localDate1.getMonthValue() + "");
            staff.setSday(localDate1.getDayOfMonth() + "");
@@ -376,7 +409,7 @@
            staff.setSeyear(localDate4.getYear() + "");
            staff.setSemoth(localDate4.getMonthValue() + "");
            staff.setSeday(localDate4.getDayOfMonth() + "");
        }else if (staff.getDateSelect().equals("B")){
        } else if (staff.getDateSelect().equals("B")) {
            staff.setBsyear(localDate1.getYear() + "");
            staff.setBsmoth(localDate1.getMonthValue() + "");
@@ -388,29 +421,27 @@
            staff.setBseyear(localDate4.getYear() + "");
            staff.setBsemoth(localDate4.getMonthValue() + "");
            staff.setBseday(localDate4.getDayOfMonth() + "");
        }else if (staff.getDateSelect().equals("C")){
        } else if (staff.getDateSelect().equals("C")) {
            staff.setCsyear(localDate1.getYear() + "");
            staff.setCsmoth(localDate1.getMonthValue() + "");
            staff.setCsday(localDate1.getDayOfMonth() + "");
        }
        Map<String,Object> data = new HashMap<>();
        data.put("item",staff);
        //3.加载XML æ¨¡æ¿
        Map<String, Object> data = new HashMap<>();
        data.put("item", staff);
        // 3.加载XML æ¨¡æ¿
        Template template = cfg.getTemplate("劳动合同书.xml");
        //4.生成填充后的 XML å†…容
        // 4.生成填充后的 XML å†…容
        StringWriter out = new StringWriter();
        template.process(data, out);
        String filledXml = out.toString();
        //5.将XML内容写入交件并改为.docx æ ¼å¼
        // 5.将XML内容写入交件并改为.docx æ ¼å¼
        File outputFile = new File(url);
        try(FileOutputStream fos = new FileOutputStream(outputFile);
            OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
        try (FileOutputStream fos = new FileOutputStream(outputFile);
                OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
            osw.write(filledXml);
        }
        return url;
    }
}
src/main/java/com/ruoyi/staff/service/impl/StaffSalaryMainServiceImpl.java
@@ -7,7 +7,7 @@
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.framework.web.domain.R;
import com.ruoyi.project.system.mapper.SysUserDeptMapper;
import com.ruoyi.staff.dto.CalculateSalaryDto;
import com.ruoyi.staff.mapper.StaffLeaveMapper;
@@ -48,7 +48,7 @@
    private final AccountExpenseMapper accountExpenseMapper;
    @Override
    public AjaxResult listPage(Page page, StaffSalaryMain staffSalaryMain) {
    public R<?> listPage(Page page, StaffSalaryMain staffSalaryMain) {
        LambdaQueryWrapper<StaffSalaryMain> staffSalaryMainLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(staffSalaryMain != null){
            if(StringUtils.isNotEmpty(staffSalaryMain.getSalaryTitle())){
@@ -66,31 +66,31 @@
            List<StaffSalaryDetail> staffSalaryDetailList = staffSalaryDetailMapper.selectList(new LambdaQueryWrapper<StaffSalaryDetail>().eq(StaffSalaryDetail::getMainId, main.getId()));
            main.setStaffSalaryDetailList(staffSalaryDetailList);
        });
        return AjaxResult.success(page1);
        return R.ok(page1);
    }
    @Override
    public AjaxResult add(StaffSalaryMain staffSalaryMain) {
    public R<?> add(StaffSalaryMain staffSalaryMain) {
        staffSalaryMainMapper.insert(staffSalaryMain);
        staffSalaryMain.getStaffSalaryDetailList().forEach(detail -> {
            detail.setMainId(staffSalaryMain.getId());
        });
        staffSalaryDetailService.saveBatch(staffSalaryMain.getStaffSalaryDetailList());
        return AjaxResult.success("新增成功");
        return R.ok(null, "新增成功");
    }
    @Override
    public AjaxResult updateStaffSalaryMain(StaffSalaryMain staffSalaryMain) {
    public R<?> updateStaffSalaryMain(StaffSalaryMain staffSalaryMain) {
        if(staffSalaryMain == null){
            return AjaxResult.error("参数错误");
            return R.fail("参数错误");
        }
        StaffSalaryMain staffSalaryMain1 = staffSalaryMainMapper.selectById(staffSalaryMain.getId());
        if(staffSalaryMain1 == null){
            return AjaxResult.error("参数错误");
            return R.fail("参数错误");
        }
        // å¾…审核不可编辑
//        if(staffSalaryMain1.getStatus() > 3){
//            return AjaxResult.error("待审核不可编辑");
//            return R.fail("待审核不可编辑");
//        }
        staffSalaryMainMapper.updateById(staffSalaryMain);
        if(org.apache.commons.collections4.CollectionUtils.isNotEmpty(staffSalaryMain.getStaffSalaryDetailList())){
@@ -115,27 +115,27 @@
            accountExpense.setInputTime(new Date());
            accountExpenseMapper.insert(accountExpense);
        }
        return AjaxResult.success("修改成功");
        return R.ok(null, "修改成功");
    }
    @Override
    public AjaxResult delete(List<Long> ids) {
    public R<?> delete(List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("参数错误");
            return R.fail("参数错误");
        }
        staffSalaryMainMapper.deleteBatchIds(ids);
        staffSalaryDetailMapper.delete(new LambdaQueryWrapper<StaffSalaryDetail>().in(StaffSalaryDetail::getMainId, ids));
        return AjaxResult.success("删除成功");
        return R.ok(null, "删除成功");
    }
    @Override
    public AjaxResult calculateSalary(CalculateSalaryDto calculateSalaryDto) {
    public R<?> calculateSalary(CalculateSalaryDto calculateSalaryDto) {
        if(CollectionUtils.isEmpty(calculateSalaryDto.getIds())){
            return AjaxResult.error("参数错误");
            return R.fail("参数错误");
        }
        List<Map<String, Object>> longs = setSchemeApplicableStaffUserInfo(calculateSalaryDto.getIds()); // é€šè¿‡éƒ¨é—¨ids获取用户信息
        if(CollectionUtils.isEmpty(longs)){
            return AjaxResult.error("无员工");
            return R.fail("无员工");
        }
        List<Map<String, Object>> mapList = new ArrayList<>();
        for (Map<String, Object> id : longs) {
@@ -151,7 +151,7 @@
            schemeApplicableStaffService.calculateByEmployeeId((Integer) id.get("id"),id,calculateSalaryDto.getDate());
            mapList.add(id);
        }
        return AjaxResult.success(mapList);
        return R.ok(mapList);
    }
    public List<Map<String, Object>> setSchemeApplicableStaffUserInfo(List<Long> ids) {
src/main/java/com/ruoyi/stock/controller/StockInRecordController.java
@@ -4,7 +4,8 @@
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.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.stock.dto.StockInRecordDto;
import com.ruoyi.stock.service.StockInRecordService;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -20,37 +21,37 @@
@Tag(name = "入库")
@RequestMapping("/stockInRecord")
@RequiredArgsConstructor
public class StockInRecordController {
public class StockInRecordController extends BaseController {
    private final StockInRecordService stockInRecordService;
    @GetMapping("/listPage")
    @Log(title = "生产入库-入库管理-列表", businessType = BusinessType.OTHER)
    @Operation(summary = "入库管理列表")
    public AjaxResult listPage(Page page, StockInRecordDto stockInRecordDto) {
    public R<?> listPage(Page page, StockInRecordDto stockInRecordDto) {
        IPage<StockInRecordDto> result = stockInRecordService.listPage(page, stockInRecordDto);
        return AjaxResult.success(result);
        return R.ok(result);
    }
    @DeleteMapping("")
    @Log(title = "入库管理-删除入库", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
    public R<?> delete(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        return AjaxResult.success(stockInRecordService.batchDelete(ids));
        return R.ok(stockInRecordService.batchDelete(ids));
    }
    @DeleteMapping("/pending")
    @Log(title = "入库管理-删除待审批入库", businessType = BusinessType.DELETE)
    @Operation(summary = "删除待审批的入库记录")
    public AjaxResult deletePending(@RequestBody List<Long> ids) {
    public R<?> deletePending(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        return AjaxResult.success(stockInRecordService.batchDeletePending(ids));
        return R.ok(stockInRecordService.batchDeletePending(ids));
    }
    @PostMapping("/exportStockInRecord")
@@ -62,12 +63,12 @@
    @PostMapping("/approve")
    @Log(title = "入库管理-审批入库", businessType = BusinessType.UPDATE)
    @Operation(summary = "批量审批入库记录")
    public AjaxResult approve(@RequestBody StockInRecordDto approveDto) {
    public R<?> approve(@RequestBody StockInRecordDto approveDto) {
        if(CollectionUtils.isEmpty(approveDto.getIds())){
            return AjaxResult.error("请选择至少一条数据");
            return R.fail("请选择至少一条数据");
        }
        stockInRecordService.batchApprove(approveDto.getIds(), approveDto.getApprovalStatus());
        return AjaxResult.success();
        return R.ok();
    }
}
在上述文件截断后对比
src/main/java/com/ruoyi/stock/controller/StockOutRecordController.java src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java src/main/java/com/ruoyi/technology/controller/TechnologyOperationParamController.java src/main/java/com/ruoyi/warehouse/controller/DocumentClassificationController.java src/main/java/com/ruoyi/warehouse/controller/DocumentationBorrowManagementController.java src/main/java/com/ruoyi/warehouse/controller/DocumentationController.java src/main/java/com/ruoyi/warehouse/controller/DocumentationFileController.java src/main/java/com/ruoyi/warehouse/controller/WarehouseController.java src/main/java/com/ruoyi/warehouse/controller/WarehouseGoodsShelvesController.java src/main/java/com/ruoyi/warehouse/controller/WarehouseGoodsShelvesRowcolController.java src/main/java/com/ruoyi/waterrecord/controller/WaterRecordController.java src/main/java/com/ruoyi/waterrecord/service/WaterRecordService.java src/main/java/com/ruoyi/waterrecord/service/impl/WaterRecordServiceImpl.java src/main/resources/application-dev.yml src/main/resources/approve-todo-agent-prompt.txt src/main/resources/manufacturing-agent-prompt.txt src/main/resources/mapper/account/financial/AccountSubjectMapper.xml src/main/resources/mapper/basic/CustomerMapper.xml src/main/resources/mapper/procurementrecord/ReturnManagementMapper.xml src/main/resources/mapper/production/ProductionOperationTaskMapper.xml src/main/resources/mapper/production/ProductionOrderMapper.xml src/main/resources/mapper/purchase/PurchaseReturnOrdersMapper.xml src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml src/main/resources/mapper/stock/StockInRecordMapper.xml src/main/resources/mapper/stock/StockInventoryMapper.xml src/main/resources/mapper/stock/StockOutRecordMapper.xml src/main/resources/purchase-agent-prompt.txt src/main/resources/sales-agent-prompt.txt src/main/resources/static/销售台账导入模板.xlsx