Quellcode durchsuchen

Merge pull request #84 from GoldenZqqq/bpm-optimization

工作流审批页面样式优化
芋道源码 vor 7 Monaten
Ursprung
Commit
d7e0b771ef

+ 115 - 122
src/views/bpm/processInstance/detail/ProcessInstanceBtnConatiner.vue → src/views/bpm/processInstance/detail/ProcessInstanceOperationButton.vue

@@ -1,132 +1,125 @@
 <template>
-  <el-affix target=".formCol" position="bottom" class="h-50px" v-if="runningTask?.id">
-    <el-divider class="!mb-8px !mt-0" />
-    <div
-      class="pl-50px text-14px flex items-center color-#32373c dark:color-#fff font-bold btn-container"
-    >
-      <el-popover :visible="passVisible" placement="top-end" :width="500" trigger="click">
-        <template #reference>
-          <el-button plain type="success" @click="openPopover('1')">
-            <Icon icon="ep:select" />&nbsp; 通过
-          </el-button>
-        </template>
-        <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
-          <el-form
-            label-position="top"
-            class="mb-auto"
-            ref="formRef"
-            :model="auditForm"
-            :rules="auditRule"
-            label-width="100px"
-          >
-            <el-form-item v-if="processInstance && processInstance.startUser" label="流程发起人">
-              {{ processInstance?.startUser.nickname }}
-              <el-tag size="small" type="info" class="ml-8px">
-                {{ processInstance?.startUser.deptName }}
-              </el-tag>
-            </el-form-item>
-            <el-card v-if="runningTask.formId > 0" class="mb-15px !-mt-10px">
-              <template #header>
-                <span class="el-icon-picture-outline">
-                  填写表单【{{ runningTask?.formName }}】
-                </span>
-              </template>
-              <form-create
-                v-model="approveForm.value"
-                v-model:api="approveFormFApi"
-                :option="approveForm.option"
-                :rule="approveForm.rule"
+  <div
+    class="h-50px position-fixed bottom-10 text-14px flex items-center color-#32373c dark:color-#fff font-bold btn-container"
+  >
+    <el-popover :visible="passVisible" placement="top-end" :width="500" trigger="click">
+      <template #reference>
+        <el-button plain type="success" @click="openPopover('1')">
+          <Icon icon="ep:select" />&nbsp; 通过
+        </el-button>
+      </template>
+      <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
+        <el-form
+          label-position="top"
+          class="mb-auto"
+          ref="formRef"
+          :model="auditForm"
+          :rules="auditRule"
+          label-width="100px"
+        >
+          <el-form-item v-if="processInstance && processInstance.startUser" label="流程发起人">
+            {{ processInstance?.startUser.nickname }}
+            <el-tag size="small" type="info" class="ml-8px">
+              {{ processInstance?.startUser.deptName }}
+            </el-tag>
+          </el-form-item>
+          <el-card v-if="runningTask.formId > 0" class="mb-15px !-mt-10px">
+            <template #header>
+              <span class="el-icon-picture-outline"> 填写表单【{{ runningTask?.formName }}】 </span>
+            </template>
+            <form-create
+              v-model="approveForm.value"
+              v-model:api="approveFormFApi"
+              :option="approveForm.option"
+              :rule="approveForm.rule"
+            />
+          </el-card>
+          <el-form-item label="审批建议" prop="reason">
+            <el-input v-model="auditForm.reason" placeholder="请输入审批建议" type="textarea" />
+          </el-form-item>
+          <el-form-item label="抄送人" prop="copyUserIds">
+            <el-select v-model="auditForm.copyUserIds" multiple placeholder="请选择抄送人">
+              <el-option
+                v-for="itemx in userOptions"
+                :key="itemx.id"
+                :label="itemx.nickname"
+                :value="itemx.id"
               />
-            </el-card>
-            <el-form-item label="审批建议" prop="reason">
-              <el-input v-model="auditForm.reason" placeholder="请输入审批建议" type="textarea" />
-            </el-form-item>
-            <el-form-item label="抄送人" prop="copyUserIds">
-              <el-select v-model="auditForm.copyUserIds" multiple placeholder="请选择抄送人">
-                <el-option
-                  v-for="itemx in userOptions"
-                  :key="itemx.id"
-                  :label="itemx.nickname"
-                  :value="itemx.id"
-                />
-              </el-select>
-            </el-form-item>
+            </el-select>
+          </el-form-item>
 
