Merge branch 'dev_New_pro' into dev_New_pro_财务
# Conflicts:
# src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
# src/main/java/com/ruoyi/home/controller/HomeController.java
# src/main/java/com/ruoyi/quality/controller/QualityReportController.java
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # éè´æºè½ä½ä¼ååç«¯åæ´ææ¡£ |
| | | |
| | | ## 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天ä¾åºåå°è´§å¼å¸¸æåªäºï¼ |
| | | - 帮æç»è®¡å¾
仿¬¾éè´åï¼ |
| | | - ååºæ¬æéè´éè´§æ
åµ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # é¦é¡µ 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. è页é¢å¯ä¸æ¹ï¼ç»§ç»æ²¿ç¨ååæ°ä¹è½æ£å¸¸èè°ã |
| | | |
| | |
| | | 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; |
| | | |
| | |
| | | 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); |
| | | } |
| | |
| | | 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; |
| | | |
| | |
| | | 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); |
| | | } |
| | |
| | | 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; |
| | | |
| | |
| | | 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); |
| | | } |
| | |
| | | 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; |
| | | |
| | |
| | | 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; |
| | | |
| | |
| | | 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; |
| | | } |
| | |
| | | } |
| | | 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; |
| | | } |
| | | |
| | |
| | | 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); |
| | | } |
| | | |
| | | private String extractEndDate(String text) { |
| | | Matcher matcher = DATE_PATTERN.matcher(text); |
| | | if (!matcher.find()) { |
| | | LocalDate today = LocalDate.now(CHINA_ZONE_ID); |
| | | if (text.contains("ä»å¤©")) { |
| | | return new DateRange(formatDate(today), formatDate(today)); |
| | | } |
| | | if (text.contains("æ¨å¤©")) { |
| | | LocalDate yesterday = today.minusDays(1); |
| | | return new DateRange(formatDate(yesterday), formatDate(yesterday)); |
| | | } |
| | | if (text.contains("æ¬å¨")) { |
| | | LocalDate start = today.minusDays(today.getDayOfWeek().getValue() - 1L); |
| | | return new DateRange(formatDate(start), formatDate(today)); |
| | | } |
| | | if (text.contains("ä¸å¨")) { |
| | | LocalDate thisWeekStart = today.minusDays(today.getDayOfWeek().getValue() - 1L); |
| | | LocalDate start = thisWeekStart.minusWeeks(1); |
| | | LocalDate end = start.plusDays(6); |
| | | return new DateRange(formatDate(start), formatDate(end)); |
| | | } |
| | | if (text.contains("æ¬æ")) { |
| | | return new DateRange(formatDate(today.withDayOfMonth(1)), formatDate(today)); |
| | | } |
| | | if (text.contains("䏿")) { |
| | | LocalDate start = today.minusMonths(1).withDayOfMonth(1); |
| | | return new DateRange(formatDate(start), formatDate(start.withDayOfMonth(start.lengthOfMonth()))); |
| | | } |
| | | if (text.contains("ä»å¹´") || text.contains("æ¬å¹´")) { |
| | | return new DateRange(formatDate(today.withDayOfYear(1)), formatDate(today)); |
| | | } |
| | | if (text.contains("å»å¹´")) { |
| | | LocalDate start = today.minusYears(1).withDayOfYear(1); |
| | | LocalDate end = start.withDayOfYear(start.lengthOfYear()); |
| | | return new DateRange(formatDate(start), formatDate(end)); |
| | | } |
| | | if (containsAny(text, "è¿åå¹´", "æè¿åå¹´")) { |
| | | return new DateRange(formatDate(today.minusMonths(6).plusDays(1)), formatDate(today)); |
| | | } |
| | | if (containsAny(text, "è¿å个æ", "æè¿å个æ", "å个æ")) { |
| | | return new DateRange(formatDate(today.minusDays(14)), formatDate(today)); |
| | | } |
| | | |
| | | Matcher relativeMatcher = RELATIVE_RANGE_PATTERN.matcher(text); |
| | | if (relativeMatcher.find()) { |
| | | int amount = Integer.parseInt(relativeMatcher.group(2)); |
| | | String unit = relativeMatcher.group(3); |
| | | LocalDate start = switch (unit) { |
| | | case "天" -> today.minusDays(Math.max(amount - 1L, 0)); |
| | | case "å¨" -> today.minusWeeks(Math.max(amount, 1)).plusDays(1); |
| | | case "个æ", "æ" -> today.minusMonths(Math.max(amount, 1)).plusDays(1); |
| | | case "å¹´" -> today.minusYears(Math.max(amount, 1)).plusDays(1); |
| | | default -> today.minusDays(29); |
| | | }; |
| | | return new DateRange(formatDate(start), formatDate(today)); |
| | | } |
| | | |
| | | return new DateRange(null, null); |
| | | } |
| | | |
| | | private DateRange buildDateRange(String start, String end) { |
| | | LocalDate startDate = parseDate(start); |
| | | LocalDate endDate = parseDate(end); |
| | | if (startDate == null || endDate == null) { |
| | | return new DateRange(null, null); |
| | | } |
| | | if (startDate.isAfter(endDate)) { |
| | | LocalDate temp = startDate; |
| | | startDate = endDate; |
| | | endDate = temp; |
| | | } |
| | | return new DateRange(formatDate(startDate), formatDate(endDate)); |
| | | } |
| | | |
| | | private LocalDate parseDate(String text) { |
| | | try { |
| | | return LocalDate.parse(text, DATE_FMT); |
| | | } catch (Exception ignored) { |
| | | return null; |
| | | } |
| | | 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("éè´è®¢å", "") |
| | |
| | | .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) { |
| | | } |
| | | } |
| | |
| | | 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; |
| | | |
| | |
| | | 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); |
| | | } |
| | | |
| | |
| | | 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; |
| | |
| | | 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)); |
| | | } |
| | |
| | | aiSessionUserContext.remove(memoryId); |
| | | return toAjax(aiChatSessionService.deleteCurrentUserSession(memoryId, SecurityUtils.getLoginUser())); |
| | | } |
| | | |
| | | private String currentDateForPrompt() { |
| | | return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT); |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | 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)); |
| | | } |
| | |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | private String currentDateForPrompt() { |
| | | return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT); |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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)); |
| | | } |
| | |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | private String currentDateForPrompt() { |
| | | return LocalDate.now(CHINA_ZONE_ID).format(CURRENT_DATE_FMT); |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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)); |
| | | } |
| | |
| | | .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)); |
| | |
| | | }; |
| | | } |
| | | |
| | | 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 """ |
| | | ä½ æ¯éè´ä¸å¡æä»¶åæå©æãè¯·ä¸¥æ ¼æ ¹æ®ç¨æ·ä¸ä¼ çå¤ä¸ªæä»¶åç¨æ·è¦æ±æåéè´ä¸å¡æ°æ®ã |
| | |
| | | |
| | | 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; |
| | |
| | | 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; |
| | | |
| | |
| | | .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 = "ææ¶é´èå´æ¥è¯¢éè´éè´§åå表åéè´§éé¢ã") |
| | |
| | | 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) { |
| | |
| | | } |
| | | |
| | | 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) { |
| | |
| | | return new DateRange(today.minusDays(29), today, "è¿30天"); |
| | | } |
| | | String text = timeRange.trim(); |
| | | if (text.contains("ä»å¤©")) { |
| | | return new DateRange(today, today, "ä»å¤©"); |
| | | } |
| | | if (text.contains("æ¨å¤©")) { |
| | | LocalDate yesterday = today.minusDays(1); |
| | | return new DateRange(yesterday, yesterday, "æ¨å¤©"); |
| | | } |
| | | if (text.contains("æ¬å¨")) { |
| | | LocalDate startOfWeek = today.minusDays(today.getDayOfWeek().getValue() - 1L); |
| | | return new DateRange(startOfWeek, today, "æ¬å¨"); |
| | | } |
| | | if (text.contains("ä¸å¨")) { |
| | | LocalDate thisWeekStart = today.minusDays(today.getDayOfWeek().getValue() - 1L); |
| | | LocalDate startOfLastWeek = thisWeekStart.minusWeeks(1); |
| | | return new DateRange(startOfLastWeek, startOfLastWeek.plusDays(6), "ä¸å¨"); |
| | | } |
| | | if (text.contains("ä»å¹´") || text.contains("æ¬å¹´")) { |
| | | return new DateRange(today.withDayOfYear(1), today, "ä»å¹´"); |
| | | } |
| | |
| | | if (!StringUtils.hasText(text)) { |
| | | return null; |
| | | } |
| | | try { |
| | | return LocalDate.parse(text.trim(), DATE_FMT); |
| | | } catch (Exception ignored) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | private Date toDate(LocalDate localDate) { |
| | |
| | | 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; |
| | |
| | | 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.*; |
| | | |
| | | /** |
| | |
| | | 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; |
| | |
| | | @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); |
| | | } |
| | |
| | | @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); |
| | | } |
| | |
| | | @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); |
| | | } |
| | |
| | | @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); |
| | | 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) { |
| | |
| | | } |
| | | } |
| | | |
| | | 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; |
| | |
| | | } |
| | | |
| | | 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); |
| | |
| | | |
| | | @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<>(); |
| | |
| | | } |
| | | |
| | | 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); |
| | | } |
| | |
| | | @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); |
| | | } |
| | |
| | | @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); |
| | | } |
| | |
| | | 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) { |
| | |
| | | } |
| | | } |
| | | |
| | | 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; |
| | | } |
| | |
| | | @Schema(description = "ç»ææ¥æ") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate endDate; |
| | | |
| | | @Schema(description = "æ¯å¦ç产") |
| | | private Integer isProduction; |
| | | } |
| | |
| | | @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}") |
| | |
| | | |
| | | 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); |
| | | |
| | | } |
| | |
| | | |
| | | R addRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation); |
| | | |
| | | R updateRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation); |
| | | |
| | | R deleteRouteItem(Long id); |
| | | |
| | | int sortRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation); |
| | |
| | | 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; |
| | |
| | | .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; |
| | |
| | | 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; |
| | |
| | | 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) |
| | |
| | | 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) { |
| | |
| | | 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 |
| | |
| | | } |
| | | 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); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | */ |
| | | @PostMapping("/add") |
| | | @Operation(summary = "æ°å¢æ£éª") |
| | | @Log(title = "æ°å¢æ£éª", businessType = BusinessType.INSERT) |
| | | public R<?> add(@RequestBody QualityInspectDto qualityInspectDto) { |
| | | return R.ok(qualityInspectService.add(qualityInspectDto)); |
| | | } |
| | |
| | | */ |
| | | @DeleteMapping("/del") |
| | | @Operation(summary = "å 餿£éª") |
| | | @Log(title = "å 餿£éª", businessType = BusinessType.DELETE) |
| | | public R<?> delQualityInspect(@RequestBody List<Integer> ids) { |
| | | if (CollectionUtils.isEmpty(ids)) { |
| | | return R.fail("è¯·éæ©è³å°ä¸æ¡æ°æ®"); |
| | |
| | | */ |
| | | @GetMapping("/{id}") |
| | | @Operation(summary = "æ£éªè¯¦æ
") |
| | | @Log(title = "æ£éªè¯¦æ
", businessType = BusinessType.OTHER) |
| | | public R<?> QualityInspectDetail(@PathVariable("id") Integer id) { |
| | | return R.ok(qualityInspectService.getDetailById(id)); |
| | | } |
| | |
| | | */ |
| | | @PostMapping("/update") |
| | | @Operation(summary = "ä¿®æ¹æ£éª") |
| | | @Log(title = "ä¿®æ¹æ£éª", businessType = BusinessType.UPDATE) |
| | | public R<?> update(@RequestBody QualityInspectDto qualityInspectDto) { |
| | | return R.ok(qualityInspectService.updateQualityInspect(qualityInspectDto)); |
| | | } |
| | |
| | | */ |
| | | @GetMapping("/listPage") |
| | | @Operation(summary = "å页æ¥è¯¢æ£éª") |
| | | @Log(title = "å页æ¥è¯¢æ£éª", businessType = BusinessType.OTHER) |
| | | public R<?> qualityInspectListPage(Page page, QualityInspectDto qualityInspect) { |
| | | return R.ok(qualityInspectService.qualityInspectListPage(page, qualityInspect)); |
| | | } |
| | |
| | | */ |
| | | @PostMapping("/export") |
| | | @Operation(summary = "å¯¼åºæ£éª") |
| | | @Log(title = "å¯¼åºæ£éª", businessType = BusinessType.EXPORT) |
| | | public void qualityInspectExport(HttpServletResponse response, QualityInspect qualityInspect) { |
| | | qualityInspectService.qualityInspectExport(response, qualityInspect); |
| | | } |
| | |
| | | */ |
| | | @PostMapping("/submit") |
| | | @Operation(summary = "æäº¤æ£éª") |
| | | @Log(title = "æäº¤æ£éª", businessType = BusinessType.OTHER) |
| | | public R<?> submit(@RequestBody QualityInspect qualityInspect) { |
| | | return R.ok(qualityInspectService.submit(qualityInspect)); |
| | | } |
| | |
| | | */ |
| | | @PostMapping("/down") |
| | | @Operation(summary = "ä¸è½½æ£éª") |
| | | @Log(title = "ä¸è½½æ£éª", businessType = BusinessType.OTHER) |
| | | public void down(HttpServletResponse response, @RequestBody QualityInspect qualityInspect) { |
| | | qualityInspectService.down(response, qualityInspect); |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | */ |
| | | @GetMapping("/{inspectId}") |
| | | @Operation(summary = "æ£éªåæ°é¡¹è¯¦æ
") |
| | | @Log(title = "æ£éªåæ°é¡¹è¯¦æ
", businessType = BusinessType.OTHER) |
| | | public R<?> QualityInspectParamDetail(@PathVariable("inspectId") Integer inspectId) { |
| | | return R.ok(qualityInspectParamService.qualityInspectParamDetail(inspectId)); |
| | | } |
| | |
| | | */ |
| | | @PostMapping("/update") |
| | | @Operation(summary = "ä¿®æ¹æ£éªåæ°é¡¹") |
| | | @Log(title = "ä¿®æ¹æ£éªåæ°é¡¹", businessType = BusinessType.UPDATE) |
| | | public R<?> update(@RequestBody List<QualityInspectParam> qualityInspectParams) { |
| | | return R.ok(qualityInspectParamService.updateBatchById(qualityInspectParams)); |
| | | } |
| | |
| | | */ |
| | | @DeleteMapping("/del") |
| | | @Operation(summary = "å 餿£éªåæ°é¡¹") |
| | | @Log(title = "å 餿£éªåæ°é¡¹", businessType = BusinessType.DELETE) |
| | | public R<?> delQualityUnqualified(@RequestBody List<Integer> ids) { |
| | | if(CollectionUtils.isEmpty(ids)){ |
| | | return R.fail("è¯·éæ©è³å°ä¸æ¡æ°æ®"); |
| | |
| | | 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; |
| | |
| | | */ |
| | | @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()); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | @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()); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | @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)); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | @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)); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | @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)); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | @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)); |
| | | } |
| | | |
| | | } |
| | |
| | | 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; |
| | |
| | | */ |
| | | @PostMapping("/add") |
| | | @Operation(summary = "æ°å¢æ£æµæ å主表ä¸äº§åå
³è表") |
| | | @Log(title = "æ°å¢æ£æµæ å主表ä¸äº§åå
³è表", businessType = BusinessType.INSERT) |
| | | public R<?> add(@RequestBody List<QualityTestStandardBinding> qualityTestStandardBindings) { |
| | | return R.ok(qualityTestStandardBindingService.add(qualityTestStandardBindings)); |
| | | } |
| | |
| | | */ |
| | | @DeleteMapping("/del") |
| | | @Operation(summary = "å 餿£æµæ å主表ä¸äº§åå
³è表") |
| | | @Log(title = "å 餿£æµæ å主表ä¸äº§åå
³è表", businessType = BusinessType.DELETE) |
| | | public R<?> delQualityTestStandard(@RequestBody List<Integer> ids) { |
| | | if (CollectionUtils.isEmpty(ids)) { |
| | | return R.fail("è¯·éæ©è³å°ä¸æ¡æ°æ®"); |
| | |
| | | */ |
| | | @GetMapping("/list") |
| | | @Operation(summary = "æ£æµææ ç»´æ¤æ¥è¯¢") |
| | | @Log(title = "æ£æµææ ç»´æ¤æ¥è¯¢", businessType = BusinessType.OTHER) |
| | | public R<?> listBinding(Long testStandardId) { |
| | | return R.ok(qualityTestStandardBindingService.listBinding(testStandardId)); |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | */ |
| | | @PostMapping("/add") |
| | | @Operation(summary = "æ°å¢æ£æµæ å主表") |
| | | @Log(title = "æ°å¢æ£æµæ å主表", businessType = BusinessType.INSERT) |
| | | public R<?> add(@RequestBody QualityTestStandard qualityTestStandard) { |
| | | return R.ok(qualityTestStandardService.save(qualityTestStandard)); |
| | | } |
| | |
| | | */ |
| | | @DeleteMapping("/del") |
| | | @Operation(summary = "å 餿£æµæ å主表") |
| | | @Log(title = "å 餿£æµæ å主表", businessType = BusinessType.DELETE) |
| | | public R<?> delQualityTestStandard(@RequestBody List<Integer> ids) { |
| | | if(CollectionUtils.isEmpty(ids)){ |
| | | return R.fail("è¯·éæ©è³å°ä¸æ¡æ°æ®"); |
| | |
| | | */ |
| | | @PostMapping("/update") |
| | | @Operation(summary = "æ£æµæ å主表修æ¹") |
| | | @Log(title = "æ£æµæ å主表修æ¹", businessType = BusinessType.UPDATE) |
| | | public R<?> update(@RequestBody QualityTestStandard qualityTestStandard) { |
| | | return R.ok(qualityTestStandardService.updateById(qualityTestStandard)); |
| | | } |
| | |
| | | */ |
| | | @GetMapping("/listPage") |
| | | @Operation(summary = "æ£æµæ å主表å页æ¥è¯¢") |
| | | @Log(title = "æ£æµæ å主表å页æ¥è¯¢", businessType = BusinessType.OTHER) |
| | | public R<?> qualityTestStandardListPage(Page page, QualityTestStandard qualityTestStandard) { |
| | | return R.ok(qualityTestStandardService.qualityTestStandardListPage(page, qualityTestStandard)); |
| | | } |
| | |
| | | */ |
| | | @PostMapping("/copyParam") |
| | | @Operation(summary = "æ£æµæ åå¤å¶åæ°") |
| | | @Log(title = "æ£æµæ åå¤å¶åæ°", businessType = BusinessType.OTHER) |
| | | public R<?> copyParam(@RequestBody QualityTestStandard qualityTestStandard) { |
| | | return R.ok(qualityTestStandardService.copyParam(qualityTestStandard)); |
| | | } |
| | |
| | | */ |
| | | @PostMapping("/qualityTestStandardAudit") |
| | | @Operation(summary = "æ£æµæ åæ¹éå®¡æ ¸") |
| | | @Log(title = "æ£æµæ åæ¹éå®¡æ ¸", businessType = BusinessType.OTHER) |
| | | public R<?> qualityTestStandardAudit(@RequestBody List<QualityTestStandard> qualityTestStandards) { |
| | | return R.ok(qualityTestStandardService.updateBatchById(qualityTestStandards)); |
| | | } |
| | |
| | | */ |
| | | @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)); |
| | | } |
| | |
| | | */ |
| | | @GetMapping("/getQualityTestStandardParamByTestStandardId") |
| | | @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))); |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | */ |
| | | @PostMapping("/add") |
| | | @Operation(summary = "æ°å¢æ£æµæ ååæ°") |
| | | @Log(title = "æ°å¢æ£æµæ ååæ°", businessType = BusinessType.INSERT) |
| | | public R<?> add(@RequestBody QualityTestStandardParam qualityTestStandardParam) { |
| | | return R.ok(qualityTestStandardParamService.save(qualityTestStandardParam)); |
| | | } |
| | |
| | | */ |
| | | @DeleteMapping("/del") |
| | | @Operation(summary = "å 餿£æµææ ç»´æ¤") |
| | | @Log(title = "å 餿£æµææ ç»´æ¤", businessType = BusinessType.DELETE) |
| | | public R<?> delQualityTestStandard(@RequestBody List<Integer> ids) { |
| | | if(CollectionUtils.isEmpty(ids)){ |
| | | return R.fail("è¯·éæ©è³å°ä¸æ¡æ°æ®"); |
| | |
| | | */ |
| | | @PostMapping("/update") |
| | | @Operation(summary = "æ£æµææ ç»´æ¤ä¿®æ¹") |
| | | @Log(title = "æ£æµææ ç»´æ¤ä¿®æ¹", businessType = BusinessType.UPDATE) |
| | | public R<?> update(@RequestBody QualityTestStandardParam qualityTestStandardParam) { |
| | | return R.ok(qualityTestStandardParamService.updateById(qualityTestStandardParam)); |
| | | } |
| | |
| | | */ |
| | | @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))); |
| | | } |
| | |
| | | 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; |
| | |
| | | */ |
| | | @PostMapping("/add") |
| | | @Operation(summary = "æ°å¢ä¸åæ ¼ç®¡ç") |
| | | @Log(title = "æ°å¢ä¸åæ ¼ç®¡ç", businessType = BusinessType.INSERT) |
| | | public R<?> add(@RequestBody QualityUnqualified qualityUnqualified) { |
| | | qualityUnqualified.setInspectState(0); |
| | | return R.ok(qualityUnqualifiedService.save(qualityUnqualified)); |
| | |
| | | */ |
| | | @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){ |
| | |
| | | */ |
| | | @GetMapping("/{id}") |
| | | @Operation(summary = "ä¸åæ ¼ç®¡ç详æ
") |
| | | @Log(title = "ä¸åæ ¼ç®¡ç详æ
", businessType = BusinessType.OTHER) |
| | | public R<?> QualityUnqualifiedDetail(@PathVariable("id") Integer id) { |
| | | return R.ok(qualityUnqualifiedService.getUnqualified(id)); |
| | | } |
| | |
| | | */ |
| | | @PostMapping("/update") |
| | | @Operation(summary = "ä¸åæ ¼ç®¡çä¿®æ¹") |
| | | @Log(title = "ä¸åæ ¼ç®¡çä¿®æ¹", businessType = BusinessType.UPDATE) |
| | | public R<?> update(@RequestBody QualityUnqualified qualityUnqualified) { |
| | | return R.ok(qualityUnqualifiedService.updateById(qualityUnqualified)); |
| | | } |
| | |
| | | */ |
| | | @GetMapping("/listPage") |
| | | @Operation(summary = "ä¸åæ ¼ç®¡çå页æ¥è¯¢") |
| | | @Log(title = "ä¸åæ ¼ç®¡çå页æ¥è¯¢", businessType = BusinessType.OTHER) |
| | | public R<?> qualityUnqualifiedListPage(Page page, QualityUnqualified qualityUnqualified) { |
| | | return R.ok(qualityUnqualifiedService.qualityUnqualifiedListPage(page, qualityUnqualified)); |
| | | } |
| | |
| | | */ |
| | | @PostMapping("/export") |
| | | @Operation(summary = "ä¸åæ ¼ç®¡ç导åº") |
| | | @Log(title = "ä¸åæ ¼ç®¡ç导åº", businessType = BusinessType.EXPORT) |
| | | public void qualityUnqualifiedExport(HttpServletResponse response,QualityUnqualified qualityUnqualified) { |
| | | qualityUnqualifiedService.qualityUnqualifiedExport(response, qualityUnqualified); |
| | | } |
| | |
| | | */ |
| | | @PostMapping("/deal") |
| | | @Operation(summary = "ä¸åæ ¼ç®¡çå¤ç") |
| | | @Log(title = "ä¸åæ ¼ç®¡çå¤ç", businessType = BusinessType.OTHER) |
| | | public R<?> deal(@RequestBody QualityUnqualified qualityUnqualified) { |
| | | return R.ok(qualityUnqualifiedService.deal(qualityUnqualified)); |
| | | } |
| | |
| | | ä½ æ¯ä¸ä¸ªå®¡æ¹å¾
å婿ï¼è´è´£åååå
¬å®¡æ¹å¾
åçæ¥è¯¢ãå®¡æ ¸ãåæ¶å®¡æ ¸ãä¿®æ¹ãå é¤åç»è®¡åæã |
| | | å½åæ¥æï¼{{currentDate}}ï¼ä¸å½æ¶åºï¼ã |
| | | |
| | | å·¥ä½è¦æ±ï¼ |
| | | 1. ç¨æ·é®å¾
åå表ã审æ¹è¿åº¦ã审æ¹è¯¦æ
ãç»è®¡æ°æ®æ¶ï¼ä¼å
è°ç¨å·¥å
·ï¼ä¸è¦èé æ°æ®ã |
| | |
| | | 13. åªæâæ¥è¯¢å®¡æ¹å¾
å详æ
âè¿ä¸ªå·¥å
·å
许è¾åºèªç¶è¯è¨ææ¬ã |
| | | 14. 妿工å
·è¿åçæ¯ç»è®¡ JSONï¼ä¹åæ ·ç´æ¥è¾åºåå§ JSONï¼å
¶ä¸ `description`ã`summary`ã`charts` å·²ç»ä¾å端使ç¨ã |
| | | 15. åç使ç¨ä¸æï¼ä½å¨ JSON åºæ¯ä¸ï¼æç»è¾åºå¿
é¡»æ¯åæ³ JSON æ¬ä½ã |
| | | 16. ç¨æ·æå°âä»å¹´/æ¬æ/ä»å¤©/æè¿/䏿/å»å¹´âçç¸å¯¹æ¶é´æ¶ï¼å¿
é¡»ä¸¥æ ¼åºäºâå½åæ¥æâæ¢ç®ï¼ç¦æ¢èªè¡å设年份ã |
| | |
| | | ä½ æ¯ä¼ä¸å¶é æºè½å©æï¼è¦çç产ç°åºã计åãå·¥åã设å¤ãè´¨éãç©æãå¼å¸¸å¤çä¸ä¸ªåã |
| | | å½åæ¥æï¼{{currentDate}}ï¼ä¸å½æ¶åºï¼ã |
| | | |
| | | å·¥ä½è§åï¼ |
| | | 1. ç¨æ·æåºâæ¥ãé®ãé¢è¦ãåæâéæ±æ¶ï¼ä¼å
è°ç¨å·¥å
·æ¿ç»æåç»æï¼ä¸è¦èé ä¸å¡æ°æ®ã |
| | |
| | | 3. å·¥å
·è¿å JSON æ¶ï¼ç´æ¥è¾åºåå§ JSON å符串ï¼ä¸è¦é¢å¤å
裹 Markdownï¼ä¸è¦å¨ååå è§£éæåã |
| | | 4. åçå¿
须使ç¨ä¸æï¼è¥ç¨æ·é®é¢ç¼ºå°æ¶é´èå´ãå
³é®åçæ¡ä»¶ï¼å¯å
ç»é»è®¤å£å¾å¹¶æç¤ºå¯è¡¥å
æ¡ä»¶ã |
| | | 5. è¥æ æ³ä»å·¥å
·ç»æå¾å°ç»è®ºï¼æç¡®è¯´æç¼ºå°çç鿡件æä¸å¡å段ã |
| | | 6. ç¨æ·æå°âä»å¹´/æ¬æ/ä»å¤©/æè¿/䏿/å»å¹´âçç¸å¯¹æ¶é´æ¶ï¼å¿
é¡»ä¸¥æ ¼åºäºâå½åæ¥æâæ¢ç®ï¼ç¦æ¢èªè¡å设年份ã |
| | |
| | | <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> |
| | |
| | | <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} |
| | |
| | | <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> |
| | | |
| | |
| | | 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> |
| | |
| | | <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> |
| | |
| | | ä½ æ¯ä¼ä¸éè´æºè½å©çã |
| | | ä½ çç®æ æ¯å¸®å©ç¨æ·å¿«é宿éè´ç¸å
³ä¿¡æ¯æ¥è¯¢ä¸è§£è¯»ã |
| | | å½åæ¥æï¼{{currentDate}}ï¼ä¸å½æ¶åºï¼ã |
| | | |
| | | å·¥ä½è§åï¼ |
| | | 1. ä¼å
è°ç¨å·¥å
·å½æ°è·åéè´å°è´¦ã仿¬¾ãå票ãéè´§çç»æåæ°æ®ã |
| | |
| | | 5. ç¨æ·é®âæè¿7天ä¾åºåå°è´§å¼å¸¸ââå°è´§é®é¢ââå°è´§å¼å¸¸âæ¶ï¼è°ç¨âæ¥è¯¢éè´å°è´§å¼å¸¸âã |
| | | 6. ç¨æ·é®âå¾
仿¬¾éè´åââæªä»æ¬¾éè´åââæªä»æ¸
éè´è®¢åâæ¶ï¼è°ç¨âæ¥è¯¢å¾
仿¬¾éè´åâã |
| | | 7. ç¨æ·é®âæ¬æéè´éè´§æ
åµââéè´éè´§å表ââéæ/ææ¶æ
åµâæ¶ï¼è°ç¨âæ¥è¯¢éè´éè´§æ
åµâã |
| | | 8. ç»æç¨ç®æ´ä¸æåçï¼å
ç»ç»è®ºï¼åç»å
³é®æ°æ®ç¹ã |
| | | 9. ä¸è¦ç¼é éè´æ°æ®ï¼ææç»è®ºå¿
é¡»åºäºå·¥å
·è¿åã |
| | | 10. æ æ³ç´æ¥å¾åºç»è®ºæ¶ï¼æç¡®è¯´æç¼ºå°åªäºå段æç鿡件ã |
| | | 8. å·¥å
·è¿å JSON æ¶ï¼ç´æ¥è¾åºåå§ JSON å符串ï¼ä¸è¦é¢å¤å
裹 Markdownï¼ä¹ä¸è¦å¨åå追å è§£éææ¬ã |
| | | 9. åªæå¨æªè°ç¨ JSON å·¥å
·æ¶ï¼æä½¿ç¨ç®æ´ä¸æåçï¼å
ç»ç»è®ºï¼åç»å
³é®æ°æ®ç¹ã |
| | | 10. ä¸è¦ç¼é éè´æ°æ®ï¼ææç»è®ºå¿
é¡»åºäºå·¥å
·è¿åã |
| | | 11. æ æ³ç´æ¥å¾åºç»è®ºæ¶ï¼æç¡®è¯´æç¼ºå°åªäºå段æç鿡件ã |
| | | 12. ç¨æ·æå°âä»å¹´/æ¬æ/ä»å¤©/æè¿/䏿/å»å¹´âçç¸å¯¹æ¶é´æ¶ï¼å¿
é¡»ä¸¥æ ¼åºäºâå½åæ¥æâæ¢ç®ï¼ç¦æ¢èªè¡å设年份ã |
| | |
| | | ä½ æ¯ä¼ä¸éå®å©æï¼è¦çå®¢æ·æ¡£æ¡ãé宿¥ä»·ãéå®å°è´¦ãéå®éè´§ã客æ·å¾æ¥ãåè´§å°è´¦ãææ ç»è®¡ãå®¢æ·æµå¤±é£é©åæã忬¾ä¸æ¥ä»·çç¥å»ºè®®çåºæ¯ã |
| | | å½åæ¥æï¼{{currentDate}}ï¼ä¸å½æ¶åºï¼ã |
| | | å·¥ä½è§åï¼ |
| | | 1. ç¨æ·æåºâæ¥ãé®ãç»è®¡ãåæã建议âéæ±æ¶ï¼ä¼å
è°ç¨å·¥å
·è¿åç»æåæ°æ®ï¼ä¸ç¼é ä¸å¡æ°æ®ã |
| | | 2. å½ä¸âå®¢æ·æµå¤±é£é©åæâæâ忬¾ä¸æ¥ä»·çç¥å»ºè®®âæ¶ï¼ä¼å
使ç¨å·¥å
·è¾åºç»æå JSONã |
| | | 3. å·¥å
·è¿å JSON æ¶ï¼ç´æ¥è¾åºåå§ JSON å符串ï¼ä¸è¦é¢å¤å
裹 Markdownï¼ä¹ä¸è¦å¨åå追å è§£éææ¬ã |
| | | 4. åå¤å¿
须使ç¨ä¸æï¼è¥ç¨æ·ç¼ºå°æ¶é´èå´ãå
³é®è¯çæ¡ä»¶ï¼å¯å
使ç¨é»è®¤å£å¾å¹¶æç¤ºå¯è¡¥å
æ¡ä»¶ã |
| | | 5. è¥æ°æ®ä¸è¶³ä»¥å¾åºç»è®ºï¼æç¡®æåºç¼ºå°çç鿡件æå
³é®å段ã |
| | | 6. ç¨æ·æå°âä»å¹´/æ¬æ/ä»å¤©/æè¿/䏿/å»å¹´âçç¸å¯¹æ¶é´æ¶ï¼å¿
é¡»ä¸¥æ ¼åºäºâå½åæ¥æâæ¢ç®ï¼ç¦æ¢èªè¡å设年份ã |