adapter.md 17 KB

Adapter

文档路径:apps/wisdom-legacy/docs/adapter.md(勿放在 src/ 下,避免 Vite 解析 .md 中的 import / SFC 语法)

adapter 是 wisdom-legacy 对 Vben 表单、VXE 表格、弹窗/抽屉的统一封装层。业务页面通常按 Grid 列表 + EditShell 编辑 组合开发。

views/xxx/
├── xxx.data.ts          # defineGrid + defineEditShell(声明式配置)
├── XxxList.vue          # useGridPage(列表页)
└── modules/XxxEdit.vue  # useEditShell(编辑表单)

目录

目录 职责
form/ Vben 表单封装:useVbenForm、校验规则、通用 schema 字段
vxe-table/ 表格页封装:defineGriduseGridPage、列助手、单元格渲染器、数据代理
shell/ Modal / Drawer 壳层:useShelldefineEditShelluseEditShell
antd/ Ant Design Vue 组件类型映射
setup.ts 应用启动时注册 form、vxe-table、antd 适配

初始化

在应用入口调用 adapter/setup.ts,依次完成 antd 组件注册、表单规则注册、VXE 表格与渲染器注册。

import initAdapter from '#/adapter/setup';

await initAdapter(app);

Form 表单

导出 API

import {
  useVbenForm, // 创建表单组件与 api
  defineStatusField, // 启用/禁用状态字段
  defineFormSchema, // 按 model 回填 defaultValue 的动态 schema
  z, // Zod 校验(re-export)
} from '#/adapter/form';

import type { VbenFormProps, VbenFormSchema } from '#/adapter/form';

useVbenForm

底层基于 @vben/common-uiuseVbenForm,并绑定项目内 Ant Design 组件类型。

const [Form, formApi] = useVbenForm({
  layout: 'vertical',
  showDefaultActions: false,
  schema: [
    {
      component: 'Input',
      fieldName: 'name',
      label: '名称',
      rules: 'required', // 内置规则
    },
    {
      component: 'Input',
      fieldName: 'phone',
      label: '手机号',
      rules: z.string().regex(/^\d{11}$/), // Zod schema
    },
  ],
  async handleSubmit(values) {
    // 提交逻辑
  },
});

模板中渲染 <Form />,通过 formApi 操作表单:

方法 说明
setValues(values, merge?, validate?) 回填表单
getValues() 获取当前值
validate() / validateAndSubmitForm() 校验 / 校验并提交
resetForm() 重置
setState({ schema }) 动态更新 schema

Schema 字段

每个 schema 项对应一个表单项,常用属性:

属性 说明
component 组件名,如 InputSelectApiTreeSelect
fieldName 字段路径,支持 department.id 点语法
label 标签
rules 'required''selectRequired'、Zod schema、或规则数组
defaultValue 默认值
hide / disabled 隐藏 / 禁用
dependencies 联动:ifrulestriggerFields
componentProps 传给底层组件的 props
formItemClass / wrapperClass 布局 class
renderComponentContent 自定义组件插槽内容(如 Checkbox 文案)

条件显示示例:

{
  component: 'InputPassword',
  fieldName: 'password',
  label: '密码',
  dependencies: {
    if: (values) => !values.id,       // 仅新增时显示
    triggerFields: ['id'],
  },
}

自定义插槽:<Form> 内用 #fieldName 覆盖默认渲染(见下方 EditShell 示例)。

内置规则

form/setup.ts 注册了项目级规则:

  • required — 非空字符串
  • selectRequired — 选择类非空

配合 z(Zod)可直接使用 API schema 字段:

import { UserVOSchema } from '#/api/system';

rules: UserVOSchema.shape.name,

defineStatusField

生成统一的启用/禁用单选字段:

defineStatusField(); // 默认 true
defineStatusField(false); // 默认 false

defineFormSchema

将静态 schema 包装为函数,按打开时的 model 为已有字段补充 defaultValue

const schema = defineFormSchema<UserVO>([
  { component: 'Input', fieldName: 'name', label: '姓名' },
]);

// useEditShell / useVbenForm 中:schema(model) 按行数据回填默认值

独立表单(非列表编辑)

不经过 useEditShell 时,可直接 useVbenForm 自建页面或弹窗:

const [Form, formApi] = useVbenForm({
  schema: [...],
  handleSubmit: async (values) => { /* ... */ },
});

Grid 表格页

导出 API

import {
  defineGrid,
  useGridPage,
  editModal,
  editDrawer,
  editShell,
  defineTagRender,
} from '#/adapter/vxe-table';

defineGrid — 声明列表配置

*.data.ts 中集中定义查询字段、列、数据源:

import { defineGrid } from '#/adapter/vxe-table';
import { listDepartmentMethod } from '#/api/system';

export const departmentGrid = defineGrid<DepartmentVO>({
  scope: 'system.department', // 解析 tableTitle、createText
  query: listDepartmentMethod, // alova 分页查询 Method 工厂
  tree: true, // 树表(或传入 TreePreset 对象)
  fields: [
    // 搜索区 schema(复用 form schema 结构)
    { component: 'Input', fieldName: 'name', label: '名称' },
  ],
  columns: (col) => [
    // 列定义,col 为列助手
    col.seq({ width: 140, treeNode: true }),
    { field: 'name', title: '名称', minWidth: 120 },
    ...col.audit(), // 审计字段列组
    col.status({ confirm: true }), // 状态开关列
    col.actions(['edit', 'delete'], 180),
  ],
});

