Просмотр исходного кода

研究成果 相关 扩展属性

zhangcl 22 часов назад
Родитель
Сommit
67778e1e3b
25 измененных файлов с 1628 добавлено и 6 удалено
  1. 1 1
      yudao-module-rd/yudao-module-rd-api/src/main/java/cn/iocoder/yudao/module/rd/enums/AttachmentCategoryEnum.java
  2. 7 5
      yudao-module-rd/yudao-module-rd-api/src/main/java/cn/iocoder/yudao/module/rd/enums/AttachmentTypeEnum.java
  3. 3 0
      yudao-module-rd/yudao-module-rd-api/src/main/java/cn/iocoder/yudao/module/rd/enums/ErrorCodeConstant.java
  4. 32 0
      yudao-module-rd/yudao-module-rd-api/src/main/java/cn/iocoder/yudao/module/rd/enums/attrs/template/DataSpecsDataTypeEnum.java
  5. 30 0
      yudao-module-rd/yudao-module-rd-api/src/main/java/cn/iocoder/yudao/module/rd/enums/attrs/template/TemplateAttrAccessModeEnum.java
  6. 206 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievement/ResearchAchievementController.java
  7. 69 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievement/vo/ResearchAchievementPageReqVO.java
  8. 99 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievement/vo/ResearchAchievementRespVO.java
  9. 67 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievement/vo/ResearchAchievementSaveReqVO.java
  10. 102 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievementattrs/ResearchAchievementAttrsController.java
  11. 75 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievementattrs/vo/ResearchAchievementAttrsPageReqVO.java
  12. 92 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievementattrs/vo/ResearchAchievementAttrsRespVO.java
  13. 65 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievementattrs/vo/ResearchAchievementAttrsSaveReqVO.java
  14. 96 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/dataobject/researchachievement/ResearchAchievementDO.java
  15. 101 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/dataobject/researchachievementattrs/ResearchAchievementAttrsDO.java
  16. 28 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/dataobject/researchachievementattrs/TemplateAttrEnumDataSpecs.java
  17. 87 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/dataobject/researchachievementattrs/TemplateAttrModelProperty.java
  18. 39 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/mysql/researchachievement/ResearchAchievementMapper.java
  19. 66 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/mysql/researchachievementattrs/ResearchAchievementAttrsMapper.java
  20. 2 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/service/coretechnology/CoreTechnologyServiceImpl.java
  21. 55 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/service/researchachievement/ResearchAchievementService.java
  22. 137 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/service/researchachievement/ResearchAchievementServiceImpl.java
  23. 65 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/service/researchachievementattrs/ResearchAchievementAttrsService.java
  24. 88 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/service/researchachievementattrs/ResearchAchievementAttrsServiceImpl.java
  25. 16 0
      yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/utils/DictDataUtils.java

+ 1 - 1
yudao-module-rd/yudao-module-rd-api/src/main/java/cn/iocoder/yudao/module/rd/enums/AttachmentCategoryEnum.java

