浏览代码

fix: 求职信息库导出调整

zhangying 1 周之前
父节点
当前提交
8bce320370
共有 15 个文件被更改,包括 420 次插入30 次删除
  1. 5 1
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/enterprise/controller/EnterpriseInfoController.java
  2. 1 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/enterprise/vo/EnterpriseInfoVO.java
  3. 6 5
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/personal/controller/PersonalInfoController.java
  4. 6 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/personal/entity/PersonalInfo.java
  5. 8 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/personal/service/IPersonalInfoService.java
  6. 56 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/personal/service/impl/PersonalInfoServiceImpl.java
  7. 6 4
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/post/controller/PostInfoController.java
  8. 85 4
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/controller/EnterpriseTagController.java
  9. 85 4
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/controller/PersonalTagController.java
  10. 10 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/service/IEnterpriseTagService.java
  11. 10 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/service/IPersonalTagService.java
  12. 64 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/service/impl/EnterpriseTagServiceImpl.java
  13. 64 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/service/impl/PersonalTagServiceImpl.java
  14. 7 6
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/vo/EnterpriseTagVo.java
  15. 7 6
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/vo/PersonalTagVo.java

+ 5 - 1
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/enterprise/controller/EnterpriseInfoController.java

@@ -22,6 +22,7 @@ import org.jeecg.modules.zjrs.enterprise.service.IEnterpriseInfoService;
 import org.jeecg.modules.zjrs.enterprise.vo.EnterpriseInfoVO;
 import org.jeecgframework.poi.excel.def.NormalExcelConstants;
 import org.jeecgframework.poi.excel.entity.ExportParams;
+import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
 import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
@@ -184,8 +185,11 @@ public class EnterpriseInfoController extends JeecgController<EnterpriseInfo, IE
         ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
         mv.addObject(NormalExcelConstants.FILE_NAME, "企业基本信息表");
         mv.addObject(NormalExcelConstants.CLASS, EnterpriseInfoVO.class);
-        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("企业基本信息表", "导出人:" + username, "企业信息"));
+        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("企业基本信息表", "导出人:" + username, "企业信息", ExcelType.XSSF));
         mv.addObject(NormalExcelConstants.DATA_LIST, list);
+        // 指定导出字段,与前端表格列保持一致:统一信用代码、单位名称、单位类型、所属行业、注册地址、经营地址、企业规模、是否重点企业、单位标签、经营状态、当前岗位数、数据来源
+        String exportFields = "unifiedCreditCode,companyName,companyType,industry,regAddrDistrict,officeAddress,staffSize,isKeyEnterprise,tagNames,businessStatus,postCount,dataSource";
+        mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
         return mv;
     }
 

+ 1 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/enterprise/vo/EnterpriseInfoVO.java

@@ -34,6 +34,7 @@ public class EnterpriseInfoVO extends EnterpriseInfo {
     /**
      * 企业标签名称列表(逗号分隔,用于详情展示)
      */
+    @Excel(name = "单位标签", width = 25)
     @Schema(description = "企业标签名称列表")
     private java.lang.String tagNames;
 }

+ 6 - 5
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/personal/controller/PersonalInfoController.java

@@ -244,9 +244,10 @@ public class PersonalInfoController extends JeecgController<PersonalInfo, IPerso
             queryWrapper.in("id", selectionList);
         }
 
-        // Step.2 获取导出数据并进行字典值→标签内存映射
-        List<PersonalInfo> exportList = personalInfoService.translateDictFields(
-                service.list(queryWrapper), EXPORT_DICT_FIELD_MAP);
+        // Step.2 获取导出数据,填充标签名称,再进行字典值→标签内存映射
+        List<PersonalInfo> dataList = service.list(queryWrapper);
+        personalInfoService.populateTagNames(dataList);
+        List<PersonalInfo> exportList = personalInfoService.translateDictFields(dataList, EXPORT_DICT_FIELD_MAP);
 
         // Step.3 AutoPoi 导出Excel(此时字典字段已替换为中文标签)
         ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
