vebai-loom

Core toolkit for Vue 3 admin apps: axios-based HTTP with request dedupe and caching, login/menu permissions and dynamic routes, list handlers, plus a render-agnostic dynamic-form engine. No UI component library dependency.
Install
npm install vebai-loom
Latest Version:2.0.0
Vue:3
License:MIT
Last Updated:Oct 12, 2026
Links: Gitee  ·  npm
Maintainer: vebai

vebai-loom

vebai-loom 是一套面向 Vue 3 中后台的可复用前端内核,把中后台项目里最重复、也最容易写散的部分收敛成四块能力:http、permission、handler、dynamic-form。

它要解决的不是「少写几行代码」,而是三类反复出现的问题:接口请求的重复处理与登录态联动、权限与动态路由散落在各处、列表和表单逻辑在业务组件里越堆越厚。内核把这些逻辑收到统一入口,并且不绑定任何 UI 组件库:它只产出数据和描述符,渲染交给使用方自己的组件。

  • http:基于 axios 的请求内核,内建防重复请求、短期缓存、上传下载、token 刷新与统一错误处理。
  • permission:登录态校验、动态菜单与路由生成、路由守卫,支持 role / operate / menu / menuAndOperate 四种权限模式。
  • handler:列表查询内核,覆盖分页、排序、多选、增删改、导出、筛选与路由 query 同步。
  • dynamic-form:框架无关的表单描述符引擎,把 schema 编译成与渲染无关的描述符,支持校验规则、字段联动与描述符缓存。

内核不直接依赖具体实现,而是通过 Notifier、ConfirmService、SessionAdapter、Logger、Translator、ControlRegistry、TableFilterAdapter、RouteAdapter 等注入接口访问外部能力:http / permission / handler 保留 Vue 3 + vue-router,dynamic-form 完全框架无关。

变更明细见 CHANGELOG.md。

目录

设计原则

  1. 零 UI 组件库依赖:src/ 内不出现 ant-design-vue / element-plus 等 UI 组件库,package.json 也不声明它们。所有渲染都由使用方实现。

  2. 注入接口:内核不直接依赖具体实现,而是通过接口访问外部能力:

    接口 作用
    Notifier 消息提示(success / error / warning / info)
    ConfirmService 确认框、结果弹窗
    SessionAdapter 登录态:token、authType、用户信息、菜单、路由
    Logger / Translator 日志与文案
    ControlRegistry 动态表单控件注册表(type → 组件)
    TableFilterAdapter 表格筛选下拉渲染
    RouteAdapter 路由读写(让 handler 可脱离组件运行)
  3. 分层:

    • http / permission / handler 保留 Vue3 + vue-router。
    • dynamic-form 为纯 TS 引擎,只输出描述符。

目录结构

src/
  setup.ts       统一注入入口(setupVbCore / resetVbCore)
  core-deps.ts   应用级依赖容器(CoreDeps)
  shared/        通用工具、本地存储、文案表(business.ts 为业务辅助入口)
  interfaces/    注入接口(notifier / confirm / session / logger / translator / control / table-filter / route)
  types/         框架无关类型
  http/          请求内核
  permission/    权限内核(permission.ts + routes.ts 纯函数)
  handler/       列表内核
  dynamic-form/  表单描述符引擎(descriptor / engine / rules)
  route/         路由适配器(vue / memory)
test/            纯函数单测(node:test)
scripts/         测试与构建辅助脚本
examples/        antd / element-plus 适配器写法示例(不参与构建、不导出、不声明依赖)
dist/            构建产物(npm 发布内容,仓库中不跟踪)

依赖要求

入口 需要安装
vebai-loom/dynamic-form axios、ts-md5
vebai-loom/http axios、ts-md5
vebai-loom/permission axios、ts-md5、vue、vue-router
vebai-loom/handler axios、ts-md5、vue、vue-router

vue / vue-router 为 optional peer:只用 dynamic-form 时不会被强制安装;使用 permission / handler 时请自行安装。

安装与引入

npm install vebai-loom

