Skip to content

业务组件总览

介绍

RuoYi-Plus-UniApp 前端管理端提供了一套完整的业务组件库,涵盖表单输入、数据展示、弹窗交互、图表可视化、AI 辅助等多个领域。这些组件基于 Element Plus 进行二次封装,遵循统一的设计规范和 API 约定。

核心特性:

  • 高度模块化 - 70+ 个业务组件,按功能分类清晰
  • 统一 API 设计 - 所有组件遵循一致的属性命名和事件处理规范
  • 响应式布局 - 内置智能响应式系统,支持多种屏幕尺寸自适应
  • 国际化支持 - 全面集成 i18n,所有文本支持多语言切换
  • TypeScript 类型 - 完整的类型定义,提供优秀的开发体验
  • 权限控制 - 与 v-permi 指令无缝集成

组件分类

1. 表单组件 (13个)

组件名称组件标识主要功能
文本输入框AFormInput单行/多行文本输入
下拉选择器AFormSelect单选/多选下拉框
复选框组AFormCheckbox复选框选择
单选框组AFormRadio单选框选择
日期选择器AFormDate日期/日期范围选择
开关AFormSwitch布尔值切换
树形选择器AFormTreeSelect树形结构选择
级联选择器AFormCascader级联数据选择
文件上传AFormFileUpload文件上传
图片上传AFormImgUpload图片上传
富文本编辑器AFormEditor富文本编辑
地图选择器AFormMap地理位置选择
AI辅助输入框AFormInputWithAiAI增强输入

2. 搜索和表格组件 (3个)

组件名称组件标识主要功能
搜索表单ASearchForm搜索条件容器
表格工具栏TableToolbar表格操作工具栏
分页器Pagination数据分页

3. 弹窗组件 (2个)

组件名称组件标识主要功能
通用弹窗AModal对话框/抽屉容器
详情弹窗ADetail数据详情展示

4. 业务选择器 (2个)

组件名称组件标识主要功能
用户选择器UserSelect用户选择
字典标签DictTag字典值显示

5. 卡片组件 (23个)

类别组件数量典型组件
统计卡片3AStatsCard, ABarStatsCard, ALineStatsCard
图表卡片5ABarChartCard, ALineChartCard, APieChartCard
内容卡片4AFormCard, ATableCard, AImageCard, AInfoCard
业务卡片4AUserCard, AProfileCard, APricingCard, ASocialCard
列表卡片5ADataListCard, ATimelineListCard, AActivityCard
特殊卡片2ADataCard, AEmptyCard

6. 图表组件 (10个)

组件名称图表类型使用场景
AChart通用图表ECharts 基础封装
ALineChart折线图趋势分析
ABarChart竖向柱状图数据对比
ABarHorizontalChart横向柱状图排名展示
ABarBidirectionalChart双向柱状图对比分析
APieChart饼图/环形图占比展示
ARadarChart雷达图多维度评估
AScatterChart散点图分布关系
ACandlestickChartK线图股票数据
AMapChart地图地理分布

7. AI 组件 (4个)

组件名称功能
AAiAssistantAI 助手面板
AAiTextOptimizer文本优化工具
AAiContentReviewer内容审查工具
AAiDataGenerator数据生成工具

8. 其他组件 (13个)

组件名称功能
AImportExcelExcel 导入
AOssMediaManager媒体管理器
AThemeColorPicker主题配色选择器
AThemeSvgSVG 渲染
AGeometricBackground几何背景
AWatermark水印
Icon图标渲染
IconSelect图标选择器
ImagePreview图片预览
ASelectionTags选中标签
AResizablePanels可拖拽面板
IFrameContainerIFrame 容器
ARecharge充值组件

核心功能详解

响应式布局系统

所有表单组件都支持响应式布局,通过 span 属性实现。

vue
<template>
  <!-- 固定 span -->
  <AFormInput label="用户名" v-model="form.userName" :span="12" />

  <!-- 响应式对象 -->
  <AFormInput
    label="邮箱"
    v-model="form.email"
    :span="{ xs: 24, sm: 24, md: 12, lg: 8, xl: 6 }"
  />

  <!-- 预设响应式 -->
  <AFormInput label="手机" v-model="form.phone" span="auto" />
</template>

响应式模式:

模式说明场景
screen基于屏幕尺寸默认,页面级表单
container基于容器尺寸弹窗内表单
modal-size基于 AModal size弹窗场景推荐

