gaoluyang
昨天 8c65f898ed6e5b0c7a94c792c4562f6ec831dccd
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));
        });
    }