zlwu 5 months ago
parent
commit
e90728732d
28 changed files with 165 additions and 65 deletions
  1. BIN
      bx/bx-backend/app/schemas/__pycache__/advance.cpython-312.pyc
  2. BIN
      bx/bx-backend/app/schemas/__pycache__/reimburse.cpython-312.pyc
  3. 1 0
      bx/bx-backend/app/schemas/advance.py
  4. 1 0
      bx/bx-backend/app/schemas/reimburse.py
  5. BIN
      bx/bx-backend/app/services/__pycache__/advance.cpython-312.pyc
  6. BIN
      bx/bx-backend/app/services/__pycache__/reimburse.cpython-312.pyc
  7. 8 0
      bx/bx-backend/app/services/advance.py
  8. 8 0
      bx/bx-backend/app/services/reimburse.py
  9. 2 0
      bx/bx-mobile/src/api/index.ts
  10. 19 25
      bx/bx-mobile/src/views/home/HomePage.vue
  11. 22 1
      bx/bx-web/src/styles/index.css
  12. 7 1
      bx/bx-web/src/utils/format.ts
  13. 10 3
      bx/bx-web/src/views/pages/AdvanceApplyPage.vue
  14. 19 5
      bx/bx-web/src/views/pages/AdvanceApprovePage.vue
  15. 6 1
      bx/bx-web/src/views/pages/AdvanceIssuePage.vue
  16. 6 3
      bx/bx-web/src/views/pages/AllPage.vue
  17. 1 1
      bx/bx-web/src/views/pages/DemoPage.vue
  18. 1 1
      bx/bx-web/src/views/pages/ExpenseProjectPage.vue
  19. 1 1
      bx/bx-web/src/views/pages/MenuManagePage.vue
  20. 6 3
      bx/bx-web/src/views/pages/MinePage.vue
  21. 2 2
      bx/bx-web/src/views/pages/PaymentPage.vue
  22. 10 3
      bx/bx-web/src/views/pages/ReimburseApplyPage.vue
  23. 19 5
      bx/bx-web/src/views/pages/ReimburseApprovePage.vue
  24. 1 1
      bx/bx-web/src/views/pages/RoleManagePage.vue
  25. 10 4
      bx/bx-web/src/views/pages/TodoPage.vue
  26. 1 1
      bx/bx-web/src/views/pages/UserManagePage.vue
  27. 2 2
      bx/bx-web/src/views/pages/WfAdvancePage.vue
  28. 2 2
      bx/bx-web/src/views/pages/WfReimbursePage.vue

BIN
bx/bx-backend/app/schemas/__pycache__/advance.cpython-312.pyc


BIN
bx/bx-backend/app/schemas/__pycache__/reimburse.cpython-312.pyc


+ 1 - 0
bx/bx-backend/app/schemas/advance.py

@@ -118,6 +118,7 @@ class AdvanceMyStatsOut(BaseModel):
     issued_count: int
     issued_amount: float
     month_apply_amount: float
+    month_apply_count: int
     offset_total: float
 
 

+ 1 - 0
bx/bx-backend/app/schemas/reimburse.py

@@ -155,6 +155,7 @@ class ReimburseMyStatsOut(BaseModel):
     rejected_count: int
     approved_amount: float
     month_apply_amount: float
+    month_apply_count: int
 
 
 class ReimburseApproverPendingStatsOut(BaseModel):

BIN
bx/bx-backend/app/services/__pycache__/advance.cpython-312.pyc


BIN
bx/bx-backend/app/services/__pycache__/reimburse.cpython-312.pyc


+ 8 - 0
bx/bx-backend/app/services/advance.py

@@ -374,6 +374,13 @@ class AdvanceService:
             .scalar()
             or 0
         )
+        month_apply_count = (
+            db.query(func.count())
+            .select_from(AdvanceApply)
+            .filter(base, AdvanceApply.create_time >= m0, AdvanceApply.create_time < m1)
+            .scalar()
+            or 0
+        )
         offset_total = (
             db.query(func.coalesce(func.sum(ReimburseOffset.offset_amount), 0))
             .join(AdvanceApply, ReimburseOffset.advance_id == AdvanceApply.id)
@@ -390,6 +397,7 @@ class AdvanceService:
             "issued_count": int(issued),
             "issued_amount": float(issued_amount),
             "month_apply_amount": float(month_apply_amount),
+            "month_apply_count": int(month_apply_count),
             "offset_total": float(offset_total),
         }
 

