# Array / Object 字段类型 —— 设计草案(暂未实现) > 状态:**搁置待需求**。当前没有字段需要它(powers 已用自定义类型 `powers` 解决,dropList 用自定义 type + Mixed 解决)。 > 等出现「既要结构化数组/对象、又要框架级递归校验 + 自动表单渲染」的真实字段时,再按本文档实现。 ## 背景:为什么有这份文档 ### 触发点:powers 字段类型错误 角色权限字段 `powers` 实际存的是权限 key 数组(`string[]`),但 `roleFields` 里错标成 `type: "string"`。在「字段前置验证」(`ShrimpTableModule.validateField`)加上类型校验后,String 分支 `typeof value !== 'string'` 把数组判为类型错误。 ### 已采用的解法(v0.6.2,已上线) 把 powers 改成自定义类型 `type: "powers"`。原理:`validateField` 的类型校验是 switch-case,只认 string/number/boolean/date 四个内置类型,**任何自定义 type 不匹配任何 case → 自动跳过类型校验**;且未注册 typeHandler → 无 reqFilter/resFilter → 数组原样存取,不破坏前端权限树。required/rules 仍生效。 这是最小解,powers 问题已闭环。**本文档的 array/object 不是为 powers——powers 不需要它**。 ## 何时才该实现本设计 满足以下条件之一再做,否则属于过度设计: - 出现一个字段,值是**结构化数组**(如 `[{itemId,count,weight}]`),且希望**框架级递归校验** + **自动按子字段渲染表单**(而非像 dropList 那样手写专属前端组件 + 跳过校验)。 - 多个字段重复出现「对象数组」形态,自定义类型方案的手写成本变得不划算。 判别:需求会把"要不要去重 / 要不要嵌套 / 摘要怎么显示"这些问题自然定下来,比现在凭空猜更准。 ## 设计要点(实现时参考) ### 与 multiple 的关系(关键,A 方案) `multiple` 与 `array` 是**两个正交维度,不合并**: - `multiple`:**选择基数修饰符**,依附 select/relation,含义"从固定候选集里选几个",**集合语义(不可重复)**。保持现状不动。 - `array`:**值形态类型**,开放列表,元素类型由 `item` 定,可嵌套。 - 判别标准:值来自**固定选项集**→ select/relation + multiple;值是**开放列表**→ array。 ### 后端 shrimp-server **1. `IShrimpType.ts`** ```ts // ShrimpFieldTypes 增加 Array: "array", Object: "object" // IFieldConfig 增加(复用 IFieldConfig 自身递归 —— tab 的 tabs[].fields 已有先例) item?: IFieldConfig // array 元素的类型定义 fields?: IFieldConfig[] // object 的子字段定义 unique?: boolean // array 是否去重(集合语义,默认 false) ``` **2. `ShrimpTableModule.validateField` 递归校验** - `array` 分支:值必须是数组 → 对每个元素递归 `validateField(field.item, 元素, item)`;`unique:true` 查重报错;min/max 已支持数组长度。 - `object` 分支:值必须是对象 → 对 `field.fields` 每个子字段递归 `validateField(子字段, value[子key], value)`。 - **multiple 特殊处理**:`multiple:true` 字段值是数组,但元素校验走字段自己的 options/relation;在类型 switch 里 multiple 字段**跳过标量类型检查**(防止 powers 那类问题复发)。 **3. typeHandler** - array/object **不注册 resFilter**(不同于 json 会 `JSON.stringify`)——结构原样进出,前端直接拿到结构化数据。 ### 前端 shrimp-admin 字段渲染机制:约定式自动注册 —— `components/fields/Field.vue` → 自动注册类型 ``(首字母小写)。`vueAdmin.getFieldComponent(moduleKey, type, key)` 按 type 取组件,未知 type 兜底为 string。**范本见 `FieldTab.vue`**:用 `getFieldComponent(childField.type)` 递归渲染子字段。 **1. `components/fields/FieldArray.vue`(新)** 类型 `array` - edit:列表渲染,每项 `getFieldComponent(field.item.type)` 递归 + 增/删行。 - display:摘要(JSON 截断,或「N 项」)。 - props 标准接口:`{field, modelValue, mode:'display'|'edit'|'filter', disabled}`。 **2. `components/fields/FieldObject.vue`(新)** 类型 `object` - edit:按 `field.fields` 逐个 `el-form-item` + 递归组件(≈ FieldTab 去掉 tab 选择层)。 - display:摘要。 **递归天然支持嵌套**:array 的 `item` 可以是 `{type:"object",fields:[...]}`(对象数组),object 的某字段可以是 `{type:"array",...}`,任意层级。 ### powers 若迁移到 array(可选,非必须) `{ key:"powers", type:"array", item:{type:"string"}, unique:true }`(集合去重)。但 powers 现用 `"powers"` 自定义类型已工作,**无强需求迁移**。 ## 发版 实现并前后端验证(后端 `tsc --noEmit`、前端 `vue-tsc`/build)通过后,shrimp-server + shrimp-admin 一起升 **0.7.0**,业务项目引用同步更新。 ## 关联 - 另一个已知待办:`field.validate`(字段级自定义验证函数,`IFieldConfig.validate`)在 `IShrimpType.ts` 定义了,但 `prepareAddItem`/`prepareEditItem` 只调了 `handler.validate`(typeHandler 级),**`field.validate` 从未被调用** —— 漏接,待补。