Forráskód Böngészése

feat: 工作流审批页面-时间线组件样式布局重构与展示逻辑调整

GoldenZqqq 10 hónapja
szülő
commit
c7ecb0a69f

+ 1 - 1
src/assets/svgs/bpm/condition.svg

@@ -1 +1 @@
-<svg t="1729585232424" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1602" width="200" height="200"><path d="M925.5 898.9H804.9c-19 0-34.5-15.4-34.5-34.4V761.3c0-19 15.4-34.4 34.5-34.4h34.5V572.2c0-19-15.4-34.4-34.5-34.4H529.2V727h34.5c19 0 34.5 15.4 34.5 34.4v103.2c0 19-15.4 34.4-34.5 34.4H443.1c-19 0-34.5-15.4-34.5-34.4V761.3c0-19 15.4-34.4 34.5-34.4h34.5V537.8H219.1c-19 0-34.5 15.4-34.5 34.4V727h34.5c19 0 34.5 15.4 34.5 34.4v103.2c0 19-15.4 34.4-34.5 34.4H98.5c-19 0-34.5-15.4-34.5-34.4V761.3c0-19 15.4-34.4 34.5-34.4H133V555c0-38 30.9-68.8 68.9-68.8h275.7V297.1h-34.5c-19 0-34.5-15.4-34.5-34.4V159.5c0-19 15.4-34.4 34.5-34.4h120.6c19 0 34.5 15.4 34.5 34.4v103.2c0 19-15.4 34.4-34.5 34.4h-34.5v189.2h292.9c38.1 0 68.9 30.8 68.9 68.8v172h34.5c19 0 34.5 15.4 34.5 34.4v103.2c0 18.8-15.4 34.2-34.5 34.2z m0 0" p-id="1603"></path></svg>
+<svg t="1729585232424" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1602" width="200" height="200"><path d="M925.5 898.9H804.9c-19 0-34.5-15.4-34.5-34.4V761.3c0-19 15.4-34.4 34.5-34.4h34.5V572.2c0-19-15.4-34.4-34.5-34.4H529.2V727h34.5c19 0 34.5 15.4 34.5 34.4v103.2c0 19-15.4 34.4-34.5 34.4H443.1c-19 0-34.5-15.4-34.5-34.4V761.3c0-19 15.4-34.4 34.5-34.4h34.5V537.8H219.1c-19 0-34.5 15.4-34.5 34.4V727h34.5c19 0 34.5 15.4 34.5 34.4v103.2c0 19-15.4 34.4-34.5 34.4H98.5c-19 0-34.5-15.4-34.5-34.4V761.3c0-19 15.4-34.4 34.5-34.4H133V555c0-38 30.9-68.8 68.9-68.8h275.7V297.1h-34.5c-19 0-34.5-15.4-34.5-34.4V159.5c0-19 15.4-34.4 34.5-34.4h120.6c19 0 34.5 15.4 34.5 34.4v103.2c0 19-15.4 34.4-34.5 34.4h-34.5v189.2h292.9c38.1 0 68.9 30.8 68.9 68.8v172h34.5c19 0 34.5 15.4 34.5 34.4v103.2c0 18.8-15.4 34.2-34.5 34.2z m0 0" p-id="1603" fill="#fff"></path></svg>

+ 1 - 1
src/assets/svgs/bpm/copy.svg