GridDefinition 主要字段

字段 说明
scope i18n 前缀,生成「xxx列表」「新增 xxx」文案
query (page, size, query?) => Method,返回 { items, total }
fields 搜索表单 schema,静态数组或 (model) => schema[]
columns 列配置,静态数组或 (col) => columns[]
tree true{ parentField, indent, trigger }
checkbox 多选列配置
pager 分页,false 关闭
toolbar 工具栏配置
form 搜索区 VbenForm 额外选项
features { selection, batch, treeExpand }
events VXE grid 事件监听
options.overrides 透传 gridOptions 覆盖项

列助手 col

columns: (col) => [...] 回调中使用:

方法 说明
col.seq(options?) 序号列
col.checkbox(options?) 多选列
col.status({ confirm? }) 状态 Switch 列,触发 status handler
col.audit(visible?) 创建/更新审计列组
col.action(code, options?) 单列操作按钮
col.actions(codes, width?) 操作列,'edit' / 'delete'{ code, text }

自定义单元格渲染:

import { defineTagRender } from '#/adapter/vxe-table';

cellRender: defineTagRender([
  { label: '目录', value: 'catalog', color: 'blue' },
  { label: '菜单', value: 'menu', color: 'green' },
]),

slots: { default: 'title' } 时,在 <Grid> 内用同名插槽渲染。

useGridPage — 组装列表页

// XxxList.vue — script setup
import { editModal, useGridPage } from '#/adapter/vxe-table';
import {
  deleteDepartmentMethod,
  editDepartmentStatusMethod,
} from '#/api/system';
import { departmentGrid } from './department.data';
import DepartmentEdit from './modules/DepartmentEdit.vue';

const { Grid, Edit, scope, actions, tree } = useGridPage(departmentGrid, {
  edit: editModal(DepartmentEdit),
  append: true,
  delete: deleteDepartmentMethod,
  status: editDepartmentStatusMethod,
});
<!-- XxxList.vue — template -->
<Edit />
<Grid>
  <template #toolbar-tools>
    <a-button type="primary" @click="actions.create()">
      {{ scope.createText }}
    </a-button>
  </template>
</Grid>

返回值

属性 说明
Grid 表格组件(含搜索区)
Edit 编辑壳层组件(edit handler 存在时)
scope { key, tableTitle, createText }
actions 页面动作 API
grid VXE 底层 api(querysetState 等)
tree 树表展开/收起 { toggle, loading }
selection / batch 多选与批量操作(开启 checkbox 时)

actions API

