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

1.完善“信息智能匹配推送”-“重点关注人员信息”
2.修复语法不兼容达梦导致定时任务启动报错问题

kk 1 неделя назад
Родитель
Сommit
7bf6605320
31 измененных файлов с 1861 добавлено и 147 удалено
  1. 238 0
      .docs/20260604-AI-FLOW触发器达梦数据库兼容性修复记录.md
  2. BIN
      .docs/20260604-backend_startup.log
  3. 73 0
      .docs/sql/AI-FLOW触发器兼容达梦数据库修复.sql
  4. 77 0
      .docs/sql/新增模块测试数据.sql
  5. 111 0
      .docs/sql/新增模块清理与重新执行.sql
  6. 47 0
      .docs/sql/菜单结构调整-放到信息智能匹配推送下.sql
  7. 34 0
      .docs/sql/见习人员信息重新录入.sql
  8. 44 6
      .docs/sql/重点关注人员测试数据.sql
  9. 140 0
      .docs/重点关注人员管理-P0任务实现记录.md
  10. 254 0
      .docs/重点关注人员管理-需求与现有实现对比分析.md
  11. 1 17
      jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/video/service/impl/VideoGenerationServiceImpl.java
  12. 14 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/controller/FocusPersonnelController.java
  13. 3 2
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/entity/FocusPersonnel.java
  14. 130 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/entity/FocusPersonnelDetailVo.java
  15. 8 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/mapper/FocusPersonnelMapper.java
  16. 53 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/mapper/xml/FocusPersonnelMapper.xml
  17. 8 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/service/IFocusPersonnelService.java
  18. 6 0
      jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/service/impl/FocusPersonnelServiceImpl.java
  19. 10 13
      jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260603_5__menu_insert_InternshipPost.sql
  20. 3 1
      jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260603_6__menu_insert_InternshipPersonnel.sql
  21. 10 13
      jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260603_7__menu_insert_WelfarePost.sql
  22. 10 13
      jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260603_8__menu_insert_JobRecommend.sql
  23. 118 0
      jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260604_1__init_focus_personnel_dict.sql
  24. 62 0
      jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260604_2__menu_insert_FocusPersonnel_buttons.sql
  25. 6 6
      jeecgboot-vue3/src/locales/lang/zh-CN/sys.ts
  26. 9 0
      jeecgboot-vue3/src/views/focuspersonnel/FocusPersonnel.api.ts
  27. 3 12
      jeecgboot-vue3/src/views/focuspersonnel/FocusPersonnel.data.ts
  28. 118 53
      jeecgboot-vue3/src/views/focuspersonnel/FocusPersonnelList.vue
  29. 236 0
      jeecgboot-vue3/src/views/focuspersonnel/components/FocusPersonnelDetail.vue
  30. 1 1
      jeecgboot-vue3/src/views/focuspersonnel/components/FocusPersonnelForm.vue
  31. 34 10
      jeecgboot-vue3/src/views/focuspersonnel/components/FocusPersonnelModal.vue

+ 238 - 0
.docs/20260604-AI-FLOW触发器达梦数据库兼容性修复记录.md

@@ -0,0 +1,238 @@
+# AI-FLOW 触发器在达梦数据库上启动报错修复记录
+
+## 修改日期:2026-06-04
+
+## 一、问题现象
+
+后端服务启动时,控制台抛出 `ERROR` 日志,Spring Boot 启动过程被异常打断:
+
+```
+2026-06-04 10:59:55.798 [main] ERROR org.jeecg.modules.airag.flow.service.a.d:78
+- [AI-FLOW] 初始化定时触发器任务失败
+org.springframework.dao.DataIntegrityViolationException:
+### Error querying database.  Cause: dm.jdbc.driver.DMException: -6105
+  第1 行附近出现错误: 数据类型不匹配
+### The error may exist in org/jeecg/modules/airag/flow/mapper/AiragFlowMapper.java
+### The error may involve org.jeecg.modules.airag.flow.mapper.AiragFlowMapper.selectList
+### The error occurred while executing a query
+### SQL: SELECT id, trigger_cron FROM airag_flow
+       WHERE (status = ? AND (trigger_cron IS NOT NULL AND trigger_cron <> ?))
+### Cause: dm.jdbc.driver.DMException: -6105 第1 行附近出现错误: 数据类型不匹配
+```
+
+错误链路:
+- `org.jeecg.modules.config.a.a.a(AiragScheduledTaskInitListener.java:28)` —— Spring 启动事件监听
+- `org.jeecg.modules.airag.flow.service.a.d.initCronTasksFromDB(AiragFlowTaskServiceImpl.java:69)` —— 拉取启用 cron 的流程
+- `com.baomidou.mybatisplus.extension.repository.IRepository.list` —— MyBatis-Plus 查询
+
+## 二、根因分析
+
+### 2.1 字段类型来源
+
+`airag_flow.trigger_cron` 字段在 JeecgBoot 官方升级脚本中以 `text` 类型添加:
+
+- 文件:`jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.1_0__all_upgrade.sql`
+- 关键语句:
+
+```sql
+ALTER TABLE `airag_flow`
+    ADD COLUMN `trigger_cron` text NULL COMMENT 'cron定时任务触发器配置JSON' AFTER `metadata`;
+```
+
+### 2.2 达梦数据库对 `text` 类型的处理
+
+- MySQL 中 `text` 类型可直接与空字符串 `''` 进行 `<>` 比较;
+- 达梦(DM8)数据库中,`text` 实际映射为 `CLOB` 大对象类型;
+- 达梦不允许将 `CLOB` 类型字段直接与空字符串 `''` 使用 `<>` 操作符比较,
+  否则抛出 `-6105 数据类型不匹配` 错误。
+- 通过 `USER_TAB_COLUMNS` 实测当前 `airag_flow.trigger_cron`:
+  ```
+  DATA_TYPE   = TEXT
+  DATA_LENGTH = 2147483647
+  NULLABLE    = Y
+  ```
+
+### 2.3 触发 SQL 来源
+
+`AiragFlowTaskServiceImpl.initCronTasksFromDB` 通过 MyBatis-Plus 的
+`LambdaQueryWrapper` / `QueryWrapper` 生成 SQL:
+
+```java
+wrapper.eq(AiragFlow::getStatus, "enable");
+wrapper.isNotNull(AiragFlow::getTriggerCron);
+wrapper.ne(AiragFlow::getTriggerCron, "");
+```
+
+最终生成:
+```sql
+SELECT id, trigger_cron FROM airag_flow
+WHERE (status = ? AND (trigger_cron IS NOT NULL AND trigger_cron <> ?))
+```
+
+其中 `trigger_cron <> ?` 中 `?` 绑定的是空字符串 `''`。该 SQL 在达梦上
+触发了 CLOB 与空字符串比较的限制。
+
+## 三、解决方案
+
+### 3.1 方案选择
+
+由于:
+
+1. `airag.flow` 包对应的 `AiragFlowTaskServiceImpl`、`AiragScheduledTaskInitListener`、
+   `AiragFlowMapper` 属于 JeecgBoot 商业插件,未提供源码(运行时类路径下为
+   编译后类),无法直接修改业务代码;
+2. MyBatis-Plus 的 `ne("", "")` 条件生成的 `<> ''` 属于框架行为,
+   强行通过 `InnerInterceptor` 改写 SQL 会增加维护成本与跨库兼容性风险;
+3. `trigger_cron` 字段用途为 "cron 定时任务触发器配置 JSON",
+   单条记录体积很小(远小于 2000 字符)。
+
+综合考虑,采用**数据库字段类型变更**方案:将 `trigger_cron` 由
+`text`(达梦中实际为 CLOB)变更为 `varchar(2000)`,
+使达梦(也兼容 MySQL)都能与空字符串直接比较。
+
+### 3.2 方案落实 —— 达梦标准变更流程
+
+**达梦不允许通过 `MODIFY` 直接将 TEXT/CLOB 变更为 VARCHAR**(实测报
+`-6160 数据类型的变更无效`),需采用"加新列 -> 灌数据 -> 删旧列 ->
+重命名"四步走:
+
+```sql
+-- 1. 新增临时 VARCHAR(2000) 列
+ALTER TABLE airag_flow ADD COLUMN trigger_cron_tmp VARCHAR(2000) NULL;
+-- 2. 将原 TEXT 数据通过 CAST 灌入临时列
+UPDATE airag_flow SET trigger_cron_tmp = CAST(trigger_cron AS VARCHAR(2000));
+-- 3. 删除原 TEXT 列
+ALTER TABLE airag_flow DROP COLUMN trigger_cron;
+-- 4. 将临时列重命名为原列名
+ALTER TABLE airag_flow RENAME COLUMN trigger_cron_tmp TO trigger_cron;
+```
+
+### 3.3 实测修复结果
+
+修复后通过 JDBC 验证:
+
+| 验证项 | 修复前 | 修复后 |
+|--------|--------|--------|
+| 原报错 SQL:`SELECT ... WHERE trigger_cron <> ''` | 抛出 `-6105 数据类型不匹配` | **正常执行**,命中 1 条 |
+| `trigger_cron = ''` 查询 | 可执行 | 命中 11 条(数据一致) |
+| `trigger_cron IS NULL` 查询 | 可执行 | 命中 18 条(数据一致) |
+| `UPDATE` 行数 | - | 30 行(30 条记录数据完整保留) |
+
+> 备注:经查询 `USER_TAB_COLUMNS`,修复后 `TRIGGER_CRON` 在该视图中
+> 数据类型字段仍显示为 `TEXT`(疑似达梦的元数据延迟或 TEXT 内部
+> 存储为 VARCHAR 的表现),但**实际 SQL 行为已完全符合预期**,
+> 原报错已消除,业务查询均可正常执行。
+
+### 3.4 修改文件清单
+
+| 序号 | 文件路径 | 类型 | 说明 |
+|:----:|----------|:----:|------|
+| 1 | `.docs/sql/AI-FLOW触发器兼容达梦数据库修复.sql` | 新增 | 达梦数据库手动修复 SQL(4 步变更流程 + 验证步骤) |
+| 2 | `.docs/20260604-AI-FLOW触发器达梦数据库兼容性修复记录.md` | 新增 | 本开发记录文档 |
+
+### 3.5 为什么选用 `varchar(2000)` 而不是 `clob` / `text`
+
+- `clob` / `text` 在达梦中均按大对象存储,依然存在与空字符串比较的限制;
+- `varchar(2000)` 容量充足(cron 表达式 + 简单 JSON 配置远小于该值),
+  同时支持与空字符串直接比较;
+- `varchar` 在两个数据库(达梦 / MySQL)中行为一致,不存在跨库兼容问题。
+
+## 四、对其他业务的影响评估
+
+| 影响项 | 评估结论 |
+|--------|----------|
+| AI-FLOW 业务功能 | 仅修复启动时 `initCronTasksFromDB` 的 SQL 执行,**不改变**功能逻辑 |
+| AI-FLOW 定时任务调度 | 修复后定时任务可正常从数据库加载并注册,**新增能力**(之前完全无法启动) |
+| `airag_flow` 其他字段 | 字段类型未变动,**不受影响** |
+| 其他表 | 未涉及,**不受影响** |
+| 前端 AI-FLOW 流程编排 | 前端通过 `trigger_cron` 字段写入 JSON 字符串,**不受影响** |
+| MySQL 环境 | MySQL 中 `text` 字段与空字符串比较正常,不存在此问题,无需处理 |
+
+## 五、验证步骤
+
+1. **执行 SQL**:使用达梦客户端(`disql` / `DM 管理工具` /
+   `DBeaver`)连接到 `ZJRS_JEECG_BOOT` 模式
+   (`application-dm8.yml` 中配置的 schema),按
+   `.docs/sql/AI-FLOW触发器兼容达梦数据库修复.sql` 步骤执行;
+2. **确认字段类型变更**:
+
+   ```sql
+   SELECT DATA_TYPE, DATA_LENGTH, NULLABLE
+   FROM USER_TAB_COLUMNS
+   WHERE TABLE_NAME = 'AIRAG_FLOW'
+     AND COLUMN_NAME = 'TRIGGER_CRON';
+   ```
+3. **复现原报错 SQL**:
+
+   ```sql
+   SELECT id, trigger_cron FROM airag_flow
+   WHERE (status = 'enable' AND (trigger_cron IS NOT NULL AND trigger_cron <> ''));
+   ```
+
+   预期:正常返回(不抛 `-6105`)。
+4. **重启后端服务**:
+
+   ```bash
+   cd D:\我的文件\JeecgBoot-main\jeecg-boot
+   mvn spring-boot:run -pl jeecg-module-system/jeecg-system-start `
+       -Dspring-boot.run.jvmArguments="-Dfile.encoding=UTF-8"
+   ```
+
+5. **观察启动日志**:确认不再出现以下关键字的报错:
+   - `AI-FLOW 初始化定时触发器任务失败`
+   - `dm.jdbc.driver.DMException: -6105`
+   - `数据类型不匹配`
+6. **(可选)功能验证**:进入前端 AI-FLOW 流程编排页面,创建一个配置了
+   `cronTrigger` 的流程并保存,确认数据正常写入 `airag_flow.trigger_cron`
+   字段,后端能正确读取并调度执行。
+
+## 六、回滚方案
+
+如修复后出现问题,可执行以下 SQL 回滚(将 `trigger_cron` 还原为
+`TEXT` 类型,注意 4 步流程会产生新 CLOB 列):
+
+```sql
+ALTER TABLE airag_flow ADD COLUMN trigger_cron_bak TEXT NULL;
+UPDATE airag_flow SET trigger_cron_bak = CAST(trigger_cron AS TEXT);
+ALTER TABLE airag_flow DROP COLUMN trigger_cron;
+ALTER TABLE airag_flow RENAME COLUMN trigger_cron_bak TO trigger_cron;
+```
+
+> ⚠️ 回滚后请勿再使用 `trigger_cron <> ''` 这类 SQL,否则会再次触发
+> 同样的 `-6105` 错误。
+
+## 七、参考信息
+
+- JeecgBoot 版本:3.9.2
+- 数据库:达梦 DM8(`compatibleMode=oracle`)
+- 出错模块:`org.jeecg.modules.airag.flow`(JeecgBoot 商业插件,无源码)
+- MyBatis-Plus 版本:3.5.12
+- 涉及 Flyway 历史脚本:`V3.9.1_0__all_upgrade.sql`(添加 `trigger_cron` 字段)
+- 修复实测环境:Windows 11 + JDK 17.0.4 + DmJdbcDriver18-8.1.3.140
+
+---
+
+## 八、追加修复:关闭 AI 视频配音工具检测日志
+
+### 8.1 问题现象
+
+启动日志中输出以下 WARN 提示,用户确认视频配音功能不需要使用:
+
+```
+2026-06-04 11:39:14.626 [main] INFO  o.j.m.a.v.service.impl.VideoGenerationServiceImpl:112 - === AI视频配音工具检测 ===
+2026-06-04 11:39:14.627 [main] WARN  o.j.m.a.v.service.impl.VideoGenerationServiceImpl:116 -   ffmpeg   : 未安装,视频配音功能将不可用
+2026-06-04 11:39:14.627 [main] WARN  o.j.m.a.v.service.impl.VideoGenerationServiceImpl:121 -   edge-tts : 未安装,视频配音功能将不可用
+2026-06-04 11:39:14.627 [main] WARN  o.j.m.a.v.service.impl.VideoGenerationServiceImpl:126 -   视频配音功能: 已禁用(缺少依赖工具,调用配音接口将直接返回无声视频)
+```
+
+### 8.2 修改内容
+
+修改文件:`jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/video/service/impl/VideoGenerationServiceImpl.java`
+
+将 `@PostConstruct init()` 方法中的 ffmpeg/edge-tts 检测日志输出全部移除,仅保留工具路径查找逻辑(不影响后续功能判断),替换为注释 `// 视频配音功能已关闭,不再输出检测日志`。
+
+### 8.3 影响评估
+
+- 视频配音功能本身未删除,`isToolsAvailable()` 仍可正常判断工具是否可用;
+- 仅移除启动时的日志提示,不影响其他业务逻辑;
+- 若后续需要重新启用配音功能,安装 ffmpeg/edge-tts 后功能自动恢复。

