浏览代码

三级校审复核问题汇总部分代码

徐滕 2 周之前
父节点
当前提交
12bc30cd29
共有 15 个文件被更改,包括 845 次插入 和 0 次删除
  1. 83 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/controller/CommonIssueController.java
  2. 61 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/domain/CommonIssue.java
  3. 58 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/dto/CommonIssueDto.java
  4. 24 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/mapper/CommonIssueMapper.java
  5. 59 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/mapper/xml/CommonIssueMapper.xml
  6. 66 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/service/CommonIssueService.java
  7. 17 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/service/mapstruct/CommonIssueWrapper.java
  8. 82 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/controller/IssueRecordController.java
  9. 53 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/domain/IssueRecord.java
  10. 50 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/dto/IssueRecordDto.java
  11. 28 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/mapper/IssueRecordMapper.java
  12. 55 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/mapper/xml/IssueRecordMapper.xml
  13. 91 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/service/IssueRecordService.java
  14. 17 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/service/mapstruct/IssueRecordWrapper.java
  15. 101 0
      jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/workContract/service/dto/WorkContractExportDTO.java

+ 83 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/controller/CommonIssueController.java

@@ -0,0 +1,83 @@
+package com.jeeplus.assess.program.commonIssue.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.assess.program.commonIssue.domain.CommonIssue;
+import com.jeeplus.assess.program.commonIssue.dto.CommonIssueDto;
+import com.jeeplus.assess.program.commonIssue.service.CommonIssueService;
+import com.jeeplus.logging.annotation.ApiLog;
+import io.swagger.annotations.Api;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+
+@Api("常见漏洞字典管理")
+@RestController
+@RequestMapping(value = "/program/commonIssue")
+public class CommonIssueController {
+
+    @Resource
+    private CommonIssueService commonIssueService;
+
+    @ApiLog("查询常见漏洞字典列表")
+    @PreAuthorize("hasAuthority('program:commonIssue:list')")
+    @GetMapping("list")
+    public ResponseEntity<IPage<CommonIssueDto>> data(CommonIssueDto dto, Page<CommonIssueDto> page) throws Exception {
+        page.setSize(-1);
+        QueryWrapper<CommonIssue> queryWrapper = new QueryWrapper<>();
+        if (ObjectUtil.isNotEmpty(dto)) {
+            if (StringUtils.isNotBlank(dto.getIssueName())) {
+                queryWrapper.like("ci.issue_name", dto.getIssueName());
+            }
+            if (StringUtils.isNotBlank(dto.getCategory())) {
+                queryWrapper.eq("ci.category", dto.getCategory());
+            }
+            if (StringUtils.isNotBlank(dto.getAuditLevel())) {
+                queryWrapper.eq("ci.audit_level", dto.getAuditLevel());
+            }
+            if (StringUtils.isNotBlank(dto.getStatus())) {
+                queryWrapper.eq("ci.status", dto.getStatus());
+            }
+        }
+        IPage<CommonIssueDto> result = commonIssueService.findPageList(page, queryWrapper);
+        return ResponseEntity.ok(result);
+    }
+
+    @ApiLog("查询常见漏洞字典详情")
+    @PreAuthorize("hasAnyAuthority('program:commonIssue:view','program:commonIssue:add','program:commonIssue:edit')")
+    @GetMapping("queryById")
+    public ResponseEntity queryById(@RequestParam("id") String id) {
+        CommonIssueDto dto = commonIssueService.queryById(id);
+        return ResponseEntity.ok(dto);
+    }
+
+    @ApiLog("保存常见漏洞字典")
+    @PreAuthorize("hasAnyAuthority('program:commonIssue:save','program:commonIssue:edit')")
+    @PostMapping("save")
+    public ResponseEntity save(@Valid @RequestBody CommonIssueDto dto) {
+        return commonIssueService.save(dto);
+    }
+
+    @ApiLog("删除常见漏洞字典")
+    @PreAuthorize("hasAuthority('program:commonIssue:del')")
+    @DeleteMapping("delete")
+    public ResponseEntity delete(String ids) {
+        return commonIssueService.deleteByIds(ids);
+    }
+
+    /**
+     * 查询启用的漏洞列表(供驳回对话框使用)
+     * @param auditLevel 校审级别(1/2/3)
+     */
+    @ApiLog("查询启用的漏洞列表")
+    @GetMapping("getEnabledList")
+    public ResponseEntity getEnabledList(@RequestParam(value = "auditLevel", required = false) String auditLevel) {
+        return ResponseEntity.ok(commonIssueService.getEnabledList(auditLevel));
+    }
+}