+ 8 - 0
bx/bx-backend/app/services/reimburse.py

@@ -578,6 +578,13 @@ class ReimburseService:
             .scalar()
             or 0
         )
+        month_apply_count = (
+            db.query(func.count())
+            .select_from(ReimburseApply)
+            .filter(base, ReimburseApply.create_time >= m0, ReimburseApply.create_time < m1)
+            .scalar()
+            or 0
+        )
         return {
             "total_count": int(total_count),
             "pending_count": int(pending),
@@ -585,6 +592,7 @@ class ReimburseService:
             "rejected_count": int(rejected_count),
             "approved_amount": float(approved_amount),
             "month_apply_amount": float(month_apply_amount),
+            "month_apply_count": int(month_apply_count),
         }
 
     @staticmethod

+ 2 - 0
bx/bx-mobile/src/api/index.ts

@@ -63,6 +63,7 @@ export const workflowApi = {
 export const advanceApi = {
   list: (params?: Record<string, any>) => client.get('/advances/', { params }),
   my: (params?: Record<string, any>) => client.get('/advances/my', { params }),
+  myStats: () => client.get('/advances/my/stats'),
   pendingApproval: (params?: Record<string, any>) =>
     client.get('/advances/pending-approval', { params }),
   approvedByMe: (params?: Record<string, any>) =>
@@ -83,6 +84,7 @@ export const reimburseApi = {
   generateTitle: () => client.get('/reimburses/generate-title'),
   list: (params?: Record<string, any>) => client.get('/reimburses/', { params }),
   my: (params?: Record<string, any>) => client.get('/reimburses/my', { params }),
+  myStats: () => client.get('/reimburses/my/stats'),
   pendingApproval: (params?: Record<string, any>) =>
     client.get('/reimburses/pending-approval', { params }),
   approvedByMe: (params?: Record<string, any>) =>

+ 19 - 25
bx/bx-mobile/src/views/home/HomePage.vue

@@ -119,33 +119,27 @@ onMounted(async () => {
 })
 
 /* ───── Fetch & Compute Stats ───── */
+function pagedRows(res: any): any[] {
+  const d = res?.data
+  if (!d) return []
+  return d.rows ?? d.items ?? d.list ?? (Array.isArray(d) ? d : [])
+}
+
 async function fetchHomeData() {
   try {
-    const [advanceRes, reimburseRes] = await Promise.all([
-      advanceApi.my({ page: 1, pageSize: 200 }).catch(() => null),
-      reimburseApi.my({ page: 1, pageSize: 200 }).catch(() => null),
+    const [advStatsRes, reimStatsRes] = await Promise.all([
+      advanceApi.myStats().catch(() => null),
+      reimburseApi.myStats().catch(() => null),
     ])
 
-    const advanceItems: any[] = (advanceRes as any)?.data?.items || []
-    const reimburseItems: any[] = (reimburseRes as any)?.data?.items || []
-    const advanceTotal = (advanceRes as any)?.data?.total || 0
-    const reimburseTotal = (reimburseRes as any)?.data?.total || 0
-
-    const allItems = [...advanceItems, ...reimburseItems]
-    const totalCount = advanceTotal + reimburseTotal
-    const approvedCount = allItems.filter((i: any) => i.status === 'approved').length
-    const pendingCount = allItems.filter((i: any) => i.status === 'pending').length
-    const totalAmount = allItems.reduce(
-      (sum: number, i: any) => sum + (Number(i.amount) || 0),
-      0,
-    )
-
-    const now = new Date()
-    const submittedThisMonth = allItems.filter((i: any) => {
-      if (!i.createdAt) return false
-      const d = new Date(i.createdAt)
-      return d.getFullYear() === now.getFullYear() && d.getMonth() === now.getMonth()
-    }).length
+    const a = (advStatsRes as any)?.data ?? {}
+    const r = (reimStatsRes as any)?.data ?? {}
+    const submittedThisMonth = Number(r.monthApplyCount ?? 0) + Number(a.monthApplyCount ?? 0)
+    const pendingCount = Number(r.pendingCount ?? 0) + Number(a.pendingCount ?? 0)
+    const approvedCount =
+      Number(r.approvedCount ?? 0) + Number(a.approvedPassCount ?? 0) + Number(a.issuedCount ?? 0)
+    const totalCount = Number(r.totalCount ?? 0) + Number(a.totalCount ?? 0)
+    const totalAmount = 0
 
     stats.value = { submittedThisMonth, pendingCount, approvedCount, totalAmount, totalCount }
 
@@ -155,8 +149,8 @@ async function fetchHomeData() {
       reimburseApi.pendingApproval({ page: 1, pageSize: 5 }).catch(() => null),
     ])
 
-    const pendingAdvanceItems: any[] = (pendingAdvanceRes as any)?.data?.items || []
-    const pendingReimburseItems: any[] = (pendingReimburseRes as any)?.data?.items || []
+    const pendingAdvanceItems: any[] = pagedRows(pendingAdvanceRes)
+    const pendingReimburseItems: any[] = pagedRows(pendingReimburseRes)
     const pendingAdvanceTotal = (pendingAdvanceRes as any)?.data?.total || 0
     const pendingReimburseTotal = (pendingReimburseRes as any)?.data?.total || 0
 

+ 22 - 1
bx/bx-web/src/styles/index.css

@@ -965,6 +965,16 @@ body {
 
 .bx-table .col-actions .cell {
   white-space: nowrap;
+  display: inline-flex;
+  flex-wrap: nowrap;
+  align-items: center;
+  gap: 6px;
+  justify-content: flex-start;
+}
+
+/* 列表「当前节点」为空:无标签,占位与次要色 */
+.node-current-empty {
+  color: var(--text-muted);
 }
 
 /* 列表合计:第 4 列显示「本页合计(n单)」加粗 */
@@ -1005,7 +1015,18 @@ body {
 .bx-tag--pending { color: #475569; border-color: #cbd5e1; }
 .bx-tag--processing { color: #00a874; border-color: #66d9b3; }
 .bx-tag--done { color: #0f766e; border-color: #5eead4; }
-.bx-tag--warning { color: #d97706; border-color: #f6c453; }
+/* 审批中等:浅底表格上需可见描边,勿用近白/透明边 */
+.bx-tag--warning {
+  color: #b45309;
+  background: #fffbeb;
+  border-color: #f59e0b;
+}
+/* 历史误用 tone=warn 时与 warning 对齐 */
+.bx-tag--warn {
+  color: #b45309;
+  background: #fffbeb;
+  border-color: #f59e0b;
+}
 .bx-tag--error { color: #dc2626; border-color: #fca5a5; }
 .bx-tag--info { color: #0f766e; border-color: #5eead4; }
 

+ 7 - 1
bx/bx-web/src/utils/format.ts

@@ -21,7 +21,7 @@ export function statusTone(status: number | string | null | undefined): string {
     1: 'done',
     0: 'error',
     draft: 'info',
-    pending: 'warn',
+    pending: 'warning',
     approved: 'done',
     rejected: 'error',
     issued: 'done',
@@ -41,3 +41,9 @@ export function menuTypeLabel(type: number): string {
 export function formatSumMoney(n: number): string {
   return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
 }
+
+/** 列表「当前节点」是否有可展示文案(空/null/空白串视为无) */
+export function hasWorkflowNode(value: unknown): boolean {
+  if (value == null) return false
+  return String(value).trim() !== ''
+}

+ 10 - 3
bx/bx-web/src/views/pages/AdvanceApplyPage.vue

@@ -3,7 +3,7 @@ import { reactive, ref, computed, onMounted } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { Plus, EditPen, Upload, View, Close, Delete } from '@element-plus/icons-vue'
 import { advanceApi, paymentApi } from '../../api'
-import { statusLabel, statusTone, formatSumMoney } from '../../utils/format'
+import { statusLabel, statusTone, formatSumMoney, hasWorkflowNode } from '../../utils/format'
 import { useServerPaged } from '../../hooks/useServerPaged'
 import ListPageScaffold from '../../components/template/ListPageScaffold.vue'
 import BaseButton from '../../components/base/BaseButton.vue'
@@ -400,8 +400,15 @@ function summaryMethod(params: { data: any[] }) {
             <BaseTag :tone="statusTone(row.status)">{{ statusLabel(row.status) }}</BaseTag>
           </template>
         </el-table-column>
-        <el-table-column prop="currentNode" label="当前节点" min-width="120" />
-        <el-table-column label="操作" width="360" fixed="right" class-name="col-actions">
+        <el-table-column prop="currentNode" label="当前节点" min-width="120">
+          <template #default="{ row }">
+            <BaseTag v-if="hasWorkflowNode(row.currentNode)" :tone="statusTone(row.currentNode)">
+              {{ statusLabel(row.currentNode) }}
+            </BaseTag>
+            <span v-else class="node-current-empty">-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" :min-width="420" fixed="right" class-name="col-actions">
           <template #default="{ row }">
             <BaseOpButton primary :icon="View" @click="openView(row)">查看</BaseOpButton>
             <BaseOpButton v-if="row.status === 'draft' || row.status === 'rejected'" :icon="EditPen" @click="openEdit(row)">编辑</BaseOpButton>

+ 19 - 5
bx/bx-web/src/views/pages/AdvanceApprovePage.vue

@@ -3,7 +3,7 @@ import { reactive, ref, computed, onMounted } from 'vue'
 import { ElMessage } from 'element-plus'
 import { Check, Close, View } from '@element-plus/icons-vue'
 import { advanceApi } from '../../api'
-import { statusLabel, statusTone, formatSumMoney } from '../../utils/format'
+import { statusLabel, statusTone, formatSumMoney, hasWorkflowNode } from '../../utils/format'
 import { useServerPaged } from '../../hooks/useServerPaged'
 import { useApplicantOptions } from '../../hooks/useApplicantOptions'
 import ListPageScaffold from '../../components/template/ListPageScaffold.vue'
@@ -314,9 +314,16 @@ async function handleConfirmApprove() {
             <el-table-column prop="reason" label="申请原因" min-width="160" />
             <el-table-column prop="purpose" label="申请目的" min-width="160" />
             <el-table-column prop="amount" label="申请金额(元)" class-name="col-money" min-width="120" />
-            <el-table-column prop="currentNode" label="当前节点" min-width="120" />
+            <el-table-column prop="currentNode" label="当前节点" min-width="120">
+              <template #default="{ row }">
+                <BaseTag v-if="hasWorkflowNode(row.currentNode)" :tone="statusTone(row.currentNode)">
+                  {{ statusLabel(row.currentNode) }}
+                </BaseTag>
+                <span v-else class="node-current-empty">-</span>
+              </template>
+            </el-table-column>
             <el-table-column prop="applyTime" label="申请时间" min-width="140" />
-            <el-table-column label="操作" width="280" fixed="right" class-name="col-actions">
+            <el-table-column label="操作" :min-width="340" fixed="right" class-name="col-actions">
               <template #default="{ row }">
                 <BaseOpButton primary :icon="View" @click="openView(row)">查看</BaseOpButton>
                 <BaseOpButton :icon="Check" @click="openApproveDialog([row], 'approve')">通过</BaseOpButton>
@@ -392,9 +399,16 @@ async function handleConfirmApprove() {
                 <BaseTag :tone="statusTone(row.status)">{{ statusLabel(row.status) }}</BaseTag>
               </template>
             </el-table-column>
-            <el-table-column prop="currentNode" label="当前节点" min-width="120" />
+            <el-table-column prop="currentNode" label="当前节点" min-width="120">
+              <template #default="{ row }">
+                <BaseTag v-if="hasWorkflowNode(row.currentNode)" :tone="statusTone(row.currentNode)">
+                  {{ statusLabel(row.currentNode) }}
+                </BaseTag>
+                <span v-else class="node-current-empty">-</span>
+              </template>
+            </el-table-column>
             <el-table-column prop="applyTime" label="申请时间" min-width="140" />
-            <el-table-column label="操作" width="120" fixed="right" class-name="col-actions">
+            <el-table-column label="操作" :min-width="120" fixed="right" class-name="col-actions">
               <template #default="{ row }">
                 <BaseOpButton primary :icon="View" @click="openView(row)">查看</BaseOpButton>
               </template>

+ 6 - 1
bx/bx-web/src/views/pages/AdvanceIssuePage.vue

@@ -443,7 +443,12 @@ async function openView(row: any) {
             {{ row.issueUserName ?? '-' }}
           </template>
         </el-table-column>
-        <el-table-column label="操作" :width="activeTab === 'pending' ? '260' : '140'" fixed="right" class-name="col-actions">
+        <el-table-column
+          label="操作"
+          :min-width="activeTab === 'pending' ? 340 : 200"
+          fixed="right"
+          class-name="col-actions"
+        >
           <template #default="{ row }">
             <BaseOpButton v-if="activeTab === 'pending'" :icon="Check" @click="openIssueDialog(row)">
               标记发放

+ 6 - 3
bx/bx-web/src/views/pages/AllPage.vue

@@ -3,7 +3,7 @@ import { computed, onMounted, reactive, ref } from 'vue'
 import { ElMessage } from 'element-plus'
 import { View } from '@element-plus/icons-vue'
 import { advanceApi, reimburseApi } from '../../api'
-import { statusLabel, statusTone } from '../../utils/format'
+import { statusLabel, statusTone, hasWorkflowNode } from '../../utils/format'
 import ListPageScaffold from '../../components/template/ListPageScaffold.vue'
 import BaseDialog from '../../components/base/BaseDialog.vue'
 import BaseInput from '../../components/base/BaseInput.vue'
@@ -315,11 +315,14 @@ onMounted(() => {
         </el-table-column>
         <el-table-column prop="currentNode" label="当前节点" min-width="130">
           <template #default="{ row }">
-            <BaseTag :tone="statusTone(row.currentNode)">{{ statusLabel(row.currentNode) }}</BaseTag>
+            <BaseTag v-if="hasWorkflowNode(row.currentNode)" :tone="statusTone(row.currentNode)">
+              {{ statusLabel(row.currentNode) }}
+            </BaseTag>
+            <span v-else class="node-current-empty">-</span>
           </template>
         </el-table-column>
         <el-table-column prop="applyTime" label="申请时间" min-width="150" />
-        <el-table-column label="操作" width="100" fixed="right" class-name="col-actions">
+        <el-table-column label="操作" :min-width="120" fixed="right" class-name="col-actions">
           <template #default="{ row }">
             <BaseOpButton primary :icon="View" @click="openViewDetail(row)">查看</BaseOpButton>
           </template>

+ 1 - 1
bx/bx-web/src/views/pages/DemoPage.vue

@@ -284,7 +284,7 @@ onMounted(() => {
           <BaseTag :tone="statusTone(row.status)">{{ statusLabel(row.status) }}</BaseTag>
         </template>
       </el-table-column>
-      <el-table-column label="操作" width="200" fixed="right" class-name="col-actions">
+      <el-table-column label="操作" :min-width="220" fixed="right" class-name="col-actions">
         <template #default>
           <BaseOpButton
             primary

+ 1 - 1
bx/bx-web/src/views/pages/ExpenseProjectPage.vue

@@ -281,7 +281,7 @@ onMounted(() => {
             <BaseTag :tone="statusTone(row.status)">{{ statusLabel(row.status) }}</BaseTag>
           </template>
         </el-table-column>
-        <el-table-column label="操作" width="280" fixed="right" class-name="col-actions">
+        <el-table-column label="操作" :min-width="360" fixed="right" class-name="col-actions">
           <template #default="{ row }">
             <BaseOpButton primary :icon="EditPen" :loading="loadingMap.rowEdit" @click="openEditDialog(row)">
               编辑

+ 1 - 1
bx/bx-web/src/views/pages/MenuManagePage.vue

@@ -204,7 +204,7 @@ onMounted(() => {
               <BaseTag :tone="statusTone(row.status)">{{ statusLabel(row.status) }}</BaseTag>
             </template>
           </el-table-column>
-          <el-table-column label="操作" width="320" fixed="right" class-name="col-actions">
+          <el-table-column label="操作" :min-width="380" fixed="right" class-name="col-actions">
             <template #default="{ row }">
               <BaseOpButton :icon="EditPen" @click="openEditDialog(row)">编辑</BaseOpButton>
               <BaseOpButton primary :icon="Plus" @click="openAddDialog(row.id)">新增子菜单</BaseOpButton>

+ 6 - 3
bx/bx-web/src/views/pages/MinePage.vue

@@ -3,7 +3,7 @@ import { computed, onMounted, reactive, ref } from 'vue'
 import { ElMessage } from 'element-plus'
 import { View } from '@element-plus/icons-vue'
 import { advanceApi, reimburseApi } from '../../api'
-import { statusLabel, statusTone } from '../../utils/format'
+import { statusLabel, statusTone, hasWorkflowNode } from '../../utils/format'
 import ListPageScaffold from '../../components/template/ListPageScaffold.vue'
 import BaseDialog from '../../components/base/BaseDialog.vue'
 import BaseInput from '../../components/base/BaseInput.vue'
@@ -239,11 +239,14 @@ onMounted(() => {
         </el-table-column>
         <el-table-column prop="currentNode" label="当前节点" min-width="130">
           <template #default="{ row }">
-            <BaseTag :tone="statusTone(row.currentNode)">{{ statusLabel(row.currentNode) }}</BaseTag>
+            <BaseTag v-if="hasWorkflowNode(row.currentNode)" :tone="statusTone(row.currentNode)">
+              {{ statusLabel(row.currentNode) }}
+            </BaseTag>
+            <span v-else class="node-current-empty">-</span>
           </template>
         </el-table-column>
         <el-table-column prop="applyTime" label="申请时间" min-width="150" />
-        <el-table-column label="操作" width="100" fixed="right" class-name="col-actions">
+        <el-table-column label="操作" :min-width="120" fixed="right" class-name="col-actions">
           <template #default="{ row }">
             <BaseOpButton primary :icon="View" @click="openViewDetail(row)">查看</BaseOpButton>
           </template>

+ 2 - 2
bx/bx-web/src/views/pages/PaymentPage.vue

@@ -597,7 +597,7 @@ function processedSummaryMethod(params: { data: any[] }) {
                 }}
               </template>
             </el-table-column>
-            <el-table-column label="操作" width="280" fixed="right" class-name="col-actions">
+            <el-table-column label="操作" :min-width="340" fixed="right" class-name="col-actions">
               <template #default="{ row }">
                 <BaseOpButton primary :icon="View" @click="openView(row)">查看</BaseOpButton>
                 <BaseOpButton :icon="Money" @click="openIssueDialog(row)">发放</BaseOpButton>
@@ -696,7 +696,7 @@ function processedSummaryMethod(params: { data: any[] }) {
                 {{ row.payTime || '-' }}
               </template>
             </el-table-column>
-            <el-table-column label="操作" width="120" fixed="right" class-name="col-actions">
+            <el-table-column label="操作" :min-width="120" fixed="right" class-name="col-actions">
               <template #default="{ row }">
                 <BaseOpButton primary :icon="View" @click="openProcessedView(row)">查看</BaseOpButton>
               </template>

+ 10 - 3
bx/bx-web/src/views/pages/ReimburseApplyPage.vue

@@ -4,7 +4,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
 import { Plus, EditPen, Upload, View, Close, Delete, Download, ZoomIn, Document } from '@element-plus/icons-vue'
 import { reimburseApi, attachmentApi } from '../../api'
 import { useExpenseItemTree } from '../../hooks/useExpenseItemTree'
-import { statusLabel, statusTone, formatSumMoney } from '../../utils/format'
+import { statusLabel, statusTone, formatSumMoney, hasWorkflowNode } from '../../utils/format'
 import { useServerPaged } from '../../hooks/useServerPaged'
 import ListPageScaffold from '../../components/template/ListPageScaffold.vue'
 import BaseButton from '../../components/base/BaseButton.vue'
@@ -583,8 +583,15 @@ function viewDetailSummary({ columns, data }: { columns: any[]; data: any[] }) {
             <BaseTag :tone="statusTone(row.status)">{{ statusLabel(row.status) }}</BaseTag>
           </template>
         </el-table-column>
-        <el-table-column prop="currentNode" label="当前节点" min-width="120" />
-        <el-table-column label="操作" width="360" fixed="right" class-name="col-actions">
+        <el-table-column prop="currentNode" label="当前节点" min-width="120">
+          <template #default="{ row }">
+            <BaseTag v-if="hasWorkflowNode(row.currentNode)" :tone="statusTone(row.currentNode)">
+              {{ statusLabel(row.currentNode) }}
+            </BaseTag>
+            <span v-else class="node-current-empty">-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" :min-width="420" fixed="right" class-name="col-actions">
           <template #default="{ row }">
             <BaseOpButton primary :icon="View" @click="openView(row)">查看</BaseOpButton>
             <BaseOpButton v-if="row.status === 'draft' || row.status === 'rejected'" :icon="EditPen" @click="openEditDialog(row)">编辑</BaseOpButton>

+ 19 - 5
bx/bx-web/src/views/pages/ReimburseApprovePage.vue

@@ -3,7 +3,7 @@ import { reactive, ref, computed, onMounted } from 'vue'
 import { ElMessage } from 'element-plus'
 import { View, Check, Close, Download, ZoomIn, Document } from '@element-plus/icons-vue'
 import { reimburseApi, attachmentApi } from '../../api'
-import { statusLabel, statusTone, formatSumMoney } from '../../utils/format'
+import { statusLabel, statusTone, formatSumMoney, hasWorkflowNode } from '../../utils/format'
 import { useServerPaged } from '../../hooks/useServerPaged'
 import { useExpenseItemTree } from '../../hooks/useExpenseItemTree'
 import { useApplicantOptions } from '../../hooks/useApplicantOptions'
@@ -434,9 +434,16 @@ function viewDetailSummary({ columns, data }: { columns: any[]; data: any[] }) {
             <el-table-column prop="title" label="报销标题" min-width="180" />
             <el-table-column prop="expenseName" label="费用项目" min-width="140" />
             <el-table-column prop="amount" label="报销金额(元)" class-name="col-money" min-width="120" />
-            <el-table-column prop="currentNode" label="当前节点" min-width="130" />
+            <el-table-column prop="currentNode" label="当前节点" min-width="130">
+              <template #default="{ row }">
+                <BaseTag v-if="hasWorkflowNode(row.currentNode)" :tone="statusTone(row.currentNode)">
+                  {{ statusLabel(row.currentNode) }}
+                </BaseTag>
+                <span v-else class="node-current-empty">-</span>
+              </template>
+            </el-table-column>
             <el-table-column prop="applyTime" label="申请时间" min-width="150" />
-            <el-table-column label="操作" width="280" fixed="right" class-name="col-actions">
+            <el-table-column label="操作" :min-width="340" fixed="right" class-name="col-actions">
               <template #default="{ row }">
                 <BaseOpButton primary :icon="View" @click="openView(row)">查看</BaseOpButton>
                 <BaseOpButton :icon="Check" @click="openApproveDialog([row], 'approve')">通过</BaseOpButton>
@@ -542,9 +549,16 @@ function viewDetailSummary({ columns, data }: { columns: any[]; data: any[] }) {
                 <BaseTag :tone="statusTone(row.status)">{{ statusLabel(row.status) }}</BaseTag>
               </template>
             </el-table-column>
-            <el-table-column prop="currentNode" label="当前节点" min-width="130" />
+            <el-table-column prop="currentNode" label="当前节点" min-width="130">
+              <template #default="{ row }">
+                <BaseTag v-if="hasWorkflowNode(row.currentNode)" :tone="statusTone(row.currentNode)">
+                  {{ statusLabel(row.currentNode) }}
+                </BaseTag>
+                <span v-else class="node-current-empty">-</span>
+              </template>
+            </el-table-column>
             <el-table-column prop="applyTime" label="申请时间" min-width="150" />
-            <el-table-column label="操作" width="120" fixed="right" class-name="col-actions">
+            <el-table-column label="操作" :min-width="120" fixed="right" class-name="col-actions">
               <template #default="{ row }">
                 <BaseOpButton primary :icon="View" @click="openView(row)">查看</BaseOpButton>
               </template>

+ 1 - 1
bx/bx-web/src/views/pages/RoleManagePage.vue

@@ -248,7 +248,7 @@ onMounted(() => {
           <el-table-column prop="userCount" label="关联用户数" min-width="110" />
           <el-table-column prop="remark" label="备注" min-width="200" />
           <el-table-column prop="createTime" label="创建时间" min-width="150" />
-          <el-table-column label="操作" width="280" fixed="right" class-name="col-actions">
+          <el-table-column label="操作" :min-width="380" fixed="right" class-name="col-actions">
             <template #default="{ row }">
               <BaseOpButton primary :icon="View" @click="openViewDialog(row)">查看</BaseOpButton>
               <BaseOpButton :icon="Menu" @click="openMenuAssignDialog(row)">分配菜单</BaseOpButton>

+ 10 - 4
bx/bx-web/src/views/pages/TodoPage.vue

@@ -3,7 +3,7 @@ import { computed, onMounted, reactive, ref } from 'vue'
 import { ElMessage } from 'element-plus'
 import { View, Check, Close } from '@element-plus/icons-vue'
 import { advanceApi, reimburseApi } from '../../api'
-import { statusLabel, statusTone } from '../../utils/format'
+import { statusLabel, statusTone, hasWorkflowNode } from '../../utils/format'
 import ListPageScaffold from '../../components/template/ListPageScaffold.vue'
 import BaseButton from '../../components/base/BaseButton.vue'
 import BaseDialog from '../../components/base/BaseDialog.vue'
@@ -353,11 +353,14 @@ onMounted(() => {
         <el-table-column prop="amount" label="申请金额(元)" class-name="col-money" min-width="120" />
         <el-table-column prop="currentNode" label="当前节点" min-width="130">
           <template #default="{ row }">
-            <BaseTag :tone="statusTone(row.currentNode)">{{ statusLabel(row.currentNode) }}</BaseTag>
+            <BaseTag v-if="hasWorkflowNode(row.currentNode)" :tone="statusTone(row.currentNode)">
+              {{ statusLabel(row.currentNode) }}
+            </BaseTag>
+            <span v-else class="node-current-empty">-</span>
           </template>
         </el-table-column>
         <el-table-column prop="applyTime" label="申请时间" min-width="150" />
-        <el-table-column label="操作" width="280" fixed="right" class-name="col-actions">
+        <el-table-column label="操作" :min-width="340" fixed="right" class-name="col-actions">
           <template #default="{ row }">
             <BaseOpButton primary :icon="View" @click="openViewDetail(row)">查看</BaseOpButton>
             <BaseOpButton :icon="Check" :loading="loadingMap.rowPass" @click="handleApprove(row)">通过</BaseOpButton>
@@ -374,7 +377,10 @@ onMounted(() => {
             <h2 class="dlg-view-title">{{ currentRow?.applyCode || '-' }}</h2>
             <div class="dlg-view-tags">
               <BaseTag :tone="currentRow?.bizType === '报销单' ? 'processing' : 'info'">{{ currentRow?.bizType || '-' }}</BaseTag>
-              <BaseTag v-if="currentRow?.currentNode" :tone="statusTone(currentRow.currentNode)">{{ statusLabel(currentRow.currentNode) }}</BaseTag>
+              <BaseTag
+                v-if="currentRow && hasWorkflowNode(currentRow.currentNode)"
+                :tone="statusTone(currentRow.currentNode)"
+              >{{ statusLabel(currentRow.currentNode) }}</BaseTag>
             </div>
           </div>
           <p class="dlg-view-meta">金额(元):<b class="money-em">¥{{ Number(currentRow?.amount || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2 }) }}</b> · 申请人:{{ currentRow?.applicantName || '-' }}</p>

+ 1 - 1
bx/bx-web/src/views/pages/UserManagePage.vue

@@ -368,7 +368,7 @@ onMounted(() => {
           </template>
         </el-table-column>
         <el-table-column prop="createTime" label="创建时间" min-width="150" />
-        <el-table-column label="操作" width="360" fixed="right" class-name="col-actions">
+        <el-table-column label="操作" :min-width="460" fixed="right" class-name="col-actions">
           <template #default="{ row }">
             <BaseOpButton primary :icon="View" @click="openViewDialog(row)">查看</BaseOpButton>
             <BaseOpButton :icon="EditPen" @click="openEditDialog(row)">编辑</BaseOpButton>

+ 2 - 2
bx/bx-web/src/views/pages/WfAdvancePage.vue

@@ -233,12 +233,12 @@ async function moveDown(node: Record<string, any>) {
           <el-table-column prop="approverName" label="审批人" min-width="120" />
           <el-table-column label="配置状态" min-width="110">
             <template #default="{ row }">
-              <BaseTag :tone="(row.approverId ?? row.approver_id) ? 'done' : 'warn'">
+              <BaseTag :tone="(row.approverId ?? row.approver_id) ? 'done' : 'warning'">
                 {{ (row.approverId ?? row.approver_id) ? '已配置' : '未配置' }}
               </BaseTag>
             </template>
           </el-table-column>
-          <el-table-column label="操作" width="360" fixed="right" class-name="col-actions">
+          <el-table-column label="操作" :min-width="420" fixed="right" class-name="col-actions">
             <template #default="{ row }">
               <BaseOpButton primary :icon="EditPen" @click="openEditDialog(row)">
                 编辑

+ 2 - 2
bx/bx-web/src/views/pages/WfReimbursePage.vue

@@ -233,12 +233,12 @@ async function moveDown(node: Record<string, any>) {
           <el-table-column prop="approverName" label="审批人" min-width="120" />
           <el-table-column label="配置状态" min-width="110">
             <template #default="{ row }">
-              <BaseTag :tone="(row.approverId ?? row.approver_id) ? 'done' : 'warn'">
+              <BaseTag :tone="(row.approverId ?? row.approver_id) ? 'done' : 'warning'">
                 {{ (row.approverId ?? row.approver_id) ? '已配置' : '未配置' }}
               </BaseTag>
             </template>
           </el-table-column>
-          <el-table-column label="操作" width="360" fixed="right" class-name="col-actions">
+          <el-table-column label="操作" :min-width="420" fixed="right" class-name="col-actions">
             <template #default="{ row }">
               <BaseOpButton primary :icon="EditPen" @click="openEditDialog(row)">
                 编辑