From 8c65f898ed6e5b0c7a94c792c4562f6ec831dccd Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期六, 07 十一月 2026 08:50:53 +0800
Subject: [PATCH] feat: 完善质检、生产、销售、财务与人事模块并接入审批流程

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/MesPdProjectController.java |   89 +++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 83 insertions(+), 6 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/MesPdProjectController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/MesPdProjectController.java
index 88b79d1..046ab2a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/MesPdProjectController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pd/project/MesPdProjectController.java
@@ -12,6 +12,9 @@
 import cn.iocoder.yudao.module.mes.controller.admin.pd.project.vo.MesPdProjectRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.pd.project.vo.MesPdProjectSaveReqVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pd.project.MesPdProjectDO;
+import cn.iocoder.yudao.module.mes.enums.pd.MesPdProjectStatusEnum;
+import cn.iocoder.yudao.module.mes.service.wm.document.MesWmDocumentRenderer;
+import cn.iocoder.yudao.module.system.service.companyconfig.SystemCompanyConfigService;
 import cn.iocoder.yudao.module.mes.service.pd.project.MesPdProjectService;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
@@ -26,16 +29,22 @@
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.time.format.DateTimeFormatter;
 import java.util.Collections;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Stream;
 
 import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PD_PROJECT_NOT_EXISTS;
 
 @Tag(name = "绠$悊鍚庡彴 - MES 璁捐椤圭洰")
 @RestController
@@ -48,6 +57,8 @@
 
     @Resource
     private AdminUserApi adminUserApi;
+    @Resource
+    private SystemCompanyConfigService companyConfigService;
 
     @PostMapping("/create")
     @Operation(summary = "鍒涘缓璁捐椤圭洰")
@@ -76,7 +87,6 @@
     @GetMapping("/get")
     @Operation(summary = "鑾峰緱璁捐椤圭洰")
     @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
