@leadal/flowstream-ui-plus
FlowStream Vue3 前端组件接入指南
FlowStream 前端运行时组件库的 npm 包名统一为 @leadal/flowstream-ui-plus。组件库基于 Vue 3 和 Element Plus,封装流程发起、工作项列表、流程操作、任务发送、任务跳转、流程图及办理轨迹等能力。
组件库公开流程操作、列表、发送、跳转、流程实例图和流程定义预览等组件,以及命令式运行时服务。流程设计与 Editor 由工作流程引擎内部提供,不在本组件库中导出。
目录
1. 安装与配置
1.1 环境要求
| 项目 | 要求 | 说明 |
|---|---|---|
| Node.js | >= 18 |
组件库构建要求 |
| pnpm | >= 8 |
推荐包管理器 |
| Vue | >= 3.4 |
peer dependency |
| Element Plus | >= 2.8 |
peer dependency,宿主工程负责安装和注册 |
1.2 安装
pnpm add @leadal/flowstream-ui-plus
# 或使用 npm
npm install @leadal/flowstream-ui-plus
1.3 全量注册
import { createApp } from 'vue'
import FlowstreamUIPlus from '@leadal/flowstream-ui-plus'
import '@leadal/flowstream-ui-plus/style.css'
import App from './App.vue'
const app = createApp(App)
app.use(FlowstreamUIPlus, {
baseURL: import.meta.env.VITE_FLOWSTREAM_ORIGIN,
timeout: 60_000,
getToken: () => localStorage.getItem('access_token') || undefined,
})
app.mount('#app')
全量注册后,可直接使用 ui-flow-buttons、ui-flow-button、ui-flow-grid、ui-flow-send、ui-flow-jump、ui-flow-diagram、ui-flow-track-diagram、ui-flow-track-table 和 ui-flow-definition-preview 全局标签。流程发起调用默认导出的 flowstream.getRuntimeService().start()。
1.4 按需引入
import {
FlowButton,
FlowButtons,
FlowDefinitionPreview,
FlowDiagram,
FlowTrackDiagram,
FlowTrackTable,
FlowGrid,
FlowJump,
FlowSend,
configureWorkflow,
} from '@leadal/flowstream-ui-plus'
import '@leadal/flowstream-ui-plus/style.css'
configureWorkflow({
baseURL: import.meta.env.VITE_FLOWSTREAM_ORIGIN,
timeout: 60000,
getToken: () => localStorage.getItem('access_token') || undefined,
})
1.5 请求前缀
baseURL 会作为所有 FlowStream 接口的统一前缀,末尾 / 会被移除。
| 配置 | 最终行为 |
|---|---|
| 不配置 | 生产构建不自动添加前缀;开发/测试源码模式默认使用 /api |
/api |
测试或本地代理环境显式使用 /api 前缀 |
http://127.0.0.1:19090 |
直连服务,接口形如 http://127.0.0.1:19090/flowstream/... |
https://example.com/api |
使用业务网关的 /api 前缀 |
本地代理使用 /api 时,应将 /api 转发到 FlowStream 服务,并按网关实际规则决定是否移除 /api。
2. 组件定义
| 组件名 | 全局标签 | 说明 |
|---|---|---|
UiFlowButtons |
ui-flow-buttons |
根据工作项加载并执行流程操作 |
UiFlowButton |
ui-flow-button |
单个流程按钮,是 FlowButtons 的子组件,也可单独使用 |
UiFlowGrid |
ui-flow-grid |
todo / done / draft 统一工作项列表 |
UiFlowSend |
ui-flow-send |
完整任务发送弹窗 |
UiFlowJump |
ui-flow-jump |
流程任务跳转能力 |
UiFlowDiagram |
ui-flow-diagram |
BPMN 流程图、运行状态和办理轨迹 |
UiFlowTrackDiagram |
ui-flow-track-diagram |
单独展示 BPMN 运行轨迹流程图 |
UiFlowTrackTable |
ui-flow-track-table |
单独展示办理轨迹记录表格 |
UiFlowDefinitionPreview |
ui-flow-definition-preview |
BPMN 流程定义预览,不查询流程实例数据 |
除组件外,包入口还导出 configureWorkflow、请求实例 workflowHttp、类型定义以及流程 API 方法(例如 startDraft、quickStart、getFirstHandleNodes、startNodes)。
Editor、内部基础表格和图标组件不是公共导出,不要从@leadal/flowstream-ui-plus引入。
公共尺寸参数
所有公开组件统一支持 size 属性,类型为 large | default | small,默认值为 default。该属性会调整组件内部按钮、表单控件、表格行高与字号;流程图类组件会在自适应父容器后调整画布缩放和图例大小。
<ui-flow-buttons size="small" />
<ui-flow-grid type="todo" size="default" :deal-user-id="userId" />
<ui-flow-diagram
size="large"
:process-definition-id="processDefinitionId"
:process-instance-id="processInstanceId"
/>
size 只控制视觉规格,不替代宽高。列表、流程图和轨迹组件的实际可用区域仍由接入项目的父容器宽高决定。命令式启动同样支持 flowstream.getRuntimeService().start({ size: 'small', ... })。
2.1 ui-flow-buttons
ui-flow-buttons 根据当前工作项加载可用操作。优先使用显式传入的 workId;业务页面只有流程实例时,也可以传 processInstanceId + dealUserId,组件会自行查询并解析该用户的当前待办。发送和跳转默认由组件内部打开完整弹窗,业务页面不需要直接调用流程引擎接口;保存、启动等业务表单相关动作仍通过 execute-action 交给宿主处理。
| action | 处理方式 |
|---|---|
revocation / taskWithdraw |
确认后执行撤回 |
taskRecyle |
确认后执行收回;后端接口保留历史拼写 recyle |
hang |
确认后挂起流程实例 |
restore |
确认后恢复流程 |
terminate |
确认后终止流程 |
taskComplete |
确认后办毕 |
taskRollback |
确认后退回 |
taskClaim |
传入 dealUserId 后执行任务拾取 |
turnBefore / taskTurnBefore |
打开机构人员单选弹窗并执行前加签 |
turnAfter / taskTurnAfter |
打开机构人员单选弹窗并执行后加签 |
taskSend |
默认打开内置发送弹窗 |
jump / taskJump |
默认打开内置跳转弹窗 |
save / start |
触发 execute-action,由宿主处理 |
| 其他未内置动作 | 触发 execute-action,由宿主处理 |
1) 属性定义(Properties)
| 参数 | 说明 | 类型 | 必填 | 默认值 |
|---|---|---|---|---|
workId |
当前工作项 ID;未传时可自动解析 | string |
否 | — |
processInstanceId |
流程实例 ID;自动解析待办、挂起和终止流程时必需 | string |
条件 | — |
processDefinitionId |
流程定义 ID;发送和跳转时使用 | string |
否 | — |
taskId |
当前任务实例 ID;前/后加签时使用,可自动解析 | string |
否 | — |
dealUserId |
当前用户 ID;自动解析待办和拾取任务时使用 | string |
条件 | — |
dealUserName |
当前用户名称 | string |
否 | — |
variables |
发送、办毕时提交的流程变量 | Record<string, unknown> |
否 | {} |
assignmentQueryParams |
通过 extendParams 转发给扩展路由的查询参数 |
Record<string, unknown> |
否 | {} |
autoResolveWork |
未传 workId 时自动查询当前用户待办 |
boolean |
否 | true |
autoHandleDialogs |
在组件内部处理发送和跳转弹窗 | boolean |
否 | true |
forceSingleAssignee |
每个下一节点仅允许选择一名办理人 | boolean |
否 | false |
dialogZIndex |
内置弹窗固定层级;未传时自动高于当前 Drawer/Dialog | number |
否 | 自动 |
beforeAction |
动作执行前钩子;返回 false 可中断,支持异步 |
(action, context) => boolean | void | Promise |
否 | — |
afterAction |
流程动作成功后的函数型钩子 | (action, result, context) => void |
否 | — |
context 包含 workId、流程/任务/节点 ID 和原始 workData;发送、跳转完成后还包含实际提交的 requestData。
终止操作调用 POST /flowstream/server/runtime/event/terminate,请求体为 { processInstanceIds: [processInstanceId] };workId 仅用于加载当前工作项及其可用操作,不能作为终止接口参数。
2) 事件定义(Events)
| 事件名称 | 回调参数 | 说明 |
|---|---|---|
execute-action |
action, context |
需要宿主处理的自定义动作 |
after-action |
action, result, context |
流程动作成功后触发,可用于同步业务状态和刷新列表 |
work-resolved |
context |
自动解析当前用户待办成功后触发 |
error |
error: unknown |
内置操作失败时触发;用户取消确认框不会触发 |
3) 方法定义(Methods)
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
getAvailableActions() |
— | Promise<WorkflowActionItem[]> |
重新加载可用按钮 |
resolveCurrentWork() |
— | Promise<WorkflowActionContext> |
自动解析当前待办 |
executeAction(button) |
WorkflowActionItem |
Promise<void> |
按按钮定义执行或分发动作 |
4) 插槽定义(Slots)
| 插槽 | 插槽参数 | 说明 |
|---|---|---|
prefix |
{ action } |
每个流程按钮前的内容 |
default |
{ action } |
每个流程按钮区域的自定义内容 |
suffix |
{ action } |
每个流程按钮后的内容 |
append |
{ actions, loading } |
整个按钮组末尾的内容,仅渲染一次 |
5) 组件示例
<ui-flow-buttons
:process-instance-id="task.processInstanceId"
:process-definition-id="task.processDefinitionId"
:deal-user-id="loginUser.id"
:deal-user-name="loginUser.name"
force-single-assignee
:before-action="validateBeforeAction"
@execute-action="handleFlowAction"
@after-action="handleAfterAction"
@error="handleError"
>
<template #append>
<el-button link type="primary" @click="handlePrint">打印</el-button>
<el-button link type="primary" @click="handleExport">导出</el-button>
</template>
</ui-flow-buttons>
任务“办毕”等内置操作成功后,应在 after-action 中提示并刷新列表:
function handleAfterAction(action: string, result: unknown) {
ElMessage.success('操作成功')
gridRef.value?.loadTableData()
}
2.2 ui-flow-button
ui-flow-button 是按钮组内部使用的单按钮子组件,也可以单独导入。
1) 属性定义(Properties)
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
type |
预设动作类型,决定默认文字和图标 | string |
— |
label |
覆盖预设按钮文字 | string |
— |
内置类型包括 save、start、revocation、taskWithdraw、taskRecyle、hang、restore、terminate、jump、taskJump、taskComplete、taskSend、taskRollback、taskClaim、turnBefore、taskTurnBefore、turnAfter 和 taskTurnAfter。
2) 事件定义(Events)
| 类型 | 名称 | 参数 | 说明 |
|---|---|---|---|
| Event | click |
type?: string |
点击后返回对应动作类型 |
3) 插槽定义(Slots)
| 插槽 | 参数 | 说明 |
|---|---|---|
default |
— | 自定义按钮内容;未提供时显示 label,再回退到 type |
4) 组件示例
<ui-flow-button type="save" label="保存草稿" @click="saveForm" />
2.3 ui-flow-grid
ui-flow-grid 是待办、已办和草稿统一列表组件,内部完成接口请求、分页、状态显示和行操作。type 必填。
内置列
- todo / done:业务标题
businessName、当前环节activityName、发送人assigneesNames、发送时间startTime。 - draft:业务标题
title、当前环节currentActivity、创建人createUserName、创建时间createdTime。 - done 根据
stateName显示状态,draft 根据stateLabel显示状态。
发送人列必须读取接口字段
assigneesNames,不使用assignees或previousAssignee。
done 状态映射:
| stateName | 显示文本 |
|---|---|
executing |
审批中 |
completed |
已完成 |
deleted |
已删除 |
canceled |
已取消 |
withdrawed |
已撤回 |
recyled |
已回收 |
rollbacked |
已退回 |
jumped |
已跳转 |
1) 属性定义(Properties)
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
type |
列表类型 | string |
todo / done / draft |
— |
dealUserId |
当前用户 ID;todo/done 查询使用 assignee,draft 查询使用 createUserId | string |
— | '' |
appId |
草稿查询的应用 ID | string |
— | '' |
appModuleId |
草稿查询的应用模块 ID | string |
— | '' |
2) 事件定义(Events)
| 事件名称 | 回调参数 | 说明 |
|---|---|---|
on-handle |
{ action, workData } |
行办理、查看或新建草稿 |
error |
error: unknown |
列表加载失败 |
action 规则:todo 办理为 view,done 查看为 handle,draft 查看为 view,调用 create(flow) 新建草稿为 create。
todo/done 的 workData 会统一保留并补齐 workId、processDefinitionId、processInstanceId、activityId 和 activityName。
3) 方法定义(Methods)
| 名称 | 类型 | 说明 |
|---|---|---|
loadTableData() |
Method | 按当前 type、用户和页码重新加载数据 |
create(flow) |
Method | 生成默认业务标题并触发 on-handle 的 create 动作 |
data |
Ref | 当前列表数据 |
loading |
Ref | 加载状态 |
pageConfig |
Reactive | { currentPage, pageSize, total } |
4) 组件示例
<script setup lang="ts">
import { ref } from 'vue'
import { FlowGrid } from '@leadal/flowstream-ui-plus'
const gridRef = ref<InstanceType<typeof FlowGrid>>()
function handleWork({ action, workData }: {
action: 'view' | 'handle' | 'create'
workData: Record<string, unknown>
}) {
console.log(action, workData)
}
</script>
<template>
<div class="flow-grid-page">
<ui-flow-grid
ref="gridRef"
type="todo"
:deal-user-id="currentUserId"
@on-handle="handleWork"
@error="handleError"
/>
</div>
</template>
<style scoped>
.flow-grid-page {
width: 100%;
height: 100%;
min-height: 500px;
box-sizing: border-box;
}
</style>
2.4 ui-flow-send
ui-flow-send 是完整的任务发送弹窗,不只是一个“发送”按钮。组件内置以下交互:
- 根据当前流程定义、节点和
variables调用getSatisfiedSuccedingFlowNodes计算实际可达的下一环节;后端仍返回网关时继续查询后继; - 只有查询结果为唯一人工节点,且
checkSend返回的节点与之相同,才展示办理人确认框直接发送;其余情况打开完整发送弹窗; - 按下一环节加载候选办理人,支持列表和懒加载树;
- 选择各下一环节的办理人;
- 流程变量和办理人查询扩展参数由接入方传入,弹窗内不提供编辑页签;
- 填写审批意见;
- 确认后调用任务发送接口,成功后关闭弹窗并提示“发送成功”。
办理人候选数据通过 POST /flowstream/server/assignment/event/query 加载。业务路由需要额外上下文时,可通过 assignmentQueryParams 传入任意数量的扩展参数,也可以不传;组件将其整体放入请求体的 extendParams。请求根对象中的 processDefinitionId、processInstanceId、activityId、userId、parentId 和 ntype 始终由组件维护。动态路由配置为“流程启动者”时,后端通过 processInstanceId 读取该实例的起草人。variables 为空时,条件查询返回所有可能后继,不能视为已确定的办理路线。
1) 属性定义(Properties)
| 参数 | 说明 | 类型 | 必填 | 默认值 |
|---|---|---|---|---|
modelValue |
弹窗可见状态,使用 v-model |
boolean |
否 | false |
processDefinitionId |
流程定义 ID | string | number |
是 | — |
activity |
当前节点,至少包含 activityId,可带 activityName |
object |
是 | — |
workId |
当前工作项 ID | string | number |
是 | — |
processInstanceId |
流程实例 ID;动态路由以流程启动者为基准时必需 | string | number |
条件 | '' |
variables |
当前业务流程变量 | Record<string, unknown> |
否 | {} |
assignmentQueryParams |
通过 extendParams 转发给扩展路由的查询参数 |
Record<string, unknown> |
否 | {} |
dealUser |
当前用户,可传 id 或 userId |
object |
否 | {} |
bpmnXml |
BPMN XML;用于辅助判断下一节点是单人还是多人办理 | string |
否 | '' |
showTrigger |
是否显示组件自身的发送按钮 | boolean |
否 | true |
dialogTitle |
弹窗标题 | string |
否 | '发送' |
dialogWidth |
弹窗宽度 | string |
否 | '1200px' |
zIndex |
固定弹层层级;未传时自动高于当前 Drawer/Dialog | number |
否 | 自动 |
defaultOpinion |
每次打开弹窗时的默认意见 | string |
否 | '' |
forceSingleAssignee |
是否强制每个下一节点只能选择一个办理人 | boolean |
否 | false |
2) 事件定义(Events)
| 事件名称 | 回调参数 | 说明 |
|---|---|---|
update:modelValue |
visible: boolean |
v-model 更新 |
click |
— | 点击组件自身发送按钮时触发,随后组件会自行打开弹窗 |
open |
— | 开始执行发送前检查;未命中时继续打开完整弹窗 |
close |
— | 弹窗完成关闭 |
next-nodes-resolved |
nodes: FlowNode[] |
下一环节解析成功 |
before-send |
data |
请求发送前触发,参数是即将提交的数据 |
after-send |
result: ApiResponse |
发送成功后触发 |
error |
error: unknown |
下一环节、候选人或发送请求失败 |
3) 方法定义(Methods)
| 名称 | 类型 | 说明 |
|---|---|---|
open() |
Method | 执行发送前检查;未命中时打开弹窗并解析下一环节 |
close() |
Method | 关闭弹窗 |
getNextNode(variables?) |
Method | 根据变量重新解析下一环节 |
assembleData() |
Method | 组装 { workId, flowNodeAssignees, variables, opinion } |
send(formData?) |
Method | 提交发送;不传参数时使用 assembleData() |
visible |
Ref | 内部弹窗状态 |
loading |
Ref | 发送状态 |
checkingSend |
Ref | 发送前检查状态 |
nodeLoading |
Ref | 下一环节计算状态 |
nodeResolved |
Ref | 下一环节是否已完成计算 |
nextNodes |
Ref | 下一环节列表 |
4) 组件示例
ui-flow-buttons 已默认内置 FlowSend。以下手动组合方式仅用于需要完全自定义发送弹窗编排的场景,此时应关闭自动弹窗:
<script setup lang="ts">
import { ref } from 'vue'
import { FlowButtons, FlowSend } from '@leadal/flowstream-ui-plus'
const sendVisible = ref(false)
const assignmentQueryParams = {
projectId: currentProject.id,
tenantId: currentTenant.id,
}
function handleFlowAction(action: string) {
if (action === 'taskSend') sendVisible.value = true
}
function handleAfterSend() {
sendVisible.value = false
gridRef.value?.loadTableData()
}
</script>
<template>
<ui-flow-buttons
:work-id="task.workId"
:process-instance-id="task.processInstanceId"
:auto-handle-dialogs="false"
@execute-action="handleFlowAction"
/>
<ui-flow-send
v-model="sendVisible"
:process-definition-id="task.processDefinitionId"
:process-instance-id="task.processInstanceId"
:activity="{
activityId: task.activityId,
activityName: task.activityName,
}"
:work-id="task.workId"
:deal-user="currentUser"
:variables="variables"
:assignment-query-params="assignmentQueryParams"
:show-trigger="false"
default-opinion="同意"
@after-send="handleAfterSend"
@error="handleError"
/>
</template>
也可以保留默认 showTrigger=true,直接点击 FlowSend 自身按钮打开弹窗。推荐使用 v-model 控制弹窗;需要命令式调用时可使用 sendRef.value?.open()。
2.5 ui-flow-jump
ui-flow-jump 提供跳转按钮、内置节点/办理人选择弹窗和跳转接口封装。选择开始节点后,组件通过办理人接口懒加载组织树;如果节点没有返回办理人,会回填 dealUser。跳转不提供变量编辑,请求固定提交 variables: {}。
1) 属性定义(Properties)
| 参数 | 说明 | 类型 | 必填 |
|---|---|---|---|
processDefinitionId |
流程定义 ID | string | number |
是 |
workId |
当前待办工作项 ID | string | number |
确认跳转时是 |
processInstanceId |
流程实例 ID;动态路由以流程启动者为基准时必需 | string | number |
条件 |
dealUser |
当前用户,支持 { id, userId, name } |
object |
否 |
assignmentQueryParams |
通过 extendParams 转发给扩展路由的查询参数 |
Record<string, unknown> |
否 |
modelValue |
弹窗显示状态,支持 v-model |
boolean |
否 |
showTrigger |
是否显示组件自带跳转按钮,默认 true |
boolean |
否 |
dialogTitle |
弹窗标题,默认“跳转” | string |
否 |
dialogWidth |
弹窗宽度,默认 960px |
string |
否 |
zIndex |
固定弹层层级;未传时自动高于当前 Drawer/Dialog | number |
否 |
2) 事件定义(Events)
| 事件名称 | 回调参数 | 说明 |
|---|---|---|
update:modelValue |
visible |
弹窗显示状态变化 |
click |
— | 点击跳转按钮 |
open |
— | 弹窗打开 |
close |
— | 弹窗关闭 |
before-jump |
data |
提交跳转前 |
after-jump |
result |
跳转成功后 |
error |
error |
加载节点、办理人或提交跳转失败 |
3) 方法定义(Methods)
| 名称 | 类型 | 说明 |
|---|---|---|
open() / close() |
Method | 打开或关闭内置弹窗 |
getStartNodes() |
Method | 加载可跳转用户任务节点 |
assembleData(targetNode?, assigneeId?) |
Method | 组装跳转数据,变量固定为空对象 |
jump(formData?) |
Method | 执行跳转 |
loading |
Ref | 跳转请求状态 |
startNodeList |
Ref | 可跳转节点列表 |
4) 组件示例
<script setup lang="ts">
import { ref } from 'vue'
import { FlowJump } from '@leadal/flowstream-ui-plus'
const jumpVisible = ref(false)
const assignmentQueryParams = { deptCode: 'D1001' }
</script>
<template>
<ui-flow-jump
v-model="jumpVisible"
:process-definition-id="task.processDefinitionId"
:process-instance-id="task.processInstanceId"
:work-id="task.workId"
:deal-user="currentUser"
:assignment-query-params="assignmentQueryParams"
:show-trigger="false"
@before-jump="handleBeforeJump"
@after-jump="handleAfterJump"
@error="handleError"
/>
</template>
保留默认 showTrigger=true 时,点击组件自身按钮即可打开弹窗。与 ui-flow-buttons 配合时,将其设为 false,在按钮组触发 taskJump 或 jump 后把 jumpVisible 设为 true。
2.6 ui-flow-diagram
ui-flow-diagram 是组合组件,上方使用 ui-flow-track-diagram 渲染 BPMN 运行轨迹,下方保留“办理轨迹”标题并使用 ui-flow-track-table 展示办理记录。独立的 ui-flow-track-table 本身不包含标题。父容器必须有明确高度,否则流程图可能看起来是一片空白。
1) 属性定义(Properties)
| 参数 | 说明 | 类型 | 必填 |
|---|---|---|---|
processDefinitionId |
流程定义 ID,用于下载 BPMN XML | string |
是 |
processInstanceId |
流程实例 ID,用于查询运行状态和轨迹 | string |
是 |
2) 事件定义(Events)
| 事件名称 | 回调参数 | 说明 |
|---|---|---|
loaded |
— | BPMN、运行状态和轨迹全部加载并渲染完成 |
error |
error: unknown |
任一加载或渲染步骤失败 |
3) 方法定义(Methods)
| 名称 | 类型 | 说明 |
|---|---|---|
refresh() |
Method | 重新加载 BPMN、运行状态和办理轨迹 |
viewer |
ShallowRef | bpmn-js Viewer 实例 |
trackData |
Ref | 办理轨迹数据 |
4) 节点颜色
| 状态 | 颜色 | 说明 |
|---|---|---|
当前环节 executing |
#ffd37e |
正在办理 |
| 已办理节点 / StartEvent | #98e5b5 |
已办理或开始节点 |
| EndEvent | #f14b12 |
结束节点 |
| 其余 Task | #eee |
未办理节点 |
5) 组件示例
<script setup lang="ts">
import { ref } from 'vue'
import { FlowDiagram } from '@leadal/flowstream-ui-plus'
const diagramRef = ref<InstanceType<typeof FlowDiagram>>()
</script>
<template>
<div class="diagram-container">
<ui-flow-diagram
ref="diagramRef"
:process-definition-id="task.processDefinitionId"
:process-instance-id="task.processInstanceId"
@loaded="handleDiagramLoaded"
@error="handleError"
/>
</div>
</template>
<style scoped>
.diagram-container {
height: 700px;
}
</style>
任务流转后可调用 diagramRef.value?.refresh() 刷新节点颜色和办理轨迹。
6) 独立使用轨迹流程图或轨迹表格
业务页面只需要其中一部分时,可以按需引入两个拆分组件:
<script setup lang="ts">
import { ref } from 'vue'
import {
FlowTrackDiagram,
FlowTrackTable,
} from '@leadal/flowstream-ui-plus'
const trackDiagramRef = ref<InstanceType<typeof FlowTrackDiagram>>()
const trackTableRef = ref<InstanceType<typeof FlowTrackTable>>()
</script>
<template>
<div style="height: 420px">
<ui-flow-track-diagram
ref="trackDiagramRef"
:process-definition-id="task.processDefinitionId"
:process-instance-id="task.processInstanceId"
@error="handleError"
/>
</div>
<div style="height: 360px">
<ui-flow-track-table
ref="trackTableRef"
:process-instance-id="task.processInstanceId"
@error="handleError"
/>
</div>
</template>
FlowTrackDiagram 公开 refresh()、viewer 和 viewState;FlowTrackTable 是不带标题、折叠按钮和额外内边距的纯表格,公开 refresh() 和 trackData。两个组件都提供 loaded、error 事件,且父容器均应设置明确高度。
2.7 ui-flow-definition-preview
ui-flow-definition-preview 用于只读预览流程定义。组件只获取并渲染 BPMN XML,不查询流程实例状态和办理轨迹。父容器必须有明确高度。
1) 属性定义(Properties)
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
processDefinitionId |
已发布的流程定义 ID;未传 bpmnXml 时必填 |
string |
'' |
bpmnXml |
直接预览 BPMN XML,传入后优先于 processDefinitionId |
string |
'' |
fitViewport |
加载及容器尺寸变化后是否自动适应可视区域 | boolean |
true |
2) 事件定义(Events)
| 事件名称 | 回调参数 | 说明 |
|---|---|---|
loaded |
— | BPMN XML 加载并渲染完成 |
error |
error: unknown |
下载或渲染流程定义失败 |
3) 方法定义(Methods)
| 名称 | 说明 |
|---|---|
refresh() |
重新下载或读取 XML 并渲染流程定义 |
fitViewport() |
立即将流程图缩放到适合当前容器 |
viewer |
bpmn-js Viewer 实例 |
4) 已发布流程定义示例
<template>
<div class="preview-container">
<ui-flow-definition-preview
:process-definition-id="processDefinitionId"
@loaded="handleLoaded"
@error="handleError"
/>
</div>
</template>
<style scoped>
.preview-container {
width: 100%;
height: 600px;
}
</style>
5) 未发布 XML 预览示例
<ui-flow-definition-preview :bpmn-xml="modelerXml" />
同时传入 bpmnXml 和 processDefinitionId 时,组件直接渲染 bpmnXml,不会调用 BPMN 下载接口。
3. 请求与错误处理
3.1 成功响应
组件将服务端 code 为 0 或 200 的响应视为成功。其他 code 会被转换为 Error,错误信息优先读取 msg,其次读取 message。
3.2 认证
通过全量注册参数或 configureWorkflow() 设置 getToken。返回非空 token 时,请求头会写入:
Authorization: <token>
3.3 常见排查
| 现象 | 优先检查 |
|---|---|
请求出现 Cannot POST /api/... |
本地代理是否配置、是否需要移除 /api,以及 baseURL 是否只在测试环境设为 /api |
| 点击发送没有反应 | 是否传入了 workId,或可用于自动解析的 processInstanceId + dealUserId |
| 提示缺少流程定义或节点信息 | 待办数据是否包含 processDefinitionId、processInstanceId 和 activityId |
sendRef.open is not a function |
是否引用了当前 Vue3 包的完整 FlowSend;推荐改用 v-model 打开 |
| 办毕成功后页面无反馈 | 是否监听 ui-flow-buttons 的 after-action 并提示、刷新列表 |
| 流程图空白 | 父容器是否有明确高度,流程定义 ID、流程实例 ID 和 BPMN 下载接口是否正确 |
| 发送人显示错误 | Grid 列必须使用 assigneesNames,不是 assignees |
3.4 任务发送请求结构
ui-flow-send 最终向 /flowstream/server/task/event/send 提交:
{
"workId": "工作项ID",
"flowNodeAssignees": [
{
"activityId": "下一环节ID",
"assignees": [
{
"name": "用户ID",
"userId": "用户ID"
}
]
}
],
"variables": {},
"opinion": "同意"
}
发送必须使用当前有效工作项的 workId。若服务端返回 the current work is null!,应重新查询当前用户待办,并使用最新工作项 ID,不能重复发送已流转或已失效的工作项。
4. 获取第一个办理节点
已知流程定义 ID 时,可获取第一个需要人工办理的节点:
import {
getFirstHandleNodes,
type FlowNode,
} from '@leadal/flowstream-ui-plus'
const result = await getFirstHandleNodes({
processDefinitionId,
})
const firstHandleNodes: FlowNode[] = result.data || []
getFirstHandleNodes() 调用 POST /flowstream/server/model/event/get/firsthandle。服务端会跳过开始事件、网关和中间事件,返回各分支上遇到的第一个 USER_TASK,因此结果必须按数组处理;纯自动流程返回空数组,不属于失败。
flowStartNodeList(args) 暂时保留为兼容别名,但已切换到 /firsthandle。跳转组件内部使用的 startNodes() 仍调用 /event/get/usertasks,其行为不受影响。
5. 快速启动流程
流程发起不再要求业务模板放置组件,统一调用默认导出的命令式服务。内部会完成首办节点解析、快速启动、下一节点解析、候选办理人查询并自动打开发送弹窗。
import flowstream from '@leadal/flowstream-ui-plus'
async function submitBusiness() {
const result = await flowstream.getRuntimeService().start({
processDefinitionId,
draftUserId: currentUser.id,
draftUserName: currentUser.name,
business: {
key: `borrow:${borrowId}`,
name: borrowTitle,
},
variables,
assignmentQueryParams: {
projectId: currentProject.id,
tenantId: currentTenant.id,
},
async onBeforeStart(startArgs) {
// 可执行同步校验,也可以 await 业务项目自己的表单弹窗。
const formData = await openBusinessForm()
if (!formData) return false
startArgs.variables = { ...startArgs.variables, ...formData }
return true
},
async onBeforeSend(context) {
// false:实例已经创建,但不打开审批人选择弹窗。
return validateBeforeSend(context)
},
onStarted(result) {
saveFlowRelation(result.processInstanceId)
},
onAfterSend({ sendData }) {
// 下一节点审批人:sendData.flowNodeAssignees[].assignees[].userId
refreshBusinessList()
},
onClose() {
// 未发送就关闭弹窗时,运行时服务会撤销刚创建的流程实例。
},
onError(error) {
console.error(error.phase, error.message)
},
})
if (result === false) return
}
onBeforeStart 在首办节点查询和 quickStart 之前执行;返回 false 时 start() 返回 false,不会创建流程实例。onBeforeSend 在实例创建成功后、发送弹窗打开前执行;返回 false 时 start() 仍返回流程实例结果,但不会弹窗,并保留当前会话。之后调用 await flowstream.getRuntimeService().open() 会重新执行 onBeforeSend,通过后才打开弹窗;若决定放弃,调用 close() 会撤销该实例并释放会话。
两个前置钩子都支持 boolean | Promise<boolean>。因此业务项目需要“弹表单、校验通过后再启动”时,应让业务弹窗封装成 Promise,而不是由流程组件识别业务字段:
let finishBeforeStart: ((allowed: boolean) => void) | undefined
function waitForBusinessForm() {
businessDialogVisible.value = true
return new Promise<boolean>(resolve => {
finishBeforeStart = resolve
})
}
async function confirmBusinessForm() {
const valid = await businessFormRef.value?.validate().catch(() => false)
if (!valid) return
businessDialogVisible.value = false
finishBeforeStart?.(true)
finishBeforeStart = undefined
}
function cancelBusinessForm() {
businessDialogVisible.value = false
finishBeforeStart?.(false)
finishBeforeStart = undefined
}
await flowstream.getRuntimeService().start({
processDefinitionId,
draftUserId: currentUser.id,
draftUserName: currentUser.name,
onBeforeStart: waitForBusinessForm,
})
业务弹窗通过右上角关闭、路由离开或组件卸载时也必须 resolve(false),避免 start() 一直处于等待状态。singleAssignee 默认为 false,发送弹窗采用下一节点接口返回的 dealType;显式设置为 true 时会无视节点办理方式并强制单选。也可在启动参数中传入 dialogTitle、dialogWidth、defaultOpinion、bpmnXml 和 assignmentQueryParams。
quickStart()、getFirstHandleNodes()、getSatisfiedSuccedingFlowNodes()、nextSendNode()、nodeAssistant() 和 sendTask() 仍作为底层 API 导出,供组件内部及高级扩展使用;普通业务项目应优先调用 flowstream.getRuntimeService().start(),不要自行复制流程编排。
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.0.15 | ^3.4.0 | Proprietary | |
| 0.0.14 | ^3.4.0 | Proprietary | |
| 0.0.13 | ^3.4.0 | Proprietary | |
| 0.0.12 | ^3.4.0 | Proprietary | |
| 0.0.11 | ^3.4.0 | Proprietary | |
| 0.0.10 | ^3.4.0 | Proprietary | |
| 0.0.9 | ^3.4.0 | Proprietary | |
| 0.0.8 | ^3.4.0 | Proprietary | |
| 0.0.7 | ^3.4.0 | Proprietary | |
| 0.0.6 | ^3.4.0 | Proprietary | |
| 0.0.5 | ^3.4.0 | Proprietary | |
| 0.0.4 | ^3.4.0 | Proprietary | |
| 0.0.3 | ^3.4.0 | Proprietary | |
| 0.0.2 | ^3.4.0 | Proprietary | |
| 0.0.1 | ^3.4.0 | Proprietary |