前端业务组件
RuoYi Office PC 管理端在 Vben Admin 5、Ant Design Vue 和 VxeTable 之上,沉淀了一组面向 OA、HRM、system、合同、项目等模块的业务组件。它们不是简单 UI 控件,而是把「表单布局、BPM 审批、字段权限、文件上传、附件预览」等企业应用常见能力封装成可复用组件。
本文参考 Vben 文档中 API Component 的写法,按 场景说明 → 基础用法 → API → 业务实践 的结构整理,便于二开时直接复制到业务模块。
组件清单
| 组件 | 路径 | 主要用途 | 典型模块 |
|---|---|---|---|
BasicForm | src/components/basic-form | 业务单据详情页容器,集成表头、表单、审批流转、底部操作 | OA 会议室/用车/公文/出差,HRM 入转调离,项目、合同 |
CardContainer | src/components/basic-form | 表单内分组卡片,统一标题、间距和卡片样式 | OA、HRM、项目详情页 |
AttachmentList | src/components/attachment-list | 附件列表、上传、预览、下载、排序和只读控制 | OA、HRM、合同、项目 |
FileUpload | src/components/upload | 通用文件上传,支持表单 schema 或模板中使用 | system、OA、ERP、CRM、合同 |
ImageUpload | src/components/upload | 图片上传和图片列表回显,适合头像、图标、封面 | system、HRM、Mall、BPM |
InputUpload | src/components/upload | 上传文本类文件并回填到输入框/文本域 | Pay 应用配置、证书/密钥配置 |
BasicForm
BasicForm 是业务表单页面的高阶容器。它内部使用 useVbenForm 渲染 schema 表单,同时叠加业务单据表头、流程时间线、审批任务列表、流程图、打印、撤回、再次提交等能力。
适用场景
- 业务对象本身有申请单、编号、申请人、部门、公司等表头信息。
- 页面需要兼容新增、编辑、详情、待办、已办、抄送、我的流程等不同入口。
- BPM 节点字段权限需要控制字段隐藏、只读、可编辑。
- 页面底部需要固定保存、提交、删除、撤回、关闭等按钮。
基础用法
<script lang="ts" setup>
import type { VbenFormSchema } from '#/adapter/form';
import { ref } from 'vue';
import { AttachmentList } from '#/components/attachment-list';
import { BasicForm, CardContainer } from '#/components/basic-form';
const formData = ref({});
const attachments = ref([]);
const formSchema: VbenFormSchema[] = [
{ fieldName: 'title', label: '申请标题', component: 'Input' },
{ fieldName: 'applyDate', label: '申请日期', component: 'DatePicker' },
];
const headerData = ref({
billName: '出差申请',
billCode: 'TRIP202605240001',
creatorName: '张三',
companyName: '总部',
deptName: '研发部',
});
function handleSave(values: Record<string, any>) {
// 保存草稿
}
function handleSubmit(values: Record<string, any>) {
// 提交并发起流程
}
</script>
<template>
<BasicForm
:form-data="formData"
:form-schema="formSchema"
:header-data="headerData"
process-definition-key="oa_trip_apply"
@save="handleSave"
@submit="handleSubmit"
>
<CardContainer title="附件信息">
<AttachmentList v-model="attachments" />
</CardContainer>
</BasicForm>
</template>Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
headerData | headerDataProps | 空表头 | 单据表头,包含标题、编号、申请人、部门、公司、流程实例等信息 |
formData | Record<string, any> | {} | 表单回显数据,变化后会同步到内部 Vben Form |
formSchema | VbenFormSchema[] | [] | 表单 schema,写法与 Vben Form 保持一致 |
columns | number | 4 | 表单栅格列数,组件会转换为 span: 24 / columns |
disabled | boolean | false | 整体只读;待办/已办等入口还会结合 viewType 自动判断 |
viewType | string | undefined | 入口类型,常见值:todo、done、my、copy |
timelineDirection | 'horizontal' | 'vertical' | horizontal | 审批时间线方向 |
activityNodes | any[] | [] | 流程节点信息,可由业务页提前传入 |
processDefinition | any | undefined | 流程定义对象,用于提交前预测自选审批人 |
processDefinitionKey | string | undefined | 流程定义 Key,未传 processDefinition 时可用于兜底查询 |
fieldPermission | BusinessFieldPermission | undefined | BPM 业务表单字段权限配置 |
isApproval | boolean | undefined | 是否处于审批态 |
processStatus | number | undefined | 流程状态 |
hideFooter | boolean | false | 隐藏底部操作栏 |
hideSubmit | boolean | false | 隐藏提交按钮 |
hideSave | boolean | false | 隐藏保存按钮 |
hideDelete | boolean | false | 隐藏删除按钮 |
hideRevoke | boolean | false | 隐藏撤回按钮 |
showReCreate | boolean | false | 显示再次提交按钮 |
Events
| 事件 | 参数 | 说明 |
|---|---|---|
save | values | 点击保存草稿 |
submit | values | 点击提交,通常用于发起/提交业务流程 |
delete | - | 删除当前单据 |
revoke | - | 撤销或作废当前单据 |
reCreate | - | 再次提交 |
withdraw | - | BPM 任务撤回 |
close | - | 关闭或返回列表 |
valuesChange | values | 内部表单值变化 |
Expose
| 方法 | 说明 |
|---|---|
getFormApi() | 获取内部 Vben Form API,便于业务页执行 setValues、validate、resetValidate 等操作 |
表头数据结构
export type headerDataProps = {
id?: number;
billCode?: string;
billName?: string;
creatorName?: string;
createTime?: Date | string;
companyId?: number;
companyName?: string;
deptId?: number;
deptName?: string;
processInstanceId?: string;
processStatus?: number;
};业务实践建议
- 先准备后端 SaveReqVO 和详情接口:
formSchema字段名应尽量与保存接口字段一致,减少提交前转换。 - 流程 Key 不要猜:
processDefinitionKey应来自流程配置、菜单或数据库,而不是仅按模块名推断。 - 只读入口统一走 props:已办、抄送、详情页优先传
viewType或disabled,不要在每个字段上重复写disabled。 - 字段权限优先级最高:BPM 节点字段权限会覆盖普通 disabled 逻辑,业务页不要绕过组件单独隐藏字段。
- 复杂明细用插槽承载:主表字段放在
formSchema,明细表、附件、审批说明放到CardContainer中。
CardContainer
CardContainer 是 BasicForm 内部常用的分组容器,适合把基础信息、明细信息、附件信息、审批说明拆成多个卡片。
<CardContainer title="附件信息" :icon="FileOutlined">
<AttachmentList v-model="attachments" />
</CardContainer>| 属性 | 类型 | 说明 |
|---|---|---|
title | string | 分组标题 |
icon | Component | 标题左侧图标 |
AttachmentList
AttachmentList 面向正式业务附件,不只是上传控件。它会把每个文件转换成附件业务对象,支持列表展示、上传弹窗、删除、预览、下载、排序、只读等能力。
基础用法
<script lang="ts" setup>
import { ref } from 'vue';
import { AttachmentList } from '#/components/attachment-list';
const attachments = ref([]);
</script>
<template>
<AttachmentList
v-model="attachments"
accept=".pdf,.doc,.docx,.xls,.xlsx,.png,.jpg"
:max-count="10"
:max-size="20"
/>
</template>只读详情
<AttachmentList v-model="attachments" readonly />Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | AttachmentSaveReq[] | [] | 附件业务对象数组 |
readonly | boolean | false | 只读模式下隐藏上传和删除,仅保留预览/下载 |
maxCount | number | 10 | 最大附件数量 |
accept | string | * | 允许上传的文件类型,例如 .pdf,.docx |
maxSize | number | 10 | 单个文件最大大小,单位 MB |
hideUploadButton | boolean | false | 隐藏内置上传按钮,适合外部自定义按钮位置 |
Events
| 事件 | 参数 | 说明 |
|---|---|---|
update:modelValue | AttachmentSaveReq[] | 附件新增、删除或排序后同步给父组件 |
Expose
| 方法 | 说明 |
|---|---|
handleTriggerUpload() | 打开上传弹窗,常用于隐藏默认按钮后外部触发 |
reloadAttachmentGrid() | 根据当前 modelValue 刷新表格数据 |
waitUploadFinished() | 等待上传任务结束,适合提交前兜底校验 |
附件对象结构
export interface AttachmentSaveReq {
id?: number;
businessType: string;
businessId: number;
fileName: string;
filePath: string;
fileUrl: string;
fileSize: number;
fileType?: string;
fileExtension?: string;
uploadTime?: Date;
sortOrder?: number;
remark?: string;
rowKey?: string;
}预览能力
AttachmentList 会按扩展名选择预览方式:
| 类型 | 处理方式 |
|---|---|
| 图片 | 使用 Ant Design Vue Image 预览 |
| 弹窗或浏览器预览 | |
| DOCX | 使用 @vue-office/docx 预览 |
| XLSX | 使用 @vue-office/excel 预览 |
| 其他 Office 文件 | 结合配置的 kkFileViewUrl 预览 |
| 不支持类型 | 提供下载 |
FileUpload
FileUpload 是轻量级文件上传控件,适合放在 Vben Form schema 中,也可以在模板中直接使用。它默认调用 useUpload(directory).httpRequest,底层对接 infra 文件上传能力;也可以通过 api 传入自定义上传函数。
Schema 中使用
const schema = [
{
fieldName: 'attachmentUrl',
label: '附件',
component: 'FileUpload',
componentProps: {
accept: ['pdf', 'doc', 'docx'],
maxSize: 20,
maxNumber: 3,
showDescription: true,
},
},
];模板中使用
<FileUpload
v-model:value="fileUrl"
:accept="['pdf', 'docx']"
:max-size="20"
:max-number="1"
show-description
/>Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
value / modelValue | string | string[] | [] | 绑定值,单文件通常为字符串,多文件通常为数组或逗号分隔字符串 |
accept | string[] | [] | 允许上传的扩展名或 MIME 类型 |
maxSize | number | 2 | 单文件大小限制,单位 MB |
maxNumber | number | 1 | 最大文件数量 |
multiple | boolean | false | 是否允许多选;maxNumber > 1 时会自动视为多文件 |
drag | boolean | false | 是否显示拖拽上传样式 |
directory | string | undefined | 上传目录,传给默认上传实现 |
api | Function | undefined | 自定义上传函数 |
resultField | string | '' | 从响应中读取结果字段,支持嵌套路径 |
showDescription | boolean | false | 是否显示格式、大小、数量说明 |
helpText | string | '' | 自定义提示文本 |
disabled | boolean | false | 禁用上传和删除 |
autoUpload | boolean | true | 是否选择文件后自动上传 |
fileType | string[] | - | 兼容 form-create,等同 accept |
fileSize | number | - | 兼容 form-create,等同 maxSize |
limit | number | - | 兼容 form-create,等同 maxNumber |
isShowTip | boolean | - | 兼容 form-create,等同 showDescription |
Events
| 事件 | 参数 | 说明 |
|---|---|---|
update:value | string | string[] | 更新 v-model:value |
update:modelValue | string | string[] | 更新 v-model |
change | string | string[] | 文件列表变化 |
delete | UploadFile | 删除文件 |
preview | UploadFile | 点击文件预览 |
returnText | string | 上传前读取文本内容并返回,供 InputUpload 使用 |
ImageUpload
ImageUpload 与 FileUpload 共享同一套 FileUploadProps,但交互上使用图片墙/图片卡片,适合头像、图标、商品图、流程图标等场景。
<ImageUpload
v-model:value="avatar"
:max-size="2"
:max-number="1"
:accept="['jpg', 'jpeg', 'png', 'webp']"
/>常见用法:
- system OAuth2 客户端图标、用户头像。
- HRM 员工照片。
- BPM 流程模型图标。
- Mall 商品主图、分类图标和装修图片。
InputUpload
InputUpload 组合了只读输入框/文本域和 FileUpload。用户上传文本类文件后,组件读取文件文本内容并回填输入框,适合证书、密钥、公钥、私钥等配置项。
<InputUpload
v-model="privateKey"
input-type="textarea"
:textarea-props="{ rows: 8, placeholder: '上传或粘贴私钥' }"
:file-upload-props="{
accept: ['txt', 'pem', 'key'],
maxSize: 1,
maxNumber: 1,
showDescription: false,
}"
/>| 属性 | 类型 | 说明 |
|---|---|---|
modelValue | string | number | 输入框绑定值 |
defaultValue | string | number | 默认值 |
inputType | 'input' | 'textarea' | 输入框类型 |
inputProps | InputProps | 透传给 Ant Design Vue Input |
textareaProps | TextAreaProps | 透传给 Ant Design Vue Textarea |
fileUploadProps | FileUploadProps | 透传给 FileUpload |
常见组合模式
BPM 业务表单 + 附件
<BasicForm
ref="basicFormRef"
:form-data="formData"
:form-schema="formSchema"
:header-data="headerData"
:field-permission="fieldPermission"
:view-type="viewType"
@save="handleSave"
@submit="handleSubmit"
>
<CardContainer title="附件">
<AttachmentList
v-model="formData.attachments"
:readonly="readonly"
accept=".pdf,.doc,.docx,.xls,.xlsx,.png,.jpg"
/>
</CardContainer>
</BasicForm>普通管理弹窗 + 上传字段
{
fieldName: 'icon',
label: '图标',
component: 'ImageUpload',
componentProps: {
maxNumber: 1,
maxSize: 2,
accept: ['png', 'jpg', 'jpeg', 'webp'],
},
}提交前等待附件上传完成
const attachmentRef = ref<InstanceType<typeof AttachmentList>>();
async function handleSubmit() {
await attachmentRef.value?.waitUploadFinished();
// 再提交业务数据
}选型建议
| 需求 | 推荐组件 |
|---|---|
| 正式业务单据页面,包含 BPM、表头、底部按钮 | BasicForm |
| 只是 Vben Form 的一个文件字段 | FileUpload / ImageUpload |
| 需要附件表格、预览、下载、业务附件对象 | AttachmentList |
| 上传证书、密钥等文本文件并回填字段 | InputUpload |
| 表单分区、详情页分块展示 | CardContainer |
二开注意事项
- 上传组件返回值默认是文件 URL,业务附件列表返回的是附件对象数组,两者不要混用。
AttachmentList保存前需要业务页补齐businessType、businessId或在后端创建业务后再绑定。BasicForm里如果自定义明细表,提交时需要手动把明细数据合并到 SaveReqVO。- 文件大小单位统一按 MB,
accept在FileUpload中是数组,在AttachmentList中是字符串。 - PC 端业务表单优先复用这些组件,避免每个 OA/HRM 页面重复实现表头、审批、附件和底部按钮。
