Просмотр исходного кода

【功能评审】Bpm:审批签名

YunaiV 7 месяцев назад
Родитель
Сommit
8e5271a6d6

+ 34 - 69
pnpm-lock.yaml

@@ -45,8 +45,8 @@ dependencies:
     specifier: ^1.1.5
     version: 1.1.5
   bpmn-js-token-simulation:
-    specifier: ^0.10.0
-    version: 0.10.0
+    specifier: ^0.36.0
+    version: 0.36.0
   camunda-bpmn-moddle:
     specifier: ^7.0.1
     version: 7.0.1
@@ -149,6 +149,9 @@ dependencies:
   vue-types:
     specifier: ^5.1.1
     version: 5.1.3(vue@3.5.12)
+  vue3-signature:
+    specifier: ^0.2.4
+    version: 0.2.4(vue@3.5.12)
   vuedraggable:
     specifier: ^4.1.0
     version: 4.1.0(vue@3.5.12)
@@ -4581,12 +4584,14 @@ packages:
       min-dom: 4.2.1
     dev: true
 
-  /bpmn-js-token-simulation@0.10.0:
-    resolution: {integrity: sha512-QuZQ/KVXKt9Vl+XENyOBoTW2Aw+uKjuBlKdCJL6El7AyM7DkJ5bZkSYURshId1SkBDdYg2mJ1flSmsrhGuSfwg==, tarball: https://registry.npmmirror.com/bpmn-js-token-simulation/-/bpmn-js-token-simulation-0.10.0.tgz}
+  /bpmn-js-token-simulation@0.36.0:
+    resolution: {integrity: sha512-vz+RHlbZCev/6dzk6FhJRz8M0aZ1GL7Xrza0ecWqeg4tHbgPozgyOm3tXTz75XdtOwRVVBzmCjcciXQX7A55wQ==, tarball: https://registry.npmmirror.com/bpmn-js-token-simulation/-/bpmn-js-token-simulation-0.36.0.tgz}
+    engines: {node: '>= 16'}
     dependencies:
-      min-dash: 3.8.1
-      min-dom: 0.2.0
-      svg.js: 2.7.1
+      inherits-browser: 0.1.0
+      min-dash: 4.2.2
+      min-dom: 4.2.1
+      randomcolor: 0.6.2
     dev: false
 
   /bpmn-js@17.11.1:
@@ -4927,51 +4932,13 @@ packages:
       dot-prop: 5.3.0
     dev: true
 
-  /component-classes@1.2.6:
-    resolution: {integrity: sha512-hPFGULxdwugu1QWW3SvVOCUHLzO34+a2J6Wqy0c5ASQkfi9/8nZcBB0ZohaEbXOQlCflMAEMmEWk7u7BVs4koA==, tarball: https://registry.npmmirror.com/component-classes/-/component-classes-1.2.6.tgz}
-    dependencies:
-      component-indexof: 0.0.3
-    dev: false
-
-  /component-closest@0.1.4:
-    resolution: {integrity: sha512-NF9hMj6JKGM5sb6wP/dg7GdJOttaIH9PcTsUNdWcrvu7Kw/5R5swQAFpgaYEHlARrNMyn4Wf7O1PlRej+pt76Q==, tarball: https://registry.npmmirror.com/component-closest/-/component-closest-0.1.4.tgz}
-    dependencies:
-      component-matches-selector: 0.1.7
-    dev: false
-
-  /component-delegate@0.2.4:
-    resolution: {integrity: sha512-OlpcB/6Fi+kXQPh/TfXnSvvmrU04ghz7vcJh/jgLF0Ni+I+E3WGlKJQbBGDa5X+kVUG8WxOgjP+8iWbz902fPg==, tarball: https://registry.npmmirror.com/component-delegate/-/component-delegate-0.2.4.tgz}
-    dependencies:
-      component-closest: 0.1.4
-      component-event: 0.1.4
-    dev: false
-
   /component-emitter@1.3.1:
     resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==, tarball: https://registry.npmmirror.com/component-emitter/-/component-emitter-1.3.1.tgz}
     dev: true
 
-  /component-event@0.1.4:
-    resolution: {integrity: sha512-GMwOG8MnUHP1l8DZx1ztFO0SJTFnIzZnBDkXAj8RM2ntV2A6ALlDxgbMY1Fvxlg6WPQ+5IM/a6vg4PEYbjg/Rw==, tarball: https://registry.npmmirror.com/component-event/-/component-event-0.1.4.tgz}
-    dev: false
-
   /component-event@0.2.1:
     resolution: {integrity: sha512-wGA++isMqiDq1jPYeyv2as/Bt/u+3iLW0rEa+8NQ82jAv3TgqMiCM+B2SaBdn2DfLilLjjq736YcezihRYhfxw==, tarball: https://registry.npmmirror.com/component-event/-/component-event-0.2.1.tgz}
 
-  /component-indexof@0.0.3:
-    resolution: {integrity: sha512-puDQKvx/64HZXb4hBwIcvQLaLgux8o1CbWl39s41hrIIZDl1lJiD5jc22gj3RBeGK0ovxALDYpIbyjqDUUl0rw==, tarball: https://registry.npmmirror.com/component-indexof/-/component-indexof-0.0.3.tgz}
-    dev: false
-
-  /component-matches-selector@0.1.7:
-    resolution: {integrity: sha512-Yb2+pVBvrqkQVpPaDBF0DYXRreBveXJNrpJs9FnFu8PF6/5IIcz5oDZqiH9nB5hbD2/TmFVN5ZCxBzqu7yFFYQ==, tarball: https://registry.npmmirror.com/component-matches-selector/-/component-matches-selector-0.1.7.tgz}
-    dependencies:
-      component-query: 0.0.3
-      global-object: 1.0.0
-    dev: false
-
-  /component-query@0.0.3:
-    resolution: {integrity: sha512-VgebQseT1hz1Ps7vVp2uaSg+N/gsI5ts3AZUSnN6GMA2M82JH7o+qYifWhmVE/e8w/H48SJuA3nA9uX8zRe95Q==, tarball: https://registry.npmmirror.com/component-query/-/component-query-0.0.3.tgz}
-    dev: false
-
   /compute-scroll-into-view@1.0.20:
     resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==, tarball: https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz}
     dev: false
@@ -5521,6 +5488,10 @@ packages:
     resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, tarball: https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz}
     dev: true
 
+  /default-passive-events@2.0.0:
+    resolution: {integrity: sha512-eMtt76GpDVngZQ3ocgvRcNCklUMwID1PaNbCNxfpDXuiOXttSh0HzBbda1HU9SIUsDc02vb7g9+3I5tlqe/qMQ==, tarball: https://registry.npmmirror.com/default-passive-events/-/default-passive-events-2.0.0.tgz}
+    dev: false
+
   /define-data-property@1.1.4:
     resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==, tarball: https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz}
     engines: {node: '>= 0.4'}
@@ -6674,10 +6645,6 @@ packages:
       global-prefix: 3.0.0
     dev: true
 
-  /global-object@1.0.0:
-    resolution: {integrity: sha512-mSPSkY6UsHv6hgW0V2dfWBWTS8TnPnLx3ECVNoWp6rBI2Bg66VYoqGoTFlH/l7XhAZ/l+StYlntXlt87BEeCcg==, tarball: https://registry.npmmirror.com/global-object/-/global-object-1.0.0.tgz}
-    dev: false
-
   /global-prefix@3.0.0:
     resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==, tarball: https://registry.npmmirror.com/global-prefix/-/global-prefix-3.0.0.tgz}
     engines: {node: '>=6'}
@@ -7899,10 +7866,6 @@ packages:
     engines: {node: '>=18'}
     dev: true
 
-  /min-dash@3.8.1:
-    resolution: {integrity: sha512-evumdlmIlg9mbRVPbC4F5FuRhNmcMS5pvuBUbqb1G9v09Ro0ImPEgz5n3khir83lFok1inKqVDjnKEg3GpDxQg==, tarball: https://registry.npmmirror.com/min-dash/-/min-dash-3.8.1.tgz}
-    dev: false
-
   /min-dash@4.2.2:
     resolution: {integrity: sha512-qbhSYUxk6mBaF096B3JOQSumXbKWHenmT97cSpdNzgkWwGjhjhE/KZODCoDNhI2I4C9Cb6R/Q13S4BYkUSXoXQ==, tarball: https://registry.npmmirror.com/min-dash/-/min-dash-4.2.2.tgz}
 
@@ -7912,18 +7875,6 @@ packages:
       dom-walk: 0.1.2
     dev: false
 
-  /min-dom@0.2.0:
-    resolution: {integrity: sha512-VmxugbnAcVZGqvepjhOA4d4apmrpX8mMaRS+/jo0dI5Yorzrr4Ru9zc9KVALlY/+XakVCb8iQ+PYXljihQcsNw==, tarball: https://registry.npmmirror.com/min-dom/-/min-dom-0.2.0.tgz}
-    dependencies:
-      component-classes: 1.2.6
-      component-closest: 0.1.4
-      component-delegate: 0.2.4
-      component-event: 0.1.4
-      component-matches-selector: 0.1.7
-      component-query: 0.0.3
-      domify: 1.4.2
-    dev: false
-
   /min-dom@4.2.1:
     resolution: {integrity: sha512-TMoL8SEEIhUWYgkj7XMSgxmwSyGI+4fP2KFFGnN3FbHfbGHVdsLYSz8LoIsgPhz4dWRmLvxWWSMgzZMJW5sZuA==, tarball: https://registry.npmmirror.com/min-dom/-/min-dom-4.2.1.tgz}
     dependencies:
@@ -8714,6 +8665,10 @@ packages:
     resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, tarball: https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz}
     dev: true
 
+  /randomcolor@0.6.2:
+    resolution: {integrity: sha512-Mn6TbyYpFgwFuQ8KJKqf3bqqY9O1y37/0jgSK/61PUxV4QfIMv0+K2ioq8DfOjkBslcjwSzRfIDEXfzA9aCx7A==, tarball: https://registry.npmmirror.com/randomcolor/-/randomcolor-0.6.2.tgz}
+    dev: false
+
   /rd@2.0.1:
     resolution: {integrity: sha512-/XdKU4UazUZTXFmI0dpABt8jSXPWcEyaGdk340KdHnsEOdkTctlX23aAK7ChQDn39YGNlAJr1M5uvaKt4QnpNw==, tarball: https://registry.npmmirror.com/rd/-/rd-2.0.1.tgz}
     dependencies:
@@ -9128,6 +9083,10 @@ packages:
     engines: {node: '>=14'}
     dev: true
 
+  /signature_pad@3.0.0-beta.4:
+    resolution: {integrity: sha512-cOf2NhVuTiuNqe2X/ycEmizvCDXk0DoemhsEpnkcGnA4kS5iJYTCqZ9As7tFBbsch45Q1EdX61833+6sjJ8rrw==, tarball: https://registry.npmmirror.com/signature_pad/-/signature_pad-3.0.0-beta.4.tgz}
+    dev: false
+
   /sirv@2.0.4:
     resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==, tarball: https://registry.npmmirror.com/sirv/-/sirv-2.0.4.tgz}
     engines: {node: '>= 10'}
@@ -9561,10 +9520,6 @@ packages:
     resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==, tarball: https://registry.npmmirror.com/svg-tags/-/svg-tags-1.0.0.tgz}
     dev: true
 
-  /svg.js@2.7.1:
-    resolution: {integrity: sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==, tarball: https://registry.npmmirror.com/svg.js/-/svg.js-2.7.1.tgz}
-    dev: false
-
   /svgo@2.8.0:
     resolution: {integrity: sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==, tarball: https://registry.npmmirror.com/svgo/-/svgo-2.8.0.tgz}
     engines: {node: '>=10.13.0'}
@@ -10324,6 +10279,16 @@ packages:
       vue: 3.5.12(typescript@5.3.3)
     dev: false
 
+  /vue3-signature@0.2.4(vue@3.5.12):
+    resolution: {integrity: sha512-XFwwFVK9OG3F085pKIq2SlNVqx32WdFH+TXbGEWc5FfEKpx8oMmZuAwZZ50K/pH2FgmJSE8IRwU9DDhrLpd6iA==, tarball: https://registry.npmmirror.com/vue3-signature/-/vue3-signature-0.2.4.tgz}
+    peerDependencies:
+      vue: ^3.2.0
+    dependencies:
+      default-passive-events: 2.0.0
+      signature_pad: 3.0.0-beta.4
+      vue: 3.5.12(typescript@5.3.3)
+    dev: false
+
   /vue@3.5.12(typescript@5.3.3):
     resolution: {integrity: sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==, tarball: https://registry.npmmirror.com/vue/-/vue-3.5.12.tgz}
     peerDependencies:

+ 2 - 2
src/api/bpm/processInstance/index.ts

@@ -36,7 +36,7 @@ export type ApprovalTaskInfo = {
   assigneeUser: User
   status: number
   reason: string
-  sign: string
+  sign: string // TODO @lesan:字段改成 signPicUrl 签名照片。只有 sign 感觉是签名文本哈。
 }
 
 // 审批节点信息
@@ -90,7 +90,7 @@ export const getProcessInstanceCopyPage = async (params: any) => {
 
 // 获取审批详情
 export const getApprovalDetail = async (params: any) => {
-  return await request.get({ url: 'bpm/process-instance/get-approval-detail' , params })
+  return await request.get({ url: 'bpm/process-instance/get-approval-detail', params })
 }
 
 // 获取表单字段权限

+ 6 - 5
src/components/SimpleProcessDesignerV2/src/nodes-config/RouterNodeConfig.vue

@@ -37,9 +37,9 @@
                   :value="node.value"
                 />
               </el-select>
-              <el-button class="mla" type="danger" link @click="deleteRouterGroup(index)"
-                >删除</el-button
-              >
+              <el-button class="mla" type="danger" link @click="deleteRouterGroup(index)">
+                删除
+              </el-button>
             </div>
           </template>
           <Condition
@@ -67,6 +67,7 @@ import { Plus } from '@element-plus/icons-vue'
 import { SimpleFlowNode, NodeType, ConditionType, RouterCondition } from '../consts'
 import { useWatchNode, useDrawer, useNodeName } from '../node'
 import Condition from './components/Condition.vue'
+
 defineOptions({
   name: 'RouterNodeConfig'
 })
@@ -86,9 +87,9 @@ const currentNode = useWatchNode(props)
 const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(NodeType.ROUTER_BRANCH_NODE)
 const routerGroups = ref<RouterCondition[]>([])
 const nodeOptions = ref()
-
 const conditionRef = ref([])
-// 保存配置
+
+/** 保存配置 */
 const saveConfig = async () => {
   // 校验表单
   let valid = true

+ 1 - 0
src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue

@@ -440,6 +440,7 @@
           </div>
         </div>
       </el-tab-pane>
+      <!-- TODO @lesan:要不抽成 Listener 小组件?类似 Condition.vue -->
       <el-tab-pane label="监听器" name="listener">
         <el-form ref="listenerFormRef" :model="configForm" label-position="top">
           <div v-for="(listener, listenerIdx) in taskListener" :key="listenerIdx">

+ 61 - 43
src/views/bpm/processInstance/detail/ProcessInstanceOperationButton.vue

@@ -44,14 +44,26 @@
               :rows="4"
             />
           </el-form-item>
-          <el-form-item v-if="runningTask.signEnable" label="签名" prop="sign" ref="approveSignFormRef">
+          <el-form-item
+            v-if="runningTask.signEnable"
+            label="签名"
+            prop="sign"
+            ref="approveSignFormRef"
+          >
             <el-button @click="signRef.open()">点击签名</el-button>
-            <el-image class="w-90px h-40px ml-5px" v-if="approveReasonForm.sign"
-                      :src="approveReasonForm.sign"
-                      :preview-src-list="[approveReasonForm.sign]"/>
+            <el-image
+              class="w-90px h-40px ml-5px"
+              v-if="approveReasonForm.sign"
+              :src="approveReasonForm.sign"
+              :preview-src-list="[approveReasonForm.sign]"
+            />
           </el-form-item>
           <el-form-item>
-            <el-button :disabled="formLoading" type="success" @click="handleAudit(true, approveFormRef)">
+            <el-button
+              :disabled="formLoading"
+              type="success"
+              @click="handleAudit(true, approveFormRef)"
+            >
               {{ getButtonDisplayName(OperationButtonType.APPROVE) }}
             </el-button>
             <el-button @click="closePropover('approve', approveFormRef)"> 取消 </el-button>
@@ -92,7 +104,11 @@
             />
           </el-form-item>
           <el-form-item>
-            <el-button :disabled="formLoading" type="danger" @click="handleAudit(false,rejectFormRef)">
+            <el-button
+              :disabled="formLoading"
+              type="danger"
+              @click="handleAudit(false, rejectFormRef)"
+            >
               {{ getButtonDisplayName(OperationButtonType.REJECT) }}
             </el-button>
             <el-button @click="closePropover('reject', rejectFormRef)"> 取消 </el-button>
@@ -478,7 +494,8 @@
     </div>
   </div>
 
-  <SignDialog ref="signRef" @success="handleSignFinish"/>
+  <!-- 签名弹窗 -->
+  <SignDialog ref="signRef" @success="handleSignFinish" />
 </template>
 <script lang="ts" setup>
 import { useUserStoreWithOut } from '@/store/modules/user'
@@ -487,12 +504,13 @@ import * as TaskApi from '@/api/bpm/task'
 import * as ProcessInstanceApi from '@/api/bpm/processInstance'
 import * as UserApi from '@/api/system/user'
 import {
-  OperationButtonType,
-  OPERATION_BUTTON_NAME
+  OPERATION_BUTTON_NAME,
+  OperationButtonType
 } from '@/components/SimpleProcessDesignerV2/src/consts'
-import { BpmProcessInstanceStatus, BpmModelFormType } from '@/utils/constants'
+import { BpmModelFormType, BpmProcessInstanceStatus } from '@/utils/constants'
 import type { FormInstance, FormRules } from 'element-plus'
-import SignDialog from "./SignDialog.vue";
+import SignDialog from './SignDialog.vue'
+
 defineOptions({ name: 'ProcessInstanceBtnContainer' })
 
 const router = useRouter() // 路由
@@ -501,12 +519,12 @@ const message = useMessage() // 消息弹窗
 const userId = useUserStoreWithOut().getUser.id // 当前登录的编号
 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
 
-const props = defineProps< {
-  processInstance: any,  // 流程实例信息
-  processDefinition: any,  // 流程定义信息
-  userOptions: UserApi.UserVO[],
-  normalForm: any, // 流程表单 formCreate
-  normalFormApi: any, // 流程表单 formCreate Api
+const props = defineProps<{
+  processInstance: any // 流程实例信息
+  processDefinition: any // 流程定义信息
+  userOptions: UserApi.UserVO[]
+  normalForm: any // 流程表单 formCreate
+  normalFormApi: any // 流程表单 formCreate Api
   writableFields: string[] // 流程表单可以编辑的字段
 }>()
 
@@ -547,7 +565,7 @@ const rejectReasonForm = reactive({
   reason: ''
 })
 const rejectReasonRule = reactive<FormRules<typeof rejectReasonForm>>({
-  reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
+  reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }]
 })
 
 // 抄送表单
@@ -568,7 +586,7 @@ const transferForm = reactive({
 })
 const transferFormRule = reactive<FormRules<typeof transferForm>>({
   assigneeUserId: [{ required: true, message: '新审批人不能为空', trigger: 'change' }],
-  reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
+  reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }]
 })
 
 // 委派表单
@@ -579,7 +597,7 @@ const delegateForm = reactive({
 })
 const delegateFormRule = reactive<FormRules<typeof delegateForm>>({
   delegateUserId: [{ required: true, message: '接收人不能为空', trigger: 'change' }],
-  reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
+  reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }]
 })
 
 // 加签表单
@@ -590,7 +608,7 @@ const addSignForm = reactive({
 })
 const addSignFormRule = reactive<FormRules<typeof addSignForm>>({
   addSignUserIds: [{ required: true, message: '加签处理人不能为空', trigger: 'change' }],
-  reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
+  reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }]
 })
 
 // 减签表单
@@ -601,7 +619,7 @@ const deleteSignForm = reactive({
 })
 const deleteSignFormRule = reactive<FormRules<typeof deleteSignForm>>({
   deleteSignTaskId: [{ required: true, message: '减签人员不能为空', trigger: 'change' }],
- reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
+  reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }]
 })
 
 // 退回表单
@@ -621,7 +639,7 @@ const cancelForm = reactive({
   cancelReason: ''
 })
 const cancelFormRule = reactive<FormRules<typeof cancelForm>>({
-  cancelReason: [{ required: true, message: '取消理由不能为空', trigger: 'blur' }],
+  cancelReason: [{ required: true, message: '取消理由不能为空', trigger: 'blur' }]
 })
 
 /** 监听 approveFormFApis,实现它对应的 form-create 初始化后,隐藏掉对应的表单提交按钮 */
@@ -640,11 +658,11 @@ watch(
 const openPopover = async (type: string) => {
   if (type === 'approve') {
     // 校验流程表单
-     const valid = await validateNormalForm();
-     if (!valid) {
+    const valid = await validateNormalForm()
+    if (!valid) {
       message.warning('表单校验不通过,请先完善表单!!')
-      return;
-     }
+      return
+    }
   }
   if (type === 'return') {
     // 获取退回节点
@@ -665,7 +683,7 @@ const openPopover = async (type: string) => {
 const closePropover = (type: string, formRef: FormInstance | undefined) => {
   if (formRef) {
     formRef.resetFields()
-  } 
+  }
   popOverVisible.value[type] = false
 }
 
@@ -677,8 +695,8 @@ const handleAudit = async (pass: boolean, formRef: FormInstance | undefined) =>
     if (!formRef) return
     await formRef.validate()
     if (pass) {
-       // 获取修改的流程变量, 暂时只支持流程表单
-       const variables = getUpdatedProcessInstanceVaiables();
+      // 获取修改的流程变量, 暂时只支持流程表单
+      const variables = getUpdatedProcessInstanceVariables()
       // 审批通过数据
       const data = {
         id: runningTask.value.id,
@@ -701,10 +719,10 @@ const handleAudit = async (pass: boolean, formRef: FormInstance | undefined) =>
       popOverVisible.value.approve = false
       message.success('审批通过成功')
     } else {
-       // 审批不通过数据
-       const data = {
+      // 审批不通过数据
+      const data = {
         id: runningTask.value.id,
-        reason: rejectReasonForm.reason,
+        reason: rejectReasonForm.reason
       }
       await TaskApi.rejectTask(data)
       popOverVisible.value.reject = false
@@ -730,7 +748,7 @@ const handleCopy = async () => {
     const data = {
       id: runningTask.value.id,
       reason: copyForm.copyReason,
-      copyUserIds:copyForm.copyUserIds
+      copyUserIds: copyForm.copyUserIds
     }
     await TaskApi.copyTask(data)
     copyFormRef.value.resetFields()
@@ -769,7 +787,6 @@ const handleTransfer = async () => {
 const handleDelegate = async () => {
   formLoading.value = true
   try {
- 
     // 1.1 校验表单
     if (!delegateFormRef.value) return
     await delegateFormRef.value.validate()
@@ -966,24 +983,25 @@ const validateNormalForm = async () => {
     try {
       await props.normalFormApi?.validate()
     } catch {
-      valid = false;
+      valid = false
     }
-    return valid;
+    return valid
   } else {
-    return true;
+    return true
   }
 }
+
 /** 从可以编辑的流程表单字段,获取需要修改的流程实例的变量 */
-const getUpdatedProcessInstanceVaiables = ()=> {
+const getUpdatedProcessInstanceVariables = () => {
   const variables = {}
-  props.writableFields.forEach( (field) => {
-    const fieldValue = props.normalFormApi.getValue(field)
-    variables[field] = fieldValue;
+  props.writableFields.forEach((field) => {
+    variables[field] = props.normalFormApi.getValue(field)
   })
   return variables
 }
 
-const handleSignFinish = (url) => {
+/** 处理签名完成 */
+const handleSignFinish = (url: string) => {
   approveReasonForm.sign = url
   approveSignFormRef.value.validate('change')
 }

+ 5 - 3
src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue

@@ -128,9 +128,11 @@
                 class="text-#a5a5a5 text-13px mt-1 w-full bg-#f8f8fa p2 rounded-md"
               >
                 签名:
-                <el-image class="w-90px h-40px ml-5px"
-                          :src="task.sign"
-                          :preview-src-list="[task.sign]"/>
+                <el-image
+                  class="w-90px h-40px ml-5px"
+                  :src="task.sign"
+                  :preview-src-list="[task.sign]"
+                />
               </div>
             </teleport>
           </div>

+ 17 - 22
src/views/bpm/processInstance/detail/SignDialog.vue

@@ -1,11 +1,8 @@
 <template>
-  <el-dialog
-    v-model="signDialogVisible"
-    title="签名"
-    width="935"
-  >
+  <el-dialog v-model="signDialogVisible" title="签名" width="935">
     <div class="position-relative">
-      <Vue3Signature class="b b-solid b-gray" ref="signature" w="900px" h="400px"/>
+      <Vue3Signature class="b b-solid b-gray" ref="signature" w="900px" h="400px" />
+      <!-- @lesan:建议改成 unocss 哈 -->
       <el-button
         style="position: absolute; bottom: 20px; right: 10px"
         type="primary"
@@ -13,23 +10,21 @@
         size="small"
         @click="signature.clear()"
       >
-        <Icon icon="ep:delete" class="mr-5px"/>
+        <Icon icon="ep:delete" class="mr-5px" />
         清除
       </el-button>
     </div>
     <template #footer>
       <div class="dialog-footer">
         <el-button @click="signDialogVisible = false">取消</el-button>
-        <el-button type="primary" @click="submit">
-          提交
-        </el-button>
+        <el-button type="primary" @click="submit"> 提交 </el-button>
       </div>
     </template>
   </el-dialog>
 </template>
 
 <script setup lang="ts">
-import Vue3Signature from "vue3-signature"
+import Vue3Signature from 'vue3-signature'
 import * as FileApi from '@/api/infra/file'
 
 const message = useMessage() // 消息弹窗
@@ -39,25 +34,28 @@ const signature = ref()
 const open = async () => {
   signDialogVisible.value = true
 }
-defineExpose({open})
+defineExpose({ open })
 
 const emits = defineEmits(['success'])
 const submit = async () => {
   message.success('签名上传中请稍等。。。')
-  const res = await FileApi.updateFile({file: base64ToFile(signature.value.save('image/png'), '签名')})
+  const res = await FileApi.updateFile({
+    file: base64ToFile(signature.value.save('image/png'), '签名')
+  })
   emits('success', res.data)
   signDialogVisible.value = false
 }
 
+// TODO @lesan:这个要不抽到 download.js 里,让这个组件更简洁干净?
 const base64ToFile = (base64, fileName) => {
   // 将base64按照 , 进行分割 将前缀  与后续内容分隔开
-  let data = base64.split(',');
+  let data = base64.split(',')
   // 利用正则表达式 从前缀中获取图片的类型信息(image/png、image/jpeg、image/webp等)
-  let type = data[0].match(/:(.*?);/)[1];
+  let type = data[0].match(/:(.*?);/)[1]
   // 从图片的类型信息中 获取具体的文件格式后缀(png、jpeg、webp)
-  let suffix = type.split('/')[1];
+  let suffix = type.split('/')[1]
   // 使用atob()对base64数据进行解码  结果是一个文件数据流 以字符串的格式输出
-  const bstr = window.atob(data[1]);
+  const bstr = window.atob(data[1])
   // 获取解码结果字符串的长度
   let n = bstr.length
   // 根据解码结果字符串的长度创建一个等长的整形数字数组
@@ -74,11 +72,8 @@ const base64ToFile = (base64, fileName) => {
     type: type
   })
   // 将File文件对象返回给方法的调用者
-  return file;
+  return file
 }
-
 </script>
 
-<style scoped>
-
-</style>
+<style scoped></style>