使用 permission / handler 时还需要:

npm install vue vue-router

包入口指向构建产物 dist,并提供以下子路径:

vebai-loom/http  vebai-loom/permission  vebai-loom/handler  vebai-loom/dynamic-form
vebai-loom/interfaces  vebai-loom/route  vebai-loom/shared  vebai-loom/shared/business
import { DynamicForm, createHttp, Handler } from 'vebai-loom';
import { createControlRegistry } from 'vebai-loom/interfaces';
import { createVueRouteAdapter } from 'vebai-loom/route';

本地开发也可以直接依赖该包:

{
  "dependencies": {
    "vebai-loom": "file:../vebai-loom"
  }
}

快速接入

推荐用统一入口 setupVbCore() 注入一次,它会登记应用级依赖、配置 http、注册 handler 默认依赖,并可顺带创建 permission。

import { setupVbCore } from 'vebai-loom';

// 项目启动时注入一次
const core = setupVbCore({
  deps: {
    session: mySessionAdapter,
    notifier: myNotifier,
    confirm: myConfirm,          // handler 需要
    tableFilter: myTableFilter,  // handler 需要
    logger: myLogger,            // 可选,默认 console
    translator: myTranslator     // 可选,默认内置中文
  },
  http: {
    baseURL: import.meta.env.VITE_BASE_URL,
    timeout: 30000,
    repeatRequestTime: 1000,
    cacheSize: 200,
    logout: () => core.permission?.logout()   // 可选
  },
  permission: permissionConfig,  // 可选:传入即创建(内部会立即请求登录状态)
  controls: myControlRegistry    // 可选:供动态表单渲染器读取
});

// 挂到应用
app.use(core.permission!.router);

之后各处直接取用,不再重复传全局依赖:

import { createHttp, Handler, createVueRouteAdapter } from 'vebai-loom';

const http = createHttp();   // 已由 setupVbCore 配好

// 列表页 setup:只传组件级的 route(不传则走 useRoute/useRouter)
const handler = Handler.build(
  { queryApi: { url: '/api/user/page', method: 'get' }, page: true },
  { route: createVueRouteAdapter() }
);

创建权限后:

  • 已登录 → 拉取菜单、生成路由、跳到目标页或首页。
  • 未登录 → 跳 loginPath。

多后台 / 多环境 / 单测仍可用独立实例:

import { createHttpClient, createRequestConfig } from 'vebai-loom';
const other = createHttpClient(createRequestConfig({ session, notifier, name: 'other', baseURL: '/other' }));

注入接口实现

Notifier

import type { Notifier } from 'vebai-loom/interfaces';

export const myNotifier: Notifier = {
  success: (msg) => { /* toast success */ },
  error: (msg) => { /* toast error */ },
  warning: (msg) => { /* toast warning */ },
  info: (msg) => { /* toast info */ }
};

包内提供 silentNotifier(静默实现)用于测试。

ConfirmService

import type { ConfirmService } from 'vebai-loom/interfaces';

export const myConfirm: ConfirmService = {
  confirm: async (option) => {
    // option: { title?, content?, confirmText?, cancelText?, width? }
    return true; // 用户确认返回 true
  },
  alert: async (option) => { /* 仅提示,无取消 */ }
};

包内提供 passthroughConfirmService(confirm 恒为 true)作占位。

SessionAdapter

import type { SessionAdapter } from 'vebai-loom/interfaces';

export const mySession: SessionAdapter = {
  getToken: () => token,
  setToken: (t) => { token = t; },
  getAuthType: () => authType,
  setAuthType: (v) => { authType = v; },
  getInfo: () => userInfo,
  setInfo: (v) => { userInfo = v; },
  getRoutes: () => routes,
  setRoutes: (v) => { routes = v; },
  getMenus: () => menus,
  setMenus: (v) => { menus = v; },
  destroy: () => { /* 清空登录态 */ },
  setCurrRoute: (route) => { /* 可选:记录当前路由 */ }
};

ControlRegistry

import { createControlRegistry } from 'vebai-loom/interfaces';

