@wg-song/bare
v0.1.2
Published
Vue3 业务组件库 - Form / Table / Feedback 等多层结构支持
Maintainers
Readme
@wg-song/bare — Vue3 业务组件库
基于 Vue 3 + Ant Design Vue + vxe-table 的业务组件库,提供表单、表格、列表页、弹窗、标签页等高频业务场景组件。
安装
pnpm add @wg-song/barePeer dependencies(必需,由接入应用提供):
{
"vue": "^3.0.0",
"ant-design-vue": "^4.0.0",
"vxe-table": "^4.0.0",
"@ant-design/icons-vue": "^7.0.0",
"vue-router": "^4.0.0 || ^5.0.0"
}推荐一并安装(以获得完整 vxe-table 体验):
pnpm add vxe-pc-ui
vxe-pc-ui是vxe-table的配套 UI 包,提供 tooltip、loading、筛选面板等能力。本库表格组件默认使用showOverflow: 'title'避免强依赖,不强制要求vxe-pc-ui;但建议接入方一并安装并注册,否则部分 vxe-table 高级交互可能表现不一致。
快速开始
在 main.ts 中先注册 vxe-table / vxe-pc-ui,再安装本库:
import { createApp } from 'vue'
import VXETable from 'vxe-table'
import VXEPcUI from 'vxe-pc-ui'
import BareComponents from '@wg-song/bare'
import 'vxe-table/lib/style.css'
import 'vxe-pc-ui/lib/style.css'
import '@wg-song/bare/index.css'
const app = createApp(App)
app.use(VXEPcUI)
app.use(VXETable)
app.use(BareComponents)
app.mount('#app')若未注册
vxe-table,表格组件会报[Vue warn]: Failed to resolve component: vxe-grid。开发环境下本库install阶段会在控制台给出明确提示。
组件能力矩阵
场景组件
| 组件 / API | 说明 |
|---|---|
| PageList | 完整列表页(搜索 + 工具栏 + 表格 + 分页 + 详情弹窗) |
| PageShell | 列表页外壳(搜索 + 工具栏 + 表格插槽 + 分页) |
| PageEditList | 可编辑列表页 |
| PageChildList | 子列表页 |
| TableRead | 只读表格(固定操作列等) |
| TableEdit | 行内编辑表格 |
| TableChild | 父子表格 |
| TableGroup / TableGroupPage | 分组表格 |
| DialogForm | 弹窗表单场景 |
| PageModals / PageModalSlot | 页面级弹窗管理器 |
| PageListTabs | 标签页 + 列表组合 |
基础组件
| 组件 / API | 说明 |
|---|---|
| Form | Schema 驱动表单 |
| SearchForm | 搜索表单(含高级搜索、FilterBar) |
| SearchFormSimple | 简易单行搜索 |
| Table | 基础 vxe-table 封装 |
| Pagination | 分页 |
| Modal / Drawer | 声明式弹窗/抽屉 |
| Button | 按钮 |
| Switch | 开关 |
| Tag | 标签 |
| Link | 链接 |
| Icon | 图标 |
| Col | 布局列 |
| Dropdown / DropdownMenuItem / DropdownSplitButton | 下拉菜单 |
| Dialog | 对话框 |
| Popover / Tooltip / Popconfirm | 反馈类浮层 |
| Tabs / TabsView / PageTabs | 标签页 |
| SplitPane / SplitPaneLayout | 分割面板 |
| ToolbarActionBar / ToolbarActionButtonMenu | 表格工具栏操作 |
Hooks / 工具函数
| API | 说明 |
|---|---|
| useForm / useSearchForm | 表单核心 hook |
| usePageList | 列表页逻辑 hook |
| definePageList / defineLoader | 列表页配置定义 |
| usePageModals / usePageModalContext / definePageModals | 页面弹窗管理 |
| useTabState / useTabbedList | 标签页状态 hook |
| openModal / openDrawer / confirm / alert / setupModal / useModalContext | 命令式弹窗/反馈 |
| localColDriver / remoteColDriver / storeColDriver / setupColPref | 列偏好存储 |
| mapToOptions / formatDictLabel / formatAmountValue / formatDateValue / formatCellDisplay | 表格格式化工具 |
当前版本未提供独立的
Input、Select、Card组件;表单输入请使用Form/SearchForm的FormField配置,或继续使用 Ant Design Vue 原生组件。
核心使用模式
1. Schema 表单
<script setup lang="ts">
import { ref } from 'vue'
import { Form } from '@wg-song/bare'
import type { FormField } from '@wg-song/bare'
const schemas: FormField[] = [
{ field: 'name', label: '名称', component: 'input', required: true },
{ field: 'status', label: '状态', component: 'select', options: [
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 },
]},
]
const model = ref({ name: '', status: 1 })
function onSubmit(values: Record<string, any>) {
console.log(values)
}
</script>
<template>
<Form v-model="model" :schemas="schemas" @submit="onSubmit" />
</template>2. 搜索表单 + 表格
<script setup lang="ts">
import { SearchForm, Table } from '@wg-song/bare'
import type { FormField, TableColumn } from '@wg-song/bare'
const searchSchemas: FormField[] = [
{ field: 'keyword', label: '关键词', component: 'input' },
]
const columns: TableColumn[] = [
{ field: 'name', title: '名称' },
{ field: 'status', title: '状态' },
]
const data = [
{ name: '示例', status: '启用' },
]
</script>
<template>
<SearchForm :schemas="searchSchemas" />
<Table :columns="columns" :data="data" />
</template>3. 列表页(推荐)
<script setup lang="ts">
import { PageShell } from '@wg-song/bare'
import type { FormField, PageShellProps, ActionItem } from '@wg-song/bare'
const searchSchemas: FormField[] = [
{ field: 'keyword', label: '关键词', component: 'input' },
]
const toolbarActions: ActionItem[] = [
{ label: '新增', onClick: () => {} },
]
const loader: PageShellProps['loader'] = async ({ params, page, pageSize }) => {
// 调用业务 API,params 为搜索表单值
return { list: [], total: 0 }
}
</script>
<template>
<PageShell
:search-schemas="searchSchemas"
:loader="loader"
:toolbar-actions="toolbarActions"
>
<template #default="{ tableData, loading }">
<!-- 渲染表格或其他内容 -->
</template>
</PageShell>
</template>4. 命令式弹窗
import { confirm, openModal } from '@wg-song/bare'
async function onDelete() {
const ok = await confirm('确认删除', '删除后不可恢复')
if (ok) {
// 执行删除
}
}
function onOpen() {
openModal(MyComponent, { title: '详情', data: row })
}完整 CRUD 示例:角色管理
<!-- views/role/index.vue -->
<script setup lang="ts">
import { ref } from 'vue'
import { ref } from 'vue'
import { PageList, confirm } from '@wg-song/bare'
import type {
FormField,
TableColumn,
ActionItem,
PageListProps,
PageListToolbarContext,
} from '@wg-song/bare'
import RoleDetail from './RoleDetail.vue'
const pageListRef = ref<InstanceType<typeof PageList> | null>(null)
const searchSchemas: FormField[] = [
{ field: 'roleName', label: '角色名称', component: 'input' },
{ field: 'status', label: '状态', component: 'select', options: [
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 },
]},
]
const columns: TableColumn[] = [
{ field: 'roleName', title: '角色名称', component: 'link' },
{ field: 'roleCode', title: '角色编码' },
{ field: 'status', title: '状态', component: 'tag', tagColor: ({ value }) => value === 1 ? 'success' : 'default' },
{ field: 'updateTime', title: '更新时间' },
]
function toolbarActions(ctx: PageListToolbarContext): ActionItem[] {
return [
{ label: '新增', type: 'primary', onClick: () => pageListRef.value?.openDetail(null) },
{
label: '批量删除',
danger: true,
disabled: ctx.selectedCount === 0,
onClick: async () => {
const rows = ctx.getSelectedRows()
const ok = await confirm(`确认删除选中的 ${rows.length} 项?`)
if (!ok) return
// 业务侧调用删除 API,例如 await deleteRole(rows.map((r) => r.id))
pageListRef.value?.reload()
},
},
]
}
function rowActions(row: any): ActionItem[] {
return [
{ label: '编辑', onClick: () => pageListRef.value?.openDetail(row) },
{ label: '删除', danger: true, onClick: async () => {
const ok = await confirm('确认删除该角色?')
if (!ok) return
// 业务侧调用删除 API,例如 await deleteRole([row.id])
pageListRef.value?.reload()
}},
]
}
const page: PageListProps['page'] = {
tableId: 'role-management',
search: searchSchemas,
columns,
loader: async ({ params, page, pageSize }) => {
// 业务侧调用分页 API,例如 const res = await getRolePage({ ...params, currentPage: page, pageSize })
return { list: [], total: 0 }
},
toolbarActions,
rowActions,
detailComponent: RoleDetail,
detailTitle: '角色详情',
detailWidth: 600,
}
</script>
<template>
<PageList ref="pageListRef" :page="page" />
</template><!-- views/role/RoleDetail.vue -->
<script setup lang="ts">
import { computed } from 'vue'
import { Form, usePageModalContext } from '@wg-song/bare'
import type { FormField } from '@wg-song/bare'
const { row, close, confirmLoading } = usePageModalContext<any>()
/** row 存在表示编辑,不存在表示新增 */
const isEdit = computed(() => !!row.value)
const schemas: FormField[] = [
{ field: 'roleName', label: '角色名称', component: 'input', required: true },
{ field: 'roleCode', label: '角色编码', component: 'input', required: true },
{ field: 'status', label: '状态', component: 'select', options: [
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 },
]},
{ field: 'remark', label: '备注', component: 'textarea' },
]
async function submit() {
confirmLoading.value = true
try {
// 业务侧调用保存 API,例如 await saveRole(row.value)
close({ success: true })
} finally {
confirmLoading.value = false
}
}
defineExpose({ submit })
</script>
<template>
<Form
:model="row"
:schemas="schemas"
:disabled="!isEdit && false"
/>
</template>关键约定:
detailComponent通过usePageModalContext()获取row;row为null/undefined表示新增,否则为编辑。- 详情组件必须
defineExpose({ submit }),PageList 在点击「确定」时调用该方法。submit中通过confirmLoading.value = true/false控制确认按钮加载态;调用close(result)关闭弹窗。
核心 API 速查
PageList 实例方法(通过 ref 获取)
| 方法 | 说明 |
|---|---|
| openDetail(row?) | 打开详情弹窗;row 为空表示新增 |
| reload() | 重新加载当前页数据 |
| load() | 同 reload |
| reset() | 重置搜索条件 |
| gotoPage(page) | 跳转到指定页 |
| getSelectedRows() | 获取当前已选行 |
| setFieldsValue(values) | 设置搜索表单字段值 |
| clearCheckboxSelection() | 清空复选框选择 |
usePageModalContext()
| 属性 / 方法 | 类型 | 说明 |
|---|---|---|
| row | Ref<D \| undefined> | 当前行数据;为空表示新增 |
| close | (result?: any) => void | 关闭并触发 ok |
| cancel | () => void | 关闭并触发 cancel |
| confirmLoading | Ref<boolean> | 确认按钮加载状态 |
ActionItem 常用字段
| 字段 | 说明 |
|---|---|
| label | 按钮文字 |
| type | Ant Design Vue Button type:primary / default / dashed / link / text |
| danger | 是否危险样式 |
| disabled | 是否禁用 |
| onClick | 点击回调 |
全局配置
通过 app.use(BareComponents, { globalConfig }) 传入:
app.use(BareComponents, {
globalConfig: {
table: { /* Table 默认配置 */ },
pageList: { /* PageList 默认配置 */ },
colPref: { /* 列偏好设置默认配置 */ },
},
})类型导入
import type {
// 表单
FormField,
FormProps,
SearchFormProps,
DialogFormProps,
// 表格
TableColumn,
TableProps,
TableReadProps,
TableEditColumn,
TableChildProps,
TableGroupProps,
// 列表页
PageShellProps,
PageListProps,
PageListConfig,
PageListRowActions,
PageListToolbarContext,
ActionItem,
// 弹窗
ModalContext,
ModalProps,
DrawerProps,
PageModalContext,
PageModalConfig,
// 工具
OptionItem,
ColProps,
} from '@wg-song/bare'包内示例
本包附带可直接运行的业务场景示例,统一使用 from '@wg-song/bare' 导入:
examples/role-management/— 角色管理完整 CRUDexamples/user-management/— 用户管理 PageShell + TableRead
复制到业务项目的 views/ 目录即可参考使用。
构建产物
pnpm build:bare 输出到 dist/packages/:
index.mjs— ESM 主入口index.cjs— CommonJS 入口index.umd.js— UMD 入口index.css— 样式types.d.ts— TypeScript 类型声明README.md/AGENTS.md— 使用文档与 AI 指南examples/— 业务场景示例package.json
本地联调可在其他项目中:
"@wg-song/bare": "file:../songwg-business-components/dist/packages"