+ 61 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/domain/CommonIssue.java

@@ -0,0 +1,61 @@
+package com.jeeplus.assess.program.commonIssue.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 常见漏洞字典表
+ * @TableName program_common_issue
+ */
+@Data
+@TableName(value = "program_common_issue")
+public class CommonIssue extends BaseEntity {
+
+    /**
+     * 漏洞名称
+     */
+    private String issueName;
+
+    /**
+     * 漏洞描述
+     */
+    private String issueDesc;
+
+    /**
+     * 整改建议
+     */
+    private String suggestion;
+
+    /**
+     * 分类
+     */
+    private String category;
+
+    /**
+     * 适用校审级别(1/2/3)
+     */
+    private String auditLevel;
+
+    /**
+     * 提醒阈值(累计几次触发提醒)
+     */
+    private Integer threshold;
+
+    /**
+     * 重置周期(月),为空则永不重置提醒
+     */
+    private Integer resetMonths;
+
+    /**
+     * 排序
+     */
+    private Integer sortOrder;
+
+    /**
+     * 状态(0停用 1启用)
+     */
+    private String status;
+
+    private static final long serialVersionUID = 1L;
+}

+ 58 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/dto/CommonIssueDto.java

@@ -0,0 +1,58 @@
+package com.jeeplus.assess.program.commonIssue.dto;
+
+import com.jeeplus.core.service.dto.BaseDTO;
+import lombok.Data;
+
+/**
+ * 常见漏洞字典 DTO
+ */
+@Data
+public class CommonIssueDto extends BaseDTO {
+
+    /**
+     * 漏洞名称
+     */
+    private String issueName;
+
+    /**
+     * 漏洞描述
+     */
+    private String issueDesc;
+
+    /**
+     * 整改建议
+     */
+    private String suggestion;
+
+    /**
+     * 分类
+     */
+    private String category;
+
+    /**
+     * 适用校审级别(1/2/3)
+     */
+    private String auditLevel;
+
+    /**
+     * 提醒阈值
+     */
+    private Integer threshold;
+
+    /**
+     * 重置周期(月)
+     */
+    private Integer resetMonths;
+
+    /**
+     * 排序
+     */
+    private Integer sortOrder;
+
+    /**
+     * 状态(0停用 1启用)
+     */
+    private String status;
+
+    private static final long serialVersionUID = 1L;
+}

+ 24 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/mapper/CommonIssueMapper.java

@@ -0,0 +1,24 @@
+package com.jeeplus.assess.program.commonIssue.mapper;
+
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.assess.program.commonIssue.domain.CommonIssue;
+import com.jeeplus.assess.program.commonIssue.dto.CommonIssueDto;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 常见漏洞字典表 Mapper
+ */
+@Mapper
+@InterceptorIgnore(tenantLine = "true")
+public interface CommonIssueMapper extends BaseMapper<CommonIssue> {
+
+    IPage<CommonIssueDto> findPageList(Page<CommonIssueDto> page, @Param(Constants.WRAPPER) QueryWrapper<CommonIssue> queryWrapper);
+
+    CommonIssueDto queryById(@Param("id") String id);
+}

+ 59 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/mapper/xml/CommonIssueMapper.xml

