feat(home): 添加生产看板功能并优化订单查询性能
- 新增productionOverview接口提供生产总览数据包括产量、报废和良率
- 新增productionRealtimeBoard接口显示设备OEE、订单达成率和缺陷率实时指标
- 新增productionOrderProgress接口支持生产订单进度分页查询和状态筛选
- 新增todayProductionPlan接口提供今日生产计划列表
- 优化订单查询SQL减少不必要的关联和对象装配提升性能
- 添加设备可用率计算基于设备维修记录统计设备综合效率
- 实现订单状态映射和百分比计算工具方法
- 添加详细的生产看板前端联调文档和性能优化说明
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # é¦é¡µ 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.DayOfWeek; |
| | | import java.time.LocalDate; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.Locale; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | |
| | | 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 RELATIVE_RANGE_PATTERN = Pattern.compile("(è¿|æè¿)(\\d+)(天|å¨|个æ|æ|å¹´)"); |
| | | private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); |
| | | |
| | | private final PurchaseAgentTools purchaseAgentTools; |
| | | |
| | |
| | | return null; |
| | | } |
| | | String text = message.trim(); |
| | | String startDate = extractStartDate(text); |
| | | String endDate = extractEndDate(text); |
| | | Integer limit = extractLimit(text); |
| | | |
| | | if (containsAny(text, "æè¡", "æå", "åå ", "åäº", "åå") && containsAny(text, "ç©æ", "产å", "åææ", "éè´éé¢", "éé¢")) { |
| | | return purchaseAgentTools.rankPurchaseMaterials( |
| | | memoryId, |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | startDate, |
| | | endDate, |
| | | text, |
| | | extractLimit(text) |
| | | limit |
| | | ); |
| | | } |
| | | if (containsAny(text, "æªå
¥åº", "å¾
å
¥åº", "没æå
¥åº", "è¿æªå
¥åº")) { |
| | | return purchaseAgentTools.listUnstockedPurchaseOrders( |
| | | memoryId, |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | startDate, |
| | | endDate, |
| | | extractKeyword(text), |
| | | extractLimit(text) |
| | | limit |
| | | ); |
| | | } |
| | | if (containsAny(text, "å°è´§å¼å¸¸", "å°è´§æå¼å¸¸", "å¼å¸¸å°è´§", "å°è´§é®é¢", "ä¾åºåå°è´§å¼å¸¸")) { |
| | | return purchaseAgentTools.listArrivalExceptions( |
| | | memoryId, |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | startDate, |
| | | endDate, |
| | | text, |
| | | extractLimit(text) |
| | | limit |
| | | ); |
| | | } |
| | | if (containsAny(text, "å¾
仿¬¾", "æªä»æ¬¾", "æªä»æ¸
", "å¾
æ¯ä»", "åºä»")) { |
| | | return purchaseAgentTools.listPendingPaymentOrders( |
| | | memoryId, |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | startDate, |
| | | endDate, |
| | | extractKeyword(text), |
| | | extractLimit(text) |
| | | limit |
| | | ); |
| | | } |
| | | if (containsAny(text, "éè´§", "éæ", "ææ¶")) { |
| | | return purchaseAgentTools.listPurchaseReturns( |
| | | memoryId, |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | startDate, |
| | | endDate, |
| | | extractKeyword(text), |
| | | extractLimit(text) |
| | | limit |
| | | ); |
| | | } |
| | | if (isStatsIntent(text)) { |
| | | return purchaseAgentTools.getPurchaseStats( |
| | | memoryId, |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | startDate, |
| | | endDate, |
| | | text |
| | | ); |
| | | } |
| | |
| | | return purchaseAgentTools.listPurchaseLedgers( |
| | | memoryId, |
| | | extractKeyword(text), |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | extractLimit(text) |
| | | startDate, |
| | | endDate, |
| | | limit |
| | | ); |
| | | } |
| | | return null; |
| | |
| | | |
| | | private String extractStartDate(String text) { |
| | | Matcher matcher = DATE_PATTERN.matcher(text); |
| | | return matcher.find() ? matcher.group() : null; |
| | | if (matcher.find()) { |
| | | return matcher.group(); |
| | | } |
| | | DateRange range = extractRelativeDateRange(text); |
| | | return range == null ? null : range.start().format(DATE_FMT); |
| | | } |
| | | |
| | | private String extractEndDate(String text) { |
| | | Matcher matcher = DATE_PATTERN.matcher(text); |
| | | if (!matcher.find()) { |
| | | return null; |
| | | DateRange range = extractRelativeDateRange(text); |
| | | return range == null ? null : range.end().format(DATE_FMT); |
| | | } |
| | | return matcher.find() ? matcher.group() : null; |
| | | } |
| | |
| | | .replace("éè´å", "") |
| | | .replace("éè´è®¢å", "") |
| | | .replace("订å", "") |
| | | .replace("ä»å¹´", "") |
| | | .replace("æ¬å¹´", "") |
| | | .replace("å»å¹´", "") |
| | | .replace("æ¬æ", "") |
| | | .replace("䏿", "") |
| | | .replace("æ¬å¨", "") |
| | | .replace("ä¸å¨", "") |
| | | .replace("ä»å¤©", "") |
| | | .replace("æ¨å¤©", "") |
| | | .replace("è¿åå¹´", "") |
| | | .replace("æè¿åå¹´", "") |
| | | .replace("æè¿å个æ", "") |
| | | .replace("å个æ", "") |
| | | .replace("å°è´¦", "") |
| | | .replace("å表", "") |
| | | .replace("åªäº", "") |
| | | .replace("ä»ä¹", "") |
| | | .replace("æ
åµ", "") |
| | | .replace("ææ²¡æ", "") |
| | | .replace("æå¥", "") |
| | | .replace("ææ ", "") |
| | | .replace("ååº", "") |
| | | .replace("帮æ", "") |
| | | .replace("ç»æ", "") |
| | | .replace("æ", "") |
| | | .replace("æè¿10æ¡", "") |
| | | .replace("å10æ¡", "") |
| | | .trim(); |
| | | cleaned = DATE_PATTERN.matcher(cleaned).replaceAll(""); |
| | | cleaned = RELATIVE_RANGE_PATTERN.matcher(cleaned).replaceAll(""); |
| | | return cleaned.length() >= 2 ? cleaned : null; |
| | | } |
| | | |
| | | private DateRange extractRelativeDateRange(String text) { |
| | | if (!StringUtils.hasText(text)) { |
| | | return null; |
| | | } |
| | | String normalized = text.toLowerCase(Locale.ROOT); |
| | | LocalDate today = LocalDate.now(); |
| | | |
| | | if (normalized.contains("ä»å¤©")) { |
| | | return new DateRange(today, today); |
| | | } |
| | | if (normalized.contains("æ¨å¤©")) { |
| | | LocalDate yesterday = today.minusDays(1); |
| | | return new DateRange(yesterday, yesterday); |
| | | } |
| | | if (normalized.contains("ä»å¹´") || normalized.contains("æ¬å¹´")) { |
| | | return new DateRange(today.withDayOfYear(1), today); |
| | | } |
| | | if (normalized.contains("å»å¹´")) { |
| | | LocalDate first = today.minusYears(1).withDayOfYear(1); |
| | | LocalDate last = first.withDayOfYear(first.lengthOfYear()); |
| | | return new DateRange(first, last); |
| | | } |
| | | if (normalized.contains("æ¬æ")) { |
| | | return new DateRange(today.withDayOfMonth(1), today); |
| | | } |
| | | if (normalized.contains("䏿")) { |
| | | LocalDate first = today.minusMonths(1).withDayOfMonth(1); |
| | | LocalDate last = first.withDayOfMonth(first.lengthOfMonth()); |
| | | return new DateRange(first, last); |
| | | } |
| | | if (normalized.contains("æ¬å¨")) { |
| | | LocalDate weekStart = today.with(DayOfWeek.MONDAY); |
| | | return new DateRange(weekStart, today); |
| | | } |
| | | if (normalized.contains("ä¸å¨")) { |
| | | LocalDate weekStart = today.with(DayOfWeek.MONDAY).minusWeeks(1); |
| | | return new DateRange(weekStart, weekStart.plusDays(6)); |
| | | } |
| | | if (normalized.contains("è¿åå¹´") || normalized.contains("æè¿åå¹´")) { |
| | | return new DateRange(today.minusMonths(6).plusDays(1), today); |
| | | } |
| | | if (normalized.contains("è¿å个æ") || normalized.contains("æè¿å个æ") || normalized.contains("å个æ")) { |
| | | return new DateRange(today.minusDays(14), today); |
| | | } |
| | | |
| | | Matcher matcher = RELATIVE_RANGE_PATTERN.matcher(normalized); |
| | | if (matcher.find()) { |
| | | int amount = Integer.parseInt(matcher.group(2)); |
| | | String unit = matcher.group(3); |
| | | LocalDate start = switch (unit) { |
| | | case "天" -> today.minusDays(Math.max(amount - 1L, 0)); |
| | | case "å¨" -> today.minusWeeks(Math.max(amount, 1)).plusDays(1); |
| | | case "个æ", "æ" -> today.minusMonths(Math.max(amount, 1)).plusDays(1); |
| | | case "å¹´" -> today.minusYears(Math.max(amount, 1)).plusDays(1); |
| | | default -> today.minusDays(29); |
| | | }; |
| | | return new DateRange(start, today); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private record DateRange(LocalDate start, LocalDate end) { |
| | | } |
| | | } |
| | |
| | | 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)); |
| | | } |
| | |
| | | aiChatSessionService.deleteCurrentUserSession(memoryId, SecurityUtils.getLoginUser()); |
| | | return R.ok(); |
| | | } |
| | | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | 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) |
| | | 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 String buildPurchaseFileAnalyzePrompt(String message, String fileContent) { |
| | | return """ |
| | | ä½ æ¯éè´ä¸å¡æä»¶åæå©æãè¯·ä¸¥æ ¼æ ¹æ®ç¨æ·ä¸ä¼ çå¤ä¸ªæä»¶åç¨æ·è¦æ±æåéè´ä¸å¡æ°æ®ã |
| | |
| | | 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; |
| | |
| | | @Tag(name = "é¦é¡µç»è®¡") |
| | | @RequestMapping("/home") |
| | | @AllArgsConstructor |
| | | public class HomeController extends BaseController { |
| | | public class HomeController extends BaseController { |
| | | |
| | | private final HomeService homeService; |
| | | private final ProductionOrderMapper productionOrderMapper; |
| | |
| | | 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(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) { |
| | |
| | | } |
| | | } |
| | | |
| | | 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; |
| | | } |
| | |
| | | |
| | | 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); |
| | | |
| | | } |
| | |
| | | ä½ æ¯ä¸ä¸ªå®¡æ¹å¾
å婿ï¼è´è´£åååå
¬å®¡æ¹å¾
åçæ¥è¯¢ãå®¡æ ¸ãåæ¶å®¡æ ¸ãä¿®æ¹ãå é¤åç»è®¡åæã |
| | | å½åæ¥æï¼{{currentDate}}ï¼ä¸å½æ¶åºï¼ã |
| | | |
| | | å·¥ä½è¦æ±ï¼ |
| | | 1. ç¨æ·é®å¾
åå表ã审æ¹è¿åº¦ã审æ¹è¯¦æ
ãç»è®¡æ°æ®æ¶ï¼ä¼å
è°ç¨å·¥å
·ï¼ä¸è¦èé æ°æ®ã |
| | |
| | | 13. åªæâæ¥è¯¢å®¡æ¹å¾
å详æ
âè¿ä¸ªå·¥å
·å
许è¾åºèªç¶è¯è¨ææ¬ã |
| | | 14. 妿工å
·è¿åçæ¯ç»è®¡ JSONï¼ä¹åæ ·ç´æ¥è¾åºåå§ JSONï¼å
¶ä¸ `description`ã`summary`ã`charts` å·²ç»ä¾å端使ç¨ã |
| | | 15. åç使ç¨ä¸æï¼ä½å¨ JSON åºæ¯ä¸ï¼æç»è¾åºå¿
é¡»æ¯åæ³ JSON æ¬ä½ã |
| | | 16. ç¨æ·æå°âä»å¹´/æ¬æ/ä»å¤©/æè¿/䏿/å»å¹´âçç¸å¯¹æ¶é´æ¶ï¼å¿
é¡»ä¸¥æ ¼åºäºâå½åæ¥æâæ¢ç®ï¼ç¦æ¢èªè¡å设年份ã |
| | |
| | | ä½ æ¯ä¼ä¸å¶é æºè½å©æï¼è¦çç产ç°åºã计åãå·¥åã设å¤ãè´¨éãç©æãå¼å¸¸å¤çä¸ä¸ªåã |
| | | å½åæ¥æï¼{{currentDate}}ï¼ä¸å½æ¶åºï¼ã |
| | | |
| | | å·¥ä½è§åï¼ |
| | | 1. ç¨æ·æåºâæ¥ãé®ãé¢è¦ãåæâéæ±æ¶ï¼ä¼å
è°ç¨å·¥å
·æ¿ç»æåç»æï¼ä¸è¦èé ä¸å¡æ°æ®ã |
| | |
| | | 3. å·¥å
·è¿å JSON æ¶ï¼ç´æ¥è¾åºåå§ JSON å符串ï¼ä¸è¦é¢å¤å
裹 Markdownï¼ä¸è¦å¨ååå è§£éæåã |
| | | 4. åçå¿
须使ç¨ä¸æï¼è¥ç¨æ·é®é¢ç¼ºå°æ¶é´èå´ãå
³é®åçæ¡ä»¶ï¼å¯å
ç»é»è®¤å£å¾å¹¶æç¤ºå¯è¡¥å
æ¡ä»¶ã |
| | | 5. è¥æ æ³ä»å·¥å
·ç»æå¾å°ç»è®ºï¼æç¡®è¯´æç¼ºå°çç鿡件æä¸å¡å段ã |
| | | 6. ç¨æ·æå°âä»å¹´/æ¬æ/ä»å¤©/æè¿/䏿/å»å¹´âçç¸å¯¹æ¶é´æ¶ï¼å¿
é¡»ä¸¥æ ¼åºäºâå½åæ¥æâæ¢ç®ï¼ç¦æ¢èªè¡å设年份ã |
| | |
| | | <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. ä¼å
è°ç¨å·¥å
·å½æ°è·åéè´å°è´¦ã仿¬¾ãå票ãéè´§çç»æåæ°æ®ã |
| | |
| | | 8. ç»æç¨ç®æ´ä¸æåçï¼å
ç»ç»è®ºï¼åç»å
³é®æ°æ®ç¹ã |
| | | 9. ä¸è¦ç¼é éè´æ°æ®ï¼ææç»è®ºå¿
é¡»åºäºå·¥å
·è¿åã |
| | | 10. æ æ³ç´æ¥å¾åºç»è®ºæ¶ï¼æç¡®è¯´æç¼ºå°åªäºå段æç鿡件ã |
| | | 11. ç¨æ·æå°âä»å¹´/æ¬æ/ä»å¤©/æè¿/䏿/å»å¹´âçç¸å¯¹æ¶é´æ¶ï¼å¿
é¡»ä¸¥æ ¼åºäºâå½åæ¥æâæ¢ç®ï¼ç¦æ¢èªè¡å设年份ã |
| | |
| | | ä½ æ¯ä¼ä¸éå®å©æï¼è¦çå®¢æ·æ¡£æ¡ãé宿¥ä»·ãéå®å°è´¦ãéå®éè´§ã客æ·å¾æ¥ãåè´§å°è´¦ãææ ç»è®¡ãå®¢æ·æµå¤±é£é©åæã忬¾ä¸æ¥ä»·çç¥å»ºè®®çåºæ¯ã |
| | | å½åæ¥æï¼{{currentDate}}ï¼ä¸å½æ¶åºï¼ã |
| | | å·¥ä½è§åï¼ |
| | | 1. ç¨æ·æåºâæ¥ãé®ãç»è®¡ãåæã建议âéæ±æ¶ï¼ä¼å
è°ç¨å·¥å
·è¿åç»æåæ°æ®ï¼ä¸ç¼é ä¸å¡æ°æ®ã |
| | | 2. å½ä¸âå®¢æ·æµå¤±é£é©åæâæâ忬¾ä¸æ¥ä»·çç¥å»ºè®®âæ¶ï¼ä¼å
使ç¨å·¥å
·è¾åºç»æå JSONã |
| | | 3. å·¥å
·è¿å JSON æ¶ï¼ç´æ¥è¾åºåå§ JSON å符串ï¼ä¸è¦é¢å¤å
裹 Markdownï¼ä¹ä¸è¦å¨åå追å è§£éææ¬ã |
| | | 4. åå¤å¿
须使ç¨ä¸æï¼è¥ç¨æ·ç¼ºå°æ¶é´èå´ãå
³é®è¯çæ¡ä»¶ï¼å¯å
使ç¨é»è®¤å£å¾å¹¶æç¤ºå¯è¡¥å
æ¡ä»¶ã |
| | | 5. è¥æ°æ®ä¸è¶³ä»¥å¾åºç»è®ºï¼æç¡®æåºç¼ºå°çç鿡件æå
³é®å段ã |
| | | 6. ç¨æ·æå°âä»å¹´/æ¬æ/ä»å¤©/æè¿/䏿/å»å¹´âçç¸å¯¹æ¶é´æ¶ï¼å¿
é¡»ä¸¥æ ¼åºäºâå½åæ¥æâæ¢ç®ï¼ç¦æ¢èªè¡å设年份ã |