diff --git a/docs/reports/implementation/2026-03-23-intermediary-person-subtype-relation-implementation.md b/docs/reports/implementation/2026-03-23-intermediary-person-subtype-relation-implementation.md new file mode 100644 index 00000000..c1e06be0 --- /dev/null +++ b/docs/reports/implementation/2026-03-23-intermediary-person-subtype-relation-implementation.md @@ -0,0 +1,53 @@ +# 个人中介中介子类型与关联关系调整实施记录 + +## 1. 改动概述 + +本次调整“信息维护-中介库管理-个人中介”录入与详情展示逻辑,目标如下: + +- 将个人中介表单中的“人员子类型”改为“中介子类型”。 +- “中介子类型”改为从关联关系选项中选择,并补充“个人”选项。 +- 隐藏个人中介表单中单独的“关联关系”字段,避免重复录入。 +- 详情弹窗中同步以“中介子类型”展示原关联关系语义,移除重复的“关系类型”展示。 + +## 2. 修改文件 + +- `ruoyi-ui/src/views/ccdiIntermediary/components/EditDialog.vue` +- `ruoyi-ui/src/views/ccdiIntermediary/components/DetailDialog.vue` +- `ruoyi-ui/tests/unit/intermediary-person-edit-ui.test.js` + +## 3. 实现说明 + +### 3.1 编辑弹窗 + +- 将个人中介表单字段标签由“人员子类型”调整为“中介子类型”。 +- 将原自由输入框改为下拉选择,数据源基于现有 `relationTypeOptions`,前端追加 `个人` 选项并做去重。 +- 新增 `handlePersonSubTypeChange` 与 `syncPersonSubTypeRelation`,确保隐藏 `relationType` 后,提交时 `personSubType` 与 `relationType` 保持一致。 +- 移除个人中介表单中单独展示的“关联关系”字段。 + +### 3.2 详情弹窗 + +- 将详情中的“人员子类型”展示调整为“中介子类型”。 +- 展示值优先取 `personSubType`,兼容回退到 `relationType`,避免存量数据为空时页面显示缺失。 +- 删除重复的“关系类型”展示项。 + +### 3.3 回归测试 + +- 新增源码级测试 `intermediary-person-edit-ui.test.js`,约束以下行为: + - 编辑弹窗必须展示“中介子类型”下拉。 + - 选项中必须包含“个人”。 + - 编辑弹窗不再单独展示“关联关系”字段。 + - 详情弹窗以“中介子类型”展示,不再单独展示“关系类型”。 + +## 4. 验证记录 + +执行命令: + +```bash +node /Users/wkc/Desktop/ccdi/ccdi/ruoyi-ui/tests/unit/intermediary-person-edit-ui.test.js +npm run build:prod +``` + +验证结果: + +- `node .../intermediary-person-edit-ui.test.js`:先红后绿,最终通过。 +- `npm run build:prod`:构建通过,仅存在项目原有的产物体积告警,无新增编译错误。 diff --git a/ruoyi-ui/src/views/ccdiIntermediary/components/DetailDialog.vue b/ruoyi-ui/src/views/ccdiIntermediary/components/DetailDialog.vue index 1c629548..85eaed5e 100644 --- a/ruoyi-ui/src/views/ccdiIntermediary/components/DetailDialog.vue +++ b/ruoyi-ui/src/views/ccdiIntermediary/components/DetailDialog.vue @@ -16,7 +16,7 @@ diff --git a/ruoyi-ui/src/views/ccdiIntermediary/components/EditDialog.vue b/ruoyi-ui/src/views/ccdiIntermediary/components/EditDialog.vue index 12ef11b9..df4a1a20 100644 --- a/ruoyi-ui/src/views/ccdiIntermediary/components/EditDialog.vue +++ b/ruoyi-ui/src/views/ccdiIntermediary/components/EditDialog.vue @@ -62,8 +62,21 @@ - - + + + + @@ -132,20 +145,6 @@ - - - - - - - - - { + if (!item || !item.value || existedValues.has(item.value)) { + return; + } + existedValues.add(item.value); + dedupedOptions.push(item); + }); + + return dedupedOptions; } }, watch: { @@ -446,6 +460,8 @@ export default { } this.shouldAnimate = false; } + + this.syncPersonSubTypeRelation(); }, /** @@ -454,6 +470,9 @@ export default { handleTypeSelect(type) { this.tempSelectedType = type; this.form.intermediaryType = type; + if (type === '1') { + this.syncPersonSubTypeRelation(); + } // 延迟设置 selectedType,使表单显示带动画效果 setTimeout(() => { this.selectedType = type; @@ -478,6 +497,10 @@ export default { return; } + if (this.form.intermediaryType === '1') { + this.syncPersonSubTypeRelation(); + } + // 根据类型验证不同的表单 const formRef = this.form.intermediaryType === '1' ? 'indivForm' : 'corpForm'; @@ -491,6 +514,19 @@ export default { }); }, + handlePersonSubTypeChange(value) { + this.form.relationType = value || null; + }, + + syncPersonSubTypeRelation() { + if (!this.form || this.form.intermediaryType !== '1') { + return; + } + const currentValue = this.form.personSubType || this.form.relationType || null; + this.form.personSubType = currentValue; + this.form.relationType = currentValue; + }, + /** * 滚动到第一个错误字段 */ diff --git a/ruoyi-ui/tests/unit/intermediary-person-edit-ui.test.js b/ruoyi-ui/tests/unit/intermediary-person-edit-ui.test.js new file mode 100644 index 00000000..18722733 --- /dev/null +++ b/ruoyi-ui/tests/unit/intermediary-person-edit-ui.test.js @@ -0,0 +1,55 @@ +const assert = require("assert"); +const fs = require("fs"); +const path = require("path"); + +const editDialogPath = path.resolve( + __dirname, + "../../src/views/ccdiIntermediary/components/EditDialog.vue" +); +const detailDialogPath = path.resolve( + __dirname, + "../../src/views/ccdiIntermediary/components/DetailDialog.vue" +); + +const editDialogSource = fs.readFileSync(editDialogPath, "utf8"); +const detailDialogSource = fs.readFileSync(detailDialogPath, "utf8"); + +[ + 'label="中介子类型"', + 'v-model="form.personSubType"', + 'v-for="item in personSubTypeOptions"', + "label: '个人'", + "handlePersonSubTypeChange" +].forEach((token) => { + assert( + editDialogSource.includes(token), + `个人中介编辑弹窗缺少中介子类型改造: ${token}` + ); +}); + +[ + 'label="关联关系"', + 'v-model="form.relationType" placeholder="请选择关联关系"' +].forEach((token) => { + assert( + !editDialogSource.includes(token), + `个人中介编辑弹窗不应继续单独展示关联关系字段: ${token}` + ); +}); + +[ + 'label="中介子类型"', + "detailData.personSubType || detailData.relationType || '-'" +].forEach((token) => { + assert( + detailDialogSource.includes(token), + `个人中介详情缺少中介子类型展示调整: ${token}` + ); +}); + +assert( + !detailDialogSource.includes('label="关系类型"'), + "个人中介详情不应继续展示单独的关系类型字段" +); + +console.log("intermediary-person-edit-ui test passed");