@shaonq/vue

shaonq Vue Library
3,356
Install
npm install @shaonq/vue
Latest Version:1.6.1
Vue:3
License:MIT
Last Updated:Sep 23, 2026
Links: npm
Maintainer: shaonq

@shaonq/vue

Vue 3 组件库:OrcTable(vxe-table 封装)、OrcForm(配置驱动动态表单)、OrcSearch(搜索栏)。

ColBuilder 配置构建器

ColBuilder 用于以最少的代码构建 orc-table 列配置(OrcTableItem)与 orc-form 表单项配置(OrcFormItem),消除 type/model/name 与深层嵌套(OrcFormTable / OrcFormLayer)的样板代码。

import { ColBuilder } from '@shaonq/vue';

表格列(orc-table / orc-search)

方法 签名 说明
tableItem (dataIndex, title?, overrides?) 通用列。overrides.dataType 自动附带默认列宽
tableItemStatus (dataIndex, title, texts?, size?, overrides?) 状态标签列(Tag 渲染),texts 为 { value, label, color }[]
ColBuilder.tableItem('name', '姓名', { dataType: 'string' });
ColBuilder.tableItem('amount', '金额', { dataType: 'number', align: 'right' });
ColBuilder.tableItem('other'); // 占位操作列

ColBuilder.tableItemStatus('status', '状态', [
  { value: '1', label: '启用', color: 'green' },
  { value: (v) => !v, label: '空', color: 'gray' }, // value 支持函数
]);

表单项(orc-form config)

方法 签名 说明
formItem (model, name?, overrides?) 通用表单项。overrides.props 与 componentAttr 合并透传组件属性
formTable (model, name, columns, opts?) 子表格(OrcFormTable)。columns 为列配置(继续用 formItem)
formLayer (model, name, tableOptions, opts?) 弹窗选行(OrcFormLayer)。tableOptions 为表格配置,columns 用 tableItem
// 基础表单项
ColBuilder.formItem('name', '姓名', { type: 'a-input', options: { required: true } });
ColBuilder.formItem('role', '角色', {
  type: 'a-select',
  options: { required: true },
  defaultValue: '1',
  props: { allowClear: true },
  events: { onMounted: () => [{ label: '管理员', value: '1' }] }, // 异步选项
});

// 子表格(OrcFormTable):列配置用 formItem
ColBuilder.formTable(
  'list',
  '不合格明细',
  [
    ColBuilder.formItem('F_BadId', '不合格原因', { type: 'a-select' }),
    ColBuilder.formItem('F_Qty', '数量', { type: 'a-input-number' }),
    ColBuilder.formItem('other'),
  ],
  {
    span: 24, // 栅格宽度
    required: true, // 表单项必填
    defaultValue: [], // 缺省 []
    height: 200, // 表格高度
    hideTools: false,
    tableOptions: { rules: { F_Qty: [{ type: 'number', min: 10, message: '数量必须≥10' }] } }, // 行编辑校验
  }
);

// 弹窗选行(OrcFormLayer):表格配置用 OrcTableOption,列用 tableItem
ColBuilder.formLayer(
  'holiday',
  '选择假期',
  {
    selectedType: 'radio',
    scrollX: { enabled: true },
    scrollY: { enabled: true },
    columns: [ColBuilder.tableItem('date', '日期', { dataType: 'date' }), ColBuilder.tableItem('name', '假日名称', { dataType: 'string' })],
  },
  {
    span: 24,
    required: true,
    pagination: true,
    nameKey: 'name', // 回显字段,缺省 'name'
    tableData: [], // 静态数据(不走接口时)
  }
);

输出结构(等价手写配置)

  • formTable → { type: OrcFormTable, model, name, options: { span, required }, defaultValue: [] , componentAttr: { ...剩余项, options: columns } }
  • formLayer → { type: OrcFormLayer, model, name, options: { span, required }, componentAttr: { ...剩余项, options: tableOptions } }
  • formItem → 字段分发:options/defaultValue/events 保持原结构,props 与 componentAttr 合并到 componentAttr