@@ -257,8 +258,8 @@ public class PersonalInfoController extends JeecgController<PersonalInfo, IPerso
         mv.addObject(NormalExcelConstants.PARAMS, exportParams);
         mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
 
-        // 指定导出字段:姓名、性别、民族、国籍、出生日期(年龄)、学历、户口所在地、现居住地、户口所在地完整路径、现居住地完整路径、求职人员类别、联系电话、求职状态、数据来源
-        String exportFields = "fullName,gender,nation,nationality,birthDate,education,householdLocation,currentResidence,householdAreaName,residenceAreaName,jobSeekerCategory,contactPhone,jobSearchStatus,dataSource";
+        // 指定导出字段,与前端表格列保持一致:姓名、性别、年龄(出生日期)、学历、民族、国籍、户口所在地、现居住地、求职人员类别、联系电话、个人标签、求职状态、数据来源
+        String exportFields = "fullName,gender,birthDate,education,nation,nationality,householdAreaName,residenceAreaName,jobSeekerCategory,contactPhone,tagNames,jobSearchStatus,dataSource";
         mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
         return mv;
     }

+ 6 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/personal/entity/PersonalInfo.java

@@ -201,6 +201,12 @@ public class PersonalInfo implements Serializable {
     @Excel(name = "职业技能等级", width = 15)
     @Schema(description = "职业技能等级")
     private java.lang.String skillLevel;
+    /**
+     * 个人标签名称(逗号分隔,用于导出展示)
+     */
+    @Excel(name = "个人标签", width = 25)
+    @Schema(description = "个人标签名称")
+    private java.lang.String tagNames;
     /**
      * 求职状态
      */

+ 8 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/personal/service/IPersonalInfoService.java

@@ -61,4 +61,12 @@ public interface IPersonalInfoService extends IService<PersonalInfo> {
      * @return IPage<PersonalInfoVO>(含 tagIds 和 tagNames)
      */
     IPage<PersonalInfoVO> queryPageListWithTags(Page<PersonalInfo> page, QueryWrapper<PersonalInfo> queryWrapper);
+
+    /**
+     * 批量填充人员标签名称(用于导出)
+     * 根据人员ID批量查询个人标签关联,设置PersonalInfo.tagNames字段
+     *
+     * @param list 人员信息列表
+     */
+    void populateTagNames(List<PersonalInfo> list);
 }

+ 56 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/personal/service/impl/PersonalInfoServiceImpl.java

@@ -270,6 +270,62 @@ public class PersonalInfoServiceImpl extends ServiceImpl<PersonalInfoMapper, Per
         }
     }
 
+    /**
+     * 批量填充人员标签名称(用于导出)
+     * 根据人员ID批量查询个人标签关联和标签名称,设置到PersonalInfo.tagNames字段
+     * 通过两次批量查询 + 内存映射,避免N+1问题
+     */
+    @Override
+    public void populateTagNames(List<PersonalInfo> list) {
+        if (list == null || list.isEmpty()) {
+            return;
+        }
+
+        // 1. 收集所有人员ID
+        List<String> personalIds = list.stream()
+                .map(PersonalInfo::getId)
+                .collect(Collectors.toList());
+
+        // 2. 批量查询所有关联关系
+        LambdaQueryWrapper<PersonalTagRelation> relationQuery = new LambdaQueryWrapper<>();
+        relationQuery.in(PersonalTagRelation::getPersonalId, personalIds);
+        List<PersonalTagRelation> allRelations = personalTagRelationMapper.selectList(relationQuery);
+
+        if (allRelations.isEmpty()) {
+            return;
+        }
+
+        // 3. 按人员ID分组关联关系
+        Map<String, List<String>> personalTagIdMap = new HashMap<>();
+        Set<String> allTagIds = new HashSet<>();
+        for (PersonalTagRelation relation : allRelations) {
+            personalTagIdMap.computeIfAbsent(relation.getPersonalId(), k -> new ArrayList<>())
+                    .add(relation.getTagId());
+            allTagIds.add(relation.getTagId());
+        }
+
+        // 4. 批量查询所有标签名称
+        LambdaQueryWrapper<PersonalTag> tagQuery = new LambdaQueryWrapper<>();
+        tagQuery.in(PersonalTag::getId, new ArrayList<>(allTagIds));
+        List<PersonalTag> tags = personalTagMapper.selectList(tagQuery);
+        Map<String, String> tagNameMap = new HashMap<>();
+        for (PersonalTag tag : tags) {
+            tagNameMap.put(tag.getId(), tag.getTagName());
+        }
+
+        // 5. 设置每个人的tagNames
+        for (PersonalInfo info : list) {
+            List<String> tagIds = personalTagIdMap.get(info.getId());
+            if (tagIds != null && !tagIds.isEmpty()) {
+                String tagNames = tagIds.stream()
+                        .map(tagNameMap::get)
+                        .filter(name -> name != null)
+                        .collect(Collectors.joining(", "));
+                info.setTagNames(tagNames);
+            }
+        }
+    }
+
     /**
      * 删除人员的所有标签关联
      */