-            <el-form-item>
-              <el-button :disabled="formLoading" type="success" @click="handleAudit(true)">
-                通过
-              </el-button>
-              <el-button @click="passVisible = false"> 取消 </el-button>
-            </el-form-item>
-          </el-form>
-        </div>
-      </el-popover>
-      <el-popover :visible="rejectVisible" placement="top-end" :width="500" trigger="click">
-        <template #reference>
-          <el-button class="mr-20px" plain type="danger" @click="openPopover('2')">
-            <Icon icon="ep:close" />&nbsp; 拒绝
-          </el-button>
-        </template>
-        <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
-          <el-form
-            label-position="top"
-            class="mb-auto"
-            ref="formRef"
-            :model="auditForm"
-            :rules="auditRule"
-            label-width="100px"
-          >
-            <el-form-item v-if="processInstance && processInstance.startUser" label="流程发起人">
-              {{ processInstance?.startUser.nickname }}
-              <el-tag size="small" type="info" class="ml-8px">
-                {{ processInstance?.startUser.deptName }}
-              </el-tag>
-            </el-form-item>
-            <el-card v-if="runningTask.formId > 0" class="mb-15px !-mt-10px">
-              <template #header>
-                <span class="el-icon-picture-outline">
-                  填写表单【{{ runningTask?.formName }}】
-                </span>
-              </template>
-              <form-create
-                v-model="approveForm.value"
-                v-model:api="approveFormFApi"
-                :option="approveForm.option"
-                :rule="approveForm.rule"
+          <el-form-item>
+            <el-button :disabled="formLoading" type="success" @click="handleAudit(true)">
+              通过
+            </el-button>
+            <el-button @click="passVisible = false"> 取消 </el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </el-popover>
+    <el-popover :visible="rejectVisible" placement="top-end" :width="500" trigger="click">
+      <template #reference>
+        <el-button class="mr-20px" plain type="danger" @click="openPopover('2')">
+          <Icon icon="ep:close" />&nbsp; 拒绝
+        </el-button>
+      </template>
+      <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
+        <el-form
+          label-position="top"
+          class="mb-auto"
+          ref="formRef"
+          :model="auditForm"
+          :rules="auditRule"
+          label-width="100px"
+        >
+          <el-form-item v-if="processInstance && processInstance.startUser" label="流程发起人">
+            {{ processInstance?.startUser.nickname }}
+            <el-tag size="small" type="info" class="ml-8px">
+              {{ processInstance?.startUser.deptName }}
+            </el-tag>
+          </el-form-item>
+          <el-card v-if="runningTask.formId > 0" class="mb-15px !-mt-10px">
+            <template #header>
+              <span class="el-icon-picture-outline"> 填写表单【{{ runningTask?.formName }}】 </span>
+            </template>
+            <form-create
+              v-model="approveForm.value"
+              v-model:api="approveFormFApi"
+              :option="approveForm.option"
+              :rule="approveForm.rule"
+            />
+          </el-card>
+          <el-form-item label="审批建议" prop="reason">
+            <el-input v-model="auditForm.reason" placeholder="请输入审批建议" type="textarea" />
+          </el-form-item>
+          <el-form-item label="抄送人" prop="copyUserIds">
+            <el-select v-model="auditForm.copyUserIds" multiple placeholder="请选择抄送人">
+              <el-option
+                v-for="itemx in userOptions"
+                :key="itemx.id"
+                :label="itemx.nickname"
+                :value="itemx.id"
               />
-            </el-card>
-            <el-form-item label="审批建议" prop="reason">
-              <el-input v-model="auditForm.reason" placeholder="请输入审批建议" type="textarea" />
-            </el-form-item>
-            <el-form-item label="抄送人" prop="copyUserIds">
-              <el-select v-model="auditForm.copyUserIds" multiple placeholder="请选择抄送人">
-                <el-option
-                  v-for="itemx in userOptions"
-                  :key="itemx.id"
-                  :label="itemx.nickname"
-                  :value="itemx.id"
-                />
-              </el-select>
-            </el-form-item>
+            </el-select>
+          </el-form-item>
 
