Merge branch 'dev_NEW_pro' of http://114.132.189.42:9002/r/product-inventory-management into dev_NEW_pro
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æ°æ®æ¨¡æ - åºç¡æ°æ®æ£æµ |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - æ°æ®æ¨¡ææä½é¡µé¢ï¼æ°å¢ï¼ |
| | | |
| | | ## API |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | POST | /mock/dataCheck | æ£æµæå®æ¨¡åçåºç¡æ°æ®æ¯å¦å°±ç»ª | |
| | | |
| | | **请æ±åæ°ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | modules | List\<String\> | æ¯ | è¦æ£æµç模åå表ï¼å¯éå¼ï¼salesï¼éå®ï¼ãpurchaseï¼éè´ï¼ãqualityï¼è´¨éï¼ãproductionï¼çäº§ï¼ | |
| | | |
| | | 请æ±ä½ç¤ºä¾ï¼ |
| | | ```json |
| | | { "modules": ["sales", "purchase", "quality", "production"] } |
| | | ``` |
| | | |
| | | **ååºï¼** |
| | | ```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 | 缺å°éè´å®¡æ¹æ¨¡æ¿ï¼è¯·å
å¨ãç³»ç»ç®¡ç-å®¡æ¹æ¨¡æ¿ãä¸å建éè´å®¡æ¹æ¨¡æ¿ | |
| | | |
| | | ### ç产模å (production) |
| | | | æ£æµé¡¹ | æä½æ°é | æªéè¿æç¤º | |
| | | |--------|----------|------------| |
| | | | äº§åæ°æ® | 1 | 缺å°äº§åæ°æ®ï¼è¯·å
å¨ãåºç¡æ°æ®-产å管çã䏿·»å è³å°1æ¡äº§å | |
| | | | 产åè§æ ¼ | 1 | 缺å°äº§åè§æ ¼ï¼è¯·å
å¨ãåºç¡æ°æ®-产å管çãä¸ä¸ºäº§åæ·»å è§æ ¼åå· | |
| | | | å·¥åº | 1 | 缺å°å·¥åºï¼è¯·å
å¨ãå·¥èºè®¾è®¡-å·¥åºç®¡çãä¸åå»ºå·¥åº | |
| | | | BOM | 1 | 缺å°BOMï¼è¯·å
å¨ãå·¥èºè®¾è®¡-BOM管çãä¸å建BOM | |
| | | | BOM产åç»æ | 1 | 缺å°BOM产åç»æï¼è¯·å
å¨ãå·¥èºè®¾è®¡-BOM管çãä¸ä¸ºBOMæ·»å 产åç»æèç¹ | |
| | | | å·¥èºè·¯çº¿ | 1 | 缺å°å·¥èºè·¯çº¿ï¼è¯·å
å¨ãå·¥èºè®¾è®¡-å·¥èºè·¯çº¿ãä¸å建工èºè·¯çº¿ | |
| | | | å·¥èºè·¯çº¿å·¥åº | 1 | 缺å°å·¥èºè·¯çº¿å·¥åºï¼è¯·å
å¨ãå·¥èºè®¾è®¡-å·¥èºè·¯çº¿ãä¸ä¸ºå·¥èºè·¯çº¿æ·»å å·¥åº | |
| | | | 产å-å·¥èºè·¯çº¿å
³è | â¥1 | é¨å产åè§æ ¼æªå
³èå·¥èºè·¯çº¿ï¼è¯·å
å¨ãå·¥èºè®¾è®¡-å·¥èºè·¯çº¿ãä¸ä¸ºäº§åè§æ ¼å建工èºè·¯çº¿ | |
| | | | å·¥èºè·¯çº¿-å·¥åºå
³è | â¥1 | é¨åå·¥èºè·¯çº¿æªæ·»å å·¥åºï¼è¯·å
å¨ãå·¥èºè®¾è®¡-å·¥èºè·¯çº¿ãä¸ä¸ºå·¥èºè·¯çº¿æ·»å å·¥åº | |
| | | | BOM-产åç»æå
³è | â¥1 | é¨åBOMæªæ·»å 产åç»æï¼è¯·å
å¨ãå·¥èºè®¾è®¡-BOM管çãä¸ä¸ºBOMæ·»å 产åç»æèç¹ | |
| | | |
| | | ### è´¨éæ¨¡å (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 label="production">ç产模å</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', 'production'], |
| | | 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 |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - äº§åæ°æ®ï¼å
Œ
±åºç¡ï¼å¨å¤ä¸ªæ¨¡åé´å
±äº«ï¼æ£æµç»æä¸åªåºç°ä¸æ¬¡ï¼ä¸ä¼éå¤å±ç¤º |
| | | - æ£æµä»
ååªè¯»æ¥è¯¢ï¼ä¸åå
¥ä»»ä½æ°æ® |
| | | - 模ååæ°ä¸ºç©ºæ°ç»æ¶è¿åç©ºæ£æµå表 |
| | | - å»ºè®®å¨æ°æ®æ¨¡æå¼å§åå
è°ç¨æ¤æ¥å£ç¡®è®¤åºç¡æ°æ®å°±ç»ª |
| | | - ç产模åé¤äºæ£æµæ°æ®éï¼è¿ä¼æ£æµå
³èæ§ï¼äº§å-å·¥èºè·¯çº¿ãå·¥èºè·¯çº¿-å·¥åºãBOM-产åç»æï¼ï¼ç¡®ä¿å·¥èºè®¾è®¡æ°æ®å®æ´ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æ°æ®æ¨¡æ - 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 çåæ®µ |
| | |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // æ¹éå审åºåºè®°å½ |
| | | export const batchUnapproveStockOutRecords = (data) => { |
| | | return request({ |
| | | url: "/stockOutRecord/reAudit", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // AI çææ¨¡ææ°æ®ï¼å«åç½®åºç¡æ°æ®æ£æµï¼ |
| | | export function mockGenerate(data) { |
| | | return request({ |
| | | url: "/mock/generate", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| | |
| | | <div class="actions"> |
| | | <el-button type="primary" |
| | | @click="handleBatchApprove">审æ¹</el-button> |
| | | <el-button :disabled="!canReverseApprove" |
| | | @click="handleReverseApprove">å审</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | |
| | | getStockOutPage, |
| | | delPendingStockOut, |
| | | batchApproveStockOutRecords, |
| | | batchUnapproveStockOutRecords, |
| | | } from "@/api/inventoryManagement/stockOut.js"; |
| | | import { |
| | | findAllQualifiedStockOutRecordTypeOptions, |
| | |
| | | selectedRows.value = selection.filter(item => item.id); |
| | | console.log("selection", selectedRows.value); |
| | | }; |
| | | |
| | | const isRejectedApproval = status => { |
| | | return status === 2 || status === "2" || status === "rejected" || status === "REJECTED"; |
| | | }; |
| | | |
| | | const canReverseApprove = computed(() => { |
| | | return ( |
| | | selectedRows.value.length > 0 && |
| | | selectedRows.value.every(row => isRejectedApproval(row.approvalStatus)) |
| | | ); |
| | | }); |
| | | |
| | | const handleReverseApprove = () => { |
| | | if (!canReverseApprove.value) { |
| | | proxy.$modal.msgWarning("è¯·éæ©é©³åç¶æçæ°æ®"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | ElMessageBox.confirm("å审åè®°å½å°æ¢å¤ä¸ºå¾
审æ¹ç¶æï¼æ¯å¦ç¡®è®¤å审ï¼", "å审", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | batchUnapproveStockOutRecords({ ids }) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("å审æå"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("å审失败"); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | const expandedRowKeys = ref([]); |
| | | |
| | | const handleBatchApprove = () => { |
| | |
| | | <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-group> |
| | | <div style="margin-top: 16px"> |
| | | <el-button type="primary" @click="handleCheck" :loading="checking"> |
| | |
| | | <el-table-column prop="message" label="æç¤º" min-width="200" /> |
| | | </el-table> |
| | | </el-card> |
| | | |
| | | <!-- AI æ°æ®çæ --> |
| | | <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" |
| | | unlink-panels |
| | | /> |
| | | </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> |
| | | |
| | | <!-- çæç»æ --> |
| | | <el-card v-if="generateResult" header="çæç»æ" style="margin-top: 16px"> |
| | | <el-alert |
| | | :title="`å
±çæ ${generateResult.totalGenerated} æ¡æ°æ®`" |
| | | type="success" |
| | | :closable="false" |
| | | show-icon |
| | | /> |
| | | <el-table :data="generateResult.moduleSummaries" style="margin-top: 12px" border> |
| | | <el-table-column prop="module" label="模å" width="100" /> |
| | | <el-table-column prop="entityName" label="å®ä½åç§°" width="160" /> |
| | | <el-table-column prop="generatedCount" label="çææ¡æ°" width="80" align="center" /> |
| | | <el-table-column prop="successCount" label="æå" width="80" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tag type="success">{{ row.successCount }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="failCount" label="失败" width="80" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tag v-if="row.failCount > 0" type="danger">{{ row.failCount }}</el-tag> |
| | | <span v-else>0</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div v-if="generateResult.errors && generateResult.errors.length > 0" style="margin-top: 12px"> |
| | | <el-alert |
| | | v-for="(err, i) in generateResult.errors" |
| | | :key="i" |
| | | :title="err" |
| | | type="error" |
| | | :closable="false" |
| | | style="margin-bottom: 4px" |
| | | /> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from "vue"; |
| | | import { ref, reactive } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { dataCheck } from "@/api/mock/dataCheck.js"; |
| | | import { mockGenerate } from "@/api/mock/generate.js"; |
| | | |
| | | const selectedModules = ref(["sales", "purchase", "quality"]); |
| | | const selectedModules = ref(["sales", "purchase", "quality", "production"]); |
| | | const checking = ref(false); |
| | | const checkResult = ref(null); |
| | | |
| | | const generateForm = reactive({ |
| | | modules: [], |
| | | industries: [], |
| | | countRange: [3, 10], |
| | | dateRange: [], |
| | | additionalInfo: "", |
| | | }); |
| | | |
| | | const generating = ref(false); |
| | | const generateResult = ref(null); |
| | | |
| | | const handleCheck = async () => { |
| | | if (selectedModules.value.length === 0) { |
| | |
| | | checking.value = false; |
| | | } |
| | | }; |
| | | |
| | | // ç´æ¥çæï¼å
é¨èªå¨æ£æµï¼ |
| | | const handleGenerate = async () => { |
| | | if (generateForm.modules.length === 0) { |
| | | ElMessage.warning("请è³å°éæ©ä¸ä¸ªæ¨¡å"); |
| | | return; |
| | | } |
| | | generating.value = true; |
| | | try { |
| | | const res = await mockGenerate({ |
| | | modules: generateForm.modules, |
| | | industries: generateForm.industries, |
| | | countMin: generateForm.countRange[0], |
| | | countMax: generateForm.countRange[1], |
| | | dateStart: generateForm.dateRange[0] || null, |
| | | dateEnd: generateForm.dateRange[1] || null, |
| | | additionalInfo: generateForm.additionalInfo, |
| | | }); |
| | | generateResult.value = res.data; |
| | | ElMessage.success(`æåçæ ${res.data.totalGenerated} æ¡æ°æ®`); |
| | | } catch (err) { |
| | | // code 500 æ¶ååºæ¦æªå¨ä¼å¼¹é误æç¤ºï¼æ¤å¤ä¸åéå¤æç¤º |
| | | // è¥éè¦å±ç¤ºæ£æµç»æï¼éè¦å端å¨é200æ¶ä¹è¿åæ°æ®ï¼æ¤å¤æä¸å¤ç |
| | | } finally { |
| | | generating.value = false; |
| | | } |
| | | }; |
| | | |
| | | // å
æ£æµåçæ |
| | | const handleCheckFirst = async () => { |
| | | if (generateForm.modules.length === 0) { |
| | | ElMessage.warning("请è³å°éæ©ä¸ä¸ªæ¨¡å"); |
| | | return; |
| | | } |
| | | checking.value = true; |
| | | try { |
| | | const res = await dataCheck(generateForm.modules); |
| | | const result = res.data; |
| | | if (result.passedItems === result.totalItems) { |
| | | await handleGenerate(); |
| | | } else { |
| | | checkResult.value = result; |
| | | ElMessage.warning("请å
è¡¥é½åºç¡æ°æ®ååçæ"); |
| | | } |
| | | } finally { |
| | | checking.value = false; |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped></style> |
| | |
| | | @click="openDetail(scope.row)" |
| | | >详æ
|
| | | </el-button> |
| | | <el-button |
| | | link |
| | | type="danger" |
| | | :disabled="isApproving(scope.row.status)" |
| | | @click="handleDeleteSingle(scope.row)" |
| | | >å é¤ |
| | | </el-button> |
| | | <!-- <el-button--> |
| | | <!-- link--> |
| | | <!-- type="danger"--> |
| | | <!-- :disabled="isApproving(scope.row.status)"--> |
| | | <!-- @click="handleDeleteSingle(scope.row)"--> |
| | | <!-- >å é¤--> |
| | | <!-- </el-button>--> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | const { VITE_APP_ENV } = env; |
| | | const baseUrl = |
| | | env.VITE_APP_ENV === "development" |
| | | ? "http://1.15.17.182:9048" |
| | | ? "http://localhost:7005" |
| | | : env.VITE_BASE_API; |
| | | const javaUrl = |
| | | env.VITE_APP_ENV === "development" |