+ 6 - 4
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/post/controller/PostInfoController.java

@@ -174,6 +174,9 @@ public class PostInfoController extends JeecgController<PostInfo, IPostInfoServi
 
         List<PostInfoVo> exportList = postInfoService.queryListWithEnterprise(queryWrapper, request);
 
+        // 字典字段值→标签内存映射翻译
+        exportList = postInfoService.translateDictFields(exportList, EXPORT_DICT_FIELD_MAP);
+
         ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
         mv.addObject(NormalExcelConstants.FILE_NAME, "岗位信息表");
         mv.addObject(NormalExcelConstants.CLASS, PostInfoVo.class);
@@ -181,10 +184,9 @@ public class PostInfoController extends JeecgController<PostInfo, IPostInfoServi
         mv.addObject(NormalExcelConstants.PARAMS, exportParams);
         mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
 
-        String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
-        if (oConvertUtils.isNotEmpty(exportFields)) {
-            mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
-        }
+        // 指定导出字段,与前端表格列保持一致:企业名称、职业工种、岗位名称、薪酬待遇(最低)、薪酬待遇(最高)、招聘人数、岗位有效期、职位标签、学历要求、工作经验、联系人、联系电话、数据来源
+        String exportFields = "companyName,occupation,postName,salaryMin,salaryMax,recruitCount,postValidDate,postTag,educationRequire,workExperienceRequire,contactPerson,contactPhone,dataSource";
+        mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
         return mv;
     }
 

+ 85 - 4
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/controller/EnterpriseTagController.java

@@ -57,6 +57,16 @@ public class EnterpriseTagController extends JeecgController<EnterpriseTag, IEnt
     @Autowired
     private EnterpriseTagRelationMapper enterpriseTagRelationMapper;
 