@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.assess.program.commonIssue.mapper.CommonIssueMapper">
+
+    <resultMap id="BaseResultMap" type="com.jeeplus.assess.program.commonIssue.dto.CommonIssueDto">
+        <id property="id" column="id" jdbcType="VARCHAR"/>
+        <result property="issueName" column="issue_name" jdbcType="VARCHAR"/>
+        <result property="issueDesc" column="issue_desc" jdbcType="VARCHAR"/>
+        <result property="suggestion" column="suggestion" jdbcType="VARCHAR"/>
+        <result property="category" column="category" jdbcType="VARCHAR"/>
+        <result property="auditLevel" column="audit_level" jdbcType="VARCHAR"/>
+        <result property="threshold" column="threshold" jdbcType="INTEGER"/>
+        <result property="resetMonths" column="reset_months" jdbcType="INTEGER"/>
+        <result property="sortOrder" column="sort_order" jdbcType="INTEGER"/>
+        <result property="status" column="status" jdbcType="CHAR"/>
+        <result property="createById" column="create_by_id" jdbcType="VARCHAR"/>
+        <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+        <result property="updateById" column="update_by_id" jdbcType="VARCHAR"/>
+        <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+        <result property="delFlag" column="del_flag" jdbcType="INTEGER"/>
+        <result property="remarks" column="remarks" jdbcType="VARCHAR"/>
+        <result property="tenantId" column="tenant_id" jdbcType="VARCHAR"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        ci.id,
+        ci.issue_name,
+        ci.issue_desc,
+        ci.suggestion,
+        ci.category,
+        ci.audit_level,
+        ci.threshold,
+        ci.reset_months,
+        ci.sort_order,
+        ci.status,
+        ci.create_by_id,
+        ci.create_time,
+        ci.update_by_id,
+        ci.update_time,
+        ci.del_flag,
+        ci.remarks,
+        ci.tenant_id
+    </sql>
+
+    <select id="findPageList" resultMap="BaseResultMap">
+        SELECT
+        <include refid="Base_Column_List"/>
+        FROM program_common_issue ci
+        ${ew.customSqlSegment}
+    </select>
+
+    <select id="queryById" resultMap="BaseResultMap">
+        SELECT
+        <include refid="Base_Column_List"/>
+        FROM program_common_issue ci
+        WHERE ci.del_flag = 0 AND ci.id = #{id}
+    </select>
+
+</mapper>

+ 66 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/service/CommonIssueService.java

@@ -0,0 +1,66 @@
+package com.jeeplus.assess.program.commonIssue.service;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.collect.Lists;
+import com.jeeplus.assess.program.commonIssue.domain.CommonIssue;
+import com.jeeplus.assess.program.commonIssue.dto.CommonIssueDto;
+import com.jeeplus.assess.program.commonIssue.mapper.CommonIssueMapper;
+import com.jeeplus.assess.program.commonIssue.service.mapstruct.CommonIssueWrapper;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+@Transactional
+public class CommonIssueService extends ServiceImpl<CommonIssueMapper, CommonIssue> {
+
+    @Resource
+    private CommonIssueMapper commonIssueMapper;
+
+    public IPage<CommonIssueDto> findPageList(Page<CommonIssueDto> page, QueryWrapper<CommonIssue> queryWrapper) {
+        queryWrapper.eq("ci.del_flag", 0).orderByAsc("ci.sort_order");
+        return commonIssueMapper.findPageList(page, queryWrapper);
+    }
+
+    public CommonIssueDto queryById(String id) {
+        return commonIssueMapper.queryById(id);
+    }
+
+    public ResponseEntity save(CommonIssueDto dto) {
+        CommonIssue entity = CommonIssueWrapper.INSTANCE.toEntity(dto);
+        this.saveOrUpdate(entity);
+        return ResponseEntity.ok("保存成功");
+    }
+
+    public ResponseEntity deleteByIds(String ids) {
+        String[] idArray = ids.split(",");
+        if (CollectionUtil.isNotEmpty(Lists.newArrayList(idArray))) {
+            this.removeByIds(Lists.newArrayList(idArray));
+        }
+        return ResponseEntity.ok("删除成功");
+    }
+
+    /**
+     * 查询所有启用的漏洞字典(按级别筛选)
+     * @param auditLevel 校审级别,为空则查全部
+     */
+    public List<CommonIssue> getEnabledList(String auditLevel) {
+        QueryWrapper<CommonIssue> wrapper = new QueryWrapper<>();
+        wrapper.eq("del_flag", 0).eq("status", "1");
+        if (StrUtil.isNotBlank(auditLevel)) {
+            wrapper.and(w -> w.eq("audit_level", auditLevel).or().eq("audit_level", "0"));
+        }
+        wrapper.orderByAsc("category", "sort_order");
+        return this.list(wrapper);
+    }
+}

