系统组件
1. 组件概述
梵医云前端项目提供了一套完整的系统组件库,基于 Element Plus 进行二次封装,提供了更便捷、更符合业务需求的组件。
1.1 组件特点
- 基于 Element Plus:在 Element Plus 基础上进行封装,保持一致性
- 业务导向:针对实际业务场景进行优化
- 类型安全:完整的 TypeScript 类型定义
- 易于使用:简化 API,提供默认配置
- 高度可定制:支持灵活的配置和扩展
1.2 组件列表
| 组件名称 | 说明 | 路径 |
|---|---|---|
| Dialog | 对话框组件 | @/components/Dialog |
| Table | 表格组件 | @/components/Table |
| Form | 表单组件 | @/components/Form |
| UploadFile | 文件上传组件 | @/components/UploadFile |
| ContentWrap | 内容包装组件 | @/components/ContentWrap |
| Editor | 富文本编辑器组件 | @/components/Editor |
| Pagination | 分页组件 | @/components/Pagination |
| Icon | 图标组件 | @/components/Icon |
| IconSelect | 图标选择器组件 | @/components/Icon |
| DictTag | 字典标签组件 | @/components/DictTag |
| Cropper | 图片裁剪组件 | @/components/Cropper |
| ImageViewer | 图片查看器组件 | @/components/ImageViewer |
| Search | 搜索组件 | @/components/Search |
| Descriptions | 描述列表组件 | @/components/Descriptions |
| Verifition | 验证码组件 | @/components/Verifition |
| Qrcode | 二维码组件 | @/components/Qrcode |
| CountTo | 数字滚动组件 | @/components/CountTo |
| Crontab | 定时任务组件 | @/components/Crontab |
| Sticky | 粘性布局组件 | @/components/Sticky |
| Backtop | 回到顶部组件 | @/components/Backtop |
| Tooltip | 提示组件 | @/components/Tooltip |
| Infotip | 信息提示组件 | @/components/Infotip |
| Error | 错误页面组件 | @/components/Error |
| IFrame | 内嵌框架组件 | @/components/IFrame |
| DocAlert | 文档提示组件 | @/components/DocAlert |
| Echart | 图表组件 | @/components/Echart |
| Highlight | 代码高亮组件 | @/components/Highlight |
| MarkdownView | Markdown 查看器组件 | @/components/MarkdownView |
| InputPassword | 密码输入组件 | @/components/InputPassword |
| ColorInput | 颜色输入组件 | @/components/ColorInput |
| InputWithColor | 带颜色输入组件 | @/components/InputWithColor |
| AppLinkInput | 应用链接输入组件 | @/components/AppLinkInput |
| Area | 地区选择组件 | @/components/Area |
| RouterSearch | 路由搜索组件 | @/components/RouterSearch |
| ShortcutDateRangePicker | 快捷日期范围选择器组件 | @/components/ShortcutDateRangePicker |
| SummaryCard | 汇总卡片组件 | @/components/SummaryCard |
| VerticalButtonGroup | 垂直按钮组组件 | @/components/VerticalButtonGroup |
| Draggable | 拖拽组件 | @/components/Draggable |
| MagicCubeEditor | 魔方编辑器组件 | @/components/MagicCubeEditor |
| SimpleProcessDesigner | 简单流程设计器组件 | @/components/SimpleProcessDesigner |
| BpmDialog | BPM 对话框组件 | @/components/BpmDialog |
| ConfigGlobal | 全局配置组件 | @/components/ConfigGlobal |
| ContentDetailWrap | 内容详情包装组件 | @/components/ContentDetailWrap |
| CardTitle | 卡片标题组件 | @/components/CardTitle |
| OperateLogV2 | 操作日志组件 | @/components/OperateLogV2 |
| FormCreate | 表单创建组件 | @/components/FormCreate |
| DiyEditor | DIY 编辑器组件 | @/components/DiyEditor |
2. Dialog 对话框组件
2.1 组件介绍
Dialog 是基于 Element Plus ElDialog 封装的对话框组件,支持全屏切换、滚动条等功能。
2.2 基础使用
vue
<template>
<el-button @click="dialogVisible = true">打开对话框</el-button>
<Dialog v-model="dialogVisible" title="对话框标题">
<div>对话框内容</div>
</Dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Dialog } from '@/components/Dialog'
const dialogVisible = ref(false)
</script>2.3 组件属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| modelValue | Boolean | false | 是否显示对话框 |
| title | String | 'Dialog' | 对话框标题 |
| fullscreen | Boolean | true | 是否显示全屏按钮 |
| width | String/Number | '40%' | 对话框宽度 |
| scroll | Boolean | false | 是否开启滚动条 |
| maxHeight | String/Number | '400px' | 最大高度 |
2.4 组件插槽
| 插槽名 | 说明 |
|---|---|
| default | 对话框内容 |
| title | 对话框标题 |
| footer | 对话框底部 |
2.5 完整示例
vue
<template>
<el-button @click="openDialog">打开对话框</el-button>
<Dialog v-model="dialogVisible" title="用户信息" width="50%" :scroll="true">
<el-form :model="form" label-width="120px">
<el-form-item label="用户名">
<el-input v-model="form.username" />
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="form.email" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { Dialog } from '@/components/Dialog'
const dialogVisible = ref(false)
const form = reactive({
username: '',
email: ''
})
const openDialog = () => {
dialogVisible.value = true
}
const handleConfirm = () => {
console.log('提交', form)
dialogVisible.value = false
}
</script>3. Table 表格组件
3.1 组件介绍
Table 是基于 Element Plus ElTable 封装的表格组件,支持分页、选择、展开等功能。
3.2 基础使用
vue
<template>
<Table
:columns="columns"
:data="tableData"
:pagination="pagination"
@register="registerTable"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Table } from '@/components/Table'
const columns = ref([
{ field: 'id', label: 'ID' },
{ field: 'name', label: '名称' },
{ field: 'status', label: '状态' }
])
const tableData = ref([
{ id: 1, name: '张三', status: 1 },
{ id: 2, name: '李四', status: 0 }
])
const pagination = ref({
total: 2,
pageSize: 10,
currentPage: 1
})
const registerTable = () => {
console.log('表格注册')
}
</script>3.3 组件属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| pageSize | Number | 10 | 每页显示条数 |
| currentPage | Number | 1 | 当前页码 |
| selection | Boolean | false | 是否多选 |
| showOverflowTooltip | Boolean | true | 是否超出隐藏 |
| columns | Array | [] | 表头配置 |
| expand | Boolean | false | 是否展开行 |
| pagination | Object | undefined | 分页配置 |
| reserveSelection | Boolean | false | 是否保留之前选中的数据 |
| loading | Boolean | false | 加载状态 |
| reserveIndex | Boolean | false | 是否叠加索引 |
| align | String | 'center' | 对齐方式 |
| headerAlign | String | 'center' | 表头对齐方式 |
| data | Array | [] | 表格数据 |
3.4 组件事件
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| update:pageSize | 每页条数变化时触发 | (pageSize: number) => void |
| update:currentPage | 当前页码变化时触发 | (currentPage: number) => void |
| register | 表格注册时触发 | (tableRef, elTableRef) => void |
3.5 完整示例
vue
<template>
<ContentWrap title="用户列表">
<Table
:columns="columns"
:data="tableData"
:pagination="pagination"
:loading="loading"
:selection="true"
@register="registerTable"
/>
</ContentWrap>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { Table } from '@/components/Table'
import { ContentWrap } from '@/components/ContentWrap'
const loading = ref(false)
const tableData = ref([])
const columns = ref([
{ field: 'id', label: '用户编号', width: 80 },
{ field: 'username', label: '用户名称' },
{ field: 'nickname', label: '用户昵称' },
{ field: 'mobile', label: '手机号码' },
{ field: 'status', label: '状态' }
])
const pagination = ref({
total: 0,
pageSize: 10,
currentPage: 1
})
const registerTable = (tableRef, elTableRef) => {
console.log('表格注册', tableRef, elTableRef)
}
const getList = async () => {
loading.value = true
// 模拟请求数据
setTimeout(() => {
tableData.value = [
{ id: 1, username: 'admin', nickname: '管理员', mobile: '13800138000', status: 0 },
{ id: 2, username: 'test', nickname: '测试用户', mobile: '13800138001', status: 1 }
]
pagination.value.total = 2
loading.value = false
}, 1000)
}
onMounted(() => {
getList()
})
</script>4. Form 表单组件
4.1 组件介绍
Form 是基于 Element Plus ElForm 封装的表单组件,支持动态表单、表单验证等功能。
4.2 基础使用
vue
<template>
<Form :schema="formSchema" :model="formModel" @register="registerForm" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Form } from '@/components/Form'
const formModel = ref({})
const formSchema = ref([
{
field: 'username',
label: '用户名',
component: 'Input',
required: true
},
{
field: 'email',
label: '邮箱',
component: 'Input',
rules: [{ type: 'email', message: '请输入正确的邮箱地址' }]
}
])
const registerForm = (formRef) => {
console.log('表单注册', formRef)
}
</script>4.3 组件属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| schema | Array | [] | 表单配置数组 |
| isCol | Boolean | false | 是否需要栅格布局 |
| model | Object | {} | 表单数据对象 |
| autoSetPlaceholder | Boolean | true | 是否自动设置 placeholder |
| isCustom | Boolean | false | 是否自定义内容 |
| labelWidth | String/Number | 'auto' | 表单 label 宽度 |
| vLoading | Boolean | false | 是否 loading 数据中 |
4.4 组件事件
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| register | 表单注册时触发 | (formRef, elFormRef) => void |
4.5 表单配置
typescript
interface FormSchema {
field: string // 字段名
label?: string // 标签文本
component?: string // 组件类型
componentProps?: object // 组件属性
rules?: object[] // 验证规则
required?: boolean // 是否必填
colProps?: object // 栅格属性
formItemProps?: object // 表单项属性
slot?: string // 插槽名称
}4.6 完整示例
vue
<template>
<ContentWrap title="用户表单">
<Form
:schema="formSchema"
:model="formModel"
:is-col="true"
@register="registerForm"
/>
<el-button type="primary" @click="handleSubmit">提交</el-button>
</ContentWrap>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Form } from '@/components/Form'
import { ContentWrap } from '@/components/ContentWrap'
const formModel = ref({})
const formSchema = ref([
{
field: 'username',
label: '用户名',
component: 'Input',
required: true,
colProps: { span: 12 },
componentProps: {
placeholder: '请输入用户名'
}
},
{
field: 'email',
label: '邮箱',
component: 'Input',
colProps: { span: 12 },
rules: [
{ required: true, message: '请输入邮箱地址' },
{ type: 'email', message: '请输入正确的邮箱地址' }
]
},
{
field: 'status',
label: '状态',
component: 'Select',
colProps: { span: 12 },
componentProps: {
options: [
{ label: '启用', value: 0 },
{ label: '禁用', value: 1 }
]
}
},
{
field: 'remark',
label: '备注',
component: 'Input',
componentProps: {
type: 'textarea',
rows: 4
},
colProps: { span: 24 }
}
])
const registerForm = (formRef, elFormRef) => {
console.log('表单注册', formRef, elFormRef)
}
const handleSubmit = () => {
console.log('提交', formModel.value)
}
</script>5. UploadFile 文件上传组件
5.1 组件介绍
UploadFile 是基于 Element Plus ElUpload 封装的文件上传组件,支持文件类型限制、大小限制、数量限制等功能。
5.2 基础使用
vue
<template>
<UploadFile v-model="fileList" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { UploadFile } from '@/components/UploadFile'
const fileList = ref([])
</script>5.3 组件属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| modelValue | String/String[] | - | 文件列表 |
| fileType | Array | ['doc', 'xls', 'ppt', 'txt', 'pdf'] | 文件类型 |
| fileSize | Number | 5 | 大小限制(MB) |
| limit | Number | 5 | 数量限制 |
| autoUpload | Boolean | true | 自动上传 |
| drag | Boolean | false | 拖拽上传 |
| isShowTip | Boolean | true | 是否显示提示 |
| disabled | Boolean | false | 是否禁用上传组件 |
5.4 组件事件
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| update:modelValue | 文件列表变化时触发 | (fileList: string[]) => void |
5.5 完整示例
vue
<template>
<ContentWrap title="文件上传">
<el-form :model="form" label-width="120px">
<el-form-item label="上传文件">
<UploadFile
v-model="form.files"
:file-type="['pdf', 'doc', 'docx', 'xls', 'xlsx']"
:file-size="10"
:limit="3"
/>
</el-form-item>
</el-form>
</ContentWrap>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
import { UploadFile } from '@/components/UploadFile'
import { ContentWrap } from '@/components/ContentWrap'
const form = reactive({
files: []
})
</script>6. ContentWrap 内容包装组件
6.1 组件介绍
ContentWrap 是基于 Element Plus ElCard 封装的内容包装组件,提供统一的卡片样式和布局。
6.2 基础使用
vue
<template>
<ContentWrap title="卡片标题">
<div>卡片内容</div>
</ContentWrap>
</template>
<script setup lang="ts">
import { ContentWrap } from '@/components/ContentWrap'
</script>7. Editor 富文本编辑器组件
7.1 组件介绍
Editor 是基于 wangEditor 封装的富文本编辑器组件,提供丰富的文本编辑功能。
7.2 基础使用
vue
<template>
<Editor v-model="content" height="500px" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Editor } from '@/components/Editor'
const content = ref('')
</script>7.3 组件属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| editorId | String | 'wangeEditor-1' | 编辑器 ID |
| height | String/Number | '500px' | 编辑器高度 |
| editorConfig | Object | undefined | 编辑器配置 |
| readonly | Boolean | false | 是否只读 |
| modelValue | String | '' | 编辑器内容 |
7.4 组件事件
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| change | 内容变化时触发 | (html: string) => void |
| update:modelValue | 内容变化时触发 | (html: string) => void |
7.5 完整示例
vue
<template>
<ContentWrap title="富文本编辑器">
<Editor
v-model="content"
height="600px"
:editor-config="editorConfig"
@change="handleChange"
/>
</ContentWrap>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Editor } from '@/components/Editor'
import { ContentWrap } from '@/components/ContentWrap'
const content = ref('<p>默认内容</p>')
const editorConfig = {
placeholder: '请输入内容...',
MENU_CONF: {
uploadImage: {
server: '/api/upload'
}
}
}
const handleChange = (html: string) => {
console.log('内容变化', html)
}
</script>8. Pagination 分页组件
8.1 组件介绍
Pagination 是基于 Element Plus ElPagination 封装的分页组件,提供简洁的分页功能。
8.2 基础使用
vue
<template>
<Pagination
:total="total"
:page="page"
:limit="limit"
@pagination="handlePagination"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Pagination } from '@/components/Pagination'
const total = ref(100)
const page = ref(1)
const limit = ref(20)
const handlePagination = ({ page, limit }) => {
console.log('分页变化', page, limit)
}
</script>8.3 组件属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| total | Number | - | 总条目数(必填) |
| page | Number | 1 | 当前页数 |
| limit | Number | 20 | 每页显示条目个数 |
| pagerCount | Number | 7 | 最大页码按钮数 |
8.4 组件事件
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| update:page | 当前页码变化时触发 | (page: number) => void |
| update:limit | 每页条数变化时触发 | (limit: number) => void |
| pagination | 分页变化时触发 | ({ page, limit }) => void |
8.5 完整示例
vue
<template>
<ContentWrap title="用户列表">
<el-table :data="tableData" v-loading="loading">
<el-table-column prop="id" label="ID" />
<el-table-column prop="username" label="用户名" />
<el-table-column prop="nickname" label="昵称" />
</el-table>
<Pagination
:total="total"
:page="queryParams.pageNo"
:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
</template>
<script setup lang="ts">
import { reactive, ref, onMounted } from 'vue'
import { Pagination } from '@/components/Pagination'
import { ContentWrap } from '@/components/ContentWrap'
const loading = ref(false)
const total = ref(0)
const tableData = ref([])
const queryParams = reactive({
pageNo: 1,
pageSize: 20
})
const getList = async () => {
loading.value = true
// 模拟请求数据
setTimeout(() => {
tableData.value = [
{ id: 1, username: 'admin', nickname: '管理员' },
{ id: 2, username: 'test', nickname: '测试用户' }
]
total.value = 2
loading.value = false
}, 1000)
}
onMounted(() => {
getList()
})
</script>9. Icon 图标组件
9.1 组件介绍
Icon 是基于 Iconify 封装的图标组件,支持多种图标库。
9.2 基础使用
vue
<template>
<Icon icon="ep:home-filled" />
<Icon icon="ep:user" color="#409EFF" :size="24" />
</template>
<script setup lang="ts">
import { Icon } from '@/components/Icon'
</script>9.3 组件属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| icon | String | - | 图标名称 |
| color | String | - | 图标颜色 |
| size | Number | 16 | 图标大小 |
| svgClass | String | '' | 图标 SVG 的 class 类名 |
9.4 完整示例
vue
<template>
<div class="icon-list">
<Icon icon="ep:home-filled" :size="32" />
<Icon icon="ep:user" :size="32" color="#409EFF" />
<Icon icon="ep:setting" :size="32" color="#67C23A" />
<Icon icon="ep:search" :size="32" color="#E6A23C" />
<Icon icon="ep:delete" :size="32" color="#F56C6C" />
</div>
</template>
<script setup lang="ts">
import { Icon } from '@/components/Icon'
</script>
<style scoped>
.icon-list {
display: flex;
gap: 20px;
}
</style>10. DictTag 字典标签组件
10.1 组件介绍
DictTag 是基于字典数据的标签组件,自动根据字典值显示对应的标签和颜色。
10.2 基础使用
vue
<template>
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="status" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { DictTag } from '@/components/DictTag'
import { DICT_TYPE } from '@/utils/dict'
const status = ref(0)
</script>10.3 组件属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| type | String | - | 字典类型 |
| value | String/Number/Boolean | - | 字典值 |
10.4 完整示例
vue
<template>
<el-table :data="tableData">
<el-table-column prop="username" label="用户名" />
<el-table-column label="状态">
<template #default="{ row }">
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
</template>
</el-table-column>
</el-table>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { DictTag } from '@/components/DictTag'
import { DICT_TYPE } from '@/utils/dict'
const tableData = ref([
{ username: 'admin', status: 0 },
{ username: 'test', status: 1 }
])
</script>11. 组件使用最佳实践
11.1 组件导入
推荐使用按需导入的方式:
typescript
// ✅ 好的做法:按需导入
import { Dialog } from '@/components/Dialog'
import { Table } from '@/components/Table'
import { Form } from '@/components/Form'
// ❌ 不好的做法:全局导入
import * as Components from '@/components'11.2 组件命名
使用 PascalCase 命名组件:
typescript
// ✅ 好的做法
import { Dialog, Table, Form } from '@/components'
// ❌ 不好的做法
import { dialog, table, form } from '@/components'11.3 组件组合
合理组合使用组件,避免重复代码:
vue
<template>
<ContentWrap title="用户管理">
<el-form :model="queryParams" :inline="true">
<el-form-item label="用户名">
<el-input v-model="queryParams.username" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">搜索</el-button>
</el-form-item>
</el-form>
<Table
:columns="columns"
:data="tableData"
:pagination="pagination"
@register="registerTable"
/>
<Pagination
:total="total"
:page="queryParams.pageNo"
:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
</template>11.4 组件性能优化
- 使用 v-if 和 v-show 合理控制组件显示
- 避免在循环中使用复杂组件
- 合理使用组件缓存
vue
<template>
<!-- ✅ 好的做法:使用 v-if 控制组件显示 -->
<Dialog v-if="dialogVisible" v-model="dialogVisible" title="对话框">
<div>对话框内容</div>
</Dialog>
<!-- ❌ 不好的做法:频繁创建和销毁组件 -->
<Dialog v-model="dialogVisible" title="对话框">
<div>对话框内容</div>
</Dialog>
</template>12. 组件常见问题
12.1 组件样式不生效
问题原因:
- 样式优先级问题
- 组件作用域问题
解决方案:
vue
<style scoped>
/* 使用 :deep() 修改组件内部样式 */
:deep(.el-dialog__body) {
padding: 20px;
}
</style>12.2 组件事件不触发
问题原因:
- 事件名称错误
- 事件参数不匹配
解决方案:
vue
<template>
<!-- ✅ 正确的事件名称 -->
<Dialog v-model="dialogVisible" @open="handleOpen" />
<!-- ❌ 错误的事件名称 -->
<Dialog v-model="dialogVisible" @onOpen="handleOpen" />
</template>12.3 组件属性不生效
问题原因:
- 属性名称错误
- 属性类型不匹配
解决方案:
vue
<template>
<!-- ✅ 正确的属性类型 -->
<Dialog v-model="dialogVisible" width="50%" />
<!-- ❌ 错误的属性类型 -->
<Dialog v-model="dialogVisible" width="50" />
</template>注意:本文档持续更新中,如有问题请及时反馈。