BIN
.docs/20260604-backend_startup.log


+ 73 - 0
.docs/sql/AI-FLOW触发器兼容达梦数据库修复.sql

@@ -0,0 +1,73 @@
+-- ============================================================
+-- AI-FLOW 触发器兼容达梦数据库修复脚本
+-- 修复日期:2026-06-04
+-- 修复人:Trae
+-- ============================================================
+-- 问题描述:
+--  Spring Boot 启动时,AiragScheduledTaskInitListener 监听器
+--  调用 AiragFlowTaskServiceImpl.initCronTasksFromDB() 方法,
+--  执行 SQL:
+--      SELECT id, trigger_cron FROM airag_flow
+--      WHERE (status = ? AND (trigger_cron IS NOT NULL AND trigger_cron <> ?))
+--  在达梦数据库上抛出异常:
+--      dm.jdbc.driver.DMException: -6105 数据类型不匹配
+--
+-- 根因分析:
+--  airag_flow.trigger_cron 字段原始类型为 text(V3.9.1_0__all_upgrade.sql 中
+--  通过 ALTER TABLE 添加),在达梦数据库中 text 类型映射为 CLOB 大对象类型。
+--  达梦数据库不允许将 CLOB 类型字段与空字符串 '' 直接使用 <> 进行比较,
+--  因此触发 "数据类型不匹配" 错误。
+--  MySQL 中 text 类型可直接与 '' 比较,因此该问题在 MySQL 环境下不会复现。
+--
+-- 解决方案:
+--  由于达梦数据库不允许通过 MODIFY 将 TEXT/CLOB 直接变更为 VARCHAR,
+--  采用标准变更流程:新增临时 VARCHAR 列 -> 灌数据 -> 删旧列 -> 重命名。
+--  经实测,重命名后 airag_flow.trigger_cron 已可正常与空字符串 '' 进行比较,
+--  原报错 SQL(trigger_cron <> '')可成功执行。
+--
+-- 影响范围:
+--  仅修改 airag_flow 表的 trigger_cron 字段类型,不影响其他字段、
+--  其他表以及业务逻辑。已实测 30 条历史记录数据完整保留(空串、null、JSON)。
+-- ============================================================
+
+-- Step 1:检查字段当前类型(仅用于人工确认,查询无结果可忽略)
+SELECT DATA_TYPE, DATA_LENGTH, NULLABLE
+FROM USER_TAB_COLUMNS
+WHERE TABLE_NAME = 'AIRAG_FLOW'
+  AND COLUMN_NAME = 'TRIGGER_CRON';
+
+-- Step 2:标准变更流程(4 步)
+-- 2.1 新增临时 VARCHAR(2000) 列
+ALTER TABLE airag_flow ADD COLUMN trigger_cron_tmp VARCHAR(2000) NULL;
+
+-- 2.2 将原 TEXT 列数据通过 CAST 灌入临时列(30 行实测)
+UPDATE airag_flow
+SET trigger_cron_tmp = CAST(trigger_cron AS VARCHAR(2000));
+
+-- 2.3 删除原 TEXT 列
+ALTER TABLE airag_flow DROP COLUMN trigger_cron;
+
+-- 2.4 将临时列重命名为原列名
+ALTER TABLE airag_flow RENAME COLUMN trigger_cron_tmp TO trigger_cron;
+
+-- Step 3:验证修改结果(仅用于人工确认,查询无结果可忽略)
+SELECT DATA_TYPE, DATA_LENGTH, NULLABLE
+FROM USER_TAB_COLUMNS
+WHERE TABLE_NAME = 'AIRAG_FLOW'
+  AND COLUMN_NAME = 'TRIGGER_CRON';
+
+-- Step 4:复现原报错 SQL,验证修复成功
+-- 预期结果:查询成功,命中记录数 >= 0(无 -6105 错误)
+SELECT id, trigger_cron FROM airag_flow
+WHERE (status = 'enable' AND (trigger_cron IS NOT NULL AND trigger_cron <> ''));
+
+-- Step 5:人工验证其他业务查询正常
+-- 5.1 空字符串记录数(修复前后数据应一致)
+SELECT COUNT(*) AS empty_cnt FROM airag_flow WHERE trigger_cron = '';
+-- 5.2 NULL 记录数(修复前后数据应一致)
+SELECT COUNT(*) AS null_cnt FROM airag_flow WHERE trigger_cron IS NULL;
+
+-- Step 6:触发 AI-FLOW 定时任务初始化校验
+-- 提示:可重启后端服务,观察启动日志中是否还存在
+--   "AI-FLOW 初始化定时触发器任务失败" 错误
+-- 若启动正常无相关异常,则表示修复成功。

Разница между файлами не показана из-за своего большого размера
+ 77 - 0
.docs/sql/新增模块测试数据.sql


+ 111 - 0
.docs/sql/新增模块清理与重新执行.sql

@@ -0,0 +1,111 @@
+-- ============================================================
+-- 就业一湛通服务平台 - 新增模块数据清理与重新执行
+--
+-- 说明:
+-- 1. 先清除新增模块的所有测试数据(按依赖顺序倒序删除)
+-- 2. 清空企业信息、岗位信息(这些表只在新增模块测试数据中建立)
+-- 3. 删除新增的"见习人员"类型个人信息(ID: 206~208)
+--    注意:不会删除原有重点关注人员的个人信息(200~205)
+-- 4. 删除视图
+-- 5. 重新执行新增模块测试数据SQL
+--
+-- 执行方式:直接运行本脚本即可
+-- 数据库:达梦数据库 (DM8) / MySQL 8.0 兼容
+-- 创建日期:2026-06-03
+-- ============================================================
+
+-- ============================================================
+-- 第1步:删除岗位推荐数据
+-- ============================================================
+DELETE FROM job_recommend WHERE ID >= 178060100000350 AND ID <= 178060100000354;
+
+-- ============================================================
+-- 第2步:删除见习人员数据
+-- ============================================================
+DELETE FROM internship_personnel WHERE ID >= 178060100000330 AND ID <= 178060100000334;
+
+-- ============================================================
+-- 第3步:删除公益性岗位数据
+-- ============================================================
+DELETE FROM welfare_post WHERE ID >= 178060100000340 AND ID <= 178060100000344;
+
+-- ============================================================
+-- 第4步:删除见习岗位数据
+-- ============================================================
+DELETE FROM internship_post WHERE ID >= 178060100000320 AND ID <= 178060100000324;
+
+-- ============================================================
+-- 第5步:删除岗位信息数据
+-- ============================================================
+DELETE FROM post_info WHERE ID >= 178060100000310 AND ID <= 178060100000314;
+
+-- ============================================================
+-- 第6步:删除企业信息数据
+-- ============================================================
+DELETE FROM enterprise_info WHERE ID >= 178060100000300 AND ID <= 178060100000304;
+
+-- ============================================================
+-- 第7步:删除新增的"见习人员"类型个人信息
+-- 注意:不会删除原有重点关注人员的个人信息(200~205)
+-- ============================================================
+DELETE FROM personal_info WHERE ID >= 178060100000206 AND ID <= 178060100000208;
+
+-- ============================================================
+-- 第8步:删除视图
+-- ============================================================
+DROP VIEW IF EXISTS v_job_recommend_list;
+DROP VIEW IF EXISTS v_internship_personnel_list;
+
+-- ============================================================
+-- 第9步:重新创建视图
+-- ============================================================
+
+-- 岗位推荐列表视图
+CREATE VIEW v_job_recommend_list AS
+SELECT
+    job_recommend.id,
+    job_recommend.personal_id,
+    job_recommend.post_id,
+    job_recommend.recommend_type,
+    job_recommend.recommend_opinion,
+    job_recommend.recommend_status,
+    personal_info.full_name,
+    personal_info.gender,
+    personal_info.contact_phone,
+    personal_info.education,
+    post_info.post_name,
+    post_info.work_location,
+    enterprise_info.company_name
+FROM job_recommend
+LEFT JOIN personal_info ON job_recommend.personal_id = personal_info.id
+LEFT JOIN post_info ON job_recommend.post_id = post_info.id
+LEFT JOIN enterprise_info ON post_info.enterprise_id = enterprise_info.id;
+
+-- 见习人员列表视图
+CREATE VIEW v_internship_personnel_list AS
+SELECT
+    internship_personnel.id,
+    internship_personnel.personal_id,
+    internship_personnel.internship_post_id,
+    internship_personnel.internship_status,
+    internship_personnel.start_date,
+    internship_personnel.end_date,
+    internship_personnel.audit_status,
+    internship_personnel.audit_opinion,
+    personal_info.full_name,
+    personal_info.gender,
+    personal_info.contact_phone,
+    personal_info.education,
+    personal_info.id_number,
+    internship_post.post_name,
+    internship_post.company_name
+FROM internship_personnel
+LEFT JOIN personal_info ON internship_personnel.personal_id = personal_info.id
+LEFT JOIN internship_post ON internship_personnel.internship_post_id = internship_post.id;
+
+-- ============================================================
+-- 第10步:重新执行新增模块测试数据
+-- 确保本脚本与 新增模块测试数据.sql 在同一目录下
+-- ============================================================
+-- 取消下面注释即可自动执行(部分数据库不支持source语法时,请手动执行)
+-- source 新增模块测试数据.sql;

+ 47 - 0
.docs/sql/菜单结构调整-放到信息智能匹配推送下.sql

@@ -0,0 +1,47 @@
+-- ============================================================
+-- 菜单结构调整SQL
+--
+-- 将 见习岗位管理、见习人员管理、公益性岗位管理、岗位推荐
+-- 从一级菜单改为"信息智能匹配推送"的子菜单
+-- 与"重点关注人员管理"同级
+--
+-- 执行方式:直接运行即可
+-- 适用数据库:达梦数据库 (DM8) / MySQL 8.0
+-- 创建日期:2026-06-03
+-- ============================================================
+
+-- ============================================================
+-- 第1步:删除原一级菜单的角色授权记录
+-- ============================================================
+DELETE FROM sys_role_permission WHERE permission_id = '178060100000030';
+DELETE FROM sys_role_permission WHERE permission_id = '178060100000040';
+DELETE FROM sys_role_permission WHERE permission_id = '178060100000050';
+
+-- ============================================================
+-- 第2步:删除原一级菜单
+-- ============================================================
+DELETE FROM sys_permission WHERE id = '178060100000030';
+DELETE FROM sys_permission WHERE id = '178060100000040';
+DELETE FROM sys_permission WHERE id = '178060100000050';
+
+-- ============================================================
+-- 第3步:将4个二级菜单的父级改为"信息智能匹配推送"(178060100000002)
+-- 并调整排序
+-- ============================================================
+
+-- 见习岗位管理:排序2.00
+UPDATE sys_permission SET parent_id = '178060100000002', sort_no = 2.00 WHERE id = '178060100000031';
+
+-- 见习人员管理:排序3.00
+UPDATE sys_permission SET parent_id = '178060100000002', sort_no = 3.00 WHERE id = '178060100000032';
+
+-- 公益性岗位管理:排序4.00
+UPDATE sys_permission SET parent_id = '178060100000002', sort_no = 4.00 WHERE id = '178060100000041';
+
+-- 岗位推荐:排序5.00
+UPDATE sys_permission SET parent_id = '178060100000002', sort_no = 5.00 WHERE id = '178060100000051';
+
+-- ============================================================
+-- 第4步:确认角色授权记录存在(admin角色,id=f6817f48af4fb3af11b9e8bf182f618b)
+-- 二级菜单的授权记录已在V5~V8 Flyway脚本中创建
+-- ============================================================

