Skip to content

系统组件

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
MarkdownViewMarkdown 查看器组件@/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
BpmDialogBPM 对话框组件@/components/BpmDialog
ConfigGlobal全局配置组件@/components/ConfigGlobal
ContentDetailWrap内容详情包装组件@/components/ContentDetailWrap
CardTitle卡片标题组件@/components/CardTitle
OperateLogV2操作日志组件@/components/OperateLogV2
FormCreate表单创建组件@/components/FormCreate
DiyEditorDIY 编辑器组件@/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 组件属性

属性类型默认值说明
modelValueBooleanfalse是否显示对话框
titleString'Dialog'对话框标题
fullscreenBooleantrue是否显示全屏按钮
widthString/Number'40%'对话框宽度
scrollBooleanfalse是否开启滚动条
maxHeightString/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 组件属性

属性类型默认值说明
pageSizeNumber10每页显示条数
currentPageNumber1当前页码
selectionBooleanfalse是否多选
showOverflowTooltipBooleantrue是否超出隐藏
columnsArray[]表头配置
expandBooleanfalse是否展开行
paginationObjectundefined分页配置
reserveSelectionBooleanfalse是否保留之前选中的数据
loadingBooleanfalse加载状态
reserveIndexBooleanfalse是否叠加索引
alignString'center'对齐方式
headerAlignString'center'表头对齐方式
dataArray[]表格数据

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 组件属性

属性类型默认值说明
schemaArray[]表单配置数组
isColBooleanfalse是否需要栅格布局
modelObject{}表单数据对象
autoSetPlaceholderBooleantrue是否自动设置 placeholder
isCustomBooleanfalse是否自定义内容
labelWidthString/Number'auto'表单 label 宽度
vLoadingBooleanfalse是否 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 组件属性

属性类型默认值说明
modelValueString/String[]-文件列表
fileTypeArray['doc', 'xls', 'ppt', 'txt', 'pdf']文件类型
fileSizeNumber5大小限制(MB)
limitNumber5数量限制
autoUploadBooleantrue自动上传
dragBooleanfalse拖拽上传
isShowTipBooleantrue是否显示提示
disabledBooleanfalse是否禁用上传组件

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 组件属性

属性类型默认值说明
editorIdString'wangeEditor-1'编辑器 ID
heightString/Number'500px'编辑器高度
editorConfigObjectundefined编辑器配置
readonlyBooleanfalse是否只读
modelValueString''编辑器内容

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 组件属性

属性类型默认值说明
totalNumber-总条目数(必填)
pageNumber1当前页数
limitNumber20每页显示条目个数
pagerCountNumber7最大页码按钮数

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 组件属性

属性类型默认值说明
iconString-图标名称
colorString-图标颜色
sizeNumber16图标大小
svgClassString''图标 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 组件属性

属性类型默认值说明
typeString-字典类型
valueString/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>

注意:本文档持续更新中,如有问题请及时反馈。