+ 17 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/commonIssue/service/mapstruct/CommonIssueWrapper.java

@@ -0,0 +1,17 @@
+package com.jeeplus.assess.program.commonIssue.service.mapstruct;
+
+import com.jeeplus.assess.program.commonIssue.domain.CommonIssue;
+import com.jeeplus.assess.program.commonIssue.dto.CommonIssueDto;
+import com.jeeplus.core.mapstruct.EntityWrapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+import org.mapstruct.factory.Mappers;
+
+/**
+ * CommonIssue Wrapper
+ */
+@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE, uses = {})
+public interface CommonIssueWrapper extends EntityWrapper<CommonIssueDto, CommonIssue> {
+
+    CommonIssueWrapper INSTANCE = Mappers.getMapper(CommonIssueWrapper.class);
+}

+ 82 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/controller/IssueRecordController.java

@@ -0,0 +1,82 @@
+package com.jeeplus.assess.program.issueRecord.controller;
+
+import com.jeeplus.assess.program.issueRecord.service.IssueRecordService;
+import com.jeeplus.logging.annotation.ApiLog;
+import io.swagger.annotations.Api;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+
+@Api("漏洞标记记录管理")
+@RestController
+@RequestMapping(value = "/program/issueRecord")
+public class IssueRecordController {
+
+    @Resource
+    private IssueRecordService issueRecordService;
+
+    /**
+     * 批量保存漏洞标记记录(驳回时调用)
+     */
+    @ApiLog("保存漏洞标记记录")
+    @PreAuthorize("hasAuthority('program:issueRecord:save')")
+    @PostMapping("saveRecords")
+    public ResponseEntity saveRecords(@RequestBody SaveRecordsParam param) {
+        return issueRecordService.saveIssueRecords(
+                param.getProjectId(),
+                param.getAuditId(),
+                param.getAuditLevel(),
+                param.getIssueIds(),
+                param.getTargetUserId()
+        );
+    }
+
+    /**
+     * 删除标记记录(管理员操作)
+     */
+    @ApiLog("删除漏洞标记记录")
+    @PreAuthorize("hasAuthority('program:issueRecord:del')")
+    @DeleteMapping("delete")
+    public ResponseEntity delete(String ids) {
+        return issueRecordService.deleteByIds(ids);
+    }
+
+    /**
+     * 查询用户超过阈值的漏洞提醒
+     * @param targetUserId 被标记人ID
+     * @param auditLevel 校审级别
+     */
+    @ApiLog("查询漏洞提醒")
+    @GetMapping("getReminders")
+    public ResponseEntity<List<Map<String, Object>>> getReminders(
+            @RequestParam("targetUserId") String targetUserId,
+            @RequestParam("auditLevel") String auditLevel) {
+        return ResponseEntity.ok(issueRecordService.findOverThresholdIssues(targetUserId, auditLevel));
+    }
+
+    /**
+     * 请求参数封装
+     */
+    public static class SaveRecordsParam {
+        private String projectId;
+        private String auditId;
+        private String auditLevel;
+        private List<String> issueIds;
+        private String targetUserId;
+
+        public String getProjectId() { return projectId; }
+        public void setProjectId(String projectId) { this.projectId = projectId; }
+        public String getAuditId() { return auditId; }
+        public void setAuditId(String auditId) { this.auditId = auditId; }
+        public String getAuditLevel() { return auditLevel; }
+        public void setAuditLevel(String auditLevel) { this.auditLevel = auditLevel; }
+        public List<String> getIssueIds() { return issueIds; }
+        public void setIssueIds(List<String> issueIds) { this.issueIds = issueIds; }
+        public String getTargetUserId() { return targetUserId; }
+        public void setTargetUserId(String targetUserId) { this.targetUserId = targetUserId; }
+    }
+}

+ 53 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/domain/IssueRecord.java

