重点关注人员管理-P0任务实现记录.md 55 KB

重点关注人员管理(3.2.1)- P0任务实现记录

修改日期:2026-06-04

一、任务说明

根据"需求与现有实现对比分析",实施P0优先级任务:

  1. 数据库初始化(字典)
  2. 详情页面完善(展示30个字段)
  3. 补充查询条件

二、修改文件清单

2.1 新增文件

序号 文件路径 说明
1 jeecg-boot/.../flyway/sql/mysql/V20260604_1__init_focus_personnel_dict.sql 字典数据初始化SQL脚本
2 jeecg-boot/.../flyway/sql/mysql/V20260604_2__menu_insert_FocusPersonnel_buttons.sql 补充5个按钮权限SQL
3 jeecg-boot/.../flyway/sql/mysql/V20260604_3__alter_view_focus_personnel_list.sql 更新视图,添加birthDate和age计算字段(达梦兼容)
4 jeecg-boot/.../flyway/sql/mysql/V20260604_4__fix_minor_tag_dict.sql 修复旧数据与字典不匹配的映射更新SQL
5 jeecg-boot/.../focuspersonnel/entity/FocusPersonnelDetailVo.java 详情VO(含个人信息30个字段)
6 jeecgboot-vue3/.../focuspersonnel/components/FocusPersonnelDetail.vue 前端详情展示组件(Tab页签+概要头部)

2.2 修改文件

序号 文件路径 修改内容
1 FocusPersonnel.java minorTag字段添加@Dict注解
2 FocusPersonnelPageVo.java 添加@Dict注解和@Excel注解
3 FocusPersonnelMapper.java 新增queryDetailById方法
4 FocusPersonnelMapper.xml 新增detail查询SQL;列表补充5个查询条件;增加age范围过滤
5 IFocusPersonnelService.java 新增queryDetailById接口
6 FocusPersonnelServiceImpl.java 实现queryDetailById
7 FocusPersonnelController.java 新增queryDetailById;补充查询参数;增加ageBegin/ageEnd
8 FocusPersonnel.api.ts 新增queryDetailById API
9 FocusPersonnelList.vue 多次迭代:最终改为查询条件10个、顶部按钮仅刷新生成+导出、操作栏显示3个按钮(查看+岗位推送+服务跟进)、年龄范围查询、重置按钮手动清空年龄范围
10 FocusPersonnelModal.vue 新增detail方法,支持详情/编辑双模式
11 FocusPersonnelForm.vue minorTag改为字典选择器
12 FocusPersonnel.data.ts minorTag配置dictCode;清空superQuerySchema

三、数据库初始化

3.1 字典数据

字典编码 字典名称 字典项数 说明
focus_major_tag 人员大类标签 2 就业困难人员、脱贫人员
focus_minor_tag 人员小类标签 16 就业困难13类 + 脱贫3类

3.2 按钮权限

权限标识 名称 状态
focus_personnel:refresh 刷新生成 占位
focus_personnel:messagePush 消息推送 占位
focus_personnel:jobPush 岗位推送 占位
focus_personnel:serviceFollow 服务跟进 占位
focus_personnel:customTag 自定义标签 占位

3.3 视图更新