注意(formTable / formLayer):

  • 字段级 events.onChange 对 OrcFormTable 不生效(子表格不 emit change 事件)。行内联动请写在列配置的 events.onChange 上(参数为 [value, { rowIndex, row }])
  • OrcFormLayer 的 events.onChange 参数是 { name, data } 对象而非新值(与普通字段不同),联动建议直接用 util.getModel(...)
  • componentAttr 中的函数属性(如 disabled)每次渲染执行两次,请保持为纯函数(无请求/计数副作用)

OrcTable 树形表格

orc-table 继承 vxe-table,通过 option.treeConfig 与列的 treeNode 开启树形结构(treeConfig 即 vxe 的 tree-config)。

配置 类型 说明
option.treeConfig object { transform: true, rowField: 'id', parentField: 'parentId' } 等原生配置
option.checkStrictly boolean 复选框关闭父子联动
columns[].treeNode boolean 标记展开图标所在列
<orc-table
  :data="list"
  :option="{
    rowKey: 'id',
    treeConfig: { transform: true, rowField: 'id', parentField: 'parentId', expandAll: true },
    columns: [
      { dataIndex: 'name', title: '名称', treeNode: true, width: 260 },
      { dataIndex: 'amount', title: '金额', width: 120, align: 'right' },
    ],
  }"
/>
  • transform: true 时传扁平数据(含 parentId),由 vxe 自动转成树;根节点 parentId 置空
  • transform: false 时传嵌套数据(children)
  • rowKey 需与 treeConfig.rowField 一致
  • option.tableProps 优先级最高,会覆盖 treeConfig

OrcForm 替换 a-form 使用指南

OrcForm 内部就是 a-form + a-row + a-col + a-form-item 的封装,把「模板 + v-model + rules」改写成「一个 config 数组」。数据绑定、校验、提交、禁用、联动全部由配置驱动,模板只剩一行。

1. 对比示例

a-form 写法(模板 20 行)

<a-form ref="formRef" :model="formData" :rules="rules" :label-col-props="{ flex: '110px' }" label-align="right" size="small">
  <a-row :gutter="8">
    <a-col :span="12">
      <a-form-item field="name" label="姓名" :rules="[{ required: true, message: '请输入姓名' }]">
        <a-input v-model="formData.name" placeholder="请输入姓名" allow-clear />
      </a-form-item>
    </a-col>
    <a-col :span="12">
      <a-form-item field="role" label="角色">
        <a-select v-model="formData.role" :options="roleOptions" placeholder="请选择角色" allow-search />
      </a-form-item>
    </a-col>
  </a-row>
  <a-form-item>
    <a-button type="primary" html-type="submit">提交</a-button>
  </a-form-item>
</a-form>

orc-form 等价写法(config 一份 + 模板一行)

import { OrcForm, ColBuilder } from '@shaonq/vue';
import type { OrcFormItem } from '@shaonq/vue';

const roleOptions = [
  { label: '管理员', value: '1' },
  { label: '用户', value: '2' },
];

const config: OrcFormItem[] = [
  ColBuilder.formItem('name', '姓名', {
    type: 'a-input',
    options: { required: true }, // 自动生成必填规则 + 红星
    props: { allowClear: true }, // 组件属性透传(等价 v-bind)
  }),
  ColBuilder.formItem('role', '角色', {
    type: 'a-select',
    defaultValue: '1',
    props: { options: roleOptions, allowSearch: true }, // 组件属性(含数据源)
  }),
];
<orc-form v-model="formData" :config="config" @submit="onSubmit" />

2. 属性映射表