@@ -0,0 +1,53 @@
+package com.jeeplus.assess.program.issueRecord.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 漏洞标记记录表
+ * @TableName program_issue_record
+ */
+@Data
+@TableName(value = "program_issue_record")
+public class IssueRecord extends BaseEntity {
+
+    /**
+     * 项目ID
+     */
+    private String projectId;
+
+    /**
+     * 校审记录ID(关联program_audit)
+     */
+    private String auditId;
+
+    /**
+     * 校审级别(1/2/3)
+     */
+    private String auditLevel;
+
+    /**
+     * 漏洞ID(关联program_common_issue)
+     */
+    private String issueId;
+
+    /**
+     * 被标记人ID
+     */
+    private String targetUserId;
+
+    /**
+     * 标记人(审核人)ID
+     */
+    private String markUserId;
+
+    /**
+     * 标记时间
+     */
+    private Date markTime;
+
+    private static final long serialVersionUID = 1L;
+}

+ 50 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/dto/IssueRecordDto.java

@@ -0,0 +1,50 @@
+package com.jeeplus.assess.program.issueRecord.dto;
+
+import com.jeeplus.core.service.dto.BaseDTO;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 漏洞标记记录 DTO
+ */
+@Data
+public class IssueRecordDto extends BaseDTO {
+
+    /**
+     * 项目ID
+     */
+    private String projectId;
+
+    /**
+     * 校审记录ID
+     */
+    private String auditId;
+
+    /**
+     * 校审级别
+     */
+    private String auditLevel;
+
+    /**
+     * 漏洞ID
+     */
+    private String issueId;
+
+    /**
+     * 被标记人ID
+     */
+    private String targetUserId;
+
+    /**
+     * 标记人ID
+     */
+    private String markUserId;
+
+    /**
+     * 标记时间
+     */
+    private Date markTime;
+
+    private static final long serialVersionUID = 1L;
+}

+ 28 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/mapper/IssueRecordMapper.java

@@ -0,0 +1,28 @@
+package com.jeeplus.assess.program.issueRecord.mapper;
+
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.assess.program.issueRecord.domain.IssueRecord;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 漏洞标记记录表 Mapper
+ */
+@Mapper
+@InterceptorIgnore(tenantLine = "true")
+public interface IssueRecordMapper extends BaseMapper<IssueRecord> {
+
+    /**
+     * 查询用户在各校审级别下超过阈值的漏洞提醒
+     * @param targetUserId 被标记人ID
+     * @param auditLevel 校审级别(1/2/3)
+     * @return 超过阈值的漏洞列表(含累计次数)
+     */
+    List<Map<String, Object>> findOverThresholdIssues(@Param("targetUserId") String targetUserId,
+                                                       @Param("auditLevel") String auditLevel);
+
+}

