@jari-ace/element-plus-component 0.6.2 → 0.6.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/dist/components/flowShell/FlowFormShell.vue.d.ts +6 -0
- package/dist/components/flowShell/FlowFormShell.vue.d.ts.map +1 -1
- package/dist/components/flowShell/FlowFormShell.vue.js +329 -96
- package/dist/components/flowShell/FlowFormShell.vue.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.js +9064 -8947
- package/lib/index.umd.cjs +36 -36
- package/package.json +2 -2
- package/packages/components/flowShell/FlowFormShell.vue +238 -30
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jari-ace/element-plus-component",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.3",
|
|
5
5
|
"main": "lib/index.umd.cjs",
|
|
6
6
|
"module": "lib/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"pretty-bytes": "^7.1.0",
|
|
28
28
|
"vue-pdf-embed": "^2.1.3",
|
|
29
29
|
"vue-router": "^5.0.1",
|
|
30
|
-
"@jari-ace/app-bolts": "0.7.
|
|
30
|
+
"@jari-ace/app-bolts": "0.7.11"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/lodash-es": "^4.17.12",
|
|
@@ -52,12 +52,9 @@
|
|
|
52
52
|
</template>
|
|
53
53
|
</el-result>
|
|
54
54
|
</div>
|
|
55
|
-
<div v-else
|
|
55
|
+
<div v-else>
|
|
56
56
|
<slot name="default" :flowParam="flowFormParam"></slot>
|
|
57
57
|
</div>
|
|
58
|
-
<div class="no-form-tip" v-else>
|
|
59
|
-
<el-empty description="暂无表单内容" />
|
|
60
|
-
</div>
|
|
61
58
|
</div>
|
|
62
59
|
</section>
|
|
63
60
|
|
|
@@ -107,19 +104,53 @@
|
|
|
107
104
|
<ja-button @click="handleForward" type="danger" shortcut="Ctrl+F" v-if="showForwardButton"
|
|
108
105
|
:tooltip="'保存并' + (flowFormParam?.taskInstance ? '结束当前工作步骤办理' : '发起工作')" :loading="saving"
|
|
109
106
|
:disabled="saving">{{
|
|
110
|
-
flowFormParam?.taskInstance ? "办理结束" : "
|
|
107
|
+
flowFormParam?.taskInstance ? "办理结束" : "发起流程" }}</ja-button>
|
|
111
108
|
<slot name="footer" :flowParam="flowFormParam"></slot>
|
|
112
109
|
</footer>
|
|
113
110
|
</div>
|
|
111
|
+
|
|
112
|
+
<!-- 流程选择对话框 -->
|
|
113
|
+
<el-dialog
|
|
114
|
+
v-model="flowSelectionDialogVisible"
|
|
115
|
+
title="选择流程"
|
|
116
|
+
width="500px"
|
|
117
|
+
:close-on-click-modal="false"
|
|
118
|
+
:show-close="false"
|
|
119
|
+
align-center
|
|
120
|
+
append-to-body
|
|
121
|
+
>
|
|
122
|
+
<el-scrollbar max-height="50vh">
|
|
123
|
+
<div class="flow-selection-list">
|
|
124
|
+
<el-card
|
|
125
|
+
v-for="flow in selectableFlows"
|
|
126
|
+
:key="flow.flowKey"
|
|
127
|
+
class="flow-selection-card"
|
|
128
|
+
shadow="hover"
|
|
129
|
+
@click="handleSelectFlow(flow)"
|
|
130
|
+
>
|
|
131
|
+
<div class="flow-card-content">
|
|
132
|
+
<div class="flow-caption">{{ flow.flowCaption }}</div>
|
|
133
|
+
<div class="flow-key">{{ flow.flowKey }}</div>
|
|
134
|
+
</div>
|
|
135
|
+
<el-icon><ArrowRight /></el-icon>
|
|
136
|
+
</el-card>
|
|
137
|
+
</div>
|
|
138
|
+
</el-scrollbar>
|
|
139
|
+
<template #footer>
|
|
140
|
+
<span class="dialog-footer">
|
|
141
|
+
<el-button @click="handleCancelFlowSelection">取消</el-button>
|
|
142
|
+
</span>
|
|
143
|
+
</template>
|
|
144
|
+
</el-dialog>
|
|
114
145
|
</div>
|
|
115
146
|
</template>
|
|
116
147
|
|
|
117
148
|
<script setup lang="ts" generic="T extends Record<string, any>">
|
|
118
149
|
import { ref, watch, computed, nextTick } from 'vue'
|
|
119
|
-
import { useTaskQueryApi, useFlowDefinitionApi, type FlowFormParamDto } from '@jari-ace/app-bolts'
|
|
150
|
+
import { useTaskQueryApi, useFlowDefinitionApi, type FlowFormParamDto, type ProjectedFlowDefinitionDto } from '@jari-ace/app-bolts'
|
|
120
151
|
import type { FlowProcessRequest, TaskInstanceDto } from '@jari-ace/app-bolts'
|
|
121
152
|
import { createAxiosWithoutCache, useLoading } from '@jari-ace/app-bolts'
|
|
122
|
-
import { ElMessage, ElTag, ElCard, ElButton, ElTimeline, ElTimelineItem, ElEmpty, ElIcon, ElResult } from 'element-plus'
|
|
153
|
+
import { ElMessage, ElTag, ElCard, ElButton, ElTimeline, ElTimelineItem, ElEmpty, ElIcon, ElResult, ElDialog, ElScrollbar } from 'element-plus'
|
|
123
154
|
import { JaButton } from '../button'
|
|
124
155
|
import { JaUserInfoTag } from '../userTag'
|
|
125
156
|
import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue'
|
|
@@ -141,6 +172,10 @@ const props = withDefaults(defineProps<{
|
|
|
141
172
|
* 流程定义Key
|
|
142
173
|
*/
|
|
143
174
|
flowKey?: string
|
|
175
|
+
/**
|
|
176
|
+
* 业务标签,当 flowKey 为空时,根据 bizTag 查找流程
|
|
177
|
+
*/
|
|
178
|
+
bizTag?: string
|
|
144
179
|
/**
|
|
145
180
|
* 开始节点Key
|
|
146
181
|
*/
|
|
@@ -169,14 +204,20 @@ const props = withDefaults(defineProps<{
|
|
|
169
204
|
* 侧边栏默认是否收起
|
|
170
205
|
*/
|
|
171
206
|
defaultCollapsed?: boolean
|
|
207
|
+
/**
|
|
208
|
+
* 是否是新表单,如果为 true,则不等待 formId,直接加载流程定义。如果为 false,且没有 taskId,则会等待 formData.flowFormId 有值后再加载。
|
|
209
|
+
*/
|
|
210
|
+
isNewForm: boolean
|
|
172
211
|
}>(), {
|
|
173
212
|
appName: undefined,
|
|
174
213
|
flowKey: undefined,
|
|
214
|
+
bizTag: undefined,
|
|
175
215
|
startNodeKey: undefined,
|
|
176
216
|
taskInstanceId: undefined,
|
|
177
217
|
width: undefined,
|
|
178
218
|
height: undefined,
|
|
179
|
-
defaultCollapsed: false
|
|
219
|
+
defaultCollapsed: false,
|
|
220
|
+
isNewForm: false
|
|
180
221
|
})
|
|
181
222
|
|
|
182
223
|
// 内部状态
|
|
@@ -308,26 +349,59 @@ const getTaskStatus = (state?: number) => {
|
|
|
308
349
|
}
|
|
309
350
|
}
|
|
310
351
|
|
|
352
|
+
const actualFlowKey = ref(props.flowKey)
|
|
353
|
+
const flowSelectionDialogVisible = ref(false)
|
|
354
|
+
const selectableFlows = ref<ProjectedFlowDefinitionDto[]>([])
|
|
355
|
+
const selectableFlowParams = ref<FlowFormParamDto[]>([])
|
|
356
|
+
|
|
311
357
|
// 监听dialogVisible变化
|
|
312
358
|
watch(
|
|
313
359
|
() => dialogVisible.value,
|
|
314
360
|
async (newValue) => {
|
|
315
361
|
resetState()
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
362
|
+
actualFlowKey.value = props.flowKey
|
|
363
|
+
if (newValue) {
|
|
364
|
+
emits('open')
|
|
365
|
+
//等待状态同步
|
|
319
366
|
await nextTick()
|
|
320
|
-
|
|
367
|
+
if (props.taskId) {
|
|
368
|
+
// 场景一:通过 taskId 打开,直接加载
|
|
369
|
+
loadFlowFormParam()
|
|
370
|
+
} else if (props.isNewForm) {
|
|
371
|
+
// 场景二:明确是新表单发起流程,不等待 formId,直接加载流程定义
|
|
372
|
+
loadFlowFormParam()
|
|
373
|
+
} else if (props.formData?.flowFormId) {
|
|
374
|
+
// 场景三:非新表单,且一开始就已经有 formId,直接加载
|
|
375
|
+
loadFlowFormParam()
|
|
376
|
+
}
|
|
377
|
+
// 场景四:非新表单且没有 formId,什么都不做,等待 formData.flowFormId 的 watcher 触发
|
|
321
378
|
} else {
|
|
322
379
|
emits('closed')
|
|
323
380
|
}
|
|
324
381
|
}
|
|
325
382
|
)
|
|
326
383
|
|
|
384
|
+
// 监听 formData 的 flowFormId 变化,用于处理异步加载表单数据的场景
|
|
385
|
+
watch(
|
|
386
|
+
() => props.formData?.flowFormId,
|
|
387
|
+
(newFormId, oldFormId) => {
|
|
388
|
+
// 只有在 dialog 打开的情况下,且从无到有,或者发生了变化,且没有 taskId 的时候,才重新加载流程参数
|
|
389
|
+
if (dialogVisible.value && !props.taskId && !props.isNewForm && newFormId && newFormId !== oldFormId) {
|
|
390
|
+
// 避免重复加载,可以先重置
|
|
391
|
+
resetState()
|
|
392
|
+
actualFlowKey.value = props.flowKey
|
|
393
|
+
loadFlowFormParam()
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
)
|
|
397
|
+
|
|
327
398
|
// 重置状态
|
|
328
399
|
const resetState = () => {
|
|
329
400
|
error.value = ''
|
|
330
401
|
flowFormParam.value = undefined
|
|
402
|
+
selectableFlows.value = []
|
|
403
|
+
selectableFlowParams.value = []
|
|
404
|
+
actualFlowKey.value = undefined
|
|
331
405
|
}
|
|
332
406
|
|
|
333
407
|
// 加载流程表单参数
|
|
@@ -335,28 +409,45 @@ const loadFlowFormParam = async () => {
|
|
|
335
409
|
resetState()
|
|
336
410
|
const formId = props.formData?.flowFormId;
|
|
337
411
|
// 检查参数
|
|
338
|
-
// 必须提供 taskId,或者 appName 和 flowKey
|
|
339
|
-
if (!props.taskId && !(props.appName && props.flowKey)) {
|
|
340
|
-
ElMessage.error('参数错误: 必须提供taskId或appName、flowKey和flowFormId')
|
|
412
|
+
// 必须提供 taskId,或者 appName 和 (flowKey 或 bizTag)
|
|
413
|
+
if (!props.taskId && !(props.appName && (props.flowKey || props.bizTag))) {
|
|
414
|
+
ElMessage.error('参数错误: 必须提供taskId或appName、flowKey/bizTag和flowFormId')
|
|
341
415
|
return
|
|
342
416
|
}
|
|
343
|
-
|
|
344
|
-
try {
|
|
417
|
+
try {
|
|
345
418
|
if (props.taskId) {
|
|
346
419
|
// 优先使用Id
|
|
347
420
|
flowFormParam.value = await taskQueryApi.getTaskInstanceById(props.taskId)
|
|
348
|
-
} else if (formId) {
|
|
421
|
+
} else if (formId && props.flowKey) {
|
|
349
422
|
// 使用appName、flowKey、formId
|
|
350
|
-
|
|
423
|
+
const param = await taskQueryApi.getTaskByFormIdAndAppAndFlowKey(formId, props.appName!, props.flowKey!)
|
|
424
|
+
if (param && param.flowDefinition) {
|
|
425
|
+
flowFormParam.value = param
|
|
426
|
+
} else {
|
|
427
|
+
// 兜底:如果没查到流程参数或者只有表单数据没有流程实例,按照新建模式加载流程定义
|
|
428
|
+
const flowDefinition = await flowDefinitionApi.getEffectiveDefinition(props.appName!, props.flowKey!)
|
|
429
|
+
flowFormParam.value = {
|
|
430
|
+
flowDefinition: flowDefinition,
|
|
431
|
+
} as FlowFormParamDto
|
|
432
|
+
}
|
|
433
|
+
} else if (formId && props.bizTag) {
|
|
434
|
+
// formId 存在,但没有 flowKey,有 bizTag,查询可能存在的多个流程参数
|
|
435
|
+
const params = await taskQueryApi.getTasksByFormIdAndAppAndBizTag(formId, props.appName!, props.bizTag)
|
|
436
|
+
if (!params || params.length === 0 || !params.some(p => p.flowDefinition)) {
|
|
437
|
+
// 兜底:如果没查到,或者查出来的都没有流程定义,直接按照没有formId走新建模式处理
|
|
438
|
+
await loadNewFlowParamWithBizTag()
|
|
439
|
+
} else if (params.length === 1) {
|
|
440
|
+
flowFormParam.value = params[0]
|
|
441
|
+
actualFlowKey.value = params[0].flowDefinition?.flowKey
|
|
442
|
+
} else {
|
|
443
|
+
// 多于1个,不立即弹出选择框,先存起来,留到点击"发起工作"时再选
|
|
444
|
+
selectableFlowParams.value = params
|
|
445
|
+
selectableFlows.value = params.map(p => p.flowDefinition as ProjectedFlowDefinitionDto)
|
|
446
|
+
return
|
|
447
|
+
}
|
|
351
448
|
} else {
|
|
352
|
-
//
|
|
353
|
-
|
|
354
|
-
const flowDefinition = await flowDefinitionApi.getEffectiveDefinition(props.appName!, props.flowKey!)
|
|
355
|
-
// 构造部分 flowFormParam
|
|
356
|
-
flowFormParam.value = {
|
|
357
|
-
flowDefinition: flowDefinition,
|
|
358
|
-
// 其他字段为空
|
|
359
|
-
} as FlowFormParamDto
|
|
449
|
+
// 新建模式
|
|
450
|
+
await loadNewFlowParamWithBizTag()
|
|
360
451
|
}
|
|
361
452
|
} catch (e: any) {
|
|
362
453
|
ElMessage.error(e.message || '加载流程信息失败')
|
|
@@ -364,6 +455,68 @@ const loadFlowFormParam = async () => {
|
|
|
364
455
|
}
|
|
365
456
|
}
|
|
366
457
|
|
|
458
|
+
const loadNewFlowParamWithBizTag = async () => {
|
|
459
|
+
let keyToUse = props.flowKey
|
|
460
|
+
if (!keyToUse && props.bizTag) {
|
|
461
|
+
// 根据 bizTag 查询当前生效的可用流程
|
|
462
|
+
const res = await flowDefinitionApi.getEffectiveDefinitionsByBizTag(props.appName!, props.bizTag)
|
|
463
|
+
|
|
464
|
+
if (!res || res.length === 0) {
|
|
465
|
+
throw new Error(`未找到业务标签为 ${props.bizTag} 的生效可用流程定义`)
|
|
466
|
+
} else if (res.length === 1) {
|
|
467
|
+
keyToUse = res[0].flowKey
|
|
468
|
+
} else {
|
|
469
|
+
// 弹出选择对话框的动作延迟到点击发起工作
|
|
470
|
+
selectableFlows.value = res
|
|
471
|
+
return
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
actualFlowKey.value = keyToUse
|
|
476
|
+
|
|
477
|
+
// 获取流程定义
|
|
478
|
+
const flowDefinition = await flowDefinitionApi.getEffectiveDefinition(props.appName!, keyToUse!)
|
|
479
|
+
// 构造部分 flowFormParam
|
|
480
|
+
flowFormParam.value = {
|
|
481
|
+
flowDefinition: flowDefinition,
|
|
482
|
+
// 其他字段为空
|
|
483
|
+
} as FlowFormParamDto
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const handleSelectFlow = async (flow: ProjectedFlowDefinitionDto) => {
|
|
487
|
+
flowSelectionDialogVisible.value = false
|
|
488
|
+
actualFlowKey.value = flow.flowKey
|
|
489
|
+
|
|
490
|
+
try {
|
|
491
|
+
if (selectableFlowParams.value.length > 0) {
|
|
492
|
+
// 已经有完整的流程参数了,直接使用
|
|
493
|
+
const param = selectableFlowParams.value.find(p => p.flowDefinition?.flowKey === flow.flowKey)
|
|
494
|
+
if (param) {
|
|
495
|
+
flowFormParam.value = param
|
|
496
|
+
// 选择了之后,直接执行原先因为需要选择而暂停的 发起/提交流程 操作
|
|
497
|
+
await executeForward()
|
|
498
|
+
return
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// 否则作为新建模式加载最新流程定义
|
|
503
|
+
const flowDefinition = await flowDefinitionApi.getEffectiveDefinition(props.appName!, flow.flowKey!)
|
|
504
|
+
flowFormParam.value = {
|
|
505
|
+
flowDefinition: flowDefinition,
|
|
506
|
+
} as FlowFormParamDto
|
|
507
|
+
// 选择了之后,直接执行原先因为需要选择而暂停的 发起/提交流程 操作
|
|
508
|
+
await executeForward()
|
|
509
|
+
} catch (e: any) {
|
|
510
|
+
ElMessage.error(e.message || '加载流程信息失败')
|
|
511
|
+
error.value = e.message
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const handleCancelFlowSelection = () => {
|
|
516
|
+
flowSelectionDialogVisible.value = false
|
|
517
|
+
// 取消选择不再关闭整个表单,只是取消本次的发起动作
|
|
518
|
+
}
|
|
519
|
+
|
|
367
520
|
// 底部按钮处理
|
|
368
521
|
const handleSave = async () => {
|
|
369
522
|
saving.value = true
|
|
@@ -373,7 +526,7 @@ const handleSave = async () => {
|
|
|
373
526
|
taskId: flowFormParam.value?.taskInstance?.id || '',
|
|
374
527
|
processRequestType: "SAVE_FORM",
|
|
375
528
|
appName: props.appName || '',
|
|
376
|
-
flowKey:
|
|
529
|
+
flowKey: actualFlowKey.value || '',
|
|
377
530
|
startNodeKey: props.startNodeKey || '',
|
|
378
531
|
forwardTo: []
|
|
379
532
|
},
|
|
@@ -384,7 +537,8 @@ const handleSave = async () => {
|
|
|
384
537
|
}
|
|
385
538
|
}
|
|
386
539
|
|
|
387
|
-
|
|
540
|
+
// 实际执行保存并转发的核心逻辑
|
|
541
|
+
const executeForward = async () => {
|
|
388
542
|
saving.value = true
|
|
389
543
|
try {
|
|
390
544
|
const p = flowFormParam.value
|
|
@@ -393,7 +547,7 @@ const handleForward = async () => {
|
|
|
393
547
|
taskId: p?.taskInstance?.id || '',
|
|
394
548
|
processRequestType: p?.taskInstance ? "FORWARD" : "INITIATE",
|
|
395
549
|
appName: props.appName || '',
|
|
396
|
-
flowKey:
|
|
550
|
+
flowKey: actualFlowKey.value || '',
|
|
397
551
|
startNodeKey: props.startNodeKey || '',
|
|
398
552
|
forwardTo: []
|
|
399
553
|
},
|
|
@@ -406,6 +560,16 @@ const handleForward = async () => {
|
|
|
406
560
|
}
|
|
407
561
|
}
|
|
408
562
|
|
|
563
|
+
const handleForward = async () => {
|
|
564
|
+
// 如果需要选择流程,并且还没有确定实际使用的 flowKey,则弹出选择对话框
|
|
565
|
+
if (selectableFlows.value.length > 1 && !actualFlowKey.value) {
|
|
566
|
+
flowSelectionDialogVisible.value = true
|
|
567
|
+
return
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
await executeForward()
|
|
571
|
+
}
|
|
572
|
+
|
|
409
573
|
</script>
|
|
410
574
|
|
|
411
575
|
<style>
|
|
@@ -715,4 +879,48 @@ const handleForward = async () => {
|
|
|
715
879
|
box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.05);
|
|
716
880
|
z-index: 100;
|
|
717
881
|
}
|
|
882
|
+
|
|
883
|
+
/* 流程选择弹窗样式 */
|
|
884
|
+
.flow-selection-list {
|
|
885
|
+
display: flex;
|
|
886
|
+
flex-direction: column;
|
|
887
|
+
gap: 12px;
|
|
888
|
+
padding: 4px;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
.flow-selection-card {
|
|
892
|
+
cursor: pointer;
|
|
893
|
+
transition: all 0.3s;
|
|
894
|
+
border: 1px solid #e4e7ed;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
.flow-selection-card:hover {
|
|
898
|
+
border-color: var(--el-color-primary);
|
|
899
|
+
transform: translateY(-2px);
|
|
900
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
.flow-selection-card :deep(.el-card__body) {
|
|
904
|
+
display: flex;
|
|
905
|
+
justify-content: space-between;
|
|
906
|
+
align-items: center;
|
|
907
|
+
padding: 16px;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
.flow-card-content {
|
|
911
|
+
display: flex;
|
|
912
|
+
flex-direction: column;
|
|
913
|
+
gap: 4px;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
.flow-caption {
|
|
917
|
+
font-size: 16px;
|
|
918
|
+
font-weight: 500;
|
|
919
|
+
color: #303133;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
.flow-key {
|
|
923
|
+
font-size: 13px;
|
|
924
|
+
color: #909399;
|
|
925
|
+
}
|
|
718
926
|
</style>
|