-    @PreAuthorize("@ss.hasPermission('mes:pd-project:query')")
     public CommonResult<MesPdProjectRespVO> getProject(@RequestParam("id") Long id) {
         MesPdProjectDO project = projectService.getProject(id);
         if (project == null) {
@@ -87,7 +97,6 @@
 
     @GetMapping("/page")
     @Operation(summary = "鑾峰緱璁捐椤圭洰鍒嗛〉")
-    @PreAuthorize("@ss.hasPermission('mes:pd-project:query')")
     public CommonResult<PageResult<MesPdProjectRespVO>> getProjectPage(@Valid MesPdProjectPageReqVO pageReqVO) {
         PageResult<MesPdProjectDO> pageResult = projectService.getProjectPage(pageReqVO);
         return success(new PageResult<>(buildProjectRespVOList(pageResult.getList()), pageResult.getTotal()));
@@ -104,6 +113,61 @@
         // 瀵煎嚭 Excel
         ExcelUtils.write(response, "璁捐椤圭洰.xls", "鏁版嵁", MesPdProjectRespVO.class,
                 buildProjectRespVOList(list));
+    }
+
+    @GetMapping("/export-word")
+    @Operation(summary = "瀵煎嚭椤圭洰璺熻釜琛� Word锛堣〃澶磋嚜鍔ㄥ~鍏咃紝璺熻釜璁板綍鐣欑┖鍙墜濉級")
+    @Parameter(name = "id", description = "璁捐椤圭洰缂栧彿", required = true)
+    @PreAuthorize("@ss.hasPermission('mes:pd-project:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportProjectTrackingWord(@RequestParam("id") Long id,
+                                          HttpServletResponse response) throws IOException {
+        MesPdProjectDO project = projectService.getProject(id);
+        if (project == null) {
+            throw exception(PD_PROJECT_NOT_EXISTS);
+        }
+        Map<String, String> fields = new LinkedHashMap<>();
+        fields.put("taskCode", project.getTaskCode());
+        fields.put("taskName", project.getTaskName());
+        fields.put("productCode", project.getProductCode());
+        fields.put("productName", project.getProductName());
+        fields.put("version", project.getVersion());
+        fields.put("status", resolveStatusName(project.getStatus()));
+        fields.put("chiefDesigner", resolveUserName(project.getChiefDesigner()));
+        fields.put("reviewer", resolveUserName(project.getReviewer()));
+        fields.put("planFinishTime", project.getPlanFinishTime() == null ? null
+                : project.getPlanFinishTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")));
+        fields.put("printDate", java.time.LocalDate.now().toString());
+        fields.put("remark", project.getRemark());
+
+        var companyConfig = companyConfigService.getCompanyConfig();
+        byte[] content = MesWmDocumentRenderer.renderProjectTracking(fields,
+                companyConfig != null ? companyConfig.getCompanyName() : null);
+        String filename = "椤圭洰璺熻釜琛�-" + project.getTaskCode() + ".docx";
+        String encoded = URLEncoder.encode(filename, StandardCharsets.UTF_8).replace("+", "%20");
+        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+        response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + encoded);
+        response.getOutputStream().write(content);
+    }
+
+    private String resolveStatusName(Integer status) {
+        if (status == null) {
+            return null;
+        }
+        for (MesPdProjectStatusEnum item : MesPdProjectStatusEnum.values()) {
+            if (item.getStatus().equals(status)) {
+                return item.getName();
+            }
+        }
+        return "鏈煡鐘舵��(" + status + ")";
+    }
+
+    private String resolveUserName(Long userId) {
+        if (userId == null) {
+            return null;
+        }
+        AdminUserRespDTO user = adminUserApi.getUser(userId);
+        return user != null ? user.getNickname() : "ID=" + userId;
     }
 
     @PutMapping("/publish")
@@ -124,13 +188,22 @@
         return success(true);
     }
 
-    @PutMapping("/audit")
-    @Operation(summary = "瀹℃牳璁捐椤圭洰锛堝緟瀹℃牳鈫掑緟褰掓。锛�")
+    @PutMapping("/submit-approval")
+    @Operation(summary = "鎻愪氦璁捐椤圭洰瀹℃壒锛堝緟瀹℃牳鈫掑鎵逛腑锛�")
     @Parameter(name = "id", description = "缂栧彿", required = true)
+    @Parameter(name = "processDefinitionKey", description = "娴佺▼瀹氫箟 Key", required = true)
     @PreAuthorize("@ss.hasPermission('mes:pd-project:update')")
-    public CommonResult<Boolean> auditProject(@RequestParam("id") Long id) {
-        projectService.auditProject(id);
+    public CommonResult<Boolean> submitProjectApproval(@RequestParam("id") Long id,
+                                                       @RequestParam("processDefinitionKey") String processDefinitionKey) {
+        projectService.submitProjectApproval(id, processDefinitionKey);
         return success(true);
+    }
+
+    @GetMapping("/approve-process-list")
+    @Operation(summary = "鑾峰緱璁捐椤圭洰瀹℃壒娴佺▼鍒楄〃")
+    @PreAuthorize("@ss.hasPermission('mes:pd-project:update')")
+    public CommonResult<List<Map<String, Object>>> getProjectApproveProcessDefinitionList() {
+        return success(projectService.getProjectApproveProcessDefinitionList());
     }
 
     @PutMapping("/archive")
@@ -151,12 +224,16 @@
         // 1.1 鎵归噺鑾峰彇鍏宠仈鏁版嵁锛堜富璁捐甯� + 瀹℃牳浜猴級
         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSetByFlatMap(list,
                 project -> Stream.of(project.getChiefDesigner(), project.getReviewer())));
+        // 1.2 鎵归噺鑾峰彇鍚勯」鐩緟瀹℃牳鏂囦欢鏁�
+        Map<Long, Integer> pendingAuditCountMap = projectService.getPendingAuditCountMap(
+                convertSet(list, MesPdProjectDO::getId));
         // 2. 鎷兼帴 VO
         return BeanUtils.toBean(list, MesPdProjectRespVO.class, vo -> {
             MapUtils.findAndThen(userMap, vo.getChiefDesigner(),
                     user -> vo.setChiefDesignerNickname(user.getNickname()));
             MapUtils.findAndThen(userMap, vo.getReviewer(),
                     user -> vo.setReviewerNickname(user.getNickname()));
+            vo.setPendingAuditCount(pendingAuditCountMap.getOrDefault(vo.getId(), 0));
         });
     }
 

--
Gitblit v1.9.3