From f8b236340b16d9dfe2ca88407343ac01f34f3cbf Mon Sep 17 00:00:00 2001
From: zss <zss@example.com>
Date: 星期四, 21 五月 2026 15:09:42 +0800
Subject: [PATCH] Merge branch 'dev_New_pro' into dev_New_pro_财务
---
src/main/java/com/ruoyi/ai/assistant/SalesAgent.java | 4
src/main/java/com/ruoyi/home/controller/HomeController.java | 146 +++++-
src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java | 64 ++
src/main/resources/manufacturing-agent-prompt.txt | 2
doc/20260521_首页HomeController接口升级前端变更文档.md | 113 +++++
src/main/java/com/ruoyi/ai/controller/SalesAiController.java | 12
src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java | 5
doc/20260521_采购智能体优化前端变更文档.md | 85 ++++
src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java | 149 ++++++
src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java | 2
src/main/resources/approve-todo-agent-prompt.txt | 2
src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java | 3
src/main/java/com/ruoyi/quality/controller/QualityReportController.java | 34 +
src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java | 3
src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java | 12
src/main/java/com/ruoyi/ai/service/PurchaseAiService.java | 64 ++
src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java | 10
src/main/resources/mapper/production/ProductionOrderMapper.xml | 30 +
src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java | 18
src/main/resources/purchase-agent-prompt.txt | 9
src/main/resources/sales-agent-prompt.txt | 2
src/main/resources/mapper/production/ProductionOperationTaskMapper.xml | 3
src/main/java/com/ruoyi/quality/controller/QualityInspectController.java | 10
src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java | 9
src/main/java/com/ruoyi/ai/assistant/PurchaseIntentExecutor.java | 249 ++++++++--
src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java | 2
src/main/java/com/ruoyi/ai/controller/XiaozhiController.java | 11
src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java | 3
src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java | 5
src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java | 3
src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java | 6
src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java | 3
src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java | 137 ++++++
33 files changed, 1,071 insertions(+), 139 deletions(-)
diff --git "a/doc/20260521_\351\207\207\350\264\255\346\231\272\350\203\275\344\275\223\344\274\230\345\214\226\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md" "b/doc/20260521_\351\207\207\350\264\255\346\231\272\350\203\275\344\275\223\344\274\230\345\214\226\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..58089e8
--- /dev/null
+++ "b/doc/20260521_\351\207\207\350\264\255\346\231\272\350\203\275\344\275\223\344\274\230\345\214\226\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
@@ -0,0 +1,85 @@
+# 閲囪喘鏅鸿兘浣撲紭鍖栧墠绔彉鏇存枃妗�
+
+## 1. 鍙樻洿鑳屾櫙
+
+鏈閽堝閲囪喘鏅鸿兘浣撳仛浜嗗榻愪紭鍖栵紙鍙傝�冮攢鍞�/瀹℃壒/鍒堕�犳櫤鑳戒綋锛夛細
+
+1. 鎻愬崌 `quickPrompts` 鍛戒腑绋冲畾鎬с��
+2. 澧炲己鐩稿鏃堕棿璇嗗埆锛堜粖澶�/鏄ㄥぉ/鏈懆/涓婂懆/鏈湀/涓婃湀/浠婂勾/鍘诲勾/杩慛澶╃瓑锛夈��
+3. 澧炲姞涓氬姟鎰忓浘鏈瘑鍒椂鐨勭粨鏋勫寲鍏滃簳鍝嶅簲锛岄伩鍏嶇紪閫犳暟鎹��
+4. 琛ュ厖寰呬粯娆炬煡璇㈢殑姹囨�诲瓧娈碉紝渚夸簬鍓嶇鐩存帴娓叉煋缁熻鍗$墖銆�
+
+## 2. 鎺ュ彛褰卞搷姒傝
+
+| 鎺ュ彛 | 鏂规硶 | 鏄惁鏀硅矾寰� | 鏄惁鏀瑰叆鍙� | 鏄惁鏀硅繑鍥炵粨鏋� |
+| --- | --- | --- | --- | --- |
+| `/purchase-ai/chat` | POST(SSE) | 鍚� | 鍚� | 鏄紙鏂板鍏滃簳 JSON 绫诲瀷锛� |
+| `/purchase-ai/analyze-files` | POST(SSE) | 鍚� | 鍚� | 鍚︼紙浠呭唴閮ㄦ彁绀鸿瘝澧炲己锛� |
+
+## 3. 鏂板鍏滃簳鍝嶅簲锛堥噸鐐癸級
+
+褰撶敤鎴锋槑鏄惧湪闂噰璐笟鍔★紝浣嗘潯浠朵笉鍏呭垎涓旀湭鍛戒腑鍙墽琛屾剰鍥炬椂锛宍/purchase-ai/chat` 浼氱洿鎺ヨ繑鍥炵粨鏋勫寲 JSON锛堣�屼笉鏄嚜鐢辨枃鏈級锛�
+
+```json
+{
+ "success": false,
+ "type": "purchase_intent_not_recognized",
+ "description": "鏈瘑鍒埌鍙墽琛岀殑閲囪喘鏌ヨ鏉′欢銆備负淇濊瘉缁撴灉鍑嗙‘锛屽綋鍓嶄笉浼氭帹娴嬫垨缂栭�犳暟鎹紝璇疯ˉ鍏呮槑纭椂闂磋寖鍥淬�佷緵搴斿晢銆侀噰璐悎鍚屽彿鎴栫墿鏂欏悗鍐嶆煡璇€��",
+ "summary": {},
+ "data": {
+ "quickPrompts": [
+ "鏈湀閲囪喘閲戦鎺掑悕鍓嶅崄鐨勭墿鏂欐湁鍝簺锛�",
+ "鍝簺閲囪喘璁㈠崟杩樻湭鍏ュ簱锛�",
+ "鏈�杩�7澶╀緵搴斿晢鍒拌揣寮傚父鏈夊摢浜涳紵",
+ "甯垜缁熻寰呬粯娆鹃噰璐崟锛�",
+ "鍒楀嚭鏈湀閲囪喘閫�璐ф儏鍐�"
+ ]
+ },
+ "charts": {}
+}
+```
+
+鍓嶇澶勭悊寤鸿锛�
+
+1. 褰� `type === "purchase_intent_not_recognized"` 鏃讹紝灞曠ず `description`銆�
+2. 璇诲彇 `data.quickPrompts` 浣滀负蹇嵎鎻愰棶鎸夐挳锛堝彲鐩存帴鍥炲~杈撳叆妗嗭級銆�
+
+## 4. 寰呬粯娆捐繑鍥炴柊澧炴眹鎬诲瓧娈�
+
+鎺ュ彛绫诲瀷锛歚type = "purchase_pending_payment_list"`
+浣嶇疆锛歚summary`
+
+鏂板瀛楁锛�
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+| --- | --- | --- |
+| pendingOrderCount | number | 寰呬粯娆捐鍗曟暟 |
+| totalContractAmount | number | 寰呬粯娆捐鍗曞悎鍚屾�婚 |
+| totalPaidAmount | number | 宸蹭粯娆炬�婚 |
+| totalPendingAmount | number | 寰呬粯娆炬�婚 |
+
+璇存槑锛氬師鏈夊瓧娈典粛淇濈暀锛堝吋瀹癸級锛屾湰娆′负澧為噺瀛楁锛屼笉鐮村潖鐜版湁娓叉煋銆�
+
+## 5. 鏃堕棿鍙e緞浼樺寲
+
+閲囪喘鏅鸿兘浣撶幇鍦ㄧ粺涓�鎸変腑鍥芥椂鍖哄姩鎬佹棩鏈熸崲绠楃浉瀵规椂闂达紝鏀寔锛�
+
+- 浠婂ぉ銆佹槰澶�
+- 鏈懆銆佷笂鍛�
+- 鏈湀銆佷笂鏈�
+- 浠婂勾銆佸幓骞�
+- 杩慛澶�/鍛�/鏈�/骞淬�佽繎鍗婂勾銆佽繎鍗婁釜鏈�
+
+鍓嶇鏃犻渶鏀逛紶鍙傦紝浣嗗睍绀烘椂闂磋寖鍥存椂璇蜂互鍚庣杩斿洖 `summary.startDate/endDate/timeRange` 涓哄噯銆�
+
+## 6. 鍓嶇鑱旇皟妫�鏌ユ竻鍗�
+
+1. `chat` 娴佸紡缁撴灉鎷兼帴鍚庯紝浼樺厛鎸� JSON 瑙f瀽銆�
+2. 瑕嗙洊鏂扮被鍨� `purchase_intent_not_recognized` 鐨� UI 澶勭悊銆�
+3. 寰呬粯娆鹃〉闈㈣鍙栧苟灞曠ず `summary.totalPendingAmount` 绛夋柊澧炲瓧娈点��
+4. 楠岃瘉浠ヤ笅蹇嵎闂鍙ǔ瀹氳繑鍥炵粨鏋勫寲缁撴灉锛�
+ - 鏈湀閲囪喘閲戦鎺掑悕鍓嶅崄鐨勭墿鏂欐湁鍝簺锛�
+ - 鍝簺閲囪喘璁㈠崟杩樻湭鍏ュ簱锛�
+ - 鏈�杩�7澶╀緵搴斿晢鍒拌揣寮傚父鏈夊摢浜涳紵
+ - 甯垜缁熻寰呬粯娆鹃噰璐崟锛�
+ - 鍒楀嚭鏈湀閲囪喘閫�璐ф儏鍐�
diff --git "a/doc/20260521_\351\246\226\351\241\265HomeController\346\216\245\345\217\243\345\215\207\347\272\247\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md" "b/doc/20260521_\351\246\226\351\241\265HomeController\346\216\245\345\217\243\345\215\207\347\272\247\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..008660f
--- /dev/null
+++ "b/doc/20260521_\351\246\226\351\241\265HomeController\346\216\245\345\217\243\345\215\207\347\272\247\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
@@ -0,0 +1,113 @@
+# 棣栭〉 HomeController 鎺ュ彛鍗囩骇鍓嶇鍙樻洿鏂囨。
+
+鏇存柊鏃堕棿锛�2026-05-21
+閫傜敤妯″潡锛氶椤碉紙`/home`锛�
+
+## 1. 鍙樻洿姒傝
+
+鏈涓� **鍏煎寮忓崌绾�**锛屾棫璋冪敤鏂瑰紡浠嶅彲鐢ㄣ��
+閲嶇偣鏄粰鐢熶骇鐪嬫澘鎺ュ彛澧炲姞鏇存槑纭殑绛涢�夊弬鏁帮紝渚夸簬鍓嶇鎸夋棩鏈熷拰鐘舵�佹煡璇€��
+
+娑夊強鎺ュ彛锛�
+
+1. `GET /home/productionOrderProgress`
+2. `GET /home/todayProductionPlan`
+
+## 2. 鍙傛暟鍙樻洿
+
+### 2.1 鐢熶骇璁㈠崟杩涘害 `GET /home/productionOrderProgress`
+
+鏃у弬鏁帮紙浠嶅吋瀹癸級锛�
+
+- `tab`锛歚all` / `inProgress` / `completed` / `paused`
+- `pageNum`锛氶粯璁� `1`
+- `pageSize`锛氶粯璁� `10`锛屾渶澶� `50`
+
+鏂板鍙傛暟锛�
+
+- `status`锛堝彲閫夛級锛氱姸鎬佺瓫閫夛紝浼樺厛绾ч珮浜� `tab`
+ 鍙�夊�硷細`all` / `waiting` / `inProgress` / `completed` / `paused` / `1` / `2` / `3` / `4`
+- `bizDate`锛堝彲閫夛級锛氫笟鍔℃棩鏈熺瓫閫夛紝鏍煎紡 `yyyy-MM-dd`锛堟寜璁㈠崟鍒涘缓鏃堕棿杩囨护锛�
+
+鍙傛暟浼樺厛绾э細
+
+1. 濡傛灉浼犱簡 `status`锛屽悗绔紭鍏堟寜 `status` 瑙f瀽锛�
+2. 鏈紶 `status` 鏃讹紝娌跨敤鍘熸湁 `tab` 琛屼负锛�
+3. `status` 鎴� `bizDate` 鏍煎紡閿欒鏃惰繑鍥炲け璐ヤ俊鎭��
+
+璇锋眰绀轰緥锛�
+
+```http
+GET /home/productionOrderProgress?status=completed&bizDate=2026-05-20&pageNum=1&pageSize=10
+```
+
+### 2.2 浠婃棩鐢熶骇璁″垝 `GET /home/todayProductionPlan`
+
+鏃у弬鏁帮紙浠嶅吋瀹癸級锛�
+
+- `limit`锛氶粯璁� `4`锛屾渶澶� `20`
+
+鏂板鍙傛暟锛�
+
+- `planDate`锛堝彲閫夛級锛氳鍒掓棩鏈熺瓫閫夛紝鏍煎紡 `yyyy-MM-dd`锛堟寜 `plan_complete_time` 杩囨护锛�
+
+璇锋眰绀轰緥锛�
+
+```http
+GET /home/todayProductionPlan?limit=6&planDate=2026-05-21
+```
+
+## 3. 杩斿洖缁撴瀯鍙樻洿
+
+### 3.1 `productionOrderProgress` 杩斿洖鏂板瀛楁
+
+鏂板锛�
+
+- `status`锛氭爣鍑嗗寲鐘舵�佸洖鏄撅紙`all` / `waiting` / `inProgress` / `completed` / `paused`锛�
+- `bizDate`锛氭棩鏈熺瓫閫夊洖鏄撅紙鏈紶鏃朵负 `null`锛�
+- `waitingCount`锛氬緟寮�濮嬭鍗曟暟閲�
+
+鍏煎淇濈暀锛�
+
+- `tab` 瀛楁缁х画杩斿洖锛堣�侀〉闈㈡棤闇�鏀瑰姩鍙户缁娇鐢級
+
+杩斿洖绀轰緥锛�
+
+```json
+{
+ "tab": "completed",
+ "status": "completed",
+ "bizDate": "2026-05-20",
+ "total": 24,
+ "pageNum": 1,
+ "pageSize": 10,
+ "waitingCount": 3,
+ "inProgressCount": 6,
+ "completedCount": 12,
+ "pausedCount": 2,
+ "records": []
+}
+```
+
+### 3.2 `todayProductionPlan` 杩斿洖鏂板瀛楁
+
+鏂板锛�
+
+- `planDate`锛氭棩鏈熺瓫閫夊洖鏄撅紙鏈紶鏃朵负 `null`锛�
+
+杩斿洖绀轰緥锛�
+
+```json
+{
+ "planDate": "2026-05-21",
+ "total": 9,
+ "records": []
+}
+```
+
+## 4. 鍓嶇鏀归�犲缓璁�
+
+1. 鏂伴〉闈㈠缓璁紭鍏堜紶 `status`锛岄�愭鏇夸唬 `tab`銆�
+2. 闇�瑕佹寜鏃ユ湡澶嶇洏鐪嬫澘鏃讹紝浣跨敤 `bizDate` / `planDate`銆�
+3. 鑰侀〉闈㈠彲涓嶆敼锛岀户缁部鐢ㄥ師鍙傛暟涔熻兘姝e父鑱旇皟銆�
+
diff --git a/src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java b/src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java
index 3b37909..bad0e0a 100644
--- a/src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java
+++ b/src/main/java/com/ruoyi/ai/assistant/ApproveTodoAgent.java
@@ -3,6 +3,7 @@
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
+import dev.langchain4j.service.V;
import dev.langchain4j.service.spring.AiService;
import reactor.core.publisher.Flux;
@@ -16,5 +17,5 @@
public interface ApproveTodoAgent {
@SystemMessage(fromResource = "approve-todo-agent-prompt.txt")
- Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage);
+ Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage, @V("currentDate") String currentDate);
}
diff --git a/src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java b/src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java
index f0e8cf7..0d16703 100644
--- a/src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java
+++ b/src/main/java/com/ruoyi/ai/assistant/ManufacturingAgent.java
@@ -3,6 +3,7 @@
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
+import dev.langchain4j.service.V;
import dev.langchain4j.service.spring.AiService;
import reactor.core.publisher.Flux;
@@ -17,5 +18,5 @@
public interface ManufacturingAgent {
@SystemMessage(fromResource = "manufacturing-agent-prompt.txt")
- Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage);
+ Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage, @V("currentDate") String currentDate);
}
diff --git a/src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java b/src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java
index 6a4ff4e..421261d 100644
--- a/src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java
+++ b/src/main/java/com/ruoyi/ai/assistant/PurchaseAgent.java
@@ -3,6 +3,7 @@
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
+import dev.langchain4j.service.V;
import dev.langchain4j.service.spring.AiService;
import reactor.core.publisher.Flux;
@@ -17,5 +18,5 @@
public interface PurchaseAgent {
@SystemMessage(fromResource = "purchase-agent-prompt.txt")
- Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage);
+ Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage, @V("currentDate") String currentDate);
}
diff --git a/src/main/java/com/ruoyi/ai/assistant/PurchaseIntentExecutor.java b/src/main/java/com/ruoyi/ai/assistant/PurchaseIntentExecutor.java
index 5991fc3..c04915e 100644
--- a/src/main/java/com/ruoyi/ai/assistant/PurchaseIntentExecutor.java
+++ b/src/main/java/com/ruoyi/ai/assistant/PurchaseIntentExecutor.java
@@ -4,6 +4,9 @@
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -11,8 +14,12 @@
public class PurchaseIntentExecutor {
private static final Pattern ID_PATTERN = Pattern.compile("\\b\\d{1,12}\\b");
- private static final Pattern LIMIT_PATTERN = Pattern.compile("(鍓峾鏈�杩�)?(\\d{1,2})鏉�");
- private static final Pattern DATE_PATTERN = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
+ private static final Pattern LIMIT_PATTERN = Pattern.compile("(鍓峾鏈�杩�)?\\s*(\\d{1,2})\\s*鏉�");
+ private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2})");
+ private static final Pattern RELATIVE_RANGE_PATTERN = Pattern.compile("(杩憒鏈�杩�)\\s*(\\d{1,3})\\s*(澶﹟鍛▅涓湀|鏈坾骞�)");
+ private static final Pattern HALF_RANGE_PATTERN = Pattern.compile("(鏈�杩憒杩�)?鍗�(涓�)?(鏈坾骞�)");
+ private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ private static final ZoneId CHINA_ZONE_ID = ZoneId.of("Asia/Shanghai");
private final PurchaseAgentTools purchaseAgentTools;
@@ -25,71 +32,63 @@
return null;
}
String text = message.trim();
+ String quickPromptResponse = tryExecuteQuickPrompt(memoryId, text);
+ if (StringUtils.hasText(quickPromptResponse)) {
+ return quickPromptResponse;
+ }
- if (containsAny(text, "鎺掕", "鎺掑悕", "鍓嶅嚑", "鍓嶄簲", "鍓嶅崄") && containsAny(text, "鐗╂枡", "浜у搧", "鍘熸潗鏂�", "閲囪喘閲戦", "閲戦")) {
- return purchaseAgentTools.rankPurchaseMaterials(
- memoryId,
- extractStartDate(text),
- extractEndDate(text),
- text,
- extractLimit(text)
- );
+ String keyword = extractKeyword(text);
+ Integer limit = extractLimit(text);
+ DateRange dateRange = extractDateRange(text);
+ String startDate = dateRange.startDate();
+ String endDate = dateRange.endDate();
+
+ if (containsAny(text, "鎺掕", "鎺掑悕", "鍓嶅嚑", "鍓嶄簲", "鍓嶅崄")
+ && containsAny(text, "鐗╂枡", "浜у搧", "鍘熸潗鏂�", "閲囪喘閲戦", "閲戦")) {
+ return purchaseAgentTools.rankPurchaseMaterials(memoryId, startDate, endDate, text, limit);
}
if (containsAny(text, "鏈叆搴�", "寰呭叆搴�", "娌℃湁鍏ュ簱", "杩樻湭鍏ュ簱")) {
- return purchaseAgentTools.listUnstockedPurchaseOrders(
- memoryId,
- extractStartDate(text),
- extractEndDate(text),
- extractKeyword(text),
- extractLimit(text)
- );
+ return purchaseAgentTools.listUnstockedPurchaseOrders(memoryId, startDate, endDate, keyword, limit);
}
if (containsAny(text, "鍒拌揣寮傚父", "鍒拌揣鏈夊紓甯�", "寮傚父鍒拌揣", "鍒拌揣闂", "渚涘簲鍟嗗埌璐у紓甯�")) {
- return purchaseAgentTools.listArrivalExceptions(
- memoryId,
- extractStartDate(text),
- extractEndDate(text),
- text,
- extractLimit(text)
- );
+ return purchaseAgentTools.listArrivalExceptions(memoryId, startDate, endDate, text, limit);
}
if (containsAny(text, "寰呬粯娆�", "鏈粯娆�", "鏈粯娓�", "寰呮敮浠�", "搴斾粯")) {
- return purchaseAgentTools.listPendingPaymentOrders(
- memoryId,
- extractStartDate(text),
- extractEndDate(text),
- extractKeyword(text),
- extractLimit(text)
- );
+ return purchaseAgentTools.listPendingPaymentOrders(memoryId, startDate, endDate, keyword, limit);
}
if (containsAny(text, "閫�璐�", "閫�鏂�", "鎷掓敹")) {
- return purchaseAgentTools.listPurchaseReturns(
- memoryId,
- extractStartDate(text),
- extractEndDate(text),
- extractKeyword(text),
- extractLimit(text)
- );
+ return purchaseAgentTools.listPurchaseReturns(memoryId, startDate, endDate, keyword, limit);
}
if (isStatsIntent(text)) {
- return purchaseAgentTools.getPurchaseStats(
- memoryId,
- extractStartDate(text),
- extractEndDate(text),
- text
- );
+ return purchaseAgentTools.getPurchaseStats(memoryId, startDate, endDate, text);
}
- if (containsAny(text, "璇︽儏", "鏄庣粏") && extractId(text) != null) {
- return purchaseAgentTools.getPurchaseLedgerDetail(memoryId, extractId(text));
+
+ Long ledgerId = extractId(text);
+ if (containsAny(text, "璇︽儏", "鏄庣粏") && ledgerId != null) {
+ return purchaseAgentTools.getPurchaseLedgerDetail(memoryId, ledgerId);
}
if (containsAny(text, "鍙拌处", "閲囪喘鍗�", "閲囪喘璁㈠崟", "璁㈠崟", "鍚堝悓", "鍒楄〃", "鏌ヨ")) {
- return purchaseAgentTools.listPurchaseLedgers(
- memoryId,
- extractKeyword(text),
- extractStartDate(text),
- extractEndDate(text),
- extractLimit(text)
- );
+ return purchaseAgentTools.listPurchaseLedgers(memoryId, keyword, startDate, endDate, limit);
+ }
+ return null;
+ }
+
+ private String tryExecuteQuickPrompt(String memoryId, String text) {
+ String normalized = normalizeForMatch(text);
+ if ("鏈湀閲囪喘閲戦鎺掑悕鍓嶅崄鐨勭墿鏂欐湁鍝簺".equals(normalized)) {
+ return purchaseAgentTools.rankPurchaseMaterials(memoryId, null, null, "鏈湀", 10);
+ }
+ if ("鍝簺閲囪喘璁㈠崟杩樻湭鍏ュ簱".equals(normalized)) {
+ return purchaseAgentTools.listUnstockedPurchaseOrders(memoryId, null, null, null, 10);
+ }
+ if ("鏈�杩�7澶╀緵搴斿晢鍒拌揣寮傚父鏈夊摢浜�".equals(normalized)) {
+ return purchaseAgentTools.listArrivalExceptions(memoryId, null, null, "鏈�杩�7澶�", 10);
+ }
+ if ("甯垜缁熻寰呬粯娆鹃噰璐崟".equals(normalized)) {
+ return purchaseAgentTools.listPendingPaymentOrders(memoryId, null, null, null, 10);
+ }
+ if ("鍒楀嚭鏈湀閲囪喘閫�璐ф儏鍐�".equals(normalized)) {
+ return purchaseAgentTools.listPurchaseReturns(memoryId, null, null, null, 10);
}
return null;
}
@@ -100,8 +99,10 @@
}
boolean queryWord = containsAny(text, "鏌ヨ", "鏌ョ湅", "鐪嬩笅", "鐪嬬湅", "鑾峰彇");
boolean dataWord = containsAny(text, "鏁版嵁", "閲戦", "鏁伴噺", "鍚堝悓棰�", "浠樻棰�", "鍙戠エ棰�");
- boolean timeWord = containsAny(text, "浠婂ぉ", "鏈懆", "鏈湀", "涓婃湀", "浠婂勾", "鍘诲勾", "杩戝崐骞�", "鏈�杩戝崐涓湀", "鍗婁釜鏈�")
- || DATE_PATTERN.matcher(text).find();
+ boolean timeWord = containsAny(text, "浠婂ぉ", "鏄ㄥぉ", "鏈懆", "涓婂懆", "鏈湀", "涓婃湀", "浠婂勾", "鍘诲勾", "杩戝崐骞�", "鏈�杩戝崐涓湀", "鍗婁釜鏈�")
+ || DATE_PATTERN.matcher(text).find()
+ || RELATIVE_RANGE_PATTERN.matcher(text).find()
+ || HALF_RANGE_PATTERN.matcher(text).find();
return queryWord && dataWord && timeWord;
}
@@ -127,23 +128,125 @@
return matcher.find() ? Integer.parseInt(matcher.group(2)) : 10;
}
- private String extractStartDate(String text) {
+ private DateRange extractDateRange(String text) {
Matcher matcher = DATE_PATTERN.matcher(text);
- return matcher.find() ? matcher.group() : null;
+ if (matcher.find()) {
+ String first = matcher.group(1);
+ String second = matcher.find() ? matcher.group(1) : first;
+ return buildDateRange(first, second);
+ }
+
+ LocalDate today = LocalDate.now(CHINA_ZONE_ID);
+ if (text.contains("浠婂ぉ")) {
+ return new DateRange(formatDate(today), formatDate(today));
+ }
+ if (text.contains("鏄ㄥぉ")) {
+ LocalDate yesterday = today.minusDays(1);
+ return new DateRange(formatDate(yesterday), formatDate(yesterday));
+ }
+ if (text.contains("鏈懆")) {
+ LocalDate start = today.minusDays(today.getDayOfWeek().getValue() - 1L);
+ return new DateRange(formatDate(start), formatDate(today));
+ }
+ if (text.contains("涓婂懆")) {
+ LocalDate thisWeekStart = today.minusDays(today.getDayOfWeek().getValue() - 1L);
+ LocalDate start = thisWeekStart.minusWeeks(1);
+ LocalDate end = start.plusDays(6);
+ return new DateRange(formatDate(start), formatDate(end));
+ }
+ if (text.contains("鏈湀")) {
+ return new DateRange(formatDate(today.withDayOfMonth(1)), formatDate(today));
+ }
+ if (text.contains("涓婃湀")) {
+ LocalDate start = today.minusMonths(1).withDayOfMonth(1);
+ return new DateRange(formatDate(start), formatDate(start.withDayOfMonth(start.lengthOfMonth())));
+ }
+ if (text.contains("浠婂勾") || text.contains("鏈勾")) {
+ return new DateRange(formatDate(today.withDayOfYear(1)), formatDate(today));
+ }
+ if (text.contains("鍘诲勾")) {
+ LocalDate start = today.minusYears(1).withDayOfYear(1);
+ LocalDate end = start.withDayOfYear(start.lengthOfYear());
+ return new DateRange(formatDate(start), formatDate(end));
+ }
+ if (containsAny(text, "杩戝崐骞�", "鏈�杩戝崐骞�")) {
+ return new DateRange(formatDate(today.minusMonths(6).plusDays(1)), formatDate(today));
+ }
+ if (containsAny(text, "杩戝崐涓湀", "鏈�杩戝崐涓湀", "鍗婁釜鏈�")) {
+ return new DateRange(formatDate(today.minusDays(14)), formatDate(today));
+ }
+
+ Matcher relativeMatcher = RELATIVE_RANGE_PATTERN.matcher(text);
+ if (relativeMatcher.find()) {
+ int amount = Integer.parseInt(relativeMatcher.group(2));
+ String unit = relativeMatcher.group(3);
+ LocalDate start = switch (unit) {
+ case "澶�" -> today.minusDays(Math.max(amount - 1L, 0));
+ case "鍛�" -> today.minusWeeks(Math.max(amount, 1)).plusDays(1);
+ case "涓湀", "鏈�" -> today.minusMonths(Math.max(amount, 1)).plusDays(1);
+ case "骞�" -> today.minusYears(Math.max(amount, 1)).plusDays(1);
+ default -> today.minusDays(29);
+ };
+ return new DateRange(formatDate(start), formatDate(today));
+ }
+
+ return new DateRange(null, null);
}
- private String extractEndDate(String text) {
- Matcher matcher = DATE_PATTERN.matcher(text);
- if (!matcher.find()) {
+ private DateRange buildDateRange(String start, String end) {
+ LocalDate startDate = parseDate(start);
+ LocalDate endDate = parseDate(end);
+ if (startDate == null || endDate == null) {
+ return new DateRange(null, null);
+ }
+ if (startDate.isAfter(endDate)) {
+ LocalDate temp = startDate;
+ startDate = endDate;
+ endDate = temp;
+ }
+ return new DateRange(formatDate(startDate), formatDate(endDate));
+ }
+
+ private LocalDate parseDate(String text) {
+ try {
+ return LocalDate.parse(text, DATE_FMT);
+ } catch (Exception ignored) {
return null;
}
- return matcher.find() ? matcher.group() : null;
+ }
+
+ private String formatDate(LocalDate date) {
+ return date == null ? null : date.format(DATE_FMT);
+ }
+
+ private String normalizeForMatch(String text) {
+ if (!StringUtils.hasText(text)) {
+ return "";
+ }
+ return text.replace("锛�", "")
+ .replace(",", "")
+ .replace("銆�", "")
+ .replace(".", "")
+ .replace("锛�", "")
+ .replace("!", "")
+ .replace("锛�", "")
+ .replace("?", "")
+ .replace("锛�", "")
+ .replace(":", "")
+ .replace("锛�", "")
+ .replace(";", "")
+ .replace(" ", "")
+ .trim();
}
private String extractKeyword(String text) {
String cleaned = text
.replace("鏌ヨ", "")
.replace("鏌ョ湅", "")
+ .replace("鐪嬩笅", "")
+ .replace("鐪嬬湅", "")
+ .replace("璇�", "")
+ .replace("涓�涓�", "")
.replace("閲囪喘", "")
.replace("閲囪喘鍗�", "")
.replace("閲囪喘璁㈠崟", "")
@@ -153,9 +256,33 @@
.replace("鍝簺", "")
.replace("鍒楀嚭", "")
.replace("甯垜", "")
+ .replace("缁熻", "")
+ .replace("鍒嗘瀽", "")
+ .replace("鏈湀", "")
+ .replace("涓婃湀", "")
+ .replace("鏈勾", "")
+ .replace("浠婂勾", "")
+ .replace("鍘诲勾", "")
+ .replace("鏈懆", "")
+ .replace("涓婂懆", "")
+ .replace("浠婂ぉ", "")
+ .replace("鏄ㄥぉ", "")
+ .replace("杩�30澶�", "")
+ .replace("杩�7澶�", "")
+ .replace("杩�15澶�", "")
+ .replace("杩�60澶�", "")
+ .replace("鏈�杩�30澶�", "")
+ .replace("鏈�杩�7澶�", "")
+ .replace("鏈�杩�15澶�", "")
+ .replace("鏈�杩�60澶�", "")
.replace("鏈�杩�10鏉�", "")
.replace("鍓�10鏉�", "")
+ .replace("鍓�20鏉�", "")
+ .replace("鏈�杩�20鏉�", "")
.trim();
return cleaned.length() >= 2 ? cleaned : null;
}
+
+ private record DateRange(String startDate, String endDate) {
+ }
}
diff --git a/src/main/java/com/ruoyi/ai/assistant/SalesAgent.java b/src/main/java/com/ruoyi/ai/assistant/SalesAgent.java
index 1636239..e2f9a81 100644
--- a/src/main/java/com/ruoyi/ai/assistant/SalesAgent.java
+++ b/src/main/java/com/ruoyi/ai/assistant/SalesAgent.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,6 +18,5 @@
public interface SalesAgent {
@SystemMessage(fromResource = "sales-agent-prompt.txt")
- Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage);
+ Flux<String> chat(@MemoryId String memoryId, @UserMessage String userMessage, @V("currentDate") String currentDate);
}
-
diff --git a/src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java b/src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java
index cb7c0ba..87eb418 100644
--- a/src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java
+++ b/src/main/java/com/ruoyi/ai/controller/ManufacturingAiController.java
@@ -24,12 +24,18 @@
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.util.List;
@Tag(name = "鍒堕�犳櫤鑳藉姪鎵�")
@RestController
@RequestMapping("/manufacturing-ai")
public class ManufacturingAiController extends BaseController {
+
+ private static final DateTimeFormatter CURRENT_DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ private static final ZoneId CHINA_ZONE_ID = ZoneId.of("Asia/Shanghai");
private final ManufacturingAgent manufacturingAgent;
private final ManufacturingIntentExecutor manufacturingIntentExecutor;
@@ -76,7 +82,7 @@
return Flux.just(directResponse);
}
- return manufacturingAgent.chat(memoryId, userMessage)
+ return manufacturingAgent.chat(memoryId, userMessage, currentDateForPrompt())
.doOnComplete(() -> aiChatSessionService.refreshSessionStats(memoryId, loginUser))
.doOnError(ex -> aiChatSessionService.refreshSessionStats(memoryId, loginUser));
}
@@ -99,4 +105,8 @@
aiSessionUserContext.remove(memoryId);
return toAjax(aiChatSessionService.deleteCurrentUserSession(memoryId, SecurityUtils.getLoginUser()));
}
+
+ private String currentDateForPrompt() {
+ return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT);
+ }
}
diff --git a/src/main/java/com/ruoyi/ai/controller/SalesAiController.java b/src/main/java/com/ruoyi/ai/controller/SalesAiController.java
index c3a569b..0c92ad6 100644
--- a/src/main/java/com/ruoyi/ai/controller/SalesAiController.java
+++ b/src/main/java/com/ruoyi/ai/controller/SalesAiController.java
@@ -24,12 +24,18 @@
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.util.List;
@Tag(name = "閿�鍞姪鎵嬫櫤鑳戒綋")
@RestController
@RequestMapping("/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;
@@ -86,7 +92,7 @@
return Flux.just(noGuessResponse);
}
- return salesAgent.chat(memoryId, userMessage)
+ return salesAgent.chat(memoryId, userMessage, currentDateForPrompt())
.doOnComplete(() -> aiChatSessionService.refreshSessionStats(memoryId, loginUser))
.doOnError(ex -> aiChatSessionService.refreshSessionStats(memoryId, loginUser));
}
@@ -128,4 +134,8 @@
}
return false;
}
+
+ private String currentDateForPrompt() {
+ return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT);
+ }
}
diff --git a/src/main/java/com/ruoyi/ai/controller/XiaozhiController.java b/src/main/java/com/ruoyi/ai/controller/XiaozhiController.java
index affa347..82d088c 100644
--- a/src/main/java/com/ruoyi/ai/controller/XiaozhiController.java
+++ b/src/main/java/com/ruoyi/ai/controller/XiaozhiController.java
@@ -29,6 +29,9 @@
import reactor.core.publisher.Flux;
import java.io.IOException;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.UUID;
@@ -39,6 +42,8 @@
public class XiaozhiController extends BaseController {
private static final String FILE_ANALYZE_MEMORY_PREFIX = "file-analyze::";
+ private static final DateTimeFormatter CURRENT_DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ private static final ZoneId CHINA_ZONE_ID = ZoneId.of("Asia/Shanghai");
private final ApproveTodoAgent approveTodoAgent;
private final ApproveTodoIntentExecutor approveTodoIntentExecutor;
@@ -100,7 +105,7 @@
return Flux.just(noGuessResponse);
}
- return approveTodoAgent.chat(memoryId, userMessage)
+ return approveTodoAgent.chat(memoryId, userMessage, currentDateForPrompt())
.doOnComplete(() -> aiChatSessionService.refreshSessionStats(memoryId, loginUser))
.doOnError(ex -> aiChatSessionService.refreshSessionStats(memoryId, loginUser));
}
@@ -190,4 +195,8 @@
}
return false;
}
+
+ private String currentDateForPrompt() {
+ return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT);
+ }
}
diff --git a/src/main/java/com/ruoyi/ai/service/PurchaseAiService.java b/src/main/java/com/ruoyi/ai/service/PurchaseAiService.java
index 47c914b..cbc936c 100644
--- a/src/main/java/com/ruoyi/ai/service/PurchaseAiService.java
+++ b/src/main/java/com/ruoyi/ai/service/PurchaseAiService.java
@@ -1,5 +1,6 @@
package com.ruoyi.ai.service;
+import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -68,6 +69,8 @@
private static final int MAX_FILE_COUNT = 10;
private static final int MAX_SINGLE_FILE_TEXT_LENGTH = 8000;
private static final int MAX_TOTAL_FILE_TEXT_LENGTH = 30000;
+ private static final DateTimeFormatter CURRENT_DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ private static final ZoneId CHINA_ZONE_ID = ZoneId.of("Asia/Shanghai");
private final PurchaseAgent purchaseAgent;
private final PurchaseIntentExecutor purchaseIntentExecutor;
@@ -132,7 +135,17 @@
return Flux.just(directResponse);
}
- return purchaseAgent.chat(memoryId, userMessage)
+ if (isPurchaseBusinessIntent(userMessage)) {
+ String noGuessResponse = buildNoGuessResponse();
+ mongoChatMemoryStore.appendMessages(
+ memoryId,
+ List.of(UserMessage.from(userMessage), AiMessage.from(noGuessResponse))
+ );
+ aiChatSessionService.refreshSessionStats(memoryId, loginUser);
+ return Flux.just(noGuessResponse);
+ }
+
+ return purchaseAgent.chat(memoryId, userMessage, currentDateForPrompt())
.doOnComplete(() -> aiChatSessionService.refreshSessionStats(memoryId, loginUser))
.doOnError(ex -> aiChatSessionService.refreshSessionStats(memoryId, loginUser));
}
@@ -194,10 +207,10 @@
.doOnError(ex -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser));
}
- return Flux.defer(() -> purchaseAgent.chat(finalMemoryId, userPrompt))
+ return Flux.defer(() -> purchaseAgent.chat(finalMemoryId, userPrompt, currentDateForPrompt()))
.onErrorResume(NoSuchElementException.class, ex -> {
mongoChatMemoryStore.deleteMessages(finalMemoryId);
- return purchaseAgent.chat(finalMemoryId, userPrompt);
+ return purchaseAgent.chat(finalMemoryId, userPrompt, currentDateForPrompt());
})
.doOnComplete(() -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser))
.doOnError(ex -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser));
@@ -464,6 +477,51 @@
};
}
+ private String currentDateForPrompt() {
+ return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT);
+ }
+
+ private boolean isPurchaseBusinessIntent(String message) {
+ if (!StringUtils.hasText(message)) {
+ return false;
+ }
+ String text = message.trim();
+ boolean hasDomainWord = containsAny(text,
+ "閲囪喘", "閲囪喘鍙拌处", "閲囪喘鍗�", "閲囪喘璁㈠崟", "渚涘簲鍟�", "鐗╂枡", "鍏ュ簱", "鍒拌揣", "寰呬粯娆�",
+ "浠樻", "閫�璐�", "閫�鏂�", "鍙戠エ", "鍚堝悓");
+ boolean hasIntentWord = containsAny(text,
+ "鏌ヨ", "鏌ョ湅", "缁熻", "鍒嗘瀽", "鎺掕", "鎺掑悕", "鍒楀嚭", "鏈夊摢浜�", "鎯呭喌", "鏄庣粏", "璇︽儏", "鎶ヨ〃");
+ return hasDomainWord && hasIntentWord;
+ }
+
+ private boolean containsAny(String text, String... keywords) {
+ for (String keyword : keywords) {
+ if (text.contains(keyword)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private String buildNoGuessResponse() {
+ Map<String, Object> result = new LinkedHashMap<>();
+ result.put("success", false);
+ result.put("type", "purchase_intent_not_recognized");
+ result.put("description", "鏈瘑鍒埌鍙墽琛岀殑閲囪喘鏌ヨ鏉′欢銆備负淇濊瘉缁撴灉鍑嗙‘锛屽綋鍓嶄笉浼氭帹娴嬫垨缂栭�犳暟鎹紝璇疯ˉ鍏呮槑纭椂闂磋寖鍥淬�佷緵搴斿晢銆侀噰璐悎鍚屽彿鎴栫墿鏂欏悗鍐嶆煡璇€��");
+ result.put("summary", Map.of());
+ result.put("data", Map.of(
+ "quickPrompts", List.of(
+ "鏈湀閲囪喘閲戦鎺掑悕鍓嶅崄鐨勭墿鏂欐湁鍝簺锛�",
+ "鍝簺閲囪喘璁㈠崟杩樻湭鍏ュ簱锛�",
+ "鏈�杩�7澶╀緵搴斿晢鍒拌揣寮傚父鏈夊摢浜涳紵",
+ "甯垜缁熻寰呬粯娆鹃噰璐崟锛�",
+ "鍒楀嚭鏈湀閲囪喘閫�璐ф儏鍐�"
+ )
+ ));
+ result.put("charts", Map.of());
+ return JSON.toJSONString(result);
+ }
+
private String buildPurchaseFileAnalyzePrompt(String message, String fileContent) {
return """
浣犳槸閲囪喘涓氬姟鏂囦欢鍒嗘瀽鍔╂墜銆傝涓ユ牸鏍规嵁鐢ㄦ埛涓婁紶鐨勫涓枃浠跺拰鐢ㄦ埛瑕佹眰鎻愬彇閲囪喘涓氬姟鏁版嵁銆�
diff --git a/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java b/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
index c25aeed..5d0f9ae 100644
--- a/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
+++ b/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
@@ -23,6 +23,7 @@
import java.math.BigDecimal;
import java.time.LocalDate;
+import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
@@ -37,6 +38,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;
@@ -279,8 +281,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 = "鎸夋椂闂磋寖鍥存煡璇㈤噰璐��璐у崟鍒楄〃鍜岄��璐ч噾棰濄��")
@@ -440,6 +458,26 @@
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);
+ wrapper.ge(PaymentRegistration::getPaymentDate, toDate(range.start()))
+ .lt(PaymentRegistration::getPaymentDate, toExclusiveEndDate(range.end()));
+ return defaultList(paymentRegistrationMapper.selectList(wrapper));
+ }
private List<PurchaseReturnOrders> queryReturns(LoginUser loginUser, DateRange range) {
@@ -464,7 +502,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) {
@@ -481,6 +519,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, "浠婂勾");
}
@@ -518,7 +572,11 @@
if (!StringUtils.hasText(text)) {
return null;
}
- return LocalDate.parse(text.trim(), DATE_FMT);
+ try {
+ return LocalDate.parse(text.trim(), DATE_FMT);
+ } catch (Exception ignored) {
+ return null;
+ }
}
private Date toDate(LocalDate localDate) {
diff --git a/src/main/java/com/ruoyi/home/controller/HomeController.java b/src/main/java/com/ruoyi/home/controller/HomeController.java
index 2b3bb32..7878d28 100644
--- a/src/main/java/com/ruoyi/home/controller/HomeController.java
+++ b/src/main/java/com/ruoyi/home/controller/HomeController.java
@@ -16,8 +16,8 @@
import com.ruoyi.production.mapper.ProductionOrderMapper;
import com.ruoyi.production.mapper.ProductionProductOutputMapper;
import com.ruoyi.production.pojo.ProductionOrder;
-import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -28,8 +28,16 @@
import java.math.RoundingMode;
import java.text.ParseException;
import java.time.LocalDate;
+import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import java.util.*;
/**
@@ -40,7 +48,7 @@
@Tag(name = "棣栭〉缁熻")
@RequestMapping("/home")
@AllArgsConstructor
- public class HomeController extends BaseController {
+public class HomeController extends BaseController {
private final HomeService homeService;
private final ProductionOrderMapper productionOrderMapper;
@@ -49,6 +57,7 @@
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;
@@ -58,7 +67,7 @@
@GetMapping("/todos")
@Log(title = "寰呭姙浜嬮」", businessType = BusinessType.OTHER)
@Operation(summary = "寰呭姙浜嬮」")
- public R todos(ApproveProcess req) throws ParseException {
+ public R todos() throws ParseException {
List<ApproveProcess> approveProcessList = homeService.todos();
return R.ok(approveProcessList);
}
@@ -130,7 +139,7 @@
@GetMapping("/business")
@Log(title = "閿�鍞�-閲囪喘-搴撳瓨鏁版嵁", businessType = BusinessType.OTHER)
@Operation(summary = "閿�鍞�-閲囪喘-搴撳瓨鏁版嵁")
- public R business(HomeBusinessDto req) {
+ public R business() {
HomeBusinessDto homeBusinessDto = homeService.business();
return R.ok(homeBusinessDto);
}
@@ -138,7 +147,7 @@
@GetMapping("/analysisCustomerContractAmounts")
@Log(title = "瀹㈡埛鍚堝悓閲戦鍒嗘瀽", businessType = BusinessType.OTHER)
@Operation(summary = "瀹㈡埛鍚堝悓閲戦鍒嗘瀽")
- public R analysisCustomerContractAmounts(AnalysisCustomerContractAmountsDto req) {
+ public R analysisCustomerContractAmounts() {
AnalysisCustomerContractAmountsDto analysisCustomerContractAmounts = homeService.analysisCustomerContractAmounts();
return R.ok(analysisCustomerContractAmounts);
}
@@ -241,13 +250,27 @@
@GetMapping("/productionOrderProgress")
@Operation(summary = "Production Order Progress")
public R productionOrderProgress(@RequestParam(defaultValue = "all") String tab,
- @RequestParam(defaultValue = "1") Long pageNum,
- @RequestParam(defaultValue = "10") Long pageSize) {
+ @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);
- Integer status = resolveOrderStatus(tab);
long offset = (safePageNum - 1) * safePageSize;
- List<Map<String, Object>> rawRows = productionOrderMapper.selectHomeOrderProgressPage(status, offset, 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) {
@@ -255,15 +278,18 @@
}
}
+ long waitingCount = 0L;
long inProgressCount = 0L;
long completedCount = 0L;
long pausedCount = 0L;
- List<Map<String, Object>> statusCountRows = productionOrderMapper.countHomeOrderProgressByStatus();
+ 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_RUNNING)) {
+ 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;
@@ -274,10 +300,13 @@
}
Map<String, Object> result = new LinkedHashMap<>();
- result.put("tab", tab);
- result.put("total", toLong(productionOrderMapper.countHomeOrderProgress(status)));
+ 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);
@@ -287,10 +316,18 @@
@GetMapping("/todayProductionPlan")
@Operation(summary = "Today Production Plan")
- public R todayProductionPlan(@RequestParam(defaultValue = "4") Long limit) {
+ 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);
+ 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<>();
@@ -306,7 +343,8 @@
}
Map<String, Object> result = new LinkedHashMap<>();
- result.put("total", toLong(productionOrderMapper.countHomeTodayProductionPlan()));
+ 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);
}
@@ -367,7 +405,7 @@
@GetMapping("/qualityStatistics")
@Log(title = "璐ㄩ噺鍒嗘瀽", businessType = BusinessType.OTHER)
@Operation(summary = "璐ㄩ噺鍒嗘瀽")
- public R qualityStatistics(QualityStatisticsDto req) {
+ public R qualityStatistics() {
QualityStatisticsDto qualityStatisticsDto = homeService.qualityStatistics();
return R.ok(qualityStatisticsDto);
}
@@ -418,7 +456,7 @@
@GetMapping("/statisticsReceivablePayable")
@Log(title = "搴旀敹搴斾粯缁熻", businessType = BusinessType.OTHER)
@Operation(summary = "搴旀敹搴斾粯缁熻")
- public R statisticsReceivablePayable(StatisticsReceivablePayableDto req, @DefaultType Integer type ) {
+ public R statisticsReceivablePayable(@DefaultType Integer type ) {
StatisticsReceivablePayableDto statisticsReceivablePayable = homeService.statisticsReceivablePayable(type);
return R.ok(statisticsReceivablePayable);
}
@@ -467,21 +505,66 @@
return row;
}
- private Integer resolveOrderStatus(String tab) {
- if (tab == null) {
+ 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 = tab.trim().toLowerCase();
- if ("inprogress".equals(normalized)) {
+ 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 ("completed".equals(normalized)) {
+ if ("3".equals(normalized) || "completed".equals(normalized)) {
return ORDER_STATUS_COMPLETED;
}
- if ("paused".equals(normalized)) {
+ 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) {
@@ -639,6 +722,21 @@
}
}
+ 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;
}
diff --git a/src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java b/src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java
index 965cbf3..8a75dcd 100644
--- a/src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java
+++ b/src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java
@@ -44,4 +44,7 @@
@Schema(description = "缁撴潫鏃ユ湡")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate endDate;
+
+ @Schema(description = "鏄惁鐢熶骇")
+ private Integer isProduction;
}
diff --git a/src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java b/src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java
index dda1aa0..2765c10 100644
--- a/src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java
+++ b/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}")
diff --git a/src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java b/src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java
index fcc9172..cec7ca5 100644
--- a/src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java
+++ b/src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java
@@ -42,14 +42,22 @@
List<Map<String, Object>> selectHomeOrderProgressPage(@Param("status") Integer status,
@Param("offset") Long offset,
- @Param("size") Long size);
+ @Param("size") Long size,
+ @Param("startTime") LocalDateTime startTime,
+ @Param("endTime") LocalDateTime endTime);
- Long countHomeOrderProgress(@Param("status") Integer status);
+ Long countHomeOrderProgress(@Param("status") Integer status,
+ @Param("startTime") LocalDateTime startTime,
+ @Param("endTime") LocalDateTime endTime);
- List<Map<String, Object>> countHomeOrderProgressByStatus();
+ List<Map<String, Object>> countHomeOrderProgressByStatus(@Param("startTime") LocalDateTime startTime,
+ @Param("endTime") LocalDateTime endTime);
- List<Map<String, Object>> selectHomeTodayProductionPlan(@Param("size") Long size);
+ List<Map<String, Object>> selectHomeTodayProductionPlan(@Param("size") Long size,
+ @Param("planStart") LocalDateTime planStart,
+ @Param("planEnd") LocalDateTime planEnd);
- Long countHomeTodayProductionPlan();
+ Long countHomeTodayProductionPlan(@Param("planStart") LocalDateTime planStart,
+ @Param("planEnd") LocalDateTime planEnd);
}
diff --git a/src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java b/src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java
index 2377dc3..8878006 100644
--- a/src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java
+++ b/src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java
@@ -8,6 +8,8 @@
R addRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
+ R updateRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
+
R deleteRouteItem(Long id);
int sortRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
index 31cdc79..c6256a8 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -23,6 +23,7 @@
import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
import com.ruoyi.production.pojo.ProductionProductMain;
import com.ruoyi.production.service.ProductionBomStructureService;
+import com.ruoyi.production.util.TaskPlanQuantityUtil;
import com.ruoyi.technology.mapper.TechnologyOperationMapper;
import com.ruoyi.technology.mapper.TechnologyOperationParamMapper;
import com.ruoyi.technology.mapper.TechnologyParamMapper;
@@ -262,7 +263,7 @@
.filter(item -> item != null && item.getId() != null)
.collect(Collectors.toMap(ProductionOrderRoutingOperation::getId, item -> item, (left, right) -> left));
// Keep task plan quantities aligned with the same order BOM snapshot demand used during snapshot creation.
- Map<String, BigDecimal> demandedQuantityMap = buildOperationDemandedQuantityMap(structureList, rootProductModelId);
+ Map<String, BigDecimal> demandedQuantityMap = TaskPlanQuantityUtil.buildOperationDemandedQuantityMap(structureList, rootProductModelId);
for (ProductionOperationTask task : taskList) {
if (task == null || task.getId() == null || task.getProductionOrderRoutingOperationId() == null) {
continue;
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
index 3d16a07..75d0696 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
@@ -4,21 +4,15 @@
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.framework.web.domain.R;
-import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
-import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
-import com.ruoyi.production.mapper.ProductionOrderRoutingOperationParamMapper;
-import com.ruoyi.production.mapper.ProductionProductMainMapper;
-import com.ruoyi.production.pojo.ProductionOperationTask;
-import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
-import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
-import com.ruoyi.production.pojo.ProductionProductMain;
+import com.ruoyi.production.mapper.*;
+import com.ruoyi.production.util.TaskPlanQuantityUtil;
+import com.ruoyi.technology.mapper.*;
+import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProductionOrderRoutingOperationService;
import com.ruoyi.production.service.ProductionProductMainService;
-import com.ruoyi.technology.mapper.TechnologyOperationParamMapper;
-import com.ruoyi.technology.mapper.TechnologyParamMapper;
-import com.ruoyi.technology.pojo.TechnologyOperationParam;
-import com.ruoyi.technology.pojo.TechnologyParam;
+import com.ruoyi.technology.pojo.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -26,8 +20,7 @@
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
@Service
@Transactional(rollbackFor = Exception.class)
@@ -42,6 +35,11 @@
private final TechnologyOperationParamMapper technologyOperationParamMapper;
private final TechnologyParamMapper technologyParamMapper;
private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
+ private final ProductionOrderMapper productionOrderMapper;
+ private final ProductionOrderRoutingMapper productionOrderRoutingMapper;
+ private final ProductionOrderBomMapper productionOrderBomMapper;
+ private final ProductionBomStructureMapper productionBomStructureMapper;
+ private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
@Override
public R addRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
@@ -102,6 +100,109 @@
productionOperationTaskMapper.insert(productionOperationTask);
}
return R.ok();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public R updateRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
+ Long operationId = productionOrderRoutingOperation.getId();
+
+ // 鏇存柊宸ヨ壓璺嚎宸ュ簭
+ productionOrderRoutingOperationMapper.updateById(productionOrderRoutingOperation);
+
+ // 閲嶆柊鏌ヨ瀹屾暣璁板綍锛堝墠绔彲鑳芥病鏈変紶閫掓墍鏈夊瓧娈碉紝濡� productionOrderId锛�
+ ProductionOrderRoutingOperation updatedOperation = productionOrderRoutingOperationMapper.selectById(operationId);
+ if (updatedOperation == null) {
+ throw new ServiceException("宸ヨ壓璺嚎宸ュ簭涓嶅瓨鍦�");
+ }
+
+ // 鏌ヨ鏄惁瀛樺湪宸ュ崟
+ ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectOne(
+ new LambdaQueryWrapper<ProductionOperationTask>()
+ .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, operationId)
+ .last("limit 1"));
+
+ // 鏍规嵁鏄惁闇�瑕佺敓浜ц繘琛屽鐞�
+ Boolean isProduction = updatedOperation.getIsProduction();
+
+ if (Boolean.TRUE.equals(isProduction)) {
+ // 闇�瑕佺敓浜э細妫�鏌ュ伐鍗曟槸鍚﹀瓨鍦紝涓嶅瓨鍦ㄥ垯鐢熸垚
+ if (productionOperationTask == null) {
+ ProductionOperationTask task = new ProductionOperationTask();
+ task.setProductionOrderRoutingOperationId(updatedOperation.getId());
+ task.setProductionOrderId(updatedOperation.getProductionOrderId());
+ // 鑾峰彇鐢熶骇璁㈠崟
+ ProductionOrder productionOrder = productionOrderMapper.selectById(updatedOperation.getProductionOrderId());
+ if (productionOrder == null) {
+ throw new ServiceException("鐢熶骇璁㈠崟涓嶅瓨鍦�");
+ }
+
+ // 鑾峰彇璁㈠崟BOM
+ ProductionOrderBom orderBom = productionOrderBomMapper.selectOne(
+ Wrappers.<ProductionOrderBom>lambdaQuery()
+ .eq(ProductionOrderBom::getProductionOrderId, productionOrder.getId()));
+
+ // 纭畾鏍逛骇鍝佽鏍糏D
+ Long rootProductModelId = orderBom != null && orderBom.getProductModelId() != null
+ ? orderBom.getProductModelId()
+ : productionOrder.getProductModelId();
+
+ // 鑾峰彇BOM缁撴瀯鍒楄〃
+ List<ProductionBomStructure> orderBomStructureList = orderBom == null || orderBom.getId() == null
+ ? Collections.emptyList()
+ : productionBomStructureMapper.selectList(
+ Wrappers.<ProductionBomStructure>lambdaQuery()
+ .eq(ProductionBomStructure::getProductionOrderBomId, orderBom.getId())
+ .orderByAsc(ProductionBomStructure::getId));
+
+ // 鏋勫缓宸ュ簭闇�姹傞噺鏄犲皠
+ Map<String, BigDecimal> operationDemandedQuantityMap =
+ TaskPlanQuantityUtil.buildOperationDemandedQuantityMap(orderBomStructureList, rootProductModelId);
+
+ // 鑾峰彇宸ヨ壓璺嚎宸ュ簭锛堢敤浜庤绠楄鍒掓暟閲忥級
+ TechnologyRoutingOperation sourceOperation = technologyRoutingOperationMapper.selectById(
+ updatedOperation.getTechnologyRoutingOperationId());
+ // 灏嗗師鏉ョ殑绉佹湁鏂规硶鏇挎崲涓鸿皟鐢ㄥ伐鍏风被
+ BigDecimal planQuantity = TaskPlanQuantityUtil.resolveTaskPlanQuantity(
+ sourceOperation,
+ operationDemandedQuantityMap,
+ productionOrder,
+ rootProductModelId);
+ task.setPlanQuantity(planQuantity);
+ task.setCompleteQuantity(BigDecimal.ZERO);
+ task.setWorkOrderNo(generateNextTaskNo());
+ task.setStatus(2);
+ productionOperationTaskMapper.insert(task);
+ }
+ } else {
+ // 涓嶉渶瑕佺敓浜э細妫�鏌ュ伐鍗曟槸鍚﹀瓨鍦�
+ if (productionOperationTask != null) {
+ validateTaskCanRemove(productionOperationTask);
+ // 娌℃湁鎶ュ伐锛屽垯鍒犻櫎宸ュ崟
+ productionOperationTaskMapper.deleteById(productionOperationTask.getId());
+ }
+ }
+
+ return R.ok();
+ }
+
+ private void validateTaskCanRemove(ProductionOperationTask task) {
+ if (task == null || task.getId() == null) {
+ return;
+ }
+ if (defaultDecimal(task.getCompleteQuantity()).compareTo(BigDecimal.ZERO) > 0) {
+ throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ簭蹇収");
+ }
+ long reportCount = productionProductMainMapper.selectCount(
+ Wrappers.<ProductionProductMain>lambdaQuery()
+ .eq(ProductionProductMain::getProductionOperationTaskId, task.getId()));
+ if (reportCount > 0) {
+ throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ崟");
+ }
+ }
+
+ private BigDecimal defaultDecimal(BigDecimal value) {
+ return value == null ? BigDecimal.ZERO : value;
}
@Override
@@ -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);
+ }
}
diff --git a/src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java b/src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java
new file mode 100644
index 0000000..e82d7e4
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java
@@ -0,0 +1,137 @@
+package com.ruoyi.production.util;
+
+import com.ruoyi.production.pojo.ProductionBomStructure;
+import com.ruoyi.production.pojo.ProductionOrder;
+import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
+import com.ruoyi.technology.pojo.TechnologyRoutingOperation;
+import lombok.experimental.UtilityClass;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 宸ュ崟璁″垝鏁伴噺璁$畻宸ュ叿绫�
+ */
+@UtilityClass
+public class TaskPlanQuantityUtil {
+
+ /**
+ * 璁$畻宸ュ崟璁″垝鏁伴噺锛堜娇鐢� TechnologyRoutingOperation锛�
+ */
+ public BigDecimal resolveTaskPlanQuantity(TechnologyRoutingOperation sourceOperation,
+ Map<String, BigDecimal> operationDemandedQuantityMap,
+ ProductionOrder productionOrder,
+ Long rootProductModelId) {
+ if (sourceOperation == null || operationDemandedQuantityMap == null || operationDemandedQuantityMap.isEmpty()) {
+ return defaultDecimal(productionOrder == null ? null : productionOrder.getQuantity());
+ }
+ Long outputProductModelId = sourceOperation.getProductModelId() != null
+ ? sourceOperation.getProductModelId()
+ : rootProductModelId;
+ String key = buildOperationDemandedQuantityKey(sourceOperation.getTechnologyOperationId(), outputProductModelId);
+ BigDecimal planQuantity = operationDemandedQuantityMap.get(key);
+ return planQuantity != null ? planQuantity : defaultDecimal(productionOrder == null ? null : productionOrder.getQuantity());
+ }
+
+ /**
+ * 璁$畻宸ュ崟璁″垝鏁伴噺锛堜娇鐢� ProductionOrderRoutingOperation锛�
+ */
+ public BigDecimal resolveTaskPlanQuantity(ProductionOrderRoutingOperation routingOperation,
+ Map<String, BigDecimal> demandedQuantityMap,
+ BigDecimal orderQuantity,
+ Long rootProductModelId) {
+ if (routingOperation == null || demandedQuantityMap == null || demandedQuantityMap.isEmpty()) {
+ return orderQuantity;
+ }
+ Long outputProductModelId = routingOperation.getProductModelId() != null
+ ? routingOperation.getProductModelId()
+ : rootProductModelId;
+ String key = buildOperationDemandedQuantityKey(routingOperation.getTechnologyOperationId(), outputProductModelId);
+ BigDecimal planQuantity = demandedQuantityMap.get(key);
+ return planQuantity != null ? planQuantity : orderQuantity;
+ }
+
+ /**
+ * 鏋勫缓宸ュ簭闇�姹傞噺鏄犲皠琛�
+ */
+ public Map<String, BigDecimal> buildOperationDemandedQuantityMap(List<ProductionBomStructure> bomStructures, Long rootProductModelId) {
+ if (bomStructures == null || bomStructures.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map<Long, ProductionBomStructure> structureById = new HashMap<>();
+ for (ProductionBomStructure item : bomStructures) {
+ if (item != null && item.getId() != null) {
+ structureById.put(item.getId(), item);
+ }
+ }
+ Map<String, BigDecimal> demandedQuantityMap = new HashMap<>();
+ Set<String> mergedOutputNodeKeySet = new HashSet<>();
+ for (ProductionBomStructure bomStructure : bomStructures) {
+ if (bomStructure == null || bomStructure.getTechnologyOperationId() == null) {
+ continue;
+ }
+ ProductionBomStructure outputNode = resolveOperationOutputNode(bomStructure, structureById);
+ Long outputProductModelId = resolveOutputProductModelId(outputNode, rootProductModelId);
+ if (outputProductModelId == null) {
+ continue;
+ }
+ String mergedOutputNodeKey = buildOperationOutputNodeKey(bomStructure.getTechnologyOperationId(),
+ outputNode == null ? null : outputNode.getId(), outputProductModelId);
+ if (!mergedOutputNodeKeySet.add(mergedOutputNodeKey)) {
+ continue;
+ }
+ BigDecimal demandedQuantity = defaultDecimal(outputNode == null ? null : outputNode.getDemandedQuantity());
+ String key = buildOperationDemandedQuantityKey(bomStructure.getTechnologyOperationId(), outputProductModelId);
+ demandedQuantityMap.merge(key, demandedQuantity, BigDecimal::add);
+ }
+ return demandedQuantityMap;
+ }
+
+ /**
+ * 鏋勫缓宸ュ簭闇�姹傞噺key
+ */
+ public String buildOperationDemandedQuantityKey(Long operationId, Long outputProductModelId) {
+ return String.valueOf(operationId) + "#" + String.valueOf(outputProductModelId);
+ }
+
+ /**
+ * 鏋勫缓杈撳嚭鑺傜偣key
+ */
+ public String buildOperationOutputNodeKey(Long operationId, Long outputNodeId, Long outputProductModelId) {
+ return String.valueOf(operationId) + "#" + String.valueOf(outputNodeId) + "#" + String.valueOf(outputProductModelId);
+ }
+
+ /**
+ * 瑙f瀽宸ュ簭杈撳嚭鑺傜偣
+ */
+ public ProductionBomStructure resolveOperationOutputNode(ProductionBomStructure bomStructure,
+ Map<Long, ProductionBomStructure> structureById) {
+ if (bomStructure == null) {
+ return null;
+ }
+ if (bomStructure.getParentId() == null) {
+ return bomStructure;
+ }
+ ProductionBomStructure parent = structureById.get(bomStructure.getParentId());
+ return parent != null ? parent : bomStructure;
+ }
+
+ /**
+ * 瑙f瀽杈撳嚭浜у搧瑙勬牸ID
+ */
+ public Long resolveOutputProductModelId(ProductionBomStructure outputNode, Long rootProductModelId) {
+ if (outputNode == null) {
+ return rootProductModelId;
+ }
+ return outputNode.getProductModelId() != null ? outputNode.getProductModelId() : rootProductModelId;
+ }
+
+ /**
+ * 榛樿BigDecimal鍊�
+ */
+ public BigDecimal defaultDecimal(BigDecimal value) {
+ return value == null ? BigDecimal.ZERO : value;
+ }
+
+}
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java b/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
index be53963..cc295d5 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
@@ -2,6 +2,8 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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.R;
import com.ruoyi.quality.dto.QualityInspectDto;
import com.ruoyi.quality.pojo.QualityInspect;
@@ -39,6 +41,7 @@
*/
@PostMapping("/add")
@Operation(summary = "鏂板妫�楠�")
+ @Log(title = "鏂板妫�楠�", businessType = BusinessType.INSERT)
public R<?> add(@RequestBody QualityInspectDto qualityInspectDto) {
return R.ok(qualityInspectService.add(qualityInspectDto));
}
@@ -51,6 +54,7 @@
*/
@DeleteMapping("/del")
@Operation(summary = "鍒犻櫎妫�楠�")
+ @Log(title = "鍒犻櫎妫�楠�", businessType = BusinessType.DELETE)
public R<?> delQualityInspect(@RequestBody List<Integer> ids) {
if (CollectionUtils.isEmpty(ids)) {
return R.fail("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
@@ -80,6 +84,7 @@
*/
@GetMapping("/{id}")
@Operation(summary = "妫�楠岃鎯�")
+ @Log(title = "妫�楠岃鎯�", businessType = BusinessType.OTHER)
public R<?> QualityInspectDetail(@PathVariable("id") Integer id) {
return R.ok(qualityInspectService.getDetailById(id));
}
@@ -92,6 +97,7 @@
*/
@PostMapping("/update")
@Operation(summary = "淇敼妫�楠�")
+ @Log(title = "淇敼妫�楠�", businessType = BusinessType.UPDATE)
public R<?> update(@RequestBody QualityInspectDto qualityInspectDto) {
return R.ok(qualityInspectService.updateQualityInspect(qualityInspectDto));
}
@@ -105,6 +111,7 @@
*/
@GetMapping("/listPage")
@Operation(summary = "鍒嗛〉鏌ヨ妫�楠�")
+ @Log(title = "鍒嗛〉鏌ヨ妫�楠�", businessType = BusinessType.OTHER)
public R<?> qualityInspectListPage(Page page, QualityInspectDto qualityInspect) {
return R.ok(qualityInspectService.qualityInspectListPage(page, qualityInspect));
}
@@ -117,6 +124,7 @@
*/
@PostMapping("/export")
@Operation(summary = "瀵煎嚭妫�楠�")
+ @Log(title = "瀵煎嚭妫�楠�", businessType = BusinessType.EXPORT)
public void qualityInspectExport(HttpServletResponse response, QualityInspect qualityInspect) {
qualityInspectService.qualityInspectExport(response, qualityInspect);
}
@@ -129,6 +137,7 @@
*/
@PostMapping("/submit")
@Operation(summary = "鎻愪氦妫�楠�")
+ @Log(title = "鎻愪氦妫�楠�", businessType = BusinessType.OTHER)
public R<?> submit(@RequestBody QualityInspect qualityInspect) {
return R.ok(qualityInspectService.submit(qualityInspect));
}
@@ -141,6 +150,7 @@
*/
@PostMapping("/down")
@Operation(summary = "涓嬭浇妫�楠�")
+ @Log(title = "涓嬭浇妫�楠�", businessType = BusinessType.OTHER)
public void down(HttpServletResponse response, @RequestBody QualityInspect qualityInspect) {
qualityInspectService.down(response, qualityInspect);
}
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java b/src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java
index 21bfa2e..48fc093 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityInspectParamController.java
@@ -2,6 +2,8 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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.R;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityInspectFile;
@@ -34,6 +36,7 @@
*/
@GetMapping("/{inspectId}")
@Operation(summary = "妫�楠屽弬鏁伴」璇︽儏")
+ @Log(title = "妫�楠屽弬鏁伴」璇︽儏", businessType = BusinessType.OTHER)
public R<?> QualityInspectParamDetail(@PathVariable("inspectId") Integer inspectId) {
return R.ok(qualityInspectParamService.qualityInspectParamDetail(inspectId));
}
@@ -46,6 +49,7 @@
*/
@PostMapping("/update")
@Operation(summary = "淇敼妫�楠屽弬鏁伴」")
+ @Log(title = "淇敼妫�楠屽弬鏁伴」", businessType = BusinessType.UPDATE)
public R<?> update(@RequestBody List<QualityInspectParam> qualityInspectParams) {
return R.ok(qualityInspectParamService.updateBatchById(qualityInspectParams));
}
@@ -57,6 +61,7 @@
*/
@DeleteMapping("/del")
@Operation(summary = "鍒犻櫎妫�楠屽弬鏁伴」")
+ @Log(title = "鍒犻櫎妫�楠屽弬鏁伴」", businessType = BusinessType.DELETE)
public R<?> delQualityUnqualified(@RequestBody List<Integer> ids) {
if(CollectionUtils.isEmpty(ids)){
return R.fail("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityReportController.java b/src/main/java/com/ruoyi/quality/controller/QualityReportController.java
index 4d005b0..370e8f0 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityReportController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityReportController.java
@@ -1,6 +1,8 @@
package com.ruoyi.quality.controller;
-import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.domain.R;
import com.ruoyi.quality.service.QualityReportService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -30,8 +32,9 @@
*/
@Operation(summary = "鑾峰彇妫�楠岀粺璁℃暟鎹�")
@GetMapping("/getInspectStatistics")
- public AjaxResult getInspectStatistics() {
- return AjaxResult.success(qualityReportService.getInspectStatistics());
+ @Log(title = "鑾峰彇妫�楠岀粺璁℃暟鎹�", businessType = BusinessType.OTHER)
+ public R<?> getInspectStatistics() {
+ return R.ok(qualityReportService.getInspectStatistics());
}
/**
@@ -39,8 +42,9 @@
*/
@Operation(summary = "鑾峰彇鍚堟牸鐜囩粺璁℃暟鎹�")
@GetMapping("/getPassRateStatistics")
- public AjaxResult getPassRateStatistics() {
- return AjaxResult.success(qualityReportService.getPassRateStatistics());
+ @Log(title = "鑾峰彇鍚堟牸鐜囩粺璁℃暟鎹�", businessType = BusinessType.OTHER)
+ public R<?> getPassRateStatistics() {
+ return R.ok(qualityReportService.getPassRateStatistics());
}
/**
@@ -48,8 +52,9 @@
*/
@Operation(summary = "鑾峰彇鏈堝害鍚堟牸鐜囩粺璁℃暟鎹�")
@GetMapping("/getMonthlyPassRateStatistics")
- public AjaxResult getMonthlyPassRateStatistics(@RequestParam("year") String year) {
- return AjaxResult.success(qualityReportService.getMonthlyPassRateStatistics(year));
+ @Log(title = "鑾峰彇鏈堝害鍚堟牸鐜囩粺璁℃暟鎹�", businessType = BusinessType.OTHER)
+ public R<?> getMonthlyPassRateStatistics(@RequestParam("year") String year) {
+ return R.ok(qualityReportService.getMonthlyPassRateStatistics(year));
}
/**
@@ -57,8 +62,9 @@
*/
@Operation(summary = "鑾峰彇骞村害鎬诲悎鏍肩巼缁熻鏁版嵁")
@GetMapping("/getYearlyPassRateStatistics")
- public AjaxResult getYearlyPassRateStatistics(@RequestParam("year") String year) {
- return AjaxResult.success(qualityReportService.getYearlyPassRateStatistics(year));
+ @Log(title = "鑾峰彇骞村害鎬诲悎鏍肩巼缁熻鏁版嵁", businessType = BusinessType.OTHER)
+ public R<?> getYearlyPassRateStatistics(@RequestParam("year") String year) {
+ return R.ok(qualityReportService.getYearlyPassRateStatistics(year));
}
/**
@@ -66,8 +72,9 @@
*/
@Operation(summary = "鑾峰彇鏈堝害瀹屾垚鏄庣粏鏁版嵁")
@GetMapping("/getMonthlyCompletionDetails")
- public AjaxResult getMonthlyCompletionDetails(@RequestParam("year") String year) {
- return AjaxResult.success(qualityReportService.getMonthlyCompletionDetails(year));
+ @Log(title = "鑾峰彇鏈堝害瀹屾垚鏄庣粏鏁版嵁", businessType = BusinessType.OTHER)
+ public R<?> getMonthlyCompletionDetails(@RequestParam("year") String year) {
+ return R.ok(qualityReportService.getMonthlyCompletionDetails(year));
}
/**
@@ -75,8 +82,9 @@
*/
@Operation(summary = "鑾峰彇鐑偣妫�娴嬫寚鏍囩粺璁�")
@GetMapping("/getTopParameters")
- public AjaxResult getTopParameters(@RequestParam("modelType") Integer modelType) {
- return AjaxResult.success(qualityReportService.getTopParameters(modelType));
+ @Log(title = "鑾峰彇鐑偣妫�娴嬫寚鏍囩粺璁�", businessType = BusinessType.OTHER)
+ public R<?> getTopParameters(@RequestParam("modelType") Integer modelType) {
+ return R.ok(qualityReportService.getTopParameters(modelType));
}
}
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java b/src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java
index e590802..7f2142e 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityTestStandardBindingController.java
@@ -1,5 +1,7 @@
package com.ruoyi.quality.controller;
+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;
@@ -35,6 +37,7 @@
*/
@PostMapping("/add")
@Operation(summary = "鏂板妫�娴嬫爣鍑嗕富琛ㄤ笌浜у搧鍏宠仈琛�")
+ @Log(title = "鏂板妫�娴嬫爣鍑嗕富琛ㄤ笌浜у搧鍏宠仈琛�", businessType = BusinessType.INSERT)
public R<?> add(@RequestBody List<QualityTestStandardBinding> qualityTestStandardBindings) {
return R.ok(qualityTestStandardBindingService.add(qualityTestStandardBindings));
}
@@ -47,6 +50,7 @@
*/
@DeleteMapping("/del")
@Operation(summary = "鍒犻櫎妫�娴嬫爣鍑嗕富琛ㄤ笌浜у搧鍏宠仈琛�")
+ @Log(title = "鍒犻櫎妫�娴嬫爣鍑嗕富琛ㄤ笌浜у搧鍏宠仈琛�", businessType = BusinessType.DELETE)
public R<?> delQualityTestStandard(@RequestBody List<Integer> ids) {
if (CollectionUtils.isEmpty(ids)) {
return R.fail("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
@@ -61,6 +65,7 @@
*/
@GetMapping("/list")
@Operation(summary = "妫�娴嬫寚鏍囩淮鎶ゆ煡璇�")
+ @Log(title = "妫�娴嬫寚鏍囩淮鎶ゆ煡璇�", businessType = BusinessType.OTHER)
public R<?> listBinding(Long testStandardId) {
return R.ok(qualityTestStandardBindingService.listBinding(testStandardId));
}
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java b/src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java
index 0ccfd65..ab8fca9 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityTestStandardController.java
@@ -2,6 +2,8 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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.R;
import com.ruoyi.quality.pojo.QualityTestStandard;
import com.ruoyi.quality.pojo.QualityTestStandardParam;
@@ -43,6 +45,7 @@
*/
@PostMapping("/add")
@Operation(summary = "鏂板妫�娴嬫爣鍑嗕富琛�")
+ @Log(title = "鏂板妫�娴嬫爣鍑嗕富琛�", businessType = BusinessType.INSERT)
public R<?> add(@RequestBody QualityTestStandard qualityTestStandard) {
return R.ok(qualityTestStandardService.save(qualityTestStandard));
}
@@ -54,6 +57,7 @@
*/
@DeleteMapping("/del")
@Operation(summary = "鍒犻櫎妫�娴嬫爣鍑嗕富琛�")
+ @Log(title = "鍒犻櫎妫�娴嬫爣鍑嗕富琛�", businessType = BusinessType.DELETE)
public R<?> delQualityTestStandard(@RequestBody List<Integer> ids) {
if(CollectionUtils.isEmpty(ids)){
return R.fail("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
@@ -68,6 +72,7 @@
*/
@PostMapping("/update")
@Operation(summary = "妫�娴嬫爣鍑嗕富琛ㄤ慨鏀�")
+ @Log(title = "妫�娴嬫爣鍑嗕富琛ㄤ慨鏀�", businessType = BusinessType.UPDATE)
public R<?> update(@RequestBody QualityTestStandard qualityTestStandard) {
return R.ok(qualityTestStandardService.updateById(qualityTestStandard));
}
@@ -80,6 +85,7 @@
*/
@GetMapping("/listPage")
@Operation(summary = "妫�娴嬫爣鍑嗕富琛ㄥ垎椤垫煡璇�")
+ @Log(title = "妫�娴嬫爣鍑嗕富琛ㄥ垎椤垫煡璇�", businessType = BusinessType.OTHER)
public R<?> qualityTestStandardListPage(Page page, QualityTestStandard qualityTestStandard) {
return R.ok(qualityTestStandardService.qualityTestStandardListPage(page, qualityTestStandard));
}
@@ -91,6 +97,7 @@
*/
@PostMapping("/copyParam")
@Operation(summary = "妫�娴嬫爣鍑嗗鍒跺弬鏁�")
+ @Log(title = "妫�娴嬫爣鍑嗗鍒跺弬鏁�", businessType = BusinessType.OTHER)
public R<?> copyParam(@RequestBody QualityTestStandard qualityTestStandard) {
return R.ok(qualityTestStandardService.copyParam(qualityTestStandard));
}
@@ -102,6 +109,7 @@
*/
@PostMapping("/qualityTestStandardAudit")
@Operation(summary = "妫�娴嬫爣鍑嗘壒閲忓鏍�")
+ @Log(title = "妫�娴嬫爣鍑嗘壒閲忓鏍�", businessType = BusinessType.OTHER)
public R<?> qualityTestStandardAudit(@RequestBody List<QualityTestStandard> qualityTestStandards) {
return R.ok(qualityTestStandardService.updateBatchById(qualityTestStandards));
}
@@ -112,6 +120,7 @@
*/
@GetMapping("/getQualityTestStandardByProductId")
@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));
}
@@ -122,6 +131,7 @@
*/
@GetMapping("/getQualityTestStandardParamByTestStandardId")
@Operation(summary = "鏍规嵁妫�娴嬫爣鍑唅d鏌ヨ鐩稿叧鐨勬楠屾爣鍑嗗弬鏁�")
+ @Log(title = "鏍规嵁妫�娴嬫爣鍑唅d鏌ヨ鐩稿叧鐨勬楠屾爣鍑嗗弬鏁�", businessType = BusinessType.OTHER)
public R<?> getQualityTestStandardParamByTestStandardId(Long testStandardId) {
return R.ok(qualityTestStandardParamService.list(Wrappers.<QualityTestStandardParam>lambdaQuery().eq(QualityTestStandardParam::getTestStandardId, testStandardId)));
}
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java b/src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java
index a12535b..16788c9 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityTestStandardParamController.java
@@ -2,6 +2,8 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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.R;
import com.ruoyi.quality.pojo.QualityTestStandard;
import com.ruoyi.quality.pojo.QualityTestStandardParam;
@@ -38,6 +40,7 @@
*/
@PostMapping("/add")
@Operation(summary = "鏂板妫�娴嬫爣鍑嗗弬鏁�")
+ @Log(title = "鏂板妫�娴嬫爣鍑嗗弬鏁�", businessType = BusinessType.INSERT)
public R<?> add(@RequestBody QualityTestStandardParam qualityTestStandardParam) {
return R.ok(qualityTestStandardParamService.save(qualityTestStandardParam));
}
@@ -49,6 +52,7 @@
*/
@DeleteMapping("/del")
@Operation(summary = "鍒犻櫎妫�娴嬫寚鏍囩淮鎶�")
+ @Log(title = "鍒犻櫎妫�娴嬫寚鏍囩淮鎶�", businessType = BusinessType.DELETE)
public R<?> delQualityTestStandard(@RequestBody List<Integer> ids) {
if(CollectionUtils.isEmpty(ids)){
return R.fail("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
@@ -63,6 +67,7 @@
*/
@PostMapping("/update")
@Operation(summary = "妫�娴嬫寚鏍囩淮鎶や慨鏀�")
+ @Log(title = "妫�娴嬫寚鏍囩淮鎶や慨鏀�", businessType = BusinessType.UPDATE)
public R<?> update(@RequestBody QualityTestStandardParam qualityTestStandardParam) {
return R.ok(qualityTestStandardParamService.updateById(qualityTestStandardParam));
}
@@ -73,6 +78,7 @@
*/
@GetMapping("/list")
@Operation(summary = "妫�娴嬫寚鏍囩淮鎶ゆ煡璇�")
+ @Log(title = "妫�娴嬫寚鏍囩淮鎶ゆ煡璇�", businessType = BusinessType.OTHER)
public R<?> list(Long testStandardId) {
return R.ok(qualityTestStandardParamService.list(Wrappers.<QualityTestStandardParam>lambdaQuery().eq(QualityTestStandardParam::getTestStandardId,testStandardId)));
}
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java b/src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
index 020841f..a2222c3 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
@@ -1,6 +1,8 @@
package com.ruoyi.quality.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.quality.pojo.QualityUnqualified;
import com.ruoyi.quality.service.IQualityUnqualifiedService;
@@ -32,6 +34,7 @@
*/
@PostMapping("/add")
@Operation(summary = "鏂板涓嶅悎鏍肩鐞�")
+ @Log(title = "鏂板涓嶅悎鏍肩鐞�", businessType = BusinessType.INSERT)
public R<?> add(@RequestBody QualityUnqualified qualityUnqualified) {
qualityUnqualified.setInspectState(0);
return R.ok(qualityUnqualifiedService.save(qualityUnqualified));
@@ -44,6 +47,7 @@
*/
@DeleteMapping("/del")
@Operation(summary = "鍒犻櫎涓嶅悎鏍肩鐞�")
+ @Log(title = "鍒犻櫎涓嶅悎鏍肩鐞�", businessType = BusinessType.DELETE)
public R<?> delQualityUnqualified(@RequestBody List<Integer> ids) {
qualityUnqualifiedService.listByIds(ids).stream().forEach(qualityUnqualified -> {
if (qualityUnqualified.getInspectState()==1){
@@ -60,6 +64,7 @@
*/
@GetMapping("/{id}")
@Operation(summary = "涓嶅悎鏍肩鐞嗚鎯�")
+ @Log(title = "涓嶅悎鏍肩鐞嗚鎯�", businessType = BusinessType.OTHER)
public R<?> QualityUnqualifiedDetail(@PathVariable("id") Integer id) {
return R.ok(qualityUnqualifiedService.getUnqualified(id));
}
@@ -71,6 +76,7 @@
*/
@PostMapping("/update")
@Operation(summary = "涓嶅悎鏍肩鐞嗕慨鏀�")
+ @Log(title = "涓嶅悎鏍肩鐞嗕慨鏀�", businessType = BusinessType.UPDATE)
public R<?> update(@RequestBody QualityUnqualified qualityUnqualified) {
return R.ok(qualityUnqualifiedService.updateById(qualityUnqualified));
}
@@ -83,6 +89,7 @@
*/
@GetMapping("/listPage")
@Operation(summary = "涓嶅悎鏍肩鐞嗗垎椤垫煡璇�")
+ @Log(title = "涓嶅悎鏍肩鐞嗗垎椤垫煡璇�", businessType = BusinessType.OTHER)
public R<?> qualityUnqualifiedListPage(Page page, QualityUnqualified qualityUnqualified) {
return R.ok(qualityUnqualifiedService.qualityUnqualifiedListPage(page, qualityUnqualified));
}
@@ -94,6 +101,7 @@
*/
@PostMapping("/export")
@Operation(summary = "涓嶅悎鏍肩鐞嗗鍑�")
+ @Log(title = "涓嶅悎鏍肩鐞嗗鍑�", businessType = BusinessType.EXPORT)
public void qualityUnqualifiedExport(HttpServletResponse response,QualityUnqualified qualityUnqualified) {
qualityUnqualifiedService.qualityUnqualifiedExport(response, qualityUnqualified);
}
@@ -105,6 +113,7 @@
*/
@PostMapping("/deal")
@Operation(summary = "涓嶅悎鏍肩鐞嗗鐞�")
+ @Log(title = "涓嶅悎鏍肩鐞嗗鐞�", businessType = BusinessType.OTHER)
public R<?> deal(@RequestBody QualityUnqualified qualityUnqualified) {
return R.ok(qualityUnqualifiedService.deal(qualityUnqualified));
}
diff --git a/src/main/resources/approve-todo-agent-prompt.txt b/src/main/resources/approve-todo-agent-prompt.txt
index c309da8..f026fee 100644
--- a/src/main/resources/approve-todo-agent-prompt.txt
+++ b/src/main/resources/approve-todo-agent-prompt.txt
@@ -1,4 +1,5 @@
浣犳槸涓�涓鎵瑰緟鍔炲姪鎵嬶紝璐熻矗鍗忓悓鍔炲叕瀹℃壒寰呭姙鐨勬煡璇€�佸鏍搞�佸彇娑堝鏍搞�佷慨鏀广�佸垹闄ゅ拰缁熻鍒嗘瀽銆�
+褰撳墠鏃ユ湡锛歿{currentDate}}锛堜腑鍥芥椂鍖猴級銆�
宸ヤ綔瑕佹眰锛�
1. 鐢ㄦ埛闂緟鍔炲垪琛ㄣ�佸鎵硅繘搴︺�佸鎵硅鎯呫�佺粺璁℃暟鎹椂锛屼紭鍏堣皟鐢ㄥ伐鍏凤紝涓嶈鑷嗛�犳暟鎹��
@@ -16,3 +17,4 @@
13. 鍙湁鈥滄煡璇㈠鎵瑰緟鍔炶鎯呪�濊繖涓伐鍏峰厑璁歌緭鍑鸿嚜鐒惰瑷�鏂囨湰銆�
14. 濡傛灉宸ュ叿杩斿洖鐨勬槸缁熻 JSON锛屼篃鍚屾牱鐩存帴杈撳嚭鍘熷 JSON锛涘叾涓� `description`銆乣summary`銆乣charts` 宸茬粡渚涘墠绔娇鐢ㄣ��
15. 鍥炵瓟浣跨敤涓枃锛涗絾鍦� JSON 鍦烘櫙涓嬶紝鏈�缁堣緭鍑哄繀椤绘槸鍚堟硶 JSON 鏈綋銆�
+16. 鐢ㄦ埛鎻愬埌鈥滀粖骞�/鏈湀/浠婂ぉ/鏈�杩�/涓婃湀/鍘诲勾鈥濈瓑鐩稿鏃堕棿鏃讹紝蹇呴』涓ユ牸鍩轰簬鈥滃綋鍓嶆棩鏈熲�濇崲绠楋紝绂佹鑷鍋囪骞翠唤銆�
diff --git a/src/main/resources/manufacturing-agent-prompt.txt b/src/main/resources/manufacturing-agent-prompt.txt
index c1a30c8..1653bb9 100644
--- a/src/main/resources/manufacturing-agent-prompt.txt
+++ b/src/main/resources/manufacturing-agent-prompt.txt
@@ -1,4 +1,5 @@
浣犳槸浼佷笟鍒堕�犳櫤鑳藉姪鎵嬶紝瑕嗙洊鐢熶骇鐜板満銆佽鍒掋�佸伐鍗曘�佽澶囥�佽川閲忋�佺墿鏂欍�佸紓甯稿鐞嗕竷涓煙銆�
+褰撳墠鏃ユ湡锛歿{currentDate}}锛堜腑鍥芥椂鍖猴級銆�
宸ヤ綔瑙勫垯锛�
1. 鐢ㄦ埛鎻愬嚭鈥滄煡銆侀棶銆侀璀︺�佸垎鏋愨�濋渶姹傛椂锛屼紭鍏堣皟鐢ㄥ伐鍏锋嬁缁撴瀯鍖栫粨鏋滐紝涓嶈鑷嗛�犱笟鍔℃暟鎹��
@@ -6,3 +7,4 @@
3. 宸ュ叿杩斿洖 JSON 鏃讹紝鐩存帴杈撳嚭鍘熷 JSON 瀛楃涓诧紝涓嶈棰濆鍖呰9 Markdown锛屼笉瑕佸湪鍓嶅悗鍔犺В閲婃枃瀛椼��
4. 鍥炵瓟蹇呴』浣跨敤涓枃锛涜嫢鐢ㄦ埛闂缂哄皯鏃堕棿鑼冨洿銆佸叧閿瓧绛夋潯浠讹紝鍙厛缁欓粯璁ゅ彛寰勫苟鎻愮ず鍙ˉ鍏呮潯浠躲��
5. 鑻ユ棤娉曚粠宸ュ叿缁撴灉寰楀埌缁撹锛屾槑纭鏄庣己灏戠殑绛涢�夋潯浠舵垨涓氬姟瀛楁銆�
+6. 鐢ㄦ埛鎻愬埌鈥滀粖骞�/鏈湀/浠婂ぉ/鏈�杩�/涓婃湀/鍘诲勾鈥濈瓑鐩稿鏃堕棿鏃讹紝蹇呴』涓ユ牸鍩轰簬鈥滃綋鍓嶆棩鏈熲�濇崲绠楋紝绂佹鑷鍋囪骞翠唤銆�
diff --git a/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml b/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
index f029ef7..199eb21 100644
--- a/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
+++ b/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
@@ -64,6 +64,9 @@
<if test="c != null and c.status != null">
and pot.status = #{c.status}
</if>
+ <if test="c != null and c.isProduction != null">
+ and poro.is_production = #{c.isProduction}
+ </if>
<if test="c != null and c.workOrderNo != null and c.workOrderNo != ''">
and pot.work_order_no like concat('%', #{c.workOrderNo}, '%')
</if>
diff --git a/src/main/resources/mapper/production/ProductionOrderMapper.xml b/src/main/resources/mapper/production/ProductionOrderMapper.xml
index 95679a7..8e64413 100644
--- a/src/main/resources/mapper/production/ProductionOrderMapper.xml
+++ b/src/main/resources/mapper/production/ProductionOrderMapper.xml
@@ -227,6 +227,10 @@
<if test="status != null">
and po.status = #{status}
</if>
+ <if test="startTime != null and endTime != null">
+ and po.create_time >= #{startTime}
+ and po.create_time < #{endTime}
+ </if>
</where>
order by po.id desc
limit #{offset}, #{size}
@@ -239,13 +243,21 @@
<if test="status != null">
and po.status = #{status}
</if>
+ <if test="startTime != null and endTime != null">
+ and po.create_time >= #{startTime}
+ and po.create_time < #{endTime}
+ </if>
</where>
</select>
<select id="countHomeOrderProgressByStatus" resultType="java.util.Map">
select po.status as status, count(1) as cnt
from production_order po
- where po.status in (2, 3, 4)
+ where po.status in (1, 2, 3, 4)
+ <if test="startTime != null and endTime != null">
+ and po.create_time >= #{startTime}
+ and po.create_time < #{endTime}
+ </if>
group by po.status
</select>
@@ -258,7 +270,13 @@
from production_order po
left join product_model pm on po.product_model_id = pm.id
left join product p on pm.product_id = p.id
- where po.status in (1, 2)
+ <where>
+ po.status in (1, 2)
+ <if test="planStart != null and planEnd != null">
+ and po.plan_complete_time >= #{planStart}
+ and po.plan_complete_time < #{planEnd}
+ </if>
+ </where>
order by case when po.status = 2 then 0 else 1 end, po.id desc
limit #{size}
</select>
@@ -266,7 +284,13 @@
<select id="countHomeTodayProductionPlan" resultType="java.lang.Long">
select count(1)
from production_order po
- where po.status in (1, 2)
+ <where>
+ po.status in (1, 2)
+ <if test="planStart != null and planEnd != null">
+ and po.plan_complete_time >= #{planStart}
+ and po.plan_complete_time < #{planEnd}
+ </if>
+ </where>
</select>
</mapper>
diff --git a/src/main/resources/purchase-agent-prompt.txt b/src/main/resources/purchase-agent-prompt.txt
index 97f7eb2..2fd5021 100644
--- a/src/main/resources/purchase-agent-prompt.txt
+++ b/src/main/resources/purchase-agent-prompt.txt
@@ -1,5 +1,6 @@
浣犳槸浼佷笟閲囪喘鏅鸿兘鍔╃悊銆�
浣犵殑鐩爣鏄府鍔╃敤鎴峰揩閫熷畬鎴愰噰璐浉鍏充俊鎭煡璇笌瑙h銆�
+褰撳墠鏃ユ湡锛歿{currentDate}}锛堜腑鍥芥椂鍖猴級銆�
宸ヤ綔瑙勫垯锛�
1. 浼樺厛璋冪敤宸ュ叿鍑芥暟鑾峰彇閲囪喘鍙拌处銆佷粯娆俱�佸彂绁ㄣ�侀��璐х瓑缁撴瀯鍖栨暟鎹��
@@ -9,6 +10,8 @@
5. 鐢ㄦ埛闂�滄渶杩�7澶╀緵搴斿晢鍒拌揣寮傚父鈥濃�滃埌璐ч棶棰樷�濃�滃埌璐у紓甯糕�濇椂锛岃皟鐢ㄢ�滄煡璇㈤噰璐埌璐у紓甯糕�濄��
6. 鐢ㄦ埛闂�滃緟浠樻閲囪喘鍗曗�濃�滄湭浠樻閲囪喘鍗曗�濃�滄湭浠樻竻閲囪喘璁㈠崟鈥濇椂锛岃皟鐢ㄢ�滄煡璇㈠緟浠樻閲囪喘鍗曗�濄��
7. 鐢ㄦ埛闂�滄湰鏈堥噰璐��璐ф儏鍐碘�濃�滈噰璐��璐у垪琛ㄢ�濃�滈��鏂�/鎷掓敹鎯呭喌鈥濇椂锛岃皟鐢ㄢ�滄煡璇㈤噰璐��璐ф儏鍐碘�濄��
-8. 缁撴灉鐢ㄧ畝娲佷腑鏂囧洖绛旓紝鍏堢粰缁撹锛屽啀缁欏叧閿暟鎹偣銆�
-9. 涓嶈缂栭�犻噰璐暟鎹紝鎵�鏈夌粨璁哄繀椤诲熀浜庡伐鍏疯繑鍥炪��
-10. 鏃犳硶鐩存帴寰楀嚭缁撹鏃讹紝鏄庣‘璇存槑缂哄皯鍝簺瀛楁鎴栫瓫閫夋潯浠躲��
+8. 宸ュ叿杩斿洖 JSON 鏃讹紝鐩存帴杈撳嚭鍘熷 JSON 瀛楃涓诧紝涓嶈棰濆鍖呰9 Markdown锛屼篃涓嶈鍦ㄥ墠鍚庤拷鍔犺В閲婃枃鏈��
+9. 鍙湁鍦ㄦ湭璋冪敤 JSON 宸ュ叿鏃讹紝鎵嶄娇鐢ㄧ畝娲佷腑鏂囧洖绛旓紝鍏堢粰缁撹锛屽啀缁欏叧閿暟鎹偣銆�
+10. 涓嶈缂栭�犻噰璐暟鎹紝鎵�鏈夌粨璁哄繀椤诲熀浜庡伐鍏疯繑鍥炪��
+11. 鏃犳硶鐩存帴寰楀嚭缁撹鏃讹紝鏄庣‘璇存槑缂哄皯鍝簺瀛楁鎴栫瓫閫夋潯浠躲��
+12. 鐢ㄦ埛鎻愬埌鈥滀粖骞�/鏈湀/浠婂ぉ/鏈�杩�/涓婃湀/鍘诲勾鈥濈瓑鐩稿鏃堕棿鏃讹紝蹇呴』涓ユ牸鍩轰簬鈥滃綋鍓嶆棩鏈熲�濇崲绠楋紝绂佹鑷鍋囪骞翠唤銆�
diff --git a/src/main/resources/sales-agent-prompt.txt b/src/main/resources/sales-agent-prompt.txt
index 5cd87ff..3a43502 100644
--- a/src/main/resources/sales-agent-prompt.txt
+++ b/src/main/resources/sales-agent-prompt.txt
@@ -1,7 +1,9 @@
浣犳槸浼佷笟閿�鍞姪鎵嬶紝瑕嗙洊瀹㈡埛妗f銆侀攢鍞姤浠枫�侀攢鍞彴璐︺�侀攢鍞��璐с�佸鎴峰線鏉ャ�佸彂璐у彴璐︺�佹寚鏍囩粺璁°�佸鎴锋祦澶遍闄╁垎鏋愩�佸洖娆句笌鎶ヤ环绛栫暐寤鸿绛夊満鏅��
+褰撳墠鏃ユ湡锛歿{currentDate}}锛堜腑鍥芥椂鍖猴級銆�
宸ヤ綔瑙勫垯锛�
1. 鐢ㄦ埛鎻愬嚭鈥滄煡銆侀棶銆佺粺璁°�佸垎鏋愩�佸缓璁�濋渶姹傛椂锛屼紭鍏堣皟鐢ㄥ伐鍏疯繑鍥炵粨鏋勫寲鏁版嵁锛屼笉缂栭�犱笟鍔℃暟鎹��
2. 鍛戒腑鈥滃鎴锋祦澶遍闄╁垎鏋愨�濇垨鈥滃洖娆句笌鎶ヤ环绛栫暐寤鸿鈥濇椂锛屼紭鍏堜娇鐢ㄥ伐鍏疯緭鍑虹粨鏋勫寲 JSON銆�
3. 宸ュ叿杩斿洖 JSON 鏃讹紝鐩存帴杈撳嚭鍘熷 JSON 瀛楃涓诧紝涓嶈棰濆鍖呰9 Markdown锛屼篃涓嶈鍦ㄥ墠鍚庤拷鍔犺В閲婃枃鏈��
4. 鍥炲蹇呴』浣跨敤涓枃锛涜嫢鐢ㄦ埛缂哄皯鏃堕棿鑼冨洿銆佸叧閿瘝绛夋潯浠讹紝鍙厛浣跨敤榛樿鍙e緞骞舵彁绀哄彲琛ュ厖鏉′欢銆�
5. 鑻ユ暟鎹笉瓒充互寰楀嚭缁撹锛屾槑纭寚鍑虹己灏戠殑绛涢�夋潯浠舵垨鍏抽敭瀛楁銆�
+6. 鐢ㄦ埛鎻愬埌鈥滀粖骞�/鏈湀/浠婂ぉ/鏈�杩�/涓婃湀/鍘诲勾鈥濈瓑鐩稿鏃堕棿鏃讹紝蹇呴』涓ユ牸鍩轰簬鈥滃綋鍓嶆棩鏈熲�濇崲绠楋紝绂佹鑷鍋囪骞翠唤銆�
--
Gitblit v1.9.3