瀏覽代碼

审批流快完了

yanghao 1 天之前
父節點
當前提交
c21dc128bb

+ 7 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchProject/ResearchProjectController.java

@@ -92,6 +92,13 @@ public class ResearchProjectController {
 
     // ==================== 审批流 ====================
 
+    @GetMapping("/todo-page")
+    @Operation(summary = "待我审批的项目分页")
+    @PreAuthorize("@ss.hasPermission('rd:project:query')")
+    public CommonResult<PageResult<ProjectRespVO>> getTodoPage(@Valid ProjectPageReqVO pageReqVO) {
+        return success(projectService.getTodoPage(pageReqVO));
+    }
+
     @PostMapping("/submit-pre")
     @Operation(summary = "提交预审")
     @Parameter(name = "id", description = "项目ID", required = true)

+ 23 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchProject/vo/ProjectAttachmentVO.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.rd.controller.admin.researchProject.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+public class ProjectAttachmentVO {
+
+    @Schema(description = "文件名", example = "立项申请表.pdf")
+    private String fileName;
+
+    @Schema(description = "文件MIME类型", example = "application/pdf")
+    private String fileType;
+
+    @Schema(description = "文件大小(字节)", example = "3088617")
+    private Long fileSize;
+
+    @Schema(description = "文件访问路径", example = "https://xxx.com/file/xxx.pdf")
+    private String filePath;
+
+    @Schema(description = "附件类型:APPLICATION-立项申请表 OPENING_REPORT-开题报告 OTHER-其他", example = "APPLICATION")
+    private String type;
+}

+ 60 - 27
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchProject/vo/ProjectRespVO.java

@@ -1,4 +1,5 @@
 package cn.iocoder.yudao.module.rd.controller.admin.researchProject.vo;
+
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -8,13 +9,18 @@ import java.time.LocalDateTime;
 import java.util.List;
 
 @Schema(description = "管理后台 - 项目立项 Response VO")
-
 @Data
 public class ProjectRespVO {
 
     @Schema(description = "主键ID", example = "1024")
     private Long id;
 
+    @Schema(description = "所属部门(专业公司)ID", example = "100")
+    private Long deptId;
+
+    @Schema(description = "所属部门名称", example = "XX石油技术公司")
+    private String deptName;
+
     @Schema(description = "项目级别", example = "国家级")
     private String projectLevel;
 
@@ -22,7 +28,7 @@ public class ProjectRespVO {
     private Long executingUnit;
 
     @Schema(description = "执行单位名称", example = "XX石油技术公司")
-    private String executingUnitName;   // ⭐ 前端展示用,详情接口里翻译
+    private String executingUnitName;
 
     @Schema(description = "项目名称", example = "智能仓储系统")
     private String projectName;
@@ -45,14 +51,8 @@ public class ProjectRespVO {
     @Schema(description = "创新点")
     private String innovationPoint;
 
-    @Schema(description = "立项申请表文件url")
-    private String applicationFile;
-
-    @Schema(description = "开题报告文件url")
-    private String openingReportFile;
-
-    @Schema(description = "其他文件url")
-    private String otherFile;
+    @Schema(description = "附件列表")
+    private List<ProjectAttachmentVO> attachments;
 
     @Schema(description = "排序值", example = "1")
     private Integer sort;
@@ -66,6 +66,45 @@ public class ProjectRespVO {
     @Schema(description = "创建时间")
     private LocalDateTime createTime;
 
+    // ==================== 预审阶段 ====================
+    @Schema(description = "预审状态:0未提交 1审批中 2通过 3驳回", example = "0")
+    private Integer preAuditStatus;
+
+    @Schema(description = "预审当前节点", example = "11")
+    private Integer preCurrentNode;
+
+    @Schema(description = "预审当前审批人ID", example = "1001")
+    private Long preCurrentApproverId;
+
+    @Schema(description = "预审当前节点角色code", example = "科技发展部负责人")
+    private String preCurrentRoleCode;
+
+    @Schema(description = "预审提交时间")
+    private LocalDateTime preSubmitTime;
+
+    // ==================== 正式立项阶段 ====================
+    @Schema(description = "正式审批状态:0未提交 1审批中 2通过 3驳回", example = "0")
+    private Integer formalAuditStatus;
+
+    @Schema(description = "正式当前节点", example = "21")
+    private Integer formalCurrentNode;
+
+    @Schema(description = "正式当前审批人ID", example = "1002")
+    private Long formalCurrentApproverId;
+
+    @Schema(description = "正式当前节点角色code", example = "技术副总")
+    private String formalCurrentRoleCode;
+
+    @Schema(description = "正式立项提交时间")
+    private LocalDateTime formalSubmitTime;
+
+    @Schema(description = "立项时间(正式立项通过时间)")
+    private LocalDateTime projectDate;
+
+    // ==================== 预算相关 ====================
+    @Schema(description = "是否涉及预算:0否 1是", example = "0")
+    private Integer involveBudget;
+
     // ==================== 子表数据 ====================
 
     @Schema(description = "进度安排列表")
@@ -74,12 +113,14 @@ public class ProjectRespVO {
     @Schema(description = "费用预算明细列表")
     private List<BudgetVO> budgetList;
 
+    @Schema(description = "审批记录列表")
+    private List<ApprovalRecordVO> approvalRecords;
+
     // ==================== 子表 VO ====================
 
     @Schema(description = "管理后台 - 项目进度安排 Response VO")
     @Data
     public static class ScheduleVO {
-
         @Schema(description = "主键ID", example = "1")
         private Long id;
 
@@ -91,13 +132,11 @@ public class ProjectRespVO {
 
         @Schema(description = "排序值", example = "0")
         private Integer sort;
-
     }
 
     @Schema(description = "管理后台 - 项目费用预算 Response VO")
     @Data
     public static class BudgetVO {
-
         @Schema(description = "主键ID", example = "1")
         private Long id;
 
@@ -112,25 +151,19 @@ public class ProjectRespVO {
 
         @Schema(description = "排序值", example = "0")
         private Integer sort;
-
     }
 
-
-    @Schema(description = "审批记录列表")
-    private List<ApprovalRecordVO> approvalRecords;
-
     @Schema(description = "项目审批记录 VO")
     @Data
     public static class ApprovalRecordVO {
         private Long id;
-        private Integer stage;         // 阶段:1预审 2正式
-        private Integer node;          // 节点:11、21、22、23
-        private String nodeName;       // 节点名称
-        private Long approverId;       // 审批人ID
-        private String approverName;   // 审批人姓名
-        private Integer result;        // 结果:1通过 2驳回 3撤回 4提交
-        private String opinion;        // 意见
+        private Integer stage;
+        private Integer node;
+        private String nodeName;
+        private Long approverId;
+        private String approverName;
+        private Integer result;
+        private String opinion;
         private LocalDateTime approveTime;
     }
-
-}
+}

+ 6 - 9
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchProject/vo/ProjectSaveReqVO.java

@@ -15,6 +15,9 @@ public class ProjectSaveReqVO {
     @Schema(description = "主键ID", example = "1024")
     private Long id;
 
+    @Schema(description = "创建部门(专业公司)ID")
+    private Long deptId;
+
     @Schema(description = "项目级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "国家级")
     @NotEmpty(message = "项目级别不能为空")
     private String projectLevel;
@@ -51,18 +54,12 @@ public class ProjectSaveReqVO {
     @Size(max = 500, message = "创新点长度不能超过 500 个字符")
     private String innovationPoint;
 
-    @Schema(description = "立项申请表文件url")
-    private String applicationFile;
-
-    @Schema(description = "开题报告文件url")
-    private String openingReportFile;
-
-    @Schema(description = "其他文件url")
-    private String otherFile;
-
     @Schema(description = "排序值", example = "1")
     private Integer sort;
 
+    @Schema(description = "附件列表")
+    private List<ProjectAttachmentVO> attachments;
+
     @Schema(description = "状态(0启用 1禁用)", example = "0")
     private Integer status;
 

+ 8 - 12
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/dataobject/researchProject/ProjectDO.java

@@ -7,6 +7,10 @@ import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.*;
 
 import java.time.LocalDateTime;
+import java.util.List;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import cn.iocoder.yudao.module.rd.controller.admin.researchProject.vo.ProjectAttachmentVO;
 
 /**
  * 项目立项 DO
@@ -66,18 +70,10 @@ public class ProjectDO extends BaseDO {
      * 创新点
      */
     private String innovationPoint;
-    /**
-     * 立项申请表文件url
-     */
-    private String applicationFile;
-    /**
-     * 开题报告文件url
-     */
-    private String openingReportFile;
-    /**
-     * 其他文件url
-     */
-    private String otherFile;
+
+    /** 附件列表(JSON) */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private List<ProjectAttachmentVO> attachments;
     /**
      * 排序值
      */

+ 16 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/mysql/researchProject/ProjectMapper.java

@@ -8,6 +8,8 @@ import cn.iocoder.yudao.module.rd.dal.dataobject.researchProject.ProjectDO;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Select;
 
+
+
 import java.util.List;
 
 /**
@@ -50,4 +52,18 @@ public interface ProjectMapper extends BaseMapperX<ProjectDO> {
     @Select("SELECT IFNULL(MAX(sort), 0) FROM rd_project WHERE deleted = 0")
     Integer selectMaxSort();
 
+
+    default PageResult<ProjectDO> selectTodoPage(ProjectPageReqVO reqVO, Long userId) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<ProjectDO>()
+                .likeIfPresent(ProjectDO::getProjectName, reqVO.getProjectName())   // ⭐ 放到前面
+                .and(w -> w
+                        .and(x -> x
+                                .eq(ProjectDO::getPreAuditStatus, 1)
+                                .eq(ProjectDO::getPreCurrentApproverId, userId))
+                        .or(x -> x
+                                .eq(ProjectDO::getFormalAuditStatus, 1)
+                                .eq(ProjectDO::getFormalCurrentApproverId, userId)))
+                .orderByDesc(ProjectDO::getId));
+    }
+
 }

+ 4 - 1
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/service/researchProject/ResearchProjectService.java

@@ -10,6 +10,8 @@ import cn.iocoder.yudao.module.rd.controller.admin.researchProject.vo.ProjectApp
 import javax.validation.Valid;
 import java.util.List;
 
+
+
 /**
  * 项目立项 Service 接口
  *
@@ -64,8 +66,9 @@ public interface ResearchProjectService {
 
     List<ProjectDO> getProjectList(@Valid ProjectPageReqVO pageReqVO);
 
-
     // ==================== 审批流 ====================
+    /** 待我审批 */
+    PageResult<ProjectRespVO> getTodoPage(ProjectPageReqVO pageReqVO);
 
     /** 提交预审 */
     void submitPreApproval(Long projectId);

+ 90 - 4
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/service/researchProject/ResearchProjectServiceImpl.java

@@ -15,11 +15,17 @@ import javax.annotation.Resource;
 import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Objects;
+import java.util.*;
+import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.rd.enums.ErrorCodeConstant.*;
 import static cn.iocoder.yudao.module.rd.enums.ProjectApprovalConstants.*;
 
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+
 @Service
 @Validated
 public class ResearchProjectServiceImpl implements ResearchProjectService {
@@ -34,6 +40,65 @@ public class ResearchProjectServiceImpl implements ResearchProjectService {
     private ProjectApprovalRecordMapper approvalRecordMapper;
     @Resource
     private ApproverQueryMapper approverQueryMapper;
+    @Resource
+    private DeptApi deptApi;
+
+
+    /**
+     * 单条:填充部门名(deptId 和 executingUnit 两个字段一起翻译)
+     */
+    private void fillDeptNames(ProjectRespVO vo) {
+        if (vo == null) {
+            return;
+        }
+        fillDeptNames(Collections.singletonList(vo));
+    }
+
+    /**
+     * 批量:填充列表里所有项目的部门名
+     */
+    private void fillDeptNames(List<ProjectRespVO> list) {
+        if (CollUtil.isEmpty(list)) {
+            return;
+        }
+        // 1. 收集所有需要的部门 id
+        Set<Long> deptIds = new HashSet<>();
+        for (ProjectRespVO vo : list) {
+            if (vo.getDeptId() != null) deptIds.add(vo.getDeptId());
+            if (vo.getExecutingUnit() != null) deptIds.add(vo.getExecutingUnit());
+        }
+        if (deptIds.isEmpty()) {
+            return;
+        }
+
+        // 2. 一次批量查
+        Map<Long, String> deptNameMap = getDeptNameMap(deptIds);
+
+        // 3. 回填
+        for (ProjectRespVO vo : list) {
+            if (vo.getDeptId() != null) {
+                vo.setDeptName(deptNameMap.get(vo.getDeptId()));
+            }
+            if (vo.getExecutingUnit() != null) {
+                vo.setExecutingUnitName(deptNameMap.get(vo.getExecutingUnit()));
+            }
+        }
+    }
+
+    /**
+     * 调 DeptApi 批量查「id → name」
+     */
+    private Map<Long, String> getDeptNameMap(Set<Long> deptIds) {
+        if (CollUtil.isEmpty(deptIds)) {
+            return Collections.emptyMap();
+        }
+        List<DeptRespDTO> depts = deptApi.getDeptList(deptIds);
+        if (CollUtil.isEmpty(depts)) {
+            return Collections.emptyMap();
+        }
+        return depts.stream()
+                .collect(Collectors.toMap(DeptRespDTO::getId, DeptRespDTO::getName, (a, b) -> a));
+    }
 
     // ==================== 新增 ====================
 
@@ -152,7 +217,12 @@ public class ResearchProjectServiceImpl implements ResearchProjectService {
     @Override
     public PageResult<ProjectRespVO> getProjectPage(ProjectPageReqVO pageReqVO) {
         PageResult<ProjectDO> pageResult = projectMapper.selectPage(pageReqVO);
-        return BeanUtils.toBean(pageResult, ProjectRespVO.class);
+        PageResult<ProjectRespVO> voPage = BeanUtils.toBean(pageResult, ProjectRespVO.class);
+
+        // ⭐ 批量填部门名
+        fillDeptNames(voPage.getList());
+
+        return voPage;
     }
 
     @Override
@@ -162,6 +232,15 @@ public class ResearchProjectServiceImpl implements ResearchProjectService {
 
     // ==================== 提交预审 ====================
 
+    @Override
+    public PageResult<ProjectRespVO> getTodoPage(ProjectPageReqVO pageReqVO) {
+        Long userId = SecurityFrameworkUtils.getLoginUserId();
+        PageResult<ProjectDO> pageResult = projectMapper.selectTodoPage(pageReqVO, userId);
+        PageResult<ProjectRespVO> voPage = BeanUtils.toBean(pageResult, ProjectRespVO.class);
+        fillDeptNames(voPage.getList());
+        return voPage;
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void submitPreApproval(Long projectId) {
@@ -458,11 +537,18 @@ public class ResearchProjectServiceImpl implements ResearchProjectService {
 
     /** 提交预审前的必填校验 */
     private void validateBeforeSubmitPre(ProjectDO project) {
-        // 例:附件必填
-        if (project.getApplicationFile() == null || project.getApplicationFile().isEmpty()) {
+        List<ProjectAttachmentVO> attachments = project.getAttachments();
+        if (CollUtil.isEmpty(attachments)) {
+            throw exception(PROJECT_APPLICATION_FILE_REQUIRED);
+        }
+        boolean hasApplication = attachments.stream()
+                .anyMatch(a -> "APPLICATION".equals(a.getType()));
+        if (!hasApplication) {
             throw exception(PROJECT_APPLICATION_FILE_REQUIRED);
         }
-        if (project.getOpeningReportFile() == null || project.getOpeningReportFile().isEmpty()) {
+        boolean hasOpeningReport = attachments.stream()
+                .anyMatch(a -> "OPENING_REPORT".equals(a.getType()));
+        if (!hasOpeningReport) {
             throw exception(PROJECT_OPENING_REPORT_REQUIRED);
         }
     }