From 333a93571452073a9e628c6256044d345099aa50 Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期四, 02 四月 2026 08:19:55 +0800
Subject: [PATCH] #

---
 rsf-design/src/views/basic-info/task-path-template/modules/task-path-template-flow-drawer.vue |  404 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 366 insertions(+), 38 deletions(-)

diff --git a/rsf-design/src/views/basic-info/task-path-template/modules/task-path-template-flow-drawer.vue b/rsf-design/src/views/basic-info/task-path-template/modules/task-path-template-flow-drawer.vue
index c0f68ba..a4f8fbe 100644
--- a/rsf-design/src/views/basic-info/task-path-template/modules/task-path-template-flow-drawer.vue
+++ b/rsf-design/src/views/basic-info/task-path-template/modules/task-path-template-flow-drawer.vue
@@ -2,60 +2,203 @@
   <ElDrawer
     :model-value="visible"
     title="娴佺▼鍥炬煡鐪�"
-    size="900px"
+    size="92%"
     destroy-on-close
     @update:model-value="handleVisibleChange"
   >
-    <ElScrollbar class="h-[calc(100vh-180px)] pr-1">
-      <div v-if="loading" class="py-6">
-        <ElSkeleton :rows="10" animated />
-      </div>
-      <div v-else class="space-y-4">
-        <ElCard shadow="never" class="art-table-card">
+    <div class="flex h-[calc(100vh-160px)] flex-col gap-4">
+      <ElCard shadow="never" class="shrink-0">
+        <div class="flex items-start justify-between gap-4">
+          <div class="min-w-0">
+            <div class="text-base font-semibold text-[var(--art-text-primary)]">
+              {{ detail.templateName || detail.templateCode || '--' }}
+            </div>
+            <div class="mt-1 text-sm text-[var(--art-text-secondary)]">
+              妯℃澘缂栫爜 {{ detail.templateCode || '--' }}锛岃捣鐐� {{ detail.sourceType || '--' }}锛岀粓鐐�
+              {{ detail.targetType || '--' }}
+            </div>
+          </div>
+          <ElSpace wrap>
+            <ElTag :type="detail.statusType || 'info'" effect="light">
+              {{ detail.statusText || '--' }}
+            </ElTag>
+            <ElTag :type="detail.isCurrentType || 'info'" effect="light">
+              {{ detail.isCurrentText || '--' }}
+            </ElTag>
+          </ElSpace>
+        </div>
+      </ElCard>
+
+      <div class="grid min-h-0 flex-1 gap-4 xl:grid-cols-3">
+        <ElCard shadow="never" class="min-h-0">
           <template #header>
             <div class="flex items-center justify-between gap-3">