-            <el-form-item>
-              <el-button :disabled="formLoading" type="danger" @click="handleAudit(false)">
-                拒绝
-              </el-button>
-              <el-button @click="rejectVisible = false"> 取消 </el-button>
-            </el-form-item>
-          </el-form>
-        </div>
-      </el-popover>
-      <div @click="handleSend"> <Icon :size="14" icon="svg-icon:send" />&nbsp;抄送 </div>
-      <div @click="openTaskUpdateAssigneeForm">
-        <Icon :size="14" icon="fa:share-square-o" />&nbsp;转交
+          <el-form-item>
+            <el-button :disabled="formLoading" type="danger" @click="handleAudit(false)">
+              拒绝
+            </el-button>
+            <el-button @click="rejectVisible = false"> 取消 </el-button>
+          </el-form-item>
+        </el-form>
       </div>
-      <div @click="handleDelegate"> <Icon :size="14" icon="ep:position" />&nbsp;委派 </div>
-      <div @click="handleSign"> <Icon :size="14" icon="ep:plus" />&nbsp;加签 </div>
-      <div @click="handleBack"> <Icon :size="14" icon="fa:mail-reply" />&nbsp;退回 </div>
+    </el-popover>
+    <div @click="handleSend"> <Icon :size="14" icon="svg-icon:send" />&nbsp;抄送 </div>
+    <div @click="openTaskUpdateAssigneeForm">
+      <Icon :size="14" icon="fa:share-square-o" />&nbsp;转交
     </div>
-  </el-affix>
+    <div @click="handleDelegate"> <Icon :size="14" icon="ep:position" />&nbsp;委派 </div>
+    <div @click="handleSign"> <Icon :size="14" icon="ep:plus" />&nbsp;加签 </div>
+    <div @click="handleBack"> <Icon :size="14" icon="fa:mail-reply" />&nbsp;退回 </div>
+  </div>
   <!-- 弹窗:转派审批人 -->
   <TaskTransferForm ref="taskTransferFormRef" @success="getDetail" />
   <!-- 弹窗:回退节点 -->

+ 161 - 0
src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue

@@ -0,0 +1,161 @@
+<template>
+  <el-timeline class="pt-20px">
+    <el-timeline-item v-for="(activity, index) in mockData" :key="index" size="large">
+      <div class="flex flex-col items-start">
+        <div class="font-bold"> {{ activity.name }}</div>
+        <div class="color-#a1a6ae text-12px mb-10px"> {{ activity.assigneeUser.nickname }}</div>
+        <div v-if="activity.opinion" class="text-#a5a5a5 text-12px w-100%">
+          <div class="mb-5px">审批意见:</div>
+          <div
+            class="w-100% border-1px border-#a5a5a5 border-dashed rounded py-5px px-15px text-#2d2d2d"
+          >
+            {{ activity.opinion }}
+          </div>
+        </div>
+        <div v-if="activity.createTime" class="text-#a5a5a5 text-13px">
+          {{ formatDate(activity.createTime) }}
+        </div>
+      </div>
+      <!-- 该节点用户的头像 -->
+      <template #dot>
+        <div class="w-35px h-35px position-relative">
+          <img
+            src="@/assets/imgs/avatar.jpg"
+            class="rounded-full w-full h-full position-absolute bottom-6px right-12px"
+            alt=""
+          />
+          <div
+            class="position-absolute top-16px left-8px bg-#fff rounded-full flex items-center content-center p-2px"
+          >
+            <Icon
+              :size="12"
+              :icon="optIconMap[activity.status]?.icon"
+              :color="optIconMap[activity.status]?.color"
+            />
+          </div>
+        </div>
+      </template>
+    </el-timeline-item>
+  </el-timeline>
+</template>
+
+<script lang="ts" setup>
+import { formatDate } from '@/utils/formatTime'
+import { propTypes } from '@/utils/propTypes'
+
+defineOptions({ name: 'BpmProcessInstanceTimeline' })
+defineProps({
+  tasks: propTypes.array // 流程任务的数组
+})
+
+const optIconMap = {
+  // 审批中
+  '1': {
+    color: '#00b32a',
+    icon: 'fa-solid:clock'
+  },
+  // 审批通过
+  '2': { color: '#00b32a', icon: 'fa-solid:check-circle' },
+  // 审批不通过
+  '3': { color: '#f46b6c', icon: 'fa-solid:times-circle' }
+}
+
+const mockData: any = [
+  {
+    id: 'fe1190ee-68c3-11ef-9c7d-00a6181404fd',
+    name: '发起人',
+    createTime: 1725237646192,
+    endTime: null,
+    durationInMillis: null,
+    status: 1,
+    reason: null,
+    ownerUser: null,
+    assigneeUser: {
+      id: 104,
+      nickname: '测试号',
+      deptId: 107,
+      deptName: '运维部门'
+    },
+    taskDefinitionKey: 'task-01',
+    processInstanceId: 'fe0c60c6-68c3-11ef-9c7d-00a6181404fd',
+    processInstance: {
+      id: 'fe0c60c6-68c3-11ef-9c7d-00a6181404fd',
+      name: 'oa_leave',
+      createTime: null,
+      processDefinitionId: 'oa_leave:1:6e5ac269-5f87-11ef-bdb6-00a6181404fd',
+      startUser: null
+    },
+    parentTaskId: null,
+    children: null,
+    formId: null,
+    formName: null,
+    formConf: null,
+    formFields: null,
+    formVariables: null
+  },
+  {
+    id: 'fe1190ee-68c3-11ef-9c7d-00a6181404fd',
+    name: '领导审批',
+    createTime: 1725237646192,
+    endTime: null,
+    durationInMillis: null,
+    status: 2,
+    reason: null,
+    ownerUser: null,
+    assigneeUser: {
+      id: 104,
+      nickname: '领导',
+      deptId: 107,
+      deptName: '运维部门'
+    },
+    taskDefinitionKey: 'task-01',
+    processInstanceId: 'fe0c60c6-68c3-11ef-9c7d-00a6181404fd',
+    processInstance: {
+      id: 'fe0c60c6-68c3-11ef-9c7d-00a6181404fd',
+      name: 'oa_leave',
+      createTime: null,
+      processDefinitionId: 'oa_leave:1:6e5ac269-5f87-11ef-bdb6-00a6181404fd',
+      startUser: null
+    },
+    parentTaskId: null,
+    children: null,
+    formId: null,
+    formName: null,
+    formConf: null,
+    formFields: null,
+    formVariables: null
+  },
+  {
+    id: 'fe1190ee-68c3-11ef-9c7d-00a6181404fd',
+    name: '财务总监审核',
+    createTime: 1725237646192,
+    endTime: null,
+    durationInMillis: null,
+    status: 3,
+    reason: null,
+    ownerUser: null,
+    assigneeUser: {
+      id: 104,
+      nickname: '财务总监',
+      deptId: 107,
+      deptName: '运维部门'
+    },
+    taskDefinitionKey: 'task-01',
+    processInstanceId: 'fe0c60c6-68c3-11ef-9c7d-00a6181404fd',
+    processInstance: {
+      id: 'fe0c60c6-68c3-11ef-9c7d-00a6181404fd',
+      name: 'oa_leave',
+      createTime: null,
+      processDefinitionId: 'oa_leave:1:6e5ac269-5f87-11ef-bdb6-00a6181404fd',
+      startUser: null
+    },
+    parentTaskId: null,
+    children: null,
+    formId: null,
+    formName: null,
+    formConf: null,
+    formFields: null,
+    formVariables: null
+  }
+]
+</script>

+ 9 - 50
src/views/bpm/processInstance/detail/index_new.vue

@@ -46,61 +46,18 @@
                 <BusinessFormComponent :id="processInstance.businessKey" />
               </div>
             </div>
+
             <!-- 操作栏按钮 -->