export const controls = createControlRegistry({
  input: { component: MyInput },
  select: { component: MySelect, props: { clearable: true } }
});

TableFilterAdapter

枚举标签组件(Tag)

BizEnumHelper 把枚举值渲染成状态标签;标签组件由使用方注入,默认是纯 span。

import { BizEnumHelper } from 'vebai-loom';

// ant-design-vue 的 Tag、Element Plus 的 ElTag,或自有组件
BizEnumHelper.setTag(Tag);

// 也可以放进统一入口,启动时注册一次
setupVbCore({ deps: { /* ... */ }, tag: Tag });

getTag(value) 会把枚举项里除 label / value 之外的字段(如 color、disabled)作为 props 传给标签组件;getTag(value, false) 只输出纯文本。旧写法 setTagNode(createVNode(Tag)) 仍可用,内部取 VNode 的组件类型。

import type { TableFilterAdapter } from 'vebai-loom/interfaces';

export const myTableFilter: TableFilterAdapter = {
  buildFilter(kind, ctx) {
    // kind: 'text' | 'number' | 'date'
    // ctx: { handler, column?, name? }
    return { filterIcon: () => null, filterDropdown: (opt) => null };
  },
  buildSelectFilter(filters, ctx, option, multiple, ignoreType) {
    return { /* 同上,返回表格框架能识别的筛选属性 */ };
  }
};

包内提供 noopTableFilterAdapter 作空实现。

Logger

import type { Logger } from 'vebai-loom/interfaces';

export const myLogger: Logger = {
  log: (...args) => console.log(...args),
  warn: (...args) => console.warn(...args),
  error: (...args) => console.error(...args)
};

包内提供 consoleLogger(默认)与 silentLogger;http / permission 可通过 logger 注入。

Translator

import type { Translator } from 'vebai-loom/interfaces';

export const myTranslator: Translator = {
  t: (key, params) => i18n.t(key, params)
};

包内提供 createTranslator(catalog) 与内置中文表 zhCNMessages(默认 defaultTranslator)。http / permission 可通过 translator 注入;buildFormItemRules(title, type, rules, translator?) 也支持。

RouteAdapter

import type { RouteAdapter } from 'vebai-loom/interfaces';

const adapter: RouteAdapter = {
  getQuery: () => ({}),
  pushQuery: (query) => {},
  replaceQuery: (query) => {},   // 可选;提供时优先使用
  watchQuery: (cb) => {}         // 可选
};

包内提供两个实现:

  • createVueRouteAdapter():基于 useRoute/useRouter,需在组件 setup 内调用。
  • createMemoryRouteAdapter(initial?):纯内存实现,用于单测与组件外。

HTTP 请求

基本用法

import { createHttp, createHttpClient, createRequestConfig, httpRequest } from 'vebai-loom';

// 默认实例(使用 setDefaultRequestConfig 配置)
const http = createHttp();
await http.get('/api/user/list', { pageNo: 1 });
await http.post('/api/user/save', { name: '张三' });
await http.put('/api/user/save', payload);   // put / delete / head / patch 均已支持
await http.request('delete', '/api/user/remove', { id: 1 });

// 简写(GET/HEAD 拼 query,POST/PUT/PATCH/DELETE 带 body,带防重复与短期缓存)
const list = await httpRequest('get', '/api/user/list', { pageNo: 1 });
const saved = await httpRequest('post', '/api/user/save', payload);

// 独立实例:多后台 / 多环境 / 单测(不参与 name 缓存)
const other = createHttpClient(createRequestConfig({ session, notifier, name: 'other', baseURL: '/other' }));

上传 / 下载

http.upload('/api/file/upload', formData, (e, requestId) => {
  console.log('进度', e.loaded, e.total);
}, { requestId: 'upload-1' });

http.download('get', '/api/export', { type: 'excel' });

download() 在请求失败时会 reject,调用方需自行 catch;文件名解析已对无 filename= 的响应头做防御。

单次请求配置

