| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å¾
æ¥å·¥å°è´¦ æ¥å£æ¹æ¡ |
| | | |
| | | ## éæ± |
| | | |
| | | æäº§åéè¦ä¸ä¸ª"å¾
æ¥å·¥å°è´¦"ï¼å±ç¤ºå·²æäº§ä½å°æªæ¥å·¥å®çä»»å¡ï¼æ ¸å¿æ¯ **å¾
æ¥å·¥æ°é = æäº§æ°é â å·²æ¥å·¥æ°é**ã |
| | | |
| | | æ°æ®æºç¨ `mes_pro_task`ï¼ä»»å¡çº§æ±æ»ï¼æ£ç¡®--å¾
æ¥å·¥å¤©ç¶æ¯ä»»å¡çº§æ¦å¿µï¼å·²ç产æ°é producedQuantity ç±æ¥å·¥å®¡æ¹ç´¯å ååï¼æ éç°ç® feedbackï¼ã |
| | | |
| | | ## æ ¸å¿è¿æ»¤ä¸å段 |
| | | |
| | | - **è¿æ»¤**ï¼`status = PREPARE(0)`ï¼è¿è¡ä¸ï¼æé¤å·²å®æ/已忶ï¼AND `(quantity - IFNULL(produced_quantity,0)) > 0`ï¼ä»æå¾
æ¥å·¥éï¼ |
| | | - **æ°å¢å±ç¤ºå段**ï¼ |
| | | - `pendingQuantity` å¾
æ¥å·¥æ°é = `quantity - producedQuantity` |
| | | - `feedbackRate` æ¥å·¥å®æç = `producedQuantity / quantity à 100`ï¼æäº§æ°é为 0 æ¶ç» 0ï¼ |
| | | - å
¶ä½å±ç¤ºå段å¤ç¨ç°æ `MesProTaskRespVO`ï¼å·¥åå·ã产åãå·¥åºãå·¥ä½ã客æ·ãæäº§/å·²ç产/åæ ¼/ä¸è¯æ°éãéæ±æ¥æçï¼å·²ç± `buildTaskRespVOList` æ¹éå
³èæ¼å¥½ï¼ |
| | | |
| | | ## æ¹å¨æ¸
å |
| | | |
| | | ### 1. `MesProTaskRespVO` å ä¸¤ä¸ªåæ®µ |
| | | |
| | | `controller/admin/pro/task/vo/MesProTaskRespVO.java`ï¼å¨ `unqualifyQuantity` ä¹åï¼ |
| | | |
| | | ```java |
| | | @Schema(description = "å¾
æ¥å·¥æ°é", example = "50.00") |
| | | private BigDecimal pendingQuantity; |
| | | |
| | | @Schema(description = "æ¥å·¥å®æç(%)", example = "50.00") |
| | | private BigDecimal feedbackRate; |
| | | ``` |
| | | |
| | | ### 2. `MesProTaskController.buildTaskRespVOList` 计ç®è¿ä¸¤ä¸ªå段 |
| | | |
| | | å¨ `convertList` ç lambda éï¼`BeanUtils.toBean` ä¹å追å ï¼ |
| | | |
| | | ```java |
| | | BigDecimal quantity = task.getQuantity() == null ? BigDecimal.ZERO : task.getQuantity(); |
| | | BigDecimal produced = task.getProducedQuantity() == null ? BigDecimal.ZERO : task.getProducedQuantity(); |
| | | vo.setPendingQuantity(quantity.subtract(produced)); |
| | | vo.setFeedbackRate(quantity.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO |
| | | : produced.multiply(new BigDecimal("100")).divide(quantity, 2, RoundingMode.HALF_UP)); |
| | | ``` |
| | | |
| | | > ç°æ page / get / gantt é½èµ° `buildTaskRespVOList`ï¼å è¿ä¸¤ååå®ä»¬ä¹ä¼å¸¦åºï¼æ 害䏿´å®æ´ã |
| | | |
| | | ### 3. `MesProTaskMapper` å `selectPendingFeedbackPage` |
| | | |
| | | `dal/mysql/pro/task/MesProTaskMapper.java`ï¼ä»¿ `selectPage`ï¼å¼ºå¶ `status=PREPARE` + å¾
æ¥å·¥é>0ï¼å¤ç¨å
¶ä½è¿æ»¤æ¡ä»¶ï¼ä¸éè¦ checkFlag joinï¼ |
| | | |
| | | ```java |
| | | default PageResult<MesProTaskDO> selectPendingFeedbackPage(MesProTaskPageReqVO reqVO) { |
| | | MPJLambdaWrapperX<MesProTaskDO> query = new MPJLambdaWrapperX<>(); |
| | | query.selectAll(MesProTaskDO.class); |
| | | query.eq(MesProTaskDO::getStatus, MesProTaskStatusEnum.PREPARE.getStatus()); // å¾
æ¥å·¥=è¿è¡ä¸ |
| | | query.apply("(quantity - IFNULL(produced_quantity, 0)) > 0"); // 仿å¾
æ¥å·¥é |
| | | query.likeIfPresent(MesProTaskDO::getCode, reqVO.getCode()) |
| | | .likeIfPresent(MesProTaskDO::getName, reqVO.getName()) |
| | | .eqIfPresent(MesProTaskDO::getWorkOrderId, reqVO.getWorkOrderId()) |
| | | .eqIfPresent(MesProTaskDO::getRouteId, reqVO.getRouteId()) |
| | | .eqIfPresent(MesProTaskDO::getProcessId, reqVO.getProcessId()) |
| | | .eqIfPresent(MesProTaskDO::getWorkstationId, reqVO.getWorkstationId()) |
| | | .betweenIfPresent(MesProTaskDO::getCreateTime, reqVO.getCreateTime()) |
| | | .orderByDesc(MesProTaskDO::getId); |
| | | return selectPage(reqVO, query); |
| | | } |
| | | ``` |
| | | |
| | | > `apply` ç¨è£¸ååï¼æ¬æ¥è¯¢æ joinï¼`quantity`/`produced_quantity` æ æ§ä¹ã`reqVO.getStatus()`/`getStatuses()` 卿¤æ¥å£è¢«å¿½ç¥ï¼å¼ºå¶ PREPAREï¼ï¼ç¬¦å"å¾
æ¥å·¥"è¯ä¹ã |
| | | |
| | | ### 4. `MesProTaskService` + Impl å æ¹æ³ |
| | | |
| | | æ¥å£å ï¼ |
| | | |
| | | ```java |
| | | PageResult<MesProTaskDO> getPendingFeedbackPage(MesProTaskPageReqVO pageReqVO); |
| | | ``` |
| | | |
| | | Implï¼ |
| | | |
| | | ```java |
| | | @Override |
| | | public PageResult<MesProTaskDO> getPendingFeedbackPage(MesProTaskPageReqVO pageReqVO) { |
| | | return taskMapper.selectPendingFeedbackPage(pageReqVO); |
| | | } |
| | | ``` |
| | | |
| | | ### 5. `MesProTaskController` å æ¥å£ |
| | | |
| | | å¤ç¨ `buildTaskRespVOList` æ¼å±ç¤ºå段ï¼å¤ç¨ `MesProTaskPageReqVO` åè¿æ»¤ï¼ |
| | | |
| | | ```java |
| | | @GetMapping("/pending-feedback-page") |
| | | @Operation(summary = "è·å¾å¾
æ¥å·¥å°è´¦å页", description = "å·²æäº§ä¸ä»æå¾
æ¥å·¥æ°éçä»»å¡ï¼ç¶æ=è¿è¡ä¸ï¼") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-task:query')") |
| | | public CommonResult<PageResult<MesProTaskRespVO>> getPendingFeedbackPage(@Valid MesProTaskPageReqVO pageReqVO) { |
| | | PageResult<MesProTaskDO> pageResult = taskService.getPendingFeedbackPage(pageReqVO); |
| | | return success(new PageResult<>(buildTaskRespVOList(pageResult.getList()), pageResult.getTotal())); |
| | | } |
| | | ``` |
| | | |
| | | ### 6. åç«¯ææ¡£ |
| | | |
| | | æ frontend-docs è§åè¾åº `docs/task_pending_feedback_ledger.md`ï¼æ¥å£è·¯å¾ãè¿æ»¤åæ°ãååºå段ï¼å« pendingQuantity/feedbackRateï¼ãåç«¯è¡¨æ ¼å建议ã |
| | | |
| | | ### 7. ç¼è¯æ ¡éª |
| | | |
| | | `mvn compile -pl yudao-module-mes -am -Dmaven.compiler.source=25 -Dmaven.compiler.target=25 -q`ï¼æ compile-check è§åï¼ |
| | | |
| | | ## è¡ä¸ºè¯´æ |
| | | |
| | | | 任塿
åµ | æ¯å¦åºç°å¨å¾
æ¥å·¥å°è´¦ | |
| | | |---------|--------------------| |
| | | | ç¶æ=è¿è¡ä¸ï¼å·²æ¥å·¥ < æäº§ | â
åºç°ï¼pendingQuantity>0 | |
| | | | ç¶æ=è¿è¡ä¸ï¼å·²æ¥å·¥ = æäº§ï¼æ¥æ»¡äºä½å·¥å没å®å·¥ï¼| â ä¸åºç°ï¼pendingQuantity=0ï¼| |
| | | | ç¶æ=已宿/已忶 | â ä¸åºç° | |
| | | | ç¶æ=è¿è¡ä¸ï¼ä»æªæ¥å·¥ | â
åºç°ï¼pendingQuantity=æäº§æ°é | |
| | | |
| | | > å·²æ¥å·¥=æäº§ä½ä»»å¡ä» PREPARE çä»»å¡ä¸å¨å°è´¦éï¼æ²¡å¾
æ¥å·¥éäºï¼ãè¥æ³ç"ææè¿è¡ä¸ä»»å¡"ï¼ç¨ç°æ `/mes/pro/task/page?status=0`ã |
| | | |
| | | ## 䏿¹å¨é¡¹ |
| | | |
| | | - æ¥å·¥ç¸å
³é»è¾ä¸å¨ |
| | | - `MesProTaskPageReqVO` ä¸å¨ï¼å¤ç¨ï¼ |
| | | - `selectPage` åé»è¾ä¸å¨ |
| | | - 䏿°å»ºç¬ç« ReqVO/RespVOï¼å¤ç¨ç°æï¼æå°æ¹å¨ï¼ |
| | | |
| | | ## å¾
确认 |
| | | |
| | | - `feedbackRate`ï¼å®æçï¼è¦ä¸è¦ï¼é»è®¤å ä¸ï¼å±ç¤ºæ´ç´è§ï¼ä¸è¦å¯å»æã |
| | | - æ¯å¦éè¦"æå¾
æ¥å·¥æ°éååº"æåï¼å½åæ id ååºã坿¹ `orderByDesc(pendingQuantity)`ï¼ä½ MPJ 对计ç®åæåºé raw SQLï¼ç¥ç¹ãé»è®¤ id ååºï¼éè¦å说ã |
| | |
| | | "Bash(chmod +x /tmp/fix_controller.sh)", |
| | | "Bash(/tmp/fix_controller.sh)", |
| | | "Bash(chmod +x /tmp/fix2.sh)", |
| | | "Bash(/tmp/fix2.sh)" |
| | | "Bash(/tmp/fix2.sh)", |
| | | "Bash(\"E:/soft/IntelliJ IDEA 2025.3.4/plugins/maven/lib/maven3/bin/mvn.cmd\" -DskipTests=true -q compile -pl yudao-module-mdm-api,yudao-module-mdm,yudao-module-mes -am)" |
| | | ], |
| | | "deny": [ |
| | | "Bash(rm -rf *)", |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æ¹æ¬¡è¿½æº¯åè½ - å端èè°æ¹æ¡ |
| | | |
| | | ## æ¦è¿° |
| | | |
| | | æ¬æ¬¡æ¹é ä¿®å¤å¹¶å®åäºæ¹æ¬¡è¿½æº¯åè½ï¼æ¯æä»æ¹æ¬¡åºåçæ£åï¼åææâæåï¼åååï¼æåâåææï¼è¿½æº¯æ¥è¯¢ã |
| | | |
| | | --- |
| | | |
| | | ## ä¸ãæ¶åé¡µé¢ |
| | | |
| | | | é¡µé¢ | è·¯å¾ | æ¹å¨è¯´æ | |
| | | |------|------|----------| |
| | | | æ¹æ¬¡ç®¡çå表 | `/mes/wm/batch/list` | æ·»å "åå追溯"ã"åå追溯"æé® | |
| | | | æ¹æ¬¡è¯¦æ
| `/mes/wm/batch/detail` | å±ç¤ºè¿½æº¯ç»ææ¶é´çº¿ | |
| | | |
| | | --- |
| | | |
| | | ## äºãAPI æ¥å£ |
| | | |
| | | ### 2.1 æ¹æ¬¡åå追溯 |
| | | |
| | | **è¯·æ±æ¹å¼**ï¼GET |
| | | |
| | | **请æ±è·¯å¾**ï¼`/mes/wm/batch/forward-list` |
| | | |
| | | **请æ±åæ°**ï¼ |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | code | String | æ¯ | æ¹æ¬¡ç¼ç | |
| | | |
| | | **ååºç¤ºä¾**ï¼ |
| | | |
| | | ```json |
| | | { |
| | | "code": 0, |
| | | "msg": "", |
| | | "data": [ |
| | | { |
| | | "id": 1, |
| | | "code": "BATCH20250713001", |
| | | "itemId": 100, |
| | | "itemCode": "ITEM001", |
| | | "itemName": "æåA", |
| | | "workOrderId": 50, |
| | | "workOrderCode": "WO20250713001", |
| | | "taskId": 80, |
| | | "taskCode": "TASK001", |
| | | "vendorId": 20, |
| | | "vendorCode": "VENDOR001", |
| | | "vendorName": "ä¾åºåA", |
| | | "clientId": 30, |
| | | "clientCode": "CLIENT001", |
| | | "clientName": "客æ·A", |
| | | "workstationId": 40, |
| | | "workstationCode": "WS001", |
| | | "toolId": 50, |
| | | "toolCode": "TOOL001" |
| | | } |
| | | ] |
| | | } |
| | | ``` |
| | | |
| | | ### 2.2 æ¹æ¬¡åå追溯 |
| | | |
| | | **è¯·æ±æ¹å¼**ï¼GET |
| | | |
| | | **请æ±è·¯å¾**ï¼`/mes/wm/batch/backward-list` |
| | | |
| | | **请æ±åæ°**ï¼ |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | code | String | æ¯ | æ¹æ¬¡ç¼ç | |
| | | |
| | | **ååºç¤ºä¾**ï¼ååå追溯 |
| | | |
| | | --- |
| | | |
| | | ## ä¸ãå端å®ç°è¦ç¹ |
| | | |
| | | ### 3.1 æ°æ®è·åæ¶æº |
| | | |
| | | ç¨æ·ç¹å»"åå追溯"æ"åå追溯"æé®æ¶ï¼è°ç¨å¯¹åºæ¥å£è·åè¿½æº¯ç»æã |
| | | |
| | | ### 3.2 è¿½æº¯ç»æå±ç¤º |
| | | |
| | | å»ºè®®ä½¿ç¨æ¶é´çº¿ç»ä»¶å±ç¤ºè¿½æº¯é¾è·¯ï¼ |
| | | |
| | | ```html |
| | | <!-- åå追溯ï¼åææ â æå --> |
| | | <el-timeline> |
| | | <el-timeline-item |
| | | v-for="(batch, index) in forwardList" |
| | | :key="batch.id" |
| | | :timestamp="formatDate(batch.createTime)" |
| | | placement="top" |
| | | > |
| | | <el-card shadow="hover"> |
| | | <h4>æ¹æ¬¡ï¼{{ batch.code }}</h4> |
| | | <p>ç©æï¼{{ batch.itemName }} ({{ batch.itemCode }})</p> |
| | | <p v-if="batch.workOrderCode">å·¥åï¼{{ batch.workOrderCode }}</p> |
| | | <p v-if="batch.taskCode">ä»»å¡ï¼{{ batch.taskCode }}</p> |
| | | <p v-if="batch.vendorName">ä¾åºåï¼{{ batch.vendorName }}</p> |
| | | <p v-if="batch.clientName">客æ·ï¼{{ batch.clientName }}</p> |
| | | </el-card> |
| | | </el-timeline-item> |
| | | </el-timeline> |
| | | |
| | | <!-- ååè¿½æº¯ï¼æå â åææ --> |
| | | <el-timeline> |
| | | <el-timeline-item |
| | | v-for="(batch, index) in backwardList" |
| | | :key="batch.id" |
| | | :timestamp="formatDate(batch.createTime)" |
| | | placement="top" |
| | | > |
| | | <el-card shadow="hover"> |
| | | <h4>æ¹æ¬¡ï¼{{ batch.code }}</h4> |
| | | <p>ç©æï¼{{ batch.itemName }} ({{ batch.itemCode }})</p> |
| | | <p v-if="batch.workOrderCode">å·¥åï¼{{ batch.workOrderCode }}</p> |
| | | <p v-if="batch.taskCode">ä»»å¡ï¼{{ batch.taskCode }}</p> |
| | | <p v-if="batch.vendorName">ä¾åºåï¼{{ batch.vendorName }}</p> |
| | | </el-card> |
| | | </el-timeline-item> |
| | | </el-timeline> |
| | | ``` |
| | | |
| | | ### 3.3 æ æ°æ®æç¤º |
| | | |
| | | å½è¿½æº¯ç»æä¸ºç©ºæ¶ï¼æ¾ç¤ºå好æç¤ºï¼ |
| | | |
| | | ```html |
| | | <el-empty v-if="!loading && traceList.length === 0" description="ææ è¿½æº¯æ°æ®"> |
| | | <template #image> |
| | | <svg viewBox="0 0 1024 1024" width="128"> |
| | | <path d="M512 128c-199.8 0-360 160.2-360 360s160.2 360 360 360 360-160.2 360-360S711.8 128 512 128zm0 128c119.8 0 216 96.2 216 216s-96.2 216-216 216-216-96.2-216-216 96.2-216 216-216zm0 128c-52.9 0-96 43.1-96 96s43.1 96 96 96 96-43.1 96-96-43.1-96-96-96z" fill="#d9d9d9"/> |
| | | </svg> |
| | | </template> |
| | | </el-empty> |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## åãä¸å¡æµç¨å¾ |
| | | |
| | | ### 4.1 æ¹æ¬¡åå追溯æµç¨ |
| | | |
| | | ``` |
| | | âââââââââââââââ |
| | | â æ¹æ¬¡å表页 â |
| | | ââââââââ¬âââââââ |
| | | â ç¹å»"åå追溯" |
| | | â¼ |
| | | âââââââââââââââââââââââââââââââââââââââ |
| | | â è°ç¨ GET /mes/wm/batch/forward-list â |
| | | â åæ°: code = å½åæ¹æ¬¡ç¼ç â |
| | | ââââââââââââââââââââ¬âââââââââââââââââââ |
| | | â |
| | | â¼ |
| | | âââââââââââââââââââââââââââââââââââââââ |
| | | â è¿åè¯¥æ¹æ¬¡äº§åºçææä¸æ¸¸æ¹æ¬¡å表 â |
| | | â â |
| | | â 追溯路å¾ï¼ â |
| | | â åºåäºå¡(æ¶è) â æ¶èå â æ¥å·¥è®°å½ â |
| | | â â åºåäºå¡(产åº) â 䏿¸¸æ¹æ¬¡ â |
| | | ââââââââââââââââââââ¬âââââââââââââââââââ |
| | | â |
| | | â¼ |
| | | âââââââââââââââââââââââââââââââââââââââ |
| | | â 以æ¶é´çº¿å½¢å¼å±ç¤ºè¿½æº¯ç»æ â |
| | | â å¯ç¹å»ä»»ä¸æ¡ç®è·³è½¬å°å¯¹åºæ¹æ¬¡è¯¦æ
â |
| | | âââââââââââââââââââââââââââââââââââââââ |
| | | ``` |
| | | |
| | | ### 4.2 æ¹æ¬¡åå追溯æµç¨ |
| | | |
| | | ``` |
| | | âââââââââââââââ |
| | | â æ¹æ¬¡å表页 â |
| | | ââââââââ¬âââââââ |
| | | â ç¹å»"åå追溯" |
| | | â¼ |
| | | âââââââââââââââââââââââââââââââââââââââ |
| | | â è°ç¨ GET /mes/wm/batch/backward-listâ |
| | | â åæ°: code = å½åæ¹æ¬¡ç¼ç â |
| | | ââââââââââââââââââââ¬âââââââââââââââââââ |
| | | â |
| | | â¼ |
| | | âââââââââââââââââââââââââââââââââââââââ |
| | | â è¿åçäº§è¯¥æ¹æ¬¡ææ¶èçææä¸æ¸¸æ¹æ¬¡ â |
| | | â â |
| | | â 追溯路å¾ï¼ â |
| | | â åºåäºå¡(产åº) â 产åºå â æ¥å·¥è®°å½ â |
| | | â â åºåäºå¡(æ¶è) â 䏿¸¸æ¹æ¬¡ â |
| | | ââââââââââââââââââââ¬âââââââââââââââââââ |
| | | â |
| | | â¼ |
| | | âââââââââââââââââââââââââââââââââââââââ |
| | | â 以æ¶é´çº¿å½¢å¼å±ç¤ºè¿½æº¯ç»æ â |
| | | â å¯ç¹å»ä»»ä¸æ¡ç®è·³è½¬å°å¯¹åºæ¹æ¬¡è¯¦æ
â |
| | | âââââââââââââââââââââââââââââââââââââââ |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## äºã注æäºé¡¹ |
| | | |
| | | ### 5.1 æ°æ®å®æ´æ§ |
| | | |
| | | - 追溯åè½ä¾èµ `mes_wm_transaction` åºåäºå¡è¡¨çæ°æ®å®æ´æ§ |
| | | - ç¡®ä¿æææ¶èåäº§åºæä½é½æ£ç¡®çæäºåºåäºå¡è®°å½ |
| | | - `biz_type` åæ®µå¼ï¼`123` = ç©ææ¶èï¼`124` = 产åäº§åº |
| | | |
| | | ### 5.2 æ§è½èè |
| | | |
| | | - æ¹æ¬¡è¿½æº¯éç¨é彿¥è¯¢ï¼æå¤§æ·±åº¦éå¶ä¸º 20 å± |
| | | - 对äºå¤æçäº§åºæ¯ï¼å¯è½è¿å大鿰æ®ï¼å»ºè®®å页å±ç¤ºæéå¶å±ç¤ºæ°é |
| | | |
| | | ### 5.3 æéæ§å¶ |
| | | |
| | | - 追溯æ¥è¯¢éè¦ `mes:wm-batch:query` æé |
| | | - å¦éç¼è¾è¿½æº¯ç¸å
³æ°æ®ï¼éç¸åºæ¨¡åçç¼è¾æé |
| | | |
| | | --- |
| | | |
| | | ## å
ãç¸å
³æ¥å£æ±æ» |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /mes/wm/batch/get | è·åæ¹æ¬¡è¯¦æ
| |
| | | | GET | /mes/wm/batch/page | è·åæ¹æ¬¡å页å表 | |
| | | | GET | /mes/wm/batch/forward-list | æ¹æ¬¡åå追溯 | |
| | | | GET | /mes/wm/batch/backward-list | æ¹æ¬¡åå追溯 | |
| | | |
| | | --- |
| | | |
| | | ## ä¸ãæ°æ®åºåæ´è¯´æ |
| | | |
| | | ### 7.1 æ°å¢å段 |
| | | |
| | | 以ä¸è¡¨å·²æ·»å `feedback_id` åæ®µç¨äºç²¾ç¡®å
³èï¼ |
| | | |
| | | | 表å | æ°å¢å段 | 说æ | |
| | | |------|----------|------| |
| | | | mes_wm_item_consume | feedback_id | å
³èæ¥å·¥è®°å½ç¼å· | |
| | | | mes_wm_product_produce | feedback_id | å
³èæ¥å·¥è®°å½ ID | |
| | | |
| | | ### 7.2 ç´¢å¼ä¼å |
| | | |
| | | ```sql |
| | | CREATE INDEX idx_item_consume_feedback_id ON mes_wm_item_consume(feedback_id); |
| | | CREATE INDEX idx_product_produce_feedback_id ON mes_wm_product_produce(feedback_id); |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## å
«ãæ´æ°æ¥å¿ |
| | | |
| | | | æ¥æ | çæ¬ | 说æ | |
| | | |------|------|------| |
| | | | 2026-07-13 | v1.0 | åå§çæ¬ï¼å®ææ¹æ¬¡è¿½æº¯åè½ä¿®å¤ | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # CRM è·è¿è®°å½æ¥å£ - å端修æ¹è¯´æ |
| | | |
| | | ## é®é¢æè¿° |
| | | |
| | | è°ç¨ `/admin-api/crm/follow-up-record/create` æ¥å£æ¶åºç° JSON è§£æéè¯¯ï¼ |
| | | |
| | | ``` |
| | | Cannot deserialize value of type `java.util.ArrayList<java.lang.String>` from String value |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## åå åæ |
| | | |
| | | åç«¯åæ®µ `picUrls` å `fileUrls` å®ä¹ä¸º `List<String>` ç±»åï¼æææ¥æ¶æ°ç»æ ¼å¼çæ°æ®ï¼ä½åç«¯ä¼ éçæ¯åç¬¦ä¸²æ ¼å¼ã |
| | | |
| | | ### å½åå端åéçæ°æ®ï¼éè¯¯ï¼ |
| | | |
| | | ```json |
| | | { |
| | | "bizId": 2, |
| | | "bizType": 1, |
| | | "type": 2, |
| | | "nextTime": "1783924981689", |
| | | "content": "4123123", |
| | | "picUrls": "http://127.0.0.1:48080/admin-api/infra/file/29/get/xxx.png", |
| | | "fileUrls": "http://127.0.0.1:48080/admin-api/infra/file/29/get/xxx.png" |
| | | } |
| | | ``` |
| | | |
| | | ### å端ææçæ°æ®ï¼æ£ç¡®ï¼ |
| | | |
| | | ```json |
| | | { |
| | | "bizId": 2, |
| | | "bizType": 1, |
| | | "type": 2, |
| | | "nextTime": "1783924981689", |
| | | "content": "4123123", |
| | | "picUrls": ["http://127.0.0.1:48080/admin-api/infra/file/29/get/xxx.png"], |
| | | "fileUrls": ["http://127.0.0.1:48080/admin-api/infra/file/29/get/xxx.png"] |
| | | } |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## ä¿®æ¹æ¹æ¡ |
| | | |
| | | ### æ¶åé¡µé¢ |
| | | |
| | | | é¡µé¢ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | åæºè¯¦æ
| `/crm/business/detail` | æ·»å è·è¿è®°å½ | |
| | | | 客æ·è¯¦æ
| `/crm/customer/detail` | æ·»å è·è¿è®°å½ | |
| | | | åå详æ
| `/crm/contract/detail` | æ·»å è·è¿è®°å½ | |
| | | |
| | | ### ä¿®æ¹ç¹ |
| | | |
| | | #### 1. API è°ç¨åæ°å¤ç |
| | | |
| | | å¨è°ç¨å建è·è¿è®°å½æ¥å£åï¼å° URL å符串转为æ°ç»ï¼ |
| | | |
| | | ```javascript |
| | | // æä»¶è·¯å¾ï¼src/api/crm/followUpRecord.js |
| | | |
| | | import request from '@/utils/request' |
| | | |
| | | /** |
| | | * å建è·è¿è®°å½ |
| | | */ |
| | | export function createFollowUpRecord(data) { |
| | | // å¤ç picUrls å fileUrlsï¼ç¡®ä¿æ¯æ°ç»æ ¼å¼ |
| | | const processedData = { |
| | | ...data, |
| | | picUrls: Array.isArray(data.picUrls) ? data.picUrls : (data.picUrls ? [data.picUrls] : []), |
| | | fileUrls: Array.isArray(data.fileUrls) ? data.fileUrls : (data.fileUrls ? [data.fileUrls] : []) |
| | | } |
| | | |
| | | return request({ |
| | | url: '/crm/follow-up-record/create', |
| | | method: 'post', |
| | | data: processedData |
| | | }) |
| | | } |
| | | ``` |
| | | |
| | | #### 2. 表åæäº¤æ°æ®å¤ç |
| | | |
| | | å¨æäº¤è¡¨åæ¶ï¼ç¡®ä¿æ°æ®æ ¼å¼æ£ç¡®ï¼ |
| | | |
| | | ```javascript |
| | | // 示ä¾ï¼åæºè¯¦æ
页添å è·è¿è®°å½ |
| | | methods: { |
| | | async submitFollowUp() { |
| | | const formData = { |
| | | bizId: this.businessId, |
| | | bizType: 1, |
| | | type: this.form.type, |
| | | nextTime: this.form.nextTime, |
| | | content: this.form.content, |
| | | // ç¡®ä¿ picUrls å fileUrls æ¯æ°ç» |
| | | picUrls: this.form.picUrls || [], |
| | | fileUrls: this.form.fileUrls || [] |
| | | } |
| | | |
| | | await createFollowUpRecord(formData) |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | #### 3. å¾ç/éä»¶ä¸ä¼ åçæ°æ®å¤ç |
| | | |
| | | ä¸ä¼ æååï¼ç´æ¥åå¨ä¸ºæ°ç»æ ¼å¼ï¼ |
| | | |
| | | ```javascript |
| | | // ä¸ä¼ å¾çæåå |
| | | handleUploadSuccess(response) { |
| | | if (!this.form.picUrls) { |
| | | this.form.picUrls = [] |
| | | } |
| | | this.form.picUrls.push(response.url) |
| | | } |
| | | |
| | | // å é¤å¾çæ¶ |
| | | handleRemoveImage(index) { |
| | | this.form.picUrls.splice(index, 1) |
| | | } |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## 宿´ç¤ºä¾ |
| | | |
| | | ### æ°å¢è·è¿è®°å½å¼¹çªç»ä»¶ |
| | | |
| | | ```vue |
| | | <template> |
| | | <el-dialog v-model="visible" title="æ·»å è·è¿è®°å½" width="600px"> |
| | | <el-form ref="formRef" :model="form" :rules="rules" label-width="100px"> |
| | | <el-form-item label="è·è¿ç±»å" prop="type"> |
| | | <el-select v-model="form.type" placeholder="è¯·éæ©è·è¿ç±»å"> |
| | | <el-option label="çµè¯è·è¿" :value="1" /> |
| | | <el-option label="æè®¿è·è¿" :value="2" /> |
| | | <el-option label="微信è·è¿" :value="3" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="è·è¿å
容" prop="content"> |
| | | <el-input v-model="form.content" type="textarea" :rows="3" placeholder="请è¾å
¥è·è¿å
容" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="å¾ç"> |
| | | <el-upload |
| | | :action="uploadUrl" |
| | | :on-success="handlePicSuccess" |
| | | :on-remove="handlePicRemove" |
| | | :file-list="picFileList" |
| | | list-type="picture-card" |
| | | > |
| | | <el-icon><Plus /></el-icon> |
| | | </el-upload> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="éä»¶"> |
| | | <el-upload |
| | | :action="uploadUrl" |
| | | :on-success="handleFileSuccess" |
| | | :on-remove="handleFileRemove" |
| | | :file-list="fileFileList" |
| | | > |
| | | <el-button>ä¸ä¼ éä»¶</el-button> |
| | | </el-upload> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="䏿¬¡èç³»" prop="nextTime"> |
| | | <el-date-picker v-model="form.nextTime" type="datetime" placeholder="鿩䏿¬¡èç³»æ¶é´" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <template #footer> |
| | | <el-button @click="visible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive } from 'vue' |
| | | import { createFollowUpRecord } from '@/api/crm/followUpRecord' |
| | | |
| | | const visible = ref(false) |
| | | const formRef = ref() |
| | | |
| | | const form = reactive({ |
| | | type: null, |
| | | content: '', |
| | | nextTime: null, |
| | | picUrls: [], // ç¡®ä¿åå§å为æ°ç» |
| | | fileUrls: [] // ç¡®ä¿åå§å为æ°ç» |
| | | }) |
| | | |
| | | const rules = { |
| | | type: [{ required: true, message: 'è¯·éæ©è·è¿ç±»å', trigger: 'change' }], |
| | | content: [{ required: true, message: '请è¾å
¥è·è¿å
容', trigger: 'blur' }], |
| | | nextTime: [{ required: true, message: 'è¯·éæ©ä¸æ¬¡èç³»æ¶é´', trigger: 'change' }] |
| | | } |
| | | |
| | | const picFileList = ref([]) |
| | | const fileFileList = ref([]) |
| | | |
| | | // å¾çä¸ä¼ æå |
| | | const handlePicSuccess = (response) => { |
| | | if (!form.picUrls) form.picUrls = [] |
| | | form.picUrls.push(response.url) |
| | | picFileList.value.push({ name: response.name, url: response.url }) |
| | | } |
| | | |
| | | // å¾çç§»é¤ |
| | | const handlePicRemove = (file) => { |
| | | const index = picFileList.value.indexOf(file) |
| | | if (index > -1) { |
| | | picFileList.value.splice(index, 1) |
| | | form.picUrls.splice(index, 1) |
| | | } |
| | | } |
| | | |
| | | // éä»¶ä¸ä¼ æå |
| | | const handleFileSuccess = (response) => { |
| | | if (!form.fileUrls) form.fileUrls = [] |
| | | form.fileUrls.push(response.url) |
| | | fileFileList.value.push({ name: response.name, url: response.url }) |
| | | } |
| | | |
| | | // éä»¶ç§»é¤ |
| | | const handleFileRemove = (file) => { |
| | | const index = fileFileList.value.indexOf(file) |
| | | if (index > -1) { |
| | | fileFileList.value.splice(index, 1) |
| | | form.fileUrls.splice(index, 1) |
| | | } |
| | | } |
| | | |
| | | // æäº¤è¡¨å |
| | | const submitForm = async () => { |
| | | await formRef.value.validate() |
| | | await createFollowUpRecord({ |
| | | bizId: props.bizId, |
| | | bizType: props.bizType, |
| | | ...form |
| | | }) |
| | | ElMessage.success('æ·»å æå') |
| | | visible.value = false |
| | | } |
| | | |
| | | // æå¼å¼¹çª |
| | | const open = (bizId, bizType) => { |
| | | visible.value = true |
| | | form.bizId = bizId |
| | | form.bizType = bizType |
| | | form.picUrls = [] |
| | | form.fileUrls = [] |
| | | picFileList.value = [] |
| | | fileFileList.value = [] |
| | | } |
| | | |
| | | defineExpose({ open }) |
| | | </script> |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | 1. **åå§å为空æ°ç»**ï¼`picUrls` å `fileUrls` åæ®µå¨ `data` ä¸åå§å为空æ°ç» `[]`ï¼è䏿¯ç©ºå符串 `''` |
| | | |
| | | 2. **ä¸ä¼ å追å å°æ°ç»**ï¼å¾ç/éä»¶ä¸ä¼ æååï¼ä½¿ç¨ `push()` æ¹æ³è¿½å å°æ°ç»ä¸ |
| | | |
| | | 3. **å 餿¶ä»æ°ç»ç§»é¤**ï¼å é¤å¾ç/éä»¶æ¶ï¼ä½¿ç¨ `splice()` æ¹æ³ä»æ°ç»ä¸ç§»é¤å¯¹åºé¡¹ |
| | | |
| | | 4. **æäº¤åæ£æ¥æ ¼å¼**ï¼ç¡®ä¿ä¼ éç»æ¥å£çæ°æ®ä¸ï¼`picUrls` å `fileUrls` å§ç»æ¯æ°ç»æ ¼å¼ |
| | | |
| | | --- |
| | | |
| | | ## æµè¯éªè¯ |
| | | |
| | | ä¿®æ¹å®æåï¼è¯·è¿è¡ä»¥ä¸æµè¯ï¼ |
| | | |
| | | 1. ä¸ä¸ä¼ å¾çåéä»¶ï¼ç´æ¥æäº¤ â åºæå |
| | | 2. ä¸ä¼ ä¸å¼ å¾çï¼æäº¤ â åºæå |
| | | 3. ä¸ä¼ å¤å¼ å¾çï¼æäº¤ â åºæå |
| | | 4. ä¸ä¼ å¾çåå é¤ï¼åæäº¤ â åºæå |
| | | |
| | | --- |
| | | |
| | | ## ç¸å
³æ¥å£ |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | POST | /admin-api/crm/follow-up-record/create | å建è·è¿è®°å½ | |
| | | | PUT | /admin-api/crm/follow-up-record/update | æ´æ°è·è¿è®°å½ | |
| | | | DELETE | /admin-api/crm/follow-up-record/delete | å é¤è·è¿è®°å½ | |
| | | | GET | /admin-api/crm/follow-up-record/page | å页æ¥è¯¢è·è¿è®°å½ | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # ç产æ¥å·¥è¿½æº¯æ¹æ¡ |
| | | |
| | | ## ä¸ãè¿½æº¯ç®æ |
| | | |
| | | | æ¹å | é¾è·¯ | |
| | | |------|------| |
| | | | **æ£å**ï¼è®¢å -> 产åºï¼| é宿¥æº -> å·¥å -> ä»»å¡ -> æ¥å·¥ -> 产åº/æ¶è/è´¨æ£ -> åºåäºå¡ -> æ¹æ¬¡åºå | |
| | | | **åå**ï¼äº§åº -> 订åï¼| åºåäºå¡/æ¹æ¬¡ -> 产åº/æ¶èå -> æ¥å·¥ -> ä»»å¡ -> å·¥å -> 客æ·/æ¥æº | |
| | | | **横å**ï¼æç©æ/æ¹æ¬¡ï¼| ç©æ/æ¹æ¬¡ -> ææè¿åºäºå¡ -> ç¸å
³æ¥å·¥/å·¥å | |
| | | |
| | | ## äºãç°æè¿½æº¯èµäº§ï¼é¾è·¯å·²éçé¨åï¼ |
| | | |
| | | ç°æç ID é¾å·²ç»ææä¸å¼ 追溯ç½ï¼**æ£å¸¸æµç¨ä¸è¿½æº¯æ¯å®æ´ç**ï¼ |
| | | |
| | | ``` |
| | | mes_pro_work_order (å·¥å) |
| | | ââ> mes_pro_task (ä»»å¡, work_order_id) [å¾
æ¥å·¥å°è´¦å
¥å£] |
| | | ââ> mes_pro_feedback (æ¥å·¥, task_id + work_order_id) â åç»å®ï¼å·¥åä¾§å
åº |
| | | ââ> mes_wm_product_produce / _line (产åº, feedback_id) |
| | | â ââ> mes_wm_transaction (IN, biz_type=WM_PRODUCT_PRODUCE, biz_id=produce.id) |
| | | â ââ> mes_qc_ipqc (source_doc_id=feedback_id, source_line_id=produce_line_id) |
| | | â ââ> mes_qc_defect_record (qc_id) |
| | | ââ> mes_wm_item_consume / _line / _detail (æ¶è, feedback_id) |
| | | ââ> mes_wm_transaction (OUT, biz_type=WM_ITEM_CONSUME, biz_id=consume.id) |
| | | ``` |
| | | |
| | | å
³é®ç¹ï¼ |
| | | |
| | | - `mes_wm_transaction` è®°å½**æ¯ä¸ç¬**åºåè¿åºï¼æ£æ OUT / å
¥åº INï¼ï¼å¸¦ `biz_type` + `biz_id` + `biz_line_id` + `batch_id` + `transaction_time` + `related_transaction_id`ãè¿æ¯æç»ç²åº¦çæµæ°´ï¼æ¹æ¬¡/ç©æçº§è¿½æº¯é å®ã |
| | | - feedback **åæ¶å `task_id` å `work_order_id`**ï¼ä»»ä¸é¾è·¯åºé®é¢é½è½ä»å¦ä¸ä¾§ç»åã |
| | | - å·²å®¡æ¹ feedback ä¸å¯å ï¼ä»
è稿å¯å ï¼ï¼å·²ååæ°éç审计ç迹ä¿çã |
| | | - `BaseDO` ä½¿ç¨ `@TableLogic` 软å é¤ï¼`deleteById` å®ä¸ºè½¯å ï¼`deleted=1`ï¼ï¼æ°æ®è¡ä¿çï¼åè¯æ¶å¯ç»è¿è¿æ»¤æ¥è¯¢ã |
| | | |
| | | ## ä¸ãé£é©ç¹ä¸å¯¹åºæ¹æ¡ |
| | | |
| | | ### é£é©1ï¼å ä»»å¡å¯¼è´è½¯å å¼ç¨ï¼UX 追溯æé¾ï¼â æå®é
|
| | | |
| | | - **ç°ç¶**ï¼`MesProTaskServiceImpl.deleteTask` åªæ ¡éªä»»å¡éç»æï¼ä¸æ¥æ¥å·¥ãæ¥å·¥åå䏿¹ä»»å¡ç¶æï¼æ
已被æ¥å·¥çä»»å¡ä»æ¯ PREPAREãå¯å ã软å å `feedback.task_id` æå `deleted=1` çä»»å¡ï¼æ£å¸¸æ¥è¯¢çä¸å°ï¼ç¹å»è¿½æº¯æã |
| | | - **æ¹æ¡**ï¼`deleteTask` å æ ¡éªââææ¥å·¥è®°å½çä»»å¡ç¦æ¢å é¤ã |
| | | ```java |
| | | // feedbackMapper æ task_id æ¥æ°é > 0 åæ PRO_TASK_HAS_FEEDBACK |
| | | ``` |
| | | - **ææ¬**ï¼æå°ï¼ä¸ä¸ª count + ä¸ä¸ªé误ç ï¼ã**建议ç«å³åã** |
| | | |
| | | ### é£é©2ï¼taskId å¼±ç»å®ï¼æ DB å¤é®ï¼DO 注é `TODO å¾
å
³è`ï¼ |
| | | |
| | | - **ç°ç¶**ï¼é `validateFeedbackData` ä¸å¡æ ¡éªä¿è¯ task ä¸å·¥å/å·¥ä½/路线/å·¥åº/ç©æä¸è´ï¼DB 屿 FKãå½åæ°æ® 0 æ¡ null task_idã |
| | | - **æ¹æ¡**ï¼ |
| | | - **ä¸å 硬 FK**ï¼è½¯å é¤ + 跨模åä¼å²çªï¼yudao ä½ç³»æ¯ä¾ä¸ç¨ FKï¼ã |
| | | - ç» `mes_pro_feedback.task_id`ã`work_order_id` **å æ®éç´¢å¼**ï¼æå追溯æ¥è¯¢æ§è½ã |
| | | - feedback 详æ
æ¥è¯¢æ¶ç¡®ä¿è½å¸¦åº task åºæ¬ä¿¡æ¯ï¼å³ä½¿ä»»å¡è¢«è½¯å ä¹æç¤º"ä»»å¡å·²å é¤"è鿥éï¼ã |
| | | - **ææ¬**ï¼å°ã**建议ç«å³åï¼å ç´¢å¼ï¼ã** |
| | | |
| | | ### é£é©3ï¼å°è´¦çä¸å°å¨éæ¥å·¥ï¼ç²åºï¼éæé¾ï¼ |
| | | |
| | | - **ç°ç¶**ï¼å°è´¦ç¨ `task.produced_quantity`ï¼åªå«å·²å®¡æ¹ status=4ï¼ãè稿/审æ¹ä¸/å¾
æ£éªæ¥å·¥æªååï¼å°è´¦"å¾
æ¥å·¥æ°é"å大ï¼ä¸å®é
å¨éä¸ç¬¦ã |
| | | - **æ¹æ¡**ï¼ä»»å¡/å°è´¦å¢å å¨éæ¥å·¥éåæ®µï¼å£å¾æç¡®ï¼ |
| | | - `approvedQuantity` = 该任å¡ä¸ status=4 ç feedbackQuantity ä¹åï¼= producedQuantityï¼åä½å±ç¤ºï¼ |
| | | - `inTransitQuantity` = 该任å¡ä¸ status IN (0,2,3) ç feedbackQuantity ä¹å |
| | | - `pendingQuantity` = æäº§æ°é â approvedQuantityï¼å°è´¦å£å¾ä¸åï¼"å¾
æ¥å·¥"æå°æªæ¥ï¼ |
| | | - `reportableQuantity` = æäº§ â approved â inTransitï¼è¿å¯æ¥çéï¼ |
| | | - **ææ¬**ï¼ä¸ï¼ä¸ä¸ªèåæ¥è¯¢ï¼ã**å»ºè®®ä¸æåã** |
| | | |
| | | ### é£é©4ï¼æ æ¥å·¥å²é/æ¤éï¼çº é缺å£ï¼â æå¤§ç¼ºå£ |
| | | |
| | | - **ç°ç¶**ï¼æ¥å·¥å®¡æ¹åä¸å¯æ¤éãæ ååå²éåã`feedbackQuantity` æ ¡éª >0 ä¸å
è®¸è´æ°ãæ°éå¡«éåªè½æ¹ DBã |
| | | - **æ¹æ¡**ï¼æ°å¢**æ¥å·¥å²éæµç¨**ï¼ |
| | | - feedback 表å `source_feedback_id`ï¼å²éå
³è忥工ï¼+ ç¶æå `REVERSED(å·²å²é)` |
| | | - å²éæ¶åå»ºä¸æ¡å²é feedbackï¼æ°é为æ£ï¼ä½æ 记为å²éç±»åï¼ï¼çæ**åååºåäºå¡**ï¼`related_transaction_id` é
对åäºå¡ï¼ï¼ä»»å¡/工忰é**åååå**ï¼åï¼ |
| | | - å feedback ä¿çï¼å®¡è®¡ç迹ï¼ï¼ç¶æç½® `REVERSED` |
| | | - æéç¬ç«ï¼`mes:pro-feedback:reverse`ï¼ |
| | | - **ææ¬**ï¼å¤§ï¼æ°æµç¨ãååäºå¡ãç¶ææºï¼ã**å»ºè®®äºæã** |
| | | |
| | | ### é£é©5ï¼producedQuantity æ åæ´åå² |
| | | |
| | | - **ç°ç¶**ï¼`setSql increment` ç´¯å ï¼æ ç¬ç«æµæ°´ãè¦è¿åææ¶å»å¼å¾æ feedback å®¡æ¹æ¶é´ç´¯å ã |
| | | - **æ¹æ¡**ï¼ |
| | | - **Aï¼æ¨èï¼è½»éï¼**ï¼ä¸å»ºè¡¨ï¼é feedback è®°å½é建ï¼feedback æ¬èº«å°±æ¯æµæ°´ï¼æ `update_time` æåºç´¯å å³å¯è¿åï¼ãå¨ä»»å¡è¯¦æ
å "æ¥å·¥åå²"tab å±ç¤ºã |
| | | - Bï¼éï¼ï¼æ°å»º `mes_pro_task_progress_log` æ¯æ¬¡ååè®°ä¸æ¡ãæ´ä¸¥è°¨ä½ç»´æ¤ææ¬é«ã |
| | | - **ææ¬**ï¼A å°ã**å»ºè®®ä¸æåï¼å æ¥å·¥åå² tabï¼ã** |
| | | |
| | | ## åãåæå®æ½å»ºè®® |
| | | |
| | | | æ | å
容 | ææ¬ | æ¶ç | |
| | | |----|------|------|------| |
| | | | **ä¸æÂ·å µæ¼** | é£é©1 å 任塿 ¡éª + é£é©2 å ç´¢å¼ + é£é©3 å¨éæ¥å·¥é + é£é©5 æ¥å·¥åå² tab | å°ï½ä¸ | å µä½æé¾ãè¡¥é½ç²åºï¼è¿½æº¯åºæ¬å®æ´ | |
| | | | **äºæÂ·çº é** | é£é©4 æ¥å·¥å²éæµç¨ | 大 | éç¯çº éï¼å®¡è®¡å®æ´ | |
| | | | **ä¸æÂ·å¢å¼º**ï¼å¯éï¼ | æ¹æ¬¡çº§æ£åå追溯æ¥å£ï¼ä»»å¡è¿åº¦æµæ°´è¡¨ï¼B æ¹æ¡ï¼ | ä¸ | ç²¾ç»è¿½æº¯ | |
| | | |
| | | ## äºãæ¨èç追溯æ¥è¯¢æ¥å£ï¼ä¸æå¯é¡ºæå ï¼ |
| | | |
| | | | æ¥å£ | å
¥å | è¿å | ç¨é | |
| | | |------|------|------|------| |
| | | | `GET /mes/pro/feedback/trace/{id}` | æ¥å·¥ ID | æ¥å·¥ + 产åº/æ¶è/è´¨æ£ å
¨é¾ | ææ¥å·¥å追溯 | |
| | | | `GET /mes/pro/task/feedback-list?taskId=` | ä»»å¡ ID | è¯¥ä»»å¡æææ¥å·¥ï¼å«å¨éï¼ | ä»»å¡ -> æ¥å·¥æç» | |
| | | | `GET /mes/wm/transaction/trace-by-item?itemId=&batchId=` | ç©æ/æ¹æ¬¡ | ç¸å
³äºå¡ + æ¥æºåæ® | ç©æ/æ¹æ¬¡åå追溯 | |
| | | |
| | | å两个æ¯ä¸æå°±è¯¥æçåºæ¬è¿½æº¯è½åï¼å°è´¦ç¹è¿å»è½å±å¼æç»ï¼ï¼ç¬¬ä¸ä¸ªå¯ä¸æã |
| | | |
| | | ## å
ã䏿è½å°åç追溯è½åï¼é¢æï¼ |
| | | |
| | | åå®ä¸æåï¼ä»"å¾
æ¥å·¥å°è´¦"åºåç宿´è¿½æº¯è·¯å¾ï¼ |
| | | |
| | | ``` |
| | | å¾
æ¥å·¥å°è´¦ï¼ä»»å¡è¡ï¼æäº§/已审æ¹/å¨é/å¾
æ¥å·¥/坿¥éï¼ |
| | | â ç¹å»ä»»å¡ |
| | | â¼ |
| | | ä»»å¡è¯¦æ
+ æ¥å·¥åå² tabï¼ææ¶é´æåæææ¥å·¥ï¼å«å¨éç¶æï¼ |
| | | â ç¹å»ææ¡æ¥å·¥ |
| | | â¼ |
| | | æ¥å·¥è¿½æº¯é¡µï¼æ¥å·¥å + å
³è产åº/æ¶è/è´¨æ£ + åºåäºå¡æµæ°´ï¼ |
| | | â ç¹å»åºåäºå¡ |
| | | â¼ |
| | | æ¹æ¬¡åºåå卿ç»ï¼è¯¥æ¹æ¬¡ææè¿åºï¼ |
| | | ``` |
| | | |
| | | ä¸å é£é©1å·²å µï¼ä»»å¡ä¸ä¼è¢«è¯¯å å¯¼è´æé¾ï¼å é£é©2å ç´¢å¼ï¼å¤§è¡¨ä¸è¿½æº¯æ¥è¯¢ä¸å¡ã |
| | | |
| | | ## ä¸ãç»è®º |
| | | |
| | | - æ£å¸¸æµç¨ä¸ï¼ç°æ ID é¾å·²ææå®æ´è¿½æº¯ç½ï¼**追溯æ¬èº«æ¯éç**ã |
| | | - 主è¦éæ£æ¯"å ä»»å¡ä¸æ ¡éªæ¥å·¥"é æçè½¯å æé¾ï¼**䏿ç«å³ä¿®**ã |
| | | - å°è´¦ç"å¨éæ¥å·¥"ç²åºå"æ¥å·¥åå²"æ¯ä¸æè¡¥é½çéç¹ã |
| | | - æ¥å·¥å²éæ¯æå¤§ç缺å£ï¼ä½å·¥ç¨é大ï¼å»ºè®®ä¸æç¨³å®ååä¸äºæã |
| | | |
| | | ## éï¼æ¶åæä»¶æ¸
åï¼ä¸æé¢ä¼°ï¼ |
| | | |
| | | | æ¹å¨ | æä»¶ | |
| | | |------|------| |
| | | | å 任塿 ¡éª | `MesProTaskServiceImpl.deleteTask`ã`MesProFeedbackMapper`ï¼å countByTaskIdï¼ã`ErrorCodeConstants`ï¼å PRO_TASK_HAS_FEEDBACKï¼ | |
| | | | å ç´¢å¼ | DDLï¼`mes_pro_feedback` å `idx_task_id`ã`idx_work_order_id` | |
| | | | å¨éæ¥å·¥é | `MesProTaskRespVO` å åæ®µã`MesProTaskMapper`/Service å èåæ¥è¯¢ã`buildTaskRespVOList` å¡«å
| |
| | | | æ¥å·¥åå² tab | `MesProFeedbackController` å `list-by-task` æ¥å£ã`MesProFeedbackMapper` å selectListByTaskId | |
| | | | 追溯æ¥å£ | `MesProFeedbackController` å `/trace/{id}`ï¼ç»è£
产åº/æ¶è/è´¨æ£ | |
| | | | åç«¯ææ¡£ | `docs/feedback_traceability_*` ç³»åææ¡£ | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # ç©æåç±»ç»ä¸ä½¿ç¨ mes_md_item_type - å端èè°æ¹æ¡ |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - MDM ç©æç®¡ç页é¢ï¼æ°å¢/ç¼è¾ç©æï¼ |
| | | - MES ç©æç®¡ç页é¢ï¼æ°å¢/ç¼è¾ç©æï¼ |
| | | |
| | | ## ä¸å¡æµç¨ä¸æ°æ®å¸¦å
¥ |
| | | |
| | | 1. ç©æåç±»ç»ä¸ä½¿ç¨ `mes_md_item_type` 表ï¼MDM å MES 模åå
±ç¨åä¸å¥åç±»æ°æ® |
| | | 2. ç©æç±»ååæ®µ `itemType` ç¨äºå¿«ééæ©ï¼1åæã2åæåã3æåã4è¾
æ |
| | | 3. å½éæ© `categoryId` æ¶ï¼ç´æ¥å
³èåç±» IDï¼å½åªéæ© `itemType` æ¶ï¼ç³»ç»èªå¨å¹é
对åºåç§°çåç±» |
| | | |
| | | ## API |
| | | |
| | | ### è·åç©æåç±»å表 |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /admin-api/mes/md/item-type/list | è·åç©æåç±»å表 | |
| | | |
| | | **请æ±åæ°ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | status | Integer | å¦ | ç¶æçé | |
| | | |
| | | **ååºå段ï¼** |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | id | Long | åç±»ç¼å· | |
| | | | code | String | åç±»ç¼ç | |
| | | | name | String | åç±»åç§° | |
| | | | parentId | Long | ç¶åç±»ç¼å· | |
| | | | itemOrProduct | String | ç©æ/äº§åæ è¯ | |
| | | | sort | Integer | æåº | |
| | | | status | Integer | ç¶æ | |
| | | |
| | | **ååºç¤ºä¾ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "code": 0, |
| | | "data": [ |
| | | { |
| | | "id": 1, |
| | | "code": "RAW001", |
| | | "name": "åæ", |
| | | "parentId": 0, |
| | | "itemOrProduct": "1", |
| | | "sort": 1, |
| | | "status": 0 |
| | | } |
| | | ] |
| | | } |
| | | ``` |
| | | |
| | | ### è·åç©æå类详æ
|
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /admin-api/mes/md/item-type/get | è·åç©æå类详æ
| |
| | | |
| | | **请æ±åæ°ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | id | Long | æ¯ | åç±»ç¼å· | |
| | | |
| | | ### ä¿åç©æåç±» |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | POST | /admin-api/mes/md/item-type/create | åå»ºç©æåç±» | |
| | | | PUT | /admin-api/mes/md/item-type/update | æ´æ°ç©æåç±» | |
| | | |
| | | **请æ±åæ°ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | id | Long | å¦ | åç±»ç¼å·ï¼æ´æ°æ¶å¿
å¡«ï¼ | |
| | | | code | String | æ¯ | åç±»ç¼ç | |
| | | | name | String | æ¯ | åç±»åç§° | |
| | | | parentId | Long | å¦ | ç¶åç±»ç¼å· | |
| | | | itemOrProduct | String | å¦ | ç©æ/äº§åæ è¯ | |
| | | | sort | Integer | å¦ | æåº | |
| | | | status | Integer | å¦ | ç¶æ | |
| | | |
| | | ## åæ®µå±ç¤ºè§å |
| | | |
| | | | åæ®µ | å±ç¤ºä½ç½® | 说æ | |
| | | |------|----------|------| |
| | | | categoryId | æ°å¢/ç¼è¾è¡¨å | ç©æåç±»ä¸ææ¡ï¼æ°æ®æ¥æºï¼mes_md_item_type | |
| | | | itemType | æ°å¢/ç¼è¾è¡¨å | ç©æç±»åå¿«æ·éæ©ï¼1åæã2åæåã3æåã4è¾
æ | |
| | | |
| | | ## ä¸å¡è§å说æ |
| | | |
| | | | åºæ¯ | è§å | |
| | | |------|------| |
| | | | ç©æåç±»éæ© | ä½¿ç¨ `mes_md_item_type` 表ï¼MDM å MES å
±ç¨åä¸å¥åç±»æ°æ® | |
| | | | itemType ä¸ categoryId å
³ç³» | å½ categoryId 为空æ¶ï¼å¯æ ¹æ® itemType èªå¨å¹é
对åºåç§°çåç±» | |
| | | | itemType æ å° | 1âåæï¼2âåæåï¼3âæåï¼4âè¾
æ | |
| | | | åç±»æ ¡éª | ä¿åç©ææ¶ï¼ä¼éè¿ RPC API æ ¡éªåç±»æ¯å¦åå¨ | |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - ç©æåç±»æ°æ®å¨ MES 模å管çï¼MDM 模åéè¿ RPC API è°ç¨è·å |
| | | - `itemType` æ¯å¿«æ·éæ©åæ®µï¼æç»ä¼è½¬æ¢ä¸ºå¯¹åºçåç±»ç¼ç |
| | | - å¦æåæ¶è®¾ç½®äº `categoryId` å `itemType`ï¼ä¼å
ä½¿ç¨ `categoryId` |
| | | - åç±»æ¯ææ å½¢ç»æï¼å¯éè¿ `parentId` æå»ºå±çº§å
³ç³» |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # MDM ç©æåæ¥å° MES |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - MDM ç©æç®¡ç - æ°å¢ç©æå¼¹çª |
| | | - MDM ç©æç®¡ç - ç¼è¾ç©æå¼¹çª |
| | | |
| | | ## åè½è¯´æ |
| | | |
| | | å¨ MDM ç©æãæ°å¢ / ç¼è¾ãæ¶ï¼æ°å¢ãåæ¥å° MESãå¼å
³ãå¾éåï¼MDM ç©æä¿åæåçåæ¶ï¼ä¼èªå¨å¨ MES ä¾§å建/æ´æ°ä¸æ¡å¯¹åºçç©æäº§åï¼`mes_md_item`ï¼ï¼å®ç°ä¸»æ°æ®å MES ç忥ã |
| | | |
| | | - æ°å¢ï¼createï¼ï¼å¾é忥 â MDM æ°å»º + MES æ°å»ºã |
| | | - ç¼è¾ï¼updateï¼ï¼å¾é忥 â MDM æ´æ° + MES æ´æ°ï¼MES ä¾§æç©æç¼ç code å¹é
ï¼å·²åå¨åæ´æ°ï¼ä¸åå¨åæ°å»ºï¼å³ upsertï¼ã |
| | | - ä¸å¾éæ `syncMes=false`ï¼ä»
æä½ MDMï¼ä¸å½±å MESã |
| | | |
| | | ## API |
| | | |
| | | æ¥å£è·¯å¾ä¸åï¼ä»
å¨è¯·æ±ä½æ°å¢ `syncMes` åæ®µã |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | POST | /admin-api/mdm/item/create | åå»ºç©æï¼å¯åæ¥ MESï¼ | |
| | | | PUT | /admin-api/mdm/item/update | æ´æ°ç©æï¼å¯åæ¥ MESï¼ | |
| | | |
| | | **请æ±åæ°ï¼ä»
ååºæ°å¢/ç¸å
³å段ï¼ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | syncMes | Boolean | å¦ | æ¯å¦åæ¥å° MESï¼é»è®¤ falseãå¾éæ¶è§¦å MES 忥 | |
| | | | code | String | æ¯ | ç©æç¼ç ï¼MDM/MES å
³èé®ï¼ä¸¤è¾¹é¡»ä¸è´ï¼ | |
| | | | name | String | æ¯ | ç©æåç§° | |
| | | | unitMeasureId | Long | æ¯ | MDM 计éåä½ idï¼åæ¥æ¶æ code æ å°å° MES åä½ï¼ | |
| | | | categoryId | Long | æ¯ | MDM ç©æåç±» idï¼åæ¥æ¶æ code æ å°å° MES ç©æåç±»ï¼ | |
| | | |
| | | **ååºï¼** å建è¿å `{ "code": 200, "data": <ç©æid> }`ï¼æ´æ°è¿å `{ "code": 200, "data": true }`ï¼ä¸åæ¥å£ä¸è´ï¼ã |
| | | |
| | | > 注æï¼åæ¥å¤±è´¥æ¶ï¼å¦ MES ä¾§æ¾ä¸å°å¯¹åº code çåä½/åç±»ãæ MES åç§°éå¤çï¼ï¼æ¥å£ä¼è¿åé误ï¼ä¸ **MDM çå建/æ´æ°ä¼ä¸å¹¶åæ»**ï¼åä¸äºå¡ï¼ã |
| | | |
| | | ## å端修æ¹ç¹ |
| | | |
| | | ### 1. 表åå¢å ãåæ¥å° MESãå¼å
³ |
| | | |
| | | å¨ç©ææ°å¢/ç¼è¾è¡¨åï¼`mes/pd/...` æ `mdm/item` 对åºè¡¨åç»ä»¶ï¼ä¸æ°å¢ä¸ä¸ªå¼å
³ï¼ |
| | | |
| | | ```html |
| | | <el-form-item label="åæ¥å° MES"> |
| | | <el-switch v-model="formData.syncMes" /> |
| | | </el-form-item> |
| | | ``` |
| | | |
| | | ### 2. data æ°æ® |
| | | |
| | | ```js |
| | | data() { |
| | | return { |
| | | formData: { |
| | | // ... åæå段 |
| | | syncMes: false, // æ¯å¦åæ¥å° MESï¼é»è®¤ä¸å¾é |
| | | }, |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | > ç¼è¾åæ¾æ¶ï¼`syncMes` é»è®¤ç½®ä¸º `false`ï¼ä¸åæ¥ï¼å³å¯ï¼ç±ç¨æ·æéå¾éã |
| | | |
| | | ### 3. æäº¤æ¹æ³ |
| | | |
| | | æ éæ¹å¨æäº¤é»è¾ï¼`syncMes` é表åä¸å¹¶æäº¤å³å¯ï¼ |
| | | |
| | | ```js |
| | | submitForm() { |
| | | this.$refs['form'].validate(valid => { |
| | | if (!valid) return |
| | | // formData ä¸å·²å
å« syncMesï¼æ£å¸¸è°ç¨ create / update æ¥å£ |
| | | if (this.formData.id) { |
| | | updateItem(this.formData).then(...) |
| | | } else { |
| | | createItem(this.formData).then(...) |
| | | } |
| | | }) |
| | | } |
| | | ``` |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - **ä»
create / update çæ**ï¼å é¤ãç¶æåæ´ä¸åæ¥ MESã |
| | | - **åæ¥å¤±è´¥ä¼åæ»**ï¼å¾é忥åè¥ MES ä¾§åºéï¼MDM çä¿åä¹ä¼åæ»ï¼åç«¯ä¼æ¶å°é误æç¤ºï¼éæ ¹æ®é误信æ¯å¤çï¼éå¸¸æ¯ MES 侧缺对åºåä½/åç±»ï¼ã |
| | | - **MES ç©æé»è®¤ç¦ç¨**ï¼åæ¥å建ç MES ç©æç¶æä¸ºãç¦ç¨ãï¼éå¨ MES ç©æäº§å页é¢å¦è¡å¯ç¨ã |
| | | - **åæï¼åä½/åç±»ç¼ç é¡»ä¸è´**ï¼åæ¥æ `code` æ å°ââMDM ç计éåä½ `code` å¿
é¡»å¨ MES `mes_md_unit_measure` ä¸åå¨ï¼MDM çç©æåç±» `code` å¿
é¡»å¨ MES `mes_md_item_type` ä¸åå¨ï¼ä¸ä¸ºå¶ååç±»ï¼ï¼å¦å忥æ¥éåæ»ã请确ä¿ä¸¤è¾¹ä¸»æ°æ®ç¼ç 已对é½ã |
| | | - **åæ®µæ å°**ï¼MDM `isHighValue`âMES `highValue`ï¼MDM `isBatchManaged`âMES `batchFlag`ï¼`minStock/maxStock/specification/remark` ç´ä¼ ï¼MES `safeStockFlag` åºå®ä¸º true 以ä¿çåºåä¸ä¸éã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å·¥åºãæ¯å¦åå²ãåæ®µ |
| | | |
| | | ## èæ¯ |
| | | |
| | | æ¥å·¥å®¡æ¹æ¶ï¼åå²å·¥åºæ BOM èªå¨æ£æï¼BOM ç¨é à æ¥å·¥æ°éï¼ä»çº¿è¾¹åº FIFO æ£åï¼ï¼éåå²å·¥åºä¸èªå¨æ£æï¼ç©æèµ°æå·¥é¢æ/ææã |
| | | |
| | | æ°å¢å段æå¨**å·¥èºè·¯çº¿å·¥åº**ï¼`mes_pro_route_process`ï¼ä¸ãæ¯å¦å
³é®å·¥åºããæ¯å¦è´¨æ£å·¥åºãå级ï¼ï¼ä¸æ¯å·¥åºä¸»è¡¨ã |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - å·¥èºè·¯çº¿ - å·¥åºå表/表åï¼ç»´æ¤è·¯çº¿ä¸çå·¥åºé
ç½®ï¼æ°å¢ãæ¯å¦åå²ãå¼å
³ï¼ |
| | | - ç产æ¥å·¥ - æ¥å·¥å®¡æ¹ï¼åå²å·¥åºæªé
BOM æ¶ç»åºé误æç¤ºï¼ |
| | | |
| | | ## æ°æ®åº |
| | | |
| | | ```sql |
| | | ALTER TABLE mes_pro_route_process |
| | | ADD COLUMN backflush_flag bit(1) DEFAULT b'1' COMMENT 'æ¯å¦åå²' AFTER check_flag; |
| | | ``` |
| | | |
| | | - é»è®¤ `b'1'`ï¼åå²ï¼ï¼ä¿çç°æãé
äº BOM å°±æ£æãçè¡ä¸ºã |
| | | - å岿°æ®å填为åå²=trueã |
| | | |
| | | ## API |
| | | |
| | | å·¥èºè·¯çº¿å·¥åºæ¥å£ï¼`/mes/pro/route-process`ï¼ç **create / update / get / list** 请æ±ä¸ååºåæ°å¢ `backflushFlag` åæ®µï¼å
¶ä½ä¸åã |
| | | |
| | | **æ°å¢å段ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | backflushFlag | Boolean | å¦ï¼é»è®¤ trueï¼| æ¯å¦åå²ãtrue=æ¥å·¥æ¶æ BOM èªå¨æ£æï¼false=ä¸èªå¨æ£æ | |
| | | |
| | | **请æ±ç¤ºä¾ï¼create/updateï¼ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "routeId": 1, |
| | | "processId": 10, |
| | | "sort": 1, |
| | | "keyFlag": false, |
| | | "checkFlag": false, |
| | | "backflushFlag": true |
| | | } |
| | | ``` |
| | | |
| | | **ååºç¤ºä¾ï¼get/listï¼ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "id": 1, |
| | | "routeId": 1, |
| | | "processId": 10, |
| | | "keyFlag": false, |
| | | "checkFlag": false, |
| | | "backflushFlag": true |
| | | } |
| | | ``` |
| | | |
| | | æ¥å·¥å®¡æ¹æ¥å£ `PUT /mes/pro/feedback/approve` è¡ä¸ºåæ´ï¼æ å
¥åååï¼ï¼ |
| | | |
| | | | å·¥åº backflushFlag | BOM é
ç½® | 审æ¹ç»æ | |
| | | |--------------------|----------|----------| |
| | | | trueï¼é»è®¤ï¼| æ | æ£å¸¸æ£æå
¥åº | |
| | | | true | æ | æ¥éï¼`å½åå·¥åºä¸ºåå²å·¥åºï¼ä½æªé
ç½®BOMæ¶èï¼æ æ³æ¥å·¥`ï¼é误ç 1040506013ï¼| |
| | | | false | æ | 䏿£æï¼BOM é
ç½®åå¨ä½ä¸ä½¿ç¨ï¼| |
| | | | false | æ | 䏿£æ | |
| | | |
| | | ## å端修æ¹ç¹ |
| | | |
| | | ### 1. å·¥èºè·¯çº¿ - å·¥åºè¡¨åå ãæ¯å¦åå²ãå¼å
³ |
| | | |
| | | å¨ãæ¯å¦å
³é®å·¥åºããæ¯å¦è´¨æ£å·¥åºãä¹åå ä¸ä¸ª `el-switch`ï¼ |
| | | |
| | | ```html |
| | | <el-form-item label="æ¯å¦å
³é®å·¥åº"> |
| | | <el-switch v-model="form.keyFlag" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¯å¦è´¨æ£å·¥åº"> |
| | | <el-switch v-model="form.checkFlag" /> |
| | | </el-form-item> |
| | | <!-- æ°å¢ --> |
| | | <el-form-item label="æ¯å¦åå²"> |
| | | <el-switch v-model="form.backflushFlag" /> |
| | | <span style="margin-left: 8px; color: #909399; font-size: 12px;"> |
| | | å¼å¯åæ¥å·¥æ¶æBOMèªå¨æ£æï¼å
³éåä¸èªå¨æ£æï¼èµ°æå·¥é¢æ |
| | | </span> |
| | | </el-form-item> |
| | | ``` |
| | | |
| | | ### 2. data æ°æ® |
| | | |
| | | ```js |
| | | data() { |
| | | return { |
| | | form: { |
| | | // ...åæå段 |
| | | keyFlag: false, |
| | | checkFlag: false, |
| | | backflushFlag: true, // é»è®¤åå² |
| | | }, |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ### 3. å·¥åºåè¡¨è¡¨æ ¼å±ç¤ºï¼å¯éï¼ |
| | | |
| | | ```html |
| | | <el-table-column label="æ¯å¦åå²" align="center" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.backflushFlag ? 'success' : 'info'"> |
| | | {{ scope.row.backflushFlag ? 'åå²' : 'ä¸åå²' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | ``` |
| | | |
| | | ### 4. 表åéç½®/åæ¾ |
| | | |
| | | ```js |
| | | resetForm() { |
| | | this.form = { |
| | | // ...åæå段 |
| | | keyFlag: false, |
| | | checkFlag: false, |
| | | backflushFlag: true, |
| | | } |
| | | } |
| | | handleEdit(row) { |
| | | this.form = { ...row } |
| | | // backflushFlag é row åæ¾ |
| | | } |
| | | ``` |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - åæ®µæå¨**å·¥èºè·¯çº¿å·¥åº**ï¼æ¯æ¡è·¯çº¿ä¸çå·¥åºéæ¡é
ç½®ï¼ï¼ä¸æ¯å·¥åºä¸»è¡¨ï¼ä¸ `keyFlag`/`checkFlag` å级ï¼å端å¨è·¯çº¿-å·¥åºé
置页维æ¤ã |
| | | - é»è®¤å¼ä¸ºãåå²=trueãï¼ä¸åå²è¡ä¸ºä¸è´ãåªææ¾å¼å
³éçå·¥åºæä¼è·³è¿èªå¨æ£æã |
| | | - åå²å·¥åºå¿
é¡»å¨ãå·¥èºè·¯çº¿äº§å BOMãï¼`/mes/pro/route-product-bom`ï¼éé
好该路线+å·¥åº+产åç BOM æ¶èï¼å¦åæ¥å·¥å®¡æ¹ä¼æ¥éã |
| | | - éåå²å·¥åºçç©æè¯·éè¿ä»»å¡ææï¼`/mes/pro/task-issue`ï¼æä»åºé¢æåæå·¥å¤çã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ============================================= |
| | | -- æ¹æ¬¡è¿½æº¯åè½ä¿®å¤ - DDL èæ¬ |
| | | -- æ¥æ: 2026-07-13 |
| | | -- 说æ: æ·»å feedback_id åæ®µç¨äºæ¹æ¬¡è¿½æº¯ç精确å
³è |
| | | -- ============================================= |
| | | |
| | | -- 1. mes_wm_item_consume 表添å ç¼ºå¤±åæ®µ |
| | | ALTER TABLE mes_wm_item_consume ADD COLUMN task_id bigint COMMENT 'ç产任å¡ç¼å·' AFTER work_order_id; |
| | | ALTER TABLE mes_wm_item_consume ADD COLUMN workstation_id bigint COMMENT 'å·¥ä½ç«ç¼å·' AFTER task_id; |
| | | ALTER TABLE mes_wm_item_consume ADD COLUMN process_id bigint COMMENT 'å·¥åºç¼å·' AFTER workstation_id; |
| | | ALTER TABLE mes_wm_item_consume ADD COLUMN feedback_id bigint COMMENT 'æ¥å·¥è®°å½ç¼å·' AFTER process_id; |
| | | ALTER TABLE mes_wm_item_consume ADD COLUMN consume_date datetime COMMENT 'æ¶èæ¥æ' AFTER feedback_id; |
| | | |
| | | -- 2. mes_wm_product_produce 表添å feedback_id åæ®µ |
| | | ALTER TABLE mes_wm_product_produce ADD COLUMN feedback_id bigint COMMENT 'æ¥å·¥è®°å½ ID' AFTER work_order_id; |
| | | |
| | | -- 3. 为åé¦ ID æ·»å ç´¢å¼ï¼æå追溯æ¥è¯¢æ§è½ï¼ |
| | | CREATE INDEX idx_item_consume_feedback_id ON mes_wm_item_consume(feedback_id); |
| | | CREATE INDEX idx_product_produce_feedback_id ON mes_wm_product_produce(feedback_id); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # å¾
æ¥å·¥å°è´¦ |
| | | |
| | | ## èæ¯ |
| | | |
| | | æäº§åéè¦ä¸ä¸ª"å¾
æ¥å·¥å°è´¦"ï¼å±ç¤ºå·²æäº§ä½å°æªæ¥å·¥å®çä»»å¡ï¼æ ¸å¿ææ **å¾
æ¥å·¥æ°é = æäº§æ°é â å·²æ¥å·¥æ°é**ãæ°æ®æºä¸ºç产任å¡ï¼`mes_pro_task`ï¼ï¼ä»»å¡çº§æ±æ»è§å¾ã |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - æ°å¢èå/页é¢ï¼å¾
æ¥å·¥å°è´¦ï¼ç产管çä¸ï¼ |
| | | - å¤ç¨ç产任å¡å表çå
³èå±ç¤ºï¼å·¥å/产å/å·¥åº/å·¥ä½/客æ·ï¼ |
| | | |
| | | ## API |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /mes/pro/task/pending-feedback-page | å¾
æ¥å·¥å°è´¦å页ï¼è¿è¡ä¸ä¸ä»æå¾
æ¥å·¥éçä»»å¡ï¼| |
| | | |
| | | ### 请æ±åæ°ï¼Queryï¼å¤ç¨ MesProTaskPageReqVOï¼ |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | pageNo | Integer | æ¯ | 页ç | |
| | | | pageSize | Integer | æ¯ | æ¯é¡µæ¡æ° | |
| | | | code | String | å¦ | ä»»å¡ç¼ç ï¼æ¨¡ç³ï¼| |
| | | | name | String | å¦ | ä»»å¡åç§°ï¼æ¨¡ç³ï¼| |
| | | | workOrderId | Long | å¦ | ç产工åç¼å· | |
| | | | routeId | Long | å¦ | å·¥èºè·¯çº¿ç¼å· | |
| | | | processId | Long | å¦ | å·¥åºç¼å· | |
| | | | workstationId | Long | å¦ | å·¥ä½ç«ç¼å· | |
| | | | createTime | LocalDateTime[] | å¦ | å建æ¶é´åºé´ | |
| | | |
| | | > `status`/`statuses` 忰卿¤æ¥å£è¢«å¿½ç¥ï¼åç«¯å¼ºå¶ `status=è¿è¡ä¸(0)`ï¼ä¸è¿æ»¤ `å¾
æ¥å·¥æ°é > 0`ã |
| | | |
| | | ### ååºï¼MesProTaskRespVOï¼å
³é®åæ®µï¼ |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | id | Long | ä»»å¡ç¼å· | |
| | | | code | String | ä»»å¡ç¼ç | |
| | | | name | String | ä»»å¡åç§° | |
| | | | workOrderCode / workOrderName | String | å·¥åç¼ç /åç§° | |
| | | | itemCode / itemName / itemSpecification | String | 产åç¼ç /åç§°/è§æ ¼ | |
| | | | unitMeasureName | String | 计éåä½ | |
| | | | processName | String | å·¥åºåç§° | |
| | | | workstationCode / workstationName | String | å·¥ä½ç¼ç /åç§° | |
| | | | clientName | String | 客æ·åç§° | |
| | | | quantity | BigDecimal | æäº§æ°é | |
| | | | producedQuantity | BigDecimal | å·²æ¥å·¥æ°éï¼å·²å®¡æ¹ç´¯å ï¼| |
| | | | qualifyQuantity | BigDecimal | åæ ¼åæ°é | |
| | | | unqualifyQuantity | BigDecimal | ä¸è¯åæ°é | |
| | | | **pendingQuantity** | BigDecimal | **å¾
æ¥å·¥æ°é = æäº§ â å·²æ¥å·¥** | |
| | | | **feedbackRate** | BigDecimal | **æ¥å·¥å®æç(%) = å·²æ¥å·¥ / æäº§ à 100** | |
| | | | startTime / endTime | LocalDateTime | æäº§å¼å§/ç»ææ¶é´ | |
| | | | requestDate | LocalDateTime | éæ±æ¥æ | |
| | | | status | Integer | ä»»å¡ç¶æï¼æ¤å¤æä¸º 0=è¿è¡ä¸ï¼| |
| | | |
| | | **ååºç¤ºä¾ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "code": 0, |
| | | "data": { |
| | | "list": [ |
| | | { |
| | | "id": 101, |
| | | "code": "PT202507130001", |
| | | "name": "çµè·¯æ¿ã100ã个", |
| | | "workOrderCode": "WO-001", |
| | | "itemName": "çµè·¯æ¿", |
| | | "processName": "注å¡", |
| | | "workstationName": "注å¡å·¥ä½ç«", |
| | | "quantity": 100.00, |
| | | "producedQuantity": 30.00, |
| | | "qualifyQuantity": 29.00, |
| | | "unqualifyQuantity": 1.00, |
| | | "pendingQuantity": 70.00, |
| | | "feedbackRate": 30.00, |
| | | "status": 0 |
| | | } |
| | | ], |
| | | "total": 1 |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## å端修æ¹ç¹ |
| | | |
| | | ### 1. è¡¨æ ¼å建议 |
| | | |
| | | ```html |
| | | <el-table-column label="ä»»å¡ç¼ç " prop="code" /> |
| | | <el-table-column label="å·¥åç¼ç " prop="workOrderCode" /> |
| | | <el-table-column label="产å" prop="itemName" /> |
| | | <el-table-column label="å·¥åº" prop="processName" /> |
| | | <el-table-column label="å·¥ä½" prop="workstationName" /> |
| | | <el-table-column label="æäº§æ°é" prop="quantity" /> |
| | | <el-table-column label="å·²æ¥å·¥" prop="producedQuantity" /> |
| | | <el-table-column label="åæ ¼" prop="qualifyQuantity" /> |
| | | <el-table-column label="ä¸è¯" prop="unqualifyQuantity" /> |
| | | <el-table-column label="å¾
æ¥å·¥æ°é" prop="pendingQuantity"> |
| | | <template #default="scope"> |
| | | <el-tag type="warning">{{ scope.row.pendingQuantity }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="宿ç" prop="feedbackRate"> |
| | | <template #default="scope"> |
| | | <el-progress :percentage="Number(scope.row.feedbackRate)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="éæ±æ¥æ" prop="requestDate" /> |
| | | ``` |
| | | |
| | | ### 2. æ¥è¯¢è¡¨å |
| | | |
| | | ```html |
| | | <el-form :inline="true" :model="queryParams"> |
| | | <el-form-item label="ä»»å¡ç¼ç "> |
| | | <el-input v-model="queryParams.code" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="å·¥å"> |
| | | <el-select v-model="queryParams.workOrderId" clearable><!-- å·¥å䏿 --></el-select> |
| | | </el-form-item> |
| | | <el-form-item label="å·¥åº"> |
| | | <el-select v-model="queryParams.processId" clearable><!-- å·¥åºä¸æ --></el-select> |
| | | </el-form-item> |
| | | <el-form-item label="å·¥ä½"> |
| | | <el-select v-model="queryParams.workstationId" clearable><!-- å·¥ä½ä¸æ --></el-select> |
| | | </el-form-item> |
| | | </el-form> |
| | | ``` |
| | | |
| | | ### 3. API è°ç¨ |
| | | |
| | | ```js |
| | | // api/mes/pro/task.js |
| | | export function getPendingFeedbackPage(params) { |
| | | return request({ |
| | | url: '/mes/pro/task/pending-feedback-page', |
| | | method: 'get', |
| | | params |
| | | }) |
| | | } |
| | | ``` |
| | | |
| | | ```js |
| | | // é¡µé¢ list æ¹æ³ |
| | | getList() { |
| | | this.loading = true |
| | | getPendingFeedbackPage(this.queryParams).then(res => { |
| | | this.list = res.data.list |
| | | this.total = res.data.total |
| | | }).finally(() => this.loading = false) |
| | | } |
| | | ``` |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | - å°è´¦åªæ¾ç¤º **è¿è¡ä¸ + 仿å¾
æ¥å·¥é** çä»»å¡ï¼å·²æ¥æ»¡ï¼å¾
æ¥å·¥=0ï¼æå·²å®å·¥/已忶çä»»å¡ä¸åºç°ã |
| | | - æ³ç"ææè¿è¡ä¸ä»»å¡ï¼å«å·²æ¥æ»¡æªå
³åï¼"ç¨ `/mes/pro/task/page?status=0`ã |
| | | - `producedQuantity` åªå«**已审æ¹éè¿**çæ¥å·¥ï¼è稿/审æ¹ä¸/å¾
æ£éªçæ¥å·¥æªååï¼å°è´¦çä¸å°è¿é¨åå¨éæ¥å·¥éã |
| | | - 该æ¥å£å¤ç¨ä»»å¡å页æé `mes:pro-task:query`ï¼å¦éç¬ç«æé坿°å¢æé®æéç ã |
| | |
| | | <module>yudao-module-erp-api</module> |
| | | <!-- <module>yudao-module-iot</module>--> |
| | | <module>yudao-module-mes</module> |
| | | <module>yudao-module-mes-api</module> |
| | | <module>yudao-module-im</module> |
| | | <!-- MDM ä¸»æ°æ®ç®¡ç模å --> |
| | | <module>yudao-module-mdm-api</module> |
| | |
| | | @Schema(description = "å
³èçè系人ç¼å·æ°ç»") |
| | | private List<Long> contactIds; |
| | | |
| | | @Schema(description = "å¾ç") |
| | | @Schema(description = "å¾ç URL å表") |
| | | private List<String> picUrls; |
| | | @Schema(description = "éä»¶") |
| | | @Schema(description = "éä»¶ URL å表") |
| | | private List<String> fileUrls; |
| | | |
| | | } |
| | |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- MES å¶é æ§è¡ APIï¼ç¨äºåæ¥ç©æä¸»æ°æ®å° MESï¼ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-mes-api</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-system</artifactId> |
| | |
| | | @Schema(description = "è§æ ¼åå·", example = "M8*20") |
| | | private String specification; |
| | | |
| | | @Schema(description = "ç©æåç±»ç¼å·", example = "1") |
| | | @Schema(description = "ç©æåç±»ç¼å·ï¼å
³è MES ç©æåç±» mes_md_item_typeï¼", example = "1") |
| | | private Long categoryId; |
| | | |
| | | @Schema(description = "计éåä½ç¼å·", example = "1") |
| | |
| | | @Schema(description = "夿³¨", example = "夿³¨ä¿¡æ¯") |
| | | private String remark; |
| | | |
| | | @Schema(description = "æ¯å¦åæ¥å° MES", example = "false") |
| | | private Boolean syncMes; |
| | | |
| | | } |
| | |
| | | return selectOne(MdmItemDO::getCode, code); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®ç¼ç åå é¤ç¶ææ¥è¯¢ç©æï¼ç¨äºè§£å³è½¯å é¤å¯ä¸é®å²çªï¼ |
| | | */ |
| | | default MdmItemDO selectByCodeAndDeleted(String code, Boolean deleted) { |
| | | return selectOne(new LambdaQueryWrapperX<MdmItemDO>() |
| | | .eq(MdmItemDO::getCode, code) |
| | | .eq(MdmItemDO::getDeleted, deleted)); |
| | | } |
| | | |
| | | /** |
| | | * ç©çå é¤ï¼ç¨äºæ¸
ç已软å é¤çéå¤è®°å½ï¼ |
| | | * 注æï¼ç±äº BaseDO æ @TableLogicï¼deleteById æ¯è½¯å é¤ï¼éè¦ä½¿ç¨åç SQL |
| | | */ |
| | | @org.apache.ibatis.annotations.Delete("DELETE FROM mdm_item WHERE id = #{id}") |
| | | void physicalDeleteById(Long id); |
| | | |
| | | default MdmItemDO selectByBarCode(String barCode) { |
| | | return selectOne(MdmItemDO::getBarCode, barCode); |
| | | } |
| | |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemPageReqVO; |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSaveReqVO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemMapper; |
| | | import cn.iocoder.yudao.module.mdm.service.brand.MdmBrandService; |
| | | import cn.iocoder.yudao.module.mdm.service.category.MdmItemCategoryService; |
| | | import cn.iocoder.yudao.module.mdm.service.unit.MdmUnitMeasureService; |
| | | import cn.iocoder.yudao.module.mdm.service.brand.MdmBrandService; |
| | | import cn.iocoder.yudao.module.mes.api.item.MesMdItemApi; |
| | | import cn.iocoder.yudao.module.mes.api.item.MesMdItemTypeApi; |
| | | import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemSyncReqDTO; |
| | | import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemTypeRespDTO; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.util.*; |
| | |
| | | @Resource |
| | | private MdmBrandService brandService; |
| | | |
| | | @Resource |
| | | private MesMdItemApi mesMdItemApi; |
| | | @Resource |
| | | private MesMdItemTypeApi mesMdItemTypeApi; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createItem(MdmItemSaveReqVO createReqVO) { |
| | | // æ ¡éªæ°æ® |
| | | validateItemSaveData(createReqVO); |
| | | |
| | | // æå
¥ |
| | | // æå
¥ MDM ç©æ |
| | | MdmItemDO item = BeanUtils.toBean(createReqVO, MdmItemDO.class); |
| | | itemMapper.insert(item); |
| | | |
| | | // åæ¥å° MESï¼å¾é syncMes æ¶ï¼ |
| | | if (Boolean.TRUE.equals(createReqVO.getSyncMes())) { |
| | | syncItemToMes(createReqVO); |
| | | } |
| | | return item.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateItem(MdmItemSaveReqVO updateReqVO) { |
| | | // æ ¡éªåå¨ |
| | | validateItemExists(updateReqVO.getId()); |
| | | // æ ¡éªæ°æ® |
| | | validateItemSaveData(updateReqVO); |
| | | |
| | | // æ´æ° |
| | | // æ´æ° MDM ç©æ |
| | | MdmItemDO updateObj = BeanUtils.toBean(updateReqVO, MdmItemDO.class); |
| | | itemMapper.updateById(updateObj); |
| | | |
| | | // åæ¥å° MESï¼å¾é syncMes æ¶ï¼ |
| | | if (Boolean.TRUE.equals(updateReqVO.getSyncMes())) { |
| | | syncItemToMes(updateReqVO); |
| | | } |
| | | } |
| | | |
| | | private void validateItemSaveData(MdmItemSaveReqVO reqVO) { |
| | | // æ ¡éªç©æç¼ç çå¯ä¸æ§ |
| | | validateItemCodeUnique(reqVO.getId(), reqVO.getCode()); |
| | | } |
| | | |
| | | /** |
| | | * åæ¥ç©æå° MESï¼åä½/åç±»æ code æ å°ï¼ |
| | | * |
| | | * MDM ç unitMeasureId/categoryId ä¸ MES ç unitMeasureId/itemTypeId åå±ä¸¤å¥ä¸»æ°æ®ï¼ |
| | | * è¿éå
å¨ MDM ä¾§è§£æåº codeï¼åäº¤ç± MesMdItemApi å¨ MES ä¾§è§£æä¸ºå¯¹åº idã |
| | | * åæ¥å¤±è´¥å°æåºå¼å¸¸ï¼è§¦åå¤å± @Transactional æ´ä½åæ»ï¼MDM æä½ä¸å¹¶åæ»ï¼ã |
| | | */ |
| | | private void syncItemToMes(MdmItemSaveReqVO reqVO) { |
| | | // è§£æè®¡éåä½ id -> code |
| | | String unitCode = null; |
| | | if (reqVO.getUnitMeasureId() != null) { |
| | | MdmUnitMeasureDO unitMeasure = unitMeasureService.getUnitMeasure(reqVO.getUnitMeasureId()); |
| | | if (unitMeasure == null) { |
| | | throw exception(MDM_UNIT_MEASURE_NOT_EXISTS); |
| | | } |
| | | unitCode = unitMeasure.getCode(); |
| | | } |
| | | // è§£æåç±» id -> codeï¼ä½¿ç¨ MES ç©æåç±» APIï¼ |
| | | String itemTypeCode = null; |
| | | if (reqVO.getCategoryId() != null) { |
| | | CommonResult<MesMdItemTypeRespDTO> result = mesMdItemTypeApi.getItemType(reqVO.getCategoryId()); |
| | | if (result != null && result.isSuccess() && result.getData() != null) { |
| | | itemTypeCode = result.getData().getCode(); |
| | | } |
| | | } else if (reqVO.getItemType() != null) { |
| | | // æ ¹æ® itemType æ¥æ¾å¯¹åºåç±»ç¼ç |
| | | // itemType: 1åæ, 2åæå, 3æå, 4è¾
æ |
| | | String itemTypeName = convertItemTypeToName(reqVO.getItemType()); |
| | | CommonResult<List<MesMdItemTypeRespDTO>> listResult = mesMdItemTypeApi.getItemTypeList(null); |
| | | if (listResult != null && listResult.isSuccess() && listResult.getData() != null) { |
| | | itemTypeCode = listResult.getData().stream() |
| | | .filter(c -> c.getName() != null && c.getName().equals(itemTypeName)) |
| | | .findFirst() |
| | | .map(MesMdItemTypeRespDTO::getCode) |
| | | .orElse(null); |
| | | } |
| | | } |
| | | // ç»è£
忥 DTO |
| | | MesMdItemSyncReqDTO syncReqDTO = new MesMdItemSyncReqDTO(); |
| | | syncReqDTO.setCode(reqVO.getCode()); |
| | | syncReqDTO.setName(reqVO.getName()); |
| | | syncReqDTO.setSpecification(reqVO.getSpecification()); |
| | | syncReqDTO.setUnitCode(unitCode); |
| | | syncReqDTO.setItemTypeCode(itemTypeCode); |
| | | syncReqDTO.setSafeStockFlag(Boolean.TRUE); // ä¿ç MDM ç minStock/maxStockï¼é¿å
被 MES æ¸
é¶ |
| | | syncReqDTO.setMinStock(reqVO.getMinStock()); |
| | | syncReqDTO.setMaxStock(reqVO.getMaxStock()); |
| | | syncReqDTO.setHighValue(reqVO.getIsHighValue()); |
| | | syncReqDTO.setBatchFlag(reqVO.getIsBatchManaged()); |
| | | syncReqDTO.setRemark(reqVO.getRemark()); |
| | | // create èµ° createItemï¼update èµ° updateItemï¼MES ä¾§æ code upsertï¼ |
| | | if (reqVO.getId() == null) { |
| | | mesMdItemApi.createItem(syncReqDTO); |
| | | } else { |
| | | mesMdItemApi.updateItem(syncReqDTO); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteItem(Long id) { |
| | | // æ ¡éªåå¨ |
| | | validateItemExists(id); |
| | | // å é¤ |
| | | MdmItemDO item = validateItemExists(id); |
| | | // è§£å³è½¯å é¤å¯ä¸é®å²çªï¼å¦æå·²åå¨ç¸å code ä¸å·²è½¯å é¤çè®°å½ï¼å
ç©çå é¤å® |
| | | MdmItemDO existingDeleted = itemMapper.selectByCodeAndDeleted(item.getCode(), true); |
| | | if (existingDeleted != null && !existingDeleted.getId().equals(id)) { |
| | | itemMapper.physicalDeleteById(existingDeleted.getId()); |
| | | } |
| | | // 软å é¤å½åè®°å½ |
| | | itemMapper.deleteById(id); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | private void validateCategoryExists(Long categoryId) { |
| | | if (itemCategoryService.getItemCategory(categoryId) == null) { |
| | | if (categoryId == null) { |
| | | return; |
| | | } |
| | | CommonResult<MesMdItemTypeRespDTO> result = mesMdItemTypeApi.getItemType(categoryId); |
| | | if (result == null || !result.isSuccess() || result.getData() == null) { |
| | | throw exception(MDM_ITEM_CATEGORY_NOT_EXISTS); |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å° itemType 转æ¢ä¸ºä¸æåç§° |
| | | * |
| | | * @param itemType ç©æç±»åï¼1åæ, 2åæå, 3æå, 4è¾
æ |
| | | * @return 䏿åç§° |
| | | */ |
| | | private String convertItemTypeToName(Integer itemType) { |
| | | if (itemType == null) { |
| | | return null; |
| | | } |
| | | switch (itemType) { |
| | | case 1: |
| | | return "åæ"; |
| | | case 2: |
| | | return "åæå"; |
| | | case 3: |
| | | return "æå"; |
| | | case 4: |
| | | return "è¾
æ"; |
| | | default: |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public MdmItemDO getItem(Long id) { |
| | | return itemMapper.selectById(id); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <project xmlns="http://maven.apache.org/POM/4.0.0" |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao</artifactId> |
| | | <version>${revision}</version> |
| | | </parent> |
| | | <modelVersion>4.0.0</modelVersion> |
| | | <artifactId>yudao-module-mes-api</artifactId> |
| | | <packaging>jar</packaging> |
| | | |
| | | <name>${project.artifactId}</name> |
| | | <description> |
| | | mes 模åä¸ï¼å¶é æ§è¡ç³»ç»ç API æ¥å£å®ä¹ï¼ä¾å
¶ä»æ¨¡åå¼ç¨ |
| | | </description> |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-common</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- Swagger 注解 --> |
| | | <dependency> |
| | | <groupId>org.springdoc</groupId> |
| | | <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | </project> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.item; |
| | | |
| | | import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemSyncReqDTO; |
| | | |
| | | /** |
| | | * MES ç©æäº§å API æ¥å£ |
| | | * |
| | | * ä¾å
¶ä»æ¨¡åï¼å¦ MDMï¼åæ¥ç©æä¸»æ°æ®å° MES 使ç¨ã |
| | | * åä½ãåç±»åæ code ä¼ éï¼ç± MES ä¾§è§£æä¸ºå¯¹åº idã |
| | | * |
| | | * @author èéæºç |
| | | */ |
| | | public interface MesMdItemApi { |
| | | |
| | | /** |
| | | * å建 MES ç©æäº§åï¼åæ¥ç¨ï¼ |
| | | * |
| | | * @param syncReqDTO åæ¥ä¿¡æ¯ï¼åä½/åç±»ä¼ codeï¼ |
| | | * @return MES ç©æç¼å· |
| | | */ |
| | | Long createItem(MesMdItemSyncReqDTO syncReqDTO); |
| | | |
| | | /** |
| | | * æ´æ° MES ç©æäº§åï¼åæ¥ç¨ï¼ |
| | | * |
| | | * æ code å¹é
ï¼åå¨åæ´æ°ï¼ä¸åå¨åå建ï¼upsertï¼ã |
| | | * |
| | | * @param syncReqDTO åæ¥ä¿¡æ¯ |
| | | */ |
| | | void updateItem(MesMdItemSyncReqDTO syncReqDTO); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.item; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemTypeRespDTO; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * MES ç©æåç±» API æ¥å£ |
| | | * |
| | | * ä¾å
¶ä»æ¨¡åï¼å¦ MDMï¼æ¥è¯¢ç©æåç±»æ°æ®ä½¿ç¨ã |
| | | * |
| | | * @author èéæºç |
| | | */ |
| | | public interface MesMdItemTypeApi { |
| | | |
| | | String PREFIX = "/rpc-api/mes/item-type"; |
| | | |
| | | /** |
| | | * è·åç©æåç±» |
| | | * |
| | | * @param id åç±»ç¼å· |
| | | * @return ç©æåç±» |
| | | */ |
| | | CommonResult<MesMdItemTypeRespDTO> getItemType(Long id); |
| | | |
| | | /** |
| | | * è·åç©æåç±»å表 |
| | | * |
| | | * @param ids åç±»ç¼å·å表 |
| | | * @return ç©æåç±»å表 |
| | | */ |
| | | CommonResult<List<MesMdItemTypeRespDTO>> getItemTypeList(Collection<Long> ids); |
| | | |
| | | /** |
| | | * æ ¹æ®ç¼ç è·åç©æåç±» |
| | | * |
| | | * @param code åç±»ç¼ç |
| | | * @return ç©æåç±» |
| | | */ |
| | | CommonResult<MesMdItemTypeRespDTO> getItemTypeByCode(String code); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.item.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Schema(description = "MES ç©æäº§å忥 Request DTO") |
| | | @Data |
| | | public class MesMdItemSyncReqDTO { |
| | | |
| | | @Schema(description = "ç©æç¼ç ", requiredMode = Schema.RequiredMode.REQUIRED, example = "ITEM001") |
| | | private String code; |
| | | |
| | | @Schema(description = "ç©æåç§°", requiredMode = Schema.RequiredMode.REQUIRED, example = "èºä¸") |
| | | private String name; |
| | | |
| | | @Schema(description = "è§æ ¼åå·", example = "M6*20") |
| | | private String specification; |
| | | |
| | | @Schema(description = "计éåä½ç¼ç ", requiredMode = Schema.RequiredMode.REQUIRED, example = "PCS") |
| | | private String unitCode; |
| | | |
| | | @Schema(description = "ç©æåç±»ç¼ç ", requiredMode = Schema.RequiredMode.REQUIRED, example = "TYPE001") |
| | | private String itemTypeCode; |
| | | |
| | | @Schema(description = "æ¯å¦å¯ç¨å®å
¨åºå", example = "false") |
| | | private Boolean safeStockFlag; |
| | | |
| | | @Schema(description = "æä½åºåé", example = "100") |
| | | private BigDecimal minStock; |
| | | |
| | | @Schema(description = "æé«åºåé", example = "10000") |
| | | private BigDecimal maxStock; |
| | | |
| | | @Schema(description = "æ¯å¦é«å¼ç©æ", example = "false") |
| | | private Boolean highValue; |
| | | |
| | | @Schema(description = "æ¯å¦å¯ç¨æ¹æ¬¡ç®¡ç", example = "true") |
| | | private Boolean batchFlag; |
| | | |
| | | @Schema(description = "夿³¨", example = "夿³¨") |
| | | private String remark; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.item.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | @Schema(description = "RPC æå¡ - MES ç©æåç±» Response DTO") |
| | | @Data |
| | | public class MesMdItemTypeRespDTO { |
| | | |
| | | @Schema(description = "åç±»ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "åç±»ç¼ç ", requiredMode = Schema.RequiredMode.REQUIRED, example = "RAW001") |
| | | private String code; |
| | | |
| | | @Schema(description = "åç±»åç§°", requiredMode = Schema.RequiredMode.REQUIRED, example = "åæ") |
| | | private String name; |
| | | |
| | | @Schema(description = "ç¶åç±»ç¼å·", example = "0") |
| | | private Long parentId; |
| | | |
| | | @Schema(description = "ç©æ/äº§åæ è¯", example = "1") |
| | | private String itemOrProduct; |
| | | |
| | | @Schema(description = "ç¶æ", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| | | private Integer status; |
| | | |
| | | } |
| | |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- MES å¶é æ§è¡ API --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-mes-api</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- MDM ä¸»æ°æ®ç®¡ç API --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.item; |
| | | |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemSyncReqDTO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService; |
| | | import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| | | |
| | | /** |
| | | * MES ç©æäº§å API å®ç°ç±» |
| | | * |
| | | * ä¾ MDM çæ¨¡ååæ¥ç©æä¸»æ°æ®å° MES 使ç¨ã |
| | | * åä½ãåç±»æ code å¨ MES ä¾§è§£æä¸ºå¯¹åº idã |
| | | * |
| | | * @author èéæºç |
| | | */ |
| | | @Service |
| | | @Validated |
| | | @Slf4j |
| | | public class MesMdItemApiImpl implements MesMdItemApi { |
| | | |
| | | @Resource |
| | | private MesMdItemService itemService; |
| | | @Resource |
| | | private MesMdItemTypeService itemTypeService; |
| | | @Resource |
| | | private MesMdUnitMeasureService unitMeasureService; |
| | | |
| | | @Override |
| | | public Long createItem(MesMdItemSyncReqDTO syncReqDTO) { |
| | | log.info("[createItem] 忥å建 MES ç©æäº§åï¼code={}", syncReqDTO.getCode()); |
| | | MesMdItemSaveReqVO saveReqVO = buildSaveReqVO(syncReqDTO); |
| | | return itemService.createItem(saveReqVO); |
| | | } |
| | | |
| | | @Override |
| | | public void updateItem(MesMdItemSyncReqDTO syncReqDTO) { |
| | | log.info("[updateItem] åæ¥æ´æ° MES ç©æäº§åï¼code={}", syncReqDTO.getCode()); |
| | | MesMdItemSaveReqVO saveReqVO = buildSaveReqVO(syncReqDTO); |
| | | // æ code å¹é
ï¼åå¨åæ´æ°ï¼ä¸åå¨åå建ï¼upsertï¼ |
| | | MesMdItemDO existItem = itemService.getItemByCode(syncReqDTO.getCode()); |
| | | if (existItem == null) { |
| | | itemService.createItem(saveReqVO); |
| | | } else { |
| | | saveReqVO.setId(existItem.getId()); |
| | | itemService.updateItem(saveReqVO); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å°åæ¥ DTO 转æ¢ä¸º MES ç©æäº§å SaveReqVOï¼å¹¶æ code è§£æåä½/åç±» id |
| | | */ |
| | | private MesMdItemSaveReqVO buildSaveReqVO(MesMdItemSyncReqDTO syncReqDTO) { |
| | | // è§£æè®¡éåä½ code -> id |
| | | MesMdUnitMeasureDO unitMeasure = unitMeasureService.getUnitMeasureByCode(syncReqDTO.getUnitCode()); |
| | | if (unitMeasure == null) { |
| | | throw exception(MD_UNIT_MEASURE_NOT_EXISTS); |
| | | } |
| | | // è§£æç©æåç±» code -> id |
| | | MesMdItemTypeDO itemType = itemTypeService.getItemTypeByCode(syncReqDTO.getItemTypeCode()); |
| | | if (itemType == null) { |
| | | throw exception(MD_ITEM_TYPE_NOT_EXISTS); |
| | | } |
| | | // ç»è£
ï¼code/name/specification/safeStockFlag/minStock/maxStock/highValue/batchFlag/remark ååæ·è´ï¼ |
| | | MesMdItemSaveReqVO saveReqVO = BeanUtils.toBean(syncReqDTO, MesMdItemSaveReqVO.class); |
| | | saveReqVO.setUnitMeasureId(unitMeasure.getId()); |
| | | saveReqVO.setItemTypeId(itemType.getId()); |
| | | return saveReqVO; |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.api.item; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemTypeRespDTO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | |
| | | /** |
| | | * MES ç©æåç±» API å®ç°ç±» |
| | | * |
| | | * @author èéæºç |
| | | */ |
| | | @RestController |
| | | @RequestMapping(MesMdItemTypeApi.PREFIX) |
| | | @Validated |
| | | public class MesMdItemTypeApiImpl implements MesMdItemTypeApi { |
| | | |
| | | @Resource |
| | | private MesMdItemTypeService itemTypeService; |
| | | |
| | | @Override |
| | | public CommonResult<MesMdItemTypeRespDTO> getItemType(Long id) { |
| | | MesMdItemTypeDO itemType = itemTypeService.getItemType(id); |
| | | return success(BeanUtils.toBean(itemType, MesMdItemTypeRespDTO.class)); |
| | | } |
| | | |
| | | @Override |
| | | public CommonResult<List<MesMdItemTypeRespDTO>> getItemTypeList(Collection<Long> ids) { |
| | | List<MesMdItemTypeDO> list = itemTypeService.getItemTypeList(ids); |
| | | return success(BeanUtils.toBean(list, MesMdItemTypeRespDTO.class)); |
| | | } |
| | | |
| | | @Override |
| | | public CommonResult<MesMdItemTypeRespDTO> getItemTypeByCode(String code) { |
| | | MesMdItemTypeDO itemType = itemTypeService.getItemTypeByCode(code); |
| | | return success(BeanUtils.toBean(itemType, MesMdItemTypeRespDTO.class)); |
| | | } |
| | | |
| | | } |
| | |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackTraceRespVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeLineDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceLineDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.qc.ipqc.MesQcIpqcMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemconsume.MesWmItemConsumeLineMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemconsume.MesWmItemConsumeMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceLineMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.*; |
| | | import java.util.stream.Stream; |
| | |
| | | |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | |
| | | @Resource |
| | | private MesWmProductProduceMapper productProduceMapper; |
| | | @Resource |
| | | private MesWmProductProduceLineMapper productProduceLineMapper; |
| | | @Resource |
| | | private MesWmItemConsumeMapper itemConsumeMapper; |
| | | @Resource |
| | | private MesWmItemConsumeLineMapper itemConsumeLineMapper; |
| | | @Resource |
| | | private MesQcIpqcMapper ipqcMapper; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "å建ç产æ¥å·¥") |
| | |
| | | return success(new PageResult<>(buildFeedbackRespVOList(pageResult.getList()), pageResult.getTotal())); |
| | | } |
| | | |
| | | @GetMapping("/list-by-task") |
| | | @Operation(summary = "æä»»å¡è·å¾æ¥å·¥åå²å表") |
| | | @Parameter(name = "taskId", description = "ä»»å¡ç¼å·", required = true, example = "1024") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-feedback:query')") |
| | | public CommonResult<List<MesProFeedbackRespVO>> getFeedbackListByTask(@RequestParam("taskId") Long taskId) { |
| | | List<MesProFeedbackDO> list = feedbackService.getFeedbackListByTaskId(taskId); |
| | | return success(buildFeedbackRespVOList(list)); |
| | | } |
| | | |
| | | @GetMapping("/export-excel") |
| | | @Operation(summary = "导åºç产æ¥å·¥ Excel") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-feedback:export')") |
| | |
| | | |
| | | // ==================== æ¼æ¥ VO ==================== |
| | | |
| | | @GetMapping("/trace/{id}") |
| | | @Operation(summary = "è·å¾æ¥å·¥è¿½æº¯ä¿¡æ¯", description = "æ¥å·¥ + 产åº/äº§åºæç» + æ¶è/æ¶èæç» + IPQCæ£éª") |
| | | @Parameter(name = "id", description = "æ¥å·¥ç¼å·", required = true, example = "1024") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-feedback:query')") |
| | | public CommonResult<MesProFeedbackTraceRespVO> getFeedbackTrace(@PathVariable("id") Long id) { |
| | | MesProFeedbackDO feedback = feedbackService.getFeedback(id); |
| | | if (feedback == null) { |
| | | return success(null); |
| | | } |
| | | MesProFeedbackTraceRespVO trace = new MesProFeedbackTraceRespVO(); |
| | | // 1. æ¥å·¥æç»ï¼å¤ç¨å±ç¤ºæ¼æ¥ï¼å¸¦å·¥å/ä»»å¡/å·¥åº/ç©æ/æ¥å·¥äººçæ¾ç¤ºåï¼ |
| | | trace.setFeedback(buildFeedbackRespVOList(ListUtil.of(feedback)).get(0)); |
| | | // 2. çäº§äº§åº + äº§åºæç»è¡ï¼å
³é®å·¥åºææï¼ |
| | | trace.setProductProduce(productProduceMapper.selectByFeedbackId(id)); |
| | | trace.setProductProduceLines(productProduceLineMapper.selectListByFeedbackId(id)); |
| | | // 3. ç©ææ¶è + æ¶èæç»è¡ï¼åå²å·¥åºææï¼ |
| | | MesWmItemConsumeDO itemConsume = itemConsumeMapper.selectByFeedbackId(id); |
| | | trace.setItemConsume(itemConsume); |
| | | if (itemConsume != null) { |
| | | trace.setItemConsumeLines(itemConsumeLineMapper.selectListByConsumeId(itemConsume.getId())); |
| | | } |
| | | // 4. IPQC è¿ç¨æ£éªåï¼å
³é®+鿣éªå·¥åºææï¼ |
| | | trace.setIpqcList(ipqcMapper.selectListBySourceDoc(MesBizTypeConstants.PRO_FEEDBACK, id)); |
| | | return success(trace); |
| | | } |
| | | |
| | | private List<MesProFeedbackRespVO> buildFeedbackRespVOList(List<MesProFeedbackDO> list) { |
| | | if (CollUtil.isEmpty(list)) { |
| | | return Collections.emptyList(); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo; |
| | | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeLineDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceLineDO; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - æ¥å·¥è¿½æº¯ Response VO") |
| | | @Data |
| | | public class MesProFeedbackTraceRespVO { |
| | | |
| | | @Schema(description = "æ¥å·¥ä¿¡æ¯") |
| | | private MesProFeedbackRespVO feedback; |
| | | |
| | | @Schema(description = "ç产产åºåï¼å
³é®å·¥åºææï¼") |
| | | private MesWmProductProduceDO productProduce; |
| | | |
| | | @Schema(description = "çäº§äº§åºæç»è¡ï¼æåæ ¼/ä¸åæ ¼/å¾
æ£éªæè¡ï¼") |
| | | private List<MesWmProductProduceLineDO> productProduceLines; |
| | | |
| | | @Schema(description = "ç©ææ¶èåï¼åå²å·¥åºææï¼") |
| | | private MesWmItemConsumeDO itemConsume; |
| | | |
| | | @Schema(description = "ç©ææ¶èæç»è¡ï¼æ BOM ç©æï¼") |
| | | private List<MesWmItemConsumeLineDO> itemConsumeLines; |
| | | |
| | | @Schema(description = "IPQC è¿ç¨æ£éªåå表ï¼å
³é®+鿣éªå·¥åºææï¼") |
| | | private List<MesQcIpqcDO> ipqcList; |
| | | |
| | | } |
| | |
| | | @Schema(description = "æ¯å¦è´¨æ£å·¥åº", example = "false") |
| | | private Boolean checkFlag; |
| | | |
| | | @Schema(description = "æ¯å¦åå²ï¼true=æ¥å·¥æ¶æBOMèªå¨æ£æï¼false=ä¸èªå¨æ£æï¼", example = "true") |
| | | private Boolean backflushFlag; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | |
| | | @Schema(description = "æ¯å¦è´¨æ£å·¥åº", example = "false") |
| | | private Boolean checkFlag; |
| | | |
| | | @Schema(description = "æ¯å¦åå²ï¼true=æ¥å·¥æ¶æBOMèªå¨æ£æï¼false=ä¸èªå¨æ£æï¼", example = "true") |
| | | private Boolean backflushFlag; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | |
| | | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO; |
| | | import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProcessService; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.pro.feedback.MesProFeedbackService; |
| | | |
| | | import java.io.IOException; |
| | | import java.math.BigDecimal; |
| | |
| | | private MesMdUnitMeasureService unitMeasureService; |
| | | @Resource |
| | | private MesProRouteProcessService routeProcessService; |
| | | @Resource |
| | | private MesProFeedbackService feedbackService; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "å建ç产任å¡") |
| | |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-task:query')") |
| | | public CommonResult<PageResult<MesProTaskRespVO>> getTaskPage(@Valid MesProTaskPageReqVO pageReqVO) { |
| | | PageResult<MesProTaskDO> pageResult = taskService.getTaskPage(pageReqVO); |
| | | return success(new PageResult<>(buildTaskRespVOList(pageResult.getList()), pageResult.getTotal())); |
| | | } |
| | | |
| | | @GetMapping("/pending-feedback-page") |
| | | @Operation(summary = "è·å¾å¾
æ¥å·¥å°è´¦å页", description = "å·²æäº§ä¸ä»æå¾
æ¥å·¥æ°éçä»»å¡ï¼ç¶æ=è¿è¡ä¸ï¼") |
| | | @PreAuthorize("@ss.hasPermission('mes:pro-task:query')") |
| | | public CommonResult<PageResult<MesProTaskRespVO>> getPendingFeedbackPage(@Valid MesProTaskPageReqVO pageReqVO) { |
| | | PageResult<MesProTaskDO> pageResult = taskService.getPendingFeedbackPage(pageReqVO); |
| | | return success(new PageResult<>(buildTaskRespVOList(pageResult.getList()), pageResult.getTotal())); |
| | | } |
| | | |
| | |
| | | .put(rp.getProcessId(), Boolean.TRUE.equals(rp.getCheckFlag())); |
| | | } |
| | | } |
| | | // æ¥å·¥å¨ééï¼æä»»å¡èå feedbackQuantityï¼è稿/审æ¹ä¸/å¾
æ£éª = å¨éï¼å·²å®æ = 已审æ¹ï¼ |
| | | List<MesProFeedbackDO> taskFeedbacks = feedbackService.getFeedbackListByTaskIds( |
| | | convertSet(list, MesProTaskDO::getId)); |
| | | Map<Long, BigDecimal> inTransitMap = new HashMap<>(); |
| | | for (MesProFeedbackDO fb : taskFeedbacks) { |
| | | BigDecimal fbQty = fb.getFeedbackQuantity() == null ? BigDecimal.ZERO : fb.getFeedbackQuantity(); |
| | | if (!ObjUtil.equal(fb.getStatus(), MesProFeedbackStatusEnum.FINISHED.getStatus())) { |
| | | inTransitMap.merge(fb.getTaskId(), fbQty, BigDecimal::add); |
| | | } |
| | | } |
| | | // æ¼æ¥ VO |
| | | return convertList(list, task -> { |
| | | MesProTaskRespVO vo = BeanUtils.toBean(task, MesProTaskRespVO.class); |
| | | // å¾
æ¥å·¥æ°é = æäº§æ°é - å·²ç产æ°éï¼æ¥å·¥å®æç = å·²ç产 / æäº§ à 100 |
| | | BigDecimal quantity = task.getQuantity() == null ? BigDecimal.ZERO : task.getQuantity(); |
| | | BigDecimal produced = task.getProducedQuantity() == null ? BigDecimal.ZERO : task.getProducedQuantity(); |
| | | vo.setPendingQuantity(quantity.subtract(produced)); |
| | | vo.setFeedbackRate(quantity.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO |
| | | : produced.multiply(new BigDecimal("100")).divide(quantity, 2, RoundingMode.HALF_UP)); |
| | | // å¨éæ¥å·¥éï¼è稿/审æ¹ä¸/å¾
æ£éªï¼+ 坿¥å·¥æ°é = æäº§ - å·²ç产 - å¨é |
| | | BigDecimal inTransit = inTransitMap.getOrDefault(task.getId(), BigDecimal.ZERO); |
| | | vo.setInTransitQuantity(inTransit); |
| | | vo.setReportableQuantity(quantity.subtract(produced).subtract(inTransit).max(BigDecimal.ZERO)); |
| | | findAndThen(workOrderMap, task.getWorkOrderId(), wo -> |
| | | vo.setWorkOrderCode(wo.getCode()).setWorkOrderName(wo.getName()).setRequestDate(wo.getRequestDate())); |
| | | findAndThen(workstationMap, task.getWorkstationId(), ws -> |
| | |
| | | @Schema(description = "ä¸è¯åæ°é", example = "2.00") |
| | | private BigDecimal unqualifyQuantity; |
| | | |
| | | @Schema(description = "å¾
æ¥å·¥æ°é", example = "50.00") |
| | | private BigDecimal pendingQuantity; |
| | | |
| | | @Schema(description = "å¨éæ¥å·¥æ°é", example = "20.00") |
| | | private BigDecimal inTransitQuantity; |
| | | |
| | | @Schema(description = "坿¥å·¥æ°é", example = "30.00") |
| | | private BigDecimal reportableQuantity; |
| | | |
| | | @Schema(description = "æ¥å·¥å®æç(%)", example = "50.00") |
| | | private BigDecimal feedbackRate; |
| | | |
| | | @Schema(description = "è°æ´æ°é", example = "0") |
| | | private BigDecimal changedQuantity; |
| | | |
| | |
| | | */ |
| | | private Boolean checkFlag; |
| | | /** |
| | | * æ¯å¦åå² |
| | | * |
| | | * true=æ¥å·¥æ¶æ BOM èªå¨æ£æï¼false=ä¸èªå¨æ£æï¼ç©æèµ°æå·¥é¢æ/ææ |
| | | */ |
| | | private Boolean backflushFlag; |
| | | /** |
| | | * 夿³¨ |
| | | */ |
| | | private String remark; |
| | |
| | | return selectOne(MesMdItemTypeDO::getParentId, parentId, MesMdItemTypeDO::getCode, code); |
| | | } |
| | | |
| | | default MesMdItemTypeDO selectByCode(String code) { |
| | | return selectOne(MesMdItemTypeDO::getName, code); |
| | | } |
| | | |
| | | default Long selectCountByParentId(Long parentId) { |
| | | return selectCount(MesMdItemTypeDO::getParentId, parentId); |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * MES ç产æ¥å·¥ Mapper |
| | | * |
| | |
| | | .orderByDesc(MesProFeedbackDO::getId)); |
| | | } |
| | | |
| | | default Long selectCountByTaskId(Long taskId) { |
| | | return selectCount(MesProFeedbackDO::getTaskId, taskId); |
| | | } |
| | | |
| | | default List<MesProFeedbackDO> selectListByTaskId(Long taskId) { |
| | | return selectList(new LambdaQueryWrapperX<MesProFeedbackDO>() |
| | | .eq(MesProFeedbackDO::getTaskId, taskId) |
| | | .orderByDesc(MesProFeedbackDO::getId)); |
| | | } |
| | | |
| | | default List<MesProFeedbackDO> selectListByTaskIds(Collection<Long> taskIds) { |
| | | return selectList(new LambdaQueryWrapperX<MesProFeedbackDO>() |
| | | .in(MesProFeedbackDO::getTaskId, taskIds)); |
| | | } |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | return selectPage(reqVO, query); |
| | | } |
| | | |
| | | default PageResult<MesProTaskDO> selectPendingFeedbackPage(MesProTaskPageReqVO reqVO) { |
| | | MPJLambdaWrapperX<MesProTaskDO> query = new MPJLambdaWrapperX<>(); |
| | | query.selectAll(MesProTaskDO.class); |
| | | // å¾
æ¥å·¥å°è´¦ï¼è¿è¡ä¸çä»»å¡ï¼æé¤å·²å®æ/已忶ï¼ï¼ä¸ä»æå¾
æ¥å·¥é |
| | | query.eq(MesProTaskDO::getStatus, MesProTaskStatusEnum.PREPARE.getStatus()); |
| | | query.apply("(quantity - IFNULL(produced_quantity, 0)) > 0"); |
| | | query.likeIfPresent(MesProTaskDO::getCode, reqVO.getCode()) |
| | | .likeIfPresent(MesProTaskDO::getName, reqVO.getName()) |
| | | .eqIfPresent(MesProTaskDO::getWorkOrderId, reqVO.getWorkOrderId()) |
| | | .eqIfPresent(MesProTaskDO::getRouteId, reqVO.getRouteId()) |
| | | .eqIfPresent(MesProTaskDO::getProcessId, reqVO.getProcessId()) |
| | | .eqIfPresent(MesProTaskDO::getWorkstationId, reqVO.getWorkstationId()) |
| | | .betweenIfPresent(MesProTaskDO::getCreateTime, reqVO.getCreateTime()) |
| | | .orderByDesc(MesProTaskDO::getId); |
| | | return selectPage(reqVO, query); |
| | | } |
| | | |
| | | default List<MesProTaskDO> selectListByWorkOrderId(Long workOrderId) { |
| | | return selectList(new LambdaQueryWrapperX<MesProTaskDO>() |
| | | .eqIfPresent(MesProTaskDO::getWorkOrderId, workOrderId) |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * MES è¿ç¨æ£éªåï¼IPQCï¼ Mapper |
| | | * |
| | |
| | | return selectOne(MesQcIpqcDO::getCode, code); |
| | | } |
| | | |
| | | default List<MesQcIpqcDO> selectListBySourceDoc(Integer sourceDocType, Long sourceDocId) { |
| | | return selectList(new LambdaQueryWrapperX<MesQcIpqcDO>() |
| | | .eq(MesQcIpqcDO::getSourceDocType, sourceDocType) |
| | | .eq(MesQcIpqcDO::getSourceDocId, sourceDocId) |
| | | .orderByDesc(MesQcIpqcDO::getId)); |
| | | } |
| | | |
| | | } |
| | |
| | | ErrorCode PRO_TASK_WORKSTATION_MISMATCH = new ErrorCode(1_040_503_003, "ç产任å¡ä¸å±äºå½åå·¥ä½ç«"); |
| | | ErrorCode PRO_TASK_ROUTE_PROCESS_MISMATCH = new ErrorCode(1_040_503_004, "ç产任å¡ä¸å½åå·¥èºè·¯çº¿æå·¥åºä¸ä¸è´"); |
| | | ErrorCode PRO_TASK_ITEM_MISMATCH = new ErrorCode(1_040_503_005, "ç产任å¡äº§åä¸å½å产åç©æä¸ä¸è´"); |
| | | ErrorCode PRO_TASK_HAS_FEEDBACK = new ErrorCode(1_040_503_006, "该任å¡ä¸å卿¥å·¥è®°å½ï¼æ æ³å é¤ï¼é¿å
æ¥å·¥è¿½æº¯æé¾ï¼"); |
| | | ErrorCode PRO_WORKSTATION_PROCESS_MISMATCH = new ErrorCode(1_040_503_006, "å·¥ä½ç«æå±å·¥åºä¸å½åå·¥åºä¸ä¸è´"); |
| | | // ========== MES ç产管ç-çäº§ä»»å¡ææï¼1-040-503-100ï¼ ========== |
| | | ErrorCode PRO_TASK_ISSUE_NOT_EXISTS = new ErrorCode(1_040_503_100, "çäº§ä»»å¡ææè®°å½ä¸åå¨"); |
| | |
| | | ErrorCode PRO_FEEDBACK_QUANTITY_MUST_POSITIVE = new ErrorCode(1_040_506_010, "æ¥å·¥æ°éå¿
é¡»å¤§äº 0"); |
| | | ErrorCode PRO_FEEDBACK_QUALIFIED_UNQUALIFIED_REQUIRED = new ErrorCode(1_040_506_011, "请è¾å
¥åæ ¼ååä¸è¯åæ°éï¼ä¸åè®¡é¡»å¤§äº 0"); |
| | | ErrorCode PRO_FEEDBACK_UNCHECK_QUANTITY_EXISTS = new ErrorCode(1_040_506_012, "å½åæ¥å·¥åæªå®ææ£éªï¼å¾
æ£æ°éï¼{}ï¼ï¼æ æ³æ§è¡æ¥å·¥"); |
| | | ErrorCode PRO_FEEDBACK_BACKFLUSH_BOM_REQUIRED = new ErrorCode(1_040_506_013, "å½åå·¥åºä¸ºåå²å·¥åºï¼ä½æªé
ç½®BOMæ¶èï¼æ æ³æ¥å·¥"); |
| | | |
| | | // ========== MES ç产管ç-ç产æµè½¬å¡ï¼1-040-507-000ï¼ ========== |
| | | ErrorCode PRO_CARD_NOT_EXISTS = new ErrorCode(1_040_507_000, "ç产æµè½¬å¡ä¸åå¨"); |
| | |
| | | MesMdItemDO getItem(Long id); |
| | | |
| | | /** |
| | | * æ ¹æ®ç¼ç è·å¾ç©æäº§å |
| | | * |
| | | * @param code ç©æç¼ç |
| | | * @return ç©æäº§å |
| | | */ |
| | | MesMdItemDO getItemByCode(String code); |
| | | |
| | | /** |
| | | * æ ¡éªç©æäº§ååå¨ |
| | | * |
| | | * @param id ç¼å· |
| | |
| | | } |
| | | |
| | | @Override |
| | | public MesMdItemDO getItemByCode(String code) { |
| | | return itemMapper.selectByCode(code); |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<MesMdItemDO> getItemPage(MesMdItemPageReqVO pageReqVO) { |
| | | // æ¥æ¾æ¶ï¼å¦ææ¥æ¾æä¸ªåç±»ç¼å·ï¼åå
å«å®çååç±» |
| | | Set<Long> itemTypeIds = null; |
| | |
| | | MesMdItemTypeDO getItemType(Long id); |
| | | |
| | | /** |
| | | * æ ¹æ®ç¼ç è·å¾ç©æäº§ååç±» |
| | | * |
| | | * @param code åç±»ç¼ç |
| | | * @return ç©æäº§ååç±» |
| | | */ |
| | | MesMdItemTypeDO getItemTypeByCode(String code); |
| | | |
| | | /** |
| | | * è·å¾ç©æäº§ååç±»å表 |
| | | * |
| | | * @param listReqVO æ¥è¯¢æ¡ä»¶ |
| | |
| | | } |
| | | |
| | | @Override |
| | | public MesMdItemTypeDO getItemTypeByCode(String code) { |
| | | return itemTypeMapper.selectByCode(code); |
| | | } |
| | | |
| | | @Override |
| | | public List<MesMdItemTypeDO> getItemTypeList(MesMdItemTypeListReqVO listReqVO) { |
| | | return itemTypeMapper.selectList(listReqVO); |
| | | } |
| | |
| | | package cn.iocoder.yudao.module.mes.service.md.unitmeasure; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.md.unitmeasure.vo.MesMdUnitMeasurePageReqVO; |
| | |
| | | import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcLineService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcLineService; |
| | | import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateIndicatorService; |
| | | import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi; |
| | | import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| | |
| | | /** |
| | | * MES 计éåä½ Service å®ç°ç±» |
| | | * |
| | | * 注æï¼æ¥è¯¢æä½ç»ä¸ä½¿ç¨ MDM API è·åæ°æ®ï¼ä¿æä¸ MDM ä¸»æ°æ®ä¸è´ |
| | | * |
| | | * @author èéæºç |
| | | */ |
| | | @Service |
| | | @Validated |
| | | public class MesMdUnitMeasureServiceImpl implements MesMdUnitMeasureService { |
| | | |
| | | @Resource |
| | | private MdmUnitMeasureApi unitMeasureApi; |
| | | |
| | | @Resource |
| | | private MesMdUnitMeasureMapper unitMeasureMapper; |
| | |
| | | |
| | | @Override |
| | | public MesMdUnitMeasureDO getUnitMeasure(Long id) { |
| | | return unitMeasureMapper.selectById(id); |
| | | // ä¼å
ä» MDM API è·å |
| | | CommonResult<MdmUnitMeasureRespDTO> result = unitMeasureApi.getUnitMeasure(id); |
| | | if (result != null && result.isSuccess() && result.getData() != null) { |
| | | return convertToDo(result.getData()); |
| | | } |
| | | // 妿 MDM API 失败ï¼åéå°æ¬å°æ°æ®åº |
| | | MesMdUnitMeasureDO local = unitMeasureMapper.selectById(id); |
| | | if (local != null) { |
| | | return local; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<MesMdUnitMeasureDO> getUnitMeasurePage(MesMdUnitMeasurePageReqVO pageReqVO) { |
| | | // ä½¿ç¨æ¬å°æ°æ®åºå页æ¥è¯¢ï¼MDM API 䏿¯æåé¡µåæ°ï¼ |
| | | return unitMeasureMapper.selectPage(pageReqVO); |
| | | } |
| | | |
| | | @Override |
| | | public List<MesMdUnitMeasureDO> getUnitMeasureListByStatus(Integer status) { |
| | | // ä½¿ç¨æ¬å°æ°æ®åºæ¥è¯¢ï¼MDM API 䏿¯ææç¶æè¿æ»¤ï¼ |
| | | return unitMeasureMapper.selectListByStatus(status); |
| | | } |
| | | |
| | |
| | | if (CollUtil.isEmpty(ids)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | // ä¼å
ä» MDM API è·å |
| | | CommonResult<List<MdmUnitMeasureRespDTO>> result = unitMeasureApi.getUnitMeasureList(ids); |
| | | if (result != null && result.isSuccess() && result.getData() != null) { |
| | | return result.getData().stream() |
| | | .map(this::convertToDo) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | // 妿 MDM API 失败ï¼åéå°æ¬å°æ°æ®åº |
| | | return unitMeasureMapper.selectByIds(ids); |
| | | } |
| | | |
| | | @Override |
| | | public MesMdUnitMeasureDO getUnitMeasureByCode(String code) { |
| | | return unitMeasureMapper.selectByCode(code); |
| | | // ä¼å
ä» MDM API è·å |
| | | CommonResult<MdmUnitMeasureRespDTO> result = unitMeasureApi.getUnitMeasureByCode(code); |
| | | if (result != null && result.isSuccess() && result.getData() != null) { |
| | | return convertToDo(result.getData()); |
| | | } |
| | | // 妿 MDM API 失败ï¼åéå°æ¬å°æ°æ®åº |
| | | MesMdUnitMeasureDO local = unitMeasureMapper.selectByCode(code); |
| | | if (local != null) { |
| | | return local; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * å° MDM DTO 转æ¢ä¸º MES DO |
| | | */ |
| | | private MesMdUnitMeasureDO convertToDo(MdmUnitMeasureRespDTO dto) { |
| | | MesMdUnitMeasureDO doObj = new MesMdUnitMeasureDO(); |
| | | doObj.setId(dto.getId()); |
| | | doObj.setCode(dto.getCode()); |
| | | doObj.setName(dto.getName()); |
| | | doObj.setPrimaryFlag(dto.getPrimaryFlag()); |
| | | doObj.setPrimaryId(dto.getPrimaryId()); |
| | | doObj.setChangeRate(dto.getChangeRate()); |
| | | doObj.setStatus(dto.getStatus()); |
| | | return doObj; |
| | | } |
| | | |
| | | } |
| | |
| | | import jakarta.validation.Valid; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * MES ç产æ¥å·¥ Service æ¥å£ |
| | |
| | | PageResult<MesProFeedbackDO> getFeedbackPage(MesProFeedbackPageReqVO pageReqVO); |
| | | |
| | | /** |
| | | * æä»»å¡ç¼å·å表æ¹éè·å¾æ¥å·¥è®°å½ï¼ç¨äºä»»å¡å°è´¦èåå¨é/å·²å®¡æ¹æ¥å·¥éï¼ |
| | | * |
| | | * @param taskIds ä»»å¡ç¼å·å表 |
| | | * @return æ¥å·¥è®°å½å表 |
| | | */ |
| | | List<MesProFeedbackDO> getFeedbackListByTaskIds(Collection<Long> taskIds); |
| | | |
| | | /** |
| | | * æä»»å¡ç¼å·è·å¾æ¥å·¥è®°å½åè¡¨ï¼æ¥å·¥åå²ï¼å«è稿/审æ¹ä¸/å¾
æ£éª/å·²å®æï¼ |
| | | * |
| | | * @param taskId ä»»å¡ç¼å· |
| | | * @return æ¥å·¥è®°å½å表 |
| | | */ |
| | | List<MesProFeedbackDO> getFeedbackListByTaskId(Long taskId); |
| | | |
| | | /** |
| | | * æäº¤æ¥å·¥ï¼è稿 â 审æ¹ä¸ï¼ |
| | | * |
| | | * @param id ç¼å· |
| | |
| | | package cn.iocoder.yudao.module.mes.service.pro.feedback; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductBomDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeDO; |
| | |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProcessService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProductBomService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.itemconsume.MesWmItemConsumeService; |
| | |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | |
| | | private MesProWorkOrderService workOrderService; |
| | | @Resource |
| | | private MesProRouteProcessService routeProcessService; |
| | | @Resource |
| | | private MesProRouteProductBomService routeProductBomService; |
| | | @Resource |
| | | private MesMdWorkstationService workstationService; |
| | | @Resource |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<MesProFeedbackDO> getFeedbackListByTaskIds(Collection<Long> taskIds) { |
| | | if (CollUtil.isEmpty(taskIds)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | return feedbackMapper.selectListByTaskIds(taskIds); |
| | | } |
| | | |
| | | @Override |
| | | public List<MesProFeedbackDO> getFeedbackListByTaskId(Long taskId) { |
| | | return feedbackMapper.selectListByTaskId(taskId); |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<MesProFeedbackDO> getFeedbackPage(MesProFeedbackPageReqVO pageReqVO) { |
| | | return feedbackMapper.selectPage(pageReqVO); |
| | | } |
| | |
| | | throw exception(PRO_FEEDBACK_UNCHECK_QUANTITY_EXISTS, feedback.getUncheckQuantity()); |
| | | } |
| | | |
| | | // 3. ç©ææ¶èï¼æ ¹æ®å·¥åº BOM çææ¶èè®°å½å¹¶æ§è¡æ£å |
| | | MesWmItemConsumeDO itemConsume = itemConsumeService.generateItemConsume(feedback); |
| | | if (itemConsume != null) { |
| | | itemConsumeService.finishItemConsume(itemConsume.getId()); |
| | | // 3. ç©ææ¶èï¼åå²å·¥åºæ BOM èªå¨æ£æï¼éåå²å·¥åºè·³è¿ï¼ç©æèµ°æå·¥é¢æ/ææï¼ |
| | | boolean backflushFlag = routeProcess != null && Boolean.TRUE.equals(routeProcess.getBackflushFlag()); |
| | | if (backflushFlag) { |
| | | // 3.1 æ ¡éªåå²å·¥åºå¿
é¡»é
ç½® BOM æ¶èï¼é¿å
éé»ä¸æ£æ |
| | | List<MesProRouteProductBomDO> boms = routeProductBomService.getRouteProductBomList( |
| | | feedback.getRouteId(), feedback.getProcessId(), feedback.getItemId()); |
| | | if (CollUtil.isEmpty(boms)) { |
| | | throw exception(PRO_FEEDBACK_BACKFLUSH_BOM_REQUIRED); |
| | | } |
| | | // 3.2 çææ¶èè®°å½å¹¶æ§è¡æ£åï¼BOM à æ¥å·¥æ°éï¼FIFO æ£çº¿è¾¹åºï¼ |
| | | MesWmItemConsumeDO itemConsume = itemConsumeService.generateItemConsume(feedback); |
| | | if (itemConsume != null) { |
| | | itemConsumeService.finishItemConsume(itemConsume.getId()); |
| | | } |
| | | } |
| | | |
| | | // 4. å
³é®å·¥åºï¼çæäº§åºåï¼å¹¶æ ¹æ®æ¯å¦éè¦æ£éªå³å®å
¥åºæ¹å¼ |
| | |
| | | PageResult<MesProTaskDO> getTaskPage(MesProTaskPageReqVO pageReqVO); |
| | | |
| | | /** |
| | | * è·å¾å¾
æ¥å·¥å°è´¦å页ï¼è¿è¡ä¸ä¸ä»æå¾
æ¥å·¥éçä»»å¡ï¼ |
| | | * |
| | | * @param pageReqVO å页æ¥è¯¢ |
| | | * @return å¾
æ¥å·¥ä»»å¡å页 |
| | | */ |
| | | PageResult<MesProTaskDO> getPendingFeedbackPage(MesProTaskPageReqVO pageReqVO); |
| | | |
| | | /** |
| | | * æ ¹æ®å·¥åç¼å·åè¡¨ï¼æ¹éè·å¾ç产任å¡å表 |
| | | * |
| | | * @param workOrderIds å·¥åç¼å·å表 |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.task.MesProTaskMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService; |
| | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_ALREADY_FINISHED; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_HAS_FEEDBACK; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_NOT_EXISTS; |
| | | |
| | | /** |
| | |
| | | |
| | | @Resource |
| | | private MesProTaskMapper taskMapper; |
| | | |
| | | @Resource |
| | | private MesProFeedbackMapper feedbackMapper; |
| | | |
| | | @Resource |
| | | @Lazy |
| | |
| | | public void deleteTask(Long id) { |
| | | // 1. æ ¡éªåå¨ä¸éç»æ |
| | | validateTaskNotFinished(id); |
| | | |
| | | // 2. å é¤ |
| | | // 2. æ ¡éªä»»å¡ä¸æ æ¥å·¥è®°å½ï¼é¿å
å é¤åæ¥å·¥è¿½æº¯æé¾ |
| | | if (feedbackMapper.selectCountByTaskId(id) > 0) { |
| | | throw exception(PRO_TASK_HAS_FEEDBACK); |
| | | } |
| | | // 3. å é¤ |
| | | taskMapper.deleteById(id); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<MesProTaskDO> getPendingFeedbackPage(MesProTaskPageReqVO pageReqVO) { |
| | | return taskMapper.selectPendingFeedbackPage(pageReqVO); |
| | | } |
| | | |
| | | @Override |
| | | public List<MesProTaskDO> getTaskListByWorkOrderIds(Collection<Long> workOrderIds) { |
| | | if (CollUtil.isEmpty(workOrderIds)) { |
| | | return Collections.emptyList(); |
| | |
| | | |
| | | <!-- |
| | | åå追溯ï¼ä»æä¸ªåæææ¹æ¬¡åºåï¼æ¥æ¾å®è¢«åªäºå·¥åæ¶èåï¼äº§åºäºåªäºæåæ¹æ¬¡ |
| | | SQL è·¯å¾ï¼æ¶èæç»(icd) â æ¶èå(ic) â æ¥å·¥è®°å½(pf) â ç产å
¥åºå(pp) â å
¥åºè¡(ppl) |
| | | SQL è·¯å¾ï¼åºåäºå¡(æ¶è OUT) â æ¶èå â æ¥å·¥è®°å½ â åºåäºå¡(äº§åº IN) â æ¹æ¬¡ |
| | | --> |
| | | <select id="selectListByForward" parameterType="String" resultMap="BatchTraceResult"> |
| | | SELECT DISTINCT pf.work_order_id, pf.item_id, ppl.batch_id, ppl.batch_code |
| | | FROM mes_wm_item_consume_detail icd |
| | | LEFT JOIN mes_wm_item_consume ic ON icd.consume_id = ic.id AND ic.deleted = 0 |
| | | FROM mes_wm_transaction tx_consume |
| | | LEFT JOIN mes_wm_item_consume ic ON tx_consume.biz_id = ic.id AND tx_consume.biz_type = 123 AND ic.deleted = 0 |
| | | LEFT JOIN mes_pro_feedback pf ON pf.id = ic.feedback_id AND pf.deleted = 0 |
| | | LEFT JOIN mes_wm_product_produce pp ON pp.work_order_id = ic.work_order_id AND pp.deleted = 0 |
| | | LEFT JOIN mes_wm_product_produce_line ppl ON pp.id = ppl.produce_id AND ppl.deleted = 0 |
| | | WHERE icd.batch_code = #{batchCode} |
| | | AND icd.deleted = 0 |
| | | LEFT JOIN mes_wm_transaction tx_produce ON tx_produce.biz_id = pf.id AND tx_produce.biz_type = 124 AND tx_produce.deleted = 0 |
| | | LEFT JOIN mes_wm_product_produce pp ON tx_produce.biz_id = pp.id AND tx_produce.biz_type = 124 AND pp.deleted = 0 |
| | | WHERE tx_consume.batch_code = #{batchCode} |
| | | AND tx_consume.biz_type = 123 |
| | | AND tx_consume.deleted = 0 |
| | | AND tx_produce.batch_id IS NOT NULL |
| | | </select> |
| | | |
| | | <!-- |
| | | åå追溯ï¼ä»æä¸ªæåæ¹æ¬¡åºåï¼æ¥æ¾çäº§å®æ¶æ¶èäºåªäºåæææ¹æ¬¡ |
| | | SQL è·¯å¾ï¼å
¥åºæç»(ppd) â å
¥åºå(pp) â æ¶èå(ic) â æ¶èæç»(icd) |
| | | SQL è·¯å¾ï¼åºåäºå¡(äº§åº IN) â 产åºå â æ¥å·¥è®°å½ â åºåäºå¡(æ¶è OUT) â æ¹æ¬¡ |
| | | --> |
| | | <select id="selectListByBackward" parameterType="String" resultMap="BatchTraceResult"> |
| | | SELECT DISTINCT ic.work_order_id, icd.item_id, icd.batch_id, icd.batch_code |
| | | FROM mes_wm_product_produce_detail ppd |
| | | LEFT JOIN mes_wm_product_produce pp ON ppd.produce_id = pp.id AND pp.deleted = 0 |
| | | LEFT JOIN mes_wm_item_consume ic ON pp.work_order_id = ic.work_order_id AND ic.deleted = 0 |
| | | LEFT JOIN mes_wm_item_consume_detail icd ON ic.id = icd.consume_id AND icd.deleted = 0 |
| | | WHERE ppd.batch_code = #{batchCode} |
| | | AND ppd.deleted = 0 |
| | | AND icd.batch_code IS NOT NULL |
| | | FROM mes_wm_transaction tx_produce |
| | | LEFT JOIN mes_wm_product_produce pp ON tx_produce.biz_id = pp.id AND tx_produce.biz_type = 124 AND pp.deleted = 0 |
| | | LEFT JOIN mes_pro_feedback pf ON pf.id = pp.feedback_id AND pf.deleted = 0 |
| | | LEFT JOIN mes_wm_transaction tx_consume ON tx_consume.biz_id = pf.id AND tx_consume.biz_type = 123 AND tx_consume.deleted = 0 |
| | | LEFT JOIN mes_wm_item_consume ic ON tx_consume.biz_id = ic.id AND tx_consume.biz_type = 123 AND ic.deleted = 0 |
| | | WHERE tx_produce.batch_code = #{batchCode} |
| | | AND tx_produce.biz_type = 124 |
| | | AND tx_produce.deleted = 0 |
| | | AND tx_consume.batch_id IS NOT NULL |
| | | </select> |
| | | |
| | | </mapper> |