@@ -1 +1 @@
-<svg t="1729584191390" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1449" width="200" height="200"><path d="M901.489435 536.822664v-0.931601l-1.001722-198.240726c-0.100172-19.162936-9.21584-37.474409-25.043042-50.246361-14.024104-11.349507-32.265456-17.60025-51.348255-17.610268l-618.062295-0.18031c-19.142902 0-37.424323 6.280795-51.478478 17.690405-15.827203 12.842072-24.902802 31.2437-24.892785 50.486775v196.798247A114.987635 114.987635 0 1 0 195.295664 536.922836V338.782282c1.15198-1.252152 4.808264-3.596181 10.768509-3.596181l276.725622 0.090155v199.753326a114.987635 114.987635 0 1 0 65.612772 1.412428V335.326342l275.693849 0.080138c6.01033 0 9.626546 2.344029 10.768508 3.596181l1.001722 195.70637a114.987635 114.987635 0 1 0 65.592737 2.113633zM214.979496 645.910158a56.437001 56.437001 0 1 1-56.437001-56.437001 56.507122 56.507122 0 0 1 56.437001 56.437001z m354.689623 0a56.437001 56.437001 0 1 1-56.437001-56.437001 56.507122 56.507122 0 0 1 56.437001 56.437001z m295.507904 56.437001a56.437001 56.437001 0 1 1 56.437001-56.437001 56.507122 56.507122 0 0 1-56.457035 56.437001z" p-id="1450"></path></svg>
+<svg t="1729649333541" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1644" width="200" height="200"><path d="M647.888 893.84L491.904 571.52l393.888-393.888-237.904 716.208zM872.32 123.232L459.872 535.68 134.96 380.88 872.32 123.232z m90.72-68.32a23.968 23.968 0 0 0-24.784-5.568L64.08 354.816a23.984 23.984 0 0 0-2.4 44.32l381.392 181.728 187.36 387.088a24.048 24.048 0 0 0 23.152 13.504 24.032 24.032 0 0 0 21.232-16.4L968.96 79.552c2.88-8.672 0.592-18.24-5.92-24.64z" fill="#fff" p-id="1645"></path></svg>

+ 1 - 1
src/assets/svgs/bpm/parallel.svg

@@ -1 +1 @@
-<svg t="1729585239190" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1755" width="200" height="200"><path d="M901.489435 536.822664v-0.931601l-1.001722-198.240726c-0.100172-19.162936-9.21584-37.474409-25.043042-50.246361-14.024104-11.349507-32.265456-17.60025-51.348255-17.610268l-618.062295-0.18031c-19.142902 0-37.424323 6.280795-51.478478 17.690405-15.827203 12.842072-24.902802 31.2437-24.892785 50.486775v196.798247A114.987635 114.987635 0 1 0 195.295664 536.922836V338.782282c1.15198-1.252152 4.808264-3.596181 10.768509-3.596181l276.725622 0.090155v199.753326a114.987635 114.987635 0 1 0 65.612772 1.412428V335.326342l275.693849 0.080138c6.01033 0 9.626546 2.344029 10.768508 3.596181l1.001722 195.70637a114.987635 114.987635 0 1 0 65.592737 2.113633zM214.979496 645.910158a56.437001 56.437001 0 1 1-56.437001-56.437001 56.507122 56.507122 0 0 1 56.437001 56.437001z m354.689623 0a56.437001 56.437001 0 1 1-56.437001-56.437001 56.507122 56.507122 0 0 1 56.437001 56.437001z m295.507904 56.437001a56.437001 56.437001 0 1 1 56.437001-56.437001 56.507122 56.507122 0 0 1-56.457035 56.437001z" p-id="1756"></path></svg>
+<svg t="1729585239190" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1755" width="200" height="200"><path d="M901.489435 536.822664v-0.931601l-1.001722-198.240726c-0.100172-19.162936-9.21584-37.474409-25.043042-50.246361-14.024104-11.349507-32.265456-17.60025-51.348255-17.610268l-618.062295-0.18031c-19.142902 0-37.424323 6.280795-51.478478 17.690405-15.827203 12.842072-24.902802 31.2437-24.892785 50.486775v196.798247A114.987635 114.987635 0 1 0 195.295664 536.922836V338.782282c1.15198-1.252152 4.808264-3.596181 10.768509-3.596181l276.725622 0.090155v199.753326a114.987635 114.987635 0 1 0 65.612772 1.412428V335.326342l275.693849 0.080138c6.01033 0 9.626546 2.344029 10.768508 3.596181l1.001722 195.70637a114.987635 114.987635 0 1 0 65.592737 2.113633zM214.979496 645.910158a56.437001 56.437001 0 1 1-56.437001-56.437001 56.507122 56.507122 0 0 1 56.437001 56.437001z m354.689623 0a56.437001 56.437001 0 1 1-56.437001-56.437001 56.507122 56.507122 0 0 1 56.437001 56.437001z m295.507904 56.437001a56.437001 56.437001 0 1 1 56.437001-56.437001 56.507122 56.507122 0 0 1-56.457035 56.437001z" p-id="1756" fill='#fff'></path></svg>