await httpRequest('post', '/api/x', payload, {
  resubmitable: true,   // 允许重复请求
  returnRespone: true,  // 返回完整 AxiosResponse
  hideError: true       // 业务错误不弹提示
});

await httpRequest('get', '/api/x', {}, undefined, true); // force=true,跳过缓存

响应约定

请求层按下面约定解析响应体(同时满足才视为业务响应):

{ "errcode": 0, "ok": true, "success": true, "result": {} }
  • 业务成功 → 返回 data.result(除非 returnRespone)。
  • data.errcode == 44001 → 提示「登录凭证过期」并触发退出。
  • 业务失败 → 提示 data.errmsg 并抛错。
  • 响应不匹配上述结构 → 原样返回 AxiosResponse。
  • 响应头出现 authorization-refresh → 延迟 3 秒调用 deps.refreshToken。

RequestConfig 工厂

createRequestConfig({
  session,                       // 必需
  notifier,                      // 必需
  baseURL: '/',
  timeout: 30000,
  name: 'default',               // 同名实例会被复用
  returnRespone: false,
  resubmitable: false,
  headers: {},
  refreshToken: () => {},        // 可选
  logout: () => {},              // 可选,默认 session.destroy()
  repeatRequestTime: 1000,       // 可选,防重复请求窗口(毫秒)
  cacheSize: 200,                // 可选,短期响应缓存上限
  logger: myLogger,              // 可选,默认 console
  translator: myTranslator       // 可选,默认内置中文
});

Permission 权限

配置

PermissionConfig 有四种模式,公共字段一致:

字段 说明
mode 'role' | 'operate' | 'menu' | 'menuAndOperate'
loginPath 登录页路径
loadingPage 加载页路径
strict 严格模式,见下
history 'hash'(默认)或 'web'
baseRoutes 静态基础路由(登录页、404、loading 等)
mainRoute 主框架路由,动态菜单会作为其 children 挂载
routerConfig 菜单来源配置
whiteList 免登录白名单(按路由 name 匹配)
refreshTokenPath 刷新 token 接口
onNotAuth 退出前回调,支持同步/异步
filterOfPermi 是否按权限过滤菜单(仅 role 模式生效)
loginCheckPath 登录状态检查接口,默认 /api/public/admin/isLogin

模式专属字段:

  • role:roles: string[]、routeMetaName(路由 meta 上角色字段名)。
  • operate:operates: string[]、routeMetaName。
  • menu:checkType: 'name' | 'path'。
  • menuAndOperate:menus: string[]。

strict 语义

  • strict: true(默认)→ 登录校验要求 同时具备 token 与 authType。
  • strict: false → 仅要求 token。

菜单来源(三选一)

// 1) 静态路由数组
routerConfig: { menus: [ /* RouteRecordRaw[] */ ], parentName: 'index' }

// 2) Promise
routerConfig: { menus: fetchRoutes(), parentName: 'index' }

// 3) 动态接口
routerConfig: {
  parentName: 'index',
  menus: {
    url: '/api/sys/menu/list',
    method: 'get',
    cache: true,                       // 为真时优先读 session.getMenus(),未命中再请求并写回
    tree: { id: 'id', parent: 'parentId' },
    dataKey: 'result',                 // 可选,取嵌套数据
    generatorRoute: (menu) => ({       // 菜单项 → 路由
      path: menu.path,
      name: menu.code,
      component: () => import(`/src/views/${menu.component}`),
      meta: { title: menu.name, type: menu.type, hide: !menu.visible, actions: menu.actions }
    })
  }
}

checkType 生效规则:menu 模式下按 name 或 path 匹配路由;其它模式固定按 path。

常用方法

const permission = usePermission();

permission.router;                      // 供 app.use() 使用
permission.checkAuthority(route);       // 角色模式下判断路由权限
permission.login(authType, token, info);// 登录成功后调用,会重新初始化菜单
permission.logout();                    // 清登录态并跳登录页
permission.clearAuth();                 // 只清登录态,不跳转
permission.refreshToken();              // 主动刷新 token
permission.dispose();                   // 摘除路由守卫
permission.start();                     // autoStart=false 时手动启动
resetPermission();                      // 重置单例(HMR / 测试)