智能数据类型转换

AFormSelect 组件具备智能的数据类型检测和转换功能。

vue
<script setup lang="ts">
const form = ref({
  roleIds: '1,2,3' // 字符串输入
})

// 组件自动转换为数组 [1, 2, 3] 用于内部选择
// 确认后自动转回字符串 "1,2,3" 保持类型一致
</script>

类型检测规则:

  • 如果数组中有任何字符串元素,输出字符串数组
  • 如果全是数字且在安全整数范围内,输出数字数组
  • 如果数字超过 15 位,自动转为字符串防止精度丢失

选项禁用条件配置

AFormSelect 支持灵活的选项禁用配置。

vue
<template>
  <!-- 默认禁用 (status = '0') -->
  <AFormSelect v-model="form.postIds" :options="postOptions" :multiple="true" />

  <!-- 自定义禁用字段 -->
  <AFormSelect
    v-model="form.roleId"
    :options="roleList"
    disabled-field="isActive"
    :disabled-value="false"
  />

  <!-- 函数判断 -->
  <AFormSelect
    v-model="form.goodsId"
    :options="productList"
    :disabled-value="(item) => item.status === '0' || item.stock < 10"
  />
</template>

表单组件详解

AFormInput - 文本输入框

vue
<template>
  <el-form :model="form">
    <AFormInput label="用户名" v-model="form.userName" prop="userName" :span="12" />
    <AFormInput label="备注" v-model="form.remark" type="textarea" :maxlength="200" :rows="4" />
    <AFormInput label="年龄" v-model="form.age" type="number" :min="0" :max="150" :span="8" />
    <AFormInput label="密码" v-model="form.password" type="password" show-password prevent-autofill />
  </el-form>
</template>

Props 属性

参数说明类型默认值
modelValue绑定值string | number-
label标签文本string-
prop表单域字段名string-
type输入框类型'text' | 'textarea' | 'number' | 'password''text'
span栅格占据列数number | SpanType-
maxlength最大长度number255
showWordLimit显示字数统计booleantrue
showPassword显示密码可见性切换booleanfalse
preventAutofill防止自动填充booleanfalse
clearable显示清除按钮booleantrue
disabled是否禁用booleanfalse
responsiveMode响应式模式'screen' | 'container' | 'modal-size''screen'

Events 事件

事件名说明回调参数
update:modelValue值变化时触发(value: string | number) => void
input输入时触发(value: string | number) => void
change值改变时触发(value: string | number) => void
blur失去焦点时触发(event: FocusEvent) => void
enter按下回车键时触发(value: string | number) => void

Slots 插槽

插槽名说明
prepend输入框前置内容
append输入框后置内容
prefix输入框头部图标
suffix输入框尾部图标

AFormSelect - 下拉选择器

vue
<template>
  <el-form :model="form">
    <AFormSelect label="类型" v-model="form.type" :options="sys_enable_status" :span="12" />
    <AFormSelect
      label="角色"
      v-model="form.roleIds"
      :options="roleList"
      value-field="roleId"
      label-field="roleName"
      :multiple="true"
    />
    <AFormSelect label="代码" v-model="form.code" :options="codeList" :show-value="true" />
  </el-form>
</template>

<script setup lang="ts">
const { sys_enable_status } = useDict(DictTypes.sys_enable_status)
</script>

Props 属性

参数说明类型默认值
modelValue绑定值string | number | Array-
label标签文本string-
options选项数据any[][]
span栅格占据列数number | SpanType-
multiple是否多选booleanfalse
filterable是否可搜索booleantrue
clearable是否可清空booleantrue
valueFieldvalue 字段名string'value'
labelFieldlabel 字段名string'label'
disabledField禁用判断字段名string'status'
disabledValue禁用条件值DisabledCondition'0'
showValue是否显示选项值boolean-
multipleLimit多选最多可选项数number0
collapseTags多选是否折叠标签booleanfalse

AFormDate - 日期选择器

vue
<template>
  <el-form :model="form">
    <AFormDate label="出生日期" v-model="form.birthday" :span="12" />
    <AFormDate label="创建时间" v-model="form.dateRange" type="daterange" :span="12" />
    <AFormDate label="预约时间" v-model="form.appointmentTime" type="datetime" />
  </el-form>
