doc/20260615_add_plan_person_and_executor_to_routing_operation.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,8 @@ # çäº§å·¥åºæ°å¢è®¡å人ååè®¡åæ§è¡äººååæ®µ ALTER TABLE technology_routing_operation ADD plan_person bigint NULL COMMENT '计å人åID', ADD executor bigint NULL COMMENT 'è®¡åæ§è¡äººåID'; ALTER TABLE production_order_routing_operation ADD plan_person bigint NULL COMMENT '计å人åID', ADD executor bigint NULL COMMENT 'è®¡åæ§è¡äººåID'; docs/mock_data_check.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,167 @@ # æ°æ®æ¨¡æ - åºç¡æ°æ®æ£æµ ## æ¶åé¡µé¢ - æ°æ®æ¨¡ææä½é¡µé¢ï¼æ°å¢ï¼ ## API | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | POST | /mock/dataCheck | æ£æµæå®æ¨¡åçåºç¡æ°æ®æ¯å¦å°±ç»ª | **请æ±åæ°ï¼** | åæ° | ç±»å | å¿ å¡« | 说æ | |------|------|------|------| | modules | List\<String\> | æ¯ | è¦æ£æµç模åå表ï¼å¯éå¼ï¼salesï¼éå®ï¼ãpurchaseï¼éè´ï¼ãqualityï¼è´¨éï¼ | 请æ±ä½ç¤ºä¾ï¼ ```json { "modules": ["sales", "purchase", "quality"] } ``` **ååºï¼** ```json { "code": 200, "msg": "æä½æå", "data": { "totalItems": 6, "passedItems": 3, "items": [ { "module": "common", "itemName": "äº§åæ°æ®", "minRequired": 1, "currentCount": 5, "passed": true, "message": "éè¿" }, { "module": "sales", "itemName": "å®¢æ·æ°æ®", "minRequired": 1, "currentCount": 0, "passed": false, "message": "缺å°å®¢æ·æ°æ®ï¼è¯·å å¨ãåºç¡æ°æ®-客æ·ç®¡çã䏿·»å è³å°1æ¡å®¢æ·" } ] } } ``` ## æ£æµè§å ### é宿¨¡å (sales) | æ£æµé¡¹ | æä½æ°é | æªéè¿æç¤º | |--------|----------|------------| | äº§åæ°æ® | 1 | 缺å°äº§åæ°æ®ï¼è¯·å å¨ãåºç¡æ°æ®-产å管çã䏿·»å è³å°1æ¡äº§å | | å®¢æ·æ°æ® | 1 | 缺å°å®¢æ·æ°æ®ï¼è¯·å å¨ãåºç¡æ°æ®-客æ·ç®¡çã䏿·»å è³å°1æ¡å®¢æ· | | æ¥ä»·å®¡æ¹æ¨¡æ¿ | 1 | ç¼ºå°æ¥ä»·å®¡æ¹æ¨¡æ¿ï¼è¯·å å¨ãç³»ç»ç®¡ç-å®¡æ¹æ¨¡æ¿ãä¸å建æ¥ä»·å®¡æ¹æ¨¡æ¿ | | åè´§å®¡æ¹æ¨¡æ¿ | 1 | 缺å°åè´§å®¡æ¹æ¨¡æ¿ï¼è¯·å å¨ãç³»ç»ç®¡ç-å®¡æ¹æ¨¡æ¿ãä¸å建åè´§å®¡æ¹æ¨¡æ¿ | ### éè´æ¨¡å (purchase) | æ£æµé¡¹ | æä½æ°é | æªéè¿æç¤º | |--------|----------|------------| | äº§åæ°æ® | 1 | 缺å°äº§åæ°æ®ï¼è¯·å å¨ãåºç¡æ°æ®-产å管çã䏿·»å è³å°1æ¡äº§å | | ä¾åºåæ°æ® | 1 | 缺å°ä¾åºåæ°æ®ï¼è¯·å å¨ãåºç¡æ°æ®-ä¾åºå管çã䏿·»å è³å°1æ¡ä¾åºå | | éè´å®¡æ¹æ¨¡æ¿ | 1 | 缺å°éè´å®¡æ¹æ¨¡æ¿ï¼è¯·å å¨ãç³»ç»ç®¡ç-å®¡æ¹æ¨¡æ¿ãä¸å建éè´å®¡æ¹æ¨¡æ¿ | ### è´¨éæ¨¡å (quality) | æ£æµé¡¹ | æä½æ°é | æªéè¿æç¤º | |--------|----------|------------| | äº§åæ°æ® | 1 | 缺å°äº§åæ°æ®ï¼è¯·å å¨ãåºç¡æ°æ®-产å管çã䏿·»å è³å°1æ¡äº§å | | æ£æµæ å | 1 | ç¼ºå°æ£æµæ åï¼è¯·å å¨ãè´¨é管ç-æ£æµæ åãä¸åå»ºæ£æµæ å | | ææ ç»å® | 1 | ç¼ºå°ææ ç»å®ï¼è¯·å å¨ãè´¨é管ç-æ£æµæ åç»å®ãä¸å°æ£æµæ åä¸äº§åç»å® | ## å端修æ¹ç¹ ### 1. æ°æ®æ¨¡æé¡µé¢å ¥å£ å¨å·¦ä¾§èåæ°å¢"æ°æ®æ¨¡æ"èå项ï¼è·¯ç± `/mock`ã ### 2. æ°æ®æ£æµåºå ```html <template> <div class="mock-container"> <el-card header="åºç¡æ°æ®æ£æµ"> <el-checkbox-group v-model="selectedModules"> <el-checkbox label="sales">é宿¨¡å</el-checkbox> <el-checkbox label="purchase">éè´æ¨¡å</el-checkbox> <el-checkbox label="quality">è´¨éæ¨¡å</el-checkbox> </el-checkbox-group> <el-button type="primary" @click="handleCheck" :loading="checking"> å¼å§æ£æµ </el-button> </el-card> <el-card v-if="checkResult" header="æ£æµç»æ" style="margin-top: 16px"> <el-alert :title="`éè¿ ${checkResult.passedItems} / ${checkResult.totalItems} 项`" :type="checkResult.passedItems === checkResult.totalItems ? 'success' : 'warning'" :closable="false" show-icon /> <el-table :data="checkResult.items" style="margin-top: 12px"> <el-table-column prop="module" label="模å" width="100" /> <el-table-column prop="itemName" label="æ£æµé¡¹" width="160" /> <el-table-column prop="minRequired" label="æä½è¦æ±" width="80" /> <el-table-column prop="currentCount" label="å½åæ°é" width="80" /> <el-table-column label="ç¶æ" width="80"> <template #default="{ row }"> <el-tag :type="row.passed ? 'success' : 'danger'"> {{ row.passed ? 'éè¿' : 'æªéè¿' }} </el-tag> </template> </el-table-column> <el-table-column prop="message" label="æç¤º" /> </el-table> </el-card> </div> </template> ``` ### 3. data æ°æ® ```js data() { return { selectedModules: ['sales', 'purchase', 'quality'], checking: false, checkResult: null, } } ``` ### 4. æ¹æ³ ```js import request from '@/utils/request' methods: { async handleCheck() { if (this.selectedModules.length === 0) { this.$message.warning('请è³å°éæ©ä¸ä¸ªæ¨¡å') return } this.checking = true try { const res = await request.post('/mock/dataCheck', { modules: this.selectedModules }) this.checkResult = res.data } finally { this.checking = false } } } ``` ## 注æäºé¡¹ - äº§åæ°æ®ï¼å ¬å ±åºç¡ï¼å¨å¤ä¸ªæ¨¡åé´å ±äº«ï¼æ£æµç»æä¸åªåºç°ä¸æ¬¡ï¼ä¸ä¼éå¤å±ç¤º - æ£æµä» ååªè¯»æ¥è¯¢ï¼ä¸åå ¥ä»»ä½æ°æ® - 模ååæ°ä¸ºç©ºæ°ç»æ¶è¿åç©ºæ£æµå表 - å»ºè®®å¨æ°æ®æ¨¡æå¼å§åå è°ç¨æ¤æ¥å£ç¡®è®¤åºç¡æ°æ®å°±ç»ª docs/mock_data_generate.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,243 @@ # æ°æ®æ¨¡æ - AI æ°æ®çæ ## æ¶åé¡µé¢ - æ°æ®æ¨¡ææä½é¡µé¢ï¼æ°å¢/ä¿®æ¹ï¼ ## API | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | POST | /mock/generate | AI çææ¨¡ææ°æ®ï¼å«åç½®åºç¡æ°æ®æ£æµï¼ | **请æ±åæ°ï¼** | åæ° | ç±»å | å¿ å¡« | 说æ | |------|------|------|------| | modules | List\<String\> | æ¯ | è¦çææ°æ®ç模åï¼salesï¼éå®ï¼ãpurchaseï¼éè´ï¼ãqualityï¼è´¨éï¼ãproductionï¼ç产ï¼ãstockï¼åºåï¼ | | industries | List\<String\> | æ¯ | è¡ä¸ï¼å¦ï¼["æºæ¢°å¶é ", "é£åå å·¥", "çµåè£ é "] | | countMin | int | å¦ | æ¯ä¸ªå®ä½çææ¡æ°æå°å¼ï¼é»è®¤ 3 | | countMax | int | å¦ | æ¯ä¸ªå®ä½çææ¡æ°æå¤§å¼ï¼é»è®¤ 10 | | dateStart | String | å¦ | æ¶é´èå´å¼å§ï¼yyyy-MM-ddï¼ | | dateEnd | String | å¦ | æ¶é´èå´ç»æï¼yyyy-MM-ddï¼ | | additionalInfo | String | å¦ | å ¶ä»è¡¥å æè¿°ï¼å¦"产å以éå±é¶é¨ä»¶ä¸ºä¸»" | 请æ±ä½ç¤ºä¾ï¼ ```json { "modules": ["sales", "purchase", "quality"], "industries": ["æºæ¢°å¶é ", "çµåè£ é "], "countMin": 3, "countMax": 8, "dateStart": "2026-01-01", "dateEnd": "2026-06-01", "additionalInfo": "产å以éå±é¶é¨ä»¶åçµåå å¨ä»¶ä¸ºä¸»" } ``` **ååºï¼æåï¼ï¼** ```json { "code": 200, "msg": "æä½æå", "data": { "status": "SUCCESS", "totalGenerated": 24, "moduleSummaries": [ { "module": "sales", "entityName": "客æ·", "generatedCount": 5, "successCount": 5, "failCount": 0 }, { "module": "sales", "entityName": "éå®å°è´¦", "generatedCount": 5, "successCount": 5, "failCount": 0 }, { "module": "purchase", "entityName": "ä¾åºå", "generatedCount": 4, "successCount": 4, "failCount": 0 }, { "module": "purchase", "entityName": "éè´å°è´¦", "generatedCount": 4, "successCount": 4, "failCount": 0 }, { "module": "quality", "entityName": "æ£æµæ å", "generatedCount": 3, "successCount": 3, "failCount": 0 }, { "module": "quality", "entityName": "ææ ç»å®", "generatedCount": 3, "successCount": 3, "failCount": 0 } ], "errors": [], "checkResult": null } } ``` **ååºï¼åºç¡æ°æ®ä¸è¶³ï¼åç½®æ£æµæªéè¿ï¼ï¼** ```json { "code": 500, "msg": "åºç¡æ°æ®ä¸è¶³ï¼è¯·å è¡¥å ååçæ", "data": { "status": "CHECK_FAILED", "checkResult": { "totalItems": 6, "passedItems": 3, "items": [ { "module": "common", "itemName": "äº§åæ°æ®", "passed": true, "message": "éè¿" }, { "module": "sales", "itemName": "å®¢æ·æ°æ®", "passed": false, "message": "缺å°å®¢æ·æ°æ®ï¼è¯·å ..." } ] } } } ``` ## 工使µç¨ 1. ç¨æ·å¨é¡µé¢éæ©æ¨¡å + å¡«åè¡ä¸/æ°é/æ¶é´çä¿¡æ¯ 2. è°ç¨ `POST /mock/generate` 3. å端é¦å è°ç¨ `POST /mock/dataCheck` æ£æµåºç¡æ°æ®æ¯å¦å°±ç»ª 4. è¥åºç¡æ°æ®ä¸è¶³ï¼è¿åæ£æµç»æï¼æç¤ºç¨æ·å è¡¥é½ 5. è¥åºç¡æ°æ®å°±ç»ªï¼è°ç¨ AI 大模åçæç¬¦åè¡ä¸ç¹å¾ç JSON æ°æ® 6. æä¾èµé¡ºåºåå»ºæ°æ®ï¼å®¢æ·âéå®å°è´¦ãä¾åºåâéè´å°è´¦ãæ£æµæ åâææ ç»å®...ï¼ 7. è¿åçææè¦ ## å端修æ¹ç¹ ### 1. æ°æ®çæåºåï¼å¨æ°æ®æ£æµåºå䏿¹ï¼ ```html <el-card header="AI æ°æ®çæ" style="margin-top: 16px"> <el-form :model="generateForm" label-width="100px"> <el-form-item label="éæ©æ¨¡å"> <el-checkbox-group v-model="generateForm.modules"> <el-checkbox label="sales">éå®</el-checkbox> <el-checkbox label="purchase">éè´</el-checkbox> <el-checkbox label="quality">è´¨é</el-checkbox> <el-checkbox label="production">ç产</el-checkbox> <el-checkbox label="stock">åºå</el-checkbox> </el-checkbox-group> </el-form-item> <el-form-item label="è¡ä¸"> <el-select v-model="generateForm.industries" multiple filterable allow-create placeholder="è¾å ¥æéæ©è¡ä¸" > <el-option label="æºæ¢°å¶é " value="æºæ¢°å¶é " /> <el-option label="é£åå å·¥" value="é£åå å·¥" /> <el-option label="çµåè£ é " value="çµåè£ é " /> <el-option label="汽车é¶é¨ä»¶" value="汽车é¶é¨ä»¶" /> <el-option label="å»ç卿¢°" value="å»ç卿¢°" /> <el-option label="åå·¥ææ" value="åå·¥ææ" /> <el-option label="çººç»æè£ " value="çººç»æè£ " /> <el-option label="å®¶å ·å¶é " value="å®¶å ·å¶é " /> </el-select> </el-form-item> <el-row :gutter="16"> <el-col :span="12"> <el-form-item label="çææ¡æ°"> <el-slider v-model="generateForm.countRange" range :min="1" :max="50" :marks="{1:'1', 10:'10', 20:'20', 50:'50'}" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="æ¶é´èå´"> <el-date-picker v-model="generateForm.dateRange" type="daterange" range-separator="è³" start-placeholder="å¼å§æ¥æ" end-placeholder="ç»ææ¥æ" value-format="yyyy-MM-dd" /> </el-form-item> </el-col> </el-row> <el-form-item label="è¡¥å ä¿¡æ¯"> <el-input v-model="generateForm.additionalInfo" type="textarea" :rows="2" placeholder="å¦ï¼äº§å以éå±é¶é¨ä»¶ä¸ºä¸»ï¼å®¢æ·éä¸å¨åä¸å°åº" /> </el-form-item> <el-form-item> <el-button type="primary" @click="handleGenerate" :loading="generating"> å¼å§çæ </el-button> <el-button @click="handleCheckFirst" :loading="checking"> å æ£æµåçæ </el-button> </el-form-item> </el-form> </el-card> ``` ### 3. data æ°æ® ```js data() { return { generateForm: { modules: [], industries: [], countRange: [3, 10], dateRange: [], additionalInfo: '', }, generating: false, generateResult: null, } } ``` ### 4. æ¹æ³ ```js methods: { // ç´æ¥çæï¼å é¨èªå¨æ£æµï¼ async handleGenerate() { if (this.generateForm.modules.length === 0) { this.$message.warning('请è³å°éæ©ä¸ä¸ªæ¨¡å') return } this.generating = true try { const res = await request.post('/mock/generate', { modules: this.generateForm.modules, industries: this.generateForm.industries, countMin: this.generateForm.countRange[0], countMax: this.generateForm.countRange[1], dateStart: this.generateForm.dateRange[0] || null, dateEnd: this.generateForm.dateRange[1] || null, additionalInfo: this.generateForm.additionalInfo, }) if (res.code === 200) { this.generateResult = res.data this.$message.success(`æåçæ ${res.data.totalGenerated} æ¡æ°æ®`) } else { // åºç¡æ°æ®ä¸è¶³ this.generateResult = res.data this.checkResult = res.data.checkResult this.$message.warning(res.msg) } } finally { this.generating = false } }, // å æ£æµåçæ async handleCheckFirst() { await this.handleCheck() if (this.checkResult && this.checkResult.passedItems === this.checkResult.totalItems) { await this.handleGenerate() } else { this.$message.warning('请å è¡¥é½åºç¡æ°æ®ååçæ') } }, } ``` ## 注æäºé¡¹ - `POST /mock/generate` å é¨ä¼èªå¨è°ç¨æ°æ®æ£æµï¼ä¸éè¦æå¨å两æ¥èµ° - AI çæçæ°æ®ä¼å°½é符åè¡ä¸ç¹å¾ï¼ä½å»ºè®®çæåæ£æ¥å ³é®æ°æ®çåçæ§ - ç产模åååºå模åä¾èµäº§åæ°æ®ï¼Product/ProductModelï¼ï¼è¯·ç¡®ä¿åºç¡æ°æ®ä¸æäº§å - éå®å°è´¦çååéé¢ç±äº§åæç»èªå¨è®¡ç®ï¼AI åªéçæäº§åè¡çåä»·åæ°é - 产ççæ°æ®éè¿æå¡å±å建ï¼ä¼èªå¨å¡«å tenantId/deptId/createUser çåæ®µ docs/routing_operation_plan_person.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,91 @@ # çäº§å·¥åºæ°å¢è®¡å人ååè®¡åæ§è¡äººå ## æ¶åé¡µé¢ - å·¥èºè·¯çº¿å·¥åºç®¡ç页é¢ï¼technology_routing_operationï¼ ## API æ¶å以䏿¥å£ç请æ±/ååºæ°å¢åæ®µï¼ | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | GET | /technologyRoutingOperation/page | å页æ¥è¯¢ | | GET | /technologyRoutingOperation/list | å表æ¥è¯¢ | | GET | /technologyRoutingOperation/{id} | 详æ | | POST | /technologyRoutingOperation/add | æ°å¢ | | PUT | /technologyRoutingOperation | ä¿®æ¹ | **æ°å¢ååº/请æ±å段ï¼** | åæ° | ç±»å | å¿ å¡« | 说æ | |------|------|------|------| | planPerson | Long | å¦ | 计å人åID | | executor | Long | å¦ | è®¡åæ§è¡äººåID | | planPersonName | String | å¦ | 计å人åå§åï¼ååºå段ï¼å端èªå¨å ³èæ¥è¯¢ï¼ | | executorName | String | å¦ | è®¡åæ§è¡äººåå§åï¼ååºå段ï¼å端èªå¨å ³èæ¥è¯¢ï¼ | ## å端修æ¹ç¹ ### 1. è¡¨åæ°å¢å段 å¨å·¥åºè¡¨å䏿°å¢ä¸¤ä¸ªäººå鿩䏿æ¡ï¼ ```html <el-form-item label="计å人å" prop="planPerson"> <el-select v-model="processForm.planPerson" placeholder="è¯·éæ©è®¡å人å" clearable filterable style="width: 100%"> <el-option v-for="item in employeeOptions" :key="item.id" :label="item.staffName" :value="item.id" /> </el-select> </el-form-item> <el-form-item label="è®¡åæ§è¡äººå" prop="executor"> <el-select v-model="processForm.executor" placeholder="è¯·éæ©è®¡åæ§è¡äººå" clearable filterable style="width: 100%"> <el-option v-for="item in employeeOptions" :key="item.id" :label="item.staffName" :value="item.id" /> </el-select> </el-form-item> ``` ### 2. data æ°æ® ```js data() { return { processForm: { planPerson: null, executor: null, // ...å ¶ä»å段 }, employeeOptions: [], // åå·¥å表ï¼é仿¥å£è·å } } ``` ### 3. è¡¨æ ¼åæ°å¢ å表ä¸å¯ç´æ¥ä½¿ç¨å端è¿åçå§åå±ç¤ºï¼ ```html <el-table-column label="计å人å" prop="planPersonName" /> <el-table-column label="è®¡åæ§è¡äººå" prop="executorName" /> ``` ## 注æäºé¡¹ - `planPerson` å `executor` åå¨çæ¯åå·¥IDï¼Longç±»åï¼ï¼æäº¤è¡¨åæ¶ä¼ ID - ååºä¸ `planPersonName` å `executorName` ç±å端éè¿ `staff_on_job` 表èªå¨å ³èæ¥è¯¢ï¼å端æ éé¢å¤è½¬æ¢ - å工䏿åè¡¨æ°æ®éä»åå·¥æ¥å£è·åï¼åèç°æ `employeeOptions` æ°æ®æºï¼ - æ°æ®åºè¿ç§»SQLï¼`doc/20260615_add_plan_person_and_executor_to_routing_operation.sql` - ç产订åå·¥åºï¼`production_order_routing_operation`ï¼åæ¥æ¯æè¿ä¸¤ä¸ªå段 src/main/java/com/ruoyi/mock/controller/DataCheckController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,54 @@ package com.ruoyi.mock.controller; import com.ruoyi.framework.web.domain.R; import com.ruoyi.mock.dto.DataCheckRequest; import com.ruoyi.mock.dto.DataGenerateRequest; import com.ruoyi.mock.service.DataCheckService; import com.ruoyi.mock.service.DataGenerateService; import com.ruoyi.mock.vo.DataCheckResult; import com.ruoyi.mock.vo.DataCheckResult.CheckItem; import com.ruoyi.mock.vo.DataGenerateResult; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/mock") @RequiredArgsConstructor @Tag(name = "æ°æ®æ¨¡æ") public class DataCheckController { private final DataCheckService dataCheckService; private final DataGenerateService dataGenerateService; @PostMapping("/dataCheck") @Operation(summary = "æ£æµåºç¡æ°æ®") public R<DataCheckResult> dataCheck(@RequestBody DataCheckRequest request) { DataCheckResult result = dataCheckService.check(request); return R.ok(result); } @PostMapping("/generate") @Operation(summary = "AIçææ¨¡ææ°æ®") public R<?> generate(@RequestBody DataGenerateRequest request) { // å æ ¡éªåºç¡æ°æ® DataCheckRequest checkRequest = new DataCheckRequest(); checkRequest.setModules(request.getModules()); DataCheckResult checkResult = dataCheckService.check(checkRequest); boolean allPassed = checkResult.getItems().stream().allMatch(CheckItem::isPassed); if (!allPassed) { DataGenerateResult failResult = new DataGenerateResult(); failResult.setStatus("CHECK_FAILED"); failResult.setCheckResult(checkResult); return R.fail(failResult, "åºç¡æ°æ®ä¸è¶³ï¼è¯·å è¡¥å ååçæ"); } DataGenerateResult result = dataGenerateService.generate(request); return R.ok(result); } } src/main/java/com/ruoyi/mock/dto/DataCheckRequest.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,15 @@ package com.ruoyi.mock.dto; import lombok.Data; import java.util.List; /** * åºç¡æ°æ®æ£æµè¯·æ± */ @Data public class DataCheckRequest { /** éè¦æ£æµç模å: sales / purchase / quality */ private List<String> modules; } src/main/java/com/ruoyi/mock/dto/DataGenerateRequest.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,33 @@ package com.ruoyi.mock.dto; import lombok.Data; import java.util.List; /** * AIæ°æ®çæè¯·æ± */ @Data public class DataGenerateRequest { /** è¦çææ°æ®ç模å: sales / purchase / quality / production / stock */ private List<String> modules; /** è¡ä¸ï¼å¤ä¸ªï¼ï¼å¦: ["æºæ¢°å¶é ", "é£åå å·¥", "çµåè£ é "] */ private List<String> industries; /** æ¯ä¸ªå®ä½çææ°éçæå°å¼ */ private int countMin; /** æ¯ä¸ªå®ä½çææ°éçæå¤§å¼ */ private int countMax; /** æ¶é´èå´-å¼å§, yyyy-MM-dd */ private String dateStart; /** æ¶é´èå´-ç»æ, yyyy-MM-dd */ private String dateEnd; /** å ¶ä»è¡¥å æè¿° */ private String additionalInfo; } src/main/java/com/ruoyi/mock/prompt/MockDataPrompt.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,213 @@ package com.ruoyi.mock.prompt; import java.util.List; import java.util.stream.Collectors; /** * 忍¡åç AI Prompt æ¨¡æ¿ */ public final class MockDataPrompt { private MockDataPrompt() {} public static String buildSystemPrompt() { return """ ä½ æ¯ä¸ä¸ªä¼ä¸ERPç³»ç»çæ°æ®æ¨¡æä¸å®¶ãä½ éè¦æ ¹æ®ç¨æ·æä¾çè¡ä¸ãæ°éãæ¶é´èå´çä¿¡æ¯ï¼ çæç¬¦åä¸å¡é»è¾çæ¨¡ææ°æ®ã è¦æ±: 1. è¾åºå¿ é¡»æ¯çº¯JSONæ°ç»ï¼ä¸è¦ç¨markdown代ç åå 裹ï¼ä¸è¦æä»»ä½å ¶ä»æå 2. æ¯ä¸ªJSONå¯¹è±¡å¿ é¡»å å« "entity" åæ®µï¼å¼ä¸ºå®ä½ç±»åå 3. æ°æ®å 容è¦ç¬¦åæå®è¡ä¸çç¹å¾ï¼å ¬å¸åç§°ã产ååç§°ãè系人çè¦å该è¡ä¸çï¼ 4. æ¥æåæ®µå¨æå®çæ¶é´èå´å éæºåå¸ 5. éé¢ãæ°éçæ°å¼å段è¦åç 6. å䏿¨¡åå çå®ä½ä¹é´è¦æå¼ç¨å ³ç³»ï¼å¦éå®å°è´¦å¼ç¨å®¢æ·åç§°ï¼ 7. ææåç¬¦ä¸²åæ®µä¸è¦ä½¿ç¨emojiæç¹æ®unicodeå符 """; } public static String buildUserMessage(List<String> modules, List<String> industries, int countMin, int countMax, String dateStart, String dateEnd, String additionalInfo, List<Long> productIds, List<Long> productModelIds) { StringBuilder sb = new StringBuilder(); sb.append("请为以ä¸è¡ä¸çææ¨¡æERPä¸å¡æ°æ®:\n"); sb.append("- è¡ä¸: ").append(String.join("ã", industries)).append("\n"); sb.append("- æ°æ®æ¡æ°: æ¯ç§å®ä½ ").append(countMin).append("-").append(countMax).append(" æ¡\n"); sb.append("- æ¶é´èå´: ").append(dateStart).append(" ~ ").append(dateEnd).append("\n"); if (additionalInfo != null && !additionalInfo.isBlank()) { sb.append("- è¡¥å ä¿¡æ¯: ").append(additionalInfo).append("\n"); } sb.append("\n"); sb.append("å¯ç¨ç产åIDå表: ").append(productIds.stream().map(String::valueOf).collect(Collectors.joining(","))).append("\n"); sb.append("å¯ç¨ç产åè§æ ¼IDå表: ").append(productModelIds.stream().map(String::valueOf).collect(Collectors.joining(","))).append("\n"); sb.append("\n"); sb.append("éè¦çæç模å: ").append(String.join("ã", modules)).append("\n\n"); if (modules.contains("sales")) { sb.append(buildSalesPrompt(countMin, countMax, dateStart, dateEnd)); } if (modules.contains("purchase")) { sb.append(buildPurchasePrompt(countMin, countMax, dateStart, dateEnd)); } if (modules.contains("quality")) { sb.append(buildQualityPrompt(countMin, countMax)); } if (modules.contains("production")) { sb.append(buildProductionPrompt(countMin, countMax, dateStart, dateEnd)); } if (modules.contains("stock")) { sb.append(buildStockPrompt(countMin, countMax)); } sb.append("\nè¯·ç´æ¥è¾åºJSONæ°ç»ï¼ä¸è¦æä»»ä½å ¶ä»å 容:"); return sb.toString(); } private static String buildSalesPrompt(int min, int max, String dateStart, String dateEnd) { return """ é宿¨¡å - æä»¥ä¸æ ¼å¼çæ: { "entity": "customer", "customerName": "XXç§ææéå ¬å¸", "customerType": "ä¼ä¸å®¢æ·", "contactPerson": "å¼ ä¸", "contactPhone": "13800138000", "companyAddress": "XXçXXå¸XXåºXXè·¯XXå·", "taxpayerIdentificationNumber": "91110108XXXXXXXXXX" } { "entity": "salesLedger", "customerName": "å¼ç¨ä¸é¢çæç客æ·åç§°", "salesContractNo": "XS-20260601-001", "projectName": "XX项ç®", "entryDate": "2026-06-01", "salesman": "éå®åå§å", "contractAmount": 50000.00, "paymentMethod": "æç»30天", "executionDate": "2026-06-01", "deliveryDate": "2026-07-01", "type": 1, "productData": [ { "productId": 1, "productModelId": 1, "quantity": 100, "taxInclusiveUnitPrice": 500.00, "taxInclusiveTotalPrice": 50000.00, "taxRate": 13.00, "unit": "ä»¶", "type": 1 } ] } 客æ·åç§°è¦åæå®è¡ä¸çå ¬å¸ï¼ååç¼å·æ ¼å¼XS-å¹´ææ¥-åºå·ï¼éé¢åçã æ¥æèå´: %s ~ %sï¼æ¯ç§å®ä½çæ%d-%dæ¡ã """.formatted(dateStart, dateEnd, min, max); } private static String buildPurchasePrompt(int min, int max, String dateStart, String dateEnd) { return """ éè´æ¨¡å - æä»¥ä¸æ ¼å¼çæ: { "entity": "supplier", "supplierName": "XXåæææéå ¬å¸", "supplierType": "åææä¾åºå", "contactUserName": "æå", "contactUserPhone": "13900139000", "companyAddress": "XXçXXå¸XXåºXXè·¯XXå·", "taxpayerIdentificationNum": "91110108XXXXXXXXXX", "bankAccountName": "XXé¶è¡XXæ¯è¡", "bankAccountNum": "622202XXXXXXXXXXXX", "isWhite": 0 } { "entity": "purchaseLedger", "supplierName": "å¼ç¨ä¸é¢çæçä¾åºååç§°", "purchaseContractNumber": "CG-20260601-001", "projectName": "XXéè´é¡¹ç®", "entryDate": "2026-06-01", "contractAmount": 30000.00, "paymentMethod": "è´§å°ä»æ¬¾", "executionDate": "2026-06-01", "productData": [ { "productId": 1, "productModelId": 1, "quantity": 50, "taxInclusiveUnitPrice": 600.00, "taxInclusiveTotalPrice": 30000.00, "taxRate": 13.00, "unit": "ä»¶", "type": 2 } ] } ä¾åºååç§°è¦åæå®è¡ä¸çä¾åºåï¼ååç¼å·æ ¼å¼CG-å¹´ææ¥-åºå·ã æ¥æèå´: %s ~ %sï¼æ¯ç§å®ä½çæ%d-%dæ¡ã """.formatted(dateStart, dateEnd, min, max); } private static String buildQualityPrompt(int min, int max) { return """ è´¨éæ¨¡å - æä»¥ä¸æ ¼å¼çæ: { "entity": "qualityTestStandard", "standardNo": "QTS-20260601-001", "standardName": "XXäº§åæ£éªæ å", "inspectType": 0, "remark": "éç¨äºXXè¡ä¸çè´¨éæ£éªæ å" } inspectType: 0=åæææ£éª, 1=è¿ç¨æ£éª, 2=åºåæ£éªãä¸ç§ç±»åé½è¦è¦çã { "entity": "qualityTestStandardBinding", "productId": 1, "testStandardId": 1 } æ¯ç§å®ä½çæ%d-%dæ¡ã """.formatted(min, max); } private static String buildProductionPrompt(int min, int max, String dateStart, String dateEnd) { return """ ç产模å - æä»¥ä¸æ ¼å¼çæ: { "entity": "productionPlan", "productModelId": 1, "qtyRequired": 200, "requiredDate": "2026-06-15", "source": "éå®", "promisedDeliveryDate": "2026-07-01", "remark": "XX客æ·è®¢åéæ±" } { "entity": "productionOrder", "productModelId": 1, "quantity": 200, "planCompleteTime": "2026-06-30", "remark": "æ ¹æ®ç产计åXXçæ" } productionPlançsourceå¯é"éå®"æ"å é¨"ã æ¥æèå´: %s ~ %sï¼æ¯ç§å®ä½çæ%d-%dæ¡ã """.formatted(dateStart, dateEnd, min, max); } private static String buildStockPrompt(int min, int max) { return """ åºå模å - æä»¥ä¸æ ¼å¼çæ: { "entity": "stockInventory", "productModelId": 1, "qualitity": 500, "batchNo": "BATCH-20260601-001", "warnNum": 50, "remark": "å®å ¨åºå" } æ¯ç§å®ä½çæ%d-%dæ¡ãbatchNoæ ¼å¼BATCH-å¹´ææ¥-åºå·ã """.formatted(min, max); } } src/main/java/com/ruoyi/mock/service/DataCheckService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,15 @@ package com.ruoyi.mock.service; import com.ruoyi.mock.dto.DataCheckRequest; import com.ruoyi.mock.vo.DataCheckResult; /** * åºç¡æ°æ®æ£æµæå¡ */ public interface DataCheckService { /** * æ£æµæå®æ¨¡åçåºç¡æ°æ®æ¯å¦å°±ç»ª */ DataCheckResult check(DataCheckRequest request); } src/main/java/com/ruoyi/mock/service/DataGenerateService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,15 @@ package com.ruoyi.mock.service; import com.ruoyi.mock.dto.DataGenerateRequest; import com.ruoyi.mock.vo.DataGenerateResult; /** * AIæ°æ®çææå¡ */ public interface DataGenerateService { /** * æ ¹æ®è¯·æ±åæ°è°ç¨AIçææ¨¡ææ°æ®å¹¶å建 */ DataGenerateResult generate(DataGenerateRequest request); } src/main/java/com/ruoyi/mock/service/impl/DataCheckServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,146 @@ package com.ruoyi.mock.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.approve.pojo.ApprovalTemplate; import com.ruoyi.approve.mapper.ApprovalTemplateMapper; import com.ruoyi.basic.mapper.CustomerMapper; import com.ruoyi.basic.mapper.ProductMapper; import com.ruoyi.basic.mapper.SupplierManageMapper; import com.ruoyi.common.enums.TypeEnums; import com.ruoyi.mock.dto.DataCheckRequest; import com.ruoyi.mock.service.DataCheckService; import com.ruoyi.mock.vo.DataCheckResult; import com.ruoyi.mock.vo.DataCheckResult.CheckItem; import com.ruoyi.quality.mapper.QualityTestStandardBindingMapper; import com.ruoyi.quality.mapper.QualityTestStandardMapper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Service @RequiredArgsConstructor public class DataCheckServiceImpl implements DataCheckService { private final ProductMapper productMapper; private final CustomerMapper customerMapper; private final SupplierManageMapper supplierManageMapper; private final ApprovalTemplateMapper approvalTemplateMapper; private final QualityTestStandardMapper qualityTestStandardMapper; private final QualityTestStandardBindingMapper qualityTestStandardBindingMapper; @Override public DataCheckResult check(DataCheckRequest request) { List<String> modules = request.getModules(); if (modules == null) { modules = List.of(); } Map<String, CheckItem> itemMap = new LinkedHashMap<>(); if (!modules.isEmpty()) { addProductCheck(itemMap); } for (String module : modules) { switch (module) { case "sales" -> addSalesChecks(itemMap); case "purchase" -> addPurchaseChecks(itemMap); case "quality" -> addQualityChecks(itemMap); } } List<CheckItem> items = new ArrayList<>(itemMap.values()); DataCheckResult result = new DataCheckResult(); result.setItems(items); result.setTotalItems(items.size()); result.setPassedItems((int) items.stream().filter(CheckItem::isPassed).count()); return result; } private void addProductCheck(Map<String, CheckItem> itemMap) { String key = "common:äº§åæ°æ®"; if (itemMap.containsKey(key)) { return; } long count = productMapper.selectCount(null); itemMap.put(key, buildItem("common", "äº§åæ°æ®", 1, (int) count, "缺å°äº§åæ°æ®ï¼è¯·å å¨ãåºç¡æ°æ®-产å管çã䏿·»å è³å°1æ¡äº§å")); } private void addSalesChecks(Map<String, CheckItem> itemMap) { String customerKey = "sales:å®¢æ·æ°æ®"; if (!itemMap.containsKey(customerKey)) { long count = customerMapper.selectCount(null); itemMap.put(customerKey, buildItem("sales", "å®¢æ·æ°æ®", 1, (int) count, "缺å°å®¢æ·æ°æ®ï¼è¯·å å¨ãåºç¡æ°æ®-客æ·ç®¡çã䏿·»å è³å°1æ¡å®¢æ·")); } String quotationKey = "sales:æ¥ä»·å®¡æ¹æ¨¡æ¿"; if (!itemMap.containsKey(quotationKey)) { long count = approvalTemplateMapper.selectCount( new LambdaQueryWrapper<ApprovalTemplate>() .eq(ApprovalTemplate::getBusinessType, TypeEnums.QUOTATION_APPROVAL.getCode())); itemMap.put(quotationKey, buildItem("sales", "æ¥ä»·å®¡æ¹æ¨¡æ¿", 1, (int) count, "ç¼ºå°æ¥ä»·å®¡æ¹æ¨¡æ¿ï¼è¯·å å¨ãç³»ç»ç®¡ç-å®¡æ¹æ¨¡æ¿ãä¸å建æ¥ä»·å®¡æ¹æ¨¡æ¿")); } String shippingKey = "sales:åè´§å®¡æ¹æ¨¡æ¿"; if (!itemMap.containsKey(shippingKey)) { long count = approvalTemplateMapper.selectCount( new LambdaQueryWrapper<ApprovalTemplate>() .eq(ApprovalTemplate::getBusinessType, TypeEnums.SHIPPING_APPROVAL.getCode())); itemMap.put(shippingKey, buildItem("sales", "åè´§å®¡æ¹æ¨¡æ¿", 1, (int) count, "缺å°åè´§å®¡æ¹æ¨¡æ¿ï¼è¯·å å¨ãç³»ç»ç®¡ç-å®¡æ¹æ¨¡æ¿ãä¸å建åè´§å®¡æ¹æ¨¡æ¿")); } } private void addPurchaseChecks(Map<String, CheckItem> itemMap) { String supplierKey = "purchase:ä¾åºåæ°æ®"; if (!itemMap.containsKey(supplierKey)) { long count = supplierManageMapper.selectCount(null); itemMap.put(supplierKey, buildItem("purchase", "ä¾åºåæ°æ®", 1, (int) count, "缺å°ä¾åºåæ°æ®ï¼è¯·å å¨ãåºç¡æ°æ®-ä¾åºå管çã䏿·»å è³å°1æ¡ä¾åºå")); } String tplKey = "purchase:éè´å®¡æ¹æ¨¡æ¿"; if (!itemMap.containsKey(tplKey)) { long count = approvalTemplateMapper.selectCount( new LambdaQueryWrapper<ApprovalTemplate>() .eq(ApprovalTemplate::getBusinessType, TypeEnums.PURCHASE_APPROVAL.getCode())); itemMap.put(tplKey, buildItem("purchase", "éè´å®¡æ¹æ¨¡æ¿", 1, (int) count, "缺å°éè´å®¡æ¹æ¨¡æ¿ï¼è¯·å å¨ãç³»ç»ç®¡ç-å®¡æ¹æ¨¡æ¿ãä¸å建éè´å®¡æ¹æ¨¡æ¿")); } } private void addQualityChecks(Map<String, CheckItem> itemMap) { String standardKey = "quality:æ£æµæ å"; if (!itemMap.containsKey(standardKey)) { long count = qualityTestStandardMapper.selectCount(null); itemMap.put(standardKey, buildItem("quality", "æ£æµæ å", 1, (int) count, "ç¼ºå°æ£æµæ åï¼è¯·å å¨ãè´¨é管ç-æ£æµæ åãä¸åå»ºæ£æµæ å")); } String bindingKey = "quality:ææ ç»å®"; if (!itemMap.containsKey(bindingKey)) { long count = qualityTestStandardBindingMapper.selectCount(null); itemMap.put(bindingKey, buildItem("quality", "ææ ç»å®", 1, (int) count, "ç¼ºå°ææ ç»å®ï¼è¯·å å¨ãè´¨é管ç-æ£æµæ åç»å®ãä¸å°æ£æµæ åä¸äº§åç»å®")); } } private CheckItem buildItem(String module, String itemName, int minRequired, int currentCount, String failMessage) { CheckItem item = new CheckItem(); item.setModule(module); item.setItemName(itemName); item.setMinRequired(minRequired); item.setCurrentCount(currentCount); item.setPassed(currentCount >= minRequired); item.setMessage(item.isPassed() ? "éè¿" : failMessage); return item; } } src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,466 @@ package com.ruoyi.mock.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.ruoyi.ai.assistant.Assistant; import com.ruoyi.basic.mapper.ProductMapper; import com.ruoyi.basic.mapper.ProductModelMapper; import com.ruoyi.basic.pojo.Customer; import com.ruoyi.basic.pojo.SupplierManage; import com.ruoyi.basic.service.ICustomerService; import com.ruoyi.basic.service.ISupplierService; import com.ruoyi.mock.dto.DataGenerateRequest; import com.ruoyi.mock.prompt.MockDataPrompt; import com.ruoyi.mock.service.DataGenerateService; import com.ruoyi.mock.vo.DataGenerateResult; import com.ruoyi.mock.vo.DataGenerateResult.ModuleSummary; import com.ruoyi.production.pojo.ProductionOrder; import com.ruoyi.production.pojo.ProductionPlan; import com.ruoyi.production.service.ProductionOrderService; import com.ruoyi.production.service.ProductionPlanService; import com.ruoyi.purchase.dto.PurchaseLedgerDto; import com.ruoyi.purchase.service.IPurchaseLedgerService; import com.ruoyi.quality.pojo.QualityTestStandard; import com.ruoyi.quality.pojo.QualityTestStandardBinding; import com.ruoyi.quality.service.IQualityTestStandardService; import com.ruoyi.quality.service.QualityTestStandardBindingService; import com.ruoyi.sales.dto.SalesLedgerDto; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.service.ISalesLedgerService; import com.ruoyi.stock.dto.StockInventoryDto; import com.ruoyi.stock.service.StockInventoryService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.time.LocalDate; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor public class DataGenerateServiceImpl implements DataGenerateService { private final Assistant assistant; private final ProductMapper productMapper; private final ProductModelMapper productModelMapper; private final ICustomerService customerService; private final ISalesLedgerService salesLedgerService; private final ISupplierService supplierService; private final IPurchaseLedgerService purchaseLedgerService; private final IQualityTestStandardService qualityTestStandardService; private final QualityTestStandardBindingService qualityTestStandardBindingService; private final ProductionPlanService productionPlanService; private final ProductionOrderService productionOrderService; private final StockInventoryService stockInventoryService; @Override public DataGenerateResult generate(DataGenerateRequest request) { DataGenerateResult result = new DataGenerateResult(); List<ModuleSummary> summaries = new ArrayList<>(); List<String> errors = new ArrayList<>(); int totalGenerated = 0; try { List<Long> productIds = productMapper.selectList(null).stream() .map(p -> p.getId()).collect(Collectors.toList()); List<Long> productModelIds = productModelMapper.selectList(null).stream() .map(m -> m.getId()).collect(Collectors.toList()); String systemPrompt = MockDataPrompt.buildSystemPrompt(); String userMessage = MockDataPrompt.buildUserMessage( request.getModules(), request.getIndustries(), request.getCountMin(), request.getCountMax(), request.getDateStart(), request.getDateEnd(), request.getAdditionalInfo(), productIds, productModelIds); String fullPrompt = systemPrompt + "\n\n" + userMessage; log.info("è°ç¨AIçææ¨¡ææ°æ®, modules={}, industries={}", request.getModules(), request.getIndustries()); String llmResponse = assistant.chat(fullPrompt); log.info("AIè¿åæ°æ®é¿åº¦: {}", llmResponse != null ? llmResponse.length() : 0); if (llmResponse == null || llmResponse.isBlank()) { result.setStatus("FAILED"); errors.add("AIæªè¿å任使°æ®"); result.setErrors(errors); return result; } List<JSONObject> entities = parseJsonResponse(llmResponse); if (entities.isEmpty()) { result.setStatus("FAILED"); errors.add("æ æ³è§£æAIè¿åçæ°æ®"); result.setErrors(errors); return result; } Map<String, List<JSONObject>> grouped = entities.stream() .collect(Collectors.groupingBy(e -> e.getString("entity"))); // åç§°âID æ å°è¡¨ï¼ç¨äºå建ä¸å¡åæ®æ¶åå¡«å¤é® Map<String, Long> customerNameToId = new HashMap<>(); Map<String, Long> supplierNameToId = new HashMap<>(); // Tier 0: åºç¡æ°æ® if (grouped.containsKey("customer")) { ModuleSummary s = createCustomers(grouped.get("customer"), customerNameToId); summaries.add(s); totalGenerated += s.getSuccessCount(); } if (grouped.containsKey("supplier")) { ModuleSummary s = createSuppliers(grouped.get("supplier"), supplierNameToId); summaries.add(s); totalGenerated += s.getSuccessCount(); } if (grouped.containsKey("qualityTestStandard")) { ModuleSummary s = createQualityStandards(grouped.get("qualityTestStandard")); summaries.add(s); totalGenerated += s.getSuccessCount(); } // Tier 1: ä¸å¡åæ® if (grouped.containsKey("salesLedger")) { ModuleSummary s = createSalesLedgers(grouped.get("salesLedger"), customerNameToId); summaries.add(s); totalGenerated += s.getSuccessCount(); } if (grouped.containsKey("purchaseLedger")) { ModuleSummary s = createPurchaseLedgers(grouped.get("purchaseLedger"), supplierNameToId); summaries.add(s); totalGenerated += s.getSuccessCount(); } if (grouped.containsKey("productionPlan")) { ModuleSummary s = createProductionPlans(grouped.get("productionPlan")); summaries.add(s); totalGenerated += s.getSuccessCount(); } // Tier 2 if (grouped.containsKey("productionOrder")) { ModuleSummary s = createProductionOrders(grouped.get("productionOrder")); summaries.add(s); totalGenerated += s.getSuccessCount(); } if (grouped.containsKey("qualityTestStandardBinding")) { ModuleSummary s = createQualityBindings(grouped.get("qualityTestStandardBinding")); summaries.add(s); totalGenerated += s.getSuccessCount(); } if (grouped.containsKey("stockInventory")) { ModuleSummary s = createStockInventories(grouped.get("stockInventory")); summaries.add(s); totalGenerated += s.getSuccessCount(); } result.setStatus(errors.isEmpty() ? "SUCCESS" : "PARTIAL"); result.setTotalGenerated(totalGenerated); result.setModuleSummaries(summaries); result.setErrors(errors); } catch (Exception e) { log.error("æ°æ®çæå¤±è´¥", e); result.setStatus("FAILED"); errors.add("æ°æ®çæå¼å¸¸: " + e.getMessage()); result.setErrors(errors); } return result; } private List<JSONObject> parseJsonResponse(String response) { try { String trimmed = response.trim(); if (trimmed.startsWith("```")) { int start = trimmed.indexOf("\n"); int end = trimmed.lastIndexOf("```"); if (start > 0 && end > start) { trimmed = trimmed.substring(start + 1, end).trim(); } } return JSON.parseArray(trimmed, JSONObject.class); } catch (Exception e) { log.warn("JSONè§£æå¤±è´¥ï¼å°è¯æåæ°ç»ç段: {}", e.getMessage()); int start = response.indexOf('['); int end = response.lastIndexOf(']'); if (start >= 0 && end > start) { return JSON.parseArray(response.substring(start, end + 1), JSONObject.class); } return List.of(); } } // ---- Tier 0: åºç¡æ°æ® ---- private ModuleSummary createCustomers(List<JSONObject> items, Map<String, Long> nameToId) { int success = 0, fail = 0; for (JSONObject item : items) { try { Customer c = new Customer(); c.setCustomerName(item.getString("customerName")); c.setCustomerType(item.getString("customerType")); c.setContactPerson(item.getString("contactPerson")); c.setContactPhone(item.getString("contactPhone")); c.setCompanyAddress(item.getString("companyAddress")); c.setTaxpayerIdentificationNumber(item.getString("taxpayerIdentificationNumber")); customerService.insertCustomer(c); if (c.getId() != null) { nameToId.put(c.getCustomerName(), c.getId()); } success++; } catch (Exception e) { log.warn("å建客æ·å¤±è´¥: {}", e.getMessage()); fail++; } } return summary("sales", "客æ·", items.size(), success, fail); } private ModuleSummary createSuppliers(List<JSONObject> items, Map<String, Long> nameToId) { int success = 0, fail = 0; for (JSONObject item : items) { try { SupplierManage s = new SupplierManage(); s.setSupplierName(item.getString("supplierName")); s.setSupplierType(item.getString("supplierType")); s.setContactUserName(item.getString("contactUserName")); s.setContactUserPhone(item.getString("contactUserPhone")); s.setCompanyAddress(item.getString("companyAddress")); s.setTaxpayerIdentificationNum(item.getString("taxpayerIdentificationNum")); s.setBankAccountName(item.getString("bankAccountName")); s.setBankAccountNum(item.getString("bankAccountNum")); if (item.containsKey("isWhite")) { s.setIsWhite(item.getInteger("isWhite")); } supplierService.saveSupplier(s); if (s.getId() != null) { nameToId.put(s.getSupplierName(), s.getId()); } success++; } catch (Exception e) { log.warn("å建ä¾åºå失败: {}", e.getMessage()); fail++; } } return summary("purchase", "ä¾åºå", items.size(), success, fail); } private ModuleSummary createQualityStandards(List<JSONObject> items) { int success = 0, fail = 0; for (JSONObject item : items) { try { QualityTestStandard std = new QualityTestStandard(); std.setStandardNo(item.getString("standardNo")); std.setStandardName(item.getString("standardName")); std.setInspectType(item.getInteger("inspectType")); std.setRemark(item.getString("remark")); qualityTestStandardService.save(std); success++; } catch (Exception e) { log.warn("åå»ºæ£æµæ å失败: {}", e.getMessage()); fail++; } } return summary("quality", "æ£æµæ å", items.size(), success, fail); } // ---- Tier 1: ä¸å¡åæ® ---- private ModuleSummary createSalesLedgers(List<JSONObject> items, Map<String, Long> customerNameToId) { int success = 0, fail = 0; for (JSONObject item : items) { try { String customerName = item.getString("customerName"); Long customerId = customerNameToId.get(customerName); SalesLedgerDto dto = new SalesLedgerDto(); dto.setCustomerId(customerId); dto.setCustomerName(customerName); dto.setProjectName(item.getString("projectName")); dto.setSalesman(item.getString("salesman")); dto.setPaymentMethod(item.getString("paymentMethod")); dto.setType(item.getInteger("type")); if (item.containsKey("entryDate")) { dto.setEntryDate(java.sql.Date.valueOf(item.getString("entryDate"))); } if (item.containsKey("executionDate")) { dto.setExecutionDate(LocalDate.parse(item.getString("executionDate"))); } if (item.containsKey("deliveryDate")) { dto.setDeliveryDate(LocalDate.parse(item.getString("deliveryDate"))); } JSONArray productData = item.getJSONArray("productData"); if (productData != null) { List<SalesLedgerProduct> products = new ArrayList<>(); for (int i = 0; i < productData.size(); i++) { JSONObject pd = productData.getJSONObject(i); SalesLedgerProduct slp = new SalesLedgerProduct(); slp.setProductId(pd.getLong("productId")); slp.setProductModelId(pd.getLong("productModelId")); slp.setQuantity(pd.getBigDecimal("quantity")); slp.setTaxInclusiveUnitPrice(pd.getBigDecimal("taxInclusiveUnitPrice")); slp.setTaxInclusiveTotalPrice(pd.getBigDecimal("taxInclusiveTotalPrice")); slp.setTaxRate(pd.getBigDecimal("taxRate")); slp.setUnit(pd.getString("unit")); slp.setType(pd.getInteger("type")); products.add(slp); } dto.setProductData(products); } salesLedgerService.addOrUpdateSalesLedger(dto); success++; } catch (Exception e) { log.warn("å建éå®å°è´¦å¤±è´¥: {}", e.getMessage()); fail++; } } return summary("sales", "éå®å°è´¦", items.size(), success, fail); } private ModuleSummary createPurchaseLedgers(List<JSONObject> items, Map<String, Long> supplierNameToId) { int success = 0, fail = 0; for (JSONObject item : items) { try { String supplierName = item.getString("supplierName"); Long supplierId = supplierNameToId.get(supplierName); PurchaseLedgerDto dto = new PurchaseLedgerDto(); dto.setSupplierId(supplierId); dto.setSupplierName(supplierName); dto.setProjectName(item.getString("projectName")); dto.setContractAmount(item.getBigDecimal("contractAmount")); dto.setPaymentMethod(item.getString("paymentMethod")); if (item.containsKey("entryDate")) { dto.setEntryDate(java.sql.Date.valueOf(item.getString("entryDate"))); } if (item.containsKey("executionDate")) { dto.setExecutionDate(java.sql.Date.valueOf(item.getString("executionDate"))); } JSONArray productData = item.getJSONArray("productData"); if (productData != null) { List<SalesLedgerProduct> products = new ArrayList<>(); for (int i = 0; i < productData.size(); i++) { JSONObject pd = productData.getJSONObject(i); SalesLedgerProduct slp = new SalesLedgerProduct(); slp.setProductId(pd.getLong("productId")); slp.setProductModelId(pd.getLong("productModelId")); slp.setQuantity(pd.getBigDecimal("quantity")); slp.setTaxInclusiveUnitPrice(pd.getBigDecimal("taxInclusiveUnitPrice")); slp.setTaxInclusiveTotalPrice(pd.getBigDecimal("taxInclusiveTotalPrice")); slp.setTaxRate(pd.getBigDecimal("taxRate")); slp.setUnit(pd.getString("unit")); slp.setType(2); products.add(slp); } dto.setProductData(products); } purchaseLedgerService.addOrEditPurchase(dto); success++; } catch (Exception e) { log.warn("å建éè´å°è´¦å¤±è´¥: {}", e.getMessage()); fail++; } } return summary("purchase", "éè´å°è´¦", items.size(), success, fail); } private ModuleSummary createProductionPlans(List<JSONObject> items) { int success = 0, fail = 0; for (JSONObject item : items) { try { ProductionPlan plan = new ProductionPlan(); plan.setProductModelId(item.getLong("productModelId")); plan.setQtyRequired(item.getBigDecimal("qtyRequired")); plan.setSource(item.getString("source")); plan.setRemark(item.getString("remark")); if (item.containsKey("requiredDate")) { plan.setRequiredDate(LocalDate.parse(item.getString("requiredDate"))); } if (item.containsKey("promisedDeliveryDate")) { plan.setPromisedDeliveryDate(LocalDate.parse(item.getString("promisedDeliveryDate"))); } productionPlanService.save(plan); success++; } catch (Exception e) { log.warn("å建ç产计å失败: {}", e.getMessage()); fail++; } } return summary("production", "ç产计å", items.size(), success, fail); } // ---- Tier 2: åç»åæ® ---- private ModuleSummary createProductionOrders(List<JSONObject> items) { int success = 0, fail = 0; for (JSONObject item : items) { try { ProductionOrder order = new ProductionOrder(); order.setProductModelId(item.getLong("productModelId")); order.setQuantity(item.getBigDecimal("quantity")); if (item.containsKey("planCompleteTime")) { order.setPlanCompleteTime(LocalDate.parse(item.getString("planCompleteTime"))); } productionOrderService.saveProductionOrder(order); success++; } catch (Exception e) { log.warn("å建ç产订å失败: {}", e.getMessage()); fail++; } } return summary("production", "ç产订å", items.size(), success, fail); } private ModuleSummary createQualityBindings(List<JSONObject> items) { int success = 0, fail = 0; for (JSONObject item : items) { try { QualityTestStandardBinding binding = new QualityTestStandardBinding(); binding.setProductId(item.getLong("productId")); binding.setTestStandardId(item.getInteger("testStandardId")); qualityTestStandardBindingService.add(List.of(binding)); success++; } catch (Exception e) { log.warn("åå»ºææ ç»å®å¤±è´¥: {}", e.getMessage()); fail++; } } return summary("quality", "ææ ç»å®", items.size(), success, fail); } private ModuleSummary createStockInventories(List<JSONObject> items) { int success = 0, fail = 0; for (JSONObject item : items) { try { StockInventoryDto dto = new StockInventoryDto(); dto.setProductModelId(item.getLong("productModelId")); dto.setQualitity(item.getBigDecimal("qualitity")); dto.setBatchNo(item.getString("batchNo")); dto.setWarnNum(item.getBigDecimal("warnNum")); dto.setRemark(item.getString("remark")); stockInventoryService.addstockInventory(dto); success++; } catch (Exception e) { log.warn("å建åºåè®°å½å¤±è´¥: {}", e.getMessage()); fail++; } } return summary("stock", "åºåè®°å½", items.size(), success, fail); } private ModuleSummary summary(String module, String entityName, int total, int success, int fail) { ModuleSummary s = new ModuleSummary(); s.setModule(module); s.setEntityName(entityName); s.setGeneratedCount(total); s.setSuccessCount(success); s.setFailCount(fail); return s; } } src/main/java/com/ruoyi/mock/vo/DataCheckResult.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,36 @@ package com.ruoyi.mock.vo; import lombok.Data; import java.util.ArrayList; import java.util.List; /** * åºç¡æ°æ®æ£æµç»æ */ @Data public class DataCheckResult { /** æ£æµé¡¹æ»æ° */ private int totalItems; /** å·²éè¿çæ£æµé¡¹æ°é */ private int passedItems; /** æ£æµæç» */ private List<CheckItem> items = new ArrayList<>(); @Data public static class CheckItem { /** 模åï¼sales / purchase / quality / common */ private String module; /** æ£æµé¡¹åç§° */ private String itemName; /** æéæä½æ°é */ private int minRequired; /** å½åå®é æ°é */ private int currentCount; /** æ¯å¦éè¿ */ private boolean passed; /** æç¤ºä¿¡æ¯ */ private String message; } } src/main/java/com/ruoyi/mock/vo/DataGenerateResult.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,37 @@ package com.ruoyi.mock.vo; import lombok.Data; import java.util.ArrayList; import java.util.List; /** * AIæ°æ®çæç»æ */ @Data public class DataGenerateResult { /** çæç¶æ: SUCCESS / PARTIAL / FAILED */ private String status; /** æ»è®¡çææ¡æ° */ private int totalGenerated; /** 忍¡åçææè¦ */ private List<ModuleSummary> moduleSummaries = new ArrayList<>(); /** é误信æ¯ï¼å¦æï¼ */ private List<String> errors = new ArrayList<>(); /** åºç¡æ°æ®æ£æµç»æï¼åç½®æ ¡éªæªéè¿æ¶è¿åï¼ */ private DataCheckResult checkResult; @Data public static class ModuleSummary { private String module; private String entityName; private int generatedCount; private int successCount; private int failCount; } }