@leadal/flowstream-ui-plus 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # FlowStream Vue3 前端组件接入指南
2
2
 
3
- FlowStream 前端运行时组件库的 npm 包名统一为 **`@leadal/flowstream-ui-plus`**。组件库基于 Vue 3 和 Element Plus,封装工作项列表、流程操作、任务发送、任务跳转、流程图及办理轨迹等能力。
3
+ FlowStream 前端运行时组件库的 npm 包名统一为 **`@leadal/flowstream-ui-plus`**。组件库基于 Vue 3 和 Element Plus,封装流程发起、工作项列表、流程操作、任务发送、任务跳转、流程图及办理轨迹等能力。
4
4
 
5
- 组件库只公开 **5 个主组件 + 1 个子组件**。流程设计与 Editor 由工作流程引擎内部提供,不在本组件库中导出。
5
+ 组件库公开 **5 个主组件 + 1 个子组件**,以及命令式服务 `flowstream.runtimeService`。流程设计与 Editor 由工作流程引擎内部提供,不在本组件库中导出。
6
6
 
7
7
  > 目录
8
8
  >
@@ -15,6 +15,8 @@ FlowStream 前端运行时组件库的 npm 包名统一为 **`@leadal/flowstream
15
15
  > 5. [ui-flow-jump](#25-ui-flow-jump)
16
16
  > 6. [ui-flow-diagram](#26-ui-flow-diagram)
17
17
  > 3. [请求与错误处理](#3-请求与错误处理)
18
+ > 4. [获取第一个办理节点](#4-获取第一个办理节点)
19
+ > 5. [快速启动流程](#5-快速启动流程)
18
20
 
19
21
  ---
20
22
 
@@ -57,7 +59,7 @@ app.use(FlowstreamUIPlus, {
57
59
  app.mount('#app')
58
60
  ```
59
61
 
60
- 全量注册后,可直接使用 `ui-flow-buttons`、`ui-flow-button`、`ui-flow-grid`、`ui-flow-send`、`ui-flow-jump` 和 `ui-flow-diagram` 全局标签。
62
+ 全量注册后,可直接使用 `ui-flow-buttons`、`ui-flow-button`、`ui-flow-grid`、`ui-flow-send`、`ui-flow-jump` 和 `ui-flow-diagram` 全局标签。流程发起调用默认导出的 `flowstream.getRuntimeService().start()`。
61
63
 
62
64
  ### 1.4 按需引入
63
65
 