+ 78 - 166
src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue

@@ -38,88 +38,80 @@
         <div class="flex items-center flex-wrap mt-1">
           <!-- 情况一:遍历每个审批节点下的【进行中】task 任务 -->
           <div v-for="(task, idx) in activity.tasks" :key="idx" class="flex items-center">
-            <div class="flex flex-col pr-2">
-              <div class="position-relative" v-if="task.assigneeUser || task.ownerUser">
-                <!-- 信息:头像 -->
-                <el-avatar
-                  v-if="task.assigneeUser && task.assigneeUser.avatar"
-                  :size="36"
-                  :src="task.assigneeUser.avatar"
-                />
-                <el-avatar v-else-if="task.assigneeUser && task.assigneeUser.nickname">
-                  {{ task.assigneeUser.nickname.substring(0, 1) }}
-                </el-avatar>
-                <el-avatar
-                  v-else-if="task.ownerUser && task.ownerUser.avatar"
-                  :src="task.ownerUser.avatar"
-                />
-                <el-avatar v-else-if="task.ownerUser && task.ownerUser.nickname">
-                  {{ task.ownerUser.nickname.substring(0, 1) }}
-                </el-avatar>
-                <!-- 信息:任务 ICON -->
+            <div class="flex flex-col pr-2 gap2">
+              <div
+                class="position-relative flex flex-wrap gap2"
+                v-if="task.assigneeUser || task.ownerUser"
+              >
+                <!-- 信息:头像昵称 -->
                 <div
-                  class="position-absolute top-26px left-26px bg-#fff rounded-full flex items-center p-2px"
+                  class="bg-gray-100 h-35px rounded-3xl flex items-center p-8px gap-2 dark:color-gray-600 position-relative"
                 >
-                  <Icon
-                    :size="12"
-                    :icon="statusIconMap2[task.status]?.icon"
-                    :color="statusIconMap2[task.status]?.color"
-                  />
-                </div>
-              </div>
-              <div class="flex flex-col mt-1">
-                <!-- 信息:昵称 -->
-                <div
-                  v-if="task.assigneeUser && task.assigneeUser.nickname"
-                  class="text-12px text-align-center"
-                >
-                  {{ task.assigneeUser.nickname }}
+                  <template v-if="task.assigneeUser?.avatar || task.assigneeUser?.nickname">
+                    <el-avatar
+                      :size="28"
+                      v-if="task.assigneeUser?.avatar"
+                      :src="task.assigneeUser?.avatar"
+                    />
+                    <el-avatar :size="28" v-else>
+                      {{ task.assigneeUser?.nickname.substring(0, 1) }}
+                    </el-avatar>
+                    {{ task.assigneeUser?.nickname }}
+                  </template>
+                  <template v-else-if="task.ownerUser?.avatar || task.ownerUser?.nickname">
+                    <el-avatar
+                      :size="28"
+                      v-if="task.ownerUser?.avatar"
+                      :src="task.ownerUser?.avatar"
+                    />
+                    <el-avatar :size="28" v-else>
+                      {{ task.ownerUser?.nickname.substring(0, 1) }}
+                    </el-avatar>
+                    {{ task.ownerUser?.nickname }}
+                  </template>
+                  <!-- 信息:任务 ICON -->
+                  <div
+                    v-if="onlyStatusIconShow.includes(task.status)"
+                    class="position-absolute top-22px left-26px bg-#fff rounded-full flex items-center p-2px"
+                  >
+                    <Icon
+                      :size="12"
+                      :icon="statusIconMap2[task.status]?.icon"
+                      :color="statusIconMap2[task.status]?.color"
+                    />
+                  </div>
                 </div>