PermissionConfig.autoStart 默认 true:创建时自动检查登录态并初始化菜单;置为 false 后由调用方自行调用 permission.start()(返回 Promise)。

resetPermission() 会先 dispose() 再置空单例,可安全地重新 createPermission()。

Handler 列表

Handler.build 默认在组件 setup 内调用(内部使用 useRoute() / useRouter())。 notifier / confirm / tableFilter 由 setupVbCore() 注入一次,无需每次传;只有组件级的 route 需要按需传入(不传则走 useRoute/useRouter):

Handler.build(config);                                        // setup 内,最简
Handler.build(config, { route: createVueRouteAdapter() });    // 显式注入 vue-router 路由
Handler.build(config, { route: createMemoryRouteAdapter() });  // 组件外 / 单测

开启 route: true 后,查询参数通过 replace 同步到 query(不堆历史记录)。

import { Handler } from 'vebai-loom';

const handler = Handler.build({
  queryApi: { url: '/api/user/page', method: 'get' },
  page: true,
  rowKey: 'id',
  autoQuery: true,
  route: true,                 // 查询参数与路由 query 双向同步
  pageSize: 20,
  apis: {
    remove: { url: '/api/user/remove', method: 'post', autoRefresh: true },
    export: { url: '/api/user/export', method: 'get', download: true }
  }
});   // 全局依赖已由 setupVbCore() 注入;需要显式路由时再加第二个参数

HandleConfig

字段 说明
queryApi 列表查询接口
page 是否分页
autoQuery 默认 true,创建后自动查询
sort 前端排序函数
treeTable true 或 { id, pid },组织为树
pageSize / params / rowKey / listKey 分页与数据结构配置
route 与路由 query 同步
queryBefore 查询前钩子,返回 boolean 或 Promise
queryAfter 查询后钩子 (list, data) => void
apis 操作名 → Api

Api:{ url, method, title?, download?, autoRefresh?, confirmTitle?, confirmTip? }

Handler 方法与状态

成员 说明
list / loading / loaded 列表数据与加载状态
pagination / pageParam / params 分页与查询参数
query() / search() / reset() 查询 / 回到第一页查询 / 重置参数
getIndex(index) 计算序号
edit(data, key?) 设置当前编辑数据
getData() / getId(key?) 取当前数据
handle(name, data?, auto?, confirm?) 调用 apis[name]
remove() / disable() / move() / export() 常用操作的封装
importResult(data) 展示导入结果
selectedKeys / selectedObjs / onSelectedChange / setSelectedObjs / removeSelectedObjs 多选
filter(type) / selectFilter(...) 生成表格筛选属性(交给 TableFilterAdapter 渲染)
onChange(pagination, filters, sorter, extra) 传给表格的排序处理

表格列可直接使用:

columns = [
  { title: '名称', dataIndex: 'name', ...handler.filter('text') },
  { title: '状态', dataIndex: 'status', ...handler.selectFilter(statusState) }
];

// 表格事件
// @change="handler.onChange"

DynamicForm 动态表单

DynamicForm 是纯 TS 引擎:不 import vue,也不返回 VNode。它输出一份「描述符」,由使用方渲染器渲染。

基本用法

import { DynamicForm } from 'vebai-loom';

const form = { userName: '', status: 1 };
const engine = new DynamicForm([
  { type: 'input', name: 'userName', title: '用户名', rules: ['required'] },
  { type: 'select', name: 'status', title: '状态', list: statusList, firstOption: true }
], { labelWidth: 100, layout: 'horizontal' }, form);

const descriptor = engine.createDescriptor();
// descriptor.kind === 'form',交给你的渲染器

适配器写值时会调用描述符里的 onChange,引擎据此写回模型:

field.onChange(value);      // 内部 setLinkData + 触发 item.onChange
engine.getModel();          // 当前模型
engine.setValue('a.b', 1);  // 按路径写值
engine.invalidate();        // 外部直接改了模型时,手动失效描述符缓存
engine.createDescriptor();  // 带缓存;force=true 强制重建

表格(type: 'table')不再往业务数据里写 __index,提交前无需清理。

支持的控件类型

input、password、number、textarea、inputGroup、radio、checkbox、switch、select、treeSelect、radioGroup、checkboxGroup、datePicker、dateRangePicker、autoComplete、table、group、span、multipleText、fileUpload、filePicker、imageUpload、excelImport、editor、customRender。

通用字段

字段 说明
type / name / title 控件类型、字段名、标题
rules 'required' / 正则 / 对象 / 函数,或它们的数组
attrs 透传给控件的属性
width / style / colSpan / colFlex 布局
hideLabel / labelWidth / labelAttrs / labelStyle 标签
disabled / depand 布尔或 (form) => boolean
onChange({ name, value, data, index }) 值变化回调
help 帮助文本

描述符结构

FormDescriptor
├── layout / labelAlign / labelWidth / justifyLabel / attrs
└── rows: RowDescriptor[]
    └── cols: ColDescriptor[]
        └── node: FieldDescriptor | SpanDescriptor | TableDescriptor
                 | GroupDescriptor | InputGroupDescriptor | CustomDescriptor

FieldDescriptor 关键字段:

  • control:控件类型
  • name / field:完整点路径 / 叶子字段名
  • value + valueType:'value' | 'checked' | 'date' | 'dateRange'
  • options / treeData / fieldNames
  • rules / attrs / labelAttrs / style / placeholder
  • onChange(value):写回回调
  • encrypt(password)、customAdd(select)、dateFormat(日期)

渲染器职责

渲染器需要:

  1. 把 FormDescriptor 渲染成对应框架的表单容器与栅格。
  2. 按 control 从 ControlRegistry 取控件组件。
  3. 按 valueType 绑定值与回调:
    • value → 常规值绑定;
    • checked → checkbox / switch;
    • date / dateRange → 用 dateFormat 在字符串与日期对象之间转换(dayjs / Date 由适配器负责)。
  4. 把 rules 转成框架的校验规则。
  5. table / group:用描述符里的 columns / items / onAdd / onRemove / onMove 渲染。

参考实现见 examples/antd/dynamic-form-render.ts 与 examples/element-plus/dynamic-form-render.ts。

编写自己的适配器

表单承载(FormHost)

FormHost 把表单的校验、提交、成功提示与自动关闭收进内核,并用 display 切换承载方式:

display 承载方式
page 页面内卡片
modal 弹窗
drawer 抽屉

内核不依赖任何 UI 库:承载容器、按钮、表单渲染与校验实例都由 FormHostAdapter 注入,入口为 vebai-loom/form-host(与框架无关的 vebai-loom/dynamic-form 分开)。

import { FormHost } from 'vebai-loom/form-host';
import { createAntdFormHostAdapter } from './adapters/antd-form-host';

const adapter = createAntdFormHostAdapter();
<FormHost
  display="drawer"
  :visible="visible"
  title="编辑用户"
  :adapter="adapter"
  :form-items="formItems"
  :form="form"
  :init-form="{ name: '' }"
  url="/api/user/save"
  method="post"
  draft
  @update:visible="visible = $event"
  @success="onSuccess"
/>

FormHostAdapter 需要提供:

  • button:底部按钮组件。
  • renderForm(engine):渲染表单主体,通常复用已有的描述符渲染器。
  • renderContainer(context):按 display 渲染 page / modal / drawer 容器。
  • validate() / resetValidation():表单校验与清空校验。

提交流水线由 runFormSubmit() 提供,可在纯 Node 环境测试:校验 -> onSubmitBefore -> json / formData 组装 -> httpRequest -> Notifier 成功提示 -> onSuccess。

