liu
2 天以前 ffef3ed67816136e2986634657e26736c8a06545
feat(research): 课题申报成员新增成员类型并调整统计口径

- ResearchApplicationMemberDO/VO 新增 memberType 字段
- 成员去重键由 姓名+电话+单位 调整为 姓名+所属部门
- 成员统计返回成员类型汇总,关键字支持成员类型检索

Co-Authored-By: Claude <noreply@anthropic.com>
已修改6个文件
32 ■■■■■ 文件已修改
yudao-module-research/src/main/java/cn/iocoder/yudao/module/research/controller/admin/application/vo/member/ResearchApplicationMemberRespVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-research/src/main/java/cn/iocoder/yudao/module/research/controller/admin/application/vo/member/ResearchApplicationMemberSaveReqVO.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-research/src/main/java/cn/iocoder/yudao/module/research/controller/admin/application/vo/member/ResearchApplicationMemberStatisticsReqVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-research/src/main/java/cn/iocoder/yudao/module/research/controller/admin/application/vo/member/ResearchApplicationMemberStatisticsRespVO.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-research/src/main/java/cn/iocoder/yudao/module/research/dal/dataobject/application/ResearchApplicationMemberDO.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-research/src/main/java/cn/iocoder/yudao/module/research/service/application/ResearchApplicationServiceImpl.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-research/src/main/java/cn/iocoder/yudao/module/research/controller/admin/application/vo/member/ResearchApplicationMemberRespVO.java
@@ -16,6 +16,9 @@
    @Schema(description = "成员姓名", example = "李四")
    private String name;
    @Schema(description = "成员类型:教师 / 学生 / 校外人员", example = "教师")
    private String memberType;
    @Schema(description = "联系电话", example = "13800138000")
    private String contactPhone;
yudao-module-research/src/main/java/cn/iocoder/yudao/module/research/controller/admin/application/vo/member/ResearchApplicationMemberSaveReqVO.java
@@ -18,6 +18,10 @@
    @Size(max = 64, message = "成员姓名长度不能超过 64 个字符")
    private String name;
    @Schema(description = "成员类型:教师 / 学生 / 校外人员", example = "教师")
    @Size(max = 32, message = "成员类型长度不能超过 32 个字符")
    private String memberType;
    @Schema(description = "联系电话(选填,填写时须为 11 位手机号)", example = "13800138000")
    @Size(max = 20, message = "联系电话长度不能超过 20 个字符")
    @Pattern(regexp = "^$|^1[3-9]\\d{9}$", message = "成员联系电话格式不正确,请输入正确的 11 位手机号")
