567 lines
17 KiB
Markdown
567 lines
17 KiB
Markdown
# 公共组件库
|
||
|
||
:::tip 说明
|
||
项目提供丰富的公共组件,位于 `ui/src/components/` 目录,基于 AntDesign Vue 二次封装,覆盖表格、表单、弹窗、上传、富文本编辑等常见场景。组件通过 `src/plugins/` 中的 `setupCustomComponents` 全局注册,任何页面直接使用,无需单独 import。
|
||
:::
|
||
|
||
## 组件总览
|
||
|
||
| 组件 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| BasicTable | `components/Table/` | 表格(列定义、分页、操作列、全屏、密度、斑马纹) |
|
||
| TableAction | `components/Table/` | 操作列按钮组(权限控制、下拉折叠) |
|
||
| BasicForm | `components/Form/` | 表单(schemas 配置化、动态渲染、折叠展开) |
|
||
| BasicModal | `components/Modal/` | 弹窗(拖拽、全屏、自定义按钮) |
|
||
| BasicUpload | `components/Upload/` | 文件/图片上传(卡片/列表、限制数量、预览) |
|
||
| Editor | `components/Editor/` | 富文本编辑器(基于 wangeditor) |
|
||
| CropperImage | `components/Cropper/` | 图片裁剪(圆形/矩形、实时预览) |
|
||
| QrCode | `components/Qrcode/` | 二维码生成(canvas/img、内嵌 logo) |
|
||
| ChinaArea | `components/ChinaArea/` | 省市区级联(懒加载、二/三级联动) |
|
||
| Icon | `components/icon/` | 图标(支持 AntDesign 图标 + SVG 图标) |
|
||
| BasicSelect | `components/Select/` | 增强下拉(远程请求、本地缓存) |
|
||
| CountTo | `components/CountTo/` | 数字动画(前缀/后缀、千分位、缓动曲线) |
|
||
| Password | `components/Password/` | 密码强度(强度指示器、重复确认、复杂度校验) |
|
||
| PageWrapper | `components/Page/` | 页面容器(标题卡片、固定底部) |
|
||
| Authority | `components/Authority/` | 权限容器(按权限码控制子元素渲染) |
|
||
| LockScreen | `components/Lockscreen/` | 锁屏组件 |
|
||
| ImpExcel | `components/Excel/` | Excel 导入/导出 |
|
||
| AppProvider | `components/Application/` | 应用提供者(全局配置注入) |
|
||
| Websocket | `components/Websocket/` | WebSocket 连接 |
|
||
| importFile | `components/importFile/` | 通用文件导入 |
|
||
| numberInput | `components/numberInput/` | 数字输入框 |
|
||
| Region | `components/Region/` | 区域选择 |
|
||
| pagination | `components/pagination/` | 分页组件 |
|
||
|
||
---
|
||
|
||
## BasicTable 表格
|
||
|
||
表格组件是使用频率最高的组件,基于 `a-table` + `a-pagination` 封装,详见 [BasicTable 表格](/zh/volume4/frontend/table) 章节。
|
||
|
||
### Props
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `columns` | `BasicColumn[]` | `[]`(必填) | 列定义 |
|
||
| `request` | `Function` | `null` | 数据请求函数,自动管理分页和 loading |
|
||
| `dataSource` | `Function \| Array` | `[]` | 数据源(与 request 二选一) |
|
||
| `title` | `string` | `null` | 表格标题 |
|
||
| `titleTooltip` | `string` | `null` | 标题提示 |
|
||
| `pagination` | `Object \| Boolean` | `{}` | 分页配置,`false` 隐藏分页 |
|
||
| `rowKey` | `string \| Function` | `undefined` | 行数据的唯一标识 |
|
||
| `border` | `Boolean` | `false` | 是否显示边框 |
|
||
| `size` | `string` | `'default'` | 表格尺寸:`small` / `middle` / `default` |
|
||
| `maxHeight` | `Number` | - | 最大高度 |
|
||
| `canResize` | `Boolean` | `true` | 是否自适应窗口高度 |
|
||
| `resizeHeightOffset` | `Number` | `0` | 高度偏移量 |
|
||
| `showTableSetting` | `Boolean` | `true` | 是否显示工具栏 |
|
||
| `tableSetting` | `TableSetting` | 见下方 | 工具栏配置 |
|
||
| `scroll` | `Object` | - | 滚动配置(`x` / `y`) |
|
||
| `rowSelection` | `Object` | - | 多选配置 |
|
||
| `virtualScroll` | `Boolean` | `false` | 是否启用虚拟滚动(大数据量优化) |
|
||
|
||
### tableSetting 工具栏配置
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `redo` | `Boolean` | `true` | 刷新按钮 |
|
||
| `size` | `Boolean` | `true` | 密度切换 |
|
||
| `setting` | `Boolean` | `true` | 列设置 |
|
||
| `fullscreen` | `Boolean` | `true` | 全屏切换 |
|
||
| `striped` | `Boolean` | `true` | 斑马纹开关 |
|
||
|
||
### BasicColumn 列定义
|
||
|
||
| 属性 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `title` | `string` | 列标题 |
|
||
| `dataIndex` | `string` | 字段名 |
|
||
| `key` | `string` | 列唯一标识 |
|
||
| `width` | `number` | 列宽 |
|
||
| `align` | `string` | 对齐方式 |
|
||
| `fixed` | `string` | 固定列:`left` / `right` |
|
||
| `customRender` | `Function` | 自定义渲染函数 `({ text, record, index, column }) => VNode` |
|
||
| `ellipsis` | `boolean` | 超出省略(tooltip) |
|
||
| `auth` | `string[]` | 权限编码,控制列是否显示 |
|
||
| `ifShow` | `boolean \| Function` | 业务控制是否显示 |
|
||
|
||
### Events
|
||
|
||
| 事件 | 参数 | 说明 |
|
||
|------|------|------|
|
||
| `fetch-success` | `(data, result)` | 数据请求成功 |
|
||
| `fetch-error` | `(error)` | 数据请求失败 |
|
||
| `columns-change` | `(columns)` | 列设置变化 |
|
||
|
||
### Slots
|
||
|
||
| 插槽 | 说明 |
|
||
|------|------|
|
||
| `tableTitle` | 表格标题左侧区域(常放添加按钮) |
|
||
| `toolbar` | 工具栏右侧区域 |
|
||
| `bodyCell` | 自定义单元格渲染(操作列) |
|
||
|
||
### Expose 方法
|
||
|
||
| 方法 | 说明 |
|
||
|------|------|
|
||
| `reload(opt?)` | 刷新表格(保留分页) |
|
||
| `restReload(opt?)` | 重置到第一页并刷新 |
|
||
| `getDataSource()` | 获取当前数据 |
|
||
| `setTableData(data)` | 设置表格数据 |
|
||
| `updateTableData(index, record)` | 更新指定行 |
|
||
| `getColumns()` | 获取列配置 |
|
||
| `setColumns(columns)` | 设置列配置 |
|
||
| `redoHeight()` | 重新计算高度 |
|
||
|
||
### 基础用法
|
||
|
||
```vue
|
||
<template>
|
||
<BasicTable :columns="columns" :request="loadDataTable" ref="tableRef">
|
||
<template #tableTitle>
|
||
<a-space>
|
||
<a-button v-perm="['sys:level:add']" type="primary" @click="handleAdd">
|
||
<template #icon><PlusOutlined /></template>
|
||
新增
|
||
</a-button>
|
||
</a-space>
|
||
</template>
|
||
<template #bodyCell="{ column, record }">
|
||
<template v-if="column.key === 'action'">
|
||
<a-space>
|
||
<a-button type="primary" @click="handleEdit(record.id)" v-perm="['sys:level:update']">编辑</a-button>
|
||
<a-button type="primary" danger @click="handleDelete(record.id)" v-perm="['sys:level:delete']">删除</a-button>
|
||
</a-space>
|
||
</template>
|
||
</template>
|
||
</BasicTable>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||
|
||
const columns = [
|
||
{ title: '名称', dataIndex: 'name', width: 200 },
|
||
{ title: '状态', dataIndex: 'status', width: 100 },
|
||
{ title: '创建时间', dataIndex: 'createTime', width: 180 },
|
||
{ title: '操作', dataIndex: 'action', key: 'action', fixed: 'right', width: 200 },
|
||
];
|
||
|
||
async function loadDataTable({ page, pageSize }) {
|
||
const res = await getListApi({ pageNo: page, pageSize });
|
||
return { data: res.data, count: res.count };
|
||
}
|
||
</script>
|
||
```
|
||
|
||
---
|
||
|
||
## BasicForm 表单
|
||
|
||
表单组件通过 schemas 配置化定义表单字段,支持动态渲染、折叠展开,详见 [BasicForm 表单](/zh/volume4/frontend/form) 章节。
|
||
|
||
### Props
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `schemas` | `FormSchema[]` | `[]` | 表单字段配置 |
|
||
| `model` | `Object` | - | 表单数据对象 |
|
||
| `rules` | `FormRules` | - | 表单验证规则 |
|
||
| `layout` | `string` | `'vertical'` | 布局方式 |
|
||
| `labelCol` | `Object` | - | 标签栅格配置 |
|
||
| `size` | `string` | `'default'` | 表单尺寸 |
|
||
| `isFull` | `Boolean` | `true` | 组件是否 100% 宽度 |
|
||
| `showActionButtonGroup` | `Boolean` | `true` | 显示操作按钮组 |
|
||
| `showSubmitButton` | `Boolean` | `true` | 显示查询按钮 |
|
||
| `showResetButton` | `Boolean` | `true` | 显示重置按钮 |
|
||
| `submitButtonText` | `string` | `'查询'` | 查询按钮文字 |
|
||
| `resetButtonText` | `string` | `'重置'` | 重置按钮文字 |
|
||
| `rowProps` | `Object` | - | 行栅格配置(gutter 等) |
|
||
| `colProps` | `Object` | - | 列栅格配置(span 等) |
|
||
|
||
### FormSchema 字段配置
|
||
|
||
| 属性 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `name` | `string` | 字段名(必填) |
|
||
| `label` | `string` | 标签文字 |
|
||
| `component` | `ComponentType` | 渲染组件:`Input` / `Select` / `DatePicker` 等 |
|
||
| `componentProps` | `object` | 组件属性 |
|
||
| `defaultValue` | `any` | 默认值 |
|
||
| `rules` | `object \| object[]` | 字段校验规则 |
|
||
| `slot` | `string` | 自定义插槽名 |
|
||
| `hidden` | `boolean \| Function` | 是否隐藏 |
|
||
| `colProps` | `Object` | 栅格配置 |
|
||
| `labelMessage` | `string` | 标签提示信息 |
|
||
| `suffix` | `string` | 后缀插槽名 |
|
||
|
||
### Events
|
||
|
||
| 事件 | 说明 |
|
||
|------|------|
|
||
| `submit` | 点击查询按钮 |
|
||
| `reset` | 点击重置按钮 |
|
||
|
||
### Expose 方法
|
||
|
||
| 方法 | 说明 |
|
||
|------|------|
|
||
| `setFieldsValue(values)` | 设置字段值 |
|
||
| `getFieldsValue()` | 获取所有字段值 |
|
||
| `resetFields()` | 重置字段 |
|
||
| `validate()` | 校验表单 |
|
||
| `clearValidate(name?)` | 清除校验 |
|
||
| `setProps(formProps)` | 设置属性 |
|
||
| `setSchema(schemaProps)` | 动态修改 schema |
|
||
|
||
### 基础用法
|
||
|
||
```vue
|
||
<template>
|
||
<BasicForm @register="registerForm" @submit="handleSearch" @reset="handleReset" />
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
const [registerForm] = useForm({
|
||
schemas: [
|
||
{
|
||
name: 'name',
|
||
label: '名称',
|
||
component: 'Input',
|
||
componentProps: { placeholder: '请输入名称' },
|
||
},
|
||
{
|
||
name: 'status',
|
||
label: '状态',
|
||
component: 'Select',
|
||
componentProps: {
|
||
options: [
|
||
{ label: '启用', value: 1 },
|
||
{ label: '禁用', value: 0 },
|
||
],
|
||
},
|
||
},
|
||
],
|
||
});
|
||
</script>
|
||
```
|
||
|
||
---
|
||
|
||
## BasicModal 弹窗
|
||
|
||
弹窗组件基于 `a-modal` 封装,支持拖拽、自定义按钮,详见 [Modal 弹窗](/zh/volume4/frontend/modal) 章节。
|
||
|
||
### Props
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `title` | `string` | `''` | 弹窗标题 |
|
||
| `width` | `Number` | `446` | 弹窗宽度 |
|
||
| `draggable` | `Boolean` | `true` | 是否可拖拽 |
|
||
| `hideFooter` | `Boolean` | `false` | 隐藏底部按钮 |
|
||
| `okText` | `string` | `'确认'` | 确认按钮文字 |
|
||
| `cancelText` | `string` | `'取消'` | 取消按钮文字 |
|
||
|
||
### Events
|
||
|
||
| 事件 | 说明 |
|
||
|------|------|
|
||
| `ok` | 点击确认 |
|
||
| `cancel` | 点击取消 |
|
||
| `register` | 弹窗注册回调 |
|
||
|
||
### Expose 方法
|
||
|
||
| 方法 | 说明 |
|
||
|------|------|
|
||
| `setProps(props)` | 设置弹窗属性 |
|
||
| `openModal()` | 打开弹窗 |
|
||
| `closeModal()` | 关闭弹窗 |
|
||
|
||
### 基础用法
|
||
|
||
```vue
|
||
<template>
|
||
<BasicModal title="编辑用户" :width="600" @register="registerModal" @ok="handleSubmit">
|
||
<BasicForm @register="registerForm" />
|
||
</BasicModal>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
const [registerModal, { openModal, closeModal, setProps }] = useModal();
|
||
|
||
function handleEdit(record) {
|
||
setProps({ title: '编辑用户' });
|
||
openModal();
|
||
nextTick(() => {
|
||
setFieldsValue(record);
|
||
});
|
||
}
|
||
</script>
|
||
```
|
||
|
||
---
|
||
|
||
## BasicUpload 上传
|
||
|
||
文件/图片上传组件,支持卡片/列表模式、数量限制、图片预览。
|
||
|
||
### Props
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `listType` | `string` | `'picture-card'` | 展示类型:`picture-card` / `text` / `picture` |
|
||
| `limit` | `Number` | `Infinity` | 最大上传数量 |
|
||
| `maxSize` | `Number` | `2` | 文件大小上限(MB) |
|
||
| `accept` | `string` | - | 接受的文件类型 |
|
||
| `list` | `Ifiles[]` | `[]` | 已上传文件列表 |
|
||
| `circle` | `Boolean` | `false` | 圆形裁剪 |
|
||
| `uploadTitle` | `string` | `'上传图片'` | 列表模式按钮文字 |
|
||
| `helpText` | `string` | `''` | 帮助提示文字 |
|
||
|
||
### Events
|
||
|
||
| 事件 | 参数 | 说明 |
|
||
|------|------|------|
|
||
| `uploadChange` | `(fileList)` | 上传/删除变化 |
|
||
| `delete` | `(fileList)` | 删除文件 |
|
||
|
||
### 基础用法
|
||
|
||
```vue
|
||
<!-- 单图上传 -->
|
||
<Upload v-model="formData.cover" :limit="1" accept="image/*" />
|
||
|
||
<!-- 多图上传 -->
|
||
<Upload :list="formData.images" :limit="5" @uploadChange="handleImageChange" />
|
||
|
||
<!-- 文件上传 -->
|
||
<Upload list-type="text" accept=".pdf,.doc,.docx" uploadTitle="上传附件" />
|
||
```
|
||
|
||
---
|
||
|
||
## Editor 富文本编辑器
|
||
|
||
基于 [wangeditor](https://www.wangeditor.cn/) 封装,支持图片/视频上传、工具栏配置。
|
||
|
||
### Props
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `getHtml` | `string` | - | 双向绑定(HTML 内容) |
|
||
| `getText` | `string` | - | 双向绑定(纯文本) |
|
||
| `height` | `string` | `'310'` | 编辑器高度 |
|
||
| `width` | `string` | `'auto'` | 编辑器宽度 |
|
||
| `mode` | `string` | `'default'` | 模式:`default` / `simple` |
|
||
| `disable` | `Boolean` | `false` | 是否禁用 |
|
||
| `placeholder` | `string` | `'请输入内容...'` | 占位文字 |
|
||
|
||
### 基础用法
|
||
|
||
```vue
|
||
<template>
|
||
<Editor v-model:getHtml="formData.content" height="400px" />
|
||
</template>
|
||
```
|
||
|
||
:::warning 注意
|
||
编辑器内部自动处理图片上传,上传接口由 `uploadFileUrl` 配置。后端图片迁移和 XSS 清洗由 Service 层的 `rich_text_fields` 声明自动处理。
|
||
:::
|
||
|
||
---
|
||
|
||
## CropperImage 图片裁剪
|
||
|
||
基于 [cropperjs](https://github.com/fengyuanchen/cropperjs) 封装,支持圆形/矩形裁剪、实时预览。
|
||
|
||
### 基础用法
|
||
|
||
```vue
|
||
<template>
|
||
<CropperImage
|
||
:src="formData.avatar"
|
||
:circled="true"
|
||
height="300px"
|
||
@cropend="handleCropend"
|
||
/>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
function handleCropend({ imgBase64, imgInfo }) {
|
||
formData.value.avatar = imgBase64;
|
||
}
|
||
</script>
|
||
```
|
||
|
||
---
|
||
|
||
## BasicSelect 增强下拉
|
||
|
||
远程数据下拉选择器,支持请求函数和本地缓存。
|
||
|
||
### 基础用法
|
||
|
||
```vue
|
||
<template>
|
||
<BasicSelect
|
||
v-model="formData.deptId"
|
||
:request="getDeptOptions"
|
||
:cache="true"
|
||
cacheKey="dept-options"
|
||
placeholder="请选择部门"
|
||
/>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
async function getDeptOptions() {
|
||
const res = await getDeptListApi();
|
||
return res.data.map(item => ({ label: item.name, value: item.id }));
|
||
}
|
||
</script>
|
||
```
|
||
|
||
---
|
||
|
||
## PageWrapper 页面容器
|
||
|
||
页面容器组件,提供标题卡片和固定底部区域。
|
||
|
||
### 基础用法
|
||
|
||
```vue
|
||
<template>
|
||
<PageWrapper title="用户管理" content="管理系统用户信息">
|
||
<BasicTable :columns="columns" :request="loadData" />
|
||
|
||
<template #leftFooter>
|
||
<a-button @click="handleCancel">取消</a-button>
|
||
</template>
|
||
<template #rightFooter>
|
||
<a-button type="primary" @click="handleSubmit">提交</a-button>
|
||
</template>
|
||
</PageWrapper>
|
||
</template>
|
||
```
|
||
|
||
---
|
||
|
||
## Authority 权限容器
|
||
|
||
按权限码控制子元素是否渲染,类似 `v-perm` 指令的组件形式。
|
||
|
||
### 基础用法
|
||
|
||
```vue
|
||
<template>
|
||
<Authority :value="['sys:user:add']">
|
||
<a-button type="primary">新增用户</a-button>
|
||
</Authority>
|
||
</template>
|
||
```
|
||
|
||
:::tip v-perm 指令
|
||
除了 `Authority` 组件,项目还提供 `v-perm` 指令,功能相同但更简洁:
|
||
```vue
|
||
<a-button v-perm="['sys:user:add']">新增用户</a-button>
|
||
```
|
||
:::
|
||
|
||
---
|
||
|
||
## Icon 图标
|
||
|
||
统一图标组件,支持 AntDesign 图标和 SVG 图标。
|
||
|
||
### 基础用法
|
||
|
||
```vue
|
||
<template>
|
||
<!-- AntDesign 图标 -->
|
||
<PlusOutlined />
|
||
<DeleteOutlined />
|
||
<EditOutlined />
|
||
<!-- SVG 图标 -->
|
||
<Icon name="svg-icon-user" />
|
||
</template>
|
||
```
|
||
|
||
---
|
||
|
||
## ImpExcel Excel 导入/导出
|
||
|
||
Excel 文件导入和导出组件。
|
||
|
||
### 导出函数
|
||
|
||
```typescript
|
||
import { jsonToSheetXlsx, aoaToSheetXlsx } from '@/components/Excel';
|
||
|
||
// JSON 数据导出
|
||
jsonToSheetXlsx({
|
||
data: [{ name: '张三', age: 25 }],
|
||
header: { name: '姓名', age: '年龄' },
|
||
filename: '用户列表.xlsx',
|
||
});
|
||
|
||
// 二维数组导出
|
||
aoaToSheetXlsx({
|
||
data: [['姓名', '年龄'], ['张三', 25]],
|
||
filename: '用户列表.xlsx',
|
||
});
|
||
```
|
||
|
||
### 导入组件
|
||
|
||
```vue
|
||
<template>
|
||
<ImpExcel @success="handleImportSuccess" />
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
function handleImportSuccess(data) {
|
||
// data: 导入的表格数据
|
||
console.log(data);
|
||
}
|
||
</script>
|
||
```
|
||
|
||
---
|
||
|
||
## 全局注册
|
||
|
||
所有组件在 `src/plugins/setupCustomComponents.ts` 中通过 `setupCustomComponents` 全局注册:
|
||
|
||
```typescript
|
||
// main.ts
|
||
import { setupCustomComponents } from '/@/plugins';
|
||
|
||
setupCustomComponents(app); // 注册所有自定义组件
|
||
```
|
||
|
||
全局注册后,任何组件中直接使用,无需单独 import。
|
||
|
||
---
|
||
|
||
## 权限控制体系
|
||
|
||
项目提供三种权限控制方式,覆盖不同场景:
|
||
|
||
| 方式 | 语法 | 适用场景 |
|
||
|------|------|----------|
|
||
| `v-perm` 指令 | `v-perm="['sys:user:add']"` | 按钮级权限,最常用 |
|
||
| `Authority` 组件 | `<Authority :value="['sys:user:add']">` | 容器级权限,控制多个元素 |
|
||
| `auth` 列属性 | `{ auth: ['sys:user:delete'] }` | TableAction 操作列权限 |
|
||
|
||
:::warning 注意
|
||
`v-perm` 和 `Authority` 的权限码必须与后端 `@permission_required("sys:xxx:xxx")` 一致。用户 ID 1(admin)拥有所有权限。
|
||
:::
|
||
|
||
---
|
||
|
||
## 总结
|
||
|
||
公共组件库基于 AntDesign Vue 二次封装,核心三件套 BasicTable(表格)、BasicForm(表单)、BasicModal(弹窗)覆盖列表页标准场景。辅以 Upload、Editor、Cropper 等业务组件,以及 Authority、v-perm 权限体系。通过全局注册,任何页面直接使用,无需单独 import。优先使用公共组件,避免重复开发。
|