| docs/生产工单模块前端联调文档.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/api/productionManagement/workOrder.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/workOrderManagement/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| vite.config.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
docs/Éú²ú¹¤µ¥Ä£¿éǰ¶ËÁªµ÷Îĵµ.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,505 @@ # çäº§å·¥åæ¨¡åå端èè°ææ¡£ > ææ¡£çææ¥æï¼2026-06-11 > éç¨åæ¯ï¼dev_天津_ä¸å ´å®å¼º --- ## åæ´è®°å½ | æ¥æ | åæ´å 容 | å½±åèå´ | |------|----------|----------| | 2026-06-11 | /pageæ¥å£æ¹ä¸ºæè®¢ååç»èå | å表页å±ç¤ºé»è¾è°æ´ | | 2026-06-11 | æ°å¢/byOrder/{orderId}æ¥å£ | 订å详æ 页工åå表 | --- ## ä¸ãæ¥å£å表 | æ¥å£åç§° | æ¥å£è·¯å¾ | è¯·æ±æ¹å¼ | 说æ | |----------|----------|----------|------| | å·¥åå页æ¥è¯¢ | `/productionOperationTask/page` | GET | æç产订å维度åç»å±ç¤º | | 订åå·¥åå表 | `/productionOperationTask/byOrder/{orderId}` | GET | æ ¹æ®è®¢åIDæ¥è¯¢å·¥åæç» | --- ## äºãæ¥å£è¯¦æ ### 2.1 å·¥åå页æ¥è¯¢ #### åºæ¬ä¿¡æ¯ ``` GET /productionOperationTask/page ``` #### 请æ±åæ°ï¼Queryï¼ | åæ°å | ç±»å | å¿ å¡« | 说æ | |--------|------|------|------| | current | Number | å¦ | å½å页ç ï¼é»è®¤1 | | size | Number | å¦ | æ¯é¡µæ¡æ°ï¼é»è®¤10 | | npsNo | String | å¦ | ç产订åå·ï¼æ¨¡ç³æ¥è¯¢ | | productionOrderId | Number | å¦ | ç产订åIDï¼ç²¾ç¡®å¹é | #### 请æ±ç¤ºä¾ ```javascript // åºç¡å页æ¥è¯¢ axios.get('/productionOperationTask/page', { params: { current: 1, size: 10 } }) // æè®¢åå·çé axios.get('/productionOperationTask/page', { params: { current: 1, size: 10, npsNo: 'SC202606' } }) ``` #### ååºç»æ ```json { "code": 200, "msg": "æä½æå", "data": { "records": [ { "productionOrderId": 123, "npsNo": "SC20260611001", "endOrder": false, "productName": "çµçº¿çµç¼", "model": "RVV 3*2.5", "unit": "ç±³", "operationName": "ç»çº¿,ç»ç¼,æç¼", "productionTaskCount": 3, "planQuantity": 1000.00, "completeQuantity": 500.00, "goodQuantity": 500.00, "scrapQty": 10.00, "completionStatus": 50.00, "type": 1, "workOrderType": "æ£å¸¸", "workOrderNo": "GD20260611001,GD20260611002,GD20260611003", "planStartTime": "2026-06-10", "planEndTime": "2026-06-15", "actualStartTime": "2026-06-11", "actualEndTime": null, "status": 3 } ], "total": 100, "current": 1, "size": 10 } } ``` #### ååºå段说æ | åæ®µå | ç±»å | 说æ | å端å±ç¤ºå»ºè®® | |--------|------|------|--------------| | productionOrderId | Number | ç产订åID | ç¨äºè·³è½¬è®¢å详æ | | npsNo | String | ç产订åå· | å表主æ é¢ | | endOrder | Boolean | æ¯å¦ç»æ | å·²ç»ææ¶æ¾ç¤º"å·²ç»æ"æ ç¾ | | productName | String | 产ååç§° | åè¡¨å¯æ é¢ | | model | String | è§æ ¼åå· | 产åè§æ ¼å±ç¤º | | unit | String | åä½ | æ°éåä½ | | operationName | String | å·¥åºåç§°ï¼éå·åéï¼ | å·¥åºå表å±ç¤º | | productionTaskCount | Number | å·¥å任塿°é | æ¾ç¤º"å ±X个工å" | | planQuantity | Number | è®¡åæ°éï¼è®¢åçº§ï¼ | è¿åº¦æ¡æ»æ° | | completeQuantity | Number | 宿æ°éï¼è®¢åçº§ï¼ | è¿åº¦æ¡å·²å®æ | | goodQuantity | Number | è¯åæ°é | è¯åç»è®¡ | | scrapQty | Number | æ¥åºæ°é | æ¥åºç»è®¡ï¼çº¢è²æ è®°ï¼ | | completionStatus | Number | 宿è¿åº¦ç¾åæ¯ | è¿åº¦æ¡æ°å¼ | | type | Number | å·¥åºç±»å | 0=计æ¶ï¼1=计件 | | workOrderType | String | å·¥åç±»å | "æ£å¸¸"æ"è¿å·¥è¿ä¿®" | | workOrderNo | String | å·¥åç¼å·ï¼éå·åéï¼ | ç¹å»å¯å±å¼æ¥ç | | planStartTime | String | 计åå¼å§æ¶é´ | æ ¼å¼ï¼YYYY-MM-DD | | planEndTime | String | 计åç»ææ¶é´ | æ ¼å¼ï¼YYYY-MM-DD | | actualStartTime | String | å®é å¼å§æ¶é´ | æ ¼å¼ï¼YYYY-MM-DD | | actualEndTime | String | å®é ç»ææ¶é´ | æ ¼å¼ï¼YYYY-MM-DD | | status | Number | ç¶æ | è§ç¶ææä¸¾è¡¨ | --- ### 2.2 订åå·¥åå表 #### åºæ¬ä¿¡æ¯ ``` GET /productionOperationTask/byOrder/{orderId} ``` #### 请æ±åæ°ï¼Pathï¼ | åæ°å | ç±»å | å¿ å¡« | 说æ | |--------|------|------|------| | orderId | Number | æ¯ | ç产订åID | #### 请æ±ç¤ºä¾ ```javascript // æ¥è¯¢è®¢åID为123çææå·¥å axios.get('/productionOperationTask/byOrder/123') ``` #### ååºç»æ ```json { "code": 200, "msg": "æä½æå", "data": [ { "id": 1, "workOrderNo": "GD20260611001", "planStartTime": "2026-06-10", "planEndTime": "2026-06-12", "actualStartTime": "2026-06-11", "actualEndTime": null, "status": 3, "productionOrderId": 123, "planQuantity": 500.00, "completeQuantity": 300.00, "npsNo": "SC20260611001", "endOrder": false, "productName": "çµçº¿çµç¼", "model": "RVV 3*2.5", "unit": "ç±³", "operationName": "ç»çº¿", "type": 1, "workOrderType": "æ£å¸¸", "scrapQty": 5.00, "completionStatus": 60.00, "userNames": "å¼ ä¸,æå" }, { "id": 2, "workOrderNo": "FG20260611001", "planStartTime": "2026-06-12", "planEndTime": "2026-06-15", "actualStartTime": "2026-06-13", "actualEndTime": null, "status": 3, "productionOrderId": 123, "planQuantity": 100.00, "completeQuantity": 50.00, "npsNo": "SC20260611001", "endOrder": false, "productName": "çµçº¿çµç¼", "model": "RVV 3*2.5", "unit": "ç±³", "operationName": "ç»ç¼", "type": 0, "workOrderType": "è¿å·¥è¿ä¿®", "scrapQty": 2.00, "completionStatus": 50.00, "userNames": "çäº" } ] } ``` #### ååºå段说æ | åæ®µå | ç±»å | 说æ | å端å±ç¤ºå»ºè®® | |--------|------|------|--------------| | id | Number | å·¥åID | ç¨äºæ¥å·¥ã详æ 跳转 | | workOrderNo | String | å·¥åç¼å· | å表主æ é¢ | | planStartTime | String | 计åå¼å§æ¶é´ | æ¶é´èå´å±ç¤º | | planEndTime | String | 计åç»ææ¶é´ | æ¶é´èå´å±ç¤º | | actualStartTime | String | å®é å¼å§æ¶é´ | å®é æ¶é´å±ç¤º | | actualEndTime | String | å®é ç»ææ¶é´ | å®é æ¶é´å±ç¤º | | status | Number | å·¥åç¶æ | ç¶ææ ç¾ | | productionOrderId | Number | ç产订åID | å ³è订å | | planQuantity | Number | è®¡åæ°éï¼å·¥åçº§ï¼ | è¿åº¦æ¡æ»æ° | | completeQuantity | Number | 宿æ°éï¼å·¥åçº§ï¼ | è¿åº¦æ¡å·²å®æ | | npsNo | String | ç产订åå· | 订åå·å±ç¤º | | endOrder | Boolean | æ¯å¦ç»æ | ç»ææ ç¾ | | productName | String | 产ååç§° | 产åä¿¡æ¯ | | model | String | è§æ ¼åå· | è§æ ¼å±ç¤º | | unit | String | åä½ | æ°éåä½ | | operationName | String | å·¥åºåç§° | åä¸ªå·¥åº | | type | Number | å·¥åºç±»å | 0=计æ¶ï¼1=计件 | | workOrderType | String | å·¥åç±»å | è¿å·¥è¿ä¿®ç¨çº¢è²æ è®° | | scrapQty | Number | æ¥åºæ°é | æ¥åºç»è®¡ | | completionStatus | Number | 宿è¿åº¦ç¾åæ¯ | è¿åº¦æ¡æ°å¼ | | userNames | String | æ¥å·¥äººåï¼éå·åéï¼ | 人åå表 | --- ## ä¸ãæä¸¾å¼æ å° ### 3.1 å·¥åç¶æ | ç¶æå¼ | ææ¡ | æ ç¾é¢è²å»ºè®® | |--------|------|--------------| | 1 | å¾ ç¡®è®¤ | ç°è²/é»è®¤ | | 2 | å¾ ç产 | èè²/info | | 3 | çäº§ä¸ | 绿è²/success | | 4 | å·²ç产 | 深绿è²/success-dark | #### åç«¯ç¶ææ å°ç¤ºä¾ ```javascript const statusMap = { 1: { text: 'å¾ ç¡®è®¤', color: 'default' }, 2: { text: 'å¾ ç产', color: 'info' }, 3: { text: 'ç产ä¸', color: 'success' }, 4: { text: 'å·²ç产', color: 'success-dark' } } function getStatusTag(status) { return statusMap[status] || { text: 'æªç¥', color: 'default' } } ``` ### 3.2 å·¥åºç±»å | ç±»åå¼ | ææ¡ | 说æ | |--------|------|------| | 0 | è®¡æ¶ | æå·¥æ¶è®¡ç®å·¥èµ | | 1 | 计件 | æäº§é计ç®å·¥èµ | ```javascript const typeMap = { 0: '计æ¶', 1: '计件' } ``` ### 3.3 å·¥åç±»å夿 | ç±»å | 夿è§å | æ ç¾é¢è²å»ºè®® | |------|----------|--------------| | æ£å¸¸ | workOrderNo ä¸ä»¥ 'FG' å¼å¤´ | é»è®¤è² | | è¿å·¥è¿ä¿® | workOrderNo 以 'FG' å¼å¤´ | 红è²/error | ```javascript function getWorkOrderType(workOrderNo) { return workOrderNo?.startsWith('FG') ? 'è¿å·¥è¿ä¿®' : 'æ£å¸¸' } ``` --- ## åã页é¢è®¾è®¡å»ºè®® ### 4.1 å·¥åå表页ï¼ä½¿ç¨ /page æ¥å£ï¼ #### è¡¨æ ¼å设计 | åå | åæ®µ | 宽度 | 说æ | |------|------|------|------| | ç产订åå· | npsNo | 150px | å¯ç¹å»è·³è½¬è¯¦æ | | 产ååç§° | productName | 120px | - | | è§æ ¼åå· | model | 150px | - | | å·¥åº | operationName | 200px | å¤ä¸ªå·¥åºéå·åé | | å·¥åç±»å | workOrderType | 100px | æ£å¸¸/è¿å·¥è¿ä¿® | | è®¡åæ°é | planQuantity | 100px | 订åçº§å« | | 宿æ°é | completeQuantity | 100px | 订åçº§å« | | 宿è¿åº¦ | completionStatus | 120px | è¿åº¦æ¡+ç¾åæ¯ | | æ¥åºæ°é | scrapQty | 80px | çº¢è²æ è®° | | 工忰 | productionTaskCount | 80px | å ±X个工å | | ç¶æ | status | 80px | ç¶ææ ç¾ | | æä½ | - | 150px | æ¥ç详æ ãæ¥å·¥ç | #### è¿åº¦æ¡å±ç¤º ```javascript // 使ç¨è¿åº¦æ¡ç»ä»¶ <Progress percent={item.completionStatus} strokeColor="#52c41a" format={percent => `${percent}%`} /> ``` ### 4.2 订å详æ 页工åå表ï¼ä½¿ç¨ /byOrder/{orderId} æ¥å£ï¼ #### è¡¨æ ¼å设计 | åå | åæ®µ | 宽度 | 说æ | |------|------|------|------| | å·¥åç¼å· | workOrderNo | 150px | 主æ è¯ | | å·¥åºåç§° | operationName | 120px | åä¸ªå·¥åº | | å·¥åç±»å | workOrderType | 100px | æ£å¸¸/è¿å·¥è¿ä¿® | | å·¥åºç±»å | type | 80px | 计æ¶/计件 | | è®¡åæ°é | planQuantity | 100px | å·¥åçº§å« | | 宿æ°é | completeQuantity | 100px | å·¥åçº§å« | | 宿è¿åº¦ | completionStatus | 120px | è¿åº¦æ¡ | | æ¥åºæ°é | scrapQty | 80px | çº¢è²æ è®° | | æ¥å·¥äººå | userNames | 150px | å¤äººéå·åé | | è®¡åæ¶é´ | planStartTime ~ planEndTime | 180px | æ¶é´èå´ | | å®é æ¶é´ | actualStartTime ~ actualEndTime | 180px | æ¶é´èå´ | | ç¶æ | status | 80px | ç¶ææ ç¾ | | æä½ | - | 150px | æ¥å·¥ãæµè½¬å¡ç | --- ## äºã两个æ¥å£æ°æ®å·®å¼å¯¹æ¯ | 对æ¯é¡¹ | /page æ¥å£ | /byOrder/{orderId} æ¥å£ | |--------|------------|-------------------------| | æ°æ®ç»´åº¦ | è®¢åæ±æ» | å·¥åæç» | | planQuantity | 订åè®¡åæ° | å·¥åè®¡åæ° | | completeQuantity | 订åå®ææ° | å·¥åå®ææ° | | completionStatus | 订åè¿åº¦ | å·¥åè¿åº¦ | | operationName | å¤å·¥åºèå | åä¸ªå·¥åº | | workOrderNo | å¤å·¥åèå | å个工å | | userNames | æ | ææ¥å·¥äººå | | ç¨é | åè¡¨æ±æ»é¡µ | è¯¦æ æç»é¡µ | --- ## å ãå端è°ç¨æ³¨æäºé¡¹ ### 6.1 å页忰 - `/page` æ¥å£æ¯æå页ï¼éä¼ `current` å `size` - `/byOrder/{orderId}` æ¥å£ä¸å页ï¼è¿åå ¨é¨å·¥åå表 ### 6.2 æ°éåæ®µç²¾åº¦ - æææ°éåæ®µä¸º `BigDecimal` ç±»åï¼å端å±ç¤ºæ¶ä¿ç2ä½å°æ° - 宿è¿åº¦ `completionStatus` 已为ç¾åæ¯æ°å¼ï¼å¦50.00表示50%ï¼ ### 6.3 æ¶é´åæ®µæ ¼å¼ - æææ¶é´å段为 `LocalDate` æ ¼å¼ï¼`YYYY-MM-DD` - æ æ¶é´å¼æ¶è¿å `null`ï¼å端éå空å¼å¤ç ### 6.4 å·¥åç±»å夿 - æ¥å£å·²è¿å `workOrderType` åæ®µï¼æ éåç«¯å¤æ - è¿å·¥è¿ä¿®å·¥å建议使ç¨çº¢è²æ ç¾çªåºæ¾ç¤º ### 6.5 æ¥å·¥äººååæ®µ - `userNames` 为éå·åéå符串ï¼å¯è½ä¸ºç©º - å¤äººæ¶å»ºè®®ä½¿ç¨æ ç¾æå¤´åå表å±ç¤º --- ## ä¸ã常è§é®é¢å¤ç ### 7.1 è¿åº¦ä¸ºç©ºæé¤é¶ - `completionStatus` å·²å¨SQLä¸å¤çé¤é¶æ åµ - è¥è®¡åæ°é为0ï¼è¿åº¦æ¾ç¤ºä¸º0 ### 7.2 å·¥åå·ä¸ºç©º - `workOrderNo` ä¸ºå¿ å¡«åæ®µï¼ä¸ä¼ä¸ºç©º - è¥èåå±ç¤ºæ¶å¤ä¸ªå·¥åå·ç¨éå·åé ### 7.3 æ¥åºæ°éå±ç¤º - `scrapQty` 为累计æ¥åºæ°é - 建议使ç¨çº¢è²å使è¦å徿 æ è¯ --- ## å «ãMockæ°æ®ç¤ºä¾ ### 8.1 /page æ¥å£Mock ```json { "code": 200, "data": { "records": [ { "productionOrderId": 1, "npsNo": "SC20260611001", "endOrder": false, "productName": "çµçº¿çµç¼", "model": "RVV 3*2.5", "unit": "ç±³", "operationName": "ç»çº¿,ç»ç¼,æç¼", "productionTaskCount": 3, "planQuantity": 1000.00, "completeQuantity": 500.00, "goodQuantity": 500.00, "scrapQty": 10.00, "completionStatus": 50.00, "type": 1, "workOrderType": "æ£å¸¸", "workOrderNo": "GD20260611001,GD20260611002,GD20260611003", "planStartTime": "2026-06-10", "planEndTime": "2026-06-15", "actualStartTime": "2026-06-11", "actualEndTime": null, "status": 3 } ], "total": 1, "current": 1, "size": 10 } } ``` ### 8.2 /byOrder/{orderId} æ¥å£Mock ```json { "code": 200, "data": [ { "id": 1, "workOrderNo": "GD20260611001", "planStartTime": "2026-06-10", "planEndTime": "2026-06-12", "actualStartTime": "2026-06-11", "actualEndTime": null, "status": 3, "productionOrderId": 1, "planQuantity": 500.00, "completeQuantity": 300.00, "npsNo": "SC20260611001", "endOrder": false, "productName": "çµçº¿çµç¼", "model": "RVV 3*2.5", "unit": "ç±³", "operationName": "ç»çº¿", "type": 1, "workOrderType": "æ£å¸¸", "scrapQty": 5.00, "completionStatus": 60.00, "userNames": "å¼ ä¸,æå" }, { "id": 2, "workOrderNo": "FG20260611001", "planStartTime": "2026-06-12", "planEndTime": "2026-06-15", "actualStartTime": "2026-06-13", "actualEndTime": null, "status": 3, "productionOrderId": 1, "planQuantity": 100.00, "completeQuantity": 50.00, "npsNo": "SC20260611001", "endOrder": false, "productName": "çµçº¿çµç¼", "model": "RVV 3*2.5", "unit": "ç±³", "operationName": "ç»ç¼", "type": 0, "workOrderType": "è¿å·¥è¿ä¿®", "scrapQty": 2.00, "completionStatus": 50.00, "userNames": "çäº" } ] } ``` src/api/productionManagement/workOrder.js
@@ -95,3 +95,11 @@ params: query, }); } // æ ¹æ®è®¢åIDè·åå·¥åæç»å表 export function getWorkOrderListByOrderId(orderId) { return request({ url: `/productionOperationTask/byOrder/${orderId}`, method: "get", }); } src/views/productionManagement/workOrderManagement/index.vue
@@ -3,15 +3,6 @@ <div class="search_form mb20"> <div class="search-row"> <div class="search-item"> <span class="search_title">å·¥åç¼å·ï¼</span> <el-input v-model="searchForm.workOrderNo" style="width: 240px" placeholder="请è¾å ¥" @change="handleQuery" clearable prefix-icon="Search" /> </div> <div class="search-item"> <span class="search_title">ç产订åå·ï¼</span> <el-input v-model="searchForm.npsNo" style="width: 240px" @@ -27,18 +18,199 @@ </div> </div> <div class="table_list"> <PIMTable rowKey="id" :column="tableColumn" :tableData="tableData" :page="page" :tableLoading="tableLoading" @pagination="pagination"> <template #completionStatus="{ row }"> <el-progress :percentage="toProgressPercentage(row?.completionStatus)" :color="progressColor(toProgressPercentage(row?.completionStatus))" :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" /> </template> </PIMTable> <el-table :data="tableData" border v-loading="tableLoading" :expand-row-keys="expandedRowKeys" :row-key="(row) => row.productionOrderId" @expand-change="expandChange" height="calc(100vh - 22em)"> <!-- å±å¼è¡å --> <el-table-column type="expand" width="60" fixed="left"> <template #default="props"> <el-table :data="props.row.children || []" border :row-class-name="({ row }) => getChildRowClassName(row)" v-loading="childLoading[props.row.productionOrderId]" style="margin: 10px 0;"> <el-table-column align="center" label="åºå·" type="index" width="60" /> <el-table-column label="å·¥åç¼å·" prop="workOrderNo" width="140"> <template #default="scope"> <span :class="{ 'rework-text': scope.row.workOrderNo?.startsWith('FG') }"> {{ scope.row.workOrderNo }} </span> </template> </el-table-column> <el-table-column label="å·¥åºåç§°" prop="operationName" width="100" /> <el-table-column label="å·¥åºç±»å" width="80" align="center"> <template #default="scope"> <span>{{ scope.row.type === 0 ? '计æ¶' : '计件' }}</span> </template> </el-table-column> <el-table-column label="è®¡åæ°é" prop="planQuantity" width="100" /> <el-table-column label="宿æ°é" prop="completeQuantity" width="100" /> <el-table-column label="宿è¿åº¦" width="140"> <template #default="scope"> <el-progress :percentage="toProgressPercentage(scope.row?.completionStatus)" :color="progressColor(toProgressPercentage(scope.row?.completionStatus))" :status="toProgressPercentage(scope.row?.completionStatus) >= 100 ? 'success' : ''" /> </template> </el-table-column> <el-table-column label="æ¥åºæ°é" prop="scrapQty" width="80"> <template #default="scope"> <span :class="{ 'scrap-text': scope.row.scrapQty > 0 }"> {{ scope.row.scrapQty || 0 }} </span> </template> </el-table-column> <el-table-column label="æ¥å·¥äººå" prop="userNames" width="150" show-overflow-tooltip /> <el-table-column label="计åå¼å§æ¶é´" prop="planStartTime" width="120" /> <el-table-column label="计åç»ææ¶é´" prop="planEndTime" width="120" /> <el-table-column label="å®é å¼å§æ¶é´" prop="actualStartTime" width="120" /> <el-table-column label="å®é ç»ææ¶é´" prop="actualEndTime" width="120" /> <el-table-column label="ç¶æ" width="100" align="center"> <template #default="scope"> <el-tag :type="getStatusTagType(scope.row.status)"> {{ getStatusText(scope.row.status) }} </el-tag> </template> </el-table-column> <el-table-column label="æä½" width="200" align="center" fixed="right"> <template #default="scope"> <el-button link type="primary" @click="downloadAndPrintWorkOrder(scope.row)"> æµè½¬å¡ </el-button> <el-button link type="primary" @click="openWorkOrderFiles(scope.row)"> éä»¶ </el-button> <el-button link type="primary" v-if="!scope.row.endOrder" :disabled="isReportDisabled(scope.row)" @click="showReportDialog(scope.row)"> æ¥å·¥ </el-button> </template> </el-table-column> </el-table> </template> </el-table-column> <!-- 主表å --> <el-table-column align="center" label="åºå·" type="index" width="60" /> <el-table-column label="ç产订åå·" prop="npsNo" width="150" /> <el-table-column label="产ååç§°" prop="productName" width="140" /> <el-table-column label="è§æ ¼" prop="model" width="150" /> <el-table-column label="åä½" prop="unit" width="80" /> <el-table-column label="å·¥åºåç§°" prop="operationName" width="200" show-overflow-tooltip /> <el-table-column label="工忰é" prop="productionTaskCount" width="80"> <template #default="scope"> <span>å ±{{ scope.row.productionTaskCount || 0 }}个</span> </template> </el-table-column> <el-table-column label="è®¡åæ°é" prop="planQuantity" width="100" /> <el-table-column label="宿æ°é" prop="completeQuantity" width="100" /> <el-table-column label="宿è¿åº¦" width="140"> <template #default="scope"> <el-progress :percentage="toProgressPercentage(scope.row?.completionStatus)" :color="progressColor(toProgressPercentage(scope.row?.completionStatus))" :status="toProgressPercentage(scope.row?.completionStatus) >= 100 ? 'success' : ''" /> </template> </el-table-column> <el-table-column label="æ¥åºæ°é" prop="scrapQty" width="80"> <template #default="scope"> <span :class="{ 'scrap-text': scope.row.scrapQty > 0 }"> {{ scope.row.scrapQty || 0 }} </span> </template> </el-table-column> <el-table-column label="ç¶æ" width="100" align="center"> <template #default="scope"> <el-tag :type="getStatusTagType(scope.row.status)"> {{ getStatusText(scope.row.status) }} </el-tag> </template> </el-table-column> <el-table-column label="计åå¼å§æ¶é´" prop="planStartTime" width="120" /> <el-table-column label="计åç»ææ¶é´" prop="planEndTime" width="120" /> <el-table-column label="å®é å¼å§æ¶é´" prop="actualStartTime" width="120" /> <el-table-column label="å®é ç»ææ¶é´" prop="actualEndTime" width="120" /> </el-table> <PaginationComp v-show="page.total > 0" :total="page.total" :page="page.current" :limit="page.size" @pagination="pagination" /> </div> <!-- æµè½¬å¡å¼¹çª --> <el-dialog v-model="transferCardVisible" @@ -262,11 +434,12 @@ </template> <script setup> import { onMounted, ref, nextTick } from "vue"; import { onMounted, ref, nextTick, reactive, toRefs, getCurrentInstance } from "vue"; import { ElMessageBox } from "element-plus"; import dayjs from "dayjs"; import { productWorkOrderPage, getWorkOrderListByOrderId, addProductMain, downProductWorkOrder, } from "@/api/productionManagement/workOrder.js"; @@ -275,7 +448,7 @@ import { getUserProfile, userListNoPageByTenantId } from "@/api/system/user.js"; import { getDicts } from "@/api/system/dict/data"; import QRCode from "qrcode"; import { getCurrentInstance, reactive, toRefs } from "vue"; import PaginationComp from "@/components/PIMTable/Pagination.vue"; import MaterialDialog from "./components/MaterialDialog.vue"; const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue") @@ -285,130 +458,31 @@ const { proxy } = getCurrentInstance(); const userStore = useUserStore(); const tableColumn = ref([ { label: "å·¥åç±»å", prop: "workOrderType", width: "80", }, { label: "å·¥åç¼å·", prop: "workOrderNo", width: "140", }, { label: "ç产订åå·", prop: "npsNo", width: "140", }, { label: "产ååç§°", prop: "productName", width: "140", }, { label: "è§æ ¼", prop: "model", }, { label: "åä½", prop: "unit", }, { label: "å·¥åºåç§°", prop: "operationName", width: "100", }, { label: "éæ±æ°é", prop: "planQuantity", width: "140", }, { label: "宿æ°é", prop: "completeQuantity", width: "140", }, { label: "宿è¿åº¦", prop: "completionStatus", dataType: "slot", slot: "completionStatus", width: "140", }, { label: "计åå¼å§æ¶é´", prop: "planStartTime", width: "140", }, { label: "计åç»ææ¶é´", prop: "planEndTime", width: "140", }, { label: "å®é å¼å§æ¶é´", prop: "actualStartTime", width: "140", }, { label: "å®é ç»ææ¶é´", prop: "actualEndTime", width: "140", }, { label: "æä½", width: "260", align: "center", dataType: "action", fixed: "right", operation: [ { name: "æµè½¬å¡", clickFun: row => { downloadAndPrintWorkOrder(row); }, }, { name: "éä»¶", clickFun: row => { openWorkOrderFiles(row); }, }, // { // name: "ç©æ", // clickFun: row => { // openMaterialDialog(row); // }, // }, { name: "æ¥å·¥", clickFun: row => { showReportDialog(row); }, showHide: row => !row.endOrder, disabled: row => { if (row.planQuantity <= 0) return true; if (!row.userIds) return false; try { const userIds = typeof row.userIds === "string" ? JSON.parse(row.userIds) : row.userIds; if (Array.isArray(userIds)) { return !userIds.some(id => String(id) === String(userStore.id)); } return true; } catch (e) { return true; } }, }, ], }, ]); // ç¶ææä¸¾æ å° const statusMap = { 1: 'å¾ ç¡®è®¤', 2: 'å¾ ç产', 3: 'ç产ä¸', 4: 'å·²ç产', }; const getStatusText = (status) => statusMap[status] || 'æªç¥'; const getStatusTagType = (status) => { switch (status) { case 1: return 'info'; case 2: return 'warning'; case 3: return 'primary'; case 4: return 'success'; default: return 'info'; } }; const tableData = ref([]); const tableLoading = ref(false); const expandedRowKeys = ref([]); const childLoading = ref({}); const transferCardVisible = ref(false); const transferCardData = ref([]); const transferCardQrUrl = ref(""); @@ -434,7 +508,7 @@ paramGroups: {}, }); const params = ref({}); const params = ref([]); const dictOptions = ref({}); const paramLoading = ref(false); @@ -445,7 +519,6 @@ return; } const num = Number(value); // æ´æ°ä¸å¤§äºçäº1 if (isNaN(num) || !Number.isInteger(num) || num < 0) { callback(new Error("çäº§åæ ¼æ°éå¿ é¡»å¤§äºçäº0")); return; @@ -460,7 +533,6 @@ return; } const num = Number(value); // æ´æ°ä¸å¤§äºçäº0 if (isNaN(num) || !Number.isInteger(num) || num < 0) { callback(new Error("æ¥åºæ°éå¿ é¡»å¤§äºçäº0")); return; @@ -474,7 +546,7 @@ scrapQty: [{ validator: validateScrapQty, trigger: "blur" }], }; // å¤ççäº§åæ ¼æ°éè¾å ¥ï¼éå¶å¿ 须大äºçäº0 // å¤ççäº§åæ ¼æ°éè¾å ¥ const handleQuantityInput = value => { if (value === "" || value === null || value === undefined) { reportForm.quantity = null; @@ -484,15 +556,12 @@ if (isNaN(num)) { return; } // 妿å°äº1ï¼æ¸ é¤ if (num < 0) { reportForm.quantity = null; return; } // 妿æ¯å°æ°åæ´æ°é¨å if (!Number.isInteger(num)) { const intValue = Math.floor(num); // 妿忴åå°äº1ï¼æ¸ é¤ if (intValue < 0) { reportForm.quantity = null; return; @@ -510,21 +579,17 @@ return; } const num = Number(value); // 妿æ¯NaNï¼ä¿æåå¼ if (isNaN(num)) { return; } // 妿æ¯è´æ°ï¼æ¸ é¤è¾å ¥ if (num < 0) { reportForm.scrapQty = null; return; } // 妿æ¯å°æ°ï¼åæ´æ°é¨å if (!Number.isInteger(num)) { reportForm.scrapQty = Math.floor(num); return; } // ææçéè´æ´æ°ï¼å æ¬0ï¼ reportForm.scrapQty = num; }; @@ -539,11 +604,11 @@ const data = reactive({ searchForm: { workOrderNo: "", npsNo: "", }, }); const { searchForm } = toRefs(data); const toProgressPercentage = val => { const n = Number(val); if (!Number.isFinite(n)) return 0; @@ -551,6 +616,7 @@ if (n >= 100) return 100; return Math.round(n); }; const progressColor = percentage => { const p = toProgressPercentage(percentage); if (p < 30) return "#f56c6c"; @@ -560,7 +626,6 @@ }; // æ¥è¯¢å表 /** æç´¢æé®æä½ */ const handleQuery = () => { page.current = 1; getList(); @@ -574,11 +639,15 @@ const getList = () => { tableLoading.value = true; expandedRowKeys.value = []; const params = { ...searchForm.value, ...page }; productWorkOrderPage(params) .then(res => { tableLoading.value = false; tableData.value = res.data.records; tableData.value = res.data.records.map(item => ({ ...item, children: [], })); page.total = res.data.total; }) .catch(() => { @@ -586,7 +655,67 @@ }); }; // ä¸è½½å¹¶æå°å·¥åæµè½¬å¡ï¼æä»¶æµï¼ // å±å¼è¡æå è½½ const expandChange = (row, expandedRows) => { if (expandedRows.length > 0) { expandedRowKeys.value = []; const orderId = row.productionOrderId; // æ£æ¥æ¯å¦å·²ææ°æ® if (row.children && row.children.length > 0) { expandedRowKeys.value.push(orderId); return; } childLoading.value[orderId] = true; getWorkOrderListByOrderId(orderId) .then(res => { childLoading.value[orderId] = false; const index = tableData.value.findIndex( item => item.productionOrderId === orderId ); if (index > -1) { tableData.value[index].children = res.data || []; } expandedRowKeys.value.push(orderId); }) .catch(error => { childLoading.value[orderId] = false; console.error('å 载工åæç»å¤±è´¥:', error); }); } else { expandedRowKeys.value = []; } }; // åè¡¨è¡æ ·å¼ï¼è¿å·¥è¿ä¿®çº¢è²æ è®°ï¼ const getChildRowClassName = (row) => { if (row.workOrderNo?.startsWith('FG')) { return 'row-rework'; } return ''; }; // æ¥å·¥æé®ç¦ç¨é»è¾ const isReportDisabled = (row) => { if (row.planQuantity <= 0) return true; if (!row.userIds) return false; try { const userIds = typeof row.userIds === "string" ? JSON.parse(row.userIds) : row.userIds; if (Array.isArray(userIds)) { return !userIds.some(id => String(id) === String(userStore.id)); } return true; } catch (e) { return true; } }; // ä¸è½½å¹¶æå°å·¥åæµè½¬å¡ const downloadAndPrintWorkOrder = async row => { if (!row || !row.id) { proxy.$modal.msgError("缺å°å·¥åIDï¼æ æ³ä¸è½½æµè½¬å¡"); @@ -596,7 +725,6 @@ ? `å·¥åæµè½¬å¡_${row.workOrderNo}.xlsx` : "å·¥åæµè½¬å¡.xlsx"; try { // è°ç¨æ¥å£ï¼ä»¥ responseType: 'blob' è·åæä»¶æµ const blob = await downProductWorkOrder(row.id); if (!blob) { @@ -604,14 +732,12 @@ return; } // å建 Blob URL const fileBlob = blob instanceof Blob ? blob : new Blob([blob], { type: blob.type || "application/octet-stream" }); const url = window.URL.createObjectURL(fileBlob); // å建éè iframeï¼ç¨äºè§¦åæµè§å¨æå° const iframe = document.createElement("iframe"); iframe.style.position = "fixed"; iframe.style.right = "0"; @@ -628,7 +754,6 @@ iframe.contentWindow?.print(); } catch (e) { console.error("èªå¨è°ç¨æå°å¤±è´¥", e); // éèæ±å ¶æ¬¡ï¼æå¼æ°çªå£ç±ç¨æ·æå¨æå° window.open(url); } }; @@ -731,7 +856,6 @@ return; } // éªè¯çäº§åæ ¼æ°é if ( reportForm.quantity === null || reportForm.quantity === undefined || @@ -752,14 +876,6 @@ return; } // if (quantity > reportForm.planQuantity) { // ElMessageBox.alert("æ¬æ¬¡ç产æ°éä¸è½è¶ è¿å¾ ç产æ°é", "æç¤º", { // confirmButtonText: "ç¡®å®", // }); // return; // } // éªè¯æ¥åºæ°é const scrapQty = Number(reportForm.scrapQty); if (!isNaN(scrapQty) && scrapQty < 0) { ElMessageBox.alert("æ¥åºæ°éä¸è½å°äº0", "æç¤º", { @@ -767,13 +883,6 @@ }); return; } // if (!isNaN(scrapQty) && scrapQty > quantity) { // ElMessageBox.alert("æ¥åºæ°éä¸è½å¤§äºæ¬æ¬¡ç产æ°é", "æç¤º", { // confirmButtonText: "ç¡®å®", // }); // return; // } const productionOperationParamList = params.value.map(param => ({ ...param, @@ -863,7 +972,6 @@ onMounted(() => { userStore.getInfo(); getList(); // è·åç¨æ·å表 userListNoPageByTenantId().then(res => { if (res.code === 200) { userOptions.value = res.data; @@ -955,6 +1063,31 @@ font-size: 12px; min-width: 30px; } // è¿å·¥è¿ä¿®å·¥åçº¢è²æ è®° .row-rework { background-color: #fef0f0 !important; :deep(.el-table__cell) { background-color: #fef0f0 !important; } } .rework-text { color: #f56c6c; font-weight: bold; } // æ¥åºæ°éçº¢è²æ è®° .scrap-text { color: #f56c6c; } // åè¡¨æ ¼æ ·å¼ :deep(.el-table__expanded-cell) { padding: 10px 30px !important; background-color: #fafafa; } </style> <style lang="scss"> vite.config.js
@@ -8,7 +8,7 @@ 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"