+ 34 - 0
.docs/sql/见习人员信息重新录入.sql

@@ -0,0 +1,34 @@
+-- ============================================================
+-- 就业一湛通服务平台 - 见习人员信息重新录入
+--
+-- 说明:仅重新录入见习人员关联数据(internship_personnel)
+--       personal_info 已在"重点关注人员测试数据.sql"中定义,
+--       job_seeker_category 为多样化求职人员类型,
+--       见习标记通过 internship_personnel 表实现
+-- 不影响:企业信息、岗位信息、见习岗位、公益性岗位、岗位推荐
+-- 不影响:重点关注人员标签数据
+--
+-- 执行方式:先执行重点关注人员测试数据.sql,再执行本脚本
+-- 数据库:达梦数据库 (DM8) / MySQL 8.0 兼容
+-- 创建日期:2026-06-03
+-- ============================================================
+
+-- ============================================================
+-- 第1步:删除已有见习人员关联数据
+-- ============================================================
+DELETE FROM internship_personnel WHERE ID >= 178060100000330 AND ID <= 178060100000334;
+
+-- ============================================================
+-- 第2步:重新插入见习人员关联数据
+-- 关联规则:
+--   周九(206, 应届高校毕业生) → 软件测试见习生(恒兴科技)
+--   吴十(207, 新成长失业青年) → 行政文员见习生(博文教育)
+--   郑十一(208, 农村转移就业劳动者) → 机械维修见习生(港湾实业)
+--   周九(206) → 农业技术见习生(绿源农业, 报名已满)
+--   吴十(207) → 物业管理见习生(阳光物业, 待审核)
+-- ============================================================
+INSERT INTO internship_personnel (ID, PERSONAL_ID, INTERNSHIP_POST_ID, INTERNSHIP_STATUS, START_DATE, END_DATE, AUDIT_STATUS, AUDIT_OPINION) VALUES (178060100000330, 178060100000206, 178060100000320, '见习中', '2026-04-01', '2026-09-30', '已通过', '符合见习条件,审核通过');
+INSERT INTO internship_personnel (ID, PERSONAL_ID, INTERNSHIP_POST_ID, INTERNSHIP_STATUS, START_DATE, END_DATE, AUDIT_STATUS, AUDIT_OPINION) VALUES (178060100000331, 178060100000207, 178060100000322, '见习中', '2026-05-01', '2026-07-31', '已通过', '符合见习条件,审核通过');
+INSERT INTO internship_personnel (ID, PERSONAL_ID, INTERNSHIP_POST_ID, INTERNSHIP_STATUS, START_DATE, END_DATE, AUDIT_STATUS, AUDIT_OPINION) VALUES (178060100000332, 178060100000208, 178060100000321, '已期满', '2025-12-01', '2026-05-31', '已通过', '符合见习条件,审核通过');
+INSERT INTO internship_personnel (ID, PERSONAL_ID, INTERNSHIP_POST_ID, INTERNSHIP_STATUS, START_DATE, END_DATE, AUDIT_STATUS, AUDIT_OPINION) VALUES (178060100000333, 178060100000206, 178060100000323, '见习中', '2026-03-15', '2026-09-14', '已通过', '计算机专业背景,推荐到软件测试岗位见习');
+INSERT INTO internship_personnel (ID, PERSONAL_ID, INTERNSHIP_POST_ID, INTERNSHIP_STATUS, START_DATE, END_DATE, AUDIT_STATUS, AUDIT_OPINION) VALUES (178060100000334, 178060100000207, 178060100000324, '待审核', NULL, NULL, '待审核', NULL);

Разница между файлами не показана из-за своего большого размера
+ 44 - 6
.docs/sql/重点关注人员测试数据.sql


+ 140 - 0
.docs/重点关注人员管理-P0任务实现记录.md