在 V20260604_3 中更新 v_focus_personnel_list,添加了:

  • birthDate 字段(来自personal_info)
  • age 计算字段(达梦兼容使用 FLOOR(MONTHS_BETWEEN(CURRENT_DATE, pi.birth_date) / 12)

四、列表页最终状态

查询条件(10个)

姓名、性别、学历、户口所在地、现居住地、年龄(范围)、大类标签、小类标签、自定义标签、就业状态

顶部按钮

刷新生成、导出

操作栏

  • 主按钮:查看
  • 下拉菜单:岗位推送、服务跟进

五、注意事项

  1. SQL脚本执行顺序:V20260604_1 → V20260604_2 → V20260604_3(必须按顺序)
  2. 字典初始化:需要执行V20260604_1字典才会生效,否则minorTag无法翻译
  3. 视图更新:需要执行V20260604_3后才能使用年龄范围搜索
  4. 年龄搜索:使用视图中的age计算字段(FLOOR(MONTHS_BETWEEN(CURRENT_DATE, pi.birth_date) / 12)),达梦兼容
  5. 按钮权限:V20260604_2未执行时,因前端已去掉v-auth限制,按钮始终可见
  6. 岗位推送/服务跟进:当前为占位提示,需后续开发
  7. 达梦数据库兼容:所有SQL无反引号,使用 FROM DUAL

六、第二次迭代修改(自定义标签+推送消息按钮+详情页标签编辑)

修改日期:2026-06-04

6.1 修改说明

根据用户需求:

  1. 添加"自定义标签"和"推送消息"按钮,与"导出"按钮同行并放在右侧
  2. 自定义标签搜索条件从文本输入改为下拉框
  3. 此页面自定义标签只在此页面使用(从 focus_personnel 表中提取去重)
  4. 点击"查看"进入详情页时,标签信息Tab支持添加/编辑/删除自定义标签

6.2 修改文件清单

后端修改

序号 文件路径 修改内容
1 FocusPersonnelMapper.xml 新增 listCustomTags SQL,查询所有非空 custom_tag 原始数据
2 FocusPersonnelMapper.java 新增 listCustomTags() 方法定义,导入 List
3 IFocusPersonnelService.java 新增 listCustomTags() 接口方法
4 FocusPersonnelServiceImpl.java 实现 listCustomTags():拆分逗号分隔值、去重、排序
5 FocusPersonnelController.java 新增 GET /listCustomTags 端点

前端修改

序号 文件路径 修改内容
1 FocusPersonnel.api.ts 新增 listCustomTags API 枚举和导出函数
2 FocusPersonnelList.vue 自定义标签搜索改为 <a-select> 下拉框(从后端动态加载标签选项);头部按钮区改为 flex 左右布局:左侧"刷新生成",右侧"自定义标签"+"推送消息"+"导出";新增"自定义标签管理弹窗"(查看现有标签+添加新标签到选项列表);页面加载时调用 listCustomTags 初始化下拉选项
3 FocusPersonnelDetail.vue 标签信息Tab自定义标签改为可编辑:非编辑态显示标签+"编辑"按钮;编辑态显示可关闭的标签列表+输入添加框+保存/取消按钮;保存后调用 /focusPersonnel/edit 更新 custom_tag 字段;导入 PlusOutlined 图标、saveOrUpdate API、useMessage

6.3 功能说明

1. 自定义标签搜索下拉框

  • 页面加载时调用 GET /focusPersonnel/listCustomTags 获取所有标签
  • 后端从 focus_personnel 表提取 custom_tag 字段,拆分逗号分隔值、去重、排序
  • 下拉框单选,支持模糊搜索匹配选项

2. 顶部按钮布局

[刷新生成]                          [自定义标签] [推送消息] [导出]
  • 使用 a-row justify="space-between" 实现左右分布
  • "自定义标签"按钮打开管理弹窗,可查看所有标签和添加新标签
  • "推送消息"按钮暂为占位提示
  • 按钮均有 v-auth 权限控制

3. 详情页自定义标签编辑

  • 标签信息Tab中自定义标签行添加"编辑"按钮
  • 点击"编辑"进入编辑模式:标签可关闭删除、输入框回车或点击加号添加新标签
  • 点击"保存"调用 /focusPersonnel/edit 接口更新数据
  • 保存后自动刷新本地展示数据,退出编辑模式

6.4 接口说明

接口 方法 说明
/focusPersonnel/listCustomTags GET 获取所有自定义标签(去重排序后的列表)
/focusPersonnel/edit PUT/POST 保存自定义标签(通过 id + customTag 字段)

6.5 注意事项

  1. 自定义标签选项来源:从 focus_personnel.custom_tag 字段提取(已有数据的逗号分隔值)。新添加的标签若只在管理弹窗中添加而未分配给任何人,页面刷新后会消失(因为没有持久化到任何人的记录中)
  2. 权限按钮focus_personnel:customTagfocus_personnel:messagePush 已在 V20260604_2 SQL 中定义,需要执行该脚本才能生效
  3. 自定义标签搜索:下拉框选择某个标签后,会以 customTag = '选中值' 的精确匹配方式查询(而非之前的 LIKE 模糊匹配)。如果希望模糊搜索,需要在后端 XML 中修改为 LIKE 查询
  4. 需要重启后端:Java 代码修改后需要重新编译部署
  5. 详情页保存:使用原有的 /focusPersonnel/edit 接口,只更新 idcustomTag 字段,不影响其他字段

七、第三次迭代修改(字典code重构+自定义标签字典+按钮布局修复)

修改日期:2026-06-04

7.1 修改说明

根据用户反馈:

  1. 标签写死问题focus_personnel 表中 major_tag/minor_tag 存储的是文本值(如"就业困难人员"),不是字典code,应该关联字典使用数字code
  2. 自定义标签字典:自定义标签也需要关联字典 focus_custom_tag
  3. 按钮布局不显示:新增的"自定义标签"和"推送消息"按钮因 v-auth 权限未配置未显示(V20260604_2 SQL 未执行)

7.2 修改文件清单

新增文件

序号 文件路径 说明
1 flyway/sql/mysql/V20260604_5__fix_tag_dict_codes.sql 字典code重构 + 自定义标签字典 + 数据迁移

后端修改

序号 文件路径 修改内容
1 FocusPersonnel.java customTag 字段添加 @Dict(dicCode = "focus_custom_tag") 注解
2 FocusPersonnelPageVo.java customTag 字段添加 @Dict(dicCode = "focus_custom_tag") 注解
3 FocusPersonnelDetailVo.java 导入 @Dict 并给 customTag 字段添加 @Dict(dicCode = "focus_custom_tag") 注解

前端修改

序号 文件路径 修改内容
1 FocusPersonnel.data.ts 自定义标签列添加 dictCode: 'focus_custom_tag'
2 FocusPersonnelList.vue 暂时移除"自定义标签"和"推送消息"按钮的 v-auth 指令(等 V20260604_2 SQL 执行后再加回)

7.3 字典code映射表

focus_major_tag(大类标签)

item_value(code) item_text(显示)
1 就业困难人员
2 脱贫人员

focus_minor_tag(小类标签)

item_value(code) item_text(显示) 类别
1 大龄失业人员 就业困难
2 残疾人员 就业困难
3 享受最低生活保障待遇人员 就业困难
4 城镇零就业家庭人员 就业困难
5 农村零转移就业原建档立卡贫困家庭人员 就业困难
6 失地农民 就业困难
7 连续失业1年以上人员 就业困难
8 戒毒康复人员 就业困难
9 刑满释放人员 就业困难
10 精神障碍康复人员 就业困难
11 失业6个月以上退役军人 就业困难
12 需赡养患重病直系亲属的人员 就业困难
13 省人民政府规定的其他人员 就业困难
14 脱贫不稳定户 脱贫人员
15 边缘易致贫户 脱贫人员
16 突发严重困难户 脱贫人员

focus_custom_tag(自定义标签)

item_value item_text 说明
标签文本 标签文本 item_value = item_text(标签本身就是值)

7.4 SQL执行说明

已存在的SQL脚本(按顺序执行):

序号 SQL脚本 说明 状态
1 V20260604_1 初始化字典(focus_major_tag、focus_minor_tag) 已执行
2 V20260604_2 补充按钮权限 未执行(导致按钮不显示)
3 V20260604_3 重建视图(含age计算字段) 已执行
4 V20260604_4 修复旧数据字典映射 已执行
5 V20260604_5 字典code重构 + 自定义标签字典 + 数据迁移 需要执行

重要:V20260604_5 必须在 V20260604_1~V20260604_4 之后执行。它依赖于前序脚本创建的字典ID和数据。

7.5 按钮问题说明

  • "自定义标签"和"推送消息"按钮目前移除了 v-auth 指令,所有用户均可看到
  • 如需权限控制,需执行 V20260604_2 SQL 并在按钮上恢复 v-auth 指令
  • "刷新生成"和"导出"按钮保留原有的 v-auth 权限控制

7.6 注意事项

  1. 数据迁移风险:V20260604_5 会修改 focus_personnel 表中的 major_tagminor_tag 数据(文本→code),建议执行前备份
  2. 视图自动适配v_focus_personnel_list 是视图,数据迁移后自动返回code值,无需重建
  3. 自定义标签字典focus_custom_tagitem_value = item_text@Dict 注解翻译后和原值一致
  4. 需要重启后端:Java 代码修改后需要重新编译部署
  5. SQL执行顺序:必须先执行 V20260604_1 ~ V20260604_4,再执行 V20260604_5

八、第四次迭代修改(自定义标签字典化管理+序号列+标签显示修复+删除服务跟进Tab)

修改日期:2026-06-04

8.1 修改说明

根据用户反馈:

  1. 自定义标签管理和分配分离:管理员在"自定义标签"按钮中管理字典项(增删),用户在详情页只能从字典中选择已有标签(多选下拉),不允许直接输入新标签
  2. 列表加序号列
  3. 详情页标签显示名称而非codemajorTag/minorTag 显示字典翻译后的文本
  4. 详情页去掉"服务跟进"Tab:列表已有服务跟进功能,无需重复
  5. 列表页标签显示名称:通过 dictCode 客户端翻译

8.2 修改文件清单

后端修改

序号 文件路径 修改内容
1 FocusPersonnelMapper.xml 重构 listCustomTagssys_dict_item 表查询;新增 addCustomTagItem/deleteCustomTagItem/checkCustomTagItemExists SQL
2 FocusPersonnelMapper.java 新增 addCustomTagItem/deleteCustomTagItem/checkCustomTagItemExists 方法
3 IFocusPersonnelService.java 新增 addCustomTagItem/deleteCustomTagItem 接口方法
4 FocusPersonnelServiceImpl.java 实现新接口方法(UUID生成器、检查重复、增删字典项);listCustomTags 改为直接查字典
5 FocusPersonnelController.java 新增 POST /addCustomTagItemDELETE /deleteCustomTagItem 端点
6 FocusPersonnelDetailVo.java majorTagminorTag 添加 @Dict(dicCode = "focus_major_tag")@Dict(dicCode = "focus_minor_tag")
7 FocusPersonnelPageVo.java majorTag 添加 @Dict(dicCode = "focus_major_tag")

前端修改

序号 文件路径 修改内容
1 FocusPersonnel.api.ts 新增 addCustomTagItem/deleteCustomTagItem API 枚举和导出函数
2 FocusPersonnel.data.ts 添加"序号"列(customRender: ({index}) => index + 1
3 FocusPersonnelList.vue 自定义标签管理弹窗改为调用后端 API 增删字典项;添加删除确认弹窗;打开管理弹窗时自动刷新标签列表
4 FocusPersonnelDetail.vue 去掉"服务跟进"Tab(Tab5及相关代码全部删除);自定义标签编辑改为 <a-select mode="multiple"> 多选下拉(从 listCustomTags 加载选项);标签显示改为使用 getDictText 函数(优先使用 majorTag_dictText 等后端翻译字段);移除 PlusOutlined 导入

8.3 自定义标签字典化管理流程

管理员操作(列表页):
  点击"自定义标签"按钮 → 弹窗展示 focus_custom_tag 字典所有项
  → 输入名称点击"添加" → 调用 POST /addCustomTagItem → 持久化到 sys_dict_item
  → 点击"删除" → 调用 DELETE /deleteCustomTagItem → 从字典删除

用户操作(详情页):
  点击"编辑" → 显示 <a-select mode="multiple"> 多选下拉
  → 只能从已有字典项中选择 → 不能输入新标签
  → 点击"保存" → 调用 POST /focusPersonnel/edit 更新 custom_tag 字段

8.4 新增接口说明

接口 方法 说明
/focusPersonnel/addCustomTagItem POST 添加自定义标签字典项(参数:itemText)
/focusPersonnel/deleteCustomTagItem DELETE 删除自定义标签字典项(参数:itemValue)

8.5 标签显示修复说明

  • 后端FocusPersonnelDetailVoFocusPersonnelPageVomajorTag/minorTag 都加了 @Dict 注解
  • DictAspect 自动为返回的 JSON 添加 majorTag_dictText/minorTag_dictText/customTag_dictText 等翻译字段
  • 前端详情页getDictText 函数优先使用 _dictText 后缀字段,兜底返回原始值
  • 前端列表页:通过列配置的 dictCode: 'focus_major_tag' 等,由 BasicTable 客户端自动翻译

8.6 注意事项

  1. 需要执行 V20260604_5 SQL:字典code重构后,数据存储的是数字code,需要后端 @Dict 或前端 dictCode 翻译
  2. 需要重启后端:Java 代码修改后需要重新编译部署
  3. 详情页自定义标签编辑:改为下拉多选后,用户只能从管理员预定义的标签中选择,不再支持自由输入

九、BUG修复(API参数错误+标签显示数字)

修改日期:2026-06-04

9.1 BUG1:addCustomTagItem 参数错误

错误现象

Required request parameter 'itemText' for method parameter type String is not present

原因:前端 defHttp.post({ url, params })params 在 POST 请求中被当作请求体(body)发送,而不是 URL 查询参数,而后端使用 @RequestParam 只能从查询参数或表单中读取。

修复

  • 后端 FocusPersonnelController.java@PostMapping 改为 @GetMapping
  • 前端不变(params 在 GET 请求中会自动作为 URL 查询参数)

9.2 BUG2:列表和详情标签显示数字而非文字

错误现象:字典code重构(V20260604_5)后,数据存储为数字code(如 1),但前端未正确翻译。

原因

  1. 详情页 getDictText 函数依赖后端 _dictText 字段(DictAspect可能未拦截自定义方法)
  2. 列表页 BasicTable 的 dictCode 翻译依赖字典缓存,如果用户登录后字典才创建/修改,缓存未更新

修复

  • 详情页:改用 initDictOptions/sys/dict/getDictItems/{dictCode} 加载字典数据,构建 Map<item_value, item_text> 查询映射,getDictText 函数直接查映射
  • 列表页onMounted 中预加载三个字典(focus_major_tagfocus_minor_tagfocus_custom_tag),确保 BasicTable 翻译生效

9.3 修改文件清单

序号 文件路径 修改内容
1 FocusPersonnelController.java addCustomTagItem 方法改为 @GetMapping
2 FocusPersonnelDetail.vue 导入 initDictOptionsloadDictData 加载大类小类字典构建查询映射;getDictText 函数改为查映射
3 FocusPersonnelList.vue 导入 initDictOptionsonMounted 中预加载三个字典

9.4 补充修复(第一次修复无效的原因)

问题 错误原因 修复内容
API错误 Request method 'POST' is not supported 后端改为 @GetMapping 但前端仍用 defHttp.post 前端 API addCustomTagItem 改为 defHttp.get
标签仍显示数字 initDictOptions 返回的字典项字段是 text(不是 label)。JeecgBoot 的 DictModel 只有 {value, text} 字段 item.label 改为 item.text \|\| item.title \|\| item.label(兼容多种字段名)

9.5 注意事项

  1. 字典缓存问题initDictOptions 首次调用会从服务器拉取并缓存。如果字典在用户登录后被修改,需要刷新页面或重新登录清除缓存
  2. 需要重启后端:Java 代码修改后需重新编译部署
  3. 前端需刷新:前端 api.tsDetail.vue 修改后需重启前端 dev server 或硬刷新(Ctrl+F5)

十、列表和详情标签显示数字修复(_dictText + 绕过缓存)

修改日期:2026-06-04

10.1 问题现象

列表页和详情页的人员大类标签、人员小类标签、自定义标签都显示数字(如 12),而不是对应的字典文本(如"就业困难人员"、"脱贫人员")。

10.2 根因分析

列表页:JeecgBoot-vue3 的 BasicTable 组件不识别 columns 配置中的 dictCode 属性。字典翻译完全依赖后端 DictAspect 为返回结果添加的 {fieldName}_dictText 字段(如 majorTag_dictText)。但 data.ts 中列定义的 dataIndex 配置的是原始字段名(如 majorTag),导致 BasicTable 显示的是原始数字值,而不是 majorTag_dictText 的翻译文本。

参考 JeecgBoot 其他模块(如 manage.data.ts),字典列的 dataIndex 直接使用 {field}_dictText 格式:

// manage.data.ts 示例
{ title: '发送状态', dataIndex: 'esSendStatus_dictText' }

详情页loadDictData 使用 initDictOptions 加载字典数据。initDictOptions 内部优先检查前端缓存(userStore.getAllDictItemsauthCache),如果用户在字典被修改(V20260604_5 SQL)之前已登录,缓存中就是旧的字典数据(value='就业困难人员' 而非 value='1'),导致翻译查找失败。

10.3 修复内容

列表页修复

文件FocusPersonnel.data.ts

majorTagminorTagcustomTag 列的 dataIndex 从原始字段名改为 {field}_dictText,移除无用的 dictCode 属性:

// 修改前
{ title: '人员大类标签', dataIndex: 'majorTag', dictCode: 'focus_major_tag' }
{ title: '人员小类标签', dataIndex: 'minorTag', dictCode: 'focus_minor_tag' }
{ title: '自定义标签',   dataIndex: 'customTag', dictCode: 'focus_custom_tag' }

// 修改后
{ title: '人员大类标签', dataIndex: 'majorTag_dictText' }
{ title: '人员小类标签', dataIndex: 'minorTag_dictText' }
{ title: '自定义标签',   dataIndex: 'customTag_dictText' }

详情页修复

文件FocusPersonnelDetail.vue

  1. 导入 ajaxGetDictItems(从 /@/utils/dict/index
  2. loadDictData 中的 initDictOptions 改为 ajaxGetDictItems,绕过前端缓存直接调用后端 API
// 修改前
const majorDict = await initDictOptions('focus_major_tag');
const minorDict = await initDictOptions('focus_minor_tag');

// 修改后
const majorDict = await ajaxGetDictItems('focus_major_tag');
const minorDict = await ajaxGetDictItems('focus_minor_tag');

10.4 修改文件清单

序号 文件路径 修改内容
1 FocusPersonnel.data.ts majorTag/minorTag/customTag 列的 dataIndex 改为 majorTag_dictText/minorTag_dictText/customTag_dictText,移除 dictCode
2 FocusPersonnelDetail.vue 导入 ajaxGetDictItemsloadDictData 中使用 ajaxGetDictItems 替代 initDictOptions 加载大类小类字典
3 FocusPersonnel.api.ts deleteCustomTagItem 增加 { joinParamsToUrl: true } 选项,修复 DELETE 请求参数未传递到 URL 查询参数的问题

10.5 补充修复:deleteCustomTagItem 参数错误

错误现象

Required request parameter 'itemValue' for method parameter type String is not present

原因defHttp.delete 默认将 params 放在请求体(body)中发送,而后端 @RequestParam 只能从 URL 查询参数中读取。deleteOne 已有 { joinParamsToUrl: true } 正确处理,但 deleteCustomTagItem 未添加此选项。

修复:在 FocusPersonnel.api.tsdeleteCustomTagItem 函数中增加 { joinParamsToUrl: true } 选项。

10.6 补充修复:删除自定义标签时检查是否被用户绑定

需求变更:删除自定义标签时,如果有用户绑定了该标签,应禁止删除并给出提示,而不是自动清理。

原因:后端 deleteCustomTagItem 需要先检查 focus_personnel 表中是否有用户使用了该标签。

修复(4个文件修改):

  1. FocusPersonnelMapper.java — 移除 removeCustomTagFromPersonnel,新增 countPersonnelByCustomTag 方法
  2. FocusPersonnelMapper.xml — 移除清理 UPDATE SQL,新增 countPersonnelByCustomTag SELECT SQL,使用 4 种 LIKE 条件精确匹配逗号分隔值中的标签(完全匹配、开头、结尾、中间)
  3. FocusPersonnelServiceImpl.javadeleteCustomTagItem 先检查绑定用户数,大于 0 则返回 false
  4. FocusPersonnelController.java — 处理 Service 返回结果,若不可删除则返回 Result.error("该标签已被用户绑定,无法删除")
  5. FocusPersonnelList.vue — 错误提示改用 e.message 显示后端返回的具体错误信息

修改文件清单更新

序号 文件路径 修改内容
3 FocusPersonnel.api.ts deleteCustomTagItem 增加 { joinParamsToUrl: true }
4 FocusPersonnelMapper.java 移除 removeCustomTagFromPersonnel,新增 countPersonnelByCustomTag
5 FocusPersonnelMapper.xml 移除清理 UPDATE,新增绑定检查 SELECT
6 FocusPersonnelServiceImpl.java deleteCustomTagItem 先检查绑定再删字典项
7 FocusPersonnelController.java 返回 Result.error 提示已被绑定
8 FocusPersonnelList.vue 错误提示显示后端消息

10.7 注意事项

  1. 需重启前端 dev server 或硬刷新(Ctrl+F5)使前端修改生效
  2. 需重启后端:Java 代码修改后需重新编译部署
  3. 列表页依赖后端 DictAspect:已在第九章为 FocusPersonnelPageVo 添加 @Dict 注解

十一、详情页改为单页显示 + 标签去颜色

修改日期:2026-06-04

11.1 需求

  1. 点击查看时所有字段在一页显示,不需要 Tab 页签切换
  2. 标签不使用颜色(去掉 a-tagcolor 属性)

11.2 修改内容

文件FocusPersonnelDetail.vue

  1. 去除 Tab 页签:移除 a-tabs 组件,将四个 Tab(基本信息、教育与求职、联系与居住、标签信息)的字段全部合并到一个 a-descriptions 中,按原顺序排列,使用注释分组标明
  2. 标签去颜色:所有 a-tag 去掉 color 属性(原来有 bluegreenorange
  3. 清理冗余代码:移除不再使用的 activeTab ref 变量及其在 loadDetail 中的赋值,移除未使用的 initDictOptions 导入
  4. 自定义标签占整行:设置 :span="2" 使自定义标签编辑区域占满整行宽度

11.3 修改文件清单

序号 文件路径 修改内容
1 FocusPersonnelDetail.vue 合并所有 Tab 字段到单页 a-descriptions;标签去 color;清理 activeTabinitDictOptions

11.4 自定义标签 UI 二次优化

优化内容

  1. 详情页(FocusPersonnelDetail.vue)

    • 查看模式:使用 flex 布局将标签和编辑按钮行内排列,标签间距一致;编辑按钮改为 type="dashed" 并添加 EditOutlined 图标,更直观
    • 编辑模式:选择框和按钮使用 flex column 布局,按钮之间间距合理
    • 添加 scoped 样式类 .custom-tag-view.custom-tag-edit.custom-tag-item.edit-tag-btn
  2. 列表页(FocusPersonnelList.vue)

    • 自定义标签管理弹窗:替换 a-list 为自定义 div 列表,每项使用 flex 布局左侧标签名、右侧"删除"按钮
    • "删除"按钮默认隐藏,鼠标悬停行时显示(opacity 过渡),界面更简洁
    • 添加标签数量统计显示("共 X 个")
    • 添加空状态提示(a-empty
    • 添加 scoped 样式类 .custom-tag-modal.tag-list-item.tag-delete-btn

11.5 修改文件清单(最终版)

序号 文件路径 修改内容
1 FocusPersonnelDetail.vue 合并所有 Tab 到单页;标签去 color;自定义标签 UI 优化(flex 布局、图标按钮、scoped 样式)
2 FocusPersonnelList.vue 标签管理弹窗 UI 优化(自定义列表、hover 显示删除、数量统计、空状态)

11.6 注意事项

  1. 无需重启后端:纯前端修改,刷新页面即可
  2. 硬刷新(Ctrl+F5) 使修改生效

十二、标签字典迁移到 DICTIONARY_ITEM 表

修改日期:2026-06-04

12.1 需求说明

所有标签字典(focus_major_tagfocus_minor_tagfocus_custom_tag)从 JeecgBoot 系统表 sys_dict + sys_dict_item 迁移到项目自定义字典表 DICTIONARY + DICTIONARY_ITEM

12.2 后端修改

12.2.1 Flyway SQL — V20260604_6__migrate_tags_to_dictionary_item.sql

  • DICTIONARY 表创建 focus_major_tagfocus_minor_tagfocus_custom_tag 三条字典记录
  • sys_dict_item 迁移 focus_major_tagfocus_minor_tag 的字典项到 DICTIONARY_ITEM(Value=Integer编码,Name=标签文本)
  • sys_dict_item 迁移 focus_custom_tag 的字典项到 DICTIONARY_ITEM(Value=自增ROWNUM编码,Name=标签文本)
  • 达梦兼容:使用 FROM DUALNEWID()NOT EXISTS 语法

12.2.2 FocusPersonnelServiceImpl.java

  • 注入 DictionaryItemMapper 替代 baseMapper 的 sys_dict 相关操作
  • listCustomTags():从 DICTIONARY_ITEM 查询 focus_custom_tag 字典的已启用标签
  • addCustomTagItem(itemText):按 Name 查重 → 查找当前最大 Value 自增 → 插入 DICTIONARY_ITEM
  • deleteCustomTagItem(itemValue):按 Name 查找字典项 → 检查绑定 → 从 DICTIONARY_ITEM 删除
  • 删除 checkCustomTagItemExists 方法(不再需要)

12.2.3 FocusPersonnelMapper.java

  • 移除 listCustomTags()addCustomTagItem()deleteCustomTagItem()checkCustomTagItemExists() 方法
  • 保留 countPersonnelByCustomTag()(仍用于检查标签是否被用户绑定)

12.2.4 FocusPersonnelMapper.xml

  • 移除 listCustomTagsaddCustomTagItemdeleteCustomTagItemcheckCustomTagItemExists 四个 SQL
  • 保留 countPersonnelByCustomTagqueryPageListqueryDetailById

12.2.5 FocusPersonnelPageVo.java / FocusPersonnelDetailVo.java

  • 移除所有 @Dict(dicCode = "...") 注解(因不再使用系统 sys_dict 表)
  • 移除 import org.jeecg.common.aspect.annotation.Dict

12.3 前端修改

12.3.1 FocusPersonnelList.vue

  • 导入useDict from /@/hooks/dictionary/useDict,替代旧的 initDictOptionsJDictSelectTag
  • 字典加载const { getDictText, getDictOptions } = useDict(['focus_major_tag', 'focus_minor_tag'])
  • 下拉选项majorTagOptions = computed(() => getDictOptions('focus_major_tag'))minorTagOptions 同理
  • 搜索框<j-dict-select-tag> 替换为 <a-select :options="majorTagOptions">
  • 列渲染:添加 #bodyCell 插槽,使用 getDictText('focus_major_tag', text) 翻译字典值
  • 移除JDictSelectTag 组件导入、initDictOptions 函数导入、onMounted 中的预加载调用

12.3.2 FocusPersonnelDetail.vue

  • 导入useDict 替代 ajaxGetDictItems
  • 字典加载const { getDictText } = useDict(['focus_major_tag', 'focus_minor_tag'])
  • 移除dictMap 响应式变量、loadDictData() 函数、自定义 getDictText() 函数
  • 简化:只调用 loadCustomTagOptions()(从 API 加载自定义标签选项)

12.3.3 FocusPersonnel.data.ts

  • majorTag/minorTag/customTag 列的 dataIndexmajorTag_dictText 改回 majorTag(不再依赖后端 DictAspect)

12.4 修改文件清单

序号 文件路径 修改内容
1 V20260604_6__migrate_tags_to_dictionary_item.sql 新增:在 DICTIONARY/DICTIONARY_ITEM 创建标签字典并迁移数据
2 FocusPersonnelServiceImpl.java 注入 DictionaryItemMapper;CRUD 改用 DICTIONARY_ITEM 表
3 FocusPersonnelMapper.java 移除 sys_dict_item 相关方法,保留 countPersonnelByCustomTag
4 FocusPersonnelMapper.xml 移除 sys_dict_item 相关 SQL
5 FocusPersonnelPageVo.java 移除 @Dict 注解和导入
6 FocusPersonnelDetailVo.java 移除 @Dict 注解和导入
7 FocusPersonnelList.vue 引入 useDict;替换搜索框;添加 bodyCell 插槽
8 FocusPersonnelDetail.vue 引入 useDict;移除 loadDictData/自定义 getDictText
9 FocusPersonnel.data.ts dataIndex 从 _dictText 改回原始字段名

12.5 注意事项

  1. 需执行 Flyway SQL:启动后端自动执行 V20260604_6 迁移脚本
  2. 需重启后端:Java 代码修改后需重新编译部署
  3. 需硬刷新前端:Ctrl+F5 清除旧缓存
  4. 自定义标签兼容focus_custom_tag 仍通过 listCustomTags/addCustomTagItem/deleteCustomTagItem API 管理,后端存储从 sys_dict_item 改为 DICTIONARY_ITEM

十三、清理旧字典数据(sys_dict / sys_dict_item)

修改日期:2026-06-04

13.1 修改说明

V20260604_6 仅迁移数据到 DICTIONARY/DICTIONARY_ITEM 表,未删除 sys_dictsys_dict_item 中的旧数据。新增 V20260604_7 脚本清理三个标签字典的旧记录。

13.2 修改文件清单

序号 文件路径 说明
1 V20260604_7__cleanup_old_sys_dict_tags.sql 新增:删除 sys_dict_item 和 sys_dict 中 focus_major_tag/focus_minor_tag/focus_custom_tag 的旧数据

13.3 SQL 执行逻辑

  1. 先删除 sys_dict_item 子表中三个字典的字典项(通过 dict_id 关联 sys_dict
  2. 再删除 sys_dict 主表中三个字典的字典记录
  3. 最终验证确保无剩余记录

13.4 注意事项

  1. 需在 V20260604_6 之后执行:必须先迁移数据再清理旧数据
  2. 执行方式:重启后端自动执行 Flyway,或手动运行此 SQL

十四、自定义标签增加编辑(重命名)功能

修改日期:2026-06-04

14.1 需求说明

自定义标签管理弹窗中,除了添加和删除,还需要支持编辑(重命名)已有标签。编辑标签时同步更新 focus_personnel 表中已绑定该标签的用户记录。

14.2 后端修改

14.2.1 IFocusPersonnelService.java

新增 updateCustomTagItem(String oldName, String newName) 接口方法。

14.2.2 FocusPersonnelServiceImpl.java

实现 updateCustomTagItem

  1. 校验参数(非空、新旧名称不同)
  2. 按旧名称查找 DICTIONARY_ITEM 记录
  3. 检查新名称是否已存在(防止重名)
  4. 更新 DICTIONARY_ITEMNameCode 字段
  5. 调用 baseMapper.updatePersonnelCustomTagName() 同步更新 focus_personnel 中已绑定的标签名

14.2.3 FocusPersonnelMapper.java

新增 updatePersonnelCustomTagName(@Param("oldName") String oldName, @Param("newName") String newName) 方法。

14.2.4 FocusPersonnelMapper.xml

新增 updatePersonnelCustomTagName SQL,使用 CASE WHEN 分段处理 4 种逗号分隔位置:

  • 完全匹配(只有一个标签)
  • 在开头
  • 在结尾
  • 在中间

使用 SUBSTR + INSTR 函数精确替换,避免误替换子串。

14.2.5 FocusPersonnelController.java

新增 PUT /updateCustomTagItem 端点,接收 oldNamenewName 参数。

14.3 前端修改

14.3.1 FocusPersonnel.api.ts

新增 updateCustomTagItem API 枚举和导出函数(defHttp.put)。

14.3.2 FocusPersonnelList.vue

  • 导入:新增 updateCustomTagItem 导入
  • 状态:新增 editingTagOldNameeditingTagNewName ref 变量
  • 方法
    • handleStartEdit(tagName):进入编辑模式
    • handleCancelEdit():取消编辑
    • handleSaveEdit():保存编辑,调用后端 API,更新本地列表
  • 模板:每条标签在查看模式显示"编辑"+"删除"按钮(hover 显示),点击编辑后切换为内联输入框+保存/取消按钮
  • 样式:新增 .tag-actions(按钮组容器)、.tag-edit-btn.tag-edit-input.tag-edit-actions 样式

14.4 修改文件清单

序号 文件路径 修改内容
1 IFocusPersonnelService.java 新增 updateCustomTagItem 接口方法
2 FocusPersonnelServiceImpl.java 实现 updateCustomTagItem(含重名校验 + 同步更新 focus_personnel)
3 FocusPersonnelMapper.java 新增 updatePersonnelCustomTagName 方法
4 FocusPersonnelMapper.xml 新增 updatePersonnelCustomTagName SQL(CASE WHEN 分段精确替换)
5 FocusPersonnelController.java 新增 PUT /updateCustomTagItem 端点
6 FocusPersonnel.api.ts 新增 updateCustomTagItem API
7 FocusPersonnelList.vue 弹窗标签列表添加编辑模式(内联输入+保存/取消)

14.5 注意事项

  1. 需重启后端:Java 代码修改后需重新编译部署
  2. 需硬刷新前端:Ctrl+F5 清除旧缓存
  3. 标签重名限制:新名称不能与已有标签重复
  4. 同步更新机制:重命名标签时,focus_personnel 表中已绑定该标签的用户记录会同步更新(逗号分隔值中的精确替换)

十五、自定义标签管理弹窗改为标准表格+分页

修改日期:2026-06-04

15.1 需求说明

自定义标签管理弹窗从简单的列表改为标准的表格样式,支持分页查询。因为自定义标签数量可能较多,分页表格更便于管理。

15.2 后端修改

15.2.1 IFocusPersonnelService.java

新增 IPage<DictionaryItem> queryCustomTagPage(IPage<DictionaryItem> page) 分页查询接口方法。

15.2.2 FocusPersonnelServiceImpl.java

实现 queryCustomTagPage:使用 DictionaryItemMapper.selectPage() 分页查询 focus_custom_tag 字典的已启用标签。

15.2.3 FocusPersonnelController.java

新增 GET /listCustomTagsPage?pageNo=1&pageSize=10 端点,返回分页的 DictionaryItem 数据。

15.3 前端修改

15.3.1 FocusPersonnel.api.ts

新增 listCustomTagsPage API 枚举和导出函数。

15.3.2 FocusPersonnelList.vue

  • 模板:自定义标签管理弹窗改为 <a-table> 表格+分页,包含三列:序号、标签名称、操作
  • 状态:新增 customTagLoadingcustomTagPageDatacustomTagPagination 表格相关状态
  • 方法
    • loadCustomTagPageData():分页加载标签数据
    • handleCustomTagTableChange(pagination):分页切换事件
    • closeCustomTagModal():关闭弹窗(取消编辑状态)
    • 增删改方法适配表格:操作后调用 loadCustomTagPageData() 刷新表格
  • 样式:移除旧列表样式(.tag-list-wrapper.tag-list-item 等),保留简洁的输入框间距

15.4 修改文件清单

序号 文件路径 修改内容
1 IFocusPersonnelService.java 新增 queryCustomTagPage 分页查询接口
2 FocusPersonnelServiceImpl.java 实现 queryCustomTagPage(DictionaryItemMapper.selectPage)
3 FocusPersonnelController.java 新增 GET /listCustomTagsPage 端点
4 FocusPersonnel.api.ts 新增 listCustomTagsPage API
5 FocusPersonnelList.vue 弹窗改为表格+分页,移除旧列表样式

15.5 注意事项

  1. 需重启后端:Java 代码修改后需重新编译部署
  2. 需硬刷新前端:Ctrl+F5 清除旧缓存
  3. listCustomTags 保留:非分页接口仍用于详情页下拉选择框的数据源

十六、服务跟进功能实现

修改日期:2026-06-04

16.1 需求说明

根据需求文档 3.9 节,实现服务跟进功能:

  1. 数据库表 focus_personnel_service_follow:记录服务内容、服务时间、服务人员、关联人员ID
  2. 后端 CRUD 接口
  3. 前端服务跟进记录弹窗(表格展示,支持新增/编辑/删除)
  4. 按钮权限 focus_personnel:serviceFollow(已在 V20260604_2 中定义)

16.2 数据库

Flyway SQL — V20260604_8__create_service_follow_table.sql

字段名 类型 说明
id VARCHAR(32) PK 主键(UUID)
focus_personnel_id VARCHAR(32) NOT NULL 关联重点关注人员ID
service_content TEXT 服务内容
service_time DATETIME 服务时间
service_provider VARCHAR(100) 服务人员
create_by / create_time VARCHAR(50) / DATETIME 创建人/时间
update_by / update_time VARCHAR(50) / DATETIME 更新人/时间
del_flag INT DEFAULT 0 删除标识

16.3 后端修改

序号 文件路径 说明
1 entity/FocusPersonnelServiceFollow.java 新增实体类(映射 focus_personnel_service_follow 表)
2 mapper/FocusPersonnelServiceFollowMapper.java 新增 Mapper 接口
3 service/IFocusPersonnelServiceFollowService.java 新增 Service 接口
4 service/impl/FocusPersonnelServiceFollowServiceImpl.java 新增 Service 实现
5 controller/FocusPersonnelServiceFollowController.java 新增 Controller(分页列表/添加/编辑/删除/批量删除/查询)

Controller 提供 6 个端点:

端点 方法 说明
/focusPersonnelServiceFollow/list GET 分页列表查询(按 focusPersonnelId 过滤,按 service_time 倒序)
/focusPersonnelServiceFollow/add POST 新增
/focusPersonnelServiceFollow/edit PUT/POST 编辑
/focusPersonnelServiceFollow/delete DELETE 删除
/focusPersonnelServiceFollow/deleteBatch DELETE 批量删除
/focusPersonnelServiceFollow/queryById GET 按 ID 查询

16.4 前端修改

序号 文件路径 说明
1 components/FocusPersonnelServiceFollowList.vue 新增:服务跟进记录弹窗组件(表格+分页,含新增/编辑/删除表单)
2 FocusPersonnel.api.ts 新增 4 个服务跟进 API 枚举和导出函数
3 FocusPersonnelList.vue 替换占位函数为实际弹窗逻辑;导入新组件;添加弹窗标签

16.5 功能交互流程

列表页 → 点击"服务跟进" → 弹窗显示该人员的所有服务跟进记录(表格+分页)
                                   ├── [新增服务记录] → 小弹窗(服务内容/服务时间/服务人员)
                                   ├── 每条记录 [编辑] → 小弹窗编辑
                                   └── 每条记录 [删除] → 确认后删除

16.6 注意事项

  1. 需执行 Flyway SQL:启动后端自动执行 V20260604_8 建表
  2. 需重启后端:Java 代码修改后需重新编译部署
  3. 需硬刷新前端:Ctrl+F5 清除旧缓存
  4. 按钮权限focus_personnel:serviceFollow 已在 V20260604_2 中定义,需要执行该 SQL 才会生效。若未执行,前端 v-auth 指令会隐藏操作按钮

十七、BUG修复(表不存在 + 序号错误 + 搜索下拉为空)

修改日期:2026-06-04

17.1 BUG1:服务跟进表不存在

错误现象

无效的表或视图名[FOCUS_PERSONNEL_SERVICE_FOLLOW]

原因V20260604_8__create_service_follow_table.sql 未被执行,数据库中不存在 focus_personnel_service_follow 表。

解决方案:手动执行以下建表 SQL:

CREATE TABLE IF NOT EXISTS focus_personnel_service_follow (
    id              VARCHAR(32)     NOT NULL,
    focus_personnel_id VARCHAR(32)  NOT NULL COMMENT '关联重点关注人员ID',
    service_content  TEXT           COMMENT '服务内容',
    service_time     DATETIME       COMMENT '服务时间',
    service_provider VARCHAR(100)   COMMENT '服务人员',
    create_by        VARCHAR(50)    COMMENT '创建人',
    create_time      DATETIME       COMMENT '创建时间',
    update_by        VARCHAR(50)    COMMENT '更新人',
    update_time      DATETIME       COMMENT '更新时间',
    del_flag         INT DEFAULT 0  COMMENT '删除标识(0-正常,1-已删除)',
    PRIMARY KEY (id)
);

17.2 BUG2:自定义标签表格序号错误

错误现象:自定义标签管理弹窗中序号列全部显示为 1

原因:序号计算使用了 record._index,但 MyBatis Plus 返回的分页数据中,a-tablebodyCell 插槽不会自动设置 _index 属性,导致 record._index 恒为 undefined,回退到 0,所以所有行序号都是 1

修复bodyCell 插槽使用 index 参数(Ant Design Vue 提供的行索引),替代 record._index

<template #bodyCell="{ column, text, record, index }">

UI 优化:表格添加 bordered 属性,增加边框视觉层次。

17.3 BUG3:搜索条件自定义标签下拉为空

错误现象:列表页搜索条件中的"自定义标签"下拉框没有任何选项。

原因:第 15 次迭代(自定义标签管理弹窗改为表格)中,移除了 customTagOptionsref 声明,但搜索条件的模板仍在使用 v-for="tag in customTagOptions"。由于 customTagOptions 未定义,下拉框始终为空。

修复:补回 const customTagOptions = ref<string[]>([]); 声明。

17.4 修改文件清单

序号 文件路径 修改内容
1 FocusPersonnelList.vue 补回 customTagOptions ref 声明;序号改用 bodyCell 的 index 参数;表格添加 bordered
2 V20260604_8__create_service_follow_table.sql 提供建表 SQL(需手动执行)

17.5 注意事项

  1. 建表 SQL 需手动执行:在数据库管理工具中运行 V20260604_8 的建表语句
  2. 需硬刷新前端:Ctrl+F5 使前端修复生效
  3. 自定义标签搜索下拉:数据从 DICTIONARY_ITEM 表通过 listCustomTags 接口获取,需确保 focus_custom_tag 字典项已存在于 DICTIONARY_ITEM

十八、服务跟进POST请求修复 + 自定义标签改为批量勾选添加

修改日期:2026-06-04

18.1 【BUG修复】服务跟进新增/编辑 API 请求方式错误

错误现象:点击"新增服务记录"或"编辑"后提交,后端接收不到数据。

原因addServiceFolloweditServiceFollow 使用了 params 参数发送 POST 请求,但后端 Controller 使用 @RequestBody 注解。params 在 axios 中会被转为 URL 查询参数,而不是请求体 JSON,导致后端无法解析。

修复:将 params 改为 data,使其以 Request Body 形式发送 JSON。

文件 修改内容
FocusPersonnel.api.ts addServiceFollow / editServiceFollowparamsdata

18.2 【功能改造】自定义标签按钮改为批量勾选添加标签

旧功能:点击"自定义标签"按钮打开标签管理弹窗(CRUD 表格,支持新增/编辑/删除标签字典项)。

新功能:先勾选表格中的数据行,点击"自定义标签"按钮打开弹窗,选择标签后批量添加到选中人员。

涉及的修改

后端

文件 修改内容
IFocusPersonnelService.java 新增 batchUpdateCustomTag(List<String> ids, List<String> tags)
FocusPersonnelServiceImpl.java 实现:遍历人员,用 HashSet 去重合并标签,String.join(",") 写入
FocusPersonnelController.java 新增 PUT /batchUpdateCustomTag,接收 { ids, tags } JSON

前端

文件 修改内容
FocusPersonnel.api.ts 新增 batchUpdateCustomTag API 枚举 + 导出函数
FocusPersonnelList.vue 移除旧标签管理弹窗(表格+CRUD);新增批量标签弹窗(checkbox 多选);handleCustomTag 改为检查选中行 + 打开批量弹窗

18.3 交互流程

列表页 → 勾选 N 条数据 → 点击"自定义标签"
  → 弹窗:已选择 N 条数据,请选择标签:
      ☑ 就业困难人员
      ☐ 脱贫人员
      ☐ 应届毕业生
      ...
  → [确定] → 调用 batchUpdateCustomTag → 刷新表格

18.4 注意事项

  1. 需重启后端:Service/Controller 代码修改后需重新编译部署
  2. 需硬刷新前端:Ctrl+F5 使前端修改生效
  3. 服务跟进:建表 SQL 需手动执行(见 17.1)

十九、自定义标签改为存字典值 + 服务跟进新增修复 + UI 优化

修改日期:2026-06-04

19.1 需求说明

  1. 自定义标签存储改造focus_personnel.custom_tag 字段不再直接存标签文本(如"就业困难人员"),改为存字典值(如 1,2,3),和大类小类标签保持一致
  2. 服务跟进新增修复:新增按钮因 v-auth 权限指令被隐藏,移除权限限制
  3. UI 优化:列表列显示标签 tag,批量弹窗用 checkbox 组

19.2 后端修改

文件 修改内容
IFocusPersonnelService.java listCustomTags() 返回类型 List<String>List<DictionaryItem>
FocusPersonnelServiceImpl.java listCustomTags() 直接返回 dictionaryItemMapper.selectList()batchUpdateCustomTag() 参数 tagstagValues,存储值而非文本
FocusPersonnelController.java listCustomTags 返回值 Result<List<String>>Result<List<DictionaryItem>>

19.3 前端修改

文件 修改内容
FocusPersonnelList.vue useDict 增加 focus_custom_tag;② customTagOptionsref<string[]> 改为 computed(() => getDictOptions('focus_custom_tag'));③ 新增 #bodyCell 对 customTag 列用 getDictText 翻译每个值并显示 <a-tag>;④ 搜索框改用 :options="customTagOptions";⑤ 批量弹窗 checkbox 用 tag.value/tag.label;⑥ 移除旧的 loadCustomTagOptions
FocusPersonnelDetail.vue useDict 增加 focus_custom_tag;② loadCustomTagOptions 改为映射 { label: tag.name, value: String(tag.value) };③ 自定义标签显示使用 getDictText('focus_custom_tag', tagVal) 翻译
FocusPersonnelServiceFollowList.vue ① 移除新增按钮的 v-auth 权限指令;② 序号修复:record._indexindex

19.4 存储格式变更说明

字段 旧格式 新格式
custom_tag "就业困难人员,脱贫人员" "1,3"
显示方式 直接显示文本 getDictText('focus_custom_tag', '1') → "就业困难人员"
搜索传值 传文本给后端 传字典值给后端

19.5 注意事项

  1. 需重启后端:Java 代码修改后需重新编译部署
  2. 需硬刷新前端:Ctrl+F5 使前端修改生效
  3. 已有数据兼容:数据库中已有的文本格式标签需要手动清理或通过 SQL 转换为字典值。如果 V20260604_6 已执行,focus_custom_tag 字典项已存在于 DICTIONARY_ITEM 表,可用以下 SQL 更新旧数据: sql -- 示例:将旧文本标签转为字典值(按需调整) UPDATE focus_personnel SET custom_tag = NULL WHERE custom_tag IS NOT NULL;

二十、BUG修复(Integer类型转换 + UI优化 + 权限排查)

修改日期:2026-06-04

20.1 BUG1:Integer cannot be cast to CharSequence

错误现象

class java.lang.Integer cannot be cast to class java.lang.CharSequence

在调用批量添加标签接口时抛出。

原因FocusPersonnelController.batchUpdateCustomTag 中直接将 request.get("tags") 强转为 List<String>getDictOptions('focus_custom_tag') 返回的 value 是 Integer 类型(来自 DICTIONARY_ITEM.Value),JSON 序列化后为数字。Jackson 反序列化为 List<Integer>,运行时强转 List<String> 失败。

修复

// 改为 List<?> 再通过 stream 转 String
List<?> rawTags = (List<?>) request.get("tags");
List<String> tags = rawTags.stream().map(Object::toString).collect(Collectors.toList());

20.2 BUG2:批量添加自定义标签 UI 优化

优化内容:

  • 头部改用 <em> 标签突出显示选中条数,增加灰色提示文字
  • 每个标签用 <a-tag> 包裹展示,选中时变蓝色高亮
  • 改用 flex 布局 + gap,标签流式排列
  • 增加 ant-empty 上下间距

20.3 BUG3:服务跟进新增按钮仍不显示

可能原因:

  1. sys_permission 表中缺少 focus_personnel:serviceFollow 权限记录(V20260604_2 第27-30行未执行)
  2. 角色 ID 与 SQL 中的 f6817f48af4fb3af11b9e8bf182f618b 不匹配
  3. 执行 SQL 后未重新登录,权限缓存未更新

20.4 修改文件清单

序号 文件路径 修改内容
1 FocusPersonnelController.java batchUpdateCustomTag 改用 List<?> + Object::toString 避免类型转换错误
2 FocusPersonnelList.vue 批量标签弹窗改用 a-tag 样式 + flex 布局美化

20.5 后续修复

修改日期 问题 文件 修复方式
2026-06-04 Integer 类型转换 FocusPersonnelController.java List<?> + stream().map(Object::toString)(需重启后端)
2026-06-04 服务跟进按钮不显示 FocusPersonnelServiceFollowList.vue 移除权限控制,按钮始终显示,由后端 @RequiresPermissions 保护接口

二十一、服务跟进按钮权限不显示——根因修复

修改日期:2026-06-04

21.1 根因分析

服务跟进新增按钮不显示的根本原因:sys_permission 表中5个按钮权限的 status 字段为 NULL

后端 SysPermissionController.getUserPermissionByToken() 的过滤条件:

.filter(item -> item.getMenuType() == 2 && item.getStatus() == 1)

status 为 NULL 不等于 1,所以 focus_personnel:serviceFollow 等权限码从未被返回到前端 permCodeList

前端无论使用 v-auth 指令还是 v-if + computed + usePermissionStore,都依赖 permCodeList 中包含对应权限码。permCodeList 为空,按钮自然不显示。

21.2 修复方案

1. 数据库修复:将 sys_permission 表中5个按钮权限的 status 从 NULL 更新为 1

UPDATE sys_permission
SET status = 1
WHERE perms IN (
    'focus_personnel:refresh',
    'focus_personnel:messagePush',
    'focus_personnel:jobPush',
    'focus_personnel:serviceFollow',
    'focus_personnel:customTag'
)
  AND (status IS NULL OR status != 1);

2. 源SQL修复V20260604_2 中5条 INSERT 语句的 status 字段从 NULL 改为 1,防止新环境部署时出现同样问题。

3. 前端权限判断FocusPersonnelServiceFollowList.vue 使用 v-if + computed + usePermissionStore 响应式判断权限,权限数据加载后自动更新显示。

21.3 修改文件清单

序号 文件路径 修改内容
1 V20260604_2__menu_insert_FocusPersonnel_buttons.sql 5条INSERT的status字段从NULL改为1
2 V20260604_9__fix_permission_status.sql 新增UPDATE修复SQL,修复已有数据
3 FocusPersonnelServiceFollowList.vue 按钮权限判断改为 v-if + computed + usePermissionStore

21.4 操作步骤

  1. 在数据库中执行 V20260604_9 的 UPDATE SQL
  2. 重新登录系统(权限数据在登录时加载并缓存)
  3. 验证服务跟进弹窗中"新增服务记录"按钮是否显示