Переглянути джерело

fix: 岗位基本信息第二版与企业信息调整

zhangying 6 днів тому
батько
коміт
bb239b1f1e

+ 1 - 1
.docs/260604-企业基本信息模块开发记录.md

@@ -170,7 +170,7 @@
 
 | 文件                                               | 操作 | 原因                                    |
 |--------------------------------------------------|----|---------------------------------------|
-| `jeecgboot-vue3/src/views/recruitment/enterprise/EnterpriseInfoList.vue` | 修改 | 导入 `useDict`,预加载 BusinessStatus/CompanyType/CompanySize/DataSource 字典;`bodyCell` 插槽添加 4 个字典字段的 `getDictText()` 翻译渲染 |
+| `jeecgboot-vue3/src/views/recruitment/enterprise/EnterpriseInfoList.vue` | 修改 | 搜索字段改为单位名称/统一信用代码/注册地址/经营地址/单位类型/所属行业/数据来源;单位类型、数据来源使用 `<a-select>` 字典下拉;导入 `useDict` 并添加 `getDictOptions`/`getDictText`;`bodyCell` 插槽添加 4 个字典字段的翻译渲染 |
 | `jeecgboot-vue3/src/views/recruitment/enterprise/components/EnterpriseInfoForm.vue` | 修改 | 导入 `useDict`,预加载 5 个字典;5 个字典字段从 `<a-input>` 改为 `<a-select>` 下拉选择;校验提示从"请输入"改为"请选择" |
 | `jeecg-boot/.../enterprise/controller/EnterpriseInfoController.java` | 修改 | 添加 `EXPORT_DICT_FIELD_MAP` 静态常量映射 4 个字段到字典编码;导出流程增加 `translateDictFields` 调用 |
 | `jeecg-boot/.../enterprise/service/IEnterpriseInfoService.java` | 修改 | 添加 `translateDictFields` 方法声明 |

+ 239 - 0
.docs/260604-岗位信息模块开发记录.md