a-form 写法 orc-form 写法
:model="formData" + 每个控件 v-model v-model="formData" 整体绑定,控件 v-model 自动完成
整表 :rules="rules" 每个字段 options.required 或字段级 rules
:label-col-props="{ flex: '110px' }" label-width="110px"
label-align="right" label-align="right"(默认 right)
size="small" 固定 small,不需要写
<a-row :gutter="8"> :gutter="8"(默认 8)
<a-col :span="12"> 字段 options.span: 12(或组件级 :span 全局默认)
<a-form-item field="xxx"> 字段 model: 'xxx'
<a-form-item label="xxx"> 字段 name: 'xxx'
<a-form-item :disabled> 字段 options.disabled 或组件 :disabled
<a-form-item :help> 字段 options.help
<a-form-item :tooltip> 字段 options.tooltip
<a-form-item :validate-trigger> 字段 validateTrigger
<a-form-item :label-col-flex> 字段 itemAttr: { labelColFlex: ... }
控件 placeholder 字段 options.placeholder,不写自动「请输入 / 请选择」
控件其余 props 字段 componentAttr(ColBuilder 中写 props 同义)
自定义提交按钮 组件自带「保存」按钮(hide-submit 可隐藏,#row 插槽可替换)
@submit(需 ev.preventDefault()) @submit="({ data, utils }) => ...",校验通过才触发,无需 preventDefault

3. 校验

// 必填:options.required 自动生成 [{ required: true, message: '请输入/请选择xxx' }]
{ type: 'a-input', model: 'name', name: '姓名', options: { required: true } }

// 自定义规则:字段级 rules(支持 Arco 全部规则,或返回规则数组的函数)
{
  type: 'a-input-number', model: 'qty', name: '数量',
  rules: [{ type: 'number', min: 10, max: 100, message: '数量必须在 10 ~ 100 之间' }],
}

// 触发时机
{ type: 'a-input', model: 'code', name: '编码', validateTrigger: 'blur' }

提交时自动校验全部字段;未通过则触发 @error 且不触发 @submit。也可用 ref 手动校验:

const formRef = ref(); // <orc-form ref="formRef" />
const [err, data] = await formRef.value.onSubmit(); // err 为空表示通过

4. 提交与重置

function onSubmit({ data, utils }: OrcFormSubmit) {
  utils.setLoading(true); // 保存按钮转圈
  try {
    await saveApi(data); // data 为校验通过后的表单数据
    utils.resetFields(); // 重置字段(或调 ref.onReset())
    Message.success('保存成功');
  } finally {
    utils.setLoading(false);
  }
}
  • utils.setLoading(true/false) — 保存按钮 loading
  • utils.resetFields() — 清空字段
  • ref 方法:formRef.value.onSubmit()(校验+提交)、onReset()(恢复 defaultValue)、resetFields()(清空)
  • 弹窗模式(OrcFormButton)额外有 utils.setVisible(true/false)

5. 动态交互(替换原来的 watch / 手动赋值)

需求 a-form 做法 orc-form 做法
下拉选项异步加载 onMounted 请求后赋值 字段 events.onMounted: () => options数组
字段联动显示/隐藏 v-if + watch 手动控制 events.onChange 里 util.setShow(model, bool)
字段联动赋值 手动 formData.xxx = ... util.setModel('xxx', val) 或 util.setModel({a: 1})
读取字段值 formData.xxx util.getModel('xxx') / util.getModels()
动态切换下拉选项 手动改 roleOptions util.setModelOption('role', newOptions)
控件属性随状态变化 computed props componentAttr: { disabled: (util) => util.getModel('type') === 'readonly' }
值变化监听 @change 逐个绑定 字段 events.onChange: (val, util) => ...
// 联动示例:切换「类型」后,动态显示/隐藏字段并重新加载选项
ColBuilder.formItem('type', '类型', {
  type: 'a-select',
  options: { required: true },
  events: {
    onMounted: () => [{ label: 'A', value: 'a' }, { label: 'B', value: 'b' }],
    onChange(val, util) {
      util.setShow('code', val === 'a'); // 显示/隐藏
      util.setModelOption('role', val === 'a' ? [{ label: 'x', value: '1' }] : []); // 切换选项
    },
  },
}),

6. 常用字段速查

ColBuilder.formItem('name', '姓名', { type: 'a-input' }); // 文本框
ColBuilder.formItem('remark', '备注', { type: 'a-textarea', props: { maxLength: 200, showWordLimit: true } });
ColBuilder.formItem('qty', '数量', { type: 'a-input-number', props: { min: 0, max: 100 } });
ColBuilder.formItem('date', '日期', { type: 'a-date-picker' });
ColBuilder.formItem('datetime', '时间', { type: 'a-date-picker', props: { showTime: true } });
ColBuilder.formItem('switch', '启用', { type: 'a-switch', defaultValue: true });
ColBuilder.formItem('role', '角色', { type: 'a-select', props: { options: roleOptions, allowSearch: true } });
ColBuilder.formItem('sex', '性别', {
  type: 'a-radio-group',
  defaultValue: 'male',
  props: {
    options: [
      { label: '男', value: 'male' },
      { label: '女', value: 'female' },
    ],
  },
});
ColBuilder.formItem('dept', '部门', { type: 'a-tree-select', props: { treeData: [], allowSearch: true } });

7. 复杂字段(替代自定义封装)

场景 用法
子表格(行内编辑) ColBuilder.formTable(model, name, 列config, opts) — 见上文 ColBuilder 章节
弹窗选行(TablePicker 类) ColBuilder.formLayer(model, name, tableOptions, opts) — 见上文 ColBuilder 章节
自定义组件 type: 组件对象(如 defineAsyncComponent),自动注入 modelValue / update:modelValue / utils 实现 v-model
覆盖默认控件渲染 插槽 <template #model名="{ value, setValue, options, utils }">

字典类下拉(字典数据经 events.onMounted 异步加载选项,配合 util.setModelOption 可动态刷新):

// config 中:挂载时加载字典选项
{
  type: 'a-select', model: 'status', name: '状态',
  events: {
    onMounted: async (util) => {
      const list = await fetchDict('order-status'); // 自行实现字典请求
      util.setModelOption('status', list);
    },
  },
}

8. 弹窗表单(替换 a-modal + a-form + 按钮)

<orc-form-button title="新增用户" :config="config" @submit="onSubmit">
  <a-button>新增</a-button>
</orc-form-button>
// @submit 回调:校验通过后触发,utils 额外支持 setVisible
function onSubmit({ data, utils }: OrcFormSubmit) {
  utils.setLoading(true);
  await saveApi(data);
  utils.setLoading(false);
  utils.setVisible(false); // 关闭弹窗
}

常用 props:title(弹窗标题)、config、modelValue(回显数据)、labelWidth、disabled、isView(只读展示模式)、buttonAttrs(按钮属性)、modalAttrs(弹窗属性)、span/gutter。

9. 常见坑

  • 字段 options.span 缺省继承组件 :span(默认 24 即整行);想一行放多个字段记得配 span
  • componentAttr 中函数属性(如 disabled)在渲染时执行,入参 util,可做跨字段联动;保持纯函数(每次渲染执行两次,勿放请求/计数副作用)
  • 非字符串 type(自定义组件)会自动绑定 v-model,不要重复传 modelValue
  • 不要给 type 传 'a-form'/'a-form-item' 这类容器组件,容器由 OrcForm 统一管理
  • hide-submit 隐藏保存按钮后,仍可用 ref.onSubmit() 触发校验提交
  • 子表格行内联动:在列配置的 events.onChange 中 setModel 修改整行数据时,组件随后会基于旧数据回写当前列,可能覆盖联动结果。推荐写法:
// 行内联动(子表格列配置):先拿到当前行,改完后整体 setModel 刷新
ColBuilder.formItem('adjust', '调整金额', {
  type: 'a-input-number',
  events: {
    onChange([val, { rowIndex, row }], util) {
      const list = util.getModel('tableData'); // 从表单模型取整表
      list[rowIndex] = { ...row, adjust: val, status: val > 3000 ? '待审核' : '已确认' };
      util.setModel('tableData', [...list]); // 整体覆盖,避免组件旧数据回写覆盖
    },
  },
}),

本地命令

lerna clean    # 从所有包中删除 node_modules
lerna publish  # 发布
lerna link     # 关联包,模拟发布后的效果
lerna ls       # 查看本地包列表

Version History

Version Released Vue License
1.6.1 ^3.5.34 MIT
1.6.0 ^3.5.34 MIT
1.5.3 ^3.5.34 MIT
1.5.2 ^3.5.34 MIT
1.5.1 ^3.5.34 MIT
Pre-releases (1)
Version Released Vue License
1.0.7-0 ^3.2.34 MIT