</template>

AFormTreeSelect - 树形选择器

vue
<template>
  <AFormTreeSelect
    label="所属部门"
    v-model="form.deptId"
    :options="deptTree"
    :props="{ label: 'deptName', value: 'deptId', children: 'children' }"
    :span="12"
  />
</template>

AFormUpload - 文件上传

vue
<template>
  <el-form :model="form">
    <AFormFileUpload label="附件" v-model="form.fileList" :limit="5" :accept="'.pdf,.doc,.docx'" />
    <AFormImgUpload label="头像" v-model="form.avatar" :limit="1" :max-size="2" />
  </el-form>
</template>

搜索和表格组件

ASearchForm - 搜索表单

vue
<template>
  <ASearchForm v-model="queryParams" title="搜索条件">
    <AFormInput label="用户名" prop="userName" v-model="queryParams.userName" />
    <AFormSelect label="状态" prop="status" v-model="queryParams.status" :options="statusOptions" />
    <AFormDate label="创建时间" v-model="queryParams.dateRange" type="daterange" />
  </ASearchForm>
</template>

Props 属性

参数说明类型默认值
modelValue表单数据模型Record<string, any>{}
visible显示/隐藏booleantrue
inline是否行内表单booleantrue
labelWidth标签宽度string'auto'
title卡片标题string-
collapsible是否可展开收起booleantrue
defaultExpanded默认是否展开booleanfalse

TableToolbar - 表格工具栏

vue
<template>
  <TableToolbar
    :columns="tableColumns"
    :show-search="showSearch"
    @resetQuery="resetQuery"
    @queryTable="getList"
  >
    <template #left>
      <el-button type="primary" @click="handleAdd">新增</el-button>
    </template>
  </TableToolbar>
</template>

Pagination - 分页器

vue
<template>
  <Pagination
    v-model:page="queryParams.pageNum"
    v-model:limit="queryParams.pageSize"
    :total="total"
    @pagination="getList"
  />
</template>

弹窗组件详解

AModal - 通用弹窗

支持对话框和抽屉两种模式。

vue
<template>
  <!-- 对话框模式 -->
  <AModal v-model="dialogVisible" title="新增用户" @confirm="handleSubmit">
    <el-form :model="form">
      <AFormInput label="用户名" v-model="form.userName" />
    </el-form>
  </AModal>

  <!-- 抽屉模式 -->
  <AModal v-model="drawerVisible" title="用户详情" mode="drawer" direction="rtl" :show-footer="false">
    <UserDetail :user="selectedUser" />
  </AModal>
</template>

Props 属性

参数说明类型默认值
modelValue显示/隐藏状态booleanfalse
mode模式'dialog' | 'drawer''dialog'
title标题string-
size预设尺寸'small' | 'medium' | 'large' | 'xl''medium'
width自定义宽度string | number-
fullscreen是否全屏booleanfalse
movable是否可拖动booleanfalse
direction抽屉方向'ltr' | 'rtl' | 'ttb' | 'btt''rtl'
showFooter显示底部booleantrue
footerType底部按钮类型'default' | 'close-only''default'
loading加载状态booleanfalse
destroyOnClose关闭时销毁booleantrue

Events 事件

事件名说明回调参数
update:modelValue状态变化(value: boolean) => void
confirm确认按钮点击() => void
cancel取消按钮点击() => void
open开始打开() => void
opened完全打开() => void
close开始关闭() => void
closed完全关闭() => void

尺寸配置

typescript
const sizeMap = {
  small: { dialog: '600px', drawer: '600px' },
  medium: { dialog: '800px', drawer: '800px' },
  large: { dialog: '1000px', drawer: '1000px' },
  xl: { dialog: '1200px', drawer: '1200px' }
}

ADetail - 详情弹窗

vue
<template>
  <ADetail
    v-model="detailVisible"
    title="用户详情"
    :data="detailData"
    :fields="detailFields"
    mode="drawer"
  />
</template>

<script setup lang="ts">
const detailFields = ref([
  { label: '用户ID', prop: 'userId', type: 'text' },
  { label: '用户名', prop: 'userName', type: 'copyable' },
  { label: '密码', prop: 'password', type: 'password' },
  { label: '头像', prop: 'avatar', type: 'image' },
  { label: '状态', prop: 'status', type: 'dict', dictType: 'sys_enable_status' },
  { label: '创建时间', prop: 'createTime', type: 'datetime' }
])
</script>