@@ -106,7 +108,7 @@ configureWorkflow({
106
108
  | `UiFlowJump` | `ui-flow-jump` | 流程任务跳转能力 |
107
109
  | `UiFlowDiagram` | `ui-flow-diagram` | BPMN 流程图、运行状态和办理轨迹 |
108
110
 
109
- 除组件外,包入口还导出 `configureWorkflow`、请求实例 `workflowHttp`、类型定义以及流程 API 方法(例如 `startDraft`、`startNodes`)。
111
+ 除组件外,包入口还导出 `configureWorkflow`、请求实例 `workflowHttp`、类型定义以及流程 API 方法(例如 `startDraft`、`quickStart`、`getFirstHandleNodes`、`startNodes`)。
110
112
 
111
113
  > `Editor`、内部基础表格、轨迹表格和图标组件不是公共导出,不要从 `@leadal/flowstream-ui-plus` 引入。
112
114
 
@@ -114,7 +116,7 @@ configureWorkflow({
114
116
 
115
117
  ### 2.1 ui-flow-buttons
116
118
 
117
- `ui-flow-buttons` 根据 `workId` 调用操作定义接口加载当前工作项可用按钮。可由组件独立完成的动作会弹出确认框并请求后端;需要业务页面参与的动作通过 `execute-action` 交给宿主处理。
119
+ `ui-flow-buttons` 根据当前工作项加载可用操作。优先使用显式传入的 `workId`;业务页面只有流程实例时,也可以传 `processInstanceId + dealUserId`,组件会自行查询并解析该用户的当前待办。发送和跳转默认由组件内部打开完整弹窗,业务页面不需要直接调用流程引擎接口;保存、启动等业务表单相关动作仍通过 `execute-action` 交给宿主处理。
118
120
 
119
121
  | action | 处理方式 |
120
122
  | --------------------------------------------------- | --------------------------------------------- |
@@ -125,26 +127,41 @@ configureWorkflow({
125
127
  | `terminate` | 确认后终止流程 |
126
128
  | `taskComplete` | 确认后办毕 |
127
129
  | `taskRollback` | 确认后退回 |
128
- | `save` / `start` / `taskSend` / `jump` / `taskJump` | 触发 `execute-action`,由宿主处理 |
130
+ | `taskClaim` | 传入 `dealUserId` 后执行任务拾取 |
131
+ | `turnBefore` / `taskTurnBefore` | 打开机构人员单选弹窗并执行前加签 |
132
+ | `turnAfter` / `taskTurnAfter` | 打开机构人员单选弹窗并执行后加签 |
133
+ | `taskSend` | 默认打开内置发送弹窗 |
134
+ | `jump` / `taskJump` | 默认打开内置跳转弹窗 |
135
+ | `save` / `start` | 触发 `execute-action`,由宿主处理 |
129
136
  | 其他未内置动作 | 触发 `execute-action`,由宿主处理 |
130
137
 
131
138
  #### 1) 属性定义(Properties)
132
139
 
133
- | 参数 | 说明 | 类型 | 必填 | 默认值 |
134
- | ------------------- | ----------------------------------- | -------------------------------------- | ---- | ------ |
135
- | `workId` | 当前工作项 ID,用于加载和执行操作 | `string` | | — |
136
- | `processInstanceId` | 流程实例 ID,挂起等动作会使用 | `string` | | — |
137
- | `beforeAction` | 动作执行前钩子;返回 `false` 可中断 | `(action, context) => boolean \| void` | 否 | — |
138
- | `afterAction` | 内置动作成功后的函数型钩子 | `(action, result) => void` | 否 | — |
139
-
140
- `beforeAction` `context` 包含 `action`、`workId` `processInstanceIds`。
140
+ | 参数 | 说明 | 类型 | 必填 | 默认值 |
141
+ | --------------------- | ------------------------------------------------ | ------------------------------------------------- | ---- | ------ |
142
+ | `workId` | 当前工作项 ID;未传时可自动解析 | `string` | | — |
143
+ | `processInstanceId` | 流程实例 ID;自动解析待办时必需 | `string` | 条件 | — |
144
+ | `processDefinitionId` | 流程定义 ID;发送和跳转时使用 | `string` | 否 | — |
145
+ | `taskId` | 当前任务实例 ID;前/后加签时使用,可自动解析 | `string` | 否 | — |
146
+ | `dealUserId` | 当前用户 ID;自动解析待办和拾取任务时使用 | `string` | 条件 | — |
147
+ | `dealUserName` | 当前用户名称 | `string` | 否 | — |
148
+ | `variables` | 发送、办毕时提交的流程变量 | `Record<string, unknown>` | 否 | `{}` |
149
+ | `autoResolveWork` | 未传 `workId` 时自动查询当前用户待办 | `boolean` | 否 | `true` |
150
+ | `autoHandleDialogs` | 在组件内部处理发送和跳转弹窗 | `boolean` | 否 | `true` |
151
+ | `forceSingleAssignee` | 每个下一节点仅允许选择一名办理人 | `boolean` | 否 | `false`|
152
+ | `dialogZIndex` | 内置弹窗固定层级;未传时自动高于当前 Drawer/Dialog | `number` | 否 | 自动 |
153
+ | `beforeAction` | 动作执行前钩子;返回 `false` 可中断,支持异步 | `(action, context) => boolean \| void \| Promise` | 否 | — |
154
+ | `afterAction` | 流程动作成功后的函数型钩子 | `(action, result, context) => void` | 否 | — |
155
+
156
+ `context` 包含 `workId`、流程/任务/节点 ID 和原始 `workData`;发送、跳转完成后还包含实际提交的 `requestData`。
141
157
 
142
158
  #### 2) 事件定义(Events)
143
159
 
144
160
  | 事件名称 | 回调参数 | 说明 |
145
161
  | ---------------- | ------------------------------------- | ------------------------------------------------------ |
146
- | `execute-action` | `action: string` | 需要宿主处理的动作;发送操作对应 `taskSend` |
147
- | `after-action` | `action: string, result: ApiResponse` | 内置动作成功后触发,可用于成功提示、返回列表和刷新数据 |
162
+ | `execute-action` | `action, context` | 需要宿主处理的自定义动作 |
163
+ | `after-action` | `action, result, context` | 流程动作成功后触发,可用于同步业务状态和刷新列表 |
164
+ | `work-resolved` | `context` | 自动解析当前用户待办成功后触发 |
148
165
  | `error` | `error: unknown` | 内置操作失败时触发;用户取消确认框不会触发 |
149
166
 
150
167
  #### 3) 方法定义(Methods)
@@ -152,6 +169,7 @@ configureWorkflow({
152
169
  | 方法 | 参数 | 返回 | 说明 |
153
170
  | ----------------------- | -------------------- | ------------------------------- | ------------------------ |
154
171
  | `getAvailableActions()` | — | `Promise<WorkflowActionItem[]>` | 重新加载可用按钮 |
172
+ | `resolveCurrentWork()` | — | `Promise<WorkflowActionContext>`| 自动解析当前待办 |
155
173
  | `executeAction(button)` | `WorkflowActionItem` | `Promise<void>` | 按按钮定义执行或分发动作 |
156
174
 
157
175
  #### 4) 插槽定义(Slots)
@@ -166,8 +184,11 @@ configureWorkflow({
166
184
 
167
185
  ```vue
168
186
  <ui-flow-buttons
169
- :work-id="task.workId"
170
187
  :process-instance-id="task.processInstanceId"
188
+ :process-definition-id="task.processDefinitionId"
189
+ :deal-user-id="loginUser.id"
190
+ :deal-user-name="loginUser.name"
191
+ force-single-assignee
171
192
  :before-action="validateBeforeAction"
172
193
  @execute-action="handleFlowAction"
173
194
  @after-action="handleAfterAction"
@@ -195,7 +216,7 @@ function handleAfterAction(action: string, result: unknown) {
195
216
  | `type` | 预设动作类型,决定默认文字和图标 | `string` | — |
196
217
  | `label` | 覆盖预设按钮文字 | `string` | — |
197
218
 
198
- 内置类型包括 `save`、`start`、`revocation`、`taskWithdraw`、`taskRecyle`、`hang`、`restore`、`terminate`、`jump`、`taskJump`、`taskComplete`、`taskSend` 和 `taskRollback`。
219
+ 内置类型包括 `save`、`start`、`revocation`、`taskWithdraw`、`taskRecyle`、`hang`、`restore`、`terminate`、`jump`、`taskJump`、`taskComplete`、`taskSend`、`taskRollback`、`taskClaim`、`turnBefore`、`taskTurnBefore`、`turnAfter` 和 `taskTurnAfter`。
199
220
 
200
221
  #### 2) 事件定义(Events)
201
222
 
@@ -326,6 +347,8 @@ function handleWork({ action, workData }: {
326
347
  - 填写审批意见;
327
348
  - 确认后调用任务发送接口,成功后关闭弹窗并提示“发送成功”。
328
349
 
350
+ 办理人候选数据通过 `POST /flowstream/server/assignment/event/query` 加载。
351
+
329
352
  #### 1) 属性定义(Properties)
330
353
 
331
354
  | 参数 | 说明 | 类型 | 必填 | 默认值 |
@@ -341,7 +364,9 @@ function handleWork({ action, workData }: {
341
364
  | `showTrigger` | 是否显示组件自身的发送按钮 | `boolean` | 否 | `true` |
342
365
  | `dialogTitle` | 弹窗标题 | `string` | 否 | `'发送'` |
343
366
  | `dialogWidth` | 弹窗宽度 | `string` | 否 | `'1200px'` |
367
+ | `zIndex` | 固定弹层层级;未传时自动高于当前 Drawer/Dialog | `number` | 否 | 自动 |
344
368
  | `defaultOpinion` | 每次打开弹窗时的默认意见 | `string` | 否 | `''` |
369
+ | `forceSingleAssignee` | 是否强制每个下一节点只能选择一个办理人 | `boolean` | 否 | `false` |
345
370
 
346
371
  #### 2) 事件定义(Events)
347
372
 
@@ -373,7 +398,7 @@ function handleWork({ action, workData }: {
373
398
 
374
399
  #### 4) 组件示例
375
400
 
376
- `ui-flow-buttons` 配合时,隐藏 FlowSend 自身按钮,并通过 `v-model` 打开完整发送弹窗:
401
+ `ui-flow-buttons` 已默认内置 FlowSend。以下手动组合方式仅用于需要完全自定义发送弹窗编排的场景,此时应关闭自动弹窗:
377
402
 
378
403
  ```vue
379
404
  <script setup lang="ts">
@@ -396,6 +421,7 @@ function handleAfterSend() {
396
421
  <ui-flow-buttons
397
422
  :work-id="task.workId"
398
423
  :process-instance-id="task.processInstanceId"
424
+ :auto-handle-dialogs="false"
399
425
  @execute-action="handleFlowAction"
400
426
  />
401
427
 
@@ -438,6 +464,7 @@ function handleAfterSend() {
438
464
  | `showTrigger` | 是否显示组件自带跳转按钮,默认 `true` | `boolean` | 否 |
439
465
  | `dialogTitle` | 弹窗标题,默认“跳转” | `string` | 否 |
440
466
  | `dialogWidth` | 弹窗宽度,默认 `960px` | `string` | 否 |
467
+ | `zIndex` | 固定弹层层级;未传时自动高于当前 Drawer/Dialog | `number` | 否 |
441
468
 
442
469
  #### 2) 事件定义(Events)
443
470
 
@@ -579,8 +606,8 @@ Authorization: <token>
579
606
  | 现象 | 优先检查 |
580
607
  | -------------------------------- | ------------------------------------------------------------ |
581
608
  | 请求出现 `Cannot POST /api/...` | 本地代理是否配置、是否需要移除 `/api`,以及 `baseURL` 是否只在测试环境设为 `/api` |
582
- | 点击发送没有反应 | `FlowButtons` 是否监听 `execute-action`,`taskSend` 时是否把 FlowSend 的 `v-model` 设为 `true` |
583
- | 提示缺少流程定义或节点信息 | Grid 行数据是否包含 `processDefinitionId`、`processInstanceId`、`activityId`、`workId` |
609
+ | 点击发送没有反应 | 是否传入了 `workId`,或可用于自动解析的 `processInstanceId + dealUserId` |
610
+ | 提示缺少流程定义或节点信息 | 待办数据是否包含 `processDefinitionId`、`processInstanceId` 和 `activityId` |
584
611
  | `sendRef.open is not a function` | 是否引用了当前 Vue3 包的完整 FlowSend;推荐改用 `v-model` 打开 |
585
612
  | 办毕成功后页面无反馈 | 是否监听 `ui-flow-buttons` 的 `after-action` 并提示、刷新列表 |
586
613
  | 流程图空白 | 父容器是否有明确高度,流程定义 ID、流程实例 ID 和 BPMN 下载接口是否正确 |
@@ -609,4 +636,114 @@ Authorization: <token>
609
636
  }
610
637
  ```
611
638
 
612
- 发送必须使用当前有效工作项的 `workId`。若服务端返回 `the current work is null!`,应重新查询当前用户待办,并使用最新工作项 ID,不能重复发送已流转或已失效的工作项。
639
+ 发送必须使用当前有效工作项的 `workId`。若服务端返回 `the current work is null!`,应重新查询当前用户待办,并使用最新工作项 ID,不能重复发送已流转或已失效的工作项。
640
+
641
+ ---
642
+
643
+ ## 4. 获取第一个办理节点
644
+
645
+ 已知流程定义 ID 时,可获取第一个需要人工办理的节点:
646
+
647
+ ```ts
648
+ import {
649
+ getFirstHandleNodes,
650
+ type FlowNode,
651
+ } from '@leadal/flowstream-ui-plus'
652
+
653
+ const result = await getFirstHandleNodes({
654
+ processDefinitionId,
655
+ })
656
+ const firstHandleNodes: FlowNode[] = result.data || []
657
+ ```
658
+
659
+ `getFirstHandleNodes()` 调用 `POST /flowstream/server/model/event/get/firsthandle`。服务端会跳过开始事件、网关和中间事件,返回各分支上遇到的第一个 `USER_TASK`,因此结果必须按数组处理;纯自动流程返回空数组,不属于失败。
660
+
661
+ `flowStartNodeList(args)` 暂时保留为兼容别名,但已切换到 `/firsthandle`。跳转组件内部使用的 `startNodes()` 仍调用 `/event/get/usertasks`,其行为不受影响。
662
+
663
+ ---
664
+
665
+ ## 5. 快速启动流程
666
+
667
+ 流程发起不再要求业务模板放置组件,统一调用默认导出的命令式服务。内部会完成首办节点解析、快速启动、下一节点解析、候选办理人查询并自动打开发送弹窗。
668
+
669
+ ```ts
670
+ import flowstream from '@leadal/flowstream-ui-plus'
671
+
672
+ async function submitBusiness() {
673
+ const result = await flowstream.getRuntimeService().start({
674
+ processDefinitionId,
675
+ draftUserId: currentUser.id,
676
+ draftUserName: currentUser.name,
677
+ business: {
678
+ key: `borrow:${borrowId}`,
679
+ name: borrowTitle,
680
+ },
681
+ variables,
682
+ async onBeforeStart(startArgs) {
683
+ // 可执行同步校验,也可以 await 业务项目自己的表单弹窗。
684
+ const formData = await openBusinessForm()
685
+ if (!formData) return false
686
+ startArgs.variables = { ...startArgs.variables, ...formData }
687
+ return true
688
+ },
689
+ async onBeforeSend(context) {
690
+ // false:实例已经创建,但不打开审批人选择弹窗。
691
+ return validateBeforeSend(context)
692
+ },
693
+ onStarted(result) {
694
+ saveFlowRelation(result.processInstanceId)
695
+ },
696
+ onAfterSend({ sendData }) {
697
+ // 下一节点审批人:sendData.flowNodeAssignees[].assignees[].userId
698
+ refreshBusinessList()
699
+ },
700
+ onClose() {
701
+ // 未发送就关闭弹窗时,运行时服务会撤销刚创建的流程实例。
702
+ },
703
+ onError(error) {
704
+ console.error(error.phase, error.message)
705
+ },
706
+ })
707
+ if (result === false) return
708
+ }
709
+ ```
710
+
711
+ `onBeforeStart` 在首办节点查询和 `quickStart` 之前执行;返回 `false` 时 `start()` 返回 `false`,不会创建流程实例。`onBeforeSend` 在实例创建成功后、发送弹窗打开前执行;返回 `false` 时 `start()` 仍返回流程实例结果,但不会弹窗,并保留当前会话。之后调用 `await flowstream.getRuntimeService().open()` 会重新执行 `onBeforeSend`,通过后才打开弹窗;若决定放弃,调用 `close()` 会撤销该实例并释放会话。
712
+
713
+ 两个前置钩子都支持 `boolean | Promise<boolean>`。因此业务项目需要“弹表单、校验通过后再启动”时,应让业务弹窗封装成 Promise,而不是由流程组件识别业务字段:
714
+
715
+ ```ts
716
+ let finishBeforeStart: ((allowed: boolean) => void) | undefined
717
+
718
+ function waitForBusinessForm() {
719
+ businessDialogVisible.value = true
720
+ return new Promise<boolean>(resolve => {
721
+ finishBeforeStart = resolve
722
+ })
723
+ }
724
+
725
+ async function confirmBusinessForm() {
726
+ const valid = await businessFormRef.value?.validate().catch(() => false)
727
+ if (!valid) return
728
+ businessDialogVisible.value = false
729
+ finishBeforeStart?.(true)
730
+ finishBeforeStart = undefined
731
+ }
732
+
733
+ function cancelBusinessForm() {
734
+ businessDialogVisible.value = false
735
+ finishBeforeStart?.(false)
736
+ finishBeforeStart = undefined
737
+ }
738
+
739
+ await flowstream.getRuntimeService().start({
740
+ processDefinitionId,
741
+ draftUserId: currentUser.id,
742
+ draftUserName: currentUser.name,
743
+ onBeforeStart: waitForBusinessForm,
744
+ })
745
+ ```
746
+
747
+ 业务弹窗通过右上角关闭、路由离开或组件卸载时也必须 `resolve(false)`,避免 `start()` 一直处于等待状态。`singleAssignee` 默认为 `true`,也可在启动参数中传入 `dialogTitle`、`dialogWidth`、`defaultOpinion` 和 `bpmnXml`。
748
+
749
+ `quickStart()`、`getFirstHandleNodes()`、`nextSendNode()`、`nodeAssistant()` 和 `sendTask()` 仍作为底层 API 导出,供组件内部及高级扩展使用;普通业务项目应优先调用 `flowstream.getRuntimeService().start()`,不要自行复制流程编排。