+    /**
+     * 导出字段与字典编码的映射关系:entity字段名 → 字典编码
+     * 用于导出时自动将字典值翻译为中文标签
+     */
+    private static final Map<String, String> EXPORT_DICT_FIELD_MAP = new LinkedHashMap<>();
+
+    static {
+        EXPORT_DICT_FIELD_MAP.put("dataSource", "DataSource");
+    }
+
     /**
      * 分页列表查询
      *
@@ -158,6 +168,7 @@ public class EnterpriseTagController extends JeecgController<EnterpriseTag, IEnt
 
     /**
      * 导出excel
+     * 导出顺序按树形层级展开:一级→二级→三级(非树形,扁平化顺序)
      *
      * @param request
      * @param enterpriseTag
@@ -170,6 +181,21 @@ public class EnterpriseTagController extends JeecgController<EnterpriseTag, IEnt
 
         List<EnterpriseTagVo> exportList = enterpriseTagService.queryListWithRelationCount(queryWrapper, request);
 
+        // 字典字段值→标签内存映射翻译
+        exportList = enterpriseTagService.translateDictFields(exportList, EXPORT_DICT_FIELD_MAP);
+
+        // 将tagStatus转换为中文显示:1→启用,0→停用
+        for (EnterpriseTagVo tag : exportList) {
+            if ("1".equals(tag.getTagStatus())) {
+                tag.setTagStatus("启用");
+            } else if ("0".equals(tag.getTagStatus())) {
+                tag.setTagStatus("停用");
+            }
+        }
+
+        // 按树形层级排序:一级 → 一级下的二级 → 二级下的三级 → 下一个一级 ...
+        exportList = sortByTreeOrder(exportList);
+
         ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
         mv.addObject(NormalExcelConstants.FILE_NAME, "企业标签信息表");
         mv.addObject(NormalExcelConstants.CLASS, EnterpriseTagVo.class);
@@ -177,13 +203,68 @@ public class EnterpriseTagController extends JeecgController<EnterpriseTag, IEnt
         mv.addObject(NormalExcelConstants.PARAMS, exportParams);
         mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
 
-        String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
-        if (oConvertUtils.isNotEmpty(exportFields)) {
-            mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
-        }
+        // 指定导出字段,与前端表格列保持一致:标签名称、省标编码、标签编码、标签说明、启用状态、本地关联企业数、数据来源
+        String exportFields = "tagName,provinceStandardCode,tagCode,tagDescription,tagStatus,relationCount,dataSource";
+        mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
         return mv;
     }
 
+    /**
+     * 将标签列表按树形层级排序:一级 → 该一级的二级 → 该二级的三级 → 下一个一级 ...
+     * 导出时扁平化展平,但保持"1、1.1、1.1.1、2、2.1、2.1.1"的顺序
+     */
+    private List<EnterpriseTagVo> sortByTreeOrder(List<EnterpriseTagVo> tags) {
+        // 构建 id→tag 映射
+        Map<String, EnterpriseTagVo> tagMap = new LinkedHashMap<>();
+        // 构建 parentId→children 映射(二级的parent是一级,三级的parent是二级)
+        Map<String, List<EnterpriseTagVo>> parentChildrenMap = new LinkedHashMap<>();
+
+        for (EnterpriseTagVo tag : tags) {
+            tagMap.put(tag.getId(), tag);
+            String parentId = "2".equals(tag.getTagLevel()) ? tag.getFirstCategory()
+                    : "3".equals(tag.getTagLevel()) ? tag.getSecondCategory() : null;
+            if (parentId != null && !parentId.isEmpty()) {
+                parentChildrenMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(tag);
+            }
+        }
+
+        // 深度优先遍历:一级 → 其二级 → 二级的三级
+        List<EnterpriseTagVo> ordered = new ArrayList<>();
+        Set<String> visited = new HashSet<>();
+
+        for (EnterpriseTagVo tag : tags) {
+            // 只处理根节点:一级且无父分类
+            if ("1".equals(tag.getTagLevel()) && (tag.getFirstCategory() == null || tag.getFirstCategory().isEmpty())) {
+                appendTreeOrder(tag, tagMap, parentChildrenMap, visited, ordered);
+            }
+        }
+
+        // 处理可能遗漏的游离节点(如搜索过滤后父节点不在列表中的子节点)
+        for (EnterpriseTagVo tag : tags) {
+            if (!visited.contains(tag.getId())) {
+                ordered.add(tag);
+            }
+        }
+
+        return ordered;
+    }
+
+    private void appendTreeOrder(EnterpriseTagVo tag, Map<String, EnterpriseTagVo> tagMap,
+                                  Map<String, List<EnterpriseTagVo>> parentChildrenMap,
+                                  Set<String> visited, List<EnterpriseTagVo> ordered) {
+        if (!visited.add(tag.getId())) {
+            return;
+        }
+        ordered.add(tag);
+        // 递归添加子节点
+        List<EnterpriseTagVo> children = parentChildrenMap.get(tag.getId());
+        if (children != null) {
+            for (EnterpriseTagVo child : children) {
+                appendTreeOrder(child, tagMap, parentChildrenMap, visited, ordered);
+            }
+        }
+    }
+
     /**
      * 通过excel导入数据
      *

+ 85 - 4
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/controller/PersonalTagController.java

@@ -56,6 +56,16 @@ public class PersonalTagController extends JeecgController<PersonalTag, IPersona
     @Autowired
     private PersonalTagRelationMapper personalTagRelationMapper;
 
+    /**
+     * 导出字段与字典编码的映射关系:entity字段名 → 字典编码
+     * 用于导出时自动将字典值翻译为中文标签
+     */
+    private static final Map<String, String> EXPORT_DICT_FIELD_MAP = new LinkedHashMap<>();
+
+    static {
+        EXPORT_DICT_FIELD_MAP.put("dataSource", "DataSource");
+    }
+
     /**
      * 分页列表查询
      *
@@ -157,6 +167,7 @@ public class PersonalTagController extends JeecgController<PersonalTag, IPersona
 
     /**
      * 导出excel
+     * 导出顺序按树形层级展开:一级→二级→三级(非树形,扁平化顺序)
      *
      * @param request
      * @param personalTag
@@ -169,6 +180,21 @@ public class PersonalTagController extends JeecgController<PersonalTag, IPersona
 
         List<PersonalTagVo> exportList = personalTagService.queryListWithRelationCount(queryWrapper, request);
 
+        // 字典字段值→标签内存映射翻译
+        exportList = personalTagService.translateDictFields(exportList, EXPORT_DICT_FIELD_MAP);
+
+        // 将tagStatus转换为中文显示:1→启用,0→停用
+        for (PersonalTagVo tag : exportList) {
+            if ("1".equals(tag.getTagStatus())) {
+                tag.setTagStatus("启用");
+            } else if ("0".equals(tag.getTagStatus())) {
+                tag.setTagStatus("停用");
+            }
+        }
+
+        // 按树形层级排序:一级 → 一级下的二级 → 二级下的三级 → 下一个一级 ...
+        exportList = sortByTreeOrder(exportList);
+
         ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
         mv.addObject(NormalExcelConstants.FILE_NAME, "个人标签信息表");
         mv.addObject(NormalExcelConstants.CLASS, PersonalTagVo.class);
@@ -176,13 +202,68 @@ public class PersonalTagController extends JeecgController<PersonalTag, IPersona
         mv.addObject(NormalExcelConstants.PARAMS, exportParams);
         mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
 
-        String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
-        if (oConvertUtils.isNotEmpty(exportFields)) {
-            mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
-        }
+        // 指定导出字段,与前端表格列保持一致:标签名称、省标编码、标签编码、标签说明、启用状态、本地关联人数、数据来源
+        String exportFields = "tagName,provinceStandardCode,tagCode,tagDescription,tagStatus,relationCount,dataSource";
+        mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
         return mv;
     }
 
+    /**
+     * 将标签列表按树形层级排序:一级 → 该一级的二级 → 该二级的三级 → 下一个一级 ...
+     * 导出时扁平化展平,但保持"1、1.1、1.1.1、2、2.1、2.1.1"的顺序
+     */
+    private List<PersonalTagVo> sortByTreeOrder(List<PersonalTagVo> tags) {
+        // 构建 id→tag 映射
+        Map<String, PersonalTagVo> tagMap = new LinkedHashMap<>();
+        // 构建 parentId→children 映射(二级的parent是一级,三级的parent是二级)
+        Map<String, List<PersonalTagVo>> parentChildrenMap = new LinkedHashMap<>();
+
+        for (PersonalTagVo tag : tags) {
+            tagMap.put(tag.getId(), tag);
+            String parentId = "2".equals(tag.getTagLevel()) ? tag.getFirstCategory()
+                    : "3".equals(tag.getTagLevel()) ? tag.getSecondCategory() : null;
+            if (parentId != null && !parentId.isEmpty()) {
+                parentChildrenMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(tag);
+            }
+        }
+
+        // 深度优先遍历:一级 → 其二级 → 二级的三级
+        List<PersonalTagVo> ordered = new ArrayList<>();
+        Set<String> visited = new HashSet<>();
+
+        for (PersonalTagVo tag : tags) {
+            // 只处理根节点:一级且无父分类
+            if ("1".equals(tag.getTagLevel()) && (tag.getFirstCategory() == null || tag.getFirstCategory().isEmpty())) {
+                appendTreeOrder(tag, tagMap, parentChildrenMap, visited, ordered);
+            }
+        }
+
+        // 处理可能遗漏的游离节点(如搜索过滤后父节点不在列表中的子节点)
+        for (PersonalTagVo tag : tags) {
+            if (!visited.contains(tag.getId())) {
+                ordered.add(tag);
+            }
+        }
+
+        return ordered;
+    }
+
+    private void appendTreeOrder(PersonalTagVo tag, Map<String, PersonalTagVo> tagMap,
+                                  Map<String, List<PersonalTagVo>> parentChildrenMap,
+                                  Set<String> visited, List<PersonalTagVo> ordered) {
+        if (!visited.add(tag.getId())) {
+            return;
+        }
+        ordered.add(tag);
+        // 递归添加子节点
+        List<PersonalTagVo> children = parentChildrenMap.get(tag.getId());
+        if (children != null) {
+            for (PersonalTagVo child : children) {
+                appendTreeOrder(child, tagMap, parentChildrenMap, visited, ordered);
+            }
+        }
+    }
+
     /**
      * 通过excel导入数据
      *

+ 10 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/service/IEnterpriseTagService.java

@@ -9,6 +9,7 @@ import org.jeecg.modules.zjrs.tag.entity.EnterpriseTag;
 import org.jeecg.modules.zjrs.tag.vo.EnterpriseTagVo;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * @Description: 企业标签信息表
@@ -42,4 +43,13 @@ public interface IEnterpriseTagService extends IService<EnterpriseTag> {
      * 全量查询企业标签(含本地关联企业数,用于导出)
      */
     List<EnterpriseTagVo> queryListWithRelationCount(Wrapper<EnterpriseTag> queryWrapper, HttpServletRequest req);