+ 55 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/mapper/xml/IssueRecordMapper.xml

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.assess.program.issueRecord.mapper.IssueRecordMapper">
+
+    <resultMap id="BaseResultMap" type="com.jeeplus.assess.program.issueRecord.domain.IssueRecord">
+        <id column="id" property="id"/>
+        <result column="project_id" property="projectId"/>
+        <result column="audit_id" property="auditId"/>
+        <result column="audit_level" property="auditLevel"/>
+        <result column="issue_id" property="issueId"/>
+        <result column="target_user_id" property="targetUserId"/>
+        <result column="mark_user_id" property="markUserId"/>
+        <result column="mark_time" property="markTime"/>
+        <result column="create_by_id" property="createById"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_by_id" property="updateById"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="del_flag" property="delFlag"/>
+        <result column="remarks" property="remarks"/>
+        <result column="tenant_id" property="tenantId"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        r.id, r.project_id, r.audit_id, r.audit_level, r.issue_id,
+        r.target_user_id, r.mark_user_id, r.mark_time,
+        r.create_by_id, r.create_time, r.update_by_id, r.update_time,
+        r.del_flag, r.remarks, r.tenant_id
+    </sql>
+
+    <!-- 查询用户在各校审级别下超过阈值的漏洞提醒 -->
+    <select id="findOverThresholdIssues" resultType="java.util.Map">
+        SELECT
+            ci.id AS issueId,
+            ci.issue_name AS issueName,
+            ci.issue_desc AS issueDesc,
+            ci.suggestion AS suggestion,
+            ci.category AS category,
+            ci.audit_level AS auditLevel,
+            ci.threshold AS threshold,
+            ci.reset_months AS resetMonths,
+            COUNT(r.id) AS markCount
+        FROM program_issue_record r
+        INNER JOIN program_common_issue ci ON r.issue_id = ci.id AND ci.del_flag = 0 AND ci.status = '1'
+        WHERE r.del_flag = 0
+          AND r.target_user_id = #{targetUserId}
+          AND r.audit_level = #{auditLevel}
+        <if test="resetMonths != null">
+          AND r.mark_time >= DATE_SUB(NOW(), INTERVAL #{resetMonths} MONTH)
+        </if>
+        GROUP BY ci.id, ci.issue_name, ci.issue_desc, ci.suggestion, ci.category, ci.audit_level, ci.threshold, ci.reset_months
+        HAVING COUNT(r.id) >= ci.threshold
+        ORDER BY ci.category, ci.sort_order
+    </select>
+
+</mapper>

+ 91 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/service/IssueRecordService.java

@@ -0,0 +1,91 @@
+package com.jeeplus.assess.program.issueRecord.service;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jeeplus.assess.program.commonIssue.mapper.CommonIssueMapper;
+import com.jeeplus.assess.program.issueRecord.domain.IssueRecord;
+import com.jeeplus.assess.program.issueRecord.mapper.IssueRecordMapper;
+import com.jeeplus.sys.feign.IUserApi;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.*;
+
+@Service
+@Transactional
+public class IssueRecordService extends ServiceImpl<IssueRecordMapper, IssueRecord> {
+
+    @Resource
+    private IssueRecordMapper issueRecordMapper;
+
+    @Resource
+    private CommonIssueMapper commonIssueMapper;
+
+    /**
+     * 批量保存漏洞标记记录(驳回时调用)
+     * @param projectId 项目ID
+     * @param auditId 校审记录ID
+     * @param auditLevel 校审级别
+     * @param issueIds 选中的漏洞ID列表
+     * @param targetUserId 被标记人(提交人)ID
+     */
+    public ResponseEntity saveIssueRecords(String projectId, String auditId, String auditLevel,
+                                            List<String> issueIds, String targetUserId) {
+        if (issueIds == null || issueIds.isEmpty()) {
+            return ResponseEntity.ok("保存成功");
+        }
+        String currentUserId = SpringUtil.getBean(IUserApi.class).getById(targetUserId).getId();
+        Date now = new Date();
+        for (String issueId : issueIds) {
+            IssueRecord record = new IssueRecord();
+            record.setId(UUID.randomUUID().toString().replace("-", ""));
+            record.setProjectId(projectId);
+            record.setAuditId(auditId);
+            record.setAuditLevel(auditLevel);
+            record.setIssueId(issueId);
+            record.setTargetUserId(targetUserId);
+            record.setMarkUserId(currentUserId);
+            record.setMarkTime(now);
+            record.setDelFlag(0);
+            record.setCreateById(currentUserId);
+            record.setCreateTime(now);
+            this.save(record);
+        }
+        return ResponseEntity.ok("保存成功");
+    }
+
+    /**
+     * 删除标记记录(管理员操作)
+     */
+    public ResponseEntity deleteByIds(String ids) {
+        String[] idArray = ids.split(",");
+        this.removeByIds(Arrays.asList(idArray));
+        return ResponseEntity.ok("删除成功");
+    }
+
+    /**
+     * 查询用户在各校审级别下超过阈值的漏洞提醒
+     * @param targetUserId 被标记人ID
+     * @param auditLevel 校审级别
+     * @return 超过阈值的漏洞列表
+     */
+    public List<Map<String, Object>> findOverThresholdIssues(String targetUserId, String auditLevel) {
+        if (StrUtil.isBlank(targetUserId) || StrUtil.isBlank(auditLevel)) {
+            return Collections.emptyList();
+        }
+        return issueRecordMapper.findOverThresholdIssues(targetUserId, auditLevel);
+    }
+
+    /**
+     * 删除某条校审记录关联的所有漏洞标记(用于管理员删除校审记录时联动)
+     */
+    public void deleteByAuditId(String auditId) {
+        if (StrUtil.isNotBlank(auditId)) {
+            this.remove(new QueryWrapper<IssueRecord>().eq("audit_id", auditId));
+        }
+    }
+}

+ 17 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/program/issueRecord/service/mapstruct/IssueRecordWrapper.java

@@ -0,0 +1,17 @@
+package com.jeeplus.assess.program.issueRecord.service.mapstruct;
+
+import com.jeeplus.assess.program.issueRecord.domain.IssueRecord;
+import com.jeeplus.assess.program.issueRecord.dto.IssueRecordDto;
+import com.jeeplus.core.mapstruct.EntityWrapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+import org.mapstruct.factory.Mappers;
+
+/**
+ * IssueRecord Wrapper
+ */
+@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE, uses = {})
+public interface IssueRecordWrapper extends EntityWrapper<IssueRecordDto, IssueRecord> {
+
+    IssueRecordWrapper INSTANCE = Mappers.getMapper(IssueRecordWrapper.class);
+}

