# 关联配置体验重构 ## 问题诊断 | 问题 | 根因 | 影响 | |------|------|------| | 引用对象选择器出现重复选项 | `businessObjectList({})` 返回同一 objectCode 的多条记录(跨套件),未做去重 | 用户困惑 | | 引用对象选择器没法搜索 | 属性面板已有 `filterable`,但运行时 n-select 未启用远程搜索 | 大量选项时难以定位 | | 主子表关系配置太复杂 | 14+ 字段全部平铺在一个 3 列网格中,无渐进式展示 | 用户不知如何配置 | | 子表选择器报"缺少业务对象编码" | 关系配置中的 `recordSelector.objectCode` 未正确透传到运行时子表表单字段 | 选择器无法打开 | ## 设计理念 参考飞书多维表格的关联字段设计: - **最少操作**:用户只需选择目标对象 + 关系类型,其余自动推断 - **统一入口**:字段属性面板中合并为"关联配置"区域,通过"选择方式"切换下拉/弹窗 - **渐进展示**:核心配置(目标对象)第一屏展示,高级配置(字段映射、筛选)折叠隐藏 - **即时反馈**:选择目标对象后立即自动推断显示字段、值字段、搜索字段 --- ## Task 1: 修复 objectReference 选项重复 + 远程搜索 **目标**:解决引用对象选择器中的重复选项和搜索体验问题 **文件修改**: - `forge-admin-ui/src/views/app-center/components/designer/BusinessFieldPropertyPanel.vue` - `loadBusinessObjectOptions` 函数增加 `objectCode` 去重 - `forge-admin-ui/src/views/app-center/components/designer/forge-form-designer/ForgePropertyPanel.vue` - 同样的 `loadBusinessObjectOptions` 去重 - `forge-admin-ui/src/views/app-center/components/designer/BusinessRelationDesigner.vue` - `loadBusinessObjects` 函数按 objectCode 去重 - `forge-admin-ui/src/components/ai-form/AiFormItem.vue` - objectReference 运行时 n-select 增加 `remote` + `on-search` 支持远程关键词搜索 **关键逻辑**: ```javascript // 去重逻辑 const seen = new Set() businessObjectOptions.value = list .filter(item => { if (seen.has(item.objectCode)) return false seen.add(item.objectCode) return true }) .map(item => ({ ... })) ``` --- ## Task 2: 统一字段属性面板"关联配置"入口 **目标**:将 objectReference 和 recordSelector 两种配置合并为一个"关联配置"区域 **文件修改**: - `forge-admin-ui/src/views/app-center/components/designer/BusinessFieldPropertyPanel.vue` **UI 改造**: ``` ┌─ 关联配置 ────────────────────────────────────┐ │ 选择方式: ○ 下拉选择 ○ 弹窗选择器 │ │ │ │ 目标对象: [选择业务对象 ▾] (filterable) │ │ │ │ ─── 自动推断结果(只读提示)─── │ │ 显示字段: name (自动推断) [可修改] │ │ 值字段: id (默认) [可修改] │ │ │ │ ▸ 高级配置 │ │ └ 搜索字段 / 字段映射 / 过滤参数 ... │ └────────────────────────────────────────────────┘ ``` **自动推断规则**(选择目标对象后自动填充): 1. 显示字段:优先找 name/title 字段 2. 值字段:默认 id 3. 搜索字段:name + code 类字段 4. 当切换"选择方式"时自动迁移已有配置 --- ## Task 3: 重构 BusinessRelationDesigner 为极简向导 **目标**:将 14 字段密集表单改为 2 步极简配置 + 折叠高级选项 **文件修改**: - `forge-admin-ui/src/views/app-center/components/designer/BusinessRelationDesigner.vue` **新 UI 结构**: ``` ┌─ 关系卡片(折叠后只看标题行)──────────────────┐ │ ▾ 采购入库单 → 拥有多条 → 入库明细 │ │ │ │ 关系类型: [拥有多条目标记录 ▾] │ │ 目标对象: [入库明细 ▾] │ │ ── 自动推断(可覆盖)── │ │ 匹配方式: id = purchaseOrderId (自动推断) │ │ 显示字段: productName (自动推断) │ │ │ │ ▸ 显示选项(详情页签/新增编辑内嵌/排序) │ │ ▸ 子表选择器(启用/候选对象/映射/筛选) │ │ ▸ 高级设置(保存模式/默认筛选/说明) │ └────────────────────────────────────────────────┘ ``` **改造要点**: 1. 将 3 列 grid 改为自然流式布局(1-2列为主) 2. "自动推断"结果作为只读默认值呈现,旁边有"修改"按钮展开 select 3. 子表选择器配置折叠在 `n-collapse` 中,展开后保持当前的可视化映射 UI 4. 向导弹窗只保留:关系类型 + 目标对象,确认后自动推断所有字段 --- ## Task 4: 修复 recordSelector objectCode 透传 **目标**:解决点击选择按钮时提示"选择器缺少业务对象编码" **根因分析**: 1. 字段属性面板配置 `form.recordSelectorObjectCode` 2. 保存时写入字段的 `recordSelector.objectCode` 配置 3. 运行时经过 `formDesignerSchema.js` 的 `buildComponentProps` 透传 4. 到 `AiFormItem.vue` 的 `normalizeRecordSelectorConfig` 解析 **断点定位**:在 `buildComponentProps` 中,已有透传逻辑: ```javascript if (field.recordSelector || field.props?.recordSelector) props.recordSelector = field.recordSelector || field.props?.recordSelector ``` 但问题是当配置来自字段属性面板时,`objectCode` 可能保存在 `field.basicProps.recordSelector.objectCode` 或单独的 `field.recordSelectorObjectCode` 中。 **修复方案**: - `formDesignerSchema.js` 的 `buildComponentProps` 中增加兜底:当 `field.recordSelectorObjectCode` 存在时,合成 `recordSelector` 配置对象 - `BusinessFieldPropertyPanel.vue` 的 `normalizePayload` 确保将散落的 recordSelector 字段合并为完整的 `recordSelector` 对象保存 **文件修改**: - `forge-admin-ui/src/views/app-center/components/designer/form-first/formDesignerSchema.js` - `forge-admin-ui/src/views/app-center/components/designer/BusinessFieldPropertyPanel.vue` --- ## Task 5: objectReference 运行时远程搜索 **目标**:当选项数量 > 20 时自动启用远程搜索 **文件修改**: - `forge-admin-ui/src/components/ai-form/AiFormItem.vue` **改造**: ```javascript // objectReference n-select 增加 remote 属性 @search="handleObjectReferenceSearch" @update:value="handleUpdate" /> ``` 在 `buildObjectReferenceOptionSource` 中增加 keyword 支持: ```javascript params: { objectCode: config.objectCode, keyword: searchKeyword, // 动态传入 displayFields: [...], keywordFields: [config.labelField], } ``` --- ## Task 6: ESLint 检查 + 构建验证 在所有修改完成后: 1. `npx eslint` 检查修改的文件 2. `pnpm build` 确保编译通过 3. 手动列出核心变更清单供用户验证 --- ## 实施顺序 1. Task 1 (去重 + 基础修复) → 立即可见效果 2. Task 4 (objectCode 透传修复) → 修复阻塞性 bug 3. Task 5 (远程搜索) → 提升运行时体验 4. Task 2 (统一入口) → UX 重构 5. Task 3 (极简向导) → UX 重构 6. Task 6 (验证) → 质量保障