根据"需求与现有实现对比分析",实施P0优先级任务:
| 序号 | 文件路径 | 说明 |
|---|---|---|
| 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页签+概要头部) |
| 序号 | 文件路径 | 修改内容 |
|---|---|---|
| 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 |
| 字典编码 | 字典名称 | 字典项数 | 说明 |
|---|---|---|---|
focus_major_tag |
人员大类标签 | 2 | 就业困难人员、脱贫人员 |
focus_minor_tag |
人员小类标签 | 16 | 就业困难13类 + 脱贫3类 |
| 权限标识 | 名称 | 状态 |
|---|---|---|
| focus_personnel:refresh | 刷新生成 | 占位 |
| focus_personnel:messagePush | 消息推送 | 占位 |
| focus_personnel:jobPush | 岗位推送 | 占位 |
| focus_personnel:serviceFollow | 服务跟进 | 占位 |
| focus_personnel:customTag | 自定义标签 | 占位 |
在 V20260604_3 中更新 v_focus_personnel_list,添加了:
birthDate 字段(来自personal_info)age 计算字段(达梦兼容使用 FLOOR(MONTHS_BETWEEN(CURRENT_DATE, pi.birth_date) / 12))姓名、性别、学历、户口所在地、现居住地、年龄(范围)、大类标签、小类标签、自定义标签、就业状态
刷新生成、导出
FLOOR(MONTHS_BETWEEN(CURRENT_DATE, pi.birth_date) / 12)),达梦兼容根据用户需求:
focus_personnel 表中提取去重)| 序号 | 文件路径 | 修改内容 |
|---|---|---|
| 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 |
GET /focusPersonnel/listCustomTags 获取所有标签focus_personnel 表提取 custom_tag 字段,拆分逗号分隔值、去重、排序[刷新生成] [自定义标签] [推送消息] [导出]
a-row justify="space-between" 实现左右分布v-auth 权限控制/focusPersonnel/edit 接口更新数据| 接口 | 方法 | 说明 |
|---|---|---|
/focusPersonnel/listCustomTags |
GET | 获取所有自定义标签(去重排序后的列表) |
/focusPersonnel/edit |
PUT/POST | 保存自定义标签(通过 id + customTag 字段) |
focus_personnel.custom_tag 字段提取(已有数据的逗号分隔值)。新添加的标签若只在管理弹窗中添加而未分配给任何人,页面刷新后会消失(因为没有持久化到任何人的记录中)focus_personnel:customTag 和 focus_personnel:messagePush 已在 V20260604_2 SQL 中定义,需要执行该脚本才能生效customTag = '选中值' 的精确匹配方式查询(而非之前的 LIKE 模糊匹配)。如果希望模糊搜索,需要在后端 XML 中修改为 LIKE 查询/focusPersonnel/edit 接口,只更新 id 和 customTag 字段,不影响其他字段根据用户反馈:
focus_personnel 表中 major_tag/minor_tag 存储的是文本值(如"就业困难人员"),不是字典code,应该关联字典使用数字codefocus_custom_tagv-auth 权限未配置未显示(V20260604_2 SQL 未执行)| 序号 | 文件路径 | 说明 |
|---|---|---|
| 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 执行后再加回) |
| item_value(code) | item_text(显示) |
|---|---|
| 1 | 就业困难人员 |
| 2 | 脱贫人员 |
| item_value(code) | item_text(显示) | 类别 |
|---|---|---|
| 1 | 大龄失业人员 | 就业困难 |
| 2 | 残疾人员 | 就业困难 |
| 3 | 享受最低生活保障待遇人员 | 就业困难 |
| 4 | 城镇零就业家庭人员 | 就业困难 |
| 5 | 农村零转移就业原建档立卡贫困家庭人员 | 就业困难 |
| 6 | 失地农民 | 就业困难 |
| 7 | 连续失业1年以上人员 | 就业困难 |
| 8 | 戒毒康复人员 | 就业困难 |
| 9 | 刑满释放人员 | 就业困难 |
| 10 | 精神障碍康复人员 | 就业困难 |
| 11 | 失业6个月以上退役军人 | 就业困难 |
| 12 | 需赡养患重病直系亲属的人员 | 就业困难 |
| 13 | 省人民政府规定的其他人员 | 就业困难 |
| 14 | 脱贫不稳定户 | 脱贫人员 |
| 15 | 边缘易致贫户 | 脱贫人员 |
| 16 | 突发严重困难户 | 脱贫人员 |
| item_value | item_text | 说明 |
|---|---|---|
| 标签文本 | 标签文本 | item_value = item_text(标签本身就是值) |
已存在的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和数据。
v-auth 指令,所有用户均可看到v-auth 指令v-auth 权限控制focus_personnel 表中的 major_tag 和 minor_tag 数据(文本→code),建议执行前备份v_focus_personnel_list 是视图,数据迁移后自动返回code值,无需重建focus_custom_tag 的 item_value = item_text,@Dict 注解翻译后和原值一致根据用户反馈:
majorTag/minorTag 显示字典翻译后的文本dictCode 客户端翻译| 序号 | 文件路径 | 修改内容 |
|---|---|---|
| 1 | FocusPersonnelMapper.xml |
重构 listCustomTags 从 sys_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 /addCustomTagItem 和 DELETE /deleteCustomTagItem 端点 |
| 6 | FocusPersonnelDetailVo.java |
majorTag 和 minorTag 添加 @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 导入 |
管理员操作(列表页):
点击"自定义标签"按钮 → 弹窗展示 focus_custom_tag 字典所有项
→ 输入名称点击"添加" → 调用 POST /addCustomTagItem → 持久化到 sys_dict_item
→ 点击"删除" → 调用 DELETE /deleteCustomTagItem → 从字典删除
用户操作(详情页):
点击"编辑" → 显示 <a-select mode="multiple"> 多选下拉
→ 只能从已有字典项中选择 → 不能输入新标签
→ 点击"保存" → 调用 POST /focusPersonnel/edit 更新 custom_tag 字段
| 接口 | 方法 | 说明 |
|---|---|---|
/focusPersonnel/addCustomTagItem |
POST | 添加自定义标签字典项(参数:itemText) |
/focusPersonnel/deleteCustomTagItem |
DELETE | 删除自定义标签字典项(参数:itemValue) |
FocusPersonnelDetailVo 和 FocusPersonnelPageVo 的 majorTag/minorTag 都加了 @Dict 注解majorTag_dictText/minorTag_dictText/customTag_dictText 等翻译字段getDictText 函数优先使用 _dictText 后缀字段,兜底返回原始值dictCode: 'focus_major_tag' 等,由 BasicTable 客户端自动翻译@Dict 或前端 dictCode 翻译错误现象:
Required request parameter 'itemText' for method parameter type String is not present
原因:前端 defHttp.post({ url, params }) 中 params 在 POST 请求中被当作请求体(body)发送,而不是 URL 查询参数,而后端使用 @RequestParam 只能从查询参数或表单中读取。
修复:
FocusPersonnelController.java:@PostMapping 改为 @GetMappingparams 在 GET 请求中会自动作为 URL 查询参数)错误现象:字典code重构(V20260604_5)后,数据存储为数字code(如 1),但前端未正确翻译。
原因:
getDictText 函数依赖后端 _dictText 字段(DictAspect可能未拦截自定义方法)dictCode 翻译依赖字典缓存,如果用户登录后字典才创建/修改,缓存未更新修复:
initDictOptions 从 /sys/dict/getDictItems/{dictCode} 加载字典数据,构建 Map<item_value, item_text> 查询映射,getDictText 函数直接查映射onMounted 中预加载三个字典(focus_major_tag、focus_minor_tag、focus_custom_tag),确保 BasicTable 翻译生效| 序号 | 文件路径 | 修改内容 |
|---|---|---|
| 1 | FocusPersonnelController.java |
addCustomTagItem 方法改为 @GetMapping |
| 2 | FocusPersonnelDetail.vue |
导入 initDictOptions;loadDictData 加载大类小类字典构建查询映射;getDictText 函数改为查映射 |
| 3 | FocusPersonnelList.vue |
导入 initDictOptions;onMounted 中预加载三个字典 |
| 问题 | 错误原因 | 修复内容 |
|---|---|---|
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(兼容多种字段名) |
initDictOptions 首次调用会从服务器拉取并缓存。如果字典在用户登录后被修改,需要刷新页面或重新登录清除缓存api.ts 和 Detail.vue 修改后需重启前端 dev server 或硬刷新(Ctrl+F5)列表页和详情页的人员大类标签、人员小类标签、自定义标签都显示数字(如 1、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.getAllDictItems 或 authCache),如果用户在字典被修改(V20260604_5 SQL)之前已登录,缓存中就是旧的字典数据(value='就业困难人员' 而非 value='1'),导致翻译查找失败。
文件:FocusPersonnel.data.ts
将 majorTag、minorTag、customTag 列的 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
ajaxGetDictItems(从 /@/utils/dict/index)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');
| 序号 | 文件路径 | 修改内容 |
|---|---|---|
| 1 | FocusPersonnel.data.ts |
majorTag/minorTag/customTag 列的 dataIndex 改为 majorTag_dictText/minorTag_dictText/customTag_dictText,移除 dictCode |
| 2 | FocusPersonnelDetail.vue |
导入 ajaxGetDictItems;loadDictData 中使用 ajaxGetDictItems 替代 initDictOptions 加载大类小类字典 |
| 3 | FocusPersonnel.api.ts |
deleteCustomTagItem 增加 { joinParamsToUrl: true } 选项,修复 DELETE 请求参数未传递到 URL 查询参数的问题 |
错误现象:
Required request parameter 'itemValue' for method parameter type String is not present
原因:defHttp.delete 默认将 params 放在请求体(body)中发送,而后端 @RequestParam 只能从 URL 查询参数中读取。deleteOne 已有 { joinParamsToUrl: true } 正确处理,但 deleteCustomTagItem 未添加此选项。
修复:在 FocusPersonnel.api.ts 的 deleteCustomTagItem 函数中增加 { joinParamsToUrl: true } 选项。
需求变更:删除自定义标签时,如果有用户绑定了该标签,应禁止删除并给出提示,而不是自动清理。
原因:后端 deleteCustomTagItem 需要先检查 focus_personnel 表中是否有用户使用了该标签。
修复(4个文件修改):
FocusPersonnelMapper.java — 移除 removeCustomTagFromPersonnel,新增 countPersonnelByCustomTag 方法FocusPersonnelMapper.xml — 移除清理 UPDATE SQL,新增 countPersonnelByCustomTag SELECT SQL,使用 4 种 LIKE 条件精确匹配逗号分隔值中的标签(完全匹配、开头、结尾、中间)FocusPersonnelServiceImpl.java — deleteCustomTagItem 先检查绑定用户数,大于 0 则返回 falseFocusPersonnelController.java — 处理 Service 返回结果,若不可删除则返回 Result.error("该标签已被用户绑定,无法删除")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 |
错误提示显示后端消息 |
FocusPersonnelPageVo 添加 @Dict 注解