@@ -11,7 +11,7 @@ public enum AttachmentCategoryEnum {
     SCIENCE_PROJECT("SCIENCE_PROJECT", "科研项目", 3),
     GOV_PROJECT("GOV_PROJECT", "政府项目", 4),
     POLICY("POLICY", "政策咨询", 5),
-    PATENT("PATENT", "专利", 6);
+    ACHIEVEMENT("ACHIEVEMENT", "研究成果", 6);
 
     private String code;
     private String msg;

+ 7 - 5
yudao-module-rd/yudao-module-rd-api/src/main/java/cn/iocoder/yudao/module/rd/enums/AttachmentTypeEnum.java

@@ -6,11 +6,13 @@ package cn.iocoder.yudao.module.rd.enums;
  * @create: 2025-10-20
  **/
 public enum AttachmentTypeEnum {
-    PATENT("EXTERNAL_RENTAL", "专利", 1),
-    PAPER("CONSTRUCTION_DESIGN", "论文", 2),
-    OTHER_MATERIAL("GEOLOGICAL_DESIGN", "其他资料", 3),
-    AUTH_NOTICE("COMPLETION_REPORT", "授权通知书", 4),
-    MAINTENANCE_STANDARD("CERTIFICATE", "证书", 5),
+    PATENT("PATENT", "专利", 1),
+    PAPER("PAPER", "论文", 2),
+    OTHER_MATERIAL("OTHER_MATERIAL", "其他资料", 3),
+    AUTH_NOTICE("AUTH_NOTICE", "授权通知书", 4),
+    CERTIFICATE("CERTIFICATE", "证书", 5),
+    COPYRIGHT("COPYRIGHT", "软著", 7),
+    HONOR_CERTIFICATE("HONOR_CERTIFICATE", "荣誉证书", 8),
     REGISTER_COPY("REGISTER_COPY", "登记副本", 6);
 
     private String code;

+ 3 - 0
yudao-module-rd/yudao-module-rd-api/src/main/java/cn/iocoder/yudao/module/rd/enums/ErrorCodeConstant.java

@@ -12,6 +12,9 @@ public interface ErrorCodeConstant {
     ErrorCode CORE_TECHNOLOGY_NOT_EXISTS = new ErrorCode(400, "核心技术不存在");
     ErrorCode CORE_TECHNOLOGY_DETAIL_NOT_EXISTS = new ErrorCode(401, "核心技术明细不存在");
 
+    ErrorCode RESEARCH_ACHIEVEMENT_ATTRS_NOT_EXISTS = new ErrorCode(500, "研究成果 论文 专利 软著 荣誉证书 扩展属性不存在");
+    ErrorCode RESEARCH_ACHIEVEMENT_NOT_EXISTS = new ErrorCode(501, "知识产权、荣誉证书等研究成果不存在");
+
     ErrorCode ATTACHMENT_NOT_EXISTS = new ErrorCode(300, "R&D 附件不存在");
     /***
      * 数字油藏

+ 32 - 0
yudao-module-rd/yudao-module-rd-api/src/main/java/cn/iocoder/yudao/module/rd/enums/attrs/template/DataSpecsDataTypeEnum.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.rd.enums.attrs.template;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 数据定义的数据类型枚举类
+ *
+ * @author ruiqi
+ */
+@AllArgsConstructor
+@Getter
+public enum DataSpecsDataTypeEnum implements ArrayValuable<String> {
+
+    DOUBLE("double"),
+    TEXT("text"),
+    TEXTAREA("textarea"),
+    DATE("date");
+
+    public static final String[] ARRAYS = Arrays.stream(values()).map(DataSpecsDataTypeEnum::getDataType).toArray(String[]::new);
+
+    private final String dataType;
+
+    @Override
+    public String[] array() {
+        return ARRAYS;
+    }
+
+}

+ 30 - 0
yudao-module-rd/yudao-module-rd-api/src/main/java/cn/iocoder/yudao/module/rd/enums/attrs/template/TemplateAttrAccessModeEnum.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.rd.enums.attrs.template;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 属性 模板 读取类型枚举
+ *
+ * @author ruiqi
+ */
+@AllArgsConstructor
+@Getter
+public enum TemplateAttrAccessModeEnum implements ArrayValuable<String> {
+
+    READ_ONLY("r"),
+    READ_WRITE("rw");
+
+    public static final String[] ARRAYS = Arrays.stream(values()).map(TemplateAttrAccessModeEnum::getMode).toArray(String[]::new);
+
+    private final String mode;
+
+    @Override
+    public String[] array() {
+        return ARRAYS;
+    }
+
+}

+ 206 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievement/ResearchAchievementController.java

@@ -0,0 +1,206 @@
+package cn.iocoder.yudao.module.rd.controller.admin.researchachievement;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.rd.controller.admin.attachment.vo.AttachmentPageReqVO;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievement.vo.ResearchAchievementPageReqVO;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievement.vo.ResearchAchievementRespVO;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievement.vo.ResearchAchievementSaveReqVO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.attachment.AttachmentDO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievement.ResearchAchievementDO;
+import cn.iocoder.yudao.module.rd.enums.AttachmentCategoryEnum;
+import cn.iocoder.yudao.module.rd.service.attachment.AttachmentService;
+import cn.iocoder.yudao.module.rd.service.researchachievement.ResearchAchievementService;
+import cn.iocoder.yudao.module.rd.utils.DictDataUtils;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 知识产权、荣誉证书等研究成果")
+@RestController
+@RequestMapping("/rd/research-achievement")
+@Validated
+public class ResearchAchievementController {
+
+    @Resource
+    private ResearchAchievementService researchAchievementService;
+
+    @Resource
+    private DictDataUtils dictDataUtils;
+
+    @Resource
+    private AttachmentService attachmentService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建知识产权、荣誉证书等研究成果")
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement:create')")
+    public CommonResult<Long> createResearchAchievement(@Valid @RequestBody ResearchAchievementSaveReqVO createReqVO) {
+        return success(researchAchievementService.createResearchAchievement(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新知识产权、荣誉证书等研究成果")
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement:update')")
+    public CommonResult<Boolean> updateResearchAchievement(@Valid @RequestBody ResearchAchievementSaveReqVO updateReqVO) {
+        researchAchievementService.updateResearchAchievement(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除知识产权、荣誉证书等研究成果")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement:delete')")
+    public CommonResult<Boolean> deleteResearchAchievement(@RequestParam("id") Long id) {
+        researchAchievementService.deleteResearchAchievement(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得知识产权、荣誉证书等研究成果")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement:query')")
+    public CommonResult<ResearchAchievementRespVO> getResearchAchievement(@RequestParam("id") Long id) {
+        ResearchAchievementDO researchAchievement = researchAchievementService.getResearchAchievement(id);
+        return success(buildAchievement(researchAchievement));
+    }
+
+    /**
+     * 查询研究成果 专利 软著 论文 荣誉证书 详情
+     * @param achievement
+     * @return
+     */
+    private ResearchAchievementRespVO buildAchievement(ResearchAchievementDO achievement) {
+        // 如果 technology 为空 返回空对象
+        if (ObjUtil.isEmpty(achievement)) {
+            return new ResearchAchievementRespVO();
+        }
+        ResearchAchievementRespVO achievementVO = BeanUtils.toBean(achievement, ResearchAchievementRespVO.class);
+        // 查询 研究成果类型 字典数据
+        Map<String, String> achievementTypePair = dictDataUtils.getDictData("rd_achievement_type");
+        // key 研究成果类型value值  value不同类型对应的子类型数据字典type
+        Map<String, String> achievementTypeRemarkPair = dictDataUtils.getDictDataRemark("rd_achievement_type");
+
+        // 研究成果类型
+        String achievementType = achievementVO.getAchievementType();
+        if (StrUtil.isNotBlank(achievementType) && achievementTypePair.containsKey(achievementType)) {
+            achievementVO.setAchievementTypeLabel(achievementTypePair.get(achievementType));
+        }
+
+        // 研究成果子类型
+        String subType = achievementVO.getSubType();
+        if (StrUtil.isNotBlank(achievementType) && achievementTypeRemarkPair.containsKey(achievementType)) {
+            // 当前研究成果类型 对应的子类型
+            String dictDataRemark = achievementTypeRemarkPair.get(achievementType);
+            if (StrUtil.isNotBlank(dictDataRemark)) {
+                Map<String, String> subTypePair = dictDataUtils.getDictData(dictDataRemark);
+                if (StrUtil.isNotBlank(subType) && subTypePair.containsKey(subType)) {
+                    achievementVO.setSubTypeLabel(subTypePair.get(subType));
+                }
+            }
+        }
+
+        // 查询当前 核心技术 附件列表
+        AttachmentPageReqVO reqVO = new AttachmentPageReqVO();
+        reqVO.setBizId(achievement.getId());
+        reqVO.setCategory(AttachmentCategoryEnum.ACHIEVEMENT.getCode());
+        List<AttachmentDO> attachments = attachmentService.getIotAttachments(reqVO);
+        if (CollUtil.isNotEmpty(attachments)) {
+            achievementVO.setAttachments(attachments);
+        }
+        return achievementVO;
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得知识产权、荣誉证书等研究成果分页")
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement:query')")
+    public CommonResult<PageResult<ResearchAchievementRespVO>> getResearchAchievementPage(@Valid ResearchAchievementPageReqVO pageReqVO) {
+        PageResult<ResearchAchievementDO> pageResult = researchAchievementService.getResearchAchievementPage(pageReqVO);
+        return success(new PageResult<>(buildAchievements(pageResult.getList()), pageResult.getTotal()));
+    }
+
+    /**
+     * 设置研究成果列表中 每个 研究成果的 主类型 子类型 label
+     * @param achievements
+     * @return
+     */
+    private List<ResearchAchievementRespVO> buildAchievements(List<ResearchAchievementDO> achievements) {
+        if (CollUtil.isEmpty(achievements)) {
+            return Collections.emptyList();
+        }
+        // 查询数据字典值列表
+        // 研究成果 子类型 key研究成果id   value子类型标签
+        Map<Long, String> subTypesPair = new HashMap<>();
+
+        // 查询 研究成果 主类别 字典数据
+        Map<String, String> achievementTypePair = dictDataUtils.getDictData("rd_achievement_type");
+        // key 研究成果类型value值  value不同类型对应的子类型数据字典type
+        Map<String, String> achievementTypeRemarkPair = dictDataUtils.getDictDataRemark("rd_achievement_type");
+
+        achievements.forEach(achievement -> {
+            // 每个研究成果的 主类型
+            String achievementType = achievement.getAchievementType();
+
+            // 研究成果子类型
+            String subType = achievement.getSubType();
+            if (StrUtil.isNotBlank(achievementType) && achievementTypeRemarkPair.containsKey(achievementType)) {
+                // 当前研究成果类型 对应的子类型
+                String dictDataRemark = achievementTypeRemarkPair.get(achievementType);
+                if (StrUtil.isNotBlank(dictDataRemark)) {
+                    Map<String, String> subTypePair = dictDataUtils.getDictData(dictDataRemark);
+                    if (StrUtil.isNotBlank(subType) && subTypePair.containsKey(subType)) {
+                        subTypesPair.put(achievement.getId(), subTypePair.get(subType));
+                    }
+                }
+            }
+        });
+
+        return BeanUtils.toBean(achievements, ResearchAchievementRespVO.class, (achievementVO) -> {
+            if (StrUtil.isNotBlank(achievementVO.getAchievementType())) {
+                if (achievementTypePair.containsKey(achievementVO.getAchievementType())) {
+                    achievementVO.setAchievementTypeLabel(achievementTypePair.get(achievementVO.getAchievementType()));
+                }
+            }
+            if (StrUtil.isNotBlank(achievementVO.getSubType())) {
+                if (subTypesPair.containsKey(achievementVO.getId())) {
+                    achievementVO.setSubTypeLabel(subTypesPair.get(achievementVO.getId()));
+                }
+            }
+        });
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出知识产权、荣誉证书等研究成果 Excel")
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportResearchAchievementExcel(@Valid ResearchAchievementPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<ResearchAchievementDO> list = researchAchievementService.getResearchAchievementPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "知识产权、荣誉证书等研究成果.xls", "数据", ResearchAchievementRespVO.class,
+                        BeanUtils.toBean(list, ResearchAchievementRespVO.class));
+    }
+
+}

+ 69 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievement/vo/ResearchAchievementPageReqVO.java

@@ -0,0 +1,69 @@
+package cn.iocoder.yudao.module.rd.controller.admin.researchachievement.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 知识产权、荣誉证书等研究成果分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ResearchAchievementPageReqVO extends PageParam {
+
+    @Schema(description = "所属部门(成果所有权)", example = "1444")
+    private Long deptId;
+
+    @Schema(description = "研究成果名称", example = "芋艿")
+    private String achievementName;
+
+    @Schema(description = "研究成果类型(论文 专利 软著 荣誉证书...)", example = "2")
+    private String achievementType;
+
+    @Schema(description = "研究成果子类型(发明专利 实用新型 原始取得...)", example = "2")
+    private String subType;
+
+    @Schema(description = "所属单位id", example = "20713")
+    private Long departmentId;
+
+    @Schema(description = "所属单位")
+    private String department;
+
+    @Schema(description = "概述")
+    private String summary;
+
+    @Schema(description = "头像url")
+    private String avatar;
+
+    @Schema(description = "扩展属性,存储各类型特有字段")
+    private String extAttributes;
+
+    @Schema(description = "排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+    @Schema(description = "状态(0有效 1失效)", example = "2")
+    private Integer status;
+
+    @Schema(description = "流程实例id", example = "27647")
+    private String processInstanceId;
+
+    @Schema(description = "审批状态 未提交、审批中、审批通过、审批不通过、已取消", example = "2")
+    private Integer auditStatus;
+
+    @Schema(description = "审批意见")
+    private String opinion;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 99 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievement/vo/ResearchAchievementRespVO.java

@@ -0,0 +1,99 @@
+package cn.iocoder.yudao.module.rd.controller.admin.researchachievement.vo;
+
+import cn.iocoder.yudao.module.rd.dal.dataobject.attachment.AttachmentDO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs.TemplateAttrModelProperty;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - 知识产权、荣誉证书等研究成果 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class ResearchAchievementRespVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "7121")
+    @ExcelProperty("主键id")
+    private Long id;
+
+    @Schema(description = "所属部门(成果所有权)", example = "1444")
+    @ExcelProperty("所属部门(成果所有权)")
+    private Long deptId;
+
+    @Schema(description = "研究成果名称", example = "芋艿")
+    @ExcelProperty("研究成果名称")
+    private String achievementName;
+
+    @Schema(description = "研究成果类型(论文 专利 软著 荣誉证书...)", example = "2")
+    @ExcelProperty("研究成果类型(论文 专利 软著 荣誉证书...)")
+    private String achievementType;
+
+    @Schema(description = "研究成果子类型(发明专利 实用新型 原始取得...)", example = "2")
+    @ExcelProperty("研究成果子类型(发明专利 实用新型 原始取得...)")
+    private String subType;
+
+    @Schema(description = "所属单位id", example = "20713")
+    @ExcelProperty("所属单位id")
+    private Long departmentId;
+
+    @Schema(description = "所属单位")
+    @ExcelProperty("所属单位")
+    private String department;
+
+    @Schema(description = "概述")
+    @ExcelProperty("概述")
+    private String summary;
+
+    @Schema(description = "头像url")
+    @ExcelProperty("头像url")
+    private String avatar;
+
+    @Schema(description = "扩展属性,存储各类型特有字段")
+    @ExcelProperty("扩展属性,存储各类型特有字段")
+    private List<TemplateAttrModelProperty> extAttributes;
+
+    @Schema(description = "排序值")
+    @ExcelProperty("排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "随便")
+    @ExcelProperty("备注")
+    private String remark;
+
+    @Schema(description = "状态(0有效 1失效)", example = "2")
+    @ExcelProperty("状态(0有效 1失效)")
+    private Integer status;
+
+    @Schema(description = "流程实例id", example = "27647")
+    @ExcelProperty("流程实例id")
+    private String processInstanceId;
+
+    @Schema(description = "审批状态 未提交、审批中、审批通过、审批不通过、已取消", example = "2")
+    @ExcelProperty("审批状态 未提交、审批中、审批通过、审批不通过、已取消")
+    private Integer auditStatus;
+
+    @Schema(description = "审批意见")
+    @ExcelProperty("审批意见")
+    private String opinion;
+
+    @Schema(description = "创建时间")
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    /**
+     * 扩展字段
+     */
+    @Schema(description = "研究成果类型(论文 专利 软著 荣誉证书...) 数据字典 label", example = "2")
+    @ExcelProperty("研究成果类型")
+    private String achievementTypeLabel;
+
+    @Schema(description = "研究成果子类型(发明专利 实用新型 原始取得...) 数据字典 label", example = "2")
+    @ExcelProperty("研究成果子类型")
+    private String subTypeLabel;
+
+    @Schema(description = "附件列表", example = "https://aims.deepoil.cc/admin-api/infra/file/29/get/人力资源.png")
+    private List<AttachmentDO> attachments;
+}

+ 67 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievement/vo/ResearchAchievementSaveReqVO.java

@@ -0,0 +1,67 @@
+package cn.iocoder.yudao.module.rd.controller.admin.researchachievement.vo;
+
+import cn.iocoder.yudao.module.rd.controller.admin.attachment.vo.AttachmentSaveReqVO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs.TemplateAttrModelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - 知识产权、荣誉证书等研究成果新增/修改 Request VO")
+@Data
+public class ResearchAchievementSaveReqVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "7121")
+    private Long id;
+
+    @Schema(description = "所属部门(成果所有权)", example = "1444")
+    private Long deptId;
+
+    @Schema(description = "研究成果名称", example = "芋艿")
+    private String achievementName;
+
+    @Schema(description = "研究成果类型(论文 专利 软著 荣誉证书...)", example = "2")
+    private String achievementType;
+
+    @Schema(description = "研究成果子类型(发明专利 实用新型 原始取得...)", example = "2")
+    private String subType;
+
+    @Schema(description = "所属单位id", example = "20713")
+    private Long departmentId;
+
+    @Schema(description = "所属单位")
+    private String department;
+
+    @Schema(description = "概述")
+    private String summary;
+
+    @Schema(description = "头像url")
+    private String avatar;
+
+    @Schema(description = "扩展属性,存储各类型特有字段")
+    private List<TemplateAttrModelProperty> extAttributes;
+
+    @Schema(description = "排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+    @Schema(description = "状态(0有效 1失效)", example = "2")
+    private Integer status;
+
+    @Schema(description = "流程实例id", example = "27647")
+    private String processInstanceId;
+
+    @Schema(description = "审批状态 未提交、审批中、审批通过、审批不通过、已取消", example = "2")
+    private Integer auditStatus;
+
+    @Schema(description = "审批意见")
+    private String opinion;
+
+    /**
+     * 扩展字段
+     */
+    @Schema(description = "附件列表")
+    private List<AttachmentSaveReqVO> attachments;
+}

+ 102 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievementattrs/ResearchAchievementAttrsController.java

@@ -0,0 +1,102 @@
+package cn.iocoder.yudao.module.rd.controller.admin.researchachievementattrs;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievementattrs.vo.ResearchAchievementAttrsPageReqVO;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievementattrs.vo.ResearchAchievementAttrsRespVO;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievementattrs.vo.ResearchAchievementAttrsSaveReqVO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs.ResearchAchievementAttrsDO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs.TemplateAttrModelProperty;
+import cn.iocoder.yudao.module.rd.service.researchachievementattrs.ResearchAchievementAttrsService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 研究成果 论文 专利 软著 荣誉证书 扩展属性")
+@RestController
+@RequestMapping("/rd/research-achievement-attrs")
+@Validated
+public class ResearchAchievementAttrsController {
+
+    @Resource
+    private ResearchAchievementAttrsService researchAchievementAttrsService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建研究成果 论文 专利 软著 荣誉证书 扩展属性")
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement-attrs:create')")
+    public CommonResult<Long> createResearchAchievementAttrs(@Valid @RequestBody ResearchAchievementAttrsSaveReqVO createReqVO) {
+        return success(researchAchievementAttrsService.createResearchAchievementAttrs(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新研究成果 论文 专利 软著 荣誉证书 扩展属性")
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement-attrs:update')")
+    public CommonResult<Boolean> updateResearchAchievementAttrs(@Valid @RequestBody ResearchAchievementAttrsSaveReqVO updateReqVO) {
+        researchAchievementAttrsService.updateResearchAchievementAttrs(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除研究成果 论文 专利 软著 荣誉证书 扩展属性")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement-attrs:delete')")
+    public CommonResult<Boolean> deleteResearchAchievementAttrs(@RequestParam("id") Long id) {
+        researchAchievementAttrsService.deleteResearchAchievementAttrs(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得研究成果 论文 专利 软著 荣誉证书 扩展属性")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement-attrs:query')")
+    public CommonResult<ResearchAchievementAttrsRespVO> getResearchAchievementAttrs(@RequestParam("id") Long id) {
+        ResearchAchievementAttrsDO researchAchievementAttrs = researchAchievementAttrsService.getResearchAchievementAttrs(id);
+        return success(BeanUtils.toBean(researchAchievementAttrs, ResearchAchievementAttrsRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得研究成果 论文 专利 软著 荣誉证书 扩展属性分页")
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement-attrs:query')")
+    public CommonResult<PageResult<ResearchAchievementAttrsRespVO>> getResearchAchievementAttrsPage(@Valid ResearchAchievementAttrsPageReqVO pageReqVO) {
+        PageResult<ResearchAchievementAttrsDO> pageResult = researchAchievementAttrsService.getResearchAchievementAttrsPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, ResearchAchievementAttrsRespVO.class));
+    }
+
+    @GetMapping("/attrs")
+    @Operation(summary = "获得研究成果 论文 专利 软著 荣誉证书 扩展属性 列表")
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement-attrs:query')")
+    public CommonResult<List<TemplateAttrModelProperty>> researchAchievementAttrs(@Valid ResearchAchievementAttrsPageReqVO pageReqVO) {
+        List<TemplateAttrModelProperty> achievementAttrs = researchAchievementAttrsService.achievementAttrs(pageReqVO);
+        return success(achievementAttrs);
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出研究成果 论文 专利 软著 荣誉证书 扩展属性 Excel")
+    @PreAuthorize("@ss.hasPermission('rd:research-achievement-attrs:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportResearchAchievementAttrsExcel(@Valid ResearchAchievementAttrsPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<ResearchAchievementAttrsDO> list = researchAchievementAttrsService.getResearchAchievementAttrsPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "研究成果 论文 专利 软著 荣誉证书 扩展属性.xls", "数据", ResearchAchievementAttrsRespVO.class,
+                        BeanUtils.toBean(list, ResearchAchievementAttrsRespVO.class));
+    }
+
+}

+ 75 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievementattrs/vo/ResearchAchievementAttrsPageReqVO.java

@@ -0,0 +1,75 @@
+package cn.iocoder.yudao.module.rd.controller.admin.researchachievementattrs.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 研究成果 论文 专利 软著 荣誉证书 扩展属性分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ResearchAchievementAttrsPageReqVO extends PageParam {
+
+    @Schema(description = "扩展模板id", example = "626")
+    private Long templateId;
+
+    @Schema(description = "部门id", example = "27102")
+    private Long deptId;
+
+    @Schema(description = "研究成果主类别", example = "2")
+    private String achievementType;
+
+    @Schema(description = "研究成果子类别", example = "1")
+    private String achievementSubType;
+
+    @Schema(description = "属性名称", example = "王五")
+    private String name;
+
+    @Schema(description = "属性标识符")
+    private String identifier;
+
+    @Schema(description = "数据类型(double text textarea date dropdown)", example = "1")
+    private String dataType;
+
+    @Schema(description = "是否必填(0非必填 1必填)")
+    private Integer required;
+
+    @Schema(description = "单位(MPa)")
+    private String unit;
+
+    @Schema(description = "访问模式(r读  w写)")
+    private String accessMode;
+
+    @Schema(description = "默认值")
+    private String defaultValue;
+
+    @Schema(description = "最大值")
+    private String maxValue;
+
+    @Schema(description = "最小值")
+    private String minValue;
+
+    @Schema(description = "不同类型研究成果的扩展属性")
+    private String extProperty;
+
+    @Schema(description = "排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+    @Schema(description = "状态(0启用 1禁用)", example = "2")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 92 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievementattrs/vo/ResearchAchievementAttrsRespVO.java

@@ -0,0 +1,92 @@
+package cn.iocoder.yudao.module.rd.controller.admin.researchachievementattrs.vo;
+
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs.TemplateAttrModelProperty;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 研究成果 论文 专利 软著 荣誉证书 扩展属性 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class ResearchAchievementAttrsRespVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "28619")
+    @ExcelProperty("主键id")
+    private Long id;
+
+    @Schema(description = "扩展模板id", example = "626")
+    @ExcelProperty("扩展模板id")
+    private Long templateId;
+
+    @Schema(description = "部门id", example = "27102")
+    @ExcelProperty("部门id")
+    private Long deptId;
+
+    @Schema(description = "研究成果主类别", example = "2")
+    @ExcelProperty("研究成果主类别")
+    private String achievementType;
+
+    @Schema(description = "研究成果子类别", example = "1")
+    @ExcelProperty("研究成果子类别")
+    private String achievementSubType;
+
+    @Schema(description = "属性名称", example = "王五")
+    @ExcelProperty("属性名称")
+    private String name;
+
+    @Schema(description = "属性标识符")
+    @ExcelProperty("属性标识符")
+    private String identifier;
+
+    @Schema(description = "数据类型(double text textarea date dropdown)", example = "1")
+    @ExcelProperty("数据类型(double text textarea date dropdown)")
+    private String dataType;
+
+    @Schema(description = "是否必填(0非必填 1必填)")
+    @ExcelProperty("是否必填(0非必填 1必填)")
+    private Integer required;
+
+    @Schema(description = "单位(MPa)")
+    @ExcelProperty("单位(MPa)")
+    private String unit;
+
+    @Schema(description = "访问模式(r读  w写)")
+    @ExcelProperty("访问模式(r读  w写)")
+    private String accessMode;
+
+    @Schema(description = "默认值")
+    @ExcelProperty("默认值")
+    private String defaultValue;
+
+    @Schema(description = "最大值")
+    @ExcelProperty("最大值")
+    private String maxValue;
+
+    @Schema(description = "最小值")
+    @ExcelProperty("最小值")
+    private String minValue;
+
+    @Schema(description = "不同类型研究成果的扩展属性")
+    @ExcelProperty("不同类型研究成果的扩展属性")
+    private TemplateAttrModelProperty extProperty;
+
+    @Schema(description = "排序值")
+    @ExcelProperty("排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "随便")
+    @ExcelProperty("备注")
+    private String remark;
+
+    @Schema(description = "状态(0启用 1禁用)", example = "2")
+    @ExcelProperty("状态(0启用 1禁用)")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 65 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/controller/admin/researchachievementattrs/vo/ResearchAchievementAttrsSaveReqVO.java

@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.module.rd.controller.admin.researchachievementattrs.vo;
+
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs.TemplateAttrModelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 研究成果 论文 专利 软著 荣誉证书 扩展属性新增/修改 Request VO")
+@Data
+public class ResearchAchievementAttrsSaveReqVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "28619")
+    private Long id;
+
+    @Schema(description = "扩展模板id", example = "626")
+    private Long templateId;
+
+    @Schema(description = "部门id", example = "27102")
+    private Long deptId;
+
+    @Schema(description = "研究成果主类别", example = "2")
+    private String achievementType;
+
+    @Schema(description = "研究成果子类别", example = "1")
+    private String achievementSubType;
+
+    @Schema(description = "属性名称", example = "王五")
+    private String name;
+
+    @Schema(description = "属性标识符")
+    private String identifier;
+
+    @Schema(description = "数据类型(double text textarea date dropdown)", example = "1")
+    private String dataType;
+
+    @Schema(description = "是否必填(0非必填 1必填)")
+    private Integer required;
+
+    @Schema(description = "单位(MPa)")
+    private String unit;
+
+    @Schema(description = "访问模式(r读  w写)")
+    private String accessMode;
+
+    @Schema(description = "默认值")
+    private String defaultValue;
+
+    @Schema(description = "最大值")
+    private String maxValue;
+
+    @Schema(description = "最小值")
+    private String minValue;
+
+    @Schema(description = "不同类型研究成果的扩展属性")
+    private TemplateAttrModelProperty extProperty;
+
+    @Schema(description = "排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+    @Schema(description = "状态(0启用 1禁用)", example = "2")
+    private Integer status;
+
+}

+ 96 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/dataobject/researchachievement/ResearchAchievementDO.java

@@ -0,0 +1,96 @@
+package cn.iocoder.yudao.module.rd.dal.dataobject.researchachievement;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs.TemplateAttrModelProperty;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import lombok.*;
+
+import java.util.List;
+
+/**
+ * 知识产权、荣誉证书等研究成果 DO
+ *
+ * @author ruiqi
+ */
+@TableName(value="rd_research_achievement", autoResultMap = true)
+@KeySequence("rd_research_achievement_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ResearchAchievementDO extends BaseDO {
+
+    /**
+     * 主键id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 所属部门(成果所有权)
+     */
+    private Long deptId;
+    /**
+     * 研究成果名称
+     */
+    private String achievementName;
+    /**
+     * 研究成果类型(论文 专利 软著 荣誉证书...)
+     */
+    private String achievementType;
+    /**
+     * 研究成果子类型(发明专利 实用新型 原始取得...)
+     */
+    private String subType;
+    /**
+     * 所属单位id
+     */
+    private Long departmentId;
+    /**
+     * 所属单位
+     */
+    private String department;
+    /**
+     * 概述
+     */
+    private String summary;
+    /**
+     * 头像url
+     */
+    private String avatar;
+    /**
+     * 扩展属性,存储各类型特有字段
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private List<TemplateAttrModelProperty> extAttributes;
+    /**
+     * 排序值
+     */
+    private Integer sort;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 状态(0有效 1失效)
+     */
+    private Integer status;
+    /**
+     * 流程实例id
+     */
+    private String processInstanceId;
+    /**
+     * 审批状态 未提交、审批中、审批通过、审批不通过、已取消
+     */
+    private Integer auditStatus;
+    /**
+     * 审批意见
+     */
+    private String opinion;
+
+}

+ 101 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/dataobject/researchachievementattrs/ResearchAchievementAttrsDO.java

@@ -0,0 +1,101 @@
+package cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import lombok.*;
+
+/**
+ * 研究成果 论文 专利 软著 荣誉证书 扩展属性 DO
+ *
+ * @author ruiqi
+ */
+@TableName(value = "rd_research_achievement_attrs", autoResultMap = true)
+@KeySequence("rd_research_achievement_attrs_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ResearchAchievementAttrsDO extends BaseDO {
+
+    /**
+     * 主键id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 扩展模板id
+     */
+    private Long templateId;
+    /**
+     * 部门id
+     */
+    private Long deptId;
+    /**
+     * 研究成果主类别
+     */
+    private String achievementType;
+    /**
+     * 研究成果子类别
+     */
+    private String achievementSubType;
+    /**
+     * 属性名称
+     */
+    private String name;
+    /**
+     * 属性标识符
+     */
+    private String identifier;
+    /**
+     * 数据类型(double text textarea date dropdown)
+     */
+    private String dataType;
+    /**
+     * 是否必填(0非必填 1必填)
+     */
+    private Integer required;
+    /**
+     * 单位(MPa)
+     */
+    private String unit;
+    /**
+     * 访问模式(r读  w写)
+     */
+    private String accessMode;
+    /**
+     * 默认值
+     */
+    private String defaultValue;
+    /**
+     * 最大值
+     */
+    private String maxValue;
+    /**
+     * 最小值
+     */
+    private String minValue;
+    /**
+     * 不同类型研究成果的扩展属性
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private TemplateAttrModelProperty extProperty;
+    /**
+     * 排序值
+     */
+    private Integer sort;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 状态(0启用 1禁用)
+     */
+    private Integer status;
+
+}

+ 28 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/dataobject/researchachievementattrs/TemplateAttrEnumDataSpecs.java

@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 模板属性 数据类型为下拉列表的 DataSpec 定义
+ *
+ * 数据类型 下拉列表。
+ *
+ * @author ruiqi
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class TemplateAttrEnumDataSpecs {
+
+    /**
+     * 枚举项的名称。
+     * 可包含中文、大小写英文字母、数字、下划线(_)和短划线(-)
+     * 必须以中文、英文字母或数字开头,长度不超过 20 个字符
+     */
+    private String name;
+    /**
+     * 枚举值。
+     */
+    private String value;
+
+}

+ 87 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/dataobject/researchachievementattrs/TemplateAttrModelProperty.java

@@ -0,0 +1,87 @@
+package cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.rd.enums.attrs.template.DataSpecsDataTypeEnum;
+import cn.iocoder.yudao.module.rd.enums.attrs.template.TemplateAttrAccessModeEnum;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ * 属性 扩展模板
+ *
+ * @author ruiqi
+ */
+@Data
+public class TemplateAttrModelProperty {
+
+    /**
+     * 属性名称
+     */
+    @NotEmpty(message = "属性名称不能为空")
+    private String name;
+
+    /**
+     * 属性标识符
+     */
+    @NotEmpty(message = "属性标识符不能为空")
+    private String identifier;
+
+    /**
+     * 参数值的数据类型 (double text textarea date)
+     *
+     * 枚举 {@link DataSpecsDataTypeEnum}
+     */
+    @NotEmpty(message = "数据类型不能为空")
+    @InEnum(DataSpecsDataTypeEnum.class)
+    private String dataType;
+
+    /**
+     * 是否必填(0非必填 1必填)
+     */
+    private Integer required;
+
+    /**
+     * 单位 MPa m
+     */
+    private String unit;
+
+    /**
+     * 可以对该属性进行的操作类型
+     *
+     * 枚举 {@link TemplateAttrAccessModeEnum}
+     */
+    @InEnum(TemplateAttrAccessModeEnum.class)
+    private String accessMode;
+
+    /**
+     * 默认值
+     */
+    private String defaultValue;
+
+    /**
+     * 最大值
+     */
+    private String maxValue;
+
+    /**
+     * 最小值
+     */
+    private String minValue;
+
+    /**
+     * 排序值
+     */
+    private Integer sort;
+
+    /**
+     * 字段值
+     */
+    private String actualValue;
+
+    /**
+     * 数据类型 为下拉列表型的数据规范
+     */
+    private List<TemplateAttrEnumDataSpecs> dropdownList;
+}

+ 39 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/mysql/researchachievement/ResearchAchievementMapper.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.rd.dal.mysql.researchachievement;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievement.vo.ResearchAchievementPageReqVO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievement.ResearchAchievementDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 知识产权、荣誉证书等研究成果 Mapper
+ *
+ * @author ruiqi
+ */
+@Mapper
+public interface ResearchAchievementMapper extends BaseMapperX<ResearchAchievementDO> {
+
+    default PageResult<ResearchAchievementDO> selectPage(ResearchAchievementPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<ResearchAchievementDO>()
+                .eqIfPresent(ResearchAchievementDO::getDeptId, reqVO.getDeptId())
+                .likeIfPresent(ResearchAchievementDO::getAchievementName, reqVO.getAchievementName())
+                .eqIfPresent(ResearchAchievementDO::getAchievementType, reqVO.getAchievementType())
+                .eqIfPresent(ResearchAchievementDO::getSubType, reqVO.getSubType())
+                .eqIfPresent(ResearchAchievementDO::getDepartmentId, reqVO.getDepartmentId())
+                .eqIfPresent(ResearchAchievementDO::getDepartment, reqVO.getDepartment())
+                .eqIfPresent(ResearchAchievementDO::getSummary, reqVO.getSummary())
+                .eqIfPresent(ResearchAchievementDO::getAvatar, reqVO.getAvatar())
+                .eqIfPresent(ResearchAchievementDO::getExtAttributes, reqVO.getExtAttributes())
+                .eqIfPresent(ResearchAchievementDO::getSort, reqVO.getSort())
+                .eqIfPresent(ResearchAchievementDO::getRemark, reqVO.getRemark())
+                .eqIfPresent(ResearchAchievementDO::getStatus, reqVO.getStatus())
+                .eqIfPresent(ResearchAchievementDO::getProcessInstanceId, reqVO.getProcessInstanceId())
+                .eqIfPresent(ResearchAchievementDO::getAuditStatus, reqVO.getAuditStatus())
+                .eqIfPresent(ResearchAchievementDO::getOpinion, reqVO.getOpinion())
+                .betweenIfPresent(ResearchAchievementDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(ResearchAchievementDO::getId));
+    }
+
+}

+ 66 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/dal/mysql/researchachievementattrs/ResearchAchievementAttrsMapper.java

@@ -0,0 +1,66 @@
+package cn.iocoder.yudao.module.rd.dal.mysql.researchachievementattrs;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievementattrs.vo.ResearchAchievementAttrsPageReqVO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs.ResearchAchievementAttrsDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 研究成果 论文 专利 软著 荣誉证书 扩展属性 Mapper
+ *
+ * @author ruiqi
+ */
+@Mapper
+public interface ResearchAchievementAttrsMapper extends BaseMapperX<ResearchAchievementAttrsDO> {
+
+    default PageResult<ResearchAchievementAttrsDO> selectPage(ResearchAchievementAttrsPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<ResearchAchievementAttrsDO>()
+                .eqIfPresent(ResearchAchievementAttrsDO::getTemplateId, reqVO.getTemplateId())
+                .eqIfPresent(ResearchAchievementAttrsDO::getDeptId, reqVO.getDeptId())
+                .eqIfPresent(ResearchAchievementAttrsDO::getAchievementType, reqVO.getAchievementType())
+                .eqIfPresent(ResearchAchievementAttrsDO::getAchievementSubType, reqVO.getAchievementSubType())
+                .likeIfPresent(ResearchAchievementAttrsDO::getName, reqVO.getName())
+                .eqIfPresent(ResearchAchievementAttrsDO::getIdentifier, reqVO.getIdentifier())
+                .eqIfPresent(ResearchAchievementAttrsDO::getDataType, reqVO.getDataType())
+                .eqIfPresent(ResearchAchievementAttrsDO::getRequired, reqVO.getRequired())
+                .eqIfPresent(ResearchAchievementAttrsDO::getUnit, reqVO.getUnit())
+                .eqIfPresent(ResearchAchievementAttrsDO::getAccessMode, reqVO.getAccessMode())
+                .eqIfPresent(ResearchAchievementAttrsDO::getDefaultValue, reqVO.getDefaultValue())
+                .eqIfPresent(ResearchAchievementAttrsDO::getMaxValue, reqVO.getMaxValue())
+                .eqIfPresent(ResearchAchievementAttrsDO::getMinValue, reqVO.getMinValue())
+                .eqIfPresent(ResearchAchievementAttrsDO::getExtProperty, reqVO.getExtProperty())
+                .eqIfPresent(ResearchAchievementAttrsDO::getSort, reqVO.getSort())
+                .eqIfPresent(ResearchAchievementAttrsDO::getRemark, reqVO.getRemark())
+                .eqIfPresent(ResearchAchievementAttrsDO::getStatus, reqVO.getStatus())
+                .betweenIfPresent(ResearchAchievementAttrsDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(ResearchAchievementAttrsDO::getId));
+    }
+
+    default List<ResearchAchievementAttrsDO> achievementAttrs(ResearchAchievementAttrsPageReqVO reqVO) {
+        return selectList(new LambdaQueryWrapperX<ResearchAchievementAttrsDO>()
+                .eqIfPresent(ResearchAchievementAttrsDO::getTemplateId, reqVO.getTemplateId())
+                .eqIfPresent(ResearchAchievementAttrsDO::getDeptId, reqVO.getDeptId())
+                .eqIfPresent(ResearchAchievementAttrsDO::getAchievementType, reqVO.getAchievementType())
+                .eqIfPresent(ResearchAchievementAttrsDO::getAchievementSubType, reqVO.getAchievementSubType())
+                .likeIfPresent(ResearchAchievementAttrsDO::getName, reqVO.getName())
+                .eqIfPresent(ResearchAchievementAttrsDO::getIdentifier, reqVO.getIdentifier())
+                .eqIfPresent(ResearchAchievementAttrsDO::getDataType, reqVO.getDataType())
+                .eqIfPresent(ResearchAchievementAttrsDO::getRequired, reqVO.getRequired())
+                .eqIfPresent(ResearchAchievementAttrsDO::getUnit, reqVO.getUnit())
+                .eqIfPresent(ResearchAchievementAttrsDO::getAccessMode, reqVO.getAccessMode())
+                .eqIfPresent(ResearchAchievementAttrsDO::getDefaultValue, reqVO.getDefaultValue())
+                .eqIfPresent(ResearchAchievementAttrsDO::getMaxValue, reqVO.getMaxValue())
+                .eqIfPresent(ResearchAchievementAttrsDO::getMinValue, reqVO.getMinValue())
+                .eqIfPresent(ResearchAchievementAttrsDO::getExtProperty, reqVO.getExtProperty())
+                .eqIfPresent(ResearchAchievementAttrsDO::getSort, reqVO.getSort())
+                .eqIfPresent(ResearchAchievementAttrsDO::getRemark, reqVO.getRemark())
+                .eqIfPresent(ResearchAchievementAttrsDO::getStatus, reqVO.getStatus())
+                .betweenIfPresent(ResearchAchievementAttrsDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(ResearchAchievementAttrsDO::getId));
+    }
+
+}

+ 2 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/service/coretechnology/CoreTechnologyServiceImpl.java

@@ -105,6 +105,7 @@ public class CoreTechnologyServiceImpl implements CoreTechnologyService {
             List<CoreTechnologyDetailDO> details = new ArrayList<>();
             technologyDetails.forEach(detail -> {
                 CoreTechnologyDetailDO tempDetail = BeanUtils.toBean(detail, CoreTechnologyDetailDO.class);
+                tempDetail.setId(null);
                 tempDetail.setDeptId(updateObj.getDeptId());
                 tempDetail.setTechnologyId(updateObj.getId());
                 details.add(tempDetail);
@@ -120,6 +121,7 @@ public class CoreTechnologyServiceImpl implements CoreTechnologyService {
             List<AttachmentDO> tobeAddedAttachments = new ArrayList<>();
             attachments.forEach(att -> {
                 AttachmentDO attachment = new AttachmentDO();
+                attachment.setId(null);
                 attachment.setBizId(updateObj.getId());
                 attachment.setCategory(AttachmentCategoryEnum.CORE_TECHNOLOGY.getCode());
                 attachment.setType(att.getType());

+ 55 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/service/researchachievement/ResearchAchievementService.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.rd.service.researchachievement;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievement.vo.ResearchAchievementPageReqVO;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievement.vo.ResearchAchievementSaveReqVO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievement.ResearchAchievementDO;
+
+import javax.validation.Valid;
+
+/**
+ * 知识产权、荣誉证书等研究成果 Service 接口
+ *
+ * @author ruiqi
+ */
+public interface ResearchAchievementService {
+
+    /**
+     * 创建知识产权、荣誉证书等研究成果
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createResearchAchievement(@Valid ResearchAchievementSaveReqVO createReqVO);
+
+    /**
+     * 更新知识产权、荣誉证书等研究成果
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateResearchAchievement(@Valid ResearchAchievementSaveReqVO updateReqVO);
+
+    /**
+     * 删除知识产权、荣誉证书等研究成果
+     *
+     * @param id 编号
+     */
+    void deleteResearchAchievement(Long id);
+
+    /**
+     * 获得知识产权、荣誉证书等研究成果
+     *
+     * @param id 编号
+     * @return 知识产权、荣誉证书等研究成果
+     */
+    ResearchAchievementDO getResearchAchievement(Long id);
+
+    /**
+     * 获得知识产权、荣誉证书等研究成果分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 知识产权、荣誉证书等研究成果分页
+     */
+    PageResult<ResearchAchievementDO> getResearchAchievementPage(ResearchAchievementPageReqVO pageReqVO);
+
+}

+ 137 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/service/researchachievement/ResearchAchievementServiceImpl.java

@@ -0,0 +1,137 @@
+package cn.iocoder.yudao.module.rd.service.researchachievement;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.rd.controller.admin.attachment.vo.AttachmentSaveReqVO;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievement.vo.ResearchAchievementPageReqVO;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievement.vo.ResearchAchievementSaveReqVO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.attachment.AttachmentDO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievement.ResearchAchievementDO;
+import cn.iocoder.yudao.module.rd.dal.mysql.attachment.AttachmentMapper;
+import cn.iocoder.yudao.module.rd.dal.mysql.researchachievement.ResearchAchievementMapper;
+import cn.iocoder.yudao.module.rd.enums.AttachmentCategoryEnum;
+import com.google.common.collect.ImmutableMap;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.rd.enums.ErrorCodeConstant.RESEARCH_ACHIEVEMENT_NOT_EXISTS;
+
+
+/**
+ * 知识产权、荣誉证书等研究成果 Service 实现类
+ *
+ * @author ruiqi
+ */
+@Service
+@Validated
+public class ResearchAchievementServiceImpl implements ResearchAchievementService {
+
+    @Resource
+    private ResearchAchievementMapper researchAchievementMapper;
+
+    @Resource
+    private AttachmentMapper attachmentMapper;
+
+    @Override
+    public Long createResearchAchievement(ResearchAchievementSaveReqVO createReqVO) {
+        // 插入
+        ResearchAchievementDO researchAchievement = BeanUtils.toBean(createReqVO, ResearchAchievementDO.class);
+        researchAchievementMapper.insert(researchAchievement);
+        // 保存附件列表
+        if (CollUtil.isNotEmpty(createReqVO.getAttachments())) {
+            List<AttachmentSaveReqVO> attachments = createReqVO.getAttachments();
+            List<AttachmentDO> tobeAddedAttachments = new ArrayList<>();
+            attachments.forEach(att -> {
+                AttachmentDO attachment = new AttachmentDO();
+                attachment.setBizId(researchAchievement.getId());
+                attachment.setCategory(AttachmentCategoryEnum.ACHIEVEMENT.getCode());
+                attachment.setType(att.getType());
+                attachment.setFilePath(att.getFilePath());
+                attachment.setFileSize(att.getFileSize());
+                attachment.setFilename(att.getFilename());
+                attachment.setFileType(att.getFileType());
+                attachment.setRemark(att.getRemark());
+                tobeAddedAttachments.add(attachment);
+            });
+            if (CollUtil.isNotEmpty(tobeAddedAttachments)) {
+                attachmentMapper.insertBatch(tobeAddedAttachments);
+            }
+        }
+        // 返回
+        return researchAchievement.getId();
+    }
+
+    @Override
+    public void updateResearchAchievement(ResearchAchievementSaveReqVO updateReqVO) {
+        // 校验存在
+        validateResearchAchievementExists(updateReqVO.getId());
+        // 更新
+        ResearchAchievementDO updateObj = BeanUtils.toBean(updateReqVO, ResearchAchievementDO.class);
+        researchAchievementMapper.updateById(updateObj);
+
+        // 更新 附件
+        if (CollUtil.isNotEmpty(updateReqVO.getAttachments())) {
+            List<AttachmentSaveReqVO> attachments = updateReqVO.getAttachments();
+            List<AttachmentDO> tobeAddedAttachments = new ArrayList<>();
+            attachments.forEach(att -> {
+                AttachmentDO attachment = new AttachmentDO();
+                attachment.setId(null);
+                attachment.setBizId(updateObj.getId());
+                attachment.setCategory(AttachmentCategoryEnum.ACHIEVEMENT.getCode());
+                attachment.setType(att.getType());
+                attachment.setFilePath(att.getFilePath());
+                attachment.setFileSize(att.getFileSize());
+                attachment.setFilename(att.getFilename());
+                attachment.setFileType(att.getFileType());
+                attachment.setRemark(att.getRemark());
+                tobeAddedAttachments.add(attachment);
+            });
+            if (CollUtil.isNotEmpty(tobeAddedAttachments)) {
+                // 先删除再新增
+                int count = attachmentMapper.deleteByMap(ImmutableMap.of(
+                        "category", AttachmentCategoryEnum.ACHIEVEMENT.getCode(),
+                        "biz_id", updateObj.getId()
+                ));
+                attachmentMapper.insertBatch(tobeAddedAttachments);
+            }
+        } else {
+            // 如果传递的附件列表为空 则删除已有的附件
+            int count = attachmentMapper.deleteByMap(ImmutableMap.of(
+                    "category", AttachmentCategoryEnum.ACHIEVEMENT.getCode(),
+                    "biz_id", updateObj.getId()
+            ));
+        }
+    }
+
+    @Override
+    public void deleteResearchAchievement(Long id) {
+        // 校验存在
+        validateResearchAchievementExists(id);
+        // 删除
+        researchAchievementMapper.deleteById(id);
+    }
+
+    private void validateResearchAchievementExists(Long id) {
+        if (researchAchievementMapper.selectById(id) == null) {
+            throw exception(RESEARCH_ACHIEVEMENT_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public ResearchAchievementDO getResearchAchievement(Long id) {
+        return researchAchievementMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<ResearchAchievementDO> getResearchAchievementPage(ResearchAchievementPageReqVO pageReqVO) {
+        return researchAchievementMapper.selectPage(pageReqVO);
+    }
+
+}

+ 65 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/service/researchachievementattrs/ResearchAchievementAttrsService.java

@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.module.rd.service.researchachievementattrs;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievementattrs.vo.ResearchAchievementAttrsPageReqVO;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievementattrs.vo.ResearchAchievementAttrsSaveReqVO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs.ResearchAchievementAttrsDO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs.TemplateAttrModelProperty;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 研究成果 论文 专利 软著 荣誉证书 扩展属性 Service 接口
+ *
+ * @author ruiqi
+ */
+public interface ResearchAchievementAttrsService {
+
+    /**
+     * 创建研究成果 论文 专利 软著 荣誉证书 扩展属性
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createResearchAchievementAttrs(@Valid ResearchAchievementAttrsSaveReqVO createReqVO);
+
+    /**
+     * 更新研究成果 论文 专利 软著 荣誉证书 扩展属性
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateResearchAchievementAttrs(@Valid ResearchAchievementAttrsSaveReqVO updateReqVO);
+
+    /**
+     * 删除研究成果 论文 专利 软著 荣誉证书 扩展属性
+     *
+     * @param id 编号
+     */
+    void deleteResearchAchievementAttrs(Long id);
+
+    /**
+     * 获得研究成果 论文 专利 软著 荣誉证书 扩展属性
+     *
+     * @param id 编号
+     * @return 研究成果 论文 专利 软著 荣誉证书 扩展属性
+     */
+    ResearchAchievementAttrsDO getResearchAchievementAttrs(Long id);
+
+    /**
+     * 获得研究成果 论文 专利 软著 荣誉证书 扩展属性分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 研究成果 论文 专利 软著 荣誉证书 扩展属性分页
+     */
+    PageResult<ResearchAchievementAttrsDO> getResearchAchievementAttrsPage(ResearchAchievementAttrsPageReqVO pageReqVO);
+
+    /**
+     * 获得研究成果 论文 专利 软著 荣誉证书 扩展属性 列表
+     *
+     * @param pageReqVO 分页查询
+     * @return 研究成果 论文 专利 软著 荣誉证书 扩展属性 列表
+     */
+    List<TemplateAttrModelProperty> achievementAttrs(ResearchAchievementAttrsPageReqVO pageReqVO);
+
+}

+ 88 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/service/researchachievementattrs/ResearchAchievementAttrsServiceImpl.java

@@ -0,0 +1,88 @@
+package cn.iocoder.yudao.module.rd.service.researchachievementattrs;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievementattrs.vo.ResearchAchievementAttrsPageReqVO;
+import cn.iocoder.yudao.module.rd.controller.admin.researchachievementattrs.vo.ResearchAchievementAttrsSaveReqVO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs.ResearchAchievementAttrsDO;
+import cn.iocoder.yudao.module.rd.dal.dataobject.researchachievementattrs.TemplateAttrModelProperty;
+import cn.iocoder.yudao.module.rd.dal.mysql.researchachievementattrs.ResearchAchievementAttrsMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.rd.enums.ErrorCodeConstant.RESEARCH_ACHIEVEMENT_ATTRS_NOT_EXISTS;
+
+/**
+ * 研究成果 论文 专利 软著 荣誉证书 扩展属性 Service 实现类
+ *
+ * @author ruiqi
+ */
+@Service
+@Validated
+public class ResearchAchievementAttrsServiceImpl implements ResearchAchievementAttrsService {
+
+    @Resource
+    private ResearchAchievementAttrsMapper researchAchievementAttrsMapper;
+
+    @Override
+    public Long createResearchAchievementAttrs(ResearchAchievementAttrsSaveReqVO createReqVO) {
+        // 插入
+        ResearchAchievementAttrsDO researchAchievementAttrs = BeanUtils.toBean(createReqVO, ResearchAchievementAttrsDO.class);
+        researchAchievementAttrsMapper.insert(researchAchievementAttrs);
+        // 返回
+        return researchAchievementAttrs.getId();
+    }
+
+    @Override
+    public void updateResearchAchievementAttrs(ResearchAchievementAttrsSaveReqVO updateReqVO) {
+        // 校验存在
+        validateResearchAchievementAttrsExists(updateReqVO.getId());
+        // 更新
+        ResearchAchievementAttrsDO updateObj = BeanUtils.toBean(updateReqVO, ResearchAchievementAttrsDO.class);
+        researchAchievementAttrsMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteResearchAchievementAttrs(Long id) {
+        // 校验存在
+        validateResearchAchievementAttrsExists(id);
+        // 删除
+        researchAchievementAttrsMapper.deleteById(id);
+    }
+
+    private void validateResearchAchievementAttrsExists(Long id) {
+        if (researchAchievementAttrsMapper.selectById(id) == null) {
+            throw exception(RESEARCH_ACHIEVEMENT_ATTRS_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public ResearchAchievementAttrsDO getResearchAchievementAttrs(Long id) {
+        return researchAchievementAttrsMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<ResearchAchievementAttrsDO> getResearchAchievementAttrsPage(ResearchAchievementAttrsPageReqVO pageReqVO) {
+        return researchAchievementAttrsMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public List<TemplateAttrModelProperty> achievementAttrs(ResearchAchievementAttrsPageReqVO pageReqVO) {
+        List<TemplateAttrModelProperty> properties = new ArrayList<>();
+        List<ResearchAchievementAttrsDO> attrs = researchAchievementAttrsMapper.achievementAttrs(pageReqVO);
+        if (CollUtil.isNotEmpty(attrs)) {
+            attrs.forEach(attr -> {
+                TemplateAttrModelProperty property = attr.getExtProperty();
+                properties.add(property);
+            });
+        }
+        return properties;
+    }
+
+}

+ 16 - 0
yudao-module-rd/yudao-module-rd-biz/src/main/java/cn/iocoder/yudao/module/rd/utils/DictDataUtils.java

@@ -50,4 +50,20 @@ public class DictDataUtils {
         return dictDataPair;
     }
 
+    /**
+     * 根据数据字典类型获取数据字典 备注 列表
+     * @param dictType
+     * @return
+     */
+    public Map<String, String> getDictDataRemark(String dictType) {
+        Map<String, String> dictDataPair = new HashMap<>();
+        List<DictDataDO> somethingDictData = dictDataService.getDictDataListByDictType(dictType);
+        if (CollUtil.isNotEmpty(somethingDictData)) {
+            somethingDictData.forEach(tech -> {
+                dictDataPair.put(tech.getValue(), tech.getRemark());
+            });
+        }
+        return dictDataPair;
+    }
+
 }