+
+    /**
+     * 导出时字典字段值→标签内存映射翻译
+     *
+     * @param list         导出数据列表
+     * @param fieldDictMap 字段名→字典编码的映射
+     * @return 翻译后的数据列表
+     */
+    List<EnterpriseTagVo> translateDictFields(List<EnterpriseTagVo> list, Map<String, String> fieldDictMap);
 }

+ 10 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/service/IPersonalTagService.java

@@ -9,6 +9,7 @@ import org.jeecg.modules.zjrs.tag.entity.PersonalTag;
 import org.jeecg.modules.zjrs.tag.vo.PersonalTagVo;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * @Description: 个人标签信息表
@@ -42,4 +43,13 @@ public interface IPersonalTagService extends IService<PersonalTag> {
      * 全量查询个人标签(含本地关联人数,用于导出)
      */
     List<PersonalTagVo> queryListWithRelationCount(Wrapper<PersonalTag> queryWrapper, HttpServletRequest req);
+
+    /**
+     * 导出时字典字段值→标签内存映射翻译
+     *
+     * @param list         导出数据列表
+     * @param fieldDictMap 字段名→字典编码的映射
+     * @return 翻译后的数据列表
+     */
+    List<PersonalTagVo> translateDictFields(List<PersonalTagVo> list, Map<String, String> fieldDictMap);
 }

+ 64 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/service/impl/EnterpriseTagServiceImpl.java

@@ -10,7 +10,9 @@ import jakarta.servlet.http.HttpServletRequest;
 import org.jeecg.common.exception.JeecgBootBizTipException;
 import org.jeecg.common.util.AssertUtils;
 import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.zjrs.dictionary.service.IDictionaryItemService;
 import org.jeecg.modules.zjrs.tag.entity.EnterpriseTag;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.jeecg.modules.zjrs.tag.mapper.EnterpriseTagMapper;
 import org.jeecg.modules.zjrs.tag.service.IEnterpriseTagService;
 import org.jeecg.modules.zjrs.tag.vo.EnterpriseTagVo;
@@ -18,7 +20,10 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @Description: 企业标签信息表
@@ -29,6 +34,9 @@ import java.util.List;
 @Service
 public class EnterpriseTagServiceImpl extends ServiceImpl<EnterpriseTagMapper, EnterpriseTag> implements IEnterpriseTagService {
 
+    @Autowired
+    private IDictionaryItemService dictionaryItemService;
+
     @Override
     public String generateTagCode() {
         LambdaQueryWrapper<EnterpriseTag> queryWrapper = new LambdaQueryWrapper<>();
@@ -85,4 +93,60 @@ public class EnterpriseTagServiceImpl extends ServiceImpl<EnterpriseTagMapper, E
         }
         return baseMapper.queryListWithRelationCount(queryWrapper);
     }
+
+    @Override
+    public List<EnterpriseTagVo> translateDictFields(List<EnterpriseTagVo> list, Map<String, String> fieldDictMap) {
+        // 批量查询导出涉及的所有字典数据
+        List<String> dictCodes = new ArrayList<>(fieldDictMap.values());
+        Map<String, List<Map<String, Object>>> dictData = dictionaryItemService.getDictItemsBatch(dictCodes);
+
+        // 构建 value→label 快速查找映射: Map<字典编码, Map<value, label>>
+        Map<String, Map<String, String>> valueLabelMap = new HashMap<>();
+        for (Map.Entry<String, List<Map<String, Object>>> entry : dictData.entrySet()) {
+            Map<String, String> valueToLabel = new HashMap<>();
+            for (Map<String, Object> item : entry.getValue()) {
+                valueToLabel.put(String.valueOf(item.get("value")), String.valueOf(item.get("label")));
+            }
+            valueLabelMap.put(entry.getKey(), valueToLabel);
+        }
+
+        // 遍历导出数据,将字典字段的值替换为对应的中文标签
+        for (EnterpriseTagVo tag : list) {
+            for (Map.Entry<String, String> fieldEntry : fieldDictMap.entrySet()) {
+                String fieldName = fieldEntry.getKey();
+                String dictCode = fieldEntry.getValue();
+                Map<String, String> mapping = valueLabelMap.get(dictCode);
+                if (mapping == null) {
+                    continue;
+                }
+                Object fieldValue = getFieldValue(tag, fieldName);
+                if (fieldValue != null) {
+                    String label = mapping.get(String.valueOf(fieldValue));
+                    if (label != null) {
+                        setFieldValue(tag, fieldName, label);
+                    }
+                }
+            }
+        }
+        return list;
+    }
+
+    private Object getFieldValue(EnterpriseTagVo tag, String fieldName) {
+        try {
+            java.lang.reflect.Field field = EnterpriseTagVo.class.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            return field.get(tag);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    private void setFieldValue(EnterpriseTagVo tag, String fieldName, Object value) {
+        try {
+            java.lang.reflect.Field field = EnterpriseTagVo.class.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            field.set(tag, value);
+        } catch (Exception ignored) {
+        }
+    }
 }

+ 64 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/service/impl/PersonalTagServiceImpl.java

@@ -10,7 +10,9 @@ import jakarta.servlet.http.HttpServletRequest;
 import org.jeecg.common.exception.JeecgBootBizTipException;
 import org.jeecg.common.util.AssertUtils;
 import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.zjrs.dictionary.service.IDictionaryItemService;
 import org.jeecg.modules.zjrs.tag.entity.PersonalTag;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.jeecg.modules.zjrs.tag.mapper.PersonalTagMapper;
 import org.jeecg.modules.zjrs.tag.service.IPersonalTagService;
 import org.jeecg.modules.zjrs.tag.vo.PersonalTagVo;
@@ -18,7 +20,10 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @Description: 个人标签信息表
@@ -29,6 +34,9 @@ import java.util.List;
 @Service
 public class PersonalTagServiceImpl extends ServiceImpl<PersonalTagMapper, PersonalTag> implements IPersonalTagService {
 
+    @Autowired
+    private IDictionaryItemService dictionaryItemService;
+
     @Override
     public String generateTagCode() {
         LambdaQueryWrapper<PersonalTag> queryWrapper = new LambdaQueryWrapper<>();
@@ -85,4 +93,60 @@ public class PersonalTagServiceImpl extends ServiceImpl<PersonalTagMapper, Perso
         }
         return baseMapper.queryListWithRelationCount(queryWrapper);
     }
+
+    @Override
+    public List<PersonalTagVo> translateDictFields(List<PersonalTagVo> list, Map<String, String> fieldDictMap) {
+        // 批量查询导出涉及的所有字典数据
+        List<String> dictCodes = new ArrayList<>(fieldDictMap.values());
+        Map<String, List<Map<String, Object>>> dictData = dictionaryItemService.getDictItemsBatch(dictCodes);
+
+        // 构建 value→label 快速查找映射: Map<字典编码, Map<value, label>>
+        Map<String, Map<String, String>> valueLabelMap = new HashMap<>();
+        for (Map.Entry<String, List<Map<String, Object>>> entry : dictData.entrySet()) {
+            Map<String, String> valueToLabel = new HashMap<>();
+            for (Map<String, Object> item : entry.getValue()) {
+                valueToLabel.put(String.valueOf(item.get("value")), String.valueOf(item.get("label")));
+            }
+            valueLabelMap.put(entry.getKey(), valueToLabel);
+        }
+
+        // 遍历导出数据,将字典字段的值替换为对应的中文标签
+        for (PersonalTagVo tag : list) {
+            for (Map.Entry<String, String> fieldEntry : fieldDictMap.entrySet()) {
+                String fieldName = fieldEntry.getKey();
+                String dictCode = fieldEntry.getValue();
+                Map<String, String> mapping = valueLabelMap.get(dictCode);
+                if (mapping == null) {
+                    continue;
+                }
+                Object fieldValue = getFieldValue(tag, fieldName);
+                if (fieldValue != null) {
+                    String label = mapping.get(String.valueOf(fieldValue));
+                    if (label != null) {
+                        setFieldValue(tag, fieldName, label);
+                    }
+                }
+            }
+        }
+        return list;
+    }
+
+    private Object getFieldValue(PersonalTagVo tag, String fieldName) {
+        try {
+            java.lang.reflect.Field field = PersonalTagVo.class.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            return field.get(tag);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    private void setFieldValue(PersonalTagVo tag, String fieldName, Object value) {
+        try {
+            java.lang.reflect.Field field = PersonalTagVo.class.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            field.set(tag, value);
+        } catch (Exception ignored) {
+        }
+    }
 }

+ 7 - 6
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/vo/EnterpriseTagVo.java

@@ -28,6 +28,12 @@ public class EnterpriseTagVo implements Serializable {
      */
     @Schema(description = "主键ID")
     private java.lang.String id;
+    /**
+     * 标签名称
+     */
+    @Excel(name = "标签名称", width = 15)
+    @Schema(description = "标签名称")
+    private java.lang.String tagName;
     /**
      * 省标编码
      */
@@ -37,14 +43,9 @@ public class EnterpriseTagVo implements Serializable {
     /**
      * 标签编码
      */
+    @Excel(name = "标签编码", width = 15)
     @Schema(description = "标签编码")
     private java.lang.String tagCode;
-    /**
-     * 标签名称
-     */
-    @Excel(name = "标签名称", width = 15)
-    @Schema(description = "标签名称")
-    private java.lang.String tagName;
     /**
      * 所属一级分类
      */

+ 7 - 6
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/tag/vo/PersonalTagVo.java

@@ -28,6 +28,12 @@ public class PersonalTagVo implements Serializable {
      */
     @Schema(description = "主键ID")
     private java.lang.String id;
+    /**
+     * 标签名称
+     */
+    @Excel(name = "标签名称", width = 15)
+    @Schema(description = "标签名称")
+    private java.lang.String tagName;
     /**
      * 省标编码
      */
@@ -37,14 +43,9 @@ public class PersonalTagVo implements Serializable {
     /**
      * 标签编码
      */
+    @Excel(name = "标签编码", width = 15)
     @Schema(description = "标签编码")
     private java.lang.String tagCode;
-    /**
-     * 标签名称
-     */
-    @Excel(name = "标签名称", width = 15)
-    @Schema(description = "标签名称")
-    private java.lang.String tagName;
     /**
      * 所属一级分类
      */