Files
djangoadmin-wiki/DjangoAdmin_Flask_AntdVue/zh/volume4/frontend/components.md
T
2026-09-13 21:53:16 +08:00

567 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 公共组件库
:::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。优先使用公共组件,避免重复开发。