+ 101 - 0
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/workContract/service/dto/WorkContractExportDTO.java

@@ -0,0 +1,101 @@
+package com.jeeplus.assess.workContract.service.dto;
+
+import cn.afterturn.easypoi.excel.annotation.Excel;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 合同登记-导出Excel专用DTO
+ * 字段与列表页展示列保持一致,列顺序由 orderNum 控制;合同类型通过 dict 翻译,三个状态列由后端预翻译为中文
+ */
+@Data
+public class WorkContractExportDTO {
+
+    /**
+     * 合同编号
+     */
+    @Excel(name = "合同编号", orderNum = "1", width = 25)
+    private String no;
+
+    /**
+     * 合同名称
+     */
+    @Excel(name = "合同名称", orderNum = "2", width = 30)
+    private String name;
+
+    /**
+     * 案卷号
+     */
+    @Excel(name = "案卷号", orderNum = "3", width = 20)
+    private String filedNo;
+
+    /**
+     * 项目名称(报告号对应的项目,多个以逗号拼接)
+     */
+    @Excel(name = "项目名称", orderNum = "4", width = 30)
+    private String programNames;
+
+    /**
+     * 关联报告号(多个报告号以逗号拼接)
+     */
+    @Excel(name = "关联报告号", orderNum = "5", width = 30)
+    private String reportNos;
+
+    /**
+     * 客户名称
+     */
+    @Excel(name = "客户名称", orderNum = "6", width = 25)
+    private String clientName;
+
+    /**
+     * 合同类型
+     */
+    @Excel(name = "合同类型", orderNum = "7", width = 15, dict = "contract_type")
+    private String contractType;
+
+    /**
+     * 合同金额类别
+     */
+    @Excel(name = "合同金额类别", orderNum = "7", width = 15, dict = "contract_amount_type")
+    private String contractAmountType;
+
+    /**
+     * 合同金额(元)
+     */
+    @Excel(name = "合同金额(元)", orderNum = "8", width = 15)
+    private String contractAmount;
+
+    /**
+     * 签订日期
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "签订日期", orderNum = "9", width = 18, exportFormat = "yyyy-MM-dd")
+    private Date contractDate;
+
+    /**
+     * 创建人
+     */
+    @Excel(name = "创建人", orderNum = "10", width = 15)
+    private String createById;
+
+    /**
+     * 登记状态(后端已翻译为中文,含审批中/驳回/撤回等)
+     */
+    @Excel(name = "登记状态", orderNum = "11", width = 15)
+    private String status;
+
+    /**
+     * 归档状态(后端已翻译为中文,未发起为未归档)
+     */
+    @Excel(name = "归档状态", orderNum = "12", width = 15)
+    private String filedType;
+
+    /**
+     * 作废状态(后端已翻译为中文,未发起为未作废)
+     */
+    @Excel(name = "作废状态", orderNum = "13", width = 15)
+    private String cancelStatus;
+
+}