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 @@
{{ detailData.personType || '-' }}
- {{ detailData.personSubType || '-' }}
+ {{ detailData.personSubType || detailData.relationType || '-' }}
男
女
@@ -30,7 +30,6 @@
{{ detailData.company || '-' }}
{{ detailData.position || '-' }}
{{ detailData.socialCreditCode || '-' }}
- {{ detailData.relationType || '-' }}
{{ detailData.relatedNumId || '-' }}
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");