Browse Source

feat(web-admin): show per-person approval lines on OA progress chain

Render name/opinion/time under multi-approver nodes; hide duplicate node comment.

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu 3 months ago
parent
commit
1e2b903cd7
1 changed files with 66 additions and 1 deletions
  1. 66 1
      web-admin/src/components/oa-approval/OaProgressChain.vue

+ 66 - 1
web-admin/src/components/oa-approval/OaProgressChain.vue

@@ -51,7 +51,22 @@
               </span>
             </span>
           </div>
-          <div v-if="item.commentText" class="oa-flow-card__comment">
+          <div v-if="personLines(item).length" class="oa-person-lines">
+            <p
+              v-for="(line, li) in personLines(item)"
+              :key="`${item.key}-pl-${li}`"
+              class="oa-person-line"
+              :class="{
+                'is-ok': line.tone === 'ok',
+                'is-pending': line.tone === 'pending',
+                'is-danger': line.tone === 'danger',
+                'is-mute': line.tone === 'mute'
+              }"
+            >
+              {{ line.text }}
+            </p>
+          </div>
+          <div v-else-if="showNodeComment(item)" class="oa-flow-card__comment">
             意见:{{ item.commentText }}
           </div>
         </div>
@@ -61,6 +76,11 @@
 </template>
 
 <script setup lang="ts">
+  import {
+    formatProgressPersonLines,
+    type ProgressPersonLine
+  } from '@/utils/oa-progress-person-lines'
+
   defineOptions({ name: 'OaProgressChain' })
 
   export type OaProgressPerson = {
@@ -149,6 +169,20 @@
     return [{ nickName: name, status: item.status }]
   }
 
+  function personLines(item: OaProgressChainItem): ProgressPersonLine[] {
+    if (item.kind === 'terminal' || item.kind === 'submit') return []
+    if (item.taskType === 'cc' || item.signMode === 'cc') return []
+    const list = displayPeople(item)
+    if (!list.length) return []
+    return formatProgressPersonLines(list)
+  }
+
+  function showNodeComment(item: OaProgressChainItem): boolean {
+    // 有按人行时不再展示节点级拼接意见,避免双份
+    if (personLines(item).length) return false
+    return Boolean(item.commentText)
+  }
+
   function personChipClass(status?: string) {
     const s = status || ''
     if (s === 'approved' || s === 'completed') return 'is-ok'
@@ -338,6 +372,37 @@
     line-height: 1.4;
   }
 
+  .oa-person-lines {
+    margin-top: 8px;
+    display: grid;
+    gap: 4px;
+  }
+
+  .oa-person-line {
+    margin: 0;
+    color: var(--mint-text, #334155);
+    font-size: 12px;
+    line-height: 1.55;
+    word-break: break-word;
+
+    &.is-ok {
+      color: #059669;
+      font-weight: 500;
+    }
+
+    &.is-pending {
+      color: #d97706;
+    }
+
+    &.is-danger {
+      color: #dc2626;
+    }
+
+    &.is-mute {
+      color: #94a3b8;
+    }
+  }
+
   .oa-person-chip {
     display: inline-flex;
     gap: 3px;