Skip to content

Commit 04f4f63

Browse files
committed
feat: 完善UserTask审批签名
1 parent dd72d35 commit 04f4f63

File tree

4 files changed

+117
-1
lines changed

4 files changed

+117
-1
lines changed

src/api/bpm/processInstance/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export type ApprovalTaskInfo = {
3636
assigneeUser: User
3737
status: number
3838
reason: string
39+
sign: string
3940
}
4041

4142
// 审批节点信息

src/views/bpm/processInstance/detail/ProcessInstanceOperationButton.vue

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
:rows="4"
4545
/>
4646
</el-form-item>
47+
<el-form-item v-if="runningTask.signEnable" label="签名" prop="sign" ref="approveSignFormRef">
48+
<el-button @click="signRef.open()">点击签名</el-button>
49+
<el-image class="w-90px h-40px ml-5px" v-if="approveReasonForm.sign"
50+
:src="approveReasonForm.sign"
51+
:preview-src-list="[approveReasonForm.sign]"/>
52+
</el-form-item>
4753
<el-form-item>
4854
<el-button :disabled="formLoading" type="success" @click="handleAudit(true, approveFormRef)">
4955
{{ getButtonDisplayName(OperationButtonType.APPROVE) }}
@@ -471,6 +477,8 @@
471477
<Icon :size="14" icon="ep:refresh" />&nbsp; 再次提交
472478
</div>
473479
</div>
480+
481+
<SignDialog ref="signRef" @success="handleSignFinish"/>
474482
</template>
475483
<script lang="ts" setup>
476484
import { useUserStoreWithOut } from '@/store/modules/user'
@@ -484,6 +492,7 @@ import {
484492
} from '@/components/SimpleProcessDesignerV2/src/consts'
485493
import { BpmProcessInstanceStatus, BpmModelFormType } from '@/utils/constants'
486494
import type { FormInstance, FormRules } from 'element-plus'
495+
import SignDialog from "./SignDialog.vue";
487496
defineOptions({ name: 'ProcessInstanceBtnContainer' })
488497
489498
const router = useRouter() // 路由
@@ -522,11 +531,15 @@ const approveFormFApi = ref<any>({}) // approveForms 的 fAPi
522531
523532
// 审批通过意见表单
524533
const approveFormRef = ref<FormInstance>()
534+
const signRef = ref()
535+
const approveSignFormRef = ref()
525536
const approveReasonForm = reactive({
526-
reason: ''
537+
reason: '',
538+
sign: ''
527539
})
528540
const approveReasonRule = reactive<FormRules<typeof approveReasonForm>>({
529541
reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
542+
sign: [{ required: true, message: '签名不能为空', trigger: 'change' }]
530543
})
531544
// 拒绝表单
532545
const rejectFormRef = ref<FormInstance>()
@@ -672,6 +685,10 @@ const handleAudit = async (pass: boolean, formRef: FormInstance | undefined) =>
672685
reason: approveReasonForm.reason,
673686
variables // 审批通过, 把修改的字段值赋于流程实例变量
674687
}
688+
// 签名
689+
if (runningTask.value.signEnable) {
690+
data.sign = approveReasonForm.sign
691+
}
675692
// 多表单处理,并且有额外的 approveForm 表单,需要校验 + 拼接到 data 表单里提交
676693
// TODO 芋艿 任务有多表单这里要如何处理,会和可编辑的字段冲突
677694
const formCreateApi = approveFormFApi.value
@@ -966,6 +983,11 @@ const getUpdatedProcessInstanceVaiables = ()=> {
966983
return variables
967984
}
968985
986+
const handleSignFinish = (url) => {
987+
approveReasonForm.sign = url
988+
approveSignFormRef.value.validate('change')
989+
}
990+
969991
defineExpose({ loadTodoTask })
970992
</script>
971993

src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@
123123
>
124124
审批意见:{{ task.reason }}
125125
</div>
126+
<div
127+
v-if="task.sign && activity.nodeType === NodeType.USER_TASK_NODE"
128+
class="text-#a5a5a5 text-13px mt-1 w-full bg-#f8f8fa p2 rounded-md"
129+
>
130+
签名:
131+
<el-image class="w-90px h-40px ml-5px"
132+
:src="task.sign"
133+
:preview-src-list="[task.sign]"/>
134+
</div>
126135
</teleport>
127136
</div>
128137
<!-- 情况二:遍历每个审批节点下的【候选的】task 任务。例如说,1)依次审批,2)未来的审批任务等 -->
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<template>
2+
<el-dialog
3+
v-model="signDialogVisible"
4+
title="签名"
5+
width="935"
6+
>
7+
<div class="position-relative">
8+
<Vue3Signature class="b b-solid b-gray" ref="signature" w="900px" h="400px"/>
9+
<el-button
10+
style="position: absolute; bottom: 20px; right: 10px"
11+
type="primary"
12+
text
13+
size="small"
14+
@click="signature.clear()"
15+
>
16+
<Icon icon="ep:delete" class="mr-5px"/>
17+
清除
18+
</el-button>
19+
</div>
20+
<template #footer>
21+
<div class="dialog-footer">
22+
<el-button @click="signDialogVisible = false">取消</el-button>
23+
<el-button type="primary" @click="submit">
24+
提交
25+
</el-button>
26+
</div>
27+
</template>
28+
</el-dialog>
29+
</template>
30+
31+
<script setup lang="ts">
32+
import Vue3Signature from "vue3-signature"
33+
import * as FileApi from '@/api/infra/file'
34+
35+
const message = useMessage() // 消息弹窗
36+
const signDialogVisible = ref(false)
37+
const signature = ref()
38+
39+
const open = async () => {
40+
signDialogVisible.value = true
41+
}
42+
defineExpose({open})
43+
44+
const emits = defineEmits(['success'])
45+
const submit = async () => {
46+
message.success('签名上传中请稍等。。。')
47+
const res = await FileApi.updateFile({file: base64ToFile(signature.value.save('image/png'), '签名')})
48+
emits('success', res.data)
49+
signDialogVisible.value = false
50+
}
51+
52+
const base64ToFile = (base64, fileName) => {
53+
// 将base64按照 , 进行分割 将前缀 与后续内容分隔开
54+
let data = base64.split(',');
55+
// 利用正则表达式 从前缀中获取图片的类型信息(image/png、image/jpeg、image/webp等)
56+
let type = data[0].match(/:(.*?);/)[1];
57+
// 从图片的类型信息中 获取具体的文件格式后缀(png、jpeg、webp)
58+
let suffix = type.split('/')[1];
59+
// 使用atob()对base64数据进行解码 结果是一个文件数据流 以字符串的格式输出
60+
const bstr = window.atob(data[1]);
61+
// 获取解码结果字符串的长度
62+
let n = bstr.length
63+
// 根据解码结果字符串的长度创建一个等长的整形数字数组
64+
// 但在创建时 所有元素初始值都为 0
65+
const u8arr = new Uint8Array(n)
66+
// 将整形数组的每个元素填充为解码结果字符串对应位置字符的UTF-16 编码单元
67+
while (n--) {
68+
// charCodeAt():获取给定索引处字符对应的 UTF-16 代码单元
69+
u8arr[n] = bstr.charCodeAt(n)
70+
}
71+
// 利用构造函数创建File文件对象
72+
// new File(bits, name, options)
73+
const file = new File([u8arr], `${fileName}.${suffix}`, {
74+
type: type
75+
})
76+
// 将File文件对象返回给方法的调用者
77+
return file;
78+
}
79+
80+
</script>
81+
82+
<style scoped>
83+
84+
</style>

0 commit comments

Comments
 (0)