内核只依赖 interfaces 里的接口:

  1. 实现 Notifier / ConfirmService。
  2. 实现 SessionAdapter(token、用户信息、菜单持久化)、Logger、Translator。
  3. 用 createControlRegistry() 把控件类型(input / select / ...)映射到自己的组件。
  4. 实现 TableFilterAdapter(表格筛选下拉)。
  5. 写一个渲染器消费 FormDescriptor,把描述符渲染成你的组件。
  6. 需要组件外使用 handler 时,注入 RouteAdapter(createVueRouteAdapter() 或 createMemoryRouteAdapter())。

examples/antd 与 examples/element-plus 提供可直接参照的实现(它们不参与构建、不被导出、不在 package.json 声明依赖)。

常见注意事项

  • 初始化顺序:先 setDefaultRequestConfig,再 createPermission;否则权限初始化会取不到请求实例。
  • Handler.build 的作用域:默认必须在组件 setup 内调用(依赖 useRoute() / useRouter());注入 RouteAdapter 后可在组件外运行。
  • 日期:内核只传字符串与 dateFormat,字符串与日期对象的互转由适配器完成。
  • filterOfPermi:仅 role 模式有明确判定语义;menu 模式由后端按权限下发菜单,不再二次过滤。
  • strict:默认要求 token + authType;只有确实不需要 authType 时才设为 false。
  • 菜单缓存:DynamicMenuApi.cache = true 时,getMenus 会先读 session.getMenus(),未命中再请求并写回;退出登录会清空。
  • input 归一化:input 默认执行 trim 与 Unicode 空白过滤,可用 trim: false / filterUnicode: false 关闭。
  • 密码字段:password 若提供 encrypt,描述符不再回显原值,适配器提交前会经过 encrypt。
  • 重复初始化:initialize() 是幂等的,重复登录不会累积子路由;如需重建可调用 resetPermission()。
  • 导入结果:importResult 会把 errMsgs 先用 escapeHtml() 转义再拼 HTML,适配器可安全渲染。
  • 依赖安装:使用 permission / handler 时需自行安装 vue 与 vue-router(它们是 optional peer)。

速查表

能力 入口
配置请求 setDefaultRequestConfig(createRequestConfig(deps))
发请求 createHttp() / httpRequest()
权限 createPermission / usePermission / resetPermission
列表 Handler.build(config, deps)
动态表单 new DynamicForm(items, attrs, form) → createDescriptor()
纯函数与工具 vebai-loom/shared、vebai-loom/shared/business
参考适配器 examples/antd、examples/element-plus

脚本与构建

在包目录内执行:

脚本 作用
npm run typecheck 基础类型检查
npm run typecheck:strict 核心模块严格模式检查(shared / interfaces / types / routes / rules)
npm run typecheck:examples antd 示例类型检查
npm test 纯函数单测(node:test,零新增依赖)
npm run build 生成 dist 与 .d.ts,并把本文档复制为 dist/README.md
npm publish 发布前自动执行 prepublishOnly(npm run build)

两套哲学的取舍

  • dynamic-form 是框架无关的描述符引擎,渲染完全交给使用方。
  • http / permission / handler 保留 Vue3 + vue-router;handler 通过注入 RouteAdapter 获得组件外运行能力。

permission 默认在创建时自动检查登录态(autoStart: true);置为 false 后由调用方调用 permission.start()。

这是有意为之的取舍:渲染引擎彻底解耦收益最大,而列表/权限逻辑留在 Vue 生态成本更低。

Related Packages

vue-yp-http

基于axios使用在vue上的HTTP组件,根据YP业务二次封装。

1,088
vue-plugin-axios

A wrapper for integrating axios to Vuejs

3,521 5
@mundoit-lib/plugin-vue-axios

Vue 3 plugin for a shared Axios instance (JSON headers, multi-database base URL,...

1,637 0
@shaynekasai/v-fetch

A Vue directive to add AJAX to your app without the boilerplate

554
axios-progress-bar

Slim progress bar (NProgress) for Web applications that use Axios library for HT...

224,641 248

Version History

Version Released Vue License
2.0.0 ^3.2.37 MIT
Pre-releases (1)
Version Released License
0.0.0-stage