+                <!-- 情况二:遍历每个审批节点下的【候选的】task 任务。例如说,1)依次审批,2)未来的审批任务等 -->
                 <div
-                  v-else-if="task.ownerUser && task.ownerUser.nickname"
-                  class="text-10px text-align-center"
+                  v-for="(user, idx1) in activity.candidateUsers"
+                  :key="idx1"
+                  class="bg-gray-100 h-35px rounded-3xl flex items-center p-8px gap-2 dark:color-gray-600 position-relative"
                 >
-                  {{ task.ownerUser.nickname }}
-                </div>
-                <div
-                  v-if="task.reason && activity.nodeType === NodeType.USER_TASK_NODE"
-                  class="text-#a5a5a5 text-13px mt-1"
-                >
-                  审批意见:{{ task.reason }}
-                </div>
-              </div>
-            </div>
-          </div>
-          <!-- 情况二:遍历每个审批节点下的【候选的】task 任务。例如说,1)依次审批,2)未来的审批任务等 -->
-          <div
-            v-for="(user, idx1) in activity.candidateUsers"
-            :key="idx1"
-            class="flex items-center self-start"
-          >
-            <div class="flex items-center flex-col pr-2">
-              <div class="position-relative">
-                <!-- 信息:头像 -->
-                <el-avatar :size="36" v-if="user.avatar" :src="user.avatar" />
-                <el-avatar v-else-if="user.nickname && user.nickname">
-                  {{ user.nickname.substring(0, 1) }}
-                </el-avatar>
-                <!-- 信息:任务 ICON -->
-                <div
-                  class="position-absolute top-26px left-26px bg-#fff rounded-full flex items-center p-2px"
-                >
-                  <Icon
-                    :size="12"
-                    :icon="statusIconMap2['-1']?.icon"
-                    :color="statusIconMap2['-1']?.color"
-                  />
-                </div>
-              </div>
-              <div class="flex flex-col mt-1">
-                <!-- 信息:昵称 -->
-                <div v-if="user.nickname" class="text-10px text-align-center">
+                  <el-avatar :size="28" v-if="user.avatar" :src="user.avatar" />
+                  <el-avatar :size="28" v-else>
+                    {{ user.nickname.substring(0, 1) }}
+                  </el-avatar>
                   {{ user.nickname }}
+
+                  <!-- 信息:任务 ICON -->
+                  <div
+                    v-if="onlyStatusIconShow.includes(task.status)"
+                    class="position-absolute top-22px left-26px bg-#fff rounded-full flex items-center p-2px"
+                  >
+                    <Icon
+                      :size="12"
+                      :icon="statusIconMap2['-1']?.icon"
+                      :color="statusIconMap2['-1']?.color"
+                    />
+                  </div>
                 </div>
               </div>
+              <div
+                v-if="task.reason && activity.nodeType === NodeType.USER_TASK_NODE"
+                class="text-#a5a5a5 text-13px mt-1 w-full bg-#f8f8fa p2 rounded-md"
+              >
+                审批意见:{{ task.reason }}
+              </div>
             </div>
           </div>
         </div>
@@ -141,93 +133,9 @@ import conditionSvg from '@/assets/svgs/bpm/condition.svg'
 import parallelSvg from '@/assets/svgs/bpm/parallel.svg'
 
 defineOptions({ name: 'BpmProcessInstanceTimeline' })