yudao-module-research/src/main/java/cn/iocoder/yudao/module/research/controller/admin/application/vo/member/ResearchApplicationMemberStatisticsReqVO.java
@@ -8,7 +8,7 @@
@Data
public class ResearchApplicationMemberStatisticsReqVO {
    @Schema(description = "关键字:成员姓名 / 联系电话 / 所属单位", example = "张三")
    @Schema(description = "关键字:成员姓名 / 成员类型 / 联系电话 / 所属部门", example = "张三")
    @Size(max = 64, message = "关键字长度不能超过 64 个字符")
    private String keyword;
yudao-module-research/src/main/java/cn/iocoder/yudao/module/research/controller/admin/application/vo/member/ResearchApplicationMemberStatisticsRespVO.java
@@ -12,6 +12,10 @@
    @ExcelProperty("成员姓名")
    private String name;
    @Schema(description = "成员类型(多个以顿号分隔)", example = "教师")
    @ExcelProperty("成员类型")
    private String memberTypes;
    @Schema(description = "联系电话", example = "13800138000")
    @ExcelProperty("联系电话")
    private String contactPhone;
yudao-module-research/src/main/java/cn/iocoder/yudao/module/research/dal/dataobject/application/ResearchApplicationMemberDO.java
@@ -30,16 +30,19 @@
    /** 成员姓名 */
    private String name;
    /** 联系电话 */
    /** 成员类型:教师 / 学生 / 校外人员 */
    private String memberType;
    /** 联系电话(历史字段,不再录入) */
    private String contactPhone;
    /** 所属单位 */
    /** 所属部门 */
    private String workUnit;
    /** 职称/职务 */
    private String jobTitle;
    /** 成员角色:主持人 / 核心成员 / 参与人 */
    /** 成员角色:主持人 / 核心成员 / 参与人(历史字段,不再录入) */
    private String memberRole;
    /** 排序号 */
yudao-module-research/src/main/java/cn/iocoder/yudao/module/research/service/application/ResearchApplicationServiceImpl.java
@@ -201,10 +201,11 @@
        Map<Long, ResearchApplicationDO> applicationMap = applications.stream()
                .collect(Collectors.toMap(ResearchApplicationDO::getId, application -> application, (a, b) -> a));
        // 2. 成员子表聚合:姓名 + 电话 + 单位 相同视为同一成员
        // 2. 成员子表聚合:姓名 + 所属部门 相同视为同一成员
        String keyword = StrUtil.trimToNull(reqVO.getKeyword());
        Map<String, ResearchApplicationMemberStatisticsRespVO> resultMap = new LinkedHashMap<>();
        Map<String, Set<String>> roleMap = new HashMap<>();
        Map<String, Set<String>> typeMap = new HashMap<>();
        Map<String, Set<Long>> projectIdMap = new HashMap<>();
        Map<String, Set<String>> projectTitleMap = new HashMap<>();
        for (ResearchApplicationMemberDO member : memberMapper.selectList()) {
@@ -224,6 +225,9 @@
            if (StrUtil.isBlank(vo.getJobTitle()) && StrUtil.isNotBlank(member.getJobTitle())) {
                vo.setJobTitle(StrUtil.trim(member.getJobTitle()));
            }
            if (StrUtil.isNotBlank(member.getMemberType())) {
                typeMap.computeIfAbsent(key, k -> new LinkedHashSet<>()).add(StrUtil.trim(member.getMemberType()));
            }
            if (StrUtil.isNotBlank(member.getMemberRole())) {
                roleMap.computeIfAbsent(key, k -> new LinkedHashSet<>()).add(StrUtil.trim(member.getMemberRole()));
            }
@@ -238,6 +242,7 @@
        for (Map.Entry<String, ResearchApplicationMemberStatisticsRespVO> entry : resultMap.entrySet()) {
            String key = entry.getKey();
            ResearchApplicationMemberStatisticsRespVO vo = entry.getValue();
            vo.setMemberTypes(String.join("、", typeMap.getOrDefault(key, Collections.emptySet())));
            vo.setMemberRoles(String.join("、", roleMap.getOrDefault(key, Collections.emptySet())));
            vo.setProjectCount(projectIdMap.getOrDefault(key, Collections.emptySet()).size());
            vo.setProjectTitles(String.join(";", projectTitleMap.getOrDefault(key, Collections.emptySet())));
@@ -266,6 +271,7 @@
            list.add(ResearchApplicationMemberDO.builder()
                    .applicationId(applicationId)
                    .name(StrUtil.trim(member.getName()))
                    .memberType(StrUtil.trim(member.getMemberType()))
                    .contactPhone(StrUtil.trim(member.getContactPhone()))
                    .workUnit(StrUtil.trim(member.getWorkUnit()))
                    .jobTitle(StrUtil.trim(member.getJobTitle()))
@@ -281,7 +287,6 @@
    private String buildMemberKey(ResearchApplicationMemberDO member) {
        return StrUtil.join("|", StrUtil.nullToEmpty(member.getName()).trim(),
                StrUtil.nullToEmpty(member.getContactPhone()).trim(),
                StrUtil.nullToEmpty(member.getWorkUnit()).trim());
    }
@@ -290,6 +295,7 @@
            return true;
        }
        return StrUtil.containsIgnoreCase(member.getName(), keyword)
                || StrUtil.containsIgnoreCase(member.getMemberType(), keyword)
                || StrUtil.containsIgnoreCase(member.getContactPhone(), keyword)
                || StrUtil.containsIgnoreCase(member.getWorkUnit(), keyword);
    }