-            <!-- TODO @GoldenZqqq:ProcessInstanceOperationButton,操作按钮。不叫 Container 会好点点,和后端也更统一 -->
-            <ProcessInstanceBtnConatiner
-              ref="processInstanceBtnRef"
+            <ProcessInstanceOperationButton
+              ref="operationButtonRef"
               :processInstance="processInstance"
               :userOptions="userOptions"
               @success="getDetail"
             />
           </el-col>
           <el-col :span="6">
-            <!-- TODO @GoldenZqqq:后续这个,也拆个小组件出来 -->
-            <el-timeline class="pt-20px">
-              <el-timeline-item type="primary" size="large">
-                <div class="flex flex-col items-start gap-2">
-                  <div class="font-bold"> 发起人:{{ processInstance?.startUser?.nickname }}</div>
-                  <el-tag type="success">发起</el-tag>
-                  <div class="text-#a5a5a5 text-12px">
-                    发起时间:{{ formatDate(processInstance.startTime) }}
-                  </div>
-                </div>
-              </el-timeline-item>
-              <el-timeline-item
-                v-for="(activity, index) in tasks"
-                :key="index"
-                type="primary"
-                size="large"
-              >
-                <div class="flex flex-col items-start gap-2">
-                  <div class="font-bold"> 审批人:{{ activity.assigneeUser?.nickname }}</div>
-                  <dict-tag
-                    :type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS"
-                    :value="activity.status"
-                  />
-                  <!-- TODO:暂无该字段 -->
-                  <div v-if="activity.receiveTime" class="text-#a5a5a5 text-12px">
-                    接收时间:{{ formatDate(activity.receiveTime) }}
-                  </div>
-                  <div v-if="activity.createTime" class="text-#a5a5a5 text-12px">
-                    审批时间:{{ formatDate(activity.createTime) }}
-                  </div>
-                  <div v-if="activity.opinion" class="text-#a5a5a5 text-12px w-100%">
-                    <div class="mb-5px">审批意见:</div>
-                    <div
-                      class="w-100% border-1px border-#a5a5a5 border-dashed rounded py-5px px-15px text-#2d2d2d"
-                    >
-                      {{ activity.opinion }}
-                    </div>
-                  </div>
-                </div>
-                <!-- 该节点用户的头像 -->
-                <!-- <template #dot>
-                  <img :src="activity?.avatar" alt="" />
-                </template> -->
-              </el-timeline-item>
-            </el-timeline>
+            <!-- 审批记录时间线 -->
+            <ProcessInstanceTimeline :process-instance="processInstance" :tasks="tasks" />
           </el-col>
         </el-row>
       </el-tab-pane>
@@ -138,6 +95,8 @@ import * as ProcessInstanceApi from '@/api/bpm/processInstance'
 import * as TaskApi from '@/api/bpm/task'
 import ProcessInstanceBpmnViewer from './ProcessInstanceBpmnViewer.vue'
 import ProcessInstanceTaskList from './ProcessInstanceTaskList.vue'
+import ProcessInstanceOperationButton from './ProcessInstanceOperationButton.vue'
+import ProcessInstanceTimeline from './ProcessInstanceTimeline.vue'
 import { registerComponent } from '@/utils/routerHelper'
 import * as UserApi from '@/api/system/user'
 import audit1 from '@/assets/svgs/bpm/audit1.svg'
@@ -151,7 +110,7 @@ const message = useMessage() // 消息弹窗
 const id = query.id as unknown as string // 流程实例的编号
 const processInstanceLoading = ref(false) // 流程实例的加载中
 const processInstance = ref<any>({}) // 流程实例
-const processInstanceBtnRef = ref()
+const operationButtonRef = ref()
 const bpmnXml = ref('') // BPMN XML
 const tasksLoad = ref(true) // 任务的加载中
 const tasks = ref<any[]>([]) // 任务列表
@@ -244,7 +203,7 @@ const getTaskList = async () => {
     })
 
     // 获得需要自己审批的任务
-    processInstanceBtnRef.value.loadRunningTask(tasks.value)
+    operationButtonRef.value?.loadRunningTask(tasks.value)
   } finally {
     tasksLoad.value = false
   }