字段类型

类型说明
text普通文本
password密码(可切换显示)
copyable可复制文本
dict字典标签
image图片预览
htmlHTML 内容
file文件链接
date日期格式化
datetime日期时间格式化
currency货币格式化
boolean是/否
array数组显示

业务选择器详解

UserSelect - 用户选择器

vue
<template>
  <UserSelect v-model="selectedUsers" :multiple="true" show-inline-tags />
  <UserSelect v-model="selectedUser" :multiple="false" />
  <UserSelect
    v-model="userIds"
    :initial-user-names="userNamesString"
    :multiple="true"
    button-text="选择成员"
  />
</template>

Props 属性

参数说明类型默认值
modelValue绑定值string | number | SysUserVo | Array-
multiple是否多选booleanfalse
userIds限制用户 ID 范围string | number | Array-
defaultReturnType默认返回类型'object' | 'id''object'
showInlineTags显示内置标签booleanfalse
buttonText按钮文本string'选择用户'
buttonType按钮类型string'primary'
disabled是否禁用booleanfalse
initialUserNames初始用户名string | string[]-

智能返回类型

typescript
// 传入用户对象,返回用户对象
const user1 = ref<SysUserVo>({ userId: '1', userName: 'admin' })

// 传入用户 ID,返回用户 ID
const user2 = ref('1')

// 传入空值,根据 defaultReturnType 决定
const user3 = ref(null)

DictTag - 字典标签

vue
<template>
  <!-- dict 模式 -->
  <DictTag :options="sys_enable_status" :value="user.status" />

  <!-- region 模式 -->
  <DictTag mode="region" :value="user.regionCode" />

  <!-- cascader 模式 -->
  <DictTag mode="cascader" :value="user.categoryId" :cascader-data="categoryTree" />
</template>

Props 属性

参数说明类型默认值
mode模式'dict' | 'region' | 'cascader''dict'
options字典选项any[][]
valuestring | number-
cascaderData级联数据any[][]
valueFieldvalue 字段名string'value'
labelFieldlabel 字段名string'label'

图表组件

基本用法

vue
<template>
  <!-- 通用图表 -->
  <AChart :option="chartOption" height="400px" />

  <!-- 折线图 -->
  <ALineChart title="访问量趋势" :xData="xData" :series="series" height="300px" />

  <!-- 柱状图 -->
  <ABarChart title="产品销量" :xData="products" :series="sales" height="350px" />

  <!-- 饼图 -->
  <APieChart title="流量来源" :data="trafficData" height="400px" />
</template>

<script setup lang="ts">
const xData = ref(['1月', '2月', '3月', '4月', '5月', '6月'])
const series = ref([
  { name: 'PV', data: [120, 132, 101, 134, 90, 230] },
  { name: 'UV', data: [45, 62, 48, 71, 53, 98] }
])

const trafficData = ref([
  { name: '直接访问', value: 335 },
  { name: '搜索引擎', value: 310 },
  { name: '外部链接', value: 234 }
])
</script>

最佳实践

1. 列表页面开发流程

vue
<template>
  <div class="app-container">
    <!-- 1. 搜索表单 -->
    <ASearchForm v-model="queryParams">
      <AFormInput label="用户名" prop="userName" v-model="queryParams.userName" />
      <AFormSelect label="状态" prop="status" v-model="queryParams.status" :options="sys_enable_status" />
    </ASearchForm>

    <!-- 2. 表格工具栏 -->
    <TableToolbar :columns="tableColumns" @queryTable="getList">
      <template #left>
        <el-button type="primary" @click="handleAdd">新增</el-button>
      </template>
    </TableToolbar>

    <!-- 3. 数据表格 -->
    <el-table :data="tableData" v-loading="loading">
      <el-table-column label="用户ID" prop="userId" />
      <el-table-column label="状态" prop="status">
        <template #default="{ row }">
          <DictTag :options="sys_enable_status" :value="row.status" />
        </template>
      </el-table-column>
      <el-table-column label="操作">
        <template #default="{ row }">
          <el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- 4. 分页 -->
    <Pagination v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />

    <!-- 5. 编辑弹窗 -->
    <AModal v-model="editVisible" :title="editTitle" @confirm="handleSubmit">
      <el-form :model="form" :rules="rules" ref="formRef">
        <AFormInput label="用户名" prop="userName" v-model="form.userName" :span="12" />
      </el-form>
    </AModal>
  </div>