-// defineProps<{
-//   approveNodes: ProcessInstanceApi.ApprovalNodeInfo[] // 审批节点信息
-// }>()
-const approveNodes = [
-  {
-    id: 1,
-    name: '发起审批',
-    nodeType: NodeType.START_USER_NODE,
-    status: TaskStatusEnum.NOT_START,
-    startTime: new Date('2024-10-01 10:00:00'),
-    endTime: null,
-    candidateUsers: [],
-    tasks: []
-  },
-  {
-    id: 2,
-    name: '经理审批',
-    nodeType: NodeType.USER_TASK_NODE,
-    status: TaskStatusEnum.RUNNING, // 审批中
-    startTime: new Date('2024-10-02 11:00:00'),
-    endTime: null,
-    candidateUsers: [
-      {
-        nickname: '张经理',
-        avatar: 'https://picsum.photos/200?r=1'
-      },
-      {
-        nickname: '张经理',
-        avatar: 'https://picsum.photos/200?r=1'
-      },
-      {
-        nickname: '张经理',
-        avatar: 'https://picsum.photos/200?r=1'
-      },
-      {
-        nickname: '张经理',
-        avatar: 'https://picsum.photos/200?r=1'
-      }
-    ],
-    tasks: [
-      {
-        assigneeUser: {
-          nickname: '李经理',
-          avatar: 'https://picsum.photos/200?r=1'
-        },
-        ownerUser: null,
-        status: TaskStatusEnum.RUNNING, // 审批中
-        reason: '同意'
-      }
-    ]
-  },
-  {
-    id: 3,
-    name: '财务审批',
-    nodeType: NodeType.USER_TASK_NODE,
-    status: TaskStatusEnum.APPROVE, // 审批通过
-    startTime: new Date('2024-10-03 14:00:00'),
-    endTime: new Date('2024-10-03 15:00:00'),
-    candidateUsers: [],
-    tasks: [
-      {
-        assigneeUser: {
-          nickname: '王财务',
-          avatar: 'https://picsum.photos/200?r=1'
-        },
-        ownerUser: null,
-        status: TaskStatusEnum.APPROVE, // 审批通过
-        reason: '审批通过'
-      }
-    ]
-  },
-  {
-    id: 4,
-    name: '总经理审批',
-    nodeType: NodeType.USER_TASK_NODE,
-    status: TaskStatusEnum.NOT_START, // 未开始
-    startTime: null,
-    endTime: null,
-    candidateUsers: [
-      {
-        nickname: '总经理',
-        avatar: 'https://picsum.photos/200?r=1'
-      }
-    ],
-    tasks: []
-  }
-]
+defineProps<{
+  approveNodes: ProcessInstanceApi.ApprovalNodeInfo[] // 审批节点信息
+}>()
 
 // 审批节点
 const statusIconMap2 = {
@@ -273,17 +181,21 @@ const statusIconMap = {
 
 const nodeTypeSvgMap = {
   // 发起人节点
-  [NodeType.START_USER_NODE]: { color: '', svg: starterSvg },
+  [NodeType.START_USER_NODE]: { color: '#ffffff', svg: starterSvg },
   // 审批人节点
-  [NodeType.USER_TASK_NODE]: { color: '', svg: auditorSvg },
+  [NodeType.USER_TASK_NODE]: { color: '#ff943e', svg: auditorSvg },
   // 抄送人节点
-  [NodeType.COPY_TASK_NODE]: { color: '', svg: copySvg },
+  [NodeType.COPY_TASK_NODE]: { color: '#3296fb', svg: copySvg },
   // 条件分支节点
-  [NodeType.CONDITION_NODE]: { color: '', svg: conditionSvg },
+  [NodeType.CONDITION_NODE]: { color: '#14bb83', svg: conditionSvg },
   // 并行分支节点
-  [NodeType.PARALLEL_BRANCH_NODE]: { color: '', svg: parallelSvg }
+  [NodeType.PARALLEL_BRANCH_NODE]: { color: '#14bb83', svg: parallelSvg }
 }
 
+// 只有只有状态是 -1、0、1 才展示头像右小角状态小icon
+const onlyStatusIconShow = [-1, 0, 1]
+
+// timeline时间线上icon图标
 const getApprovalNodeImg = (nodeType: NodeType) => {
   return nodeTypeSvgMap[nodeType]?.svg
 }