方法 说明
actions.create() 打开新增编辑(edit handler,status: true
actions.edit(row?) 打开编辑
actions.append(row) 新增下级(append: true 时)
actions.run(code, row) 触发行操作(与列 code 对应)
actions.has(code) 是否注册了该 handler

PageHandlers — 第二参数

handler 的 key 与列操作 code、内置能力对应:

Handler 类型 说明
edit Component / editModal(comp) / editDrawer(comp) / RowHandler 编辑弹窗/抽屉
delete MethodInput 删除,(row) => deleteMethod(row)
status MethodInput 状态切换
append true / RowHandler 树表新增下级
batch BatchHandlers 批量操作
events GridEvents 表格事件
自定义 code RowHandler / MethodInput col.action('code') 对应

MethodInput: 直接传 alova Method 工厂,框架自动调用并处理刷新:

delete: deleteUserMethod,  // (row) => Method

RowHandler: 完全自定义,返回刷新指令:

rest: ({ row }) => {
  passwordApi.setData(row).open();
  return undefined;  // 不刷新
},

HandlerResult — 控制列表刷新:

返回值 行为
true grid.query() 全量刷新
false / undefined 不刷新
{ reload: true } true
{ reload: { id: 'xxx' } } 带参数局部刷新

编辑壳层关闭时,若 close 载荷含 id != nulledit handler 自动返回 true 触发刷新。

编辑壳层配置

// 简写:默认 modal
edit: DepartmentEdit,

// 推荐:显式壳层类型
edit: editModal(DepartmentEdit),
edit: editDrawer(RoleEdit),

// 完整配置
edit: editShell({
  type: 'drawer',
  connectedComponent: MenuEdit,
  defaultRow: { status: true },
  class: 'w-full max-w-200',
}),

标题由编辑组件内 defineEditShellscope / title 在打开时自动设置,列表侧无需重复传 title


Shell 编辑(Form + Grid 联动)

编辑流程将 Form schemaModal/Drawer 壳层alova 提交 串联为 defineEditShell + useEditShell

defineEditShell — 声明编辑配置

defineGrid 对称,放在 *.data.ts

import { defineEditShell } from '#/adapter/shell/edit';
import { defineStatusField } from '#/adapter/form';

export const departmentForm = defineEditShell<DepartmentVO>({
  scope: 'system.department',
  submit: editDepartmentMethod,
  shell: 'modal',
  prepare(data) {
    if (data.pid === '0') delete data.pid;
    return data;
  },
  load: getRoleMenuMethod,
  shouldLoad: (data) => !!data.id,
  form: { wrapperClass: 'grid-cols-2' },
  schema: [
    { component: 'Input', fieldName: 'name', label: '名称', rules: 'required' },
    defineStatusField(),
  ],
});

常用配置

字段 说明
submit alova 提交 Method 工厂
shell 壳层类型与选项(load/confirm 由框架托管)
schema 表单字段,静态数组或 (model) => schema[]
prepare 打开时整理行数据
load 详情加载 Method
shouldLoad 是否执行 load,默认有 id 时加载
shouldTitle 是否更新标题,默认 true
transform 提交成功后 close 载荷变换,默认补齐刷新 id
config alova useForm 额外配置

transform 与列表刷新: 后端编辑接口常返回 null。默认 transform 会补充占位 id,使 grid 在关闭后触发 query()。自定义:

transform: (data) => ({ id: data }),
transform: false,

useEditShell — 编辑组件

// modules/DepartmentEdit.vue — script setup
import { useEditShell } from '#/adapter/shell';
import { departmentForm } from '../department.data';

const { Form, Shell, api } = useEditShell(departmentForm);
<!-- modules/DepartmentEdit.vue — template -->
<Shell>
  <form class="mx-4" />
  <template #prepend-footer>
    <a-button type="primary" danger @click="api.reset()">重置</a-button>
  </template>
</Shell>

与 Grid 的双层壳层

列表页 useGridPage 外层:useShell(type, { connectedComponent: XxxEdit })
编辑组件内层:useEditShelluseShell(无 connectedComponent

Vben 通过 provide/inject 将内外层合并为同一个 Modal/Drawer。子组件的 Shell 只负责挂载表单与 footer 插槽,不要在模板传 title / class(由 defineEditShellloadsetState 管理)。

api 方法

方法 说明
api.open(data?) 独立使用时打开并注入数据
api.submit() 校验并提交
api.reset() 重置表单并同步 alova 上下文
api.close(payload?) 关闭壳层
api.form Vben 表单 api
api.shell 壳层 api

生命周期 handlers

useEditShell(definition, {
  onOpened(model) {},
  handleLoad(model) {},
  onLoaded(model) {},
  handleSubmit(value) {},
  onSuccess(data) {},
  onClosed() {},
});

自定义 schema 插槽

<form>
  <template #menuIds="slotProps">
    <Tree v-bind="slotProps" :tree-data="tree" multiple />
  </template>
</form>

独立 Shell(非 Grid 编辑)

参考用户列表的「重置密码」:

import { useShell } from '#/adapter/shell';

const [Password, passwordApi] = useShell('modal', {
  title: '重置密码',
  connectedComponent: UserPassword,
});

标准 CRUD 页面清单

  1. API 层 — alova Method 工厂:listXxxMethodeditXxxMethoddeleteXxxMethod
  2. xxx.data.tsdefineGrid + defineEditShell,共用类型与 schema 规则
  3. modules/XxxEdit.vueuseEditShell(xxxForm),按需加插槽与 footer
  4. XxxList.vueuseGridPage(xxxGrid, { edit, delete, status, ... }),渲染 <Edit /> + <Grid />

文件对照(系统模块)

列表定义 编辑定义 列表页 编辑组件
departmentGrid departmentForm DepartmentList.vue DepartmentEdit.vue
userGrid userForm UserList.vue UserEdit.vue
roleGrid roleForm RoleList.vue RoleEdit.vue
menuGrid menuForm MenuList.vue MenuEdit.vue

数据流

用户点击「编辑」
  → useGridPage.openEditor(row)
  → 外层 Shell.open(row)
  → 内层 useEditShell.load
      → prepare(row)
      → [可选] load API 合并详情
      → setValues + 更新标题
  → 用户确认
  → validateAndSubmitForm → alova send
  → transform(响应) → close(载荷)
  → grid 检测 id → query() 刷新

进阶

树表

defineGrid({ tree: true }) + col.seq({ treeNode: true }) + handler append: true

自定义列插槽

columns 中声明 slots: { default: 'title' }<Grid #title="{ row }"> 渲染。

渲染器扩展

vxe-table/renderer/ 提供 defineCellRendererdefineOperationRender 等,在 vxe-table/setup.ts 注册。业务列通过 defineTagRenderdefineSwitchRender 使用。

代理层

底层查询走 defineGridProxyuseGrid 内部使用),将 alova Method 绑定到 VXE proxyConfig.ajax。一般业务只需在 defineGrid 上传入 query Method 工厂。


导入路径速查

// 表单
import { useVbenForm, defineStatusField, z } from '#/adapter/form';

// 表格页
import {
  defineGrid,
  useGridPage,
  editModal,
  editDrawer,
} from '#/adapter/vxe-table';

// 编辑壳层
import { useEditShell } from '#/adapter/shell';
import { defineEditShell } from '#/adapter/shell/edit';