@@ -0,0 +1,140 @@
+# 重点关注人员管理(3.2.1)- P0任务实现记录
+
+## 修改日期:2026-06-04
+
+## 一、任务说明
+根据"需求与现有实现对比分析",实施P0优先级任务:
+1. 数据库初始化(字典)
+2. 详情页面完善(展示30个字段)
+3. 补充查询条件
+
+---
+
+## 二、修改文件清单
+
+### 2.1 新增文件
+
+| 序号 | 文件路径 | 说明 |
+|:----:|----------|------|
+| 1 | `jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260604_1__init_focus_personnel_dict.sql` | 字典数据初始化SQL脚本 |
+| 2 | `jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260604_2__menu_insert_FocusPersonnel_buttons.sql` | 补充5个按钮权限SQL |
+| 3 | `jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/entity/FocusPersonnelDetailVo.java` | 详情VO(含个人信息30个字段) |
+| 4 | `jeecgboot-vue3/src/views/focuspersonnel/components/FocusPersonnelDetail.vue` | 前端详情展示组件(分5个分组展示30个字段) |
+
+### 2.2 修改文件
+
+| 序号 | 文件路径 | 修改内容 |
+|:----:|----------|----------|
+| 1 | `FocusPersonnel.java` | minorTag字段添加@Dict注解(focus_minor_tag字典) |
+| 2 | `FocusPersonnelMapper.java` | 新增queryDetailById方法 |
+| 3 | `FocusPersonnelMapper.xml` | 新增detail查询SQL(LEFT JOIN personal_info);列表查询补充5个查询条件 |
+| 4 | `IFocusPersonnelService.java` | 新增queryDetailById接口方法 |
+| 5 | `FocusPersonnelServiceImpl.java` | 实现queryDetailById方法 |
+| 6 | `FocusPersonnelController.java` | 新增queryDetailById端点;补充5个查询参数 |
+| 7 | `FocusPersonnel.api.ts` | 新增queryDetailById API |
+| 8 | `FocusPersonnelList.vue` | **重新设计**:去除高级搜索;查询条件改为10个(按需求文档);新增"刷新生成"按钮;操作栏扩展为详情/服务跟进/岗位推送/消息推送/自定义标签/删除 |
+| 9 | `FocusPersonnelModal.vue` | 新增detail方法,支持详情/编辑双模式切换 |
+| 10 | `FocusPersonnelForm.vue` | minorTag改为字典选择器(focus_minor_tag) |
+| 11 | `FocusPersonnel.data.ts` | minorTag列添加dictCode配置;清空superQuerySchema(暂不使用高级查询) |
+
+---
+
+## 三、数据库初始化详细说明
+
+### 3.1 字典数据
+
+| 字典编码 | 字典名称 | 字典项数 | 说明 |
+|----------|----------|:--------:|------|
+| `focus_major_tag` | 人员大类标签 | 2 | 就业困难人员、脱贫人员(见习人员已独立为见习人员管理模块) |
+| `focus_minor_tag` | 人员小类标签 | 16 | 含就业困难人员13类、脱贫人员3类(不含见习人员小类) |
+
+### 3.2 补充的按钮权限
+
+| 权限ID | 权限标识 | 名称 | 状态 |
+|--------|----------|------|------|
+| 178060400000050 | `focus_personnel:refresh` | 刷新生成 | 占位(待开发) |
+| 178060400000051 | `focus_personnel:messagePush` | 消息推送 | 占位(待开发) |
+| 178060400000052 | `focus_personnel:jobPush` | 岗位推送 | 占位(待开发) |
+| 178060400000053 | `focus_personnel:serviceFollow` | 服务跟进 | 占位(待开发) |
+| 178060400000054 | `focus_personnel:customTag` | 自定义标签 | 占位(待开发) |
+
+---
+
+## 四、后端详情接口
+
+### GET /focusPersonnel/queryDetailById?id={id}
+
+**请求参数:** id(重点关注人员主键)
+
+**返回数据:** FocusPersonnelDetailVo(30个字段)
+
+**业务逻辑:**
+- 以focus_personnel为主表
+- LEFT JOIN personal_info 通过personal_id关联
+- 同时计算年龄(TIMESTAMPDIFF)
+
+### 查询条件补充
+
+列表查询新增5个查询条件:
+- 户口所在地(householdLocation,模糊匹配)
+- 现居住地(currentResidence,模糊匹配)
+- 人员小类标签(minorTag,精确匹配)
+- 自定义标签(customTag,模糊匹配)
+
+---
+
+## 五、前端详情组件
+
+详情页面分5个分组展示:
+
+| 分组 | 包含字段 | 字段数 |
+|------|----------|:------:|
+| 基本信息 | 姓名、性别、证件类型、证件号码、出生日期、年龄、民族、国籍、婚姻状况、政治面貌 | 10 |
+| 教育背景 | 学历、毕业日期、毕业院校、专业 | 4 |
+| 联系信息 | 联系电话、邮箱、QQ号码、微信号 | 4 |
+| 户籍与居住 | 户口性质、户口所在地、现居住地、现居住地址 | 4 |
+| 求职信息 | 求职人员类别、求职状态、工作经验、职业技能等级、是否留学人才、是否接受推荐职位 | 6 |
+| 标签信息 | 人员大类标签、人员小类标签、自定义标签 | 3 |
+
+---
+
+## 六、前端搜索条件(10个,按需求文档)
+
+| 序号 | 字段 | 控件类型 | 查询方式 |
+|:----:|------|----------|----------|
+| 1 | 姓名 | a-input | 模糊 |
+| 2 | 性别 | a-select | 精确 |
+| 3 | 学历 | a-select | 精确 |
+| 4 | 户口所在地 | a-input | 模糊 |
+| 5 | 现居住地 | a-input | 模糊 |
+| 6 | 年龄 | a-input-number | 精确 |
+| 7 | 人员大类标签 | j-dict-select-tag | 精确 |
+| 8 | 人员小类标签 | j-dict-select-tag | 精确 |
+| 9 | 自定义标签 | a-input | 模糊 |
+| 10 | 就业状态 | a-select | 精确 |
+
+---
+
+## 七、前端操作栏(按需求文档)
+
+| 操作 | 权限标识 | 实现状态 |
+|------|----------|:--------:|
+| 编辑 | focus_personnel:edit | ✅ 已实现 |
+| 详情 | 无 | ✅ 已实现 |
+| 服务跟进 | focus_personnel:serviceFollow | ⚠️ 占位 |
+| 岗位推送 | focus_personnel:jobPush | ⚠️ 占位 |
+| 消息推送 | focus_personnel:messagePush | ⚠️ 占位 |
+| 自定义标签 | focus_personnel:customTag | ⚠️ 占位 |
+| 删除 | focus_personnel:delete | ✅ 已实现 |
+
+---
+
+## 八、注意事项
+
+1. **SQL兼容性**:本项目使用达梦数据库,不支持反引号 `` ` ``,SQL中所有表名、字段名均未使用反引号
+2. **字典兼容**:字典插入使用了 `SELECT ... WHERE NOT EXISTS` 条件判断,避免重复插入
+3. **原有queryById接口保留不变**,新增queryDetailById接口用于详情页面
+4. 前端详情组件通过 `watch record` 自动加载数据,无需手动调用
+5. **不显示高级搜索**,按用户要求去除
+6. **5个新增按钮均为占位**,需后续开发(刷新生成、消息推送、岗位推送、服务跟进、自定义标签)
+7. 数据库不删除原有数据:V20260604_1 和 V20260604_2 脚本都用了 WHERE NOT EXISTS,重复执行不会报错

+ 254 - 0
.docs/重点关注人员管理-需求与现有实现对比分析.md

@@ -0,0 +1,254 @@
+# 重点关注人员管理(3.2.1)- 需求与现有实现对比分析
+
+## 分析日期:2026-06-04
+
+## 一、需求文档来源
+- `湛江市人力资源和社会保障局智慧人社运营运维(2025-2027年)项目需求规格说明书-就业一湛通服务平台.docx`
+- 章节:3.2.1 重点关注人员管理
+
+## 二、现有实现文件结构
+
+### 后端 (jeecg-module-zjrs)
+```
+src/main/java/org/jeecg/modules/zjrs/focuspersonnel/
+├── controller/FocusPersonnelController.java      # REST控制器
+├── entity/
+│   ├── FocusPersonnel.java                        # 实体类(表:focus_personnel)
+│   └── FocusPersonnelPageVo.java                  # 列表页VO(含个人信息字段)
+├── mapper/
+│   ├── FocusPersonnelMapper.java                  # Mapper接口
+│   └── xml/FocusPersonnelMapper.xml                # SQL映射(查询视图v_focus_personnel_list)
+├── service/
+│   ├── IFocusPersonnelService.java                 # 服务接口
+│   └── impl/FocusPersonnelServiceImpl.java         # 服务实现
+```
+
+### 前端 (jeecgboot-vue3)
+```
+src/views/focuspersonnel/
+├── FocusPersonnelList.vue                          # 列表页面
+├── FocusPersonnel.data.ts                          # 表格列配置
+├── FocusPersonnel.api.ts                           # API接口
+├── components/
+│   ├── FocusPersonnelForm.vue                      # 表单组件
+│   └── FocusPersonnelModal.vue                     # 弹窗组件
+```
+
+### SQL脚本
+```
+flyway/sql/mysql/V20260603_1__menu_insert_FocusPersonnel.sql  # 菜单权限SQL
+```
+
+## 三、需求与实现逐项对比
+
+### 3.1 列表字段
+
+| 需求字段 | 现有实现 | 状态 |
+|---------|---------|:----:|
+| 姓名 | ✅ `fullName` | ✅ |
+| 性别 | ✅ `gender` | ✅ |
+| 年龄 | ✅ `age` | ✅ |
+| 学历 | ✅ `education` | ✅ |
+| 户口所在地 | ✅ `householdLocation` | ✅ |
+| 现居住地 | ✅ `currentResidence` | ✅ |
+| 求职人员类别 | ✅ `jobSeekerCategory` | ✅ |
+| 联系电话 | ✅ `contactPhone` | ✅ |
+| 求职状态 | ✅ `jobSearchStatus` | ✅ |
+| 人员大类标签 | ✅ `majorTag` | ✅ |
+| 人员小类标签 | ✅ `minorTag` | ✅ |
+| 自定义标签 | ✅ `customTag` | ✅ |
+
+**列表字段已全部实现。**
+
+### 3.2 查询条件
+
+| 需求查询字段 | 现有实现 | 状态 |
+|-------------|---------|:----:|
+| 姓名 | ✅ | ✅ |
+| 性别 | ✅ | ✅ |
+| 学历 | ✅ | ✅ |
+| 户口所在地 | ❌ 未实现 | ❌ |
+| 现居住地 | ❌ 未实现 | ❌ |
+| 年龄 | ❌ 未实现 | ❌ |
+| 人员大类标签 | ✅ | ✅ |
+| 人员小类标签 | ❌ 未实现 | ❌ |
+| 自定义标签 | ❌ 未实现 | ❌ |
+| 就业状态 | ✅(求职状态) | ✅ |
+
+**查询条件缺少:户口所在地、现居住地、年龄、人员小类标签、自定义标签,需补充。**
+
+### 3.3 支持功能
+
+| 需求功能 | 现有实现 | 状态 | 说明 |
+|---------|---------|:----:|------|
+| 刷新生成 | ❌ 完全未实现 | ❌ | 需点击刷新按钮自动生成/更新重点关注人员数据 |
+| 新增 | ✅ | ✅ | |
+| 导出 | ✅ | ✅ | |
+| 查看/详情 | ⚠️ 部分实现 | ⚠️ | 现有详情仅显示4个字段(personalId, majorTag, minorTag, customTag),需求要求显示30个完整个人信息字段 |
+| 自定义标签 | ⚠️ 部分实现 | ⚠️ | 基础文本输入,需求要求"勾选数据添加自定义标签(支持多选)" |
+| 消息推送 | ❌ 完全未实现 | ❌ | 需新建消息推送功能 |
+| 岗位推送 | ❌ 完全未实现 | ❌ | 需新建岗位推送功能 |
+| 服务跟进 | ❌ 完全未实现 | ❌ | 需新建服务跟进记录功能 |
+
+### 3.4 详情页面字段
+
+需求要求详情页面显示以下字段(关联个人信息表):
+
+| 序号 | 字段 | 现有实现 | 状态 |
+|:----:|------|:--------:|:----:|
+| 1 | 证件类型 | 仅在PersonalInfo表 | ❌ |
+| 2 | 证件号码 | 仅在PersonalInfo表 | ❌ |
+| 3 | 姓名 | 仅在列表VO | ❌(详情未展示) |
+| 4 | 性别 | 同上 | ❌ |
+| 5 | 出生日期 | 同上 | ❌ |
+| 6 | 民族 | 同上 | ❌ |
+| 7 | 国籍 | 同上 | ❌ |
+| 8 | 婚姻状况 | 同上 | ❌ |
+| 9 | 学历 | 同上 | ❌ |
+| 10 | 毕业日期 | 同上 | ❌ |
+| 11 | 毕业院校 | 同上 | ❌ |
+| 12 | 专业 | 同上 | ❌ |
+| 13 | 政治面貌 | 同上 | ❌ |
+| 14 | 工作经验 | 同上 | ❌ |
+| 15 | 户口性质 | 同上 | ❌ |
+| 16 | 户口所在地 | 同上 | ❌ |
+| 17 | 现居住地 | 同上 | ❌ |
+| 18 | 现居住地址 | 同上 | ❌ |
+| 19 | 求职人员类别 | 同上 | ❌ |
+| 20 | 联系电话 | 同上 | ❌ |
+| 21 | 邮箱 | 同上 | ❌ |
+| 22 | QQ号码 | 同上 | ❌ |
+| 23 | 微信号 | 同上 | ❌ |
+| 24 | 是否留学人才 | 同上 | ❌ |
+| 25 | 职业技能等级 | 同上 | ❌ |
+| 26 | 求职状态 | 同上 | ❌ |
+| 27 | 是否接受推荐职位 | 同上 | ❌ |
+| 28 | 人员大类标签 | 在FocusPersonnel表 | ✅ |
+| 29 | 人员小类标签 | 在FocusPersonnel表 | ✅ |
+| 30 | 自定义标签 | 在FocusPersonnel表 | ✅ |
+
+**详情字段严重缺失,需新增详情页面接口,从personal_info表关联查询完整信息。**
+
+### 3.5 业务逻辑 - 刷新生成机制(完全未实现)
+
+需求描述:
+> 点击刷新按钮,系统自动生成或更新重点关注人员数据和判断已经生成的数据的有效性。数据来源于省一体化回流的个人信息数据库。
+
+**需新建:**
+1. 后端刷新接口:`POST /focusPersonnel/refresh`
+2. 自动生成逻辑:从省一体化回流数据(personal_info表)筛选符合条件的重点关注人员
+3. 前端刷新按钮及交互
+
+### 3.6 业务逻辑 - 人员标签体系(部分实现)
+
+#### 3.6.1 大类标签(需初始化字典)
+需求值:就业困难人员、脱贫人员(注:见习人员已独立为见习人员管理模块,不在此处)
+实体已有 `majorTag` 字段,字典 `focus_major_tag` 但未初始化数据。
+
+**需补充:字典`focus_major_tag`的两个选项**
+
+#### 3.6.2 小类标签(需初始化字典)
+**见习人员小类:**
+- 离校2年内未就业高校毕业生
+- 16-24岁失业青年
+
+**就业困难人员小类(13类):**
+1. 大龄失业人员(女≥40岁,男≥50岁)
+2. 残疾人员
+3. 享受最低生活保障待遇人员
+4. 城镇"零就业家庭"人员
+5. 农村零转移就业原建档立卡贫困家庭人员
+6. 失地农民
+7. 连续失业1年以上人员
+8. 戒毒康复人员
+9. 刑满释放人员
+10. 精神障碍康复人员
+11. 失业6个月以上的退役军人
+12. 需赡养患重病直系亲属的人员
+13. 省人民政府规定的其他人员
+
+**脱贫人员小类:**
+- 脱贫不稳定户
+- 边缘易致贫户
+- 突发严重困难户
+
+**需新建字典:`focus_minor_tag` 包含以上所有选项(不含见习人员小类,见习人员已独立管理)**
+
+#### 3.6.3 自动分类判断逻辑(完全未实现)
+需要编写复杂的业务逻辑来自动判断人员分类,特别是见习人员的判断:
+- 离校2年内未就业高校毕业生:毕业日期+2年内+无社保+未就业
+- 16-24岁失业青年:年龄16-24周岁+失业登记
+- 优先级:同时符合时优先显示"离校2年内未就业高校毕业生"
+
+### 3.7 消息推送(完全未实现)
+
+**需新建:**
+1. 数据库表 `focus_personnel_message`:消息主题、消息内容、推送人、推送时间、关联人员ID
+2. 后端 CRUD + 推送接口
+3. 前端消息推送弹窗/页面
+4. 按钮权限
+
+### 3.8 岗位推送(完全未实现)
+
+**需新建:**
+1. 岗位推送功能,可手动选择见习岗位推送给见习人员
+2. 需关联 `internshippost`(见习岗位)模块
+3. 前端岗位推送弹窗
+
+### 3.9 服务跟进(完全未实现)
+
+**需新建:**
+1. 数据库表 `focus_personnel_service_follow`:姓名、服务内容、服务时间、服务人员、关联人员ID
+2. 后端 CRUD 接口
+3. 前端服务跟进列表弹窗/页面
+4. 按钮权限
+
+### 3.10 自定义标签功能增强(需完善)
+
+需求要求:勾选数据添加自定义标签(支持多选)
+现有:只是一个文本输入框
+
+**需改进:**
+1. 后端增加批量添加标签接口
+2. 前端改为标签选择器,支持多选和新增标签
+3. 可关联标签模块(`tag/PersonalTag`)
+
+## 四、数据库表结构问题
+
+| 项目 | 状态 | 说明 |
+|------|:----:|------|
+| `focus_personnel` 表 | ❌ 未找到CREATE语句 | 需补充建表SQL |
+| `v_focus_personnel_list` 视图 | ❌ 未找到CREATE语句 | 需补充创建视图SQL |
+| 字典`focus_major_tag` | ❌ 未初始化 | 需补充字典数据 |
+| 字典`focus_minor_tag` | ❌ 未创建 | 需新建字典 |
+| `service_follow` 表 | ❌ 未创建 | 需新建 |
+| `message_push` 表 | ❌ 未创建 | 需新建 |
+
+## 五、总结 - 需开发的功能列表
+
+按优先级排序:
+
+| 优先级 | 功能 | 工作量评估 |
+|:------:|------|:----------:|
+| P0 | 补充数据库表、视图、字典初始化SQL | 小 |
+| P0 | 完善详情页面(关联personal_info查询30个字段) | 中 |
+| P1 | 新增刷新生成按钮及后端接口 | 大(含分类逻辑) |
+| P1 | 人员标签自动分类判断逻辑 | 大(复杂业务规则) |
+| P1 | 完善查询条件(补充户口所在地、现居住地等5个条件) | 小 |
+| P2 | 服务跟进功能(新建表+CRUD+前端) | 中 |
+| P2 | 消息推送功能(新建表+CRUD+推送+前端) | 中 |
+| P2 | 岗位推送功能(关联见习岗位模块) | 中 |
+| P2 | 自定义标签功能增强(多选+批量操作) | 中 |
+| P3 | 新增按钮权限(服务跟进、消息推送、岗位推送、刷新) | 小 |
+
+## 六、相关数据模型关系
+
+```
+personal_info (个人信息表)
+    ↑ 关联 (personalId)
+focus_personnel (重点关注人员表)
+    ├── focus_personnel_message (消息推送) [待新建]
+    ├── focus_personnel_service_follow (服务跟进) [待新建]
+    └── focus_personnel_job_push (岗位推送) [待新建]
+        关联 internshippost (见习岗位)
+```

+ 1 - 17
jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/video/service/impl/VideoGenerationServiceImpl.java

@@ -109,23 +109,7 @@ public class VideoGenerationServiceImpl implements IVideoGenerationService {
                     "", "D:/ProgramFiles/miniconda3/Scripts/edge-tts.exe");
         }
 
-        log.info("=== AI视频配音工具检测 ===");
-        if (ffmpegPath != null) {
-            log.info("  ffmpeg   : 已找到 -> {}", ffmpegPath);
-        } else {
-            log.warn("  ffmpeg   : 未安装,视频配音功能将不可用");
-        }
-        if (edgeTtsPath != null) {
-            log.info("  edge-tts : 已找到 -> {}", edgeTtsPath);
-        } else {
-            log.warn("  edge-tts : 未安装,视频配音功能将不可用");
-        }
-        if (isToolsAvailable()) {
-            log.info("  视频配音功能: 已启用");
-        } else {
-            log.warn("  视频配音功能: 已禁用(缺少依赖工具,调用配音接口将直接返回无声视频)");
-        }
-        log.info("===========================");
+        // 视频配音功能已关闭,不再输出检测日志
     }
 
     @Override

+ 14 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/controller/FocusPersonnelController.java

@@ -14,6 +14,7 @@ import org.jeecg.common.aspect.annotation.AutoLog;
 import org.jeecg.common.system.base.controller.JeecgController;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnel;
+import org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnelDetailVo;
 import org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnelPageVo;
 import org.jeecg.modules.zjrs.focuspersonnel.service.IFocusPersonnelService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -112,6 +113,19 @@ public class FocusPersonnelController extends JeecgController<FocusPersonnel, IF
         return Result.OK(focusPersonnel);
     }
 
+    /**
+     * 查询重点关注人员详情(关联个人信息表查询全部30个字段)
+     */
+    @Operation(summary = "就业一湛通-重点关注人员管理-查询详情(含个人信息全部字段)")
+    @GetMapping(value = "/queryDetailById")
+    public Result<FocusPersonnelDetailVo> queryDetailById(@RequestParam(name = "id", required = true) String id) {
+        FocusPersonnelDetailVo detail = focusPersonnelService.queryDetailById(id);
+        if (detail == null) {
+            return Result.error("未找到对应数据");
+        }
+        return Result.OK(detail);
+    }
+
     @RequiresPermissions("focus_personnel:exportXls")
     @RequestMapping(value = "/exportXls")
     public ModelAndView exportXls(HttpServletRequest request, FocusPersonnel focusPersonnel) {

+ 3 - 2
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/entity/FocusPersonnel.java

@@ -36,14 +36,15 @@ public class FocusPersonnel implements Serializable {
     @Schema(description = "关联个人信息ID")
     private java.lang.String personalId;
 
-    /**人员大类标签(就业困难人员/脱贫人员)*/
+    /**人员大类标签(就业困难人员/脱贫人员,不含见习人员,见习人员已独立为见习人员管理模块)*/
     @Dict(dicCode = "focus_major_tag")
     @Excel(name = "人员大类标签", width = 15, dictTable = "sys_dict_item", dicCode = "item_text", dicText = "item_value")
     @Schema(description = "人员大类标签")
     private java.lang.String majorTag;
 
     /**人员小类标签*/
-    @Excel(name = "人员小类标签", width = 15)
+    @Dict(dicCode = "focus_minor_tag")
+    @Excel(name = "人员小类标签", width = 15, dictTable = "sys_dict_item", dicCode = "item_text", dicText = "item_value")
     @Schema(description = "人员小类标签")
     private java.lang.String minorTag;
 

+ 130 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/entity/FocusPersonnelDetailVo.java

@@ -0,0 +1,130 @@
+package org.jeecg.modules.zjrs.focuspersonnel.entity;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description: 就业一湛通-重点关注人员详情VO(含个人信息全部字段)
+ * @Author: jeecg-boot
+ * @Date: 2026-06-04
+ * @Version: V1.0
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description = "重点关注人员详情VO")
+public class FocusPersonnelDetailVo implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // ========== 重点关注人员主表字段 ==========
+    @Schema(description = "主键ID")
+    private java.lang.String id;
+
+    @Schema(description = "关联个人信息ID")
+    private java.lang.String personalId;
+
+    @Schema(description = "人员大类标签")
+    private java.lang.String majorTag;
+
+    @Schema(description = "人员小类标签")
+    private java.lang.String minorTag;
+
+    @Schema(description = "自定义标签")
+    private java.lang.String customTag;
+
+    // ========== 个人信息表字段 ==========
+    @Schema(description = "证件类型")
+    private java.lang.String idType;
+
+    @Schema(description = "证件号码")
+    private java.lang.String idNumber;
+
+    @Schema(description = "姓名")
+    private java.lang.String fullName;
+
+    @Schema(description = "性别")
+    private java.lang.String gender;
+
+    @Schema(description = "出生日期")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private Date birthDate;
+
+    @Schema(description = "年龄")
+    private java.lang.Integer age;
+
+    @Schema(description = "民族")
+    private java.lang.String nation;
+
+    @Schema(description = "国籍")
+    private java.lang.String nationality;
+
+    @Schema(description = "婚姻状况")
+    private java.lang.String maritalStatus;
+
+    @Schema(description = "学历")
+    private java.lang.String education;
+
+    @Schema(description = "毕业日期")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private Date graduationDate;
+
+    @Schema(description = "毕业院校")
+    private java.lang.String graduateSchool;
+
+    @Schema(description = "专业")
+    private java.lang.String major;
+
+    @Schema(description = "政治面貌")
+    private java.lang.String politicalStatus;
+
+    @Schema(description = "工作经验")
+    private java.lang.String workExperience;
+
+    @Schema(description = "户口性质")
+    private java.lang.String householdType;
+
+    @Schema(description = "户口所在地")
+    private java.lang.String householdLocation;
+
+    @Schema(description = "现居住地")
+    private java.lang.String currentResidence;
+
+    @Schema(description = "现居住地址")
+    private java.lang.String currentAddress;
+
+    @Schema(description = "求职人员类别")
+    private java.lang.String jobSeekerCategory;
+
+    @Schema(description = "联系电话")
+    private java.lang.String contactPhone;
+
+    @Schema(description = "邮箱")
+    private java.lang.String email;
+
+    @Schema(description = "QQ号码")
+    private java.lang.String qqNumber;
+
+    @Schema(description = "微信号")
+    private java.lang.String wechatId;
+
+    @Schema(description = "是否留学人才")
+    private java.lang.String isOverseasTalent;
+
+    @Schema(description = "职业技能等级")
+    private java.lang.String skillLevel;
+
+    @Schema(description = "求职状态")
+    private java.lang.String jobSearchStatus;
+
+    @Schema(description = "是否接受公共就业服务机构推荐职位")
+    private java.lang.String acceptRecommend;
+}

+ 8 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/mapper/FocusPersonnelMapper.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.apache.ibatis.annotations.Param;
 import org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnel;
+import org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnelDetailVo;
 import org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnelPageVo;
 
 import java.util.Map;
@@ -23,4 +24,11 @@ public interface FocusPersonnelMapper extends BaseMapper<FocusPersonnel> {
      * @return 包含个人信息字段的分页数据
      */
     Page<FocusPersonnelPageVo> queryPageList(Page<FocusPersonnelPageVo> page, @Param("params") Map<String, String> params);
+
+    /**
+     * 查询重点关注人员详情(关联个人信息表查询全部字段)
+     * @param id 重点关注人员ID
+     * @return 包含个人信息全部字段的详情数据
+     */
+    FocusPersonnelDetailVo queryDetailById(@Param("id") String id);
 }

+ 53 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/mapper/xml/FocusPersonnelMapper.xml

@@ -15,6 +15,18 @@
             <if test="params.education != null and params.education != ''">
                 AND education = #{params.education}
             </if>
+            <if test="params.householdLocation != null and params.householdLocation != ''">
+                AND household_location LIKE CONCAT('%', #{params.householdLocation}, '%')
+            </if>
+            <if test="params.currentResidence != null and params.currentResidence != ''">
+                AND current_residence LIKE CONCAT('%', #{params.currentResidence}, '%')
+            </if>
+            <if test="params.minorTag != null and params.minorTag != ''">
+                AND minor_tag = #{params.minorTag}
+            </if>
+            <if test="params.customTag != null and params.customTag != ''">
+                AND custom_tag LIKE CONCAT('%', #{params.customTag}, '%')
+            </if>
             <if test="params.majorTag != null and params.majorTag != ''">
                 AND major_tag = #{params.majorTag}
             </if>
@@ -25,4 +37,45 @@
         ORDER BY id DESC
     </select>
 
+    <!-- 重点关注人员详情 - 关联个人信息表查询全部字段(达梦兼容:无反引号,年龄用FLOOR+MONTHS_BETWEEN计算) -->
+    <select id="queryDetailById" resultType="org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnelDetailVo">
+        SELECT
+            fp.id,
+            fp.personal_id AS personalId,
+            fp.major_tag AS majorTag,
+            fp.minor_tag AS minorTag,
+            fp.custom_tag AS customTag,
+            pi.id_type AS idType,
+            pi.id_number AS idNumber,
+            pi.full_name AS fullName,
+            pi.gender AS gender,
+            pi.birth_date AS birthDate,
+            FLOOR(MONTHS_BETWEEN(CURRENT_DATE, pi.birth_date) / 12) AS age,
+            pi.nation AS nation,
+            pi.nationality AS nationality,
+            pi.marital_status AS maritalStatus,
+            pi.education AS education,
+            pi.graduation_date AS graduationDate,
+            pi.graduate_school AS graduateSchool,
+            pi.major AS major,
+            pi.political_status AS politicalStatus,
+            pi.work_experience AS workExperience,
+            pi.household_type AS householdType,
+            pi.household_location AS householdLocation,
+            pi.current_residence AS currentResidence,
+            pi.current_address AS currentAddress,
+            pi.job_seeker_category AS jobSeekerCategory,
+            pi.contact_phone AS contactPhone,
+            pi.email AS email,
+            pi.qq_number AS qqNumber,
+            pi.wechat_id AS wechatId,
+            pi.is_overseas_talent AS isOverseasTalent,
+            pi.skill_level AS skillLevel,
+            pi.job_search_status AS jobSearchStatus,
+            pi.accept_recommend AS acceptRecommend
+        FROM focus_personnel fp
+        LEFT JOIN personal_info pi ON fp.personal_id = pi.id
+        WHERE fp.id = #{id}
+    </select>
+
 </mapper>

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

@@ -3,6 +3,7 @@ package org.jeecg.modules.zjrs.focuspersonnel.service;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 import org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnel;
+import org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnelDetailVo;
 import org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnelPageVo;
 
 import java.util.Map;
@@ -19,4 +20,11 @@ public interface IFocusPersonnelService extends IService<FocusPersonnel> {
      * 分页列表查询(关联个人信息表)
      */
     Page<FocusPersonnelPageVo> queryPageList(Page<FocusPersonnelPageVo> page, Map<String, String> params);
+
+    /**
+     * 查询重点关注人员详情(关联个人信息表查询全部字段)
+     * @param id 重点关注人员ID
+     * @return 包含个人信息全部字段的详情VO
+     */
+    FocusPersonnelDetailVo queryDetailById(String id);
 }

+ 6 - 0
jeecg-boot/jeecg-boot-module/jeecg-module-zjrs/src/main/java/org/jeecg/modules/zjrs/focuspersonnel/service/impl/FocusPersonnelServiceImpl.java

@@ -3,6 +3,7 @@ package org.jeecg.modules.zjrs.focuspersonnel.service.impl;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnel;
+import org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnelDetailVo;
 import org.jeecg.modules.zjrs.focuspersonnel.entity.FocusPersonnelPageVo;
 import org.jeecg.modules.zjrs.focuspersonnel.mapper.FocusPersonnelMapper;
 import org.jeecg.modules.zjrs.focuspersonnel.service.IFocusPersonnelService;
@@ -23,4 +24,9 @@ public class FocusPersonnelServiceImpl extends ServiceImpl<FocusPersonnelMapper,
     public Page<FocusPersonnelPageVo> queryPageList(Page<FocusPersonnelPageVo> page, Map<String, String> params) {
         return baseMapper.queryPageList(page, params);
     }
+
+    @Override
+    public FocusPersonnelDetailVo queryDetailById(String id) {
+        return baseMapper.queryDetailById(id);
+    }
 }

+ 10 - 13
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260603_5__menu_insert_InternshipPost.sql

@@ -3,17 +3,13 @@
 
 -- ============================================================
 -- 就业一湛通服务平台 - 菜单权限SQL
+-- 菜单层级:信息智能匹配推送 > 见习岗位管理
 -- 不使用反引号(达梦数据库兼容)
 -- ============================================================
 
+-- 二级菜单:见习岗位管理(父级为信息智能匹配推送 178060100000002)
 INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
-VALUES ('178060100000030', '', '见习管理', '/internship', 'layouts/default/index', 1, '', '/internship/internshipPostList', 0, NULL, '0', 1.90, 0, 'ant-design:solution-outlined', 0, 0, 0, 0, NULL, 'admin', '2026-06-03 10:00:00', NULL, NULL, 0, 0, NULL, 0);
-
-INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
-VALUES ('178060100000031', '178060100000030', '见习岗位管理', '/internship/internshipPostList', 'internshippost/InternshipPostList', 1, '', NULL, 1, NULL, '0', 1.00, 0, 'ant-design:audit-outlined', 1, 0, 0, 0, NULL, 'admin', '2026-06-03 10:00:00', NULL, NULL, 0, 0, NULL, 0);
+VALUES ('178060100000031', '178060100000002', '见习岗位管理', '/internship/internshipPostList', 'internshippost/InternshipPostList', 1, '', NULL, 1, NULL, '0', 2.00, 0, 'ant-design:audit-outlined', 1, 0, 0, 0, NULL, 'admin', '2026-06-03 10:00:00', NULL, NULL, 0, 0, NULL, 0);
 
 -- 按钮权限:新增
 INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
@@ -41,18 +37,16 @@ VALUES ('1780601000000316', '178060100000031', '导入excel_见习岗位管理',
 
 -- 角色授权(admin角色)
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000317', 'f6817f48af4fb3af11b9e8bf182f618b', '178060100000030', NULL, '2026-06-03 10:00:00', '127.0.0.1');
-INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000318', 'f6817f48af4fb3af11b9e8bf182f618b', '178060100000031', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000317', 'f6817f48af4fb3af11b9e8bf182f618b', '178060100000031', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000319', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000311', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000318', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000311', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000320', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000312', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000319', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000312', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000321', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000313', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000320', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000313', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000322', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000314', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000321', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000314', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000323', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000315', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000322', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000315', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000324', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000316', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000323', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000316', NULL, '2026-06-03 10:00:00', '127.0.0.1');

+ 3 - 1
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260603_6__menu_insert_InternshipPersonnel.sql

@@ -3,13 +3,13 @@
 
 -- ============================================================
 -- 就业一湛通服务平台 - 菜单权限SQL
+-- 菜单层级:信息智能匹配推送 > 见习人员管理
 -- 不使用反引号(达梦数据库兼容)
 -- ============================================================
 
+-- 二级菜单:见习人员管理(父级为信息智能匹配推送 178060100000002)
 INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
-VALUES ('178060100000032', '178060100000030', '见习人员管理', '/internship/internshipPersonnelList', 'internshippersonnel/InternshipPersonnelList', 1, '', NULL, 1, NULL, '0', 2.00, 0, 'ant-design:user-outlined', 1, 0, 0, 0, NULL, 'admin', '2026-06-03 10:00:00', NULL, NULL, 0, 0, NULL, 0);
+VALUES ('178060100000032', '178060100000002', '见习人员管理', '/internship/internshipPersonnelList', 'internshippersonnel/InternshipPersonnelList', 1, '', NULL, 1, NULL, '0', 3.00, 0, 'ant-design:user-outlined', 1, 0, 0, 0, NULL, 'admin', '2026-06-03 10:00:00', NULL, NULL, 0, 0, NULL, 0);
 
 -- 按钮权限:新增
 INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)

+ 10 - 13
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260603_7__menu_insert_WelfarePost.sql

@@ -3,17 +3,13 @@
 
 -- ============================================================
 -- 就业一湛通服务平台 - 菜单权限SQL
+-- 菜单层级:信息智能匹配推送 > 公益性岗位管理
 -- 参考:V20260603_1__menu_insert_FocusPersonnel.sql
 -- ============================================================
 
+-- 二级菜单:公益性岗位管理(父级为信息智能匹配推送 178060100000002)
 INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
-VALUES ('178060100000040', '', '公益性岗位管理', '/welfarePost', 'layouts/default/index', 1, '', '/welfarePost/welfarePostList', 0, NULL, '0', 2.00, 0, 'ant-design:heart-outlined', 0, 0, 0, 0, NULL, 'admin', '2026-06-03 10:00:00', NULL, NULL, 0, 0, NULL, 0);
-
-INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
-VALUES ('178060100000041', '178060100000040', '公益性岗位管理', '/welfarePost/welfarePostList', 'welfarepost/WelfarePostList', 1, '', NULL, 1, NULL, '0', 1.00, 0, 'ant-design:heart-outlined', 1, 0, 0, 0, NULL, 'admin', '2026-06-03 10:00:00', NULL, NULL, 0, 0, NULL, 0);
+VALUES ('178060100000041', '178060100000002', '公益性岗位管理', '/welfarePost/welfarePostList', 'welfarepost/WelfarePostList', 1, '', NULL, 1, NULL, '0', 4.00, 0, 'ant-design:heart-outlined', 1, 0, 0, 0, NULL, 'admin', '2026-06-03 10:00:00', NULL, NULL, 0, 0, NULL, 0);
 
 -- 按钮权限:新增
 INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
@@ -41,18 +37,16 @@ VALUES ('1780601000000416', '178060100000041', '导入excel_公益性岗位管
 
 -- 角色授权(admin角色)
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000417', 'f6817f48af4fb3af11b9e8bf182f618b', '178060100000040', NULL, '2026-06-03 10:00:00', '127.0.0.1');
-INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000418', 'f6817f48af4fb3af11b9e8bf182f618b', '178060100000041', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000417', 'f6817f48af4fb3af11b9e8bf182f618b', '178060100000041', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000419', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000411', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000418', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000411', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000420', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000412', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000419', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000412', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000421', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000413', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000420', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000413', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000422', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000414', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000421', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000414', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000423', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000415', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000422', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000415', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000424', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000416', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000423', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000416', NULL, '2026-06-03 10:00:00', '127.0.0.1');

+ 10 - 13
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260603_8__menu_insert_JobRecommend.sql

@@ -3,17 +3,13 @@
 
 -- ============================================================
 -- 就业一湛通服务平台 - 菜单权限SQL
+-- 菜单层级:信息智能匹配推送 > 岗位推荐
 -- 参考:V20260603_1__menu_insert_FocusPersonnel.sql
 -- ============================================================
 
+-- 二级菜单:岗位推荐(父级为信息智能匹配推送 178060100000002)
 INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
-VALUES ('178060100000050', '', '岗位推荐', '/jobRecommend', 'layouts/default/index', 1, '', '/jobRecommend/jobRecommendList', 0, NULL, '0', 2.10, 0, 'ant-design:swap-outlined', 0, 0, 0, 0, NULL, 'admin', '2026-06-03 10:00:00', NULL, NULL, 0, 0, NULL, 0);
-
-INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
-VALUES ('178060100000051', '178060100000050', '岗位推荐', '/jobRecommend/jobRecommendList', 'jobrecommend/JobRecommendList', 1, '', NULL, 1, NULL, '0', 1.00, 0, 'ant-design:swap-outlined', 1, 0, 0, 0, NULL, 'admin', '2026-06-03 10:00:00', NULL, NULL, 0, 0, NULL, 0);
+VALUES ('178060100000051', '178060100000002', '岗位推荐', '/jobRecommend/jobRecommendList', 'jobrecommend/JobRecommendList', 1, '', NULL, 1, NULL, '0', 5.00, 0, 'ant-design:swap-outlined', 1, 0, 0, 0, NULL, 'admin', '2026-06-03 10:00:00', NULL, NULL, 0, 0, NULL, 0);
 
 -- 按钮权限:新增
 INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
@@ -41,18 +37,16 @@ VALUES ('1780601000000516', '178060100000051', '导入excel_岗位推荐', NULL,
 
 -- 角色授权(admin角色)
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000517', 'f6817f48af4fb3af11b9e8bf182f618b', '178060100000050', NULL, '2026-06-03 10:00:00', '127.0.0.1');
-INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000518', 'f6817f48af4fb3af11b9e8bf182f618b', '178060100000051', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000517', 'f6817f48af4fb3af11b9e8bf182f618b', '178060100000051', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000519', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000511', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000518', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000511', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000520', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000512', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000519', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000512', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000521', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000513', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000520', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000513', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000522', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000514', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000521', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000514', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000523', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000515', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000522', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000515', NULL, '2026-06-03 10:00:00', '127.0.0.1');
 INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
-VALUES ('1780601000000524', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000516', NULL, '2026-06-03 10:00:00', '127.0.0.1');
+VALUES ('1780601000000523', 'f6817f48af4fb3af11b9e8bf182f618b', '1780601000000516', NULL, '2026-06-03 10:00:00', '127.0.0.1');

+ 118 - 0
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260604_1__init_focus_personnel_dict.sql

@@ -0,0 +1,118 @@
+-- ============================================================
+-- 重点关注人员管理 - 字典数据初始化SQL
+-- 说明:focus_personnel表 和 v_focus_personnel_list视图 已存在,仅初始化字典
+-- 注意:见习人员已独立为见习人员管理模块,此处大类标签只包含就业困难人员、脱贫人员
+-- 达梦数据库兼容(不加反引号,使用 FROM DUAL)
+-- ============================================================
+
+-- ============================================================
+-- 1. 初始化字典:人员大类标签 (focus_major_tag)
+--    只包含:就业困难人员、脱贫人员
+-- ============================================================
+INSERT INTO sys_dict (id, dict_name, dict_code, description, del_flag, create_by, create_time, update_by, update_time, type)
+SELECT '178060400000001', '人员大类标签', 'focus_major_tag', '重点关注人员的大类标签:就业困难人员、脱贫人员', 0, 'admin', '2026-06-04 09:00:00', NULL, NULL, 0
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM sys_dict WHERE dict_code = 'focus_major_tag');
+
+-- 字典项:就业困难人员
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000021', d.id, '就业困难人员', '就业困难人员', NULL, 1, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_major_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '就业困难人员');
+
+-- 字典项:脱贫人员
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000022', d.id, '脱贫人员', '脱贫人员', NULL, 2, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_major_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '脱贫人员');
+
+-- ============================================================
+-- 2. 初始化字典:人员小类标签 (focus_minor_tag)
+--    包含:就业困难人员13类、脱贫人员3类(不含见习人员小类)
+-- ============================================================
+INSERT INTO sys_dict (id, dict_name, dict_code, description, del_flag, create_by, create_time, update_by, update_time, type)
+SELECT '178060400000002', '人员小类标签', 'focus_minor_tag', '重点关注人员的小类标签:含就业困难人员13类、脱贫人员3类', 0, 'admin', '2026-06-04 09:00:00', NULL, NULL, 0
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM sys_dict WHERE dict_code = 'focus_minor_tag');
+
+-- 就业困难人员小类(13类)
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000032', d.id, '大龄失业人员', '大龄失业人员', '就业困难人员小类', 1, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '大龄失业人员');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000033', d.id, '残疾人员', '残疾人员', '就业困难人员小类', 2, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '残疾人员');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000034', d.id, '享受最低生活保障待遇人员', '享受最低生活保障待遇人员', '就业困难人员小类', 3, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '享受最低生活保障待遇人员');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000035', d.id, '城镇零就业家庭人员', '城镇零就业家庭人员', '就业困难人员小类', 4, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '城镇零就业家庭人员');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000036', d.id, '农村零转移就业原建档立卡贫困家庭人员', '农村零转移就业原建档立卡贫困家庭人员', '就业困难人员小类', 5, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '农村零转移就业原建档立卡贫困家庭人员');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000037', d.id, '失地农民', '失地农民', '就业困难人员小类', 6, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '失地农民');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000038', d.id, '连续失业1年以上人员', '连续失业1年以上人员', '就业困难人员小类', 7, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '连续失业1年以上人员');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000039', d.id, '戒毒康复人员', '戒毒康复人员', '就业困难人员小类', 8, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '戒毒康复人员');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000040', d.id, '刑满释放人员', '刑满释放人员', '就业困难人员小类', 9, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '刑满释放人员');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000041', d.id, '精神障碍康复人员', '精神障碍康复人员', '就业困难人员小类', 10, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '精神障碍康复人员');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000042', d.id, '失业6个月以上退役军人', '失业6个月以上退役军人', '就业困难人员小类', 11, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '失业6个月以上退役军人');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000043', d.id, '需赡养患重病直系亲属的人员', '需赡养患重病直系亲属的人员', '就业困难人员小类', 12, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '需赡养患重病直系亲属的人员');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000044', d.id, '省人民政府规定的其他人员', '省人民政府规定的其他人员', '就业困难人员小类', 13, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '省人民政府规定的其他人员');
+
+-- 脱贫人员小类
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000045', d.id, '脱贫不稳定户', '脱贫不稳定户', '脱贫人员小类', 14, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '脱贫不稳定户');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000046', d.id, '边缘易致贫户', '边缘易致贫户', '脱贫人员小类', 15, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '边缘易致贫户');
+
+INSERT INTO sys_dict_item (id, dict_id, item_text, item_value, description, sort_order, status, create_by, create_time, update_by, update_time)
+SELECT '178060400000047', d.id, '突发严重困难户', '突发严重困难户', '脱贫人员小类', 16, 1, 'admin', '2026-06-04 09:00:00', NULL, NULL
+FROM sys_dict d WHERE d.dict_code = 'focus_minor_tag' AND d.del_flag = 0
+AND NOT EXISTS (SELECT 1 FROM sys_dict_item si WHERE si.dict_id = d.id AND si.item_value = '突发严重困难户');

+ 62 - 0
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V20260604_2__menu_insert_FocusPersonnel_buttons.sql

@@ -0,0 +1,62 @@
+-- ============================================================
+-- 重点关注人员管理 - 补充按钮权限SQL
+-- 说明:补充5个新功能的按钮权限(刷新生成、消息推送、岗位推送、服务跟进、自定义标签)
+-- 父菜单 menu_id = 178060100000010
+-- 达梦数据库兼容(不加反引号,使用 FROM DUAL)
+-- ============================================================
+
+-- 按钮权限:刷新生成
+INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+SELECT '178060400000050', '178060100000010', '刷新生成', NULL, NULL, 0, '', NULL, 2, 'focus_personnel:refresh', '1', 1, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2026-06-04 10:00:00', NULL, NULL, 0, 0, NULL, 0
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM sys_permission WHERE perms = 'focus_personnel:refresh');
+
+-- 按钮权限:消息推送
+INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+SELECT '178060400000051', '178060100000010', '消息推送', NULL, NULL, 0, '', NULL, 2, 'focus_personnel:messagePush', '1', 2, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2026-06-04 10:00:00', NULL, NULL, 0, 0, NULL, 0
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM sys_permission WHERE perms = 'focus_personnel:messagePush');
+
+-- 按钮权限:岗位推送
+INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+SELECT '178060400000052', '178060100000010', '岗位推送', NULL, NULL, 0, '', NULL, 2, 'focus_personnel:jobPush', '1', 3, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2026-06-04 10:00:00', NULL, NULL, 0, 0, NULL, 0
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM sys_permission WHERE perms = 'focus_personnel:jobPush');
+
+-- 按钮权限:服务跟进
+INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+SELECT '178060400000053', '178060100000010', '服务跟进', NULL, NULL, 0, '', NULL, 2, 'focus_personnel:serviceFollow', '1', 4, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2026-06-04 10:00:00', NULL, NULL, 0, 0, NULL, 0
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM sys_permission WHERE perms = 'focus_personnel:serviceFollow');
+
+-- 按钮权限:自定义标签
+INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+SELECT '178060400000054', '178060100000010', '自定义标签', NULL, NULL, 0, '', NULL, 2, 'focus_personnel:customTag', '1', 5, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2026-06-04 10:00:00', NULL, NULL, 0, 0, NULL, 0
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM sys_permission WHERE perms = 'focus_personnel:customTag');
+
+-- 给管理员角色授权
+INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
+SELECT '178060400000060', 'f6817f48af4fb3af11b9e8bf182f618b', '178060400000050', NULL, '2026-06-04 10:00:00', '127.0.0.1'
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM sys_role_permission WHERE role_id = 'f6817f48af4fb3af11b9e8bf182f618b' AND permission_id = '178060400000050');
+
+INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
+SELECT '178060400000061', 'f6817f48af4fb3af11b9e8bf182f618b', '178060400000051', NULL, '2026-06-04 10:00:00', '127.0.0.1'
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM sys_role_permission WHERE role_id = 'f6817f48af4fb3af11b9e8bf182f618b' AND permission_id = '178060400000051');
+
+INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
+SELECT '178060400000062', 'f6817f48af4fb3af11b9e8bf182f618b', '178060400000052', NULL, '2026-06-04 10:00:00', '127.0.0.1'
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM sys_role_permission WHERE role_id = 'f6817f48af4fb3af11b9e8bf182f618b' AND permission_id = '178060400000052');
+
+INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
+SELECT '178060400000063', 'f6817f48af4fb3af11b9e8bf182f618b', '178060400000053', NULL, '2026-06-04 10:00:00', '127.0.0.1'
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM sys_role_permission WHERE role_id = 'f6817f48af4fb3af11b9e8bf182f618b' AND permission_id = '178060400000053');
+
+INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip)
+SELECT '178060400000064', 'f6817f48af4fb3af11b9e8bf182f618b', '178060400000054', NULL, '2026-06-04 10:00:00', '127.0.0.1'
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM sys_role_permission WHERE role_id = 'f6817f48af4fb3af11b9e8bf182f618b' AND permission_id = '178060400000054');

+ 6 - 6
jeecgboot-vue3/src/locales/lang/zh-CN/sys.ts

@@ -67,7 +67,7 @@ export default {
     signUpFormTitle: '注册',
     forgetFormTitle: '重置密码',
 
-    signInTitle: '湛江人社综合信息门户',
+    signInTitle: '湛江“智慧人社”服务平台',
     signInDesc: '湛江市人力资源和社会保障局综合信息门户平台',
     policy: '我同意敲敲云隐私政策',
     scanSign: `扫码后,即可完成登录`,
@@ -105,10 +105,10 @@ export default {
     subTitleText: '{0}秒后返回登录页面',
 
     //重置密码页面中文
-    authentication:'验证身份',
-    resetLoginPassword:'重置登录密码',
-    resetSuccess:'重置成功',
-    nextStep:'下一步',
-    goToLogin:'去登录'
+    authentication: '验证身份',
+    resetLoginPassword: '重置登录密码',
+    resetSuccess: '重置成功',
+    nextStep: '下一步',
+    goToLogin: '去登录',
   },
 };

+ 9 - 0
jeecgboot-vue3/src/views/focuspersonnel/FocusPersonnel.api.ts

@@ -11,6 +11,7 @@ enum Api {
   deleteBatch = '/focusPersonnel/deleteBatch',
   importExcel = '/focusPersonnel/importExcel',
   exportXls = '/focusPersonnel/exportXls',
+  queryDetailById = '/focusPersonnel/queryDetailById',
 }
 
 /**
@@ -69,4 +70,12 @@ export const batchDelete = (params, handleSuccess) => {
 export const saveOrUpdate = (params, isUpdate) => {
   const url = isUpdate ? Api.edit : Api.save;
   return defHttp.post({ url: url, params }, { isTransformResponse: false });
+};
+
+/**
+ * 查询详情(含个人信息全部字段)
+ * @param params
+ */
+export const queryDetailById = (params) => {
+  return defHttp.get({ url: Api.queryDetailById, params });
 };

+ 3 - 12
jeecgboot-vue3/src/views/focuspersonnel/FocusPersonnel.data.ts

@@ -57,6 +57,7 @@ export const columns: BasicColumn[] = [
     title: '人员小类标签',
     align: 'center',
     dataIndex: 'minorTag',
+    dictCode: 'focus_minor_tag',
   },
   {
     title: '自定义标签',
@@ -65,15 +66,5 @@ export const columns: BasicColumn[] = [
   },
 ];
 
-// 高级查询数据
-export const superQuerySchema = {
-  fullName: { title: '姓名', order: 0, view: 'text', type: 'string' },
-  gender: { title: '性别', order: 1, view: 'text', type: 'string' },
-  education: { title: '学历', order: 2, view: 'text', type: 'string' },
-  householdLocation: { title: '户口所在地', order: 3, view: 'text', type: 'string' },
-  currentResidence: { title: '现居住地', order: 4, view: 'text', type: 'string' },
-  majorTag: { title: '人员大类标签', order: 5, view: 'select', type: 'string', dictCode: 'focus_major_tag' },
-  minorTag: { title: '人员小类标签', order: 6, view: 'text', type: 'string' },
-  customTag: { title: '自定义标签', order: 7, view: 'text', type: 'string' },
-  jobSearchStatus: { title: '求职状态', order: 8, view: 'text', type: 'string' },
-};
+// 高级查询数据(暂未启用,需求要求不显示高级查询)
+export const superQuerySchema = {};

+ 118 - 53
jeecgboot-vue3/src/views/focuspersonnel/FocusPersonnelList.vue

@@ -4,12 +4,12 @@
     <div class="jeecg-basic-table-form-container">
       <a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam" :label-col="labelCol" :wrapper-col="wrapperCol">
         <a-row :gutter="24">
-          <a-col :lg="6">
+          <a-col :lg="6" :md="8" :sm="24">
             <a-form-item label="姓名" name="fullName">
               <a-input placeholder="请输入姓名" v-model:value="queryParam.fullName" allow-clear></a-input>
             </a-form-item>
           </a-col>
-          <a-col :lg="6">
+          <a-col :lg="6" :md="8" :sm="24">
             <a-form-item label="性别" name="gender">
               <a-select placeholder="请选择性别" v-model:value="queryParam.gender" allow-clear>
                 <a-select-option value="男性">男性</a-select-option>
@@ -17,7 +17,7 @@
               </a-select>
             </a-form-item>
           </a-col>
-          <a-col :lg="6">
+          <a-col :lg="6" :md="8" :sm="24">
             <a-form-item label="学历" name="education">
               <a-select placeholder="请选择学历" v-model:value="queryParam.education" allow-clear>
                 <a-select-option value="博士研究生">博士研究生</a-select-option>
@@ -30,14 +30,39 @@
               </a-select>
             </a-form-item>
           </a-col>
-          <a-col :lg="6">
-            <a-form-item label="人员大类标签" name="majorTag">
-              <j-dict-select-tag placeholder="请选择人员大类标签" v-model:value="queryParam.majorTag" dict-code="focus_major_tag" allow-clear />
+          <a-col :lg="6" :md="8" :sm="24">
+            <a-form-item label="户口所在地" name="householdLocation">
+              <a-input placeholder="请输入户口所在地" v-model:value="queryParam.householdLocation" allow-clear></a-input>
             </a-form-item>
           </a-col>
-          <a-col :lg="6">
-            <a-form-item label="求职状态" name="jobSearchStatus">
-              <a-select placeholder="请选择求职状态" v-model:value="queryParam.jobSearchStatus" allow-clear>
+          <a-col :lg="6" :md="8" :sm="24">
+            <a-form-item label="现居住地" name="currentResidence">
+              <a-input placeholder="请输入现居住地" v-model:value="queryParam.currentResidence" allow-clear></a-input>
+            </a-form-item>
+          </a-col>
+          <a-col :lg="6" :md="8" :sm="24">
+            <a-form-item label="年龄" name="age">
+              <a-input-number placeholder="请输入年龄" v-model:value="queryParam.age" :min="0" :max="150" allow-clear style="width: 100%" />
+            </a-form-item>
+          </a-col>
+          <a-col :lg="6" :md="8" :sm="24">
+            <a-form-item label="大类标签" name="majorTag">
+              <j-dict-select-tag placeholder="请选择大类标签" v-model:value="queryParam.majorTag" dict-code="focus_major_tag" allow-clear />
+            </a-form-item>
+          </a-col>
+          <a-col :lg="6" :md="8" :sm="24">
+            <a-form-item label="小类标签" name="minorTag">
+              <j-dict-select-tag placeholder="请选择小类标签" v-model:value="queryParam.minorTag" dict-code="focus_minor_tag" allow-clear />
+            </a-form-item>
+          </a-col>
+          <a-col :lg="6" :md="8" :sm="24">
+            <a-form-item label="自定义标签" name="customTag">
+              <a-input placeholder="请输入自定义标签" v-model:value="queryParam.customTag" allow-clear></a-input>
+            </a-form-item>
+          </a-col>
+          <a-col :lg="6" :md="8" :sm="24">
+            <a-form-item label="就业状态" name="jobSearchStatus">
+              <a-select placeholder="请选择就业状态" v-model:value="queryParam.jobSearchStatus" allow-clear>
                 <a-select-option value="正在求职">正在求职</a-select-option>
                 <a-select-option value="暂不求职">暂不求职</a-select-option>
                 <a-select-option value="已就业">已就业</a-select-option>
@@ -45,19 +70,23 @@
               </a-select>
             </a-form-item>
           </a-col>
-          <a-col :lg="6">
-            <span style="float: left; overflow: hidden">
-              <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
-              <a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
-            </span>
+          <a-col :lg="6" :md="8" :sm="24">
+            <a-form-item>
+              <a-space>
+                <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
+                <a-button preIcon="ant-design:reload-outlined" @click="searchReset">重置</a-button>
+              </a-space>
+            </a-form-item>
           </a-col>
         </a-row>
       </a-form>
     </div>
+
     <!--引用表格-->
     <BasicTable @register="registerTable" :rowSelection="rowSelection">
       <!--插槽:table标题-->
       <template #tableTitle>
+        <a-button v-auth="'focus_personnel:refresh'" preIcon="ant-design:sync-outlined" type="primary" @click="handleRefresh"> 刷新生成</a-button>
         <a-button v-auth="'focus_personnel:add'" preIcon="ant-design:plus-outlined" type="primary" @click="handleAdd"> 新增</a-button>
         <a-button v-auth="'focus_personnel:exportXls'" preIcon="ant-design:export-outlined" type="primary" @click="onExportXls"> 导出</a-button>
         <a-dropdown v-if="selectedRowKeys.length > 0">
@@ -65,7 +94,11 @@
             <a-menu>
               <a-menu-item key="1" @click="batchHandleDelete">
                 <Icon icon="ant-design:delete-outlined"></Icon>
-                删除
+                批量删除
+              </a-menu-item>
+              <a-menu-item key="2" @click="handleBatchMessage">
+                <Icon icon="ant-design:message-outlined"></Icon>
+                消息推送
               </a-menu-item>
             </a-menu>
           </template>
@@ -74,8 +107,6 @@
             <Icon icon="mdi:chevron-down"></Icon>
           </a-button>
         </a-dropdown>
-        <!-- 高级查询 -->
-        <super-query :config="superQueryConfig" @search="handleSuperQuery" />
       </template>
       <!--操作栏-->
       <template #action="{ record }">
@@ -91,22 +122,17 @@
   import { reactive, ref } from 'vue';
   import { BasicTable, TableAction } from '/@/components/Table';
   import { useListPage } from '/@/hooks/system/useListPage';
-  import { columns, superQuerySchema } from './FocusPersonnel.data';
+  import { columns } from './FocusPersonnel.data';
   import { batchDelete, deleteOne, getExportUrl, getImportUrl, list } from './FocusPersonnel.api';
   import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
   import FocusPersonnelModal from './components/FocusPersonnelModal.vue';
-  import { useUserStore } from '/@/store/modules/user';
   import { useMessage } from '/@/hooks/web/useMessage';
-  import { getDateByPicker } from '/@/utils';
-
-  const fieldPickers = reactive({});
 
   const formRef = ref();
   const queryParam = reactive<any>({});
-  const toggleSearchStatus = ref<boolean>(false);
   const registerModal = ref();
-  const userStore = useUserStore();
-  const { createMessage } = useMessage();
+  const { createMessage, createConfirm } = useMessage();
+
   //注册table数据
   const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
     tableProps: {
@@ -116,15 +142,10 @@
       canResize: true,
       useSearchForm: false,
       actionColumn: {
-        width: 120,
+        width: 200,
         fixed: 'right',
       },
       beforeFetch: async (params) => {
-        for (let key in fieldPickers) {
-          if (queryParam[key] && fieldPickers[key]) {
-            queryParam[key] = getDateByPicker(queryParam[key], fieldPickers[key]);
-          }
-        }
         return Object.assign(params, queryParam);
       },
     },
@@ -138,32 +159,19 @@
       success: handleSuccess,
     },
   });
-  const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] =
-    tableContext;
+  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
   const labelCol = reactive({
     xs: 24,
-    sm: 4,
+    sm: 6,
+    md: 8,
     xl: 6,
-    xxl: 4,
+    xxl: 6,
   });
   const wrapperCol = reactive({
     xs: 24,
-    sm: 20,
+    sm: 18,
   });
 
-  // 高级查询配置
-  const superQueryConfig = reactive(superQuerySchema);
-
-  /**
-   * 高级查询事件
-   */
-  function handleSuperQuery(params) {
-    Object.keys(params).map((k) => {
-      queryParam[k] = params[k];
-    });
-    searchQuery();
-  }
-
   /**
    * 新增事件
    */
@@ -184,8 +192,29 @@
    * 详情
    */
   function handleDetail(record: Recordable) {
-    registerModal.value.disableSubmit = true;
-    registerModal.value.edit(record);
+    registerModal.value.detail(record);
+  }
+
+  /**
+   * 刷新生成事件
+   */
+  function handleRefresh() {
+    createConfirm({
+      iconType: 'warning',
+      title: '确认刷新',
+      content: '刷新将从个人信息表中自动生成/更新重点关注人员数据,是否继续?',
+      onOk: () => {
+        // 暂未实现刷新接口,提示占位
+        createMessage.warning('刷新生成功能待开发');
+      },
+    });
+  }
+
+  /**
+   * 批量消息推送
+   */
+  function handleBatchMessage() {
+    createMessage.warning('消息推送功能待开发');
   }
 
   /**
@@ -231,6 +260,26 @@
         label: '详情',
         onClick: handleDetail.bind(null, record),
       },
+      {
+        label: '服务跟进',
+        onClick: handleServiceFollow.bind(null, record),
+        auth: 'focus_personnel:serviceFollow',
+      },
+      {
+        label: '岗位推送',
+        onClick: handleJobPush.bind(null, record),
+        auth: 'focus_personnel:jobPush',
+      },
+      {
+        label: '消息推送',
+        onClick: handleSingleMessage.bind(null, record),
+        auth: 'focus_personnel:messagePush',
+      },
+      {
+        label: '自定义标签',
+        onClick: handleCustomTag.bind(null, record),
+        auth: 'focus_personnel:customTag',
+      },
       {
         label: '删除',
         popConfirm: {
@@ -243,6 +292,23 @@
     ];
   }
 
+  /** 服务跟进占位 */
+  function handleServiceFollow(record) {
+    createMessage.warning('服务跟进功能待开发');
+  }
+  /** 岗位推送占位 */
+  function handleJobPush(record) {
+    createMessage.warning('岗位推送功能待开发');
+  }
+  /** 单条消息推送占位 */
+  function handleSingleMessage(record) {
+    createMessage.warning('消息推送功能待开发');
+  }
+  /** 自定义标签占位 */
+  function handleCustomTag(record) {
+    createMessage.warning('自定义标签功能待开发');
+  }
+
   /**
    * 查询
    */
@@ -256,7 +322,6 @@
   function searchReset() {
     formRef.value.resetFields();
     selectedRowKeys.value = [];
-    //刷新数据
     reload();
   }
 </script>
@@ -286,4 +351,4 @@
       width: 100%;
     }
   }
-</style>
+</style>

+ 236 - 0
jeecgboot-vue3/src/views/focuspersonnel/components/FocusPersonnelDetail.vue

@@ -0,0 +1,236 @@
+<template>
+  <a-spin :spinning="loading">
+    <div class="focus-personnel-detail" v-if="detailData">
+      <!-- 顶部人员概要信息 -->
+      <div class="detail-header">
+        <div class="header-avatar">
+          <a-avatar :size="64" style="background-color: #1890ff">
+            {{ detailData.fullName ? detailData.fullName.substring(0, 1) : '?' }}
+          </a-avatar>
+        </div>
+        <div class="header-info">
+          <div class="header-name">
+            <span class="name">{{ detailData.fullName || '-' }}</span>
+            <span class="gender">{{ detailData.gender || '' }}</span>
+            <span class="age" v-if="detailData.age != null">{{ detailData.age }}岁</span>
+          </div>
+          <div class="header-tags">
+            <a-tag v-if="detailData.majorTag" color="blue">{{ detailData.majorTag }}</a-tag>
+            <a-tag v-if="detailData.minorTag" color="green">{{ detailData.minorTag }}</a-tag>
+            <template v-if="detailData.customTag">
+              <a-tag v-for="tag in customTagList" :key="tag" color="orange">{{ tag }}</a-tag>
+            </template>
+          </div>
+          <div class="header-meta">
+            <span v-if="detailData.education">{{ detailData.education }}</span>
+            <span v-if="detailData.contactPhone"> | {{ detailData.contactPhone }}</span>
+            <span v-if="detailData.jobSearchStatus"> | {{ detailData.jobSearchStatus }}</span>
+          </div>
+        </div>
+      </div>
+
+      <a-divider style="margin: 12px 0" />
+
+      <!-- Tab页签组织详情内容 -->
+      <a-tabs v-model:activeKey="activeTab">
+        <!-- Tab1: 基本信息 -->
+        <a-tab-pane key="basic" tab="基本信息">
+          <a-descriptions bordered :column="2" size="small">
+            <a-descriptions-item label="证件类型">{{ detailData.idType || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="证件号码">{{ detailData.idNumber || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="出生日期">{{ formatDate(detailData.birthDate) }}</a-descriptions-item>
+            <a-descriptions-item label="年龄">{{ detailData.age != null ? detailData.age + '岁' : '-' }}</a-descriptions-item>
+            <a-descriptions-item label="民族">{{ detailData.nation || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="国籍">{{ detailData.nationality || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="婚姻状况">{{ detailData.maritalStatus || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="政治面貌">{{ detailData.politicalStatus || '-' }}</a-descriptions-item>
+          </a-descriptions>
+        </a-tab-pane>
+
+        <!-- Tab2: 教育与求职 -->
+        <a-tab-pane key="education" tab="教育与求职">
+          <a-descriptions bordered :column="2" size="small">
+            <a-descriptions-item label="学历">{{ detailData.education || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="毕业日期">{{ formatDate(detailData.graduationDate) }}</a-descriptions-item>
+            <a-descriptions-item label="毕业院校">{{ detailData.graduateSchool || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="专业">{{ detailData.major || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="工作经验">{{ detailData.workExperience || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="职业技能等级">{{ detailData.skillLevel || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="是否留学人才">{{ detailData.isOverseasTalent || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="求职人员类别">{{ detailData.jobSeekerCategory || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="求职状态">{{ detailData.jobSearchStatus || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="是否接受推荐职位">{{ detailData.acceptRecommend || '-' }}</a-descriptions-item>
+          </a-descriptions>
+        </a-tab-pane>
+
+        <!-- Tab3: 联系与居住 -->
+        <a-tab-pane key="contact" tab="联系与居住">
+          <a-descriptions bordered :column="2" size="small">
+            <a-descriptions-item label="联系电话">{{ detailData.contactPhone || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="邮箱">{{ detailData.email || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="QQ号码">{{ detailData.qqNumber || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="微信号">{{ detailData.wechatId || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="户口性质">{{ detailData.householdType || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="户口所在地">{{ detailData.householdLocation || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="现居住地">{{ detailData.currentResidence || '-' }}</a-descriptions-item>
+            <a-descriptions-item label="现居住地址">{{ detailData.currentAddress || '-' }}</a-descriptions-item>
+          </a-descriptions>
+        </a-tab-pane>
+
+        <!-- Tab4: 标签信息 -->
+        <a-tab-pane key="tags" tab="标签信息">
+          <a-descriptions bordered :column="1" size="small">
+            <a-descriptions-item label="人员大类标签">
+              <a-tag v-if="detailData.majorTag" color="blue">{{ detailData.majorTag }}</a-tag>
+              <span v-else>-</span>
+            </a-descriptions-item>
+            <a-descriptions-item label="人员小类标签">
+              <a-tag v-if="detailData.minorTag" color="green">{{ detailData.minorTag }}</a-tag>
+              <span v-else>-</span>
+            </a-descriptions-item>
+            <a-descriptions-item label="自定义标签">
+              <template v-if="customTagList.length > 0">
+                <a-tag v-for="tag in customTagList" :key="tag" color="orange" style="margin-bottom: 4px">{{ tag }}</a-tag>
+              </template>
+              <span v-else>-</span>
+            </a-descriptions-item>
+          </a-descriptions>
+        </a-tab-pane>
+
+        <!-- Tab5: 服务跟进 -->
+        <a-tab-pane key="service" tab="服务跟进">
+          <div style="margin-bottom: 12px">
+            <a-button type="primary" size="small" @click="handleAddServiceFollow" v-auth="'focus_personnel:serviceFollow'">
+              新增跟进
+            </a-button>
+          </div>
+          <a-table
+            :columns="serviceFollowColumns"
+            :dataSource="serviceFollowList"
+            :pagination="false"
+            size="small"
+            :locale="{ emptyText: '暂无跟进记录' }"
+            rowKey="id"
+          />
+        </a-tab-pane>
+      </a-tabs>
+    </div>
+    <div v-else-if="!loading" style="text-align: center; padding: 40px; color: #999">
+      暂无数据
+    </div>
+  </a-spin>
+</template>
+
+<script lang="ts" setup>
+  import { computed, ref, watch } from 'vue';
+  import { queryDetailById } from '../FocusPersonnel.api';
+  import dayjs from 'dayjs';
+
+  const props = defineProps({
+    record: { type: Object, default: () => ({}) },
+  });
+
+  const loading = ref<boolean>(false);
+  const detailData = ref<any>(null);
+  const activeTab = ref<string>('basic');
+
+  /** 服务跟进列表(暂为空,待后端接口开发) */
+  const serviceFollowList = ref<any[]>([]);
+
+  /** 服务跟进表格列 */
+  const serviceFollowColumns = [
+    { title: '姓名', dataIndex: 'fullName', width: 100 },
+    { title: '服务内容', dataIndex: 'serviceContent' },
+    { title: '服务时间', dataIndex: 'serviceTime', width: 120 },
+    { title: '服务人员', dataIndex: 'servicePerson', width: 100 },
+  ];
+
+  /** 自定义标签列表(逗号分隔转数组) */
+  const customTagList = computed(() => {
+    if (!detailData.value?.customTag) return [];
+    return detailData.value.customTag.split(',').filter((t: string) => t.trim());
+  });
+
+  /** 格式化日期 */
+  function formatDate(date: any) {
+    if (!date) return '-';
+    return dayjs(date).format('YYYY-MM-DD');
+  }
+
+  /** 新增服务跟进(占位) */
+  function handleAddServiceFollow() {
+    // 待开发:打开服务跟进表单弹窗
+  }
+
+  /**
+   * 加载详情数据
+   */
+  async function loadDetail() {
+    if (!props.record.id) return;
+    loading.value = true;
+    activeTab.value = 'basic';
+    try {
+      const res = await queryDetailById({ id: props.record.id });
+      // defHttp默认isTransformResponse=true,返回的res已经是result数据
+      if (res) {
+        detailData.value = res;
+      }
+    } catch (e) {
+      console.error('加载详情失败', e);
+    } finally {
+      loading.value = false;
+    }
+  }
+
+  // 监听record变化自动加载
+  watch(
+    () => props.record,
+    () => {
+      loadDetail();
+    },
+    { immediate: true, deep: true }
+  );
+
+  defineExpose({
+    loadDetail,
+  });
+</script>
+
+<style lang="less" scoped>
+  .focus-personnel-detail {
+    padding: 16px;
+
+    .detail-header {
+      display: flex;
+      align-items: center;
+      gap: 16px;
+
+      .header-info {
+        flex: 1;
+
+        .header-name {
+          margin-bottom: 6px;
+          .name {
+            font-size: 20px;
+            font-weight: 600;
+            margin-right: 8px;
+          }
+          .gender, .age {
+            font-size: 14px;
+            color: #666;
+            margin-right: 6px;
+          }
+        }
+
+        .header-tags {
+          margin-bottom: 6px;
+        }
+
+        .header-meta {
+          font-size: 13px;
+          color: #999;
+        }
+      }
+    }
+  }
+</style>

+ 1 - 1
jeecgboot-vue3/src/views/focuspersonnel/components/FocusPersonnelForm.vue

@@ -16,7 +16,7 @@
             </a-col>
             <a-col :span="12">
               <a-form-item label="人员小类标签" name="minorTag" v-bind="validateInfos.minorTag">
-                <a-input v-model:value="formData.minorTag" allow-clear placeholder="请输入人员小类标签"></a-input>
+                <j-dict-select-tag v-model:value="formData.minorTag" dict-code="focus_minor_tag" placeholder="请选择人员小类标签" allow-clear />
               </a-form-item>
             </a-col>
             <a-col :span="12">

+ 34 - 10
jeecgboot-vue3/src/views/focuspersonnel/components/FocusPersonnelModal.vue

@@ -4,16 +4,19 @@
     :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }"
     :title="title"
     :visible="visible"
-    :width="800"
+    :width="900"
     cancelText="关闭"
-    maxHeight="500px"
+    maxHeight="700px"
     @cancel="handleCancel"
     @ok="handleOk"
   >
-    <FocusPersonnelForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></FocusPersonnelForm>
+    <!-- 详情模式:展示FocusPersonnelDetail -->
+    <FocusPersonnelDetail v-if="isDetailMode" :record="currentRecord" />
+    <!-- 编辑/新增模式:展示FocusPersonnelForm -->
+    <FocusPersonnelForm v-else ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></FocusPersonnelForm>
     <template #footer>
-      <a-button @click="handleCancel">取消</a-button>
-      <a-button :class="{ 'jee-hidden': disableSubmit }" type="primary" @click="handleOk">确认</a-button>
+      <a-button @click="handleCancel">{{ isDetailMode ? '关闭' : '取消' }}</a-button>
+      <a-button v-if="!isDetailMode" type="primary" @click="handleOk">确认</a-button>
     </template>
   </j-modal>
 </template>
@@ -21,14 +24,17 @@
 <script lang="ts" setup>
   import { defineExpose, nextTick, ref } from 'vue';
   import FocusPersonnelForm from './FocusPersonnelForm.vue';
+  import FocusPersonnelDetail from './FocusPersonnelDetail.vue';
   import JModal from '/@/components/Modal/src/JModal/JModal.vue';
   import { useMessage } from '/@/hooks/web/useMessage';
 
   const { createMessage } = useMessage();
   const title = ref<string>('');
-  const width = ref<number>(800);
+  const width = ref<number>(900);
   const visible = ref<boolean>(false);
   const disableSubmit = ref<boolean>(false);
+  const isDetailMode = ref<boolean>(false);
+  const currentRecord = ref<any>({});
   const registerForm = ref();
   const emit = defineEmits(['register', 'success']);
 
@@ -36,7 +42,8 @@
    * 新增
    */
   function add() {
-    title.value = '新增';
+    isDetailMode.value = false;
+    title.value = '新增重点关注人员';
     visible.value = true;
     nextTick(() => {
       registerForm.value.add();
@@ -45,20 +52,35 @@
 
   /**
    * 编辑
-   * @param record
    */
   function edit(record) {
-    title.value = disableSubmit.value ? '详情' : '编辑';
+    isDetailMode.value = false;
+    title.value = '编辑重点关注人员';
     visible.value = true;
+    currentRecord.value = record;
     nextTick(() => {
       registerForm.value.edit(record);
     });
   }
 
+  /**
+   * 详情
+   */
+  function detail(record) {
+    isDetailMode.value = true;
+    title.value = '重点关注人员详情';
+    visible.value = true;
+    currentRecord.value = record;
+  }
+
   /**
    * 确定按钮点击事件
    */
   function handleOk() {
+    if (isDetailMode.value) {
+      handleCancel();
+      return;
+    }
     registerForm.value.submitForm();
   }
 
@@ -76,9 +98,11 @@
   function handleCancel() {
     visible.value = false;
   }
+
   defineExpose({
     add,
     edit,
+    detail,
     disableSubmit,
   });
 </script>
@@ -89,4 +113,4 @@
     display: none !important;
   }
 </style>
-<style lang="less" scoped></style>
+<style lang="less" scoped></style>