-              <div>
-                <h3 class="m-0 text-base font-semibold">妯℃澘娴佺▼蹇収</h3>
-                <p class="m-0 text-sm text-[var(--art-text-secondary)]">
-                  杩欓噷灞曠ず鐨勬槸鍚庣妯℃澘瀛楁缁勫悎鍑虹殑鐪熷疄娴佺▼淇℃伅锛屼笉鍋氶澶栧亣鏁版嵁鎺ㄦ紨銆�
-                </p>
-              </div>
-              <ElTag :type="detail.statusType || 'info'" effect="light">
-                {{ detail.statusText || '--' }}
-              </ElTag>
+              <span class="font-medium">妯℃澘鑺傜偣</span>
+              <span class="text-xs text-[var(--art-text-secondary)]">
+                {{ nodeLoading ? '鍔犺浇涓�' : `绗� ${nodePagination.current} 椤� / 鍏� ${nodePagination.total} 鏉 }}
+              </span>
             </div>
           </template>
 
-          <div class="grid gap-3 md:grid-cols-4">
-            <div
-              v-for="item in flowSnapshot"
-              :key="item.key"
-              class="rounded-lg border border-[var(--art-border-color)] bg-[var(--art-main-bg-color)] p-4"
-            >
-              <div class="text-sm text-[var(--art-text-secondary)]">{{ item.title }}</div>
-              <div class="mt-2 text-base font-semibold text-[var(--art-text-primary)]">
-                {{ item.value }}
+          <div class="flex h-[calc(100vh-300px)] flex-col">
+            <ElSkeleton v-if="loading || nodeLoading" :rows="8" animated />
+            <ElEmpty
+              v-else-if="nodeRows.length === 0"
+              description="鏆傛棤鑺傜偣鏁版嵁"
+              :image-size="100"
+            />
+            <template v-else>
+              <ElTable
+                :data="nodeRows"
+                border
+                highlight-current-row
+                height="100%"
+                :current-row-key="selectedNodeId"
+                row-key="id"
+                @current-change="handleNodeClick"
+              >
+                <ElTableColumn prop="nodeOrder" label="椤哄簭" width="72" align="center" />
+                <ElTableColumn prop="nodeCode" label="鑺傜偣缂栫爜" min-width="140" show-overflow-tooltip />
+                <ElTableColumn prop="nodeName" label="鑺傜偣鍚嶇О" min-width="160" show-overflow-tooltip />
+                <ElTableColumn prop="systemCode" label="绯荤粺缂栫爜" min-width="140" show-overflow-tooltip />
+              </ElTable>
+              <div class="mt-3 flex justify-end">
+                <ElPagination
+                  small
+                  background
+                  layout="prev, pager, next"
+                  :current-page="nodePagination.current"
+                  :page-size="nodePagination.pageSize"
+                  :total="nodePagination.total"
+                  @current-change="handleNodePageChange"
+                />
               </div>
-            </div>
+            </template>
           </div>
         </ElCard>
 
-        <ElDescriptions title="娴佺▼渚濇嵁" :column="2" border>
-          <ElDescriptionsItem label="妯℃澘缂栫爜">{{ detail.templateCode || '--' }}</ElDescriptionsItem>
-          <ElDescriptionsItem label="妯℃澘鍚嶇О">{{ detail.templateName || '--' }}</ElDescriptionsItem>
-          <ElDescriptionsItem label="璧风偣绫诲瀷">{{ detail.sourceType || '--' }}</ElDescriptionsItem>
-          <ElDescriptionsItem label="缁堢偣绫诲瀷">{{ detail.targetType || '--' }}</ElDescriptionsItem>
-          <ElDescriptionsItem label="姝ュ簭闀垮害">{{ detail.stepSize ?? '--' }}</ElDescriptionsItem>
-          <ElDescriptionsItem label="浼樺厛绾�">{{ detail.priority ?? '--' }}</ElDescriptionsItem>
-        </ElDescriptions>
+        <ElCard shadow="never" class="min-h-0">
+          <template #header>
+            <div class="flex items-center justify-between gap-3">
+              <span class="font-medium">瀛愮郴缁熸祦绋�</span>
+              <span class="text-xs text-[var(--art-text-secondary)]">
+                {{
+                  flowLoading
+                    ? '鍔犺浇涓�'
+                    : selectedNodeId
+                      ? `绗� ${flowPagination.current} 椤� / 鍏� ${flowPagination.total} 鏉
+                      : '寰呴�夋嫨鑺傜偣'
+                }}
+              </span>
+            </div>
+          </template>
+
+          <div class="flex h-[calc(100vh-300px)] flex-col">
+            <div
+              v-if="!selectedNodeId"
+              class="flex h-full items-center justify-center text-sm text-[var(--art-text-secondary)]"
+            >
+              璇峰厛閫夋嫨宸︿晶妯℃澘鑺傜偣
+            </div>
+            <ElSkeleton v-else-if="flowLoading" :rows="8" animated />
+            <ElEmpty
+              v-else-if="flowRows.length === 0"
+              description="鏆傛棤娴佺▼鏁版嵁"
+              :image-size="100"
+            />
+            <template v-else>
+              <ElTable
+                :data="flowRows"
+                border
+                highlight-current-row
+                height="100%"
+                :current-row-key="selectedFlowId"
+                row-key="id"
+                @current-change="handleFlowClick"
+              >
+                <ElTableColumn prop="flowCode" label="娴佺▼缂栫爜" min-width="160" show-overflow-tooltip />
+                <ElTableColumn prop="flowName" label="娴佺▼鍚嶇О" min-width="180" show-overflow-tooltip />
+                <ElTableColumn prop="systemCode" label="绯荤粺缂栫爜" min-width="140" show-overflow-tooltip />
+              </ElTable>
+              <div class="mt-3 flex justify-end">
+                <ElPagination
+                  small
+                  background
+                  layout="prev, pager, next"
+                  :current-page="flowPagination.current"
+                  :page-size="flowPagination.pageSize"
+                  :total="flowPagination.total"
+                  @current-change="handleFlowPageChange"
+                />
+              </div>
+            </template>
+          </div>
+        </ElCard>
+
+        <ElCard shadow="never" class="min-h-0">
+          <template #header>
+            <div class="flex items-center justify-between gap-3">
+              <span class="font-medium">娴佺▼姝ラ</span>
+              <span class="text-xs text-[var(--art-text-secondary)]">
+                {{
+                  stepLoading
+                    ? '鍔犺浇涓�'
+                    : selectedFlowId
+                      ? `绗� ${stepPagination.current} 椤� / 鍏� ${stepPagination.total} 鏉
+                      : '寰呴�夋嫨娴佺▼'
+                }}
+              </span>
+            </div>
+          </template>
+
+          <div class="flex h-[calc(100vh-300px)] flex-col">
+            <div
+              v-if="!selectedFlowId"
+              class="flex h-full items-center justify-center text-sm text-[var(--art-text-secondary)]"
+            >
+              璇峰厛閫夋嫨涓棿瀛愮郴缁熸祦绋�
+            </div>
+            <ElSkeleton v-else-if="stepLoading" :rows="8" animated />
+            <ElEmpty
+              v-else-if="stepRows.length === 0"
+              description="鏆傛棤姝ラ鏁版嵁"
+              :image-size="100"
+            />
+            <template v-else>
+              <ElTable :data="stepRows" border height="100%" row-key="id">
+                <ElTableColumn prop="stepOrder" label="椤哄簭" width="72" align="center" />
+                <ElTableColumn prop="stepCode" label="姝ラ缂栫爜" min-width="140" show-overflow-tooltip />
+                <ElTableColumn prop="stepName" label="姝ラ鍚嶇О" min-width="180" show-overflow-tooltip />
+                <ElTableColumn prop="stepType" label="姝ラ绫诲瀷" min-width="140" show-overflow-tooltip />
+              </ElTable>
+              <div class="mt-3 flex justify-end">
+                <ElPagination
+                  small
+                  background
+                  layout="prev, pager, next"
+                  :current-page="stepPagination.current"
+                  :page-size="stepPagination.pageSize"
+                  :total="stepPagination.total"
+                  @current-change="handleStepPageChange"
+                />
+              </div>
+            </template>
+          </div>
+        </ElCard>
       </div>
-    </ElScrollbar>
+    </div>
   </ElDrawer>
 </template>
 
 <script setup>
-  import { computed } from 'vue'
-  import { buildTaskPathTemplateFlowSnapshot } from '../taskPathTemplatePage.helpers'
+  import { computed, ref, watch } from 'vue'
+  import { ElMessage } from 'element-plus'
+  import { guardRequestWithMessage } from '@/utils/sys/requestGuard'
+  import {
+    fetchTaskPathTemplateNodePage
+  } from '@/api/task-path-template-node'
+  import { fetchSubsystemFlowTemplatePage } from '@/api/subsystem-flow-template'
+  import { fetchFlowStepTemplatePage } from '@/api/flow-step-template'
 
   const props = defineProps({
     visible: { type: Boolean, default: false },
@@ -70,9 +213,194 @@
     set: (value) => emit('update:visible', value)
   })
 
-  const flowSnapshot = computed(() => buildTaskPathTemplateFlowSnapshot(props.detail))
+  const nodeLoading = ref(false)
+  const flowLoading = ref(false)
+  const stepLoading = ref(false)
+  const nodeRows = ref([])
+  const flowRows = ref([])
+  const stepRows = ref([])
+  const selectedNodeId = ref(null)
+  const selectedFlowId = ref(null)
+  const DEFAULT_PAGE_SIZE = 20
+  const nodePagination = ref({ current: 1, pageSize: DEFAULT_PAGE_SIZE, total: 0 })
+  const flowPagination = ref({ current: 1, pageSize: DEFAULT_PAGE_SIZE, total: 0 })
+  const stepPagination = ref({ current: 1, pageSize: DEFAULT_PAGE_SIZE, total: 0 })
+
+  function normalizeRecords(response) {
+    return Array.isArray(response?.records) ? response.records : []
+  }
+
+  function normalizeTotal(response) {
+    const total = Number(response?.total)
+    return Number.isNaN(total) ? 0 : total
+  }
+
+  function resetFlowState() {
+    nodeRows.value = []
+    flowRows.value = []
+    stepRows.value = []
+    selectedNodeId.value = null
+    selectedFlowId.value = null
+    nodePagination.value.current = 1
+    nodePagination.value.total = 0
+    flowPagination.value.current = 1
+    flowPagination.value.total = 0
+    stepPagination.value.current = 1
+    stepPagination.value.total = 0
+  }
+
+  async function loadStepRows(flowId, current = stepPagination.value.current) {
+    if (!flowId) {
+      stepRows.value = []
+      selectedFlowId.value = null
+      stepPagination.value.total = 0
+      return
+    }
+
+    stepLoading.value = true
+    try {
+      const response = await guardRequestWithMessage(
+        fetchFlowStepTemplatePage({
+          current,
+          pageSize: stepPagination.value.pageSize,
+          flowId
+        }),
+        { records: [] },
+        { timeoutMessage: '娴佺▼姝ラ鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟' }
+      )
+      stepRows.value = normalizeRecords(response)
+      stepPagination.value.current = current
+      stepPagination.value.total = normalizeTotal(response)
+    } catch (error) {
+      stepRows.value = []
+      stepPagination.value.total = 0
+      ElMessage.error(error?.message || '娴佺▼姝ラ鍔犺浇澶辫触')
+    } finally {
+      stepLoading.value = false
+    }
+  }
+
+  async function loadFlowRows(node, current = flowPagination.value.current) {
+    if (!node?.nodeCode) {
+      flowRows.value = []
+      stepRows.value = []
+      selectedFlowId.value = null
+      flowPagination.value.total = 0
+      stepPagination.value.total = 0
+      return
+    }
+
+    flowLoading.value = true
+    try {
+      const response = await guardRequestWithMessage(
+        fetchSubsystemFlowTemplatePage({
+          current,
+          pageSize: flowPagination.value.pageSize,
+          flowCode: node.nodeCode
+        }),
+        { records: [] },
+        { timeoutMessage: '瀛愮郴缁熸祦绋嬪姞杞借秴鏃讹紝宸插仠姝㈢瓑寰�' }
+      )
+      flowRows.value = normalizeRecords(response)
+      flowPagination.value.current = current
+      flowPagination.value.total = normalizeTotal(response)
+      selectedFlowId.value = null
+      stepRows.value = []
+      stepPagination.value.current = 1
+      stepPagination.value.total = 0
+    } catch (error) {
+      flowRows.value = []
+      stepRows.value = []
+      selectedFlowId.value = null
+      flowPagination.value.total = 0
+      stepPagination.value.total = 0
+      ElMessage.error(error?.message || '瀛愮郴缁熸祦绋嬪姞杞藉け璐�')
+    } finally {
+      flowLoading.value = false
+    }
+  }
+
+  async function loadNodeRows(templateId, current = nodePagination.value.current) {
+    if (!templateId) {
+      resetFlowState()
+      return
+    }
+
+    nodeLoading.value = true
+    try {
+      const response = await guardRequestWithMessage(
+        fetchTaskPathTemplateNodePage({
+          current,
+          pageSize: nodePagination.value.pageSize,
+          templateId
+        }),
+        { records: [] },
+        { timeoutMessage: '妯℃澘鑺傜偣鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟' }
+      )
+      nodeRows.value = normalizeRecords(response)
+      nodePagination.value.current = current
+      nodePagination.value.total = normalizeTotal(response)
+      selectedNodeId.value = null
+      flowRows.value = []
+      stepRows.value = []
+      flowPagination.value.current = 1
+      flowPagination.value.total = 0
+      stepPagination.value.current = 1
+      stepPagination.value.total = 0
+    } catch (error) {
+      resetFlowState()
+      ElMessage.error(error?.message || '妯℃澘鑺傜偣鍔犺浇澶辫触')
+    } finally {
+      nodeLoading.value = false
+    }
+  }
+
+  function handleNodeClick(node) {
+    if (!node || selectedNodeId.value === node.id) return
+    selectedNodeId.value = node.id
+    selectedFlowId.value = null
+    stepRows.value = []
+    flowPagination.value.current = 1
+    stepPagination.value.current = 1
+    loadFlowRows(node)
+  }
+
+  function handleFlowClick(flow) {
+    if (!flow || selectedFlowId.value === flow.id) return
+    selectedFlowId.value = flow.id
+    stepPagination.value.current = 1
+    loadStepRows(flow.id)
+  }
+
+  function handleNodePageChange(current) {
+    loadNodeRows(props.detail?.id, current)
+  }
+
+  function handleFlowPageChange(current) {
+    const node = nodeRows.value.find((item) => item.id === selectedNodeId.value)
+    if (!node) return
+    loadFlowRows(node, current)
+  }
+
+  function handleStepPageChange(current) {
+    if (!selectedFlowId.value) return
+    loadStepRows(selectedFlowId.value, current)
+  }
 
   function handleVisibleChange(value) {
     visible.value = value
   }
+
+  watch(
+    () => [props.visible, props.detail?.id],
+    ([isVisible, detailId]) => {
+      if (isVisible && detailId) {
+        loadNodeRows(detailId)
+      }
+      if (!isVisible) {
+        resetFlowState()
+      }
+    },
+    { immediate: true }
+  )
 </script>

--
Gitblit v1.9.1