@@ -0,0 +1,239 @@
+# 岗位信息模块开发记录
+
+**日期:** 2026-06-04
+
+## 模块概述
+
+岗位信息模块(post)是招聘管理系统中的核心模块,负责管理招聘岗位的基本信息。该模块采用 JeecgBoot 的前后端分离架构,前端基于 Vue3 + Ant Design Vue,后端基于 Spring Boot + MyBatis-Plus。
+
+### 业务关系
+
+- **PostInfo(岗位信息)**:唯一的主表,通过 `enterprise_id` 字段关联 EnterpriseInfo(企业基本信息)表。列表查询时通过 LEFT JOIN 获取关联企业的单位名称(companyName),表单中通过 JSearchSelect 组件从企业信息表中搜索选择关联企业。
+
+---
+
+## 模块文件结构
+
+### 前端(jeecgboot-vue3/src/views/recruitment/post/)
+
+| 文件                                  | 用途                             |
+|-------------------------------------|--------------------------------|
+| `PostInfoList.vue`                  | 岗位信息列表页面,提供查询、新增、编辑、详情、删除、批量删除、导入导出等功能 |
+| `PostInfo.api.ts`                   | 岗位信息 API 封装                    |
+| `PostInfo.data.ts`                  | 列表页表格列配置(14列)与高级查询字段定义(22个查询字段) |
+| `components/PostInfoForm.vue`       | 岗位信息新增/编辑/详情表单组件,关联企业通过搜索选择下拉框录入  |
+| `components/PostInfoModal.vue`      | 岗位信息弹窗组件,包裹 PostInfoForm,全屏模式     |
+
+### 后端(jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/.../org/jeecg/modules/zjrs/post/)
+
+| 层次           | 文件                                          |
+|--------------|---------------------------------------------|
+| Controller   | `PostInfoController.java`                   |
+| Entity       | `PostInfo.java`                             |
+| VO           | `vo/PostInfoVo.java`                        |
+| Service      | `IPostInfoService.java`                     |
+| Service Impl | `PostInfoServiceImpl.java`                  |
+| Mapper       | `PostInfoMapper.java`                       |
+| Mapper XML   | `mapper/xml/PostInfoMapper.xml`             |
+
+---
+
+## 开发记录
+
+### 功能清单
+
+| 功能            | 说明                                                             |
+|---------------|----------------------------------------------------------------|
+| 分页列表查询        | 支持按岗位名称、单位名称、工作地点、学历要求等条件查询,14 列展示                        |
+| 新增            | 全屏表单,支持 23 个岗位字段录入,关联企业通过搜索选择下拉框从企业信息表中选择                      |
+| 编辑            | 复用新增表单,预填充已有数据                                                |
+| 详情            | 表单禁用模式查看岗位全部信息                                                |
+| 删除 / 批量删除     | 支持单条删除和批量删除,删除前弹窗确认                                           |
+| 导入 / 导出 Excel | 基于 Jeecg 标准 Excel 导入导出功能,导出使用 PostInfoVo 包含关联企业名称               |
+| 高级查询          | 22 个查询字段,支持灵活的筛选条件                                            |
+| 字段必填校验        | 前端(Ant Design Vue Form 校验)+ 后端(Service 层 `validatePostInfo`)双重校验    |
+| 薪酬范围校验        | 前后端均校验最高薪酬必须大于最低薪酬                                            |
+| 联系电话格式校验      | 前后端均校验联系电话格式(`^1[3-9]\d{9}$`)                                 |
+
+### 必填字段(前后端一致)
+
+共 16 个必填字段:关联企业、职业、岗位名称、工作性质、薪酬待遇、招聘人数(必须大于0)、岗位有效期、职位标签、岗位描述、学历要求、工作经验、职业技能等级、联系人、联系电话(需匹配手机号格式)、工作地点、详细地址、数据来源。
+
+---
+
+### 功能开发
+
+| 日期         | 内容           | 涉及文件          | 说明                     |
+|------------|--------------|---------------|------------------------|
+| 2026-06-04 | 岗位信息模块初始构建 | 前端 5 个文件 + 后端 7 个文件 | 完成岗位信息管理的基础 CRUD 功能,含 Excel 导入导出、企业信息关联 LEFT JOIN 查询与企业搜索选择下拉框 |
+
+### PostInfo 实体字段一览
+
+| 分类     | 字段                   | 说明            |
+|--------|----------------------|---------------|
+| 基本关联   | enterpriseId         | 关联企业基本信息ID    |
+| 岗位信息   | occupation           | 职业            |
+|        | postName             | 岗位名称          |
+|        | workNature           | 工作性质          |
+|        | postTag              | 职位标签          |
+|        | postDesc             | 岗位描述          |
+| 薪酬信息   | salaryType           | 薪酬待遇          |
+|        | salaryMin            | 最低薪酬          |
+|        | salaryMax            | 最高薪酬          |
+|        | recruitCount         | 招聘人数          |
+| 时效     | postValidDate        | 岗位有效期         |
+| 福利     | otherBenefits        | 其他福利          |
+| 要求条件   | educationRequire     | 学历要求          |
+|        | workExperienceRequire| 工作经验          |
+|        | skillLevelRequire    | 职业技能等级        |
+|        | foreignLanguage      | 外语语种          |
+|        | languageLevel        | 外语水平要求        |
+| 联系方式   | contactPerson        | 联系人           |
+|        | contactPhone         | 联系电话          |
+| 工作地点   | workLocation         | 工作地点          |
+|        | detailedAddress      | 详细地址          |
+| 配置     | dataSource           | 数据来源          |
+| 系统字段   | id / createBy / createTime / updateBy / updateTime / sysOrgCode | 系统内置字段        |
+
+### PostInfoVo 扩展字段
+
+| 字段          | 说明               | 来源                  |
+|-------------|------------------|---------------------|
+| companyName | 单位名称             | LEFT JOIN enterprise_info 表获取 |
+
+---
+
+### 2026-06-04:岗位信息模块初始构建
+
+**需求描述:** 构建岗位信息管理模块,实现岗位信息的基础 CRUD、Excel 导入导出功能。岗位需关联企业基本信息表,列表和导出中需要显示企业名称。
+
+**表格列(14列):**
+
+| 列            | 对应字段              | 说明                     |
+|---------------|-------------------|------------------------|
+| 序号            | index              | 自定义列,customRender 显示行索引   |
+| 单位名称          | companyName       | 自 enterprise_info 表 LEFT JOIN 获取 |
+| 职业            | occupation        | —                      |
+| 岗位名称          | postName          | —                      |
+| 工作性质          | workNature        | —                      |
+| 薪酬待遇          | salaryType        | —                      |
+| 最低薪酬          | salaryMin         | —                      |
+| 最高薪酬          | salaryMax         | —                      |
+| 招聘人数          | recruitCount      | —                      |
+| 岗位有效期         | postValidDate     | —                      |
+| 学历要求          | educationRequire  | —                      |
+| 联系人           | contactPerson     | —                      |
+| 联系电话          | contactPhone      | —                      |
+| 工作地点          | workLocation      | —                      |
+
+**搜索区域(4个查询条件):** 岗位名称、单位名称、工作地点、学历要求
+
+**涉及文件:**
+
+| 文件                                               | 操作 | 原因                                    |
+|--------------------------------------------------|----|---------------------------------------|
+| `jeecgboot-vue3/src/views/recruitment/post/PostInfoList.vue` | 新增 | 岗位信息列表页,含查询区域、表格、操作栏、导入导出按钮 |
+| `jeecgboot-vue3/src/views/recruitment/post/PostInfo.api.ts` | 新增 | 封装岗位信息 CRUD、导入导出 API 接口 |
+| `jeecgboot-vue3/src/views/recruitment/post/PostInfo.data.ts` | 新增 | 定义 14 列表格列配置与 22 个高级查询字段 |
+| `jeecgboot-vue3/src/views/recruitment/post/components/PostInfoForm.vue` | 新增 | 岗位信息表单,含 JSearchSelect 关联企业搜索选择、前后端双校验 |
+| `jeecgboot-vue3/src/views/recruitment/post/components/PostInfoModal.vue` | 新增 | 全屏弹窗包裹 PostInfoForm,提供新增/编辑/详情入口 |
+| `jeecg-boot/.../post/controller/PostInfoController.java` | 新增 | 岗位信息 REST 控制器,分页列表使用 `queryPageListWithEnterprise` 返回 PostInfoVo 含企业名称;导出使用 `queryListWithEnterprise` 支持选中导出和全量导出 |
+| `jeecg-boot/.../post/entity/PostInfo.java` | 新增 | 岗位信息实体,映射 `post_info` 表,含 23 个业务字段 + 系统字段 |
+| `jeecg-boot/.../post/vo/PostInfoVo.java` | 新增 | 岗位信息 VO,包含 PostInfo 所有字段 + companyName 扩展字段(关联企业名称),用于列表展示和 Excel 导出 |
+| `jeecg-boot/.../post/service/IPostInfoService.java` | 新增 | 岗位信息服务接口,定义 `queryPageListWithEnterprise` 和 `queryListWithEnterprise` 两个自定义查询方法 |
+| `jeecg-boot/.../post/service/impl/PostInfoServiceImpl.java` | 新增 | 服务实现,重写 `save`/`updateById` 增加 `validatePostInfo` 校验(16个必填项 + 薪酬范围 + 手机号格式) |
+| `jeecg-boot/.../post/mapper/PostInfoMapper.java` | 新增 | Mapper 接口,定义 `queryPageListWithEnterprise`(分页)和 `queryListWithEnterprise`(全量)两个自定义 SQL 方法 |
+| `jeecg-boot/.../post/mapper/xml/PostInfoMapper.xml` | 新增 | MyBatis XML 映射,LEFT JOIN enterprise_info 表获取 companyName 字段 |
+
+---
+
+### 2026-06-04:岗位列表查询字段与展示字段调整
+
+**需求描述:** 调整岗位信息列表页的查询条件字段和表格展示字段,使其与实际业务需求更加匹配。
+
+**查询字段调整(6个):**
+
+| 新查询字段 | 对应字段              | 说明                         |
+|-----------|-------------------|----------------------------|
+| 企业名称     | companyName       | 原"单位名称"改名为"企业名称"           |
+| 职业工种     | occupation        | 原"职业"改名为"职业工种"             |
+| 岗位名称     | postName          | 保留                          |
+| 学历要求     | educationRequire  | 保留                          |
+| 联系人      | contactPerson     | 新增查询字段                      |
+| 数据来源     | dataSource        | 新增查询字段                      |
+
+**删除的查询字段:** 工作地点
+
+**表格列调整(14列):**
+
+| 新列               | 对应字段                | 说明                     |
+|------------------|---------------------|------------------------|
+| 序号               | index               | 保留                     |
+| 企业名称             | companyName         | 原"单位名称"改名为"企业名称"       |
+| 职业工种             | occupation          | 原"职业"改名为"职业工种"         |
+| 岗位名称             | postName            | 保留                     |
+| 薪酬待遇(最低)         | salaryMin           | 原"最低薪酬"改名,合并薪酬展示      |
+| 薪酬待遇(最高)         | salaryMax           | 原"最高薪酬"改名,合并薪酬展示      |
+| 招聘人数             | recruitCount        | 保留                     |
+| 岗位有效期            | postValidDate       | 保留                     |
+| 职位标签             | postTag             | 新增显示字段                 |
+| 学历要求             | educationRequire    | 保留                     |
+| 工作经验             | workExperienceRequire | 新增显示字段                |
+| 联系人              | contactPerson       | 保留                     |
+| 联系电话             | contactPhone        | 保留                     |
+| 数据来源             | dataSource          | 新增显示字段                 |
+
+**删除的列:** 工作性质、薪酬待遇、工作地点
+
+**涉及文件:**
+
+| 文件                                               | 操作 | 原因                                    |
+|--------------------------------------------------|----|---------------------------------------|
+| `jeecgboot-vue3/src/views/recruitment/post/PostInfoList.vue` | 修改 | 查询表单 4 个字段改为 6 个(企业名称、职业工种、岗位名称、学历要求、联系人、数据来源) |
+| `jeecgboot-vue3/src/views/recruitment/post/PostInfo.data.ts` | 修改 | 更新 columns 定义,调整为 14 列新字段配置(移除工作性质、薪酬待遇、工作地点,新增职位标签、工作经验、数据来源,改名企业名称、职业工种、薪酬待遇列标题) |
+| `jeecg-boot/.../post/controller/PostInfoController.java` | 修改 | 分页列表查询接口新增 companyName 查询参数处理并委托 Service 实现;导出接口同步增加 companyName 查询条件支持 |
+| `jeecg-boot/.../post/service/IPostInfoService.java` | 修改 | 方法签名增加 `HttpServletRequest req` 参数 |
+| `jeecg-boot/.../post/service/impl/PostInfoServiceImpl.java` | 修改 | 将 companyName 模糊查询和导出 selections 选中筛选逻辑从 Controller 移到 Service 层的 `applyCustomConditions` 私有方法 |
+
+---
+
+### 2026-06-04:Controller 业务逻辑下沉到 Service 层
+
+**需求描述:** 将 PostInfoController 中本应属于 Service 层的业务逻辑代码(企业名称手动查询条件拼接、导出选中记录筛选)迁移到 Service 层,保持 Controller 层职责清晰。
+
+**涉及文件:**
+
+| 文件                                               | 操作 | 原因                                    |
+|--------------------------------------------------|----|---------------------------------------|
+| `jeecg-boot/.../post/controller/PostInfoController.java` | 修改 | 移除 `queryPageList` 中的 `companyName` 手动拼接代码;移除 `exportXls` 中的 `selections` 解析和 `companyName` 拼接代码,改为委托 Service 方法处理;移除不再使用的 `java.util.List` 导入 |
+| `jeecg-boot/.../post/service/IPostInfoService.java` | 修改 | `queryPageListWithEnterprise` 和 `queryListWithEnterprise` 方法签名增加 `HttpServletRequest req` 参数 |
+| `jeecg-boot/.../post/service/impl/PostInfoServiceImpl.java` | 修改 | 新增 `applyCustomConditions` 私有方法封装企业名称模糊查询逻辑;`queryListWithEnterprise` 中新增导出 selections 选中记录筛选处理;新增 `QueryWrapper`、`HttpServletRequest`、`oConvertUtils`、`Arrays` 导入 |
+
+---
+
+### 2026-06-04:数据字典字段适配(查询表单 + 数据表格 + 编辑表单 + 导出翻译)
+
+**需求描述:** 将岗位信息模块中匹配数据字典的字段从普通文本输入改为下拉选择,列表页显示中文标签,导出时自动翻译字典值为中文。
+
+**涉及字典及字段映射:**
+
+| 字段名                     | 字典编码            | 说明     |
+|--------------------------|-----------------|--------|
+| `workNature`             | WorkNature      | 工作性质   |
+| `salaryType`             | SalaryType      | 薪酬待遇   |
+| `postTag`                | PostTag         | 职位标签   |
+| `educationRequire`       | Education       | 学历要求   |
+| `workExperienceRequire`  | WorkExperience  | 工作经验   |
+| `skillLevelRequire`      | SkillLevel      | 职业技能等级 |
+| `languageLevel`          | LanguageLevel   | 外语水平要求 |
+| `dataSource`             | DataSource      | 数据来源   |
+
+**涉及文件:**
+
+| 文件                                               | 操作 | 原因                                    |
+|--------------------------------------------------|----|---------------------------------------|
+| `jeecgboot-vue3/src/views/recruitment/post/PostInfoList.vue` | 修改 | 导入 `useDict` 并添加 `getDictText`/`getDictOptions`;查询表单中学历要求、数据来源从 `<a-input>` 改为 `<a-select>` 字典下拉;`bodyCell` 插槽添加 4 个字典字段(职位标签、学历要求、工作经验、数据来源)的翻译渲染 |
+| `jeecgboot-vue3/src/views/recruitment/post/components/PostInfoForm.vue` | 修改 | 导入 `useDict`,预加载 8 个字典;工作性质、薪酬待遇、职位标签、学历要求、工作经验、职业技能等级、外语水平要求、数据来源 从 `<a-input>` 改为 `<a-select>` 下拉选择;校验提示从"请输入"改为"请选择" |
+| `jeecg-boot/.../post/controller/PostInfoController.java` | 修改 | 添加 `EXPORT_DICT_FIELD_MAP` 静态常量映射 8 个字段到字典编码;导出流程增加 `translateDictFields` 调用 |
+| `jeecg-boot/.../post/service/IPostInfoService.java` | 修改 | 添加 `translateDictFields` 方法声明 |
+| `jeecg-boot/.../post/service/impl/PostInfoServiceImpl.java` | 修改 | 注入 `IDictionaryItemService`;实现 `translateDictFields` 方法,采用后端内存映射方案批量查询字典并替换字段值;移除未使用的 `Collectors` 导入 |

+ 54 - 0
.docs/sql/数据字典数据插入.sql

@@ -323,6 +323,14 @@ INSERT INTO "DICTIONARY_ITEM"
 VALUES ('1174509082208395376', '', 'SkillLevel', 4, '职业资格四级(中级)', 4, 1, 1);
 INSERT INTO "DICTIONARY_ITEM"
 VALUES ('1174509082208395377', '', 'SkillLevel', 5, '职业资格五级(初级)', 5, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395414', '', 'SkillLevel', 6, '初级职称', 6, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395415', '', 'SkillLevel', 7, '中级职称', 7, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395416', '', 'SkillLevel', 8, '高级职称', 8, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395417', '', 'SkillLevel', 9, '无职业技能等级要求', 9, 1, 1);
 
 -- ----------------------------
 -- 17. 职称级别 (TitleLevel)
@@ -383,3 +391,49 @@ INSERT INTO "DICTIONARY_ITEM"
 VALUES ('1174509082208395397', '', 'IndustryField', 10, '金融机构', 10, 1, 1);
 INSERT INTO "DICTIONARY_ITEM"
 VALUES ('1174509082208395398', '', 'IndustryField', 11, '其他', 11, 1, 1);
+
+-- ----------------------------
+-- 20. 薪酬待遇 (SalaryType)
+-- ----------------------------
+INSERT INTO "DICTIONARY"
+VALUES ('SalaryType', '薪酬待遇', 20, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395399', '', 'SalaryType', 1, '月薪(元/月)', 1, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395400', '', 'SalaryType', 2, '年薪(万元/年)', 2, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395401', '', 'SalaryType', 3, '面议', 3, 1, 1);
+
+-- ----------------------------
+-- 21. 职位标签 (PostTag)
+-- ----------------------------
+INSERT INTO "DICTIONARY"
+VALUES ('PostTag', '职位标签', 21, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395402', '', 'PostTag', 1, '普通岗位', 1, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395403', '', 'PostTag', 2, '妈妈岗', 2, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395404', '', 'PostTag', 3, '应届毕业生', 3, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395405', '', 'PostTag', 4, '港澳籍', 4, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395406', '', 'PostTag', 5, '劳务协作', 5, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395407', '', 'PostTag', 6, '残疾人', 6, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395408', '', 'PostTag', 7, '动火作业岗位', 7, 1, 1);
+
+-- ----------------------------
+-- 22. 外语水平要求 (LanguageLevel)
+-- ----------------------------
+INSERT INTO "DICTIONARY"
+VALUES ('LanguageLevel', '外语水平要求', 22, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395409', '', 'LanguageLevel', 1, '精通', 1, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395410', '', 'LanguageLevel', 2, '熟练', 2, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395411', '', 'LanguageLevel', 3, '良好', 3, 1, 1);
+INSERT INTO "DICTIONARY_ITEM"
+VALUES ('1174509082208395412', '', 'LanguageLevel', 4, '一般', 4, 1, 1);

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

@@ -28,7 +28,9 @@ import org.springframework.web.bind.annotation.*;
 import org.springframework.web.servlet.ModelAndView;
 
 import java.util.Arrays;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @Description: 岗位信息表
@@ -44,6 +46,23 @@ public class PostInfoController extends JeecgController<PostInfo, IPostInfoServi
     @Autowired
     private IPostInfoService postInfoService;
 
+    /**
+     * 导出字段与字典编码的映射关系:entity字段名 → 字典编码
+     * 用于导出时自动将字典值翻译为中文标签
+     */
+    private static final Map<String, String> EXPORT_DICT_FIELD_MAP = new LinkedHashMap<>();
+
+    static {
+        EXPORT_DICT_FIELD_MAP.put("workNature", "WorkNature");
+        EXPORT_DICT_FIELD_MAP.put("salaryType", "SalaryType");
+        EXPORT_DICT_FIELD_MAP.put("postTag", "PostTag");
+        EXPORT_DICT_FIELD_MAP.put("educationRequire", "Education");
+        EXPORT_DICT_FIELD_MAP.put("workExperienceRequire", "WorkExperience");
+        EXPORT_DICT_FIELD_MAP.put("skillLevelRequire", "SkillLevel");
+        EXPORT_DICT_FIELD_MAP.put("languageLevel", "LanguageLevel");
+        EXPORT_DICT_FIELD_MAP.put("dataSource", "DataSource");
+    }
+
     /**
      * 分页列表查询
      *
@@ -61,7 +80,7 @@ public class PostInfoController extends JeecgController<PostInfo, IPostInfoServi
                                                    HttpServletRequest req) {
         QueryWrapper<PostInfo> queryWrapper = QueryGenerator.initQueryWrapper(postInfo, req.getParameterMap());
         Page<PostInfoVo> page = new Page<PostInfoVo>(pageNo, pageSize);
-        IPage<PostInfoVo> pageList = postInfoService.queryPageListWithEnterprise(page, queryWrapper);
+        IPage<PostInfoVo> pageList = postInfoService.queryPageListWithEnterprise(page, queryWrapper, req);
         return Result.OK(pageList);
     }
 
@@ -153,13 +172,7 @@ public class PostInfoController extends JeecgController<PostInfo, IPostInfoServi
         QueryWrapper<PostInfo> queryWrapper = QueryGenerator.initQueryWrapper(postInfo, request.getParameterMap());
         LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
 
-        String selections = request.getParameter("selections");
-        if (oConvertUtils.isNotEmpty(selections)) {
-            List<String> selectionList = Arrays.asList(selections.split(","));
-            queryWrapper.in("p.id", selectionList);
-        }
-
-        List<PostInfoVo> exportList = postInfoService.queryListWithEnterprise(queryWrapper);
+        List<PostInfoVo> exportList = postInfoService.queryListWithEnterprise(queryWrapper, request);
 
         ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
         mv.addObject(NormalExcelConstants.FILE_NAME, "岗位信息表");

+ 13 - 2
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/post/service/IPostInfoService.java

@@ -4,10 +4,12 @@ import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
+import jakarta.servlet.http.HttpServletRequest;
 import org.jeecg.modules.zjrs.post.entity.PostInfo;
 import org.jeecg.modules.zjrs.post.vo.PostInfoVo;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * @Description: 岗位信息表
@@ -17,7 +19,16 @@ import java.util.List;
  */
 public interface IPostInfoService extends IService<PostInfo> {
 
-    IPage<PostInfoVo> queryPageListWithEnterprise(Page<PostInfoVo> page, Wrapper<PostInfo> queryWrapper);
+    IPage<PostInfoVo> queryPageListWithEnterprise(Page<PostInfoVo> page, Wrapper<PostInfo> queryWrapper, HttpServletRequest req);
 
-    List<PostInfoVo> queryListWithEnterprise(Wrapper<PostInfo> queryWrapper);
+    List<PostInfoVo> queryListWithEnterprise(Wrapper<PostInfo> queryWrapper, HttpServletRequest req);
+
+    /**
+     * 导出时对字典字段进行值→标签的内存映射翻译
+     *
+     * @param list         待导出的数据列表
+     * @param fieldDictMap 字段名→字典编码 的映射关系
+     * @return 字典字段已替换为中文标签的数据列表
+     */
+    List<PostInfoVo> translateDictFields(List<PostInfoVo> list, Map<String, String> fieldDictMap);
 }

+ 99 - 3
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/post/service/impl/PostInfoServiceImpl.java

@@ -1,17 +1,22 @@
 package org.jeecg.modules.zjrs.post.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.servlet.http.HttpServletRequest;
 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.post.entity.PostInfo;
 import org.jeecg.modules.zjrs.post.mapper.PostInfoMapper;
 import org.jeecg.modules.zjrs.post.service.IPostInfoService;
 import org.jeecg.modules.zjrs.post.vo.PostInfoVo;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.List;
+import java.util.*;
 
 /**
  * @Description: 岗位信息表
@@ -22,16 +27,107 @@ import java.util.List;
 @Service
 public class PostInfoServiceImpl extends ServiceImpl<PostInfoMapper, PostInfo> implements IPostInfoService {
 
+    @Autowired
+    private IDictionaryItemService dictionaryItemService;
+
     @Override
-    public IPage<PostInfoVo> queryPageListWithEnterprise(Page<PostInfoVo> page, Wrapper<PostInfo> queryWrapper) {
+    public IPage<PostInfoVo> queryPageListWithEnterprise(Page<PostInfoVo> page, Wrapper<PostInfo> queryWrapper, HttpServletRequest req) {
+        applyCustomConditions((QueryWrapper<PostInfo>) queryWrapper, req);
         return baseMapper.queryPageListWithEnterprise(page, queryWrapper);
     }
 
     @Override
-    public List<PostInfoVo> queryListWithEnterprise(Wrapper<PostInfo> queryWrapper) {
+    public List<PostInfoVo> queryListWithEnterprise(Wrapper<PostInfo> queryWrapper, HttpServletRequest req) {
+        applyCustomConditions((QueryWrapper<PostInfo>) queryWrapper, req);
+        // 处理导出选中记录的筛选条件
+        String selections = req.getParameter("selections");
+        if (oConvertUtils.isNotEmpty(selections)) {
+            ((QueryWrapper<PostInfo>) queryWrapper).in("p.id", Arrays.asList(selections.split(",")));
+        }
         return baseMapper.queryListWithEnterprise(queryWrapper);
     }
 
+    @Override
+    public List<PostInfoVo> translateDictFields(List<PostInfoVo> 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 (PostInfoVo vo : 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;
+
+                switch (fieldName) {
+                    case "workNature":
+                        if (vo.getWorkNature() != null) {
+                            vo.setWorkNature(mapping.getOrDefault(vo.getWorkNature(), vo.getWorkNature()));
+                        }
+                        break;
+                    case "salaryType":
+                        if (vo.getSalaryType() != null) {
+                            vo.setSalaryType(mapping.getOrDefault(vo.getSalaryType(), vo.getSalaryType()));
+                        }
+                        break;
+                    case "postTag":
+                        if (vo.getPostTag() != null) {
+                            vo.setPostTag(mapping.getOrDefault(vo.getPostTag(), vo.getPostTag()));
+                        }
+                        break;
+                    case "educationRequire":
+                        if (vo.getEducationRequire() != null) {
+                            vo.setEducationRequire(mapping.getOrDefault(vo.getEducationRequire(), vo.getEducationRequire()));
+                        }
+                        break;
+                    case "workExperienceRequire":
+                        if (vo.getWorkExperienceRequire() != null) {
+                            vo.setWorkExperienceRequire(mapping.getOrDefault(vo.getWorkExperienceRequire(), vo.getWorkExperienceRequire()));
+                        }
+                        break;
+                    case "skillLevelRequire":
+                        if (vo.getSkillLevelRequire() != null) {
+                            vo.setSkillLevelRequire(mapping.getOrDefault(vo.getSkillLevelRequire(), vo.getSkillLevelRequire()));
+                        }
+                        break;
+                    case "languageLevel":
+                        if (vo.getLanguageLevel() != null) {
+                            vo.setLanguageLevel(mapping.getOrDefault(vo.getLanguageLevel(), vo.getLanguageLevel()));
+                        }
+                        break;
+                    case "dataSource":
+                        if (vo.getDataSource() != null) {
+                            vo.setDataSource(mapping.getOrDefault(vo.getDataSource(), vo.getDataSource()));
+                        }
+                        break;
+                }
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 应用自定义查询条件(不在 PostInfo 实体中的字段,如企业名称模糊查询)
+     */
+    private void applyCustomConditions(QueryWrapper<PostInfo> queryWrapper, HttpServletRequest req) {
+        String companyName = req.getParameter("companyName");
+        if (oConvertUtils.isNotEmpty(companyName)) {
+            queryWrapper.apply("e.company_name LIKE CONCAT('%',{0},'%')", companyName);
+        }
+    }
+
     @Override
     public boolean save(PostInfo postInfo) {
         validatePostInfo(postInfo);

+ 30 - 11
jeecgboot-vue3/src/views/recruitment/enterprise/EnterpriseInfoList.vue

@@ -4,27 +4,42 @@
     <div class="jeecg-basic-table-form-container">
       <a-form ref="formRef" :label-col="labelCol" :model="queryParam" :wrapper-col="wrapperCol" @keyup.enter.native="searchQuery">
         <a-row :gutter="24">
-          <a-col :lg="6">
+          <a-col :lg="8">
             <a-form-item label="单位名称" name="companyName">
               <a-input v-model:value="queryParam.companyName" placeholder="请输入单位名称"></a-input>
             </a-form-item>
           </a-col>
-          <a-col :lg="6">
-            <a-form-item label="统一社会信用代码" name="unifiedCreditCode">
-              <a-input v-model:value="queryParam.unifiedCreditCode" placeholder="请输入统一社会信用代码"></a-input>
+          <a-col :lg="8">
+            <a-form-item label="统一信用代码" name="unifiedCreditCode">
+              <a-input v-model:value="queryParam.unifiedCreditCode" placeholder="请输入统一信用代码"></a-input>
             </a-form-item>
           </a-col>
-          <a-col :lg="6">
-            <a-form-item label="联系人" name="contactPerson">
-              <a-input v-model:value="queryParam.contactPerson" placeholder="请输入联系人"></a-input>
+          <a-col :lg="8">
+            <a-form-item label="注册地址" name="regAddrDistrict">
+              <a-input v-model:value="queryParam.regAddrDistrict" placeholder="请输入注册地址"></a-input>
             </a-form-item>
           </a-col>
-          <a-col :lg="6">
+          <a-col :lg="8">
+            <a-form-item label="经营地址" name="officeAddress">
+              <a-input v-model:value="queryParam.officeAddress" placeholder="请输入经营地址"></a-input>
+            </a-form-item>
+          </a-col>
+          <a-col :lg="8">
+            <a-form-item label="单位类型" name="companyType">
+              <a-select v-model:value="queryParam.companyType" allow-clear placeholder="请选择单位类型" :options="companyTypeOptions" />
+            </a-form-item>
+          </a-col>
+          <a-col :lg="8">
             <a-form-item label="所属行业" name="industry">
               <a-input v-model:value="queryParam.industry" placeholder="请输入所属行业"></a-input>
             </a-form-item>
           </a-col>
-          <a-col :lg="7" :md="8" :sm="24" :xl="6">
+          <a-col :lg="8">
+            <a-form-item label="数据来源" name="dataSource">
+              <a-select v-model:value="queryParam.dataSource" allow-clear placeholder="请选择数据来源" :options="dataSourceOptions" />
+            </a-form-item>
+          </a-col>
+          <a-col :lg="8">
             <a-button preIcon="ant-design:search-outlined" type="primary" @click="searchQuery">查询</a-button>
             <a-button preIcon="ant-design:reload-outlined" style="margin-left: 8px" type="primary" @click="searchReset">重置</a-button>
           </a-col>
@@ -84,7 +99,7 @@
 </template>
 
 <script lang="ts" name="enterprise-enterpriseInfo" setup>
-  import { reactive, ref } from 'vue';
+  import { computed, reactive, ref } from 'vue';
   import { BasicTable, TableAction } from '/@/components/Table';
   import { useListPage } from '/@/hooks/system/useListPage';
   import { columns, superQuerySchema } from './EnterpriseInfo.data';
@@ -105,13 +120,17 @@
   const { createMessage } = useMessage();
 
   // 预加载页面所需的字典
-  const { getDictText } = useDict([
+  const { getDictText, getDictOptions } = useDict([
     'BusinessStatus',
     'CompanyType',
     'CompanySize',
     'DataSource',
   ]);
 
+  // 搜索框字典下拉选项
+  const companyTypeOptions = computed(() => getDictOptions('CompanyType'));
+  const dataSourceOptions = computed(() => getDictOptions('DataSource'));
+
   //注册table数据
   const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
     tableProps: {

+ 17 - 17
jeecgboot-vue3/src/views/recruitment/post/PostInfo.data.ts

@@ -10,12 +10,12 @@ export const columns: BasicColumn[] = [
     customRender: ({ index }) => index + 1,
   },
   {
-    title: '单位名称',
+    title: '企业名称',
     align: 'center',
     dataIndex: 'companyName',
   },
   {
-    title: '职业',
+    title: '职业工种',
     align: 'center',
     dataIndex: 'occupation',
   },
@@ -25,22 +25,12 @@ export const columns: BasicColumn[] = [
     dataIndex: 'postName',
   },
   {
-    title: '工作性质',
-    align: 'center',
-    dataIndex: 'workNature',
-  },
-  {
-    title: '薪酬待遇',
-    align: 'center',
-    dataIndex: 'salaryType',
-  },
-  {
-    title: '最低薪酬',
+    title: '薪酬待遇(最低)',
     align: 'center',
     dataIndex: 'salaryMin',
   },
   {
-    title: '最高薪酬',
+    title: '薪酬待遇(最高)',
     align: 'center',
     dataIndex: 'salaryMax',
   },
@@ -54,11 +44,21 @@ export const columns: BasicColumn[] = [
     align: 'center',
     dataIndex: 'postValidDate',
   },
+  {
+    title: '职位标签',
+    align: 'center',
+    dataIndex: 'postTag',
+  },
   {
     title: '学历要求',
     align: 'center',
     dataIndex: 'educationRequire',
   },
+  {
+    title: '工作经验',
+    align: 'center',
+    dataIndex: 'workExperienceRequire',
+  },
   {
     title: '联系人',
     align: 'center',
@@ -70,16 +70,16 @@ export const columns: BasicColumn[] = [
     dataIndex: 'contactPhone',
   },
   {
-    title: '工作地点',
+    title: '数据来源',
     align: 'center',
-    dataIndex: 'workLocation',
+    dataIndex: 'dataSource',
   },
 ];
 
 // 高级查询数据
 export const superQuerySchema = {
   enterpriseId: { title: '关联企业', order: 0, view: 'text', type: 'string' },
-  occupation: { title: '职业', order: 1, view: 'text', type: 'string' },
+  occupation: { title: '职业工种', order: 1, view: 'text', type: 'string' },
   postName: { title: '岗位名称', order: 2, view: 'text', type: 'string' },
   workNature: { title: '工作性质', order: 3, view: 'text', type: 'string' },
   salaryType: { title: '薪酬待遇', order: 4, view: 'text', type: 'string' },

+ 42 - 12
jeecgboot-vue3/src/views/recruitment/post/PostInfoList.vue

@@ -4,27 +4,37 @@
     <div class="jeecg-basic-table-form-container">
       <a-form ref="formRef" :label-col="labelCol" :model="queryParam" :wrapper-col="wrapperCol" @keyup.enter.native="searchQuery">
         <a-row :gutter="24">
-          <a-col :lg="6">
+          <a-col :lg="8">
+            <a-form-item label="企业名称" name="companyName">
+              <a-input v-model:value="queryParam.companyName" placeholder="请输入企业名称"></a-input>
+            </a-form-item>
+          </a-col>
+          <a-col :lg="8">
+            <a-form-item label="职业工种" name="occupation">
+              <a-input v-model:value="queryParam.occupation" placeholder="请输入职业工种"></a-input>
+            </a-form-item>
+          </a-col>
+          <a-col :lg="8">
             <a-form-item label="岗位名称" name="postName">
               <a-input v-model:value="queryParam.postName" placeholder="请输入岗位名称"></a-input>
             </a-form-item>
           </a-col>
-          <a-col :lg="6">
-            <a-form-item label="单位名称" name="companyName">
-              <a-input v-model:value="queryParam.companyName" placeholder="请输入单位名称"></a-input>
+          <a-col :lg="8">
+            <a-form-item label="学历要求" name="educationRequire">
+              <a-select v-model:value="queryParam.educationRequire" allow-clear placeholder="请选择学历要求" :options="educationOptions" />
             </a-form-item>
           </a-col>
-          <a-col :lg="6">
-            <a-form-item label="工作地点" name="workLocation">
-              <a-input v-model:value="queryParam.workLocation" placeholder="请输入工作地点"></a-input>
+          <a-col :lg="8">
+            <a-form-item label="联系人" name="contactPerson">
+              <a-input v-model:value="queryParam.contactPerson" placeholder="请输入联系人"></a-input>
             </a-form-item>
           </a-col>
-          <a-col :lg="6">
-            <a-form-item label="学历要求" name="educationRequire">
-              <a-input v-model:value="queryParam.educationRequire" placeholder="请输入学历要求"></a-input>
+          <a-col :lg="8">
+            <a-form-item label="数据来源" name="dataSource">
+              <a-select v-model:value="queryParam.dataSource" allow-clear placeholder="请选择数据来源" :options="dataSourceOptions" />
             </a-form-item>
           </a-col>
-          <a-col :lg="7" :md="8" :sm="24" :xl="6">
+          <a-col :lg="8">
             <a-button preIcon="ant-design:search-outlined" type="primary" @click="searchQuery">查询</a-button>
             <a-button preIcon="ant-design:reload-outlined" style="margin-left: 8px" type="primary" @click="searchReset">重置</a-button>
           </a-col>
@@ -61,7 +71,20 @@
       <template #action="{ record }">
         <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
       </template>
-      <template v-slot:bodyCell="{ column, record, index, text }"> </template>
+      <template v-slot:bodyCell="{ column, record, index, text }">
+        <template v-if="column.dataIndex === 'postTag'">
+          {{ getDictText('PostTag', text) }}
+        </template>
+        <template v-else-if="column.dataIndex === 'educationRequire'">
+          {{ getDictText('Education', text) }}
+        </template>
+        <template v-else-if="column.dataIndex === 'workExperienceRequire'">
+          {{ getDictText('WorkExperience', text) }}
+        </template>
+        <template v-else-if="column.dataIndex === 'dataSource'">
+          {{ getDictText('DataSource', text) }}
+        </template>
+      </template>
     </BasicTable>
     <!-- 表单区域 -->
     <PostInfoModal ref="registerModal" @success="handleSuccess"></PostInfoModal>
@@ -78,6 +101,8 @@
   import { useUserStore } from '/@/store/modules/user';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { getDateByPicker } from '/@/utils';
+  import { useDict } from '/@/hooks/dictionary/useDict';
+  import { computed } from 'vue';
 
   const fieldPickers = reactive({});
 
@@ -87,6 +112,11 @@
   const registerModal = ref();
   const userStore = useUserStore();
   const { createMessage } = useMessage();
+
+  // 预加载字典
+  const { getDictText, getDictOptions } = useDict(['Education', 'PostTag', 'WorkExperience', 'DataSource']);
+  const educationOptions = computed(() => getDictOptions('Education'));
+  const dataSourceOptions = computed(() => getDictOptions('DataSource'));
   //注册table数据
   const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
     tableProps: {

+ 67 - 52
jeecgboot-vue3/src/views/recruitment/post/components/PostInfoForm.vue

@@ -4,32 +4,32 @@
       <template #detail>
         <a-form ref="formRef" :labelCol="labelCol" :wrapperCol="wrapperCol" class="antd-modal-form" name="PostInfoForm">
           <a-row>
-            <a-col :span="12">
-              <a-form-item id="PostInfoForm-enterpriseId" label="关联企业" name="enterpriseId" v-bind="validateInfos.enterpriseId">
-                <JSearchSelect v-model:value="formData.enterpriseId" dict="enterprise_info,company_name,id" placeholder="请选择关联企业" />
+            <a-col :span="8">
+              <a-form-item id="PostInfoForm-enterpriseId" label="单位名称" name="enterpriseId" v-bind="validateInfos.enterpriseId">
+                <JSearchSelect v-model:value="formData.enterpriseId" dict="enterprise_info,company_name,id" placeholder="请选择关联单位" />
               </a-form-item>
             </a-col>
-            <a-col :span="12">
-              <a-form-item id="PostInfoForm-occupation" label="职业" name="occupation" v-bind="validateInfos.occupation">
-                <a-input v-model:value="formData.occupation" allow-clear placeholder="请输入职业"></a-input>
+            <a-col :span="8">
+              <a-form-item id="PostInfoForm-occupation" label="职业工种" name="occupation" v-bind="validateInfos.occupation">
+                <a-input v-model:value="formData.occupation" allow-clear placeholder="请输入职业工种"></a-input>
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-postName" label="岗位名称" name="postName" v-bind="validateInfos.postName">
                 <a-input v-model:value="formData.postName" allow-clear placeholder="请输入岗位名称"></a-input>
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-workNature" label="工作性质" name="workNature" v-bind="validateInfos.workNature">
-                <a-input v-model:value="formData.workNature" allow-clear placeholder="请输入工作性质"></a-input>
+                <a-select v-model:value="formData.workNature" allow-clear placeholder="请选择工作性质" :options="workNatureOptions" />
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-salaryType" label="薪酬待遇" name="salaryType" v-bind="validateInfos.salaryType">
-                <a-input v-model:value="formData.salaryType" allow-clear placeholder="请输入薪酬待遇"></a-input>
+                <a-select v-model:value="formData.salaryType" allow-clear placeholder="请选择薪酬待遇" :options="salaryTypeOptions" />
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-salaryMin" label="最低薪酬" name="salaryMin" v-bind="validateInfos.salaryMin">
                 <a-input-number
                   v-model:value="formData.salaryMin"
@@ -41,7 +41,7 @@
                 />
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-salaryMax" label="最高薪酬" name="salaryMax" v-bind="validateInfos.salaryMax">
                 <a-input-number
                   v-model:value="formData.salaryMax"
@@ -53,12 +53,12 @@
                 />
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-recruitCount" label="招聘人数" name="recruitCount" v-bind="validateInfos.recruitCount">
                 <a-input-number v-model:value="formData.recruitCount" :min="1" allow-clear placeholder="请输入招聘人数" style="width: 100%" />
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-postValidDate" label="岗位有效期" name="postValidDate" v-bind="validateInfos.postValidDate">
                 <a-date-picker
                   v-model:value="formData.postValidDate"
@@ -69,81 +69,81 @@
                 />
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-postTag" label="职位标签" name="postTag" v-bind="validateInfos.postTag">
-                <a-input v-model:value="formData.postTag" allow-clear placeholder="请输入职位标签"></a-input>
+                <a-select v-model:value="formData.postTag" allow-clear placeholder="请选择职位标签" :options="postTagOptions" />
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-otherBenefits" label="其他福利" name="otherBenefits" v-bind="validateInfos.otherBenefits">
                 <a-textarea v-model:value="formData.otherBenefits" :rows="3" allow-clear placeholder="请输入其他福利"></a-textarea>
               </a-form-item>
             </a-col>
-            <a-col :span="24">
-              <a-form-item
-                id="PostInfoForm-postDesc"
-                :labelCol="{ xs: { span: 24 }, sm: { span: 3 } }"
-                :wrapperCol="{ xs: { span: 24 }, sm: { span: 20 } }"
-                label="岗位描述"
-                name="postDesc"
-                v-bind="validateInfos.postDesc"
-              >
-                <a-textarea v-model:value="formData.postDesc" :rows="4" allow-clear placeholder="请输入岗位描述"></a-textarea>
-              </a-form-item>
-            </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-educationRequire" label="学历要求" name="educationRequire" v-bind="validateInfos.educationRequire">
-                <a-input v-model:value="formData.educationRequire" allow-clear placeholder="请输入学历要求"></a-input>
+                <a-select v-model:value="formData.educationRequire" allow-clear placeholder="请选择学历要求" :options="educationOptions" />
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item
                 id="PostInfoForm-workExperienceRequire"
                 label="工作经验"
                 name="workExperienceRequire"
                 v-bind="validateInfos.workExperienceRequire"
               >
-                <a-input v-model:value="formData.workExperienceRequire" allow-clear placeholder="请输入工作经验"></a-input>
+                <a-select v-model:value="formData.workExperienceRequire" allow-clear placeholder="请选择工作经验" :options="workExperienceOptions" />
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="24">
+              <a-form-item
+                id="PostInfoForm-postDesc"
+                :labelCol="{ span: 2}"
+                :wrapperCol="{ span: 21 }"
+                label="岗位描述"
+                name="postDesc"
+                v-bind="validateInfos.postDesc"
+              >
+                <a-textarea v-model:value="formData.postDesc" :rows="4" allow-clear placeholder="请输入岗位描述"></a-textarea>
+              </a-form-item>
+            </a-col>
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-skillLevelRequire" label="职业技能等级" name="skillLevelRequire" v-bind="validateInfos.skillLevelRequire">
-                <a-input v-model:value="formData.skillLevelRequire" allow-clear placeholder="请输入职业技能等级"></a-input>
+                <a-select v-model:value="formData.skillLevelRequire" allow-clear placeholder="请选择职业技能等级" :options="skillLevelOptions" />
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-foreignLanguage" label="外语语种" name="foreignLanguage" v-bind="validateInfos.foreignLanguage">
                 <a-input v-model:value="formData.foreignLanguage" allow-clear placeholder="请输入外语语种"></a-input>
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-languageLevel" label="外语水平要求" name="languageLevel" v-bind="validateInfos.languageLevel">
-                <a-input v-model:value="formData.languageLevel" allow-clear placeholder="请输入外语水平要求"></a-input>
+                <a-select v-model:value="formData.languageLevel" allow-clear placeholder="请选择外语水平要求" :options="languageLevelOptions" />
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-contactPerson" label="联系人" name="contactPerson" v-bind="validateInfos.contactPerson">
                 <a-input v-model:value="formData.contactPerson" allow-clear placeholder="请输入联系人"></a-input>
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-contactPhone" label="联系电话" name="contactPhone" v-bind="validateInfos.contactPhone">
                 <a-input v-model:value="formData.contactPhone" allow-clear placeholder="请输入联系电话"></a-input>
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-workLocation" label="工作地点" name="workLocation" v-bind="validateInfos.workLocation">
                 <a-input v-model:value="formData.workLocation" allow-clear placeholder="请输入工作地点"></a-input>
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-detailedAddress" label="详细地址" name="detailedAddress" v-bind="validateInfos.detailedAddress">
                 <a-input v-model:value="formData.detailedAddress" allow-clear placeholder="请输入详细地址"></a-input>
               </a-form-item>
             </a-col>
-            <a-col :span="12">
+            <a-col :span="8">
               <a-form-item id="PostInfoForm-dataSource" label="数据来源" name="dataSource" v-bind="validateInfos.dataSource">
-                <a-input v-model:value="formData.dataSource" allow-clear placeholder="请输入数据来源"></a-input>
+                <a-select v-model:value="formData.dataSource" allow-clear placeholder="请选择数据来源" :options="dataSourceOptions" />
               </a-form-item>
             </a-col>
           </a-row>
@@ -161,6 +161,7 @@
   import JSearchSelect from '/@/components/Form/src/jeecg/components/JSearchSelect.vue';
   import { Form } from 'ant-design-vue';
   import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
+  import { useDict } from '/@/hooks/dictionary/useDict';
 
   const props = defineProps({
     formDisabled: { type: Boolean, default: false },
@@ -200,20 +201,34 @@
   const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
   const confirmLoading = ref<boolean>(false);
 
+  // 预加载字典
+  const { getDictOptions } = useDict([
+    'WorkNature', 'SalaryType', 'PostTag', 'Education',
+    'WorkExperience', 'SkillLevel', 'LanguageLevel', 'DataSource'
+  ]);
+  const workNatureOptions = computed(() => getDictOptions('WorkNature'));
+  const salaryTypeOptions = computed(() => getDictOptions('SalaryType'));
+  const postTagOptions = computed(() => getDictOptions('PostTag'));
+  const educationOptions = computed(() => getDictOptions('Education'));
+  const workExperienceOptions = computed(() => getDictOptions('WorkExperience'));
+  const skillLevelOptions = computed(() => getDictOptions('SkillLevel'));
+  const languageLevelOptions = computed(() => getDictOptions('LanguageLevel'));
+  const dataSourceOptions = computed(() => getDictOptions('DataSource'));
+
   //表单验证
   const validatorRules = reactive({
     enterpriseId: [{ required: true, message: '请选择关联企业' }],
     occupation: [{ required: true, message: '请输入职业' }],
     postName: [{ required: true, message: '请输入岗位名称' }],
-    workNature: [{ required: true, message: '请输入工作性质' }],
-    salaryType: [{ required: true, message: '请输入薪酬待遇' }],
+    workNature: [{ required: true, message: '请选择工作性质' }],
+    salaryType: [{ required: true, message: '请选择薪酬待遇' }],
     recruitCount: [{ required: true, message: '请输入招聘人数' }],
     postValidDate: [{ required: true, message: '请选择岗位有效期' }],
-    postTag: [{ required: true, message: '请输入职位标签' }],
+    postTag: [{ required: true, message: '请选择职位标签' }],
     postDesc: [{ required: true, message: '请输入岗位描述' }],
-    educationRequire: [{ required: true, message: '请输入学历要求' }],
-    workExperienceRequire: [{ required: true, message: '请输入工作经验' }],
-    skillLevelRequire: [{ required: true, message: '请输入职业技能等级' }],
+    educationRequire: [{ required: true, message: '请选择学历要求' }],
+    workExperienceRequire: [{ required: true, message: '请选择工作经验' }],
+    skillLevelRequire: [{ required: true, message: '请选择职业技能等级' }],
     contactPerson: [{ required: true, message: '请输入联系人' }],
     contactPhone: [
       { required: true, message: '请输入联系电话' },
@@ -221,7 +236,7 @@
     ],
     workLocation: [{ required: true, message: '请输入工作地点' }],
     detailedAddress: [{ required: true, message: '请输入详细地址' }],
-    dataSource: [{ required: true, message: '请输入数据来源' }],
+    dataSource: [{ required: true, message: '请选择数据来源' }],
     salaryMax: [
       {
         validator: (_, value) => {