</template>

<script setup lang="ts">
import { pageUsers, addUser, updateUser } from '@/api/system/core/user/userApi'

const { sys_enable_status } = useDict(DictTypes.sys_enable_status)

const queryParams = ref({ pageNum: 1, pageSize: 10, userName: '', status: '' })
const tableData = ref([])
const total = ref(0)
const loading = ref(false)
const editVisible = ref(false)
const form = ref({})

const getList = async () => {
  loading.value = true
  const [err, data] = await pageUsers(queryParams.value)
  if (!err) {
    tableData.value = data.records || []
    total.value = data.total
  }
  loading.value = false
}

const handleSubmit = async () => {
  const api = form.value.userId ? updateUser : addUser
  const [err] = await api(form.value)
  if (!err) {
    ElMessage.success('操作成功')
    editVisible.value = false
    getList()
  }
}

onMounted(() => getList())
</script>

2. 表单验证集成

vue
<script setup lang="ts">
const rules = {
  userName: [
    { required: true, message: '请输入用户名', trigger: 'blur' },
    { min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' }
  ],
  email: [
    { required: true, message: '请输入邮箱', trigger: 'blur' },
    { type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
  ],
  phone: [
    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
  ]
}
</script>

3. 权限控制集成

vue
<template>
  <el-button v-permi="['system:user:add']" type="primary" @click="handleAdd">新增</el-button>
  <el-button v-permi="['system:user:edit']" type="primary" link @click="handleEdit(row)">编辑</el-button>
  <el-button v-permi="['system:user:delete']" type="danger" link @click="handleDelete(row)">删除</el-button>
</template>

4. 响应式布局最佳实践

vue
<template>
  <!-- 弹窗内使用 modal-size 模式 -->
  <AModal v-model="visible" size="large">
    <el-form>
      <AFormInput label="标题" v-model="form.title" :span="12" responsiveMode="modal-size" :modalSize="'large'" />
    </el-form>
  </AModal>

  <!-- 页面中使用 screen 模式 -->
  <el-form>
    <AFormInput label="用户名" v-model="form.userName" :span="{ xs: 24, sm: 24, md: 12, lg: 8, xl: 6 }" />
  </el-form>
</template>

常见问题

1. AFormSelect 多选时类型不一致?

解决方案:

typescript
// 方案1: 让组件自动处理类型转换
const form = ref({
  roleIds: '1,2,3' // 字符串输入,组件自动转换
})

// 方案2: 统一使用数组格式
const form = ref({
  roleIds: [1, 2, 3] // 数组输入
})

2. AFormInput 防自动填充不生效?

解决方案:

vue
<template>
  <AFormInput label="密码" v-model="form.password" type="password" show-password prevent-autofill />
</template>

<!-- 如果仍然不生效,可以在表单外层添加 -->
<el-form autocomplete="new-password">

3. UserSelect 返回类型如何控制?

解决方案:

typescript
// 方式1: 通过 v-model 的初始值类型自动推断
const userId = ref('')           // 返回字符串 ID
const user = ref<SysUserVo>()    // 返回用户对象
const userIds = ref<string[]>([]) // 返回 ID 数组

// 方式2: 使用 defaultReturnType 指定(当 v-model 为空时)
// <UserSelect v-model="emptyValue" defaultReturnType="id" />

4. ASearchForm 展开/收起按钮不显示?

原因: 表单项少于 2 行时不显示

解决方案: 确保表单项足够多(至少能形成 2 行),或检查 collapsible 属性是否为 true

总结

RuoYi-Plus-UniApp 前端业务组件库提供了完整的后台管理系统开发解决方案:

  • 13 个表单组件 - 完整的表单输入方案
  • 3 个搜索表格组件 - 列表页核心组件
  • 2 个弹窗组件 - 对话框和详情展示
  • 2 个业务选择器 - 用户选择和字典显示
  • 23 个卡片组件 - 丰富的展示卡片
  • 10 个图表组件 - 完整的数据可视化
  • 4 个 AI 组件 - 智能辅助工具

通过这些组件,开发者可以快速构建列表页、灵活定制表单、展示丰富数据。所有组件都经过生产环境验证,性能优秀,易于使用。