From 2c55b1a8a0700df79268550335506637b41610ce Mon Sep 17 00:00:00 2001
From: seatonwan9
Date: 星期日, 24 八月 2025 20:36:36 +0800
Subject: [PATCH] 提交源码

---
 src/views/tradeManage/seller/index.vue               |  426 +--
 src/views/approveManage/tradeApproval/checkFiles.vue | 1168 +++++++++
 src/views/approveManage/tradeApproval/list.vue       |  421 +--
 src/views/tradeManage/detail/index.vue               |  632 ++++-
 src/api/pointsApi.ts                                 |    2 
 src/api/approvalManage.ts                            |   22 
 src/views/tradeManage/upload/index.vue               |  871 ++++++-
 src/views/tradeManage/buyer/index.vue                |  487 ++--
 src/views/tradeManage/evaluate/index.vue             |  935 ++++++-
 src/views/approveManage/tradeApproval/approve.vue    | 1139 +++++++++
 src/router/modules/approvalManage.ts                 |    9 
 src/api/orderApi.ts                                  |  114 
 src/views/tradeManage/confirm/index.vue              |  585 +++-
 src/App.vue                                          |    7 
 14 files changed, 5,368 insertions(+), 1,450 deletions(-)

diff --git a/src/App.vue b/src/App.vue
index 619c861..d96e197 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -29,6 +29,13 @@
   })
 }
 provide('reload', reload)
+// 涓存椂鍒濆鍖栵細鍐欏叆 userId 涓� unitId锛屼究浜庢湰鍦拌仈璋冨悗绔笅鍗曟帴鍙�
+if (!userStore.getUserId) {
+  userStore.userId = '1'
+}
+if (!userStore.getUnitId) {
+  userStore.unitId = '1'
+}
 setInterval(() => {
 // 杩欎釜鍒ゆ柇浠h〃鐧诲綍鎴愬姛鍚庢墠寮�濮嬪啓鍏ユ椂闂�
   if(userStore.getAdminToken) {
diff --git a/src/api/approvalManage.ts b/src/api/approvalManage.ts
index 8ad16a5..3a6b20d 100644
--- a/src/api/approvalManage.ts
+++ b/src/api/approvalManage.ts
@@ -1,8 +1,9 @@
 import createAxios from '@/utils/axios'
-let url = '/admin/approval/'
-// 瀹℃壒鍒楄〃
+// 缁熶竴璧扮綉鍏冲墠缂� /admin/api
+const url = '/admin/api/order'
+// 瀹℃壒鍒楄〃锛堝緟瀹℃壒璁㈠崟鍒嗛〉锛�
 export const fetchApprovalPage = (data: any): ApiPromise =>
-  createAxios({ url: `${url}/trade/page`, method: 'post', data }) as ApiPromise
+  createAxios({ url: `${url}/approval/page`, method: 'post', data }) as ApiPromise
 
 // 瀹℃壒璇︽儏
 export const fetchApprovalDetail = (data: any): ApiPromise =>
@@ -16,4 +17,19 @@
 export const checkFiles = (data: any): ApiPromise =>
   createAxios({ url: `${url}/trade/checkFiles`, method: 'post', data }) as ApiPromise
 
+// 瀹℃壒閫氳繃锛氬皢璁㈠崟鐘舵�佹洿鏂颁负"寰呰瘎浠�"
+export const approveOrder = (data: any): ApiPromise =>
+  createAxios({ url: `${url}/trade/approve`, method: 'post', data }) as ApiPromise
+
+// 鏍规嵁璁㈠崟ID鑾峰彇瀹℃壒璁板綍锛堝惈瀹℃壒ID锛�
+export const fetchApprovalByOrderId = (orderId: string | number): ApiPromise =>
+  createAxios({ url: `/admin/api/approval/order/${orderId}`, method: 'get' }) as ApiPromise
+
+// 鎺堟潈瀹℃壒
+export const authorizeApproval = (
+  approvalId: string | number,
+  params: { authorizerId: number; authorizerName: string; authorizationOpinion?: string }
+): ApiPromise =>
+  createAxios({ url: `/admin/api/approval/authorize/${approvalId}`, method: 'post', params }) as ApiPromise
+
 
diff --git a/src/api/orderApi.ts b/src/api/orderApi.ts
index 835ef2b..aad0872 100644
--- a/src/api/orderApi.ts
+++ b/src/api/orderApi.ts
@@ -1,12 +1,13 @@
 import createAxios from '@/utils/axios'
 
-const baseUrl = '/admin/api/order'
+// 涓庡叾浠栨ā鍧椾繚鎸佷竴鑷达紝缁忚繃缃戝叧浠� /admin/api 涓哄墠缂�
+const url = '/admin/api/order'
 
 const orderApi = {
   // 鑾峰彇涓�娆℃�ч槻閲嶅鎻愪氦 Token
   getIdempotencyToken(userId?: number): ApiPromise {
     return createAxios({
-      url: `${baseUrl}/idempotency/token`,
+      url: `${url}/idempotency/token`,
       method: 'get',
       params: userId ? { userId } : {}
     }) as ApiPromise
@@ -15,11 +16,118 @@
   // 鍒涘缓璁㈠崟锛堝湪 headers 涓惡甯� Idempotency-Token锛�
   createOrder(data: any, token: string): ApiPromise {
     return createAxios({
-      url: `${baseUrl}/create`,
+      url: `${url}/create`,
       method: 'post',
       data,
       headers: { 'Idempotency-Token': token }
     }) as ApiPromise
+  },
+   getBuyerOrderPage(data: any): ApiPromise {
+    return createAxios({
+      url: `${url}/buyer/page`,
+      method: 'post',
+      data
+    }) as ApiPromise
+  },
+  getSellerOrderPage(data: any): ApiPromise {
+    return createAxios({
+      url: `${url}/seller/page`,
+      method: 'post',
+      data
+    }) as ApiPromise
+  },
+  getOrderDetail(orderId: string): ApiPromise {
+    return createAxios({
+      url: `${url}/detail/${orderId}`,
+      method: 'get'
+    }) as ApiPromise
+  },
+  generateOrderNo(): ApiPromise {
+    return createAxios({
+      url: `${url}/no/new`,
+      method: 'get'
+    }) as ApiPromise
+  },
+  
+  updateOrderDetail(data: any): ApiPromise {
+    return createAxios({
+      url: `${url}/detail/update`,
+      method: 'post',
+      data
+    }) as ApiPromise
+  },
+  
+  updateOrderDetailRemarksOnly(data: any): ApiPromise {
+    return createAxios({
+      url: `${url}/detail/remarks/update`,
+      method: 'post',
+      data
+    }) as ApiPromise
+  },
+  
+  confirmTransaction(orderId: string, userId: number): ApiPromise {
+    return createAxios({
+      url: `${url}/transaction/confirm`,
+      method: 'post',
+      params: {
+        orderId,
+        userId
+      }
+    }) as ApiPromise
+  },
+  
+  submitEvaluation(data: any): ApiPromise {
+    return createAxios({
+      url: `${url}/evaluation/add`,
+      method: 'post',
+      params: {
+        orderId: data.orderId,
+        evaluatorId: data.evaluatorId,
+        evaluatorName: data.evaluatorName,
+        evaluatorType: '涔板', // 榛樿璇勪环浜虹被鍨嬩负涔板
+        content: data.evaluationContent,
+        rating: data.overallRating,
+        serviceRating: data.serviceRating,
+        qualityRating: data.qualityRating,
+        deliveryRating: data.speedRating, // 閫熷害璇勫垎瀵瑰簲鍚庣鐨勪氦浠樿瘎鍒�
+        isAnonymous: data.isAnonymous
+      }
+    }) as ApiPromise
+  },
+  
+  // 鍙栨秷璁㈠崟
+  cancelOrder(orderId: string): ApiPromise {
+    return createAxios({
+      url: `${url}/cancel/${orderId}`,
+      method: 'delete'
+    }) as ApiPromise
+  },
+  
+  checkAgreementPriceType(orderId: string): ApiPromise {
+    return createAxios({
+      url: `${url}/agreement/check/${orderId}`,
+      method: 'get'
+    }) as ApiPromise
+  },
+  
+  updateOrderStatusToNext(orderId: string): ApiPromise {
+    return createAxios({
+      url: `${url}/status/next`,
+      method: 'post',
+      params: {
+        orderId
+      }
+    }) as ApiPromise
+  },
+  
+  updateOrderStatusToPrevious(orderId: string): ApiPromise {
+    return createAxios({
+      url: `${url}/status/previous`,
+      method: 'post',
+      params: {
+        orderId
+      }
+    }) as ApiPromise
   }
 }
 
diff --git a/src/api/pointsApi.ts b/src/api/pointsApi.ts
index 46d7136..6d8ec43 100644
--- a/src/api/pointsApi.ts
+++ b/src/api/pointsApi.ts
@@ -27,7 +27,7 @@
   // 淇濆瓨绉垎瑙勫垯閰嶇疆
   savePointsRules(data: object): ApiPromise {
     return createAxios({
-      url: `${url}rules/save`,
+      url: `${url}rules/update`,
       data: data,
     }) as ApiPromise
   },
diff --git a/src/router/modules/approvalManage.ts b/src/router/modules/approvalManage.ts
index 25165c7..752b697 100644
--- a/src/router/modules/approvalManage.ts
+++ b/src/router/modules/approvalManage.ts
@@ -29,6 +29,15 @@
         keepAlive: false,
       },
     },
+    {
+      path: 'authorization/:id',
+      name: 'tradeAuthorization',
+      component: () => import('@/views/approveManage/tradeApproval/approve.vue'),
+      meta: {
+        title: '浜ゆ槗鎺堟潈',
+        keepAlive: false,
+      },
+    },
   ],
   meta: {
     title: '瀹℃壒绠$悊',
diff --git a/src/views/approveManage/tradeApproval/approve.vue b/src/views/approveManage/tradeApproval/approve.vue
index b9fa7c0..10e67a7 100644
--- a/src/views/approveManage/tradeApproval/approve.vue
+++ b/src/views/approveManage/tradeApproval/approve.vue
@@ -1,93 +1,1134 @@
 <template>
   <div class="default-main">
+    <!-- 璁㈠崟淇℃伅 + 鐢宠浜轰俊鎭� + 浜ゆ槗鍐呭锛堝悎骞朵负鍚屼竴鍗$墖锛� -->
     <el-card shadow="never">
-      <div class="title">璁㈠崟淇℃伅</div>
-      <el-descriptions :column="3" border class="mt10">
+      <el-descriptions
+        :column="2"
+        border
+        class="mt10 order-desc fixed-label"
+        label-width="180px"
+        :label-style="labelStyle"
+        :content-style="contentStyle"
+      >
+        <el-descriptions-item :span="2" class="section-header">
+          <template #label>
+            <el-icon class="section-icon"><Document /></el-icon>
+            <span>璁㈠崟淇℃伅</span>
+          </template>
+          <template #default></template>
+        </el-descriptions-item>
         <el-descriptions-item label="璁㈠崟缂栧彿">{{ detail.orderNo }}</el-descriptions-item>
         <el-descriptions-item label="浜ゆ槗璧勬簮绫诲瀷">{{ detail.resourceTypeName }}</el-descriptions-item>
-        <el-descriptions-item label="浜ゆ槗鐘舵��">{{ detail.statusName }}</el-descriptions-item>
         <el-descriptions-item label="鐢宠鏃堕棿">{{ detail.applyTime }}</el-descriptions-item>
-        <el-descriptions-item label="鍗曚綅">{{ detail.unitName }}</el-descriptions-item>
-        <el-descriptions-item label="鐢ㄦ埛鍚�">{{ detail.userName }}</el-descriptions-item>
+        <el-descriptions-item label="浜ゆ槗鐘舵��">
+          <el-tag :type="getStatusType(detail.status)" size="small">{{ detail.statusName }}</el-tag>
+        </el-descriptions-item>
       </el-descriptions>
-    </el-card>
+      
+      <!-- 鐢宠浜轰俊鎭紙涓庤鍗曚俊鎭悓鍗$墖锛屽鐢ㄥ垎闅旀爣棰樻牱寮忥級 -->
+      <el-descriptions
+        :column="2"
+        border
+        class="mt15 order-desc fixed-label"
+        label-width="180px"
+        :label-style="labelStyle"
+        :content-style="contentStyle"
+      >
+        <el-descriptions-item :span="2" class="section-header">
+          <template #label>
+            <el-icon class="section-icon"><User /></el-icon>
+            <span>鐢宠浜轰俊鎭�</span>
+          </template>
+          <template #default></template>
+        </el-descriptions-item>
+        <el-descriptions-item label="濮撳悕">{{ detail.userName || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鍗曚綅">{{ detail.unitName || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="閮ㄩ棬">{{ detail.userDept || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鐢ㄦ埛鍚�">{{ detail.userAccount || '-' }}</el-descriptions-item>
+      </el-descriptions>
 
-    <el-card class="mt15" shadow="never">
-      <div class="title">浜ゆ槗鍐呭</div>
-      <el-table :data="detail.items" border class="mt10">
-        <el-table-column label="璇︽儏" min-width="280">
-          <template #default="{ row }">
-            <div>
-              <div>{{ row.name }}</div>
-              <div class="gray">瀹㈡埛瀵硅薄锛歿{ row.customerTarget }}</div>
-              <div class="gray">骞跺彂鑺傜偣鏁帮細{{ row.concurrentNodes }}</div>
-            </div>
+      <!-- 浜ゆ槗鍐呭锛堢揣闅忕敵璇蜂汉淇℃伅锛屽悓鍗$墖锛屽鐢ㄥ垎闅旀爣棰樻牱寮忥級 -->
+      <el-descriptions
+        :column="2"
+        border
+        class="mt15 order-desc fixed-label"
+        label-width="180px"
+        :label-style="labelStyle"
+        :content-style="contentStyle"
+      >
+        <el-descriptions-item :span="2" class="section-header">
+          <template #label>
+            <el-icon class="section-icon"><Goods /></el-icon>
+            <span>浜ゆ槗鍐呭</span>
+          </template>
+          <template #default></template>
+        </el-descriptions-item>
+        <el-descriptions-item label="浜у搧鍚嶇О">
+          <el-link type="primary" :underline="false">{{ detail.productName }}</el-link>
+        </el-descriptions-item>
+        <el-descriptions-item label="鎻愪緵鑰�">{{ detail.supplier }}</el-descriptions-item>
+        <el-descriptions-item label="琛屼笟棰嗗煙">{{ detail.industry }}</el-descriptions-item>
+        <el-descriptions-item label="鍗曚綅宸ョ▼">{{ detail.projectUnit }}</el-descriptions-item>
+        <el-descriptions-item label="浜у搧绫诲瀷">{{ detail.productType || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="浜у搧绠�浠�">
+          <div class="desc-wrap">{{ detail.productDesc }}</div>
+        </el-descriptions-item>
+      </el-descriptions>
+      
+      <!-- 璁㈠崟璇︽儏锛堢Щ鍔ㄥ埌浜ゆ槗鍐呭涓嬮潰锛屽悓涓�鍗$墖鍐咃級 -->
+      <div ref="orderTableWrapRef">
+        <el-table
+          :data="tableData"
+          border
+          class="mt10 order-table"
+          :header-cell-style="headerCenterStyle"
+          :cell-style="bodyCellStyle"
+          :row-class-name="getRowClassName"
+          :span-method="arraySpanMethod"
+        >
+        <el-table-column>
+          <template #header>
+            <el-icon class="header-icon"><List /></el-icon>
+            <span>璇︽儏</span>
+          </template>
+          <el-table-column label="" :width="colWidths.detail1">
+            <template #default="{ row }">
+              <div v-if="!row.isSummary">{{ row.name }}</div>
+              <div v-else class="summary-merged">
+                <div class="summary-left">
+                  鍏� <span class="count">{{ detail.items.length }}</span> 浠�
+                </div>
+                <div class="summary-right">
+                  鎬昏锛�<span class="price">{{ detail.pointTotal }}</span> 绉垎
+                  <span class="ml20 price">{{ detail.cashTotal }}</span> 鍏�
+                </div>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column label="" :width="colWidths.detail2">
+            <template #default="{ row }">
+              <div v-if="!row.isSummary" class="gray">閿�鍞舰寮忥細{{ row.saleType || '-' }}</div>
+              <div v-if="!row.isSummary" class="gray">璐︽埛鏁伴噺锛歿{ row.accountCount ?? '-' }}</div>
+            </template>
+          </el-table-column>
+          <el-table-column label="" :width="colWidths.detail3">
+            <template #default="{ row }">
+              <div v-if="!row.isSummary" class="gray">瀹㈡埛瀵硅薄锛歿{ row.customerTarget || '-' }}</div>
+              <div v-if="!row.isSummary" class="gray">骞跺彂鑺傜偣鏁伴噺锛歿{ row.concurrentNodes ?? '-' }}</div>
+            </template>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="鍗曚环">
+          <el-table-column label="" :width="colWidths.price">
+            <template #default="{ row }">
+              <div v-if="!row.isSummary">{{ formatPrice(row) }}</div>
+            </template>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="鏁伴噺">
+          <el-table-column label="" :width="colWidths.quantity">
+            <template #default="{ row }">
+              <div v-if="!row.isSummary">{{ row.quantity }}</div>
+            </template>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="鏈熼檺(骞�)">
+          <el-table-column label="" :width="colWidths.period">
+            <template #default="{ row }">
+              <div v-if="!row.isSummary">{{ formatPeriod(row) }}</div>
+            </template>
+          </el-table-column>
+        </el-table-column>
+        </el-table>
+      </div>
+
+      <!-- 绉婚櫎鍘熸潵鐨勮〃鏍煎簳閮ㄤ俊鎭紝鍥犱负宸茬粡绉诲埌琛ㄦ牸鏈�鍚庝竴琛� -->
+
+       <!-- 浜ゆ槗鏂囦欢锛堢Щ鍔ㄥ埌璁㈠崟璇︽儏涓嬮潰锛屽悓涓�鍗$墖鍐咃級 -->
+       <div class="file-section" v-if="isAgreementOrder && fileList.length > 0">
+         <el-table
+           :data="fileList"
+           border
+           class="file-table"
+           :header-cell-style="fileTableHeaderStyle"
+           :cell-style="fileTableCellStyle"
+         >
+           <el-table-column min-width="200">
+             <template #header>
+               <el-icon class="header-icon"><Document /></el-icon>
+               <span>浜ゆ槗鏂囦欢</span>
+             </template>
+             <template #default="{ row }">
+               <div class="file-name">
+                 <el-icon class="file-icon"><Document /></el-icon>
+                 <span>{{ row.name }}</span>
+               </div>
+             </template>
+           </el-table-column>
+           <el-table-column label="鏂囦欢澶у皬" prop="size" width="120">
+             <template #default="{ row }">
+               {{ formatFileSize(row.size) }}
+             </template>
+           </el-table-column>
+                     <el-table-column label="鎿嶄綔" width="180">
+            <template #default="{ row }">
+              <div class="file-actions">
+                <el-button
+                  type="text"
+                  size="small"
+                  class="preview-btn"
+                  @click="handlePreview(row)"
+                  v-if="isPreviewable(row)"
+                  :disabled="!isFileUploaded(row)"
+                >
+                  棰勮
+                </el-button>
+                <el-button
+                  type="text"
+                  size="small"
+                  class="download-btn"
+                  @click="handleDownload(row)"
+                  :disabled="!isFileUploaded(row)"
+                >
+                  涓嬭浇
+                </el-button>
+              </div>
+            </template>
+          </el-table-column>
+         </el-table>
+       </div>
+     </el-card>
+
+         <!-- 浜ゆ槗淇℃伅澶囨敞 -->
+   <el-card class="mt15" shadow="never">
+     <div class="title">浜ゆ槗淇℃伅澶囨敞</div>
+     <el-table :data="form.items" border class="mt10 remark-table">
+       <el-table-column label="璇︽儏" prop="name" min-width="200" />
+        <el-table-column label="澶囨敞" min-width="400">
+          <template #default="{ row, $index }">
+            <el-input
+              v-model="form.items[$index].remark"
+              type="textarea"
+              :rows="1"
+              placeholder="寮�閫氳处鍙蜂俊鎭強涓暟锛岀櫥褰曟彁绀虹瓑淇℃伅"
+              maxlength="500"
+              show-word-limit
+              class="remark-input"
+            />
           </template>
         </el-table-column>
-        <el-table-column label="鍗曚环" prop="priceName" width="140" />
-        <el-table-column label="鏁伴噺" prop="quantity" width="80" />
-        <el-table-column label="鏈熼檺(骞�)" prop="period" width="120" />
-      </el-table>
-
-      <div class="total">
-        鎬昏锛�<span class="price">{{ detail.pointTotal }}</span> 绉垎
-        <span class="ml20 price">{{ detail.cashTotal }}</span> 鍏�
-      </div>
+            </el-table>
     </el-card>
 
+    <!-- 瀹℃壒鍐呭 -->
     <el-card class="mt15" shadow="never">
-      <div class="title">瀹℃壒</div>
-      <el-form :model="form" label-width="100px" class="mt10" ref="formRef" :rules="rules">
-        <el-form-item label="瀹℃壒鎰忚" prop="remark">
-          <el-input v-model="form.remark" type="textarea" :autosize="{ minRows: 4 }" placeholder="璇疯緭鍏ュ鎵规剰瑙�" />
-        </el-form-item>
-      </el-form>
-      <div class="ba-center mt15">
-        <el-button @click="goBack">杩斿洖</el-button>
-        <el-button type="success" @click="approve(true)">瀹℃壒閫氳繃</el-button>
-        <el-button type="danger" @click="approve(false)">椹冲洖</el-button>
+      <div class="title">瀹℃壒鍐呭</div>
+      <div class="approval-content">
+        <div class="approval-form">
+          <div class="form-item">
+            <label class="required">瀹℃壒鎰忚:</label>
+            <el-input
+              v-model="approvalForm.comments"
+              type="textarea"
+              :rows="4"
+              placeholder="璇疯緭鍏ュ鎵规剰瑙�"
+              maxlength="500"
+              show-word-limit
+            />
+          </div>
+        </div>
+        <div class="approval-actions">
+          <el-button @click="goBack">杩斿洖</el-button>
+          <el-button 
+            type="primary" 
+            @click="handleApprove"
+            :loading="approvalLoading"
+          >
+            {{ isAgreementOrder ? '瀹℃壒閫氳繃' : '瀹屾垚鎺堟潈' }}
+          </el-button>
+          <el-button 
+            v-if="isAgreementOrder"
+            type="danger" 
+            @click="handleReject"
+            :loading="approvalLoading"
+          >
+            椹冲洖
+          </el-button>
+        </div>
       </div>
     </el-card>
   </div>
 </template>
 
 <script setup lang="ts">
-import { onMounted, reactive, ref } from 'vue'
+import { onMounted, reactive, ref, computed, type CSSProperties } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
-import { fetchApprovalDetail, submitApproval } from '@/api/approvalManage'
-import { ElMessage, FormInstance } from 'element-plus'
+import { Document, User, Goods, List } from '@element-plus/icons-vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import orderApi from '@/api/orderApi'
+import { approveOrder } from '@/api/approvalManage'
+import { useUserInfo } from '@/stores/modules/userInfo'
+import createAxios from '@/utils/axios'
 
 const route = useRoute()
 const router = useRouter()
-const formRef = ref<FormInstance>()
+const userStore = useUserInfo()
 const detail = reactive<any>({ items: [] })
-const form = reactive({ remark: '' })
-const rules = { remark: [{ required: true, message: '璇疯緭鍏ュ鎵规剰瑙�', trigger: 'blur' }] }
+const form = reactive<any>({ items: [] })
+const fileList = ref<any[]>([])
+const orderTableWrapRef = ref<HTMLElement | null>(null)
+const labelStyle = { width: '180px', maxWidth: '180px' }
+const contentStyle = { width: 'calc(50% - 180px)' }
+
+// 鏄惁涓哄崗璁鍗�
+const isAgreementOrder = ref(false)
+
+// 瀹℃壒琛ㄥ崟鏁版嵁
+const approvalForm = reactive({
+  comments: ''
+})
+
+// 瀹℃壒loading鐘舵��
+const approvalLoading = ref(false)
+
+// 璁$畻琛ㄦ牸鏁版嵁锛屾坊鍔犳眹鎬昏
+const tableData = computed(() => {
+  const summaryRow = {
+    id: 'summary',
+    isSummary: true,
+    name: '',
+    saleType: '',
+    accountCount: 0,
+    customerTarget: '',
+    concurrentNodes: 0,
+    pricePoint: 0,
+    priceCash: 0,
+    quantity: 0,
+    period: 0,
+  }
+  return [...detail.items, summaryRow]
+})
+
+// 鐘舵�佹槧灏勶紙鍚庣涓枃 -> 鍓嶇鏋氫妇锛�
+const statusServerToUi: Record<string, string> = {
+  '寰呬笂浼犳枃浠�': 'WAIT_UPLOAD',
+  '寰呮巿鏉�': 'WAIT_AUTHORIZE',
+  '寰呬氦鏄撶‘璁�': 'WAIT_CONFIRM',
+  '宸插畬鎴�': 'COMPLETED',
+  '宸茶瘎浠�': 'EVALUATED',
+}
+
+const formatDateTime = (val?: string) => (val ? val.replace('T', ' ').slice(0, 19) : '')
+
+const normalizePriceType = (val?: string): 'points' | 'currency' | 'agreement' | 'free' => {
+  if (!val) return 'currency'
+  const s = String(val)
+  if (/(绉垎|points)/i.test(s)) return 'points'
+  if (/(鍗忚|agreement)/i.test(s)) return 'agreement'
+  if (/(鍏嶈垂|free)/i.test(s)) return 'free'
+  return 'currency'
+}
 
 onMounted(async () => {
-  const { data } = (await fetchApprovalDetail({ id: route.params.id })) as any
-  Object.assign(detail, data || {})
+  const orderId = String(route.params.id || '')
+  if (!orderId) return
+  
+  try {
+    // 骞惰鑾峰彇璁㈠崟璇︽儏鍜屽崗璁被鍨嬫鏌�
+    const [orderRes, agreementRes] = await Promise.all([
+      orderApi.getOrderDetail(orderId),
+      orderApi.checkAgreementPriceType(orderId)
+    ])
+    
+    const res = orderRes as any
+    const data = res?.data || {}
+    
+    // 璁剧疆鏄惁涓哄崗璁鍗�
+    const agreementResult = agreementRes as any
+    isAgreementOrder.value = agreementResult?.data === true
+
+    const statusName: string = data.orderStatus || ''
+    const uiStatus = statusServerToUi[statusName] || 'INFO'
+
+    // 鏄犲皠璁㈠崟璇︽儏澶撮儴淇℃伅
+    const head = {
+      orderNo: data.orderId,
+      resourceTypeName: '杞欢浜у搧',
+      status: uiStatus,
+      statusName,
+      applyTime: formatDateTime(data.applyTime),
+      unitName: data.unitName || '-',
+      userName: data.userName || '-',
+      userAccount: data.userAccount || '-',
+      userDept: data.userDept || '-',
+      userPhone: data.userPhone || '-',
+      productName: data.productName || '-',
+      supplier: data.providerName || '-',
+      industry: data.industry || '-',
+      projectUnit: data.projectUnit || '-',
+      productType: data.productType || '-',
+      productDesc: data.productDesc || '-',
+    }
+
+    // 鏄庣粏椤规槧灏�
+    const items: any[] = Array.isArray(data.orderDetails)
+      ? data.orderDetails.map((d: any, idx: number) => {
+          const pt = normalizePriceType(d.priceType)
+          return {
+            id: String(d.id ?? idx + 1),
+            name: d.suiteName,
+            saleType: d.salesForm,
+            accountCount: d.accountLimit,
+            customerTarget: d.customerType,
+            concurrentNodes: d.concurrentNodes,
+            pricePoint: pt === 'points' ? Number(d.unitPrice || 0) : 0,
+            priceCash: pt === 'currency' ? Number(d.unitPrice || 0) : 0,
+            priceProtocol: pt === 'agreement',
+            quantity: Number(d.quantity || 0),
+            period: Number(d.duration || 0),
+            remarks: d.remarks || '', // 鏂板 remarks 瀛楁
+          }
+        })
+      : []
+
+    // 姹囨�伙紙绠�鍗曠浉鍔狅細鍗曚环*鏁伴噺锛�
+    const pointTotalNum = items.reduce((sum, it) => sum + Number(it.pricePoint || 0) * Number(it.quantity || 0), 0)
+    const cashTotalNum = items.reduce((sum, it) => sum + Number(it.priceCash || 0) * Number(it.quantity || 0), 0)
+
+    Object.assign(detail, head, {
+      items,
+      pointTotal: pointTotalNum.toLocaleString(),
+      cashTotal: cashTotalNum.toLocaleString(),
+    })
+
+    // 鍒濆鍖栬〃鍗曟暟鎹�
+    form.items = (detail.items || []).map((item: any, index: number) => {
+      return { 
+        id: item.id, // 淇濆瓨order_detail鐨刬d
+        name: item.name,
+        remark: item.remarks || '' // 浣跨敤濂椾欢淇℃伅涓殑remarks瀛楁
+      }
+    })
+
+    // 鑾峰彇璁㈠崟闄勪欢鍒楄〃锛堝鏋滄湁鐨勮瘽锛�
+    if (data.attachments && Array.isArray(data.attachments)) {
+      fileList.value = data.attachments.map((file: any) => ({
+        name: file.fileName || file.originalName,
+        size: file.fileSize || 0,
+        uid: file.id,
+        status: 'success',
+        url: file.fileUrl,
+        uploaded: true
+      }))
+    } else {
+      fileList.value = []
+    }
+  } catch (error) {
+    console.error('鑾峰彇璁㈠崟璇︽儏澶辫触:', error)
+    ElMessage.error('鑾峰彇璁㈠崟璇︽儏澶辫触')
+  }
 })
 
 const goBack = () => router.back()
-const approve = async (pass: boolean) => {
-  await formRef.value?.validate()
-  const { code } = (await submitApproval({ id: route.params.id, pass, remark: form.remark })) as any
-  if (code === 200) {
-    ElMessage.success('鎻愪氦鎴愬姛')
-    router.back()
+
+// 瀹℃壒閫氳繃澶勭悊
+const handleApprove = async () => {
+  if (!approvalForm.comments.trim()) {
+    ElMessage.warning('璇疯緭鍏ュ鎵规剰瑙�')
+    return
+  }
+  
+  try {
+    approvalLoading.value = true
+    await ElMessageBox.confirm('纭畾瑕佸鎵归�氳繃鍚楋紵', '纭鎿嶄綔', {
+      confirmButtonText: '纭畾',
+      cancelButtonText: '鍙栨秷',
+      type: 'warning'
+    })
+    
+    const orderId = String(route.params.id || '')
+    const userId = userStore.getUserId ? Number(userStore.getUserId) : undefined
+    const comments = approvalForm.comments.trim()
+
+    if (!orderId || !userId) {
+      ElMessage.error('璁㈠崟ID鎴栫敤鎴稩D涓嶈兘涓虹┖')
+      approvalLoading.value = false
+      return
+    }
+
+    // 璋冪敤瀹℃壒閫氳繃API
+    const result = await approveOrder({
+      orderId: orderId,
+      approvalOpinion: comments,
+      approverId: userId,
+      approverName: userStore.getUserDetail || '绠$悊鍛�',
+      approvalType: isAgreementOrder.value ? '瀹℃壒' : '鎺堟潈',
+      approvalResult: '閫氳繃'
+    })
+    
+    if (result && result.code === 200) {
+      // 鏇存柊浜ゆ槗淇℃伅澶囨敞锛堝彧鏇存柊remarks锛屼笉鏇存柊璁㈠崟鐘舵�侊級
+      const updateData = {
+        orderId: orderId,
+        orderDetails: form.items.map((item: any) => ({
+          id: item.id,
+          remarks: item.remark || '' // 浣跨敤琛ㄥ崟涓殑澶囨敞
+        }))
+      }
+      
+      await orderApi.updateOrderDetailRemarksOnly(updateData)
+      
+      // 瀹℃壒閫氳繃鍚庯紝浣跨敤鏂扮殑API鎺ュ彛鏇存柊璁㈠崟鐘舵�佸埌涓嬩竴涓姸鎬�
+      await orderApi.updateOrderStatusToNext(orderId)
+      ElMessage.success('瀹℃壒閫氳繃鎴愬姛')
+      router.back()
+    } else {
+      ElMessage.error(result?.msg || '瀹℃壒閫氳繃澶辫触')
+    }
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('瀹℃壒澶辫触:', error)
+      ElMessage.error('瀹℃壒澶辫触')
+    }
+  } finally {
+    approvalLoading.value = false
   }
 }
+
+// 椹冲洖澶勭悊
+const handleReject = async () => {
+  if (!approvalForm.comments.trim()) {
+    ElMessage.warning('璇疯緭鍏ュ鎵规剰瑙�')
+    return
+  }
+  
+  try {
+    approvalLoading.value = true
+    await ElMessageBox.confirm('纭畾瑕侀┏鍥炲悧锛�', '纭鎿嶄綔', {
+      confirmButtonText: '纭畾',
+      cancelButtonText: '鍙栨秷',
+      type: 'warning'
+    })
+    
+    const orderId = String(route.params.id || '')
+    const userId = userStore.getUserId ? Number(userStore.getUserId) : undefined
+    const comments = approvalForm.comments.trim()
+
+    if (!orderId || !userId) {
+      ElMessage.error('璁㈠崟ID鎴栫敤鎴稩D涓嶈兘涓虹┖')
+      approvalLoading.value = false
+      return
+    }
+
+    // 璋冪敤瀹℃壒椹冲洖API
+    const result = await approveOrder({
+      orderId: orderId,
+      approvalOpinion: comments,
+      approverId: userId,
+      approverName: userStore.getUserDetail || '绠$悊鍛�',
+      approvalType: isAgreementOrder.value ? '瀹℃壒' : '鎺堟潈',
+      approvalResult: '椹冲洖'
+    })
+    
+    if (result && result.code === 200) {
+      // 椹冲洖璁㈠崟锛屾洿鏂拌鍗曠姸鎬佸埌涓婁竴涓姸鎬�
+      await orderApi.updateOrderStatusToPrevious(orderId)
+      ElMessage.success('椹冲洖鎴愬姛')
+      router.back()
+    } else {
+      ElMessage.error(result?.msg || '椹冲洖澶辫触')
+    }
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('椹冲洖澶辫触:', error)
+      ElMessage.error('椹冲洖澶辫触')
+    }
+  } finally {
+    approvalLoading.value = false
+  }
+}
+
+// 涓庡垪琛ㄩ〉淇濇寔涓�鑷寸殑鐘舵�佺被鍨嬫槧灏勶紙UI灞曠ず鐢級
+const getStatusType = (status: string) => {
+  const statusMap: Record<string, 'warning' | 'danger' | 'success' | 'info'> = {
+    WAIT_APPROVAL: 'warning',
+    WAIT_UPLOAD: 'warning',
+    WAIT_CHECK: 'warning',
+    WAIT_CONFIRM: 'warning',
+    REJECTED: 'danger',
+    FINISH: 'success',
+  }
+  return statusMap[status] || 'info'
+}
+
+// 璁㈠崟璇︽儏涓�"鍗曚环"鏄剧ず锛氫紭鍏堟樉绀虹Н鍒嗭紝鍏舵鏄剧ず璐у竵锛涙牸寮忕ず渚嬶細
+// "绉垎锛�50,000/濂�" 鎴� "璐у竵锛�7,500/濂�/骞�" 鎴� "鍏嶈垂锛�/骞�"
+const formatPrice = (row: any) => {
+  const point = Number(row.pricePoint || 0)
+  const cash = Number(row.priceCash || 0)
+  const protocol = Boolean(row.priceProtocol)
+
+  // 鍏嶈垂
+  if (!point && !cash) {
+    return protocol ? '鍗忚锛�/骞�' : '鍏嶈垂锛�/骞�'
+  }
+  if (point) {
+    return `绉垎锛�${point.toLocaleString()}/濂梎
+  }
+  // 浠呯幇閲�
+  return `璐у竵锛�${cash.toLocaleString()}/濂�/骞碻
+}
+
+// 鏈熼檺灞曠ず锛�0 琛ㄧず"姘镐箙"锛屽叾浠栨樉绀烘暟瀛�
+const formatPeriod = (row: any) => {
+  const p = Number(row.period || 0)
+  return p === 0 ? '姘镐箙' : `${p}`
+}
+
+// 琛ㄥご鏂囧瓧灞呬腑锛屼絾绗竴琛岀殑"璇︽儏"鏂囧瓧闈犲乏瀵归綈
+const headerCenterStyle: CSSProperties = { 
+  textAlign: 'center',
+  fontSize: '14px',
+  background: '#f3f6fb'
+}
+
+// 琛ㄤ綋鏂囧瓧澶у皬
+const bodyCellStyle: CSSProperties = { fontSize: '12px' }
+
+// 涓烘眹鎬昏娣诲姞鐗规畩鏍峰紡绫诲悕
+const getRowClassName = ({ row }: { row: any }) => {
+  return row.isSummary ? 'summary-row' : ''
+}
+
+// 鍗曞厓鏍煎悎骞舵柟娉�
+const arraySpanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
+  if (row.isSummary) {
+    // 姹囨�昏锛氱涓�鍒楁樉绀哄悎骞跺唴瀹癸紝鍏朵粬鍒楅殣钘�
+    if (columnIndex === 0) {
+      return [1, 6] // 鍚堝苟1琛�6鍒�
+    } else {
+      return [0, 0] // 闅愯棌鍏朵粬鍒�
+    }
+  }
+  return [1, 1] // 鏅�氳姝e父鏄剧ず
+}
+
+// 鏂囦欢鍒楄〃琛ㄦ牸琛ㄥご鏂囧瓧灞呬腑锛屼絾绗竴鍒楃殑"浜ゆ槗鏂囦欢"鏂囧瓧闈犲乏瀵归綈
+const fileTableHeaderStyle: CSSProperties = { 
+  textAlign: 'center',
+  fontSize: '14px',
+  background: '#f3f6fb'
+}
+// 鏂囦欢鍒楄〃琛ㄦ牸琛ㄤ綋鏂囧瓧澶у皬
+const fileTableCellStyle: CSSProperties = { fontSize: '12px' }
+
+// 鏂囦欢澶у皬鏍煎紡鍖�
+const formatFileSize = (size: number) => {
+  if (!size || size === 0) return '0 Bytes';
+  const k = 1024;
+  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+  const i = Math.floor(Math.log(size) / Math.log(k));
+  return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+};
+
+// 鍒ゆ柇鏂囦欢鏄惁鍙瑙�
+const isPreviewable = (file: any) => {
+  // 棣栧厛妫�鏌IME绫诲瀷
+  const previewableTypes = [
+    'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/bmp', 'image/webp',
+    'text/plain', 'text/html', 'text/css', 'text/javascript',
+    'application/pdf',
+    'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
+    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
+    'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
+  ]
+  
+  // 濡傛灉MIME绫诲瀷鍖归厤锛岀洿鎺ヨ繑鍥瀟rue
+  if (previewableTypes.includes(file.type || '')) {
+    return true
+  }
+  
+  // 濡傛灉MIME绫诲瀷涓虹┖鎴栦笉鍖归厤锛屾牴鎹枃浠舵墿灞曞悕鍒ゆ柇
+  const fileName = file.name || ''
+  const fileExtension = fileName.toLowerCase().split('.').pop()
+  
+  const previewableExtensions = [
+    'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp',
+    'txt', 'html', 'htm', 'css', 'js',
+    'pdf',
+    'docx', 'xlsx', 'pptx'
+  ]
+  
+  return previewableExtensions.includes(fileExtension)
+}
+
+// 鍒ゆ柇鏂囦欢鏄惁宸蹭笂浼犳垚鍔�
+const isFileUploaded = (file: any) => {
+  // 鏂囦欢鏈塽rl涓旂姸鎬佷负success琛ㄧず宸蹭笂浼犳垚鍔�
+  return file.url && (file.status === 'success' || file.uploaded)
+}
+
+// 鏂囦欢棰勮
+const handlePreview = async (file: any) => {
+  if (!file.url) {
+    ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�')
+    return
+  }
+  
+  // 鑾峰彇鏂囦欢鎵╁睍鍚�
+  const fileName = file.name || ''
+  const fileExtension = fileName.toLowerCase().split('.').pop()
+  
+  let previewUrl = file.url
+  
+  // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼紭鍏堜娇鐢ㄩ瑙圲RL
+  if (file.url.includes('order-attachments')) {
+    try {
+      // 棣栧厛灏濊瘯鑾峰彇棰勮URL
+      const previewResponse = await createAxios({
+        url: `/admin/file/preview`,
+        method: 'GET',
+        params: {
+          fileName: file.url
+        }
+      })
+      
+      console.log('棰勮URL鍝嶅簲:', previewResponse)
+      
+      // 妫�鏌ュ搷搴旀牸寮�
+      const responseData = previewResponse as any
+      if (responseData && responseData.code === 200 && responseData.data) {
+        previewUrl = responseData.data
+        console.log('浣跨敤棰勮URL:', previewUrl)
+      } else {
+        console.log('棰勮URL鑾峰彇澶辫触锛屼娇鐢ㄤ笅杞芥柟寮�')
+        // 濡傛灉棰勮URL鑾峰彇澶辫触锛屽洖閫�鍒颁笅杞芥柟寮�
+        const response = await createAxios({
+          url: `/admin/file/download`,
+          method: 'GET',
+          responseType: 'blob',
+          params: {
+            fileName: file.url,
+            originalName: file.name
+          }
+        })
+        
+        // 鍒涘缓棰勮URL
+        const blob = new Blob([response as any])
+        previewUrl = window.URL.createObjectURL(blob)
+        console.log('浣跨敤Blob URL:', previewUrl)
+      }
+    } catch (error) {
+      console.error('鑾峰彇鏂囦欢澶辫触:', error)
+      ElMessage.error('鑾峰彇鏂囦欢澶辫触锛屾棤娉曢瑙�')
+      return
+    }
+  }
+  
+  // 鍥剧墖鏂囦欢鐩存帴鍦ㄦ柊绐楀彛鎵撳紑
+  if ((file.type && file.type.startsWith('image/')) || 
+      ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExtension)) {
+    console.log('棰勮鍥剧墖鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // PDF鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑
+  if (file.type === 'application/pdf' || fileExtension === 'pdf') {
+    console.log('棰勮PDF鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // 鏂囨湰鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑
+  if ((file.type && file.type.startsWith('text/')) || 
+      ['txt', 'html', 'htm', 'css', 'js'].includes(fileExtension)) {
+    console.log('棰勮鏂囨湰鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // Office鏂囨。鍜屽叾浠栨枃浠剁被鍨嬶紝灏濊瘯鍦ㄦ柊绐楀彛鎵撳紑
+  try {
+    console.log('棰勮鍏朵粬鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+  } catch (error) {
+    console.error('棰勮澶辫触:', error)
+    ElMessage.error('棰勮澶辫触锛岃涓嬭浇鍚庢煡鐪�')
+  }
+}
+
+// 鏂囦欢涓嬭浇
+const handleDownload = async (file: any) => {
+  if (!file.url) {
+    ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�')
+    return
+  }
+  
+  console.log('寮�濮嬩笅杞芥枃浠�:', file.name, 'URL:', file.url)
+  
+  try {
+    // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼娇鐢ㄥ悗绔洿鎺ヤ笅杞紸PI
+    if (file.url.includes('order-attachments')) {
+      console.log('浣跨敤MinIO涓嬭浇API')
+      
+      // 浣跨敤axios閫氳繃浠g悊璁块棶鍚庣API
+      const response = await createAxios({
+        url: `/admin/file/download`,
+        method: 'GET',
+        responseType: 'blob',
+        params: {
+          fileName: file.url,
+          originalName: file.name
+        }
+      })
+      
+      console.log('涓嬭浇鍝嶅簲:', response)
+      
+      // 鍒涘缓涓嬭浇閾炬帴
+      const blob = new Blob([response as any])
+      const downloadUrl = window.URL.createObjectURL(blob)
+      
+      console.log('鍒涘缓涓嬭浇閾炬帴:', downloadUrl)
+      
+      const link = document.createElement('a')
+      link.href = downloadUrl
+      link.download = file.name || 'download'
+      link.target = '_blank'
+      link.rel = 'noopener noreferrer'
+      
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      
+      // 娓呯悊URL瀵硅薄
+      window.URL.revokeObjectURL(downloadUrl)
+      
+      ElMessage.success('鏂囦欢涓嬭浇鎴愬姛')
+    } else {
+      console.log('浣跨敤鐩存帴URL涓嬭浇')
+      // 鍏朵粬鎯呭喌鐩存帴浣跨敤鍘烾RL
+      const link = document.createElement('a')
+      link.href = file.url
+      link.download = file.name || 'download'
+      link.target = '_blank'
+      link.rel = 'noopener noreferrer'
+      
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      
+      ElMessage.success('寮�濮嬩笅杞芥枃浠�')
+    }
+  } catch (error) {
+    console.error('涓嬭浇澶辫触:', error)
+    ElMessage.error('涓嬭浇澶辫触锛岃閲嶈瘯')
+  }
+}
+
+
+
+// 鐥囩粨涓庝慨澶嶈鏄庯細
+// 1) Element Plus 鐨� el-table 瀛愬垪 width 鐧惧垎姣旀槸鐩稿浜庤〃鏍煎鍣ㄧ殑鍍忕礌瀹藉害璁$畻锛屼絾鍙湁鍦ㄨ〃鏍煎鍣ㄦ湁鏄庣‘瀹藉害鏃舵墠鐢熸晥銆�
+// 2) 鍦ㄧ埗鍒�/澶氱骇琛ㄥご涓嬶紝瀛愬垪 width 涓虹櫨鍒嗘瘮鏃讹紝鏇寸ǔ瀹氱殑鍋氭硶鏄皢鍏惰绠椾负鍍忕礌鍊肩粦瀹氱粰瀛愬垪銆�
+// 3) 鍥犳鎴戜滑璇诲彇琛ㄦ牸澶栧眰瀹瑰櫒瀹藉害锛屾寜姣斾緥璁$畻鍍忕礌瀹藉害锛岄伩鍏嶅嚭鐜扮櫨鍒嗘瘮涓� table-layout 瀵艰嚧鐨勯敊浣嶄笌鎷変几銆�
+const colWidths = computed(() => {
+  const containerWidth = orderTableWrapRef.value?.clientWidth || 0
+  // 鐧惧垎姣斿垎鍒负锛氳鎯� 20% x 3锛屽崟浠� 15%锛屾暟閲� 10%锛屾湡闄� 15% => 鍚堣 100%
+  return {
+    detail1: Math.floor(containerWidth * 0.2),
+    detail2: Math.floor(containerWidth * 0.2),
+    detail3: Math.floor(containerWidth * 0.2),
+    price: Math.floor(containerWidth * 0.15),
+    quantity: Math.floor(containerWidth * 0.1),
+    period: Math.floor(containerWidth * 0.15),
+  }
+})
 </script>
 
 <style scoped lang="scss">
 .title { font-weight: 600; }
+.sub-title { font-weight: 600; margin: 10px 0; }
 .mt10 { margin-top: 10px; }
 .mt15 { margin-top: 15px; }
 .gray { color: #909399; font-size: 12px; }
 .total { text-align: right; margin-top: 10px; }
 .price { color: #f56c6c; font-weight: 600; }
 .ml20 { margin-left: 20px; }
+.item-block { padding: 10px; border: 1px solid #ebeef5; border-radius: 4px; margin-bottom: 10px; }
+
+/* 缁熶竴琛ㄦ牸鍐呭鏂囧瓧澶у皬 */
+.order-table :deep(.el-table__body),
+.order-table :deep(.el-table__header) {
+  font-size: 12px;
+}
+/* 琛ㄥご绗竴琛岃儗鏅壊锛堜笌浜ゆ槗鍐呭鏍囬琛屼繚鎸佷竴鑷达級 */
+.order-table :deep(.el-table__header-wrapper thead tr:first-child > th) {
+  background: #f3f6fb !important;
+  font-size: 14px !important;
+}
+/* 琛ㄥご绗簩琛岄珮搴︿笌鍐呰竟璺� */
+.order-table :deep(.el-table__header-wrapper thead tr:nth-child(2) > th) {
+  height: 5px !important;
+  padding-top: 0 !important;
+  padding-bottom: 0 !important;
+  padding-left: 0 !important;
+  padding-right: 0 !important;
+}
+/* 寮哄埗琛ㄦ牸鍒楀浐瀹氬竷灞�锛岄伩鍏嶅唴瀹瑰奖鍝嶅垪瀹� */
+.order-table :deep(table) {
+  table-layout: fixed;
+  width: 100% !important;
+}
+
+/* 姹囨�昏鏍峰紡 */
+.summary-row {
+  font-weight: 600;
+  color: #f56c6c;
+}
+.summary-total {
+  text-align: right;
+  font-weight: 600;
+}
+.summary-merged {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  width: 100%;
+}
+.summary-left {
+  text-align: left;
+}
+.summary-left .count {
+  color: #f56c6c;
+  font-weight: 600;
+}
+.summary-right {
+  text-align: right;
+}
+.order-table :deep(.summary-row) {
+  background-color: #fafafa;
+}
+.order-table :deep(.summary-row td) {
+  border-top: 2px solid #e4e7ed;
+}
+
+/* 琛ㄥご绗竴琛�"璇︽儏"鏂囧瓧闈犲乏瀵归綈 */
+.order-table :deep(.el-table__header-wrapper thead tr:first-child th:first-child) {
+  text-align: left !important;
+}
+
+/* 琛ㄥご鍥炬爣鏍峰紡 */
+.header-icon {
+  margin-right: 6px;
+  color: #409eff;
+  vertical-align: middle;
+}
+
+/* 鍒嗛殧鏍囬椋庢牸 */
+.section-header {
+  background: #f3f6fb;
+  font-weight: 600;
+  --el-border-color: #e4e7ed;
+}
+.section-header :deep(.el-descriptions__label) {
+  background: #f3f6fb;
+  border-right: none !important;
+  width: 100%;
+}
+.section-header :deep(.el-descriptions__cell) {
+  background: #f3f6fb;
+}
+.section-header :deep(.el-descriptions__content) {
+  display: none !important;
+  padding: 0 !important;
+  border: 0 !important;
+}
+.section-icon {
+  margin-right: 6px;
+  color: #409eff;
+}
+
+/* 璋冩暣鎻忚堪缁勪欢杈规浠ヤ究鏍囬琛岄鑹茶鐩栦腑闂村垎闅旂嚎 */
+:deep(.el-descriptions--border .el-descriptions__body .el-descriptions__table .el-descriptions__cell) {
+  border-right: 1px solid var(--el-border-color);
+}
+.section-header :deep(.el-descriptions__cell) {
+  border-right-color: transparent !important;
+}
+
+/* 寮哄埗 Element Plus 鎻忚堪椤圭殑 label 瀹藉害閬靛惊 label-width锛堥伩鍏嶅唴瀹规拺寮�锛� */
+/* 鍏滃簳锛氬嵆浣垮唴鑱旀牱寮忚瑕嗙洊锛屼篃鐢� important 寮哄埗鍥哄畾 */
+.fixed-label :deep(.el-descriptions__label) {
+  width: 180px !important;
+  max-width: 180px !important;
+}
+.fixed-label :deep(.el-descriptions__content) {
+  width: calc(50% - 180px) !important;
+}
+
+/* 寮哄寲绗竴琛屽垎闅旀爣棰樼殑鑳屾櫙涓庤竟妗嗚鐩� */
+.order-desc :deep(.el-descriptions__table tr:first-child .el-descriptions__cell),
+.order-desc :deep(.el-descriptions__table tr:first-child .el-descriptions__label),
+.order-desc :deep(.el-descriptions__table tr:first-child .el-descriptions__content) {
+  background: #eef3fb !important;
+  border-top-color: transparent !important;
+  border-bottom-color: #dcdfe6 !important;
+}
+.order-desc :deep(.el-descriptions__table tr:first-child .el-descriptions__label) {
+  border-right-color: transparent !important;
+}
+
+/* 缁熶竴涓や釜鎻忚堪琛ㄦ牸鐨勫垪瀵归綈锛堟爣绛惧垪鍥哄畾瀹藉害锛屽唴瀹瑰垪绛夊垎鍓╀綑瀹藉害锛� */
+.order-desc :deep(.el-descriptions__table) {
+  table-layout: fixed;
+  width: 100%;
+}
+/* 浣跨敤绫婚�夋嫨鍣ㄨ�岄潪 nth-child锛屾彁鍗囩ǔ瀹氭�э紝纭繚姣忚涓ゅ垪涓ユ牸瀵归綈 */
+.order-desc :deep(.el-descriptions__table tr:not(:first-child) .el-descriptions__label) {
+  width: 180px !important;
+  max-width: 180px !important;
+  box-sizing: border-box;
+}
+.order-desc :deep(.el-descriptions__table tr:not(:first-child) .el-descriptions__content) {
+  width: calc(50% - 180px) !important;
+}
+
+.desc-wrap {
+  white-space: pre-wrap;
+  line-height: 22px;
+}
+
+/* 鏂囦欢鍒楄〃琛ㄦ牸鏍峰紡 */
+.file-section {
+  margin-top: 15px;
+  .file-title {
+    font-weight: 600;
+    margin-bottom: 10px;
+  }
+  .file-table {
+    width: 100%;
+    .file-name {
+      display: flex;
+      align-items: center;
+      .file-icon {
+        margin-right: 8px;
+        color: #409eff;
+      }
+    }
+    .preview-btn {
+      color: #409eff;
+      &:hover {
+        text-decoration: underline;
+      }
+    }
+  }
+}
+
+/* 鏂囦欢琛ㄦ牸琛ㄥご绗竴鍒�"浜ゆ槗鏂囦欢"鏂囧瓧闈犲乏瀵归綈 */
+.file-table :deep(.el-table__header-wrapper thead tr th:first-child) {
+  text-align: left !important;
+}
+
+/* 鏂囦欢鎿嶄綔鎸夐挳鏍峰紡 */
+.file-actions {
+  display: flex;
+  gap: 8px;
+  align-items: center;
+  justify-content: center;
+  
+  .preview-btn {
+    color: #409eff;
+    &:hover {
+      text-decoration: underline;
+    }
+    &:disabled {
+      color: #c0c4cc;
+      cursor: not-allowed;
+    }
+  }
+  
+  .download-btn {
+    color: #67c23a;
+    &:hover {
+      text-decoration: underline;
+    }
+    &:disabled {
+      color: #c0c4cc;
+      cursor: not-allowed;
+    }
+  }
+}
+
+/* 浜ゆ槗淇℃伅澶囨敞琛ㄦ牸鏍峰紡 */
+.remark-table {
+  width: 100%;
+  
+  .remark-input {
+    width: 100%;
+    
+    :deep(.el-textarea__inner) {
+      border: none;
+      box-shadow: none;
+      background: transparent;
+      resize: none;
+      padding: 8px 0;
+      
+      &:focus {
+        border: 1px solid #409eff;
+        box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
+        border-radius: 4px;
+        background: #fff;
+        padding: 8px 12px;
+      }
+    }
+    
+    :deep(.el-input__count) {
+      background: transparent;
+      bottom: 2px;
+      right: 8px;
+    }
+  }
+}
+
+/* 瀹℃壒鍐呭鏍峰紡 */
+.approval-content {
+  .approval-form {
+    .form-item {
+      display: flex;
+      align-items: flex-start;
+      margin-bottom: 20px;
+      
+      label {
+        width: 120px;
+        line-height: 32px;
+        margin-right: 10px;
+        font-weight: 500;
+        
+        &.required::before {
+          content: '*';
+          color: #f56c6c;
+          margin-right: 4px;
+        }
+      }
+      
+      .el-textarea {
+        flex: 1;
+      }
+    }
+  }
+  
+  .approval-actions {
+    display: flex;
+    justify-content: center;
+    gap: 15px;
+    margin-top: 30px;
+    
+    .el-button {
+      min-width: 100px;
+    }
+  }
+}
 </style>
 
 
diff --git a/src/views/approveManage/tradeApproval/checkFiles.vue b/src/views/approveManage/tradeApproval/checkFiles.vue
index 6760c42..02db0b4 100644
--- a/src/views/approveManage/tradeApproval/checkFiles.vue
+++ b/src/views/approveManage/tradeApproval/checkFiles.vue
@@ -1,112 +1,1154 @@
 <template>
   <div class="default-main">
+    <!-- 璁㈠崟淇℃伅 + 鐢宠浜轰俊鎭� + 浜ゆ槗鍐呭锛堝悎骞朵负鍚屼竴鍗$墖锛� -->
     <el-card shadow="never">
-      <div class="title">璁㈠崟淇℃伅</div>
-      <el-descriptions :column="3" border class="mt10">
+      <el-descriptions
+        :column="2"
+        border
+        class="mt10 order-desc fixed-label"
+        label-width="180px"
+        :label-style="labelStyle"
+        :content-style="contentStyle"
+      >
+        <el-descriptions-item :span="2" class="section-header">
+          <template #label>
+            <el-icon class="section-icon"><Document /></el-icon>
+            <span>璁㈠崟淇℃伅</span>
+          </template>
+          <template #default></template>
+        </el-descriptions-item>
         <el-descriptions-item label="璁㈠崟缂栧彿">{{ detail.orderNo }}</el-descriptions-item>
         <el-descriptions-item label="浜ゆ槗璧勬簮绫诲瀷">{{ detail.resourceTypeName }}</el-descriptions-item>
-        <el-descriptions-item label="浜ゆ槗鐘舵��">{{ detail.statusName }}</el-descriptions-item>
         <el-descriptions-item label="鐢宠鏃堕棿">{{ detail.applyTime }}</el-descriptions-item>
-        <el-descriptions-item label="鍗曚綅">{{ detail.unitName }}</el-descriptions-item>
-        <el-descriptions-item label="鐢ㄦ埛鍚�">{{ detail.userName }}</el-descriptions-item>
+        <el-descriptions-item label="浜ゆ槗鐘舵��">
+          <el-tag :type="getStatusType(detail.status)" size="small">{{ detail.statusName }}</el-tag>
+        </el-descriptions-item>
       </el-descriptions>
+      
+      <!-- 鐢宠浜轰俊鎭紙涓庤鍗曚俊鎭悓鍗$墖锛屽鐢ㄥ垎闅旀爣棰樻牱寮忥級 -->
+      <el-descriptions
+        :column="2"
+        border
+        class="mt15 order-desc fixed-label"
+        label-width="180px"
+        :label-style="labelStyle"
+        :content-style="contentStyle"
+      >
+        <el-descriptions-item :span="2" class="section-header">
+          <template #label>
+            <el-icon class="section-icon"><User /></el-icon>
+            <span>鐢宠浜轰俊鎭�</span>
+          </template>
+          <template #default></template>
+        </el-descriptions-item>
+        <el-descriptions-item label="濮撳悕">{{ detail.userName || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鍗曚綅">{{ detail.unitName || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="閮ㄩ棬">{{ detail.userDept || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鐢ㄦ埛鍚�">{{ detail.userAccount || '-' }}</el-descriptions-item>
+      </el-descriptions>
+
+      <!-- 浜ゆ槗鍐呭锛堢揣闅忕敵璇蜂汉淇℃伅锛屽悓鍗$墖锛屽鐢ㄥ垎闅旀爣棰樻牱寮忥級 -->
+      <el-descriptions
+        :column="2"
+        border
+        class="mt15 order-desc fixed-label"
+        label-width="180px"
+        :label-style="labelStyle"
+        :content-style="contentStyle"
+      >
+        <el-descriptions-item :span="2" class="section-header">
+          <template #label>
+            <el-icon class="section-icon"><Goods /></el-icon>
+            <span>浜ゆ槗鍐呭</span>
+          </template>
+          <template #default></template>
+        </el-descriptions-item>
+        <el-descriptions-item label="浜у搧鍚嶇О">
+          <el-link type="primary" :underline="false">{{ detail.productName }}</el-link>
+        </el-descriptions-item>
+        <el-descriptions-item label="鎻愪緵鑰�">{{ detail.supplier }}</el-descriptions-item>
+        <el-descriptions-item label="琛屼笟棰嗗煙">{{ detail.industry }}</el-descriptions-item>
+        <el-descriptions-item label="鍗曚綅宸ョ▼">{{ detail.projectUnit }}</el-descriptions-item>
+        <el-descriptions-item label="浜у搧绫诲瀷">{{ detail.productType || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="浜у搧绠�浠�">
+          <div class="desc-wrap">{{ detail.productDesc }}</div>
+        </el-descriptions-item>
+      </el-descriptions>
+      
+      <!-- 璁㈠崟璇︽儏锛堢Щ鍔ㄥ埌浜ゆ槗鍐呭涓嬮潰锛屽悓涓�鍗$墖鍐咃級 -->
+      <div ref="orderTableWrapRef">
+        <el-table
+          :data="tableData"
+          border
+          class="mt10 order-table"
+          :header-cell-style="headerCenterStyle"
+          :cell-style="bodyCellStyle"
+          :row-class-name="getRowClassName"
+          :span-method="arraySpanMethod"
+        >
+        <el-table-column>
+          <template #header>
+            <el-icon class="header-icon"><List /></el-icon>
+            <span>璇︽儏</span>
+          </template>
+          <el-table-column label="" :width="colWidths.detail1">
+            <template #default="{ row }">
+              <div v-if="!row.isSummary">{{ row.name }}</div>
+              <div v-else class="summary-merged">
+                <div class="summary-left">
+                  鍏� <span class="count">{{ detail.items.length }}</span> 浠�
+                </div>
+                <div class="summary-right">
+                  鎬昏锛�<span class="price">{{ detail.pointTotal }}</span> 绉垎
+                  <span class="ml20 price">{{ detail.cashTotal }}</span> 鍏�
+                </div>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column label="" :width="colWidths.detail2">
+            <template #default="{ row }">
+              <div v-if="!row.isSummary" class="gray">閿�鍞舰寮忥細{{ row.saleType || '-' }}</div>
+              <div v-if="!row.isSummary" class="gray">璐︽埛鏁伴噺锛歿{ row.accountCount ?? '-' }}</div>
+            </template>
+          </el-table-column>
+          <el-table-column label="" :width="colWidths.detail3">
+            <template #default="{ row }">
+              <div v-if="!row.isSummary" class="gray">瀹㈡埛瀵硅薄锛歿{ row.customerTarget || '-' }}</div>
+              <div v-if="!row.isSummary" class="gray">骞跺彂鑺傜偣鏁伴噺锛歿{ row.concurrentNodes ?? '-' }}</div>
+            </template>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="鍗曚环">
+          <el-table-column label="" :width="colWidths.price">
+            <template #default="{ row }">
+              <div v-if="!row.isSummary">{{ formatPrice(row) }}</div>
+            </template>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="鏁伴噺">
+          <el-table-column label="" :width="colWidths.quantity">
+            <template #default="{ row }">
+              <div v-if="!row.isSummary">{{ row.quantity }}</div>
+            </template>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="鏈熼檺(骞�)">
+          <el-table-column label="" :width="colWidths.period">
+            <template #default="{ row }">
+              <div v-if="!row.isSummary">{{ formatPeriod(row) }}</div>
+            </template>
+          </el-table-column>
+        </el-table-column>
+        </el-table>
+      </div>
+
+      <!-- 绉婚櫎鍘熸潵鐨勮〃鏍煎簳閮ㄤ俊鎭紝鍥犱负宸茬粡绉诲埌琛ㄦ牸鏈�鍚庝竴琛� -->
     </el-card>
 
+    <!-- 瀹℃壒杩借釜 -->
+    <el-card class="mt15" shadow="never" v-if="detail.records?.length">
+      <div class="title">瀹℃壒杩借釜</div>
+      
+      <!-- 鏍囩椤� -->
+      <el-tabs v-model="activeTab" class="approval-tabs">
+        <el-tab-pane label="瀹℃壒璁板綍" name="records">
+          <el-table
+            :data="detail.records"
+            border
+            class="mt10 record-table"
+            :header-cell-style="recordTableHeaderStyle"
+            :cell-style="recordTableCellStyle"
+          >
+            <el-table-column label="鑺傜偣鍚嶇О" prop="nodeName" width="120" />
+            <el-table-column label="瀹℃壒浜�" prop="approver" width="120" />
+            <el-table-column label="瀹℃壒閮ㄩ棬" prop="department" width="200" />
+            <el-table-column label="寮�濮嬫椂闂�" prop="startTime" width="180" />
+            <el-table-column label="缁撴潫鏃堕棿" prop="endTime" width="180" />
+            <el-table-column label="鐘舵��" width="120">
+              <template #default="{ row }">
+                <el-tag :type="getRecordStatusType(row.statusName)" size="small">
+                  {{ row.statusName }}
+                </el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column label="瀹℃壒鎰忚" width="200">
+              <template #default="{ row }">
+                {{ row.opinion || '-' }}
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-tab-pane>
+        <el-tab-pane label="娴佺▼鑺傜偣" name="nodes">
+          <el-table
+            :data="detail.nodes"
+            border
+            class="mt10 node-table"
+            :header-cell-style="recordTableHeaderStyle"
+            :cell-style="recordTableCellStyle"
+          >
+            <el-table-column label="鑺傜偣鍚嶇О" prop="nodeName" width="120" />
+            <el-table-column label="鑺傜偣绫诲瀷" prop="nodeType" width="120" />
+            <el-table-column label="澶勭悊浜�" prop="handler" width="160" />
+            <el-table-column label="澶勭悊閮ㄩ棬" prop="department" width="200" />
+            <el-table-column label="鐘舵��" width="120">
+              <template #default="{ row }">
+                <el-tag :type="getNodeStatusType(row.status)" size="small">
+                  {{ row.statusName }}
+                </el-tag>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-tab-pane>
+      </el-tabs>
+      
+      <!-- 杩斿洖鎸夐挳 -->
+      <div class="action-buttons">
+        <el-button @click="goBack">杩斿洖</el-button>
+      </div>
+    </el-card>
+
+    <!-- 浜ゆ槗淇℃伅澶囨敞 -->
     <el-card class="mt15" shadow="never">
-      <div class="title">浜ゆ槗鍐呭</div>
-      <el-table :data="detail.items" border class="mt10">
-        <el-table-column label="璇︽儏" min-width="280">
+      <div class="title">鏂囦欢鏍告煡</div>
+      
+      <!-- 鏂囦欢鍒楄〃 -->
+      <el-table
+        :data="fileList"
+        border
+        class="mt10 file-table"
+        :header-cell-style="fileTableHeaderStyle"
+        :cell-style="fileTableCellStyle"
+        v-loading="fileLoading"
+      >
+        <el-table-column label="搴忓彿" type="index" width="60" align="center" />
+        <el-table-column label="鏂囦欢鍚�" prop="originalName" min-width="200">
           <template #default="{ row }">
-            <div>
-              <div>{{ row.name }}</div>
-              <div class="gray">瀹㈡埛瀵硅薄锛歿{ row.customerTarget }}</div>
-              <div class="gray">骞跺彂鑺傜偣鏁帮細{{ row.concurrentNodes }}</div>
+            <div class="file-name">
+              <el-icon class="file-icon" :class="getFileIconClass(row.fileType)">
+                <Document v-if="getFileIconClass(row.fileType) === 'doc'" />
+                <Picture v-else-if="getFileIconClass(row.fileType) === 'image'" />
+                <VideoPlay v-else-if="getFileIconClass(row.fileType) === 'video'" />
+                <Document v-else />
+              </el-icon>
+              <span class="file-text">{{ row.originalName || row.fileName }}</span>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="鍗曚环" prop="priceName" width="140" />
-        <el-table-column label="鏁伴噺" prop="quantity" width="80" />
-        <el-table-column label="鏈熼檺(骞�)" prop="period" width="120" />
-      </el-table>
-
-      <div class="total">
-        鎬昏锛�<span class="price">{{ detail.pointTotal }}</span> 绉垎
-        <span class="ml20 price">{{ detail.cashTotal }}</span> 鍏�
-      </div>
-    </el-card>
-
-    <el-card class="mt15" shadow="never">
-      <div class="title">浜ゆ槗鏂囦欢</div>
-      <el-table :data="files" border class="mt10">
-        <el-table-column label="鏂囦欢鍚嶇О" prop="name" />
-        <el-table-column label="鏂囦欢澶у皬" prop="size" width="140" />
-        <el-table-column label="鎿嶄綔" width="160">
+        <el-table-column label="鏂囦欢绫诲瀷" prop="fileType" width="100" align="center">
           <template #default="{ row }">
-            <el-button type="primary" link @click="preview(row)">棰勮</el-button>
-            <el-button type="primary" link @click="download(row)">涓嬭浇</el-button>
+            <el-tag :type="getFileTypeTag(row.fileType)" size="small">
+              {{ getFileTypeName(row.fileType) }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="鏂囦欢澶у皬" prop="fileSize" width="100" align="center">
+          <template #default="{ row }">
+            {{ formatFileSize(row.fileSize) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="涓婁紶鏃堕棿" prop="createdAt" width="140" align="center">
+          <template #default="{ row }">
+            {{ formatDateTime(row.createdAt) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="涓婁紶浜�" prop="uploadUserName" width="100" align="center" />
+        <el-table-column label="闄勪欢绫诲瀷" prop="attachmentType" width="100" align="center">
+          <template #default="{ row }">
+            <el-tag :type="getAttachmentTypeTag(row.attachmentType)" size="small">
+              {{ row.attachmentType || '鍏朵粬' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" width="180" align="center">
+          <template #default="{ row }">
+            <el-button 
+              type="primary" 
+              size="small" 
+              @click="handlePreview(row)"
+              :disabled="!isPreviewable(row)"
+            >
+              棰勮
+            </el-button>
+            <el-button 
+              type="success" 
+              size="small" 
+              @click="handleDownload(row)"
+            >
+              涓嬭浇
+            </el-button>
           </template>
         </el-table-column>
       </el-table>
 
-      <div class="title mt15">浜ゆ槗淇℃伅澶囨敞</div>
-      <el-form :model="form" label-width="120px" class="mt10">
-        <div v-for="(item, i) in detail.items" :key="i" class="item-block">
-          <div class="sub-title">{{ item.name }}</div>
-          <el-form-item label="澶囨敞">
-            <el-input v-model="form.items[i].remark" placeholder="璇疯緭鍏ュ娉�" />
+      <!-- 瀹℃壒鎰忚 -->
+      <div class="approval-section mt15">
+        <div class="section-title">瀹℃壒鎰忚</div>
+        <el-form :model="approvalForm" label-width="100px" class="mt10">
+          <el-form-item label="瀹℃壒鎰忚" prop="opinion">
+            <el-input
+              v-model="approvalForm.opinion"
+              type="textarea"
+              :rows="4"
+              placeholder="璇疯緭鍏ュ鎵规剰瑙�"
+              maxlength="500"
+              show-word-limit
+            />
           </el-form-item>
-        </div>
-      </el-form>
-      <div class="ba-center mt15">
-        <el-button @click="goBack">杩斿洖</el-button>
-        <el-button type="success" @click="submit(true)">閫氳繃</el-button>
-        <el-button type="danger" @click="submit(false)">椹冲洖</el-button>
+        </el-form>
+      </div>
+      
+      <!-- 鎿嶄綔鎸夐挳 -->
+      <div class="approval-actions">
+        <el-button @click="goBack" class="back-btn">杩斿洖</el-button>
+        <el-button 
+          type="success" 
+          @click="handleApprove(true)" 
+          class="approve-btn"
+          :loading="approvalLoading"
+        >
+          閫氳繃
+        </el-button>
+        <el-button 
+          type="danger" 
+          @click="handleApprove(false)" 
+          class="reject-btn"
+          :loading="approvalLoading"
+        >
+          椹冲洖
+        </el-button>
       </div>
     </el-card>
+
+    <!-- 鏂囦欢棰勮寮圭獥 -->
+    <el-dialog
+      v-model="previewVisible"
+      title="鏂囦欢棰勮"
+      width="80%"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      class="file-preview-dialog"
+    >
+      <div class="preview-content">
+        <filePreview ref="filePreviewRef" @closePreview="previewVisible = false" />
+      </div>
+    </el-dialog>
   </div>
 </template>
 
 <script setup lang="ts">
-import { onMounted, reactive } from 'vue'
+import { onMounted, reactive, ref, computed, nextTick, type CSSProperties } from 'vue'
+import { Document, User, Goods, List, Picture, VideoPlay } from '@element-plus/icons-vue'
 import { useRoute, useRouter } from 'vue-router'
-import { fetchApprovalDetail, checkFiles } from '@/api/approvalManage'
-import { ElMessage } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import orderApi from '@/api/orderApi'
+import { checkFiles } from '@/api/approvalManage'
+import filePreview from '@/components/filePreview/index.vue'
+import createAxios from '@/utils/axios'
+import { useUserInfo } from '@/stores/modules/userInfo'
 
 const route = useRoute()
 const router = useRouter()
-const detail = reactive<any>({ items: [] })
-const files = reactive<any[]>([])
-const form = reactive<any>({ items: [] })
+const userStore = useUserInfo()
+const detail = reactive<any>({ items: [], records: [], nodes: [] })
+const orderTableWrapRef = ref<HTMLElement | null>(null)
+const activeTab = ref('records')
+const labelStyle = { width: '180px', maxWidth: '180px' }
+const contentStyle = { width: 'calc(50% - 180px)' }
 
-onMounted(async () => {
-  const { data } = (await fetchApprovalDetail({ id: route.params.id })) as any
-  Object.assign(detail, data || {})
-  files.splice(0, files.length, ...(data?.files || []))
-  form.items = (detail.items || []).map(() => ({ remark: '' }))
+// 鏂囦欢鐩稿叧鏁版嵁
+const fileList = ref<any[]>([])
+const fileLoading = ref(false)
+const previewVisible = ref(false)
+const filePreviewRef = ref()
+
+// 瀹℃壒鐩稿叧鏁版嵁
+const approvalForm = reactive({
+  opinion: ''
+})
+const approvalLoading = ref(false)
+
+// 鏂囦欢琛ㄦ牸鏍峰紡
+const fileTableHeaderStyle: CSSProperties = { 
+  textAlign: 'center',
+  fontSize: '14px',
+  background: '#f3f6fb'
+}
+const fileTableCellStyle: CSSProperties = { fontSize: '12px' }
+
+// 璁$畻琛ㄦ牸鏁版嵁锛屾坊鍔犳眹鎬昏
+const tableData = computed(() => {
+  const summaryRow = {
+    id: 'summary',
+    isSummary: true,
+    name: '',
+    saleType: '',
+    accountCount: 0,
+    customerTarget: '',
+    concurrentNodes: 0,
+    pricePoint: 0,
+    priceCash: 0,
+    quantity: 0,
+    period: 0,
+  }
+  return [...detail.items, summaryRow]
 })
 
-const preview = (file: any) => window.open(file.previewUrl)
-const download = (file: any) => window.open(file.downloadUrl)
+// 鐘舵�佹槧灏勶紙鍚庣涓枃 -> 鍓嶇鏋氫妇锛�
+const statusServerToUi: Record<string, string> = {
+  '寰呬笂浼犳枃浠�': 'WAIT_UPLOAD',
+  '寰呮巿鏉�': 'WAIT_AUTHORIZE',
+  '寰呬氦鏄撶‘璁�': 'WAIT_CONFIRM',
+  '宸插畬鎴�': 'COMPLETED',
+  '宸茶瘎浠�': 'EVALUATED',
+}
+
+const formatDateTime = (val?: string) => (val ? val.replace('T', ' ').slice(0, 19) : '')
+
+const normalizePriceType = (val?: string): 'points' | 'currency' | 'agreement' | 'free' => {
+  if (!val) return 'currency'
+  const s = String(val)
+  if (/(绉垎|points)/i.test(s)) return 'points'
+  if (/(鍗忚|agreement)/i.test(s)) return 'agreement'
+  if (/(鍏嶈垂|free)/i.test(s)) return 'free'
+  return 'currency'
+}
+
+onMounted(async () => {
+  const orderId = String(route.params.id || '')
+  if (!orderId) return
+  const res = (await orderApi.getOrderDetail(orderId)) as any
+  const data = res?.data || {}
+
+  const statusName: string = data.orderStatus || ''
+  const uiStatus = statusServerToUi[statusName] || 'INFO'
+
+  // 鏄犲皠璁㈠崟璇︽儏澶撮儴淇℃伅
+  const head = {
+    orderNo: data.orderId,
+    resourceTypeName: '杞欢浜у搧',
+    status: uiStatus,
+    statusName,
+    applyTime: formatDateTime(data.applyTime),
+    unitName: '-',
+    userName: '-',
+    userAccount: '-',
+    userDept: '-',
+    userPhone: '-',
+    productName: data.productName || '-',
+    supplier: data.providerName || '-',
+    industry: '-',
+    projectUnit: '-',
+    productType: '-',
+    productDesc: '-',
+  }
+
+  // 鏄庣粏椤规槧灏�
+  const items: any[] = Array.isArray(data.orderDetails)
+    ? data.orderDetails.map((d: any, idx: number) => {
+        const pt = normalizePriceType(d.priceType)
+        return {
+          id: String(d.id ?? idx + 1),
+          name: d.suiteName,
+          saleType: d.salesForm,
+          accountCount: d.accountLimit,
+          customerTarget: d.customerType,
+          concurrentNodes: d.concurrentNodes,
+          pricePoint: pt === 'points' ? Number(d.unitPrice || 0) : 0,
+          priceCash: pt === 'currency' ? Number(d.unitPrice || 0) : 0,
+          priceProtocol: pt === 'agreement',
+          quantity: Number(d.quantity || 0),
+          period: Number(d.duration || 0),
+        }
+      })
+    : []
+
+  // 姹囨�伙紙绠�鍗曠浉鍔狅細鍗曚环*鏁伴噺锛�
+  const pointTotalNum = items.reduce((sum, it) => sum + Number(it.pricePoint || 0) * Number(it.quantity || 0), 0)
+  const cashTotalNum = items.reduce((sum, it) => sum + Number(it.priceCash || 0) * Number(it.quantity || 0), 0)
+
+  Object.assign(detail, head, {
+    items,
+    pointTotal: pointTotalNum.toLocaleString(),
+    cashTotal: cashTotalNum.toLocaleString(),
+    records: [],
+    nodes: [],
+  })
+  
+  // 鍒濆鍖栨枃浠跺垪琛�
+  if (data.attachments && Array.isArray(data.attachments)) {
+    fileList.value = data.attachments
+  }
+})
+
+// 涓庡垪琛ㄩ〉淇濇寔涓�鑷寸殑鐘舵�佺被鍨嬫槧灏勶紙UI灞曠ず鐢級
+const getStatusType = (status: string) => {
+  const statusMap: Record<string, 'warning' | 'danger' | 'success' | 'info'> = {
+    WAIT_APPROVAL: 'warning',
+    WAIT_UPLOAD: 'warning',
+    WAIT_CHECK: 'warning',
+    WAIT_CONFIRM: 'warning',
+    REJECTED: 'danger',
+    FINISH: 'success',
+  }
+  return statusMap[status] || 'info'
+}
+
+// 璁㈠崟璇︽儏涓�"鍗曚环"鏄剧ず锛氫紭鍏堟樉绀虹Н鍒嗭紝鍏舵鏄剧ず璐у竵锛涙牸寮忕ず渚嬶細
+// "绉垎锛�50,000/濂�" 鎴� "璐у竵锛�7,500/濂�/骞�" 鎴� "鍏嶈垂锛�/骞�"
+const formatPrice = (row: any) => {
+  const point = Number(row.pricePoint || 0)
+  const cash = Number(row.priceCash || 0)
+  const protocol = Boolean(row.priceProtocol)
+
+  // 鍏嶈垂
+  if (!point && !cash) {
+    return protocol ? '鍗忚锛�/骞�' : '鍏嶈垂锛�/骞�'
+  }
+  if (point) {
+    return `绉垎锛�${point.toLocaleString()}/濂梎
+  }
+  // 浠呯幇閲�
+  return `璐у竵锛�${cash.toLocaleString()}/濂�/骞碻
+}
+
+// 鏈熼檺灞曠ず锛�0 琛ㄧず"姘镐箙"锛屽叾浠栨樉绀烘暟瀛�
+const formatPeriod = (row: any) => {
+  const p = Number(row.period || 0)
+  return p === 0 ? '姘镐箙' : `${p}`
+}
+
+// 琛ㄥご鏂囧瓧灞呬腑锛屼絾绗竴琛岀殑"璇︽儏"鏂囧瓧闈犲乏瀵归綈
+const headerCenterStyle: CSSProperties = { 
+  textAlign: 'center',
+  fontSize: '14px',
+  background: '#f3f6fb'
+}
+
+// 琛ㄤ綋鏂囧瓧澶у皬
+const bodyCellStyle: CSSProperties = { fontSize: '12px' }
+
+// 瀹℃壒杩借釜琛ㄦ牸鏍峰紡
+const recordTableHeaderStyle: CSSProperties = { 
+  textAlign: 'center',
+  fontSize: '14px',
+  background: '#f3f6fb'
+}
+const recordTableCellStyle: CSSProperties = { fontSize: '12px' }
+
+// 涓烘眹鎬昏娣诲姞鐗规畩鏍峰紡绫诲悕
+const getRowClassName = ({ row }: { row: any }) => {
+  return row.isSummary ? 'summary-row' : ''
+}
+
+// 瀹℃壒璁板綍鐘舵�佺被鍨嬫槧灏�
+const getRecordStatusType = (statusName: string) => {
+  const statusMap: Record<string, 'success' | 'warning' | 'danger' | 'info'> = {
+    '宸插畬鎴�': 'success',
+    '瀹¢槄涓�': 'warning',
+    '宸叉彁浜�': 'info',
+    '寰呭鏍�': 'warning',
+    '宸叉嫆缁�': 'danger',
+  }
+  return statusMap[statusName] || 'info'
+}
+
+// 娴佺▼鑺傜偣鐘舵�佺被鍨嬫槧灏�
+const getNodeStatusType = (status: string) => {
+  const statusMap: Record<string, 'success' | 'warning' | 'danger' | 'info'> = {
+    'completed': 'success',
+    'processing': 'warning',
+    'pending': 'info',
+    'rejected': 'danger',
+  }
+  return statusMap[status] || 'info'
+}
+
+// 杩斿洖鎸夐挳
 const goBack = () => router.back()
-const submit = async (pass: boolean) => {
-  const { code } = (await checkFiles({ id: route.params.id, pass, ...form })) as any
-  if (code === 200) {
-    ElMessage.success('鎿嶄綔鎴愬姛')
-    router.back()
+
+// 鏂囦欢鐩稿叧鏂规硶
+const getFileIconClass = (fileType: string) => {
+  const type = fileType?.toLowerCase() || ''
+  if (['doc', 'docx', 'pdf', 'txt'].includes(type)) return 'doc'
+  if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(type)) return 'image'
+  if (['mp4', 'avi', 'mov', 'wmv'].includes(type)) return 'video'
+  return 'doc'
+}
+
+const getFileTypeTag = (fileType: string) => {
+  const type = fileType?.toLowerCase() || ''
+  if (['doc', 'docx'].includes(type)) return 'primary'
+  if (['pdf'].includes(type)) return 'danger'
+  if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(type)) return 'success'
+  if (['mp4', 'avi', 'mov', 'wmv'].includes(type)) return 'warning'
+  return 'info'
+}
+
+const getFileTypeName = (fileType: string) => {
+  const type = fileType?.toLowerCase() || ''
+  if (['doc', 'docx'].includes(type)) return 'Word'
+  if (['pdf'].includes(type)) return 'PDF'
+  if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(type)) return '鍥剧墖'
+  if (['mp4', 'avi', 'mov', 'wmv'].includes(type)) return '瑙嗛'
+  if (['xls', 'xlsx'].includes(type)) return 'Excel'
+  return '鍏朵粬'
+}
+
+const formatFileSize = (size: number) => {
+  if (!size) return '0 B'
+  const units = ['B', 'KB', 'MB', 'GB']
+  let index = 0
+  let fileSize = size
+  while (fileSize >= 1024 && index < units.length - 1) {
+    fileSize /= 1024
+    index++
+  }
+  return `${fileSize.toFixed(2)} ${units[index]}`
+}
+
+const getAttachmentTypeTag = (type: string) => {
+  switch (type) {
+    case '鍚堝悓': return 'primary'
+    case '鍙戠エ': return 'success'
+    default: return 'info'
   }
 }
+
+// 鍒ゆ柇鏂囦欢鏄惁鍙瑙�
+const isPreviewable = (file: any) => {
+  // 棣栧厛妫�鏌IME绫诲瀷
+  const previewableTypes = [
+    'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/bmp', 'image/webp',
+    'text/plain', 'text/html', 'text/css', 'text/javascript',
+    'application/pdf',
+    'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
+    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
+    'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
+  ]
+  
+  // 濡傛灉MIME绫诲瀷鍖归厤锛岀洿鎺ヨ繑鍥瀟rue
+  if (previewableTypes.includes(file.fileType || '')) {
+    return true
+  }
+  
+  // 濡傛灉MIME绫诲瀷涓虹┖鎴栦笉鍖归厤锛屾牴鎹枃浠舵墿灞曞悕鍒ゆ柇
+  const fileName = file.originalName || file.fileName || ''
+  const fileExtension = fileName.toLowerCase().split('.').pop()
+  
+  const previewableExtensions = [
+    'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp',
+    'txt', 'html', 'htm', 'css', 'js',
+    'pdf',
+    'docx', 'xlsx', 'pptx'
+  ]
+  
+  return previewableExtensions.includes(fileExtension)
+}
+
+// 鏂囦欢棰勮
+const handlePreview = async (file: any) => {
+  // 浼樺厛浣跨敤fileUrl锛屽鏋滄病鏈夊垯浣跨敤fileName
+  const fileUrl = file.fileUrl || file.fileName
+  if (!fileUrl) {
+    ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�')
+    return
+  }
+  
+  // 鑾峰彇鏂囦欢鎵╁睍鍚�
+  const fileName = file.originalName || file.fileName || ''
+  const fileExtension = fileName.toLowerCase().split('.').pop()
+  
+  let previewUrl = fileUrl
+  
+  // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼紭鍏堜娇鐢ㄩ瑙圲RL
+  if (fileUrl.includes('order-attachments')) {
+    try {
+      // 棣栧厛灏濊瘯鑾峰彇棰勮URL
+      const previewResponse = await createAxios({
+        url: `/admin/file/preview`,
+        method: 'GET',
+        params: {
+          fileName: fileUrl
+        }
+      })
+      
+      console.log('棰勮URL鍝嶅簲:', previewResponse)
+      
+      // 妫�鏌ュ搷搴旀牸寮�
+      const responseData = previewResponse as any
+      if (responseData && responseData.code === 200 && responseData.data) {
+        previewUrl = responseData.data
+        console.log('浣跨敤棰勮URL:', previewUrl)
+      } else {
+        console.log('棰勮URL鑾峰彇澶辫触锛屼娇鐢ㄤ笅杞芥柟寮�')
+        // 濡傛灉棰勮URL鑾峰彇澶辫触锛屽洖閫�鍒颁笅杞芥柟寮�
+        const response = await createAxios({
+          url: `/admin/file/download`,
+          method: 'GET',
+          responseType: 'blob',
+          params: {
+            fileName: fileUrl,
+            originalName: file.originalName || file.fileName
+          }
+        })
+        
+        // 鍒涘缓棰勮URL
+        const blob = new Blob([response as any])
+        previewUrl = window.URL.createObjectURL(blob)
+        console.log('浣跨敤Blob URL:', previewUrl)
+      }
+    } catch (error) {
+      console.error('鑾峰彇鏂囦欢澶辫触:', error)
+      ElMessage.error('鑾峰彇鏂囦欢澶辫触锛屾棤娉曢瑙�')
+      return
+    }
+  }
+  
+  // 鍥剧墖鏂囦欢鐩存帴鍦ㄦ柊绐楀彛鎵撳紑
+  if ((file.fileType && file.fileType.startsWith('image/')) || 
+      ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExtension)) {
+    console.log('棰勮鍥剧墖鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // PDF鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑
+  if (file.fileType === 'application/pdf' || fileExtension === 'pdf') {
+    console.log('棰勮PDF鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // 鏂囨湰鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑
+  if ((file.fileType && file.fileType.startsWith('text/')) || 
+      ['txt', 'html', 'htm', 'css', 'js'].includes(fileExtension)) {
+    console.log('棰勮鏂囨湰鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // Office鏂囨。鍜屽叾浠栨枃浠剁被鍨嬶紝灏濊瘯鍦ㄦ柊绐楀彛鎵撳紑
+  try {
+    console.log('棰勮鍏朵粬鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+  } catch (error) {
+    console.error('棰勮澶辫触:', error)
+    ElMessage.error('棰勮澶辫触锛岃涓嬭浇鍚庢煡鐪�')
+  }
+}
+
+// 鏂囦欢涓嬭浇
+const handleDownload = async (file: any) => {
+  // 浼樺厛浣跨敤fileUrl锛屽鏋滄病鏈夊垯浣跨敤fileName
+  const fileUrl = file.fileUrl || file.fileName
+  if (!fileUrl) {
+    ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�')
+    return
+  }
+  
+  console.log('寮�濮嬩笅杞芥枃浠�:', file.originalName || file.fileName, 'URL:', fileUrl)
+  
+  try {
+    // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼娇鐢ㄥ悗绔洿鎺ヤ笅杞紸PI
+    if (fileUrl.includes('order-attachments')) {
+      console.log('浣跨敤MinIO涓嬭浇API')
+      
+      // 浣跨敤axios閫氳繃浠g悊璁块棶鍚庣API
+      const response = await createAxios({
+        url: `/admin/file/download`,
+        method: 'GET',
+        responseType: 'blob',
+        params: {
+          fileName: fileUrl,
+          originalName: file.originalName || file.fileName
+        }
+      })
+      
+      console.log('涓嬭浇鍝嶅簲:', response)
+      
+      // 鍒涘缓涓嬭浇閾炬帴
+      const blob = new Blob([response as any])
+      const downloadUrl = window.URL.createObjectURL(blob)
+      
+      console.log('鍒涘缓涓嬭浇閾炬帴:', downloadUrl)
+      
+      const link = document.createElement('a')
+      link.href = downloadUrl
+      link.download = file.originalName || file.fileName || 'download'
+      link.target = '_blank'
+      link.rel = 'noopener noreferrer'
+      
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      
+      // 娓呯悊URL瀵硅薄
+      window.URL.revokeObjectURL(downloadUrl)
+      
+      ElMessage.success('鏂囦欢涓嬭浇鎴愬姛')
+    } else {
+      console.log('浣跨敤鐩存帴URL涓嬭浇')
+      // 鍏朵粬鎯呭喌鐩存帴浣跨敤鍘烾RL
+      const link = document.createElement('a')
+      link.href = fileUrl
+      link.download = file.originalName || file.fileName || 'download'
+      link.target = '_blank'
+      link.rel = 'noopener noreferrer'
+      
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      
+      ElMessage.success('寮�濮嬩笅杞芥枃浠�')
+    }
+  } catch (error) {
+    console.error('涓嬭浇澶辫触:', error)
+    ElMessage.error('涓嬭浇澶辫触锛岃閲嶈瘯')
+  }
+}
+
+// 澶勭悊瀹℃壒
+const handleApprove = async (isApprove: boolean) => {
+  if (!approvalForm.opinion.trim()) {
+    ElMessage.warning('璇疯緭鍏ュ鎵规剰瑙�')
+    return
+  }
+
+  const actionText = isApprove ? '閫氳繃' : '椹冲洖'
+  
+  try {
+    await ElMessageBox.confirm(`纭畾瑕�${actionText}璇ヨ鍗曞悧锛焋, '纭鎿嶄綔', {
+      confirmButtonText: '纭畾',
+      cancelButtonText: '鍙栨秷',
+      type: 'warning'
+    })
+    
+    approvalLoading.value = true
+    const orderId = String(route.params.id || '')
+    
+    // 璋冪敤鏂囦欢鏍告煡API
+    const result = await checkFiles({
+      orderId: orderId,
+      isApprove: isApprove,
+      approvalOpinion: approvalForm.opinion,
+      approverId: Number(userStore.getUserId) || 1,
+      approverName: userStore.getUserDetail || '绠$悊鍛�'
+    })
+    
+    if (result && result.code === 200) {
+      ElMessage.success(`${actionText}鎴愬姛`)
+      router.back()
+    } else {
+      ElMessage.error(result?.msg || `${actionText}澶辫触`)
+    }
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('瀹℃壒澶辫触:', error)
+      ElMessage.error('瀹℃壒澶辫触锛岃閲嶈瘯')
+    }
+  } finally {
+    approvalLoading.value = false
+  }
+}
+
+// 鍗曞厓鏍煎悎骞舵柟娉�
+const arraySpanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
+  if (row.isSummary) {
+    // 姹囨�昏锛氱涓�鍒楁樉绀哄悎骞跺唴瀹癸紝鍏朵粬鍒楅殣钘�
+    if (columnIndex === 0) {
+      return [1, 6] // 鍚堝苟1琛�6鍒�
+    } else {
+      return [0, 0] // 闅愯棌鍏朵粬鍒�
+    }
+  }
+  return [1, 1] // 鏅�氳姝e父鏄剧ず
+}
+
+// 鐥囩粨涓庝慨澶嶈鏄庯細
+// 1) Element Plus 鐨� el-table 瀛愬垪 width 鐧惧垎姣旀槸鐩稿浜庤〃鏍煎鍣ㄧ殑鍍忕礌瀹藉害璁$畻锛屼絾鍙湁鍦ㄨ〃鏍煎鍣ㄦ湁鏄庣‘瀹藉害鏃舵墠鐢熸晥銆�
+// 2) 鍦ㄧ埗鍒�/澶氱骇琛ㄥご涓嬶紝瀛愬垪 width 涓虹櫨鍒嗘瘮鏃讹紝鏇寸ǔ瀹氱殑鍋氭硶鏄皢鍏惰绠椾负鍍忕礌鍊肩粦瀹氱粰瀛愬垪銆�
+// 3) 鍥犳鎴戜滑璇诲彇琛ㄦ牸澶栧眰瀹瑰櫒瀹藉害锛屾寜姣斾緥璁$畻鍍忕礌瀹藉害锛岄伩鍏嶅嚭鐜扮櫨鍒嗘瘮涓� table-layout 瀵艰嚧鐨勯敊浣嶄笌鎷変几銆�
+const colWidths = computed(() => {
+  const containerWidth = orderTableWrapRef.value?.clientWidth || 0
+  // 鐧惧垎姣斿垎鍒负锛氳鎯� 20% x 3锛屽崟浠� 15%锛屾暟閲� 10%锛屾湡闄� 15% => 鍚堣 100%
+  return {
+    detail1: Math.floor(containerWidth * 0.2),
+    detail2: Math.floor(containerWidth * 0.2),
+    detail3: Math.floor(containerWidth * 0.2),
+    price: Math.floor(containerWidth * 0.15),
+    quantity: Math.floor(containerWidth * 0.1),
+    period: Math.floor(containerWidth * 0.15),
+  }
+})
 </script>
 
 <style scoped lang="scss">
 .title { font-weight: 600; }
-.sub-title { font-weight: 600; margin: 10px 0; }
 .mt10 { margin-top: 10px; }
 .mt15 { margin-top: 15px; }
 .gray { color: #909399; font-size: 12px; }
 .total { text-align: right; margin-top: 10px; }
 .price { color: #f56c6c; font-weight: 600; }
 .ml20 { margin-left: 20px; }
-.item-block { padding: 10px; border: 1px solid #ebeef5; border-radius: 4px; margin-bottom: 10px; }
+/* 缁熶竴琛ㄦ牸鍐呭鏂囧瓧澶у皬 */
+.order-table :deep(.el-table__body),
+.order-table :deep(.el-table__header) {
+  font-size: 12px;
+}
+/* 瀹℃壒杩借釜琛ㄦ牸锛氳〃澶磋儗鏅� + 瀛楀彿 */
+.record-table :deep(.el-table__body),
+.record-table :deep(.el-table__header) {
+  font-size: 12px;
+}
+.record-table :deep(.el-table__header-wrapper thead tr:first-child > th) {
+  background: #f5f7fa;
+}
+/* 琛ㄥご绗竴琛岃儗鏅壊锛堜笌浜ゆ槗鍐呭鏍囬琛屼繚鎸佷竴鑷达級 */
+.order-table :deep(.el-table__header-wrapper thead tr:first-child > th) {
+  background: #f3f6fb !important;
+  font-size: 14px !important;
+}
+/* 琛ㄥご绗簩琛岄珮搴︿笌鍐呰竟璺� */
+.order-table :deep(.el-table__header-wrapper thead tr:nth-child(2) > th) {
+  height: 5px !important;
+  padding-top: 0 !important;
+  padding-bottom: 0 !important;
+  padding-left: 0 !important;
+  padding-right: 0 !important;
+}
+/* 寮哄埗琛ㄦ牸鍒楀浐瀹氬竷灞�锛岄伩鍏嶅唴瀹瑰奖鍝嶅垪瀹� */
+.order-table :deep(table) {
+  table-layout: fixed;
+  width: 100% !important;
+}
+
+/* 姹囨�昏鏍峰紡 */
+.summary-row {
+  font-weight: 600;
+  color: #f56c6c;
+}
+.summary-total {
+  text-align: right;
+  font-weight: 600;
+}
+.summary-merged {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  width: 100%;
+}
+.summary-left {
+  text-align: left;
+}
+.summary-left .count {
+  color: #f56c6c;
+  font-weight: 600;
+}
+.summary-right {
+  text-align: right;
+}
+.order-table :deep(.summary-row) {
+  background-color: #fafafa;
+}
+.order-table :deep(.summary-row td) {
+  border-top: 2px solid #e4e7ed;
+}
+
+/* 琛ㄥご绗竴琛�"璇︽儏"鏂囧瓧闈犲乏瀵归綈 */
+.order-table :deep(.el-table__header-wrapper thead tr:first-child th:first-child) {
+  text-align: left !important;
+}
+
+/* 琛ㄥご鍥炬爣鏍峰紡 */
+.header-icon {
+  margin-right: 6px;
+  color: #409eff;
+  vertical-align: middle;
+}
+
+/* 鍒嗛殧鏍囬椋庢牸 */
+.section-header {
+  background: #f3f6fb;
+  font-weight: 600;
+  --el-border-color: #e4e7ed;
+}
+.section-header :deep(.el-descriptions__label) {
+  background: #f3f6fb;
+  border-right: none !important;
+  width: 100%;
+}
+.section-header :deep(.el-descriptions__cell) {
+  background: #f3f6fb;
+}
+.section-header :deep(.el-descriptions__content) {
+  display: none !important;
+  padding: 0 !important;
+  border: 0 !important;
+}
+.section-icon {
+  margin-right: 6px;
+  color: #409eff;
+}
+
+/* 璋冩暣鎻忚堪缁勪欢杈规浠ヤ究鏍囬琛岄鑹茶鐩栦腑闂村垎闅旂嚎 */
+:deep(.el-descriptions--border .el-descriptions__body .el-descriptions__table .el-descriptions__cell) {
+  border-right: 1px solid var(--el-border-color);
+}
+.section-header :deep(.el-descriptions__cell) {
+  border-right-color: transparent !important;
+}
+
+/* 寮哄埗 Element Plus 鎻忚堪椤圭殑 label 瀹藉害閬靛惊 label-width锛堥伩鍏嶅唴瀹规拺寮�锛� */
+/* 鍏滃簳锛氬嵆浣垮唴鑱旀牱寮忚瑕嗙洊锛屼篃鐢� important 寮哄埗鍥哄畾 */
+.fixed-label :deep(.el-descriptions__label) {
+  width: 180px !important;
+  max-width: 180px !important;
+}
+.fixed-label :deep(.el-descriptions__content) {
+  width: calc(50% - 180px) !important;
+}
+
+/* 寮哄寲绗竴琛屽垎闅旀爣棰樼殑鑳屾櫙涓庤竟妗嗚鐩� */
+.order-desc :deep(.el-descriptions__table tr:first-child .el-descriptions__cell),
+.order-desc :deep(.el-descriptions__table tr:first-child .el-descriptions__label),
+.order-desc :deep(.el-descriptions__table tr:first-child .el-descriptions__content) {
+  background: #eef3fb !important;
+  border-top-color: transparent !important;
+  border-bottom-color: #dcdfe6 !important;
+}
+.order-desc :deep(.el-descriptions__table tr:first-child .el-descriptions__label) {
+  border-right-color: transparent !important;
+}
+
+/* 缁熶竴涓や釜鎻忚堪琛ㄦ牸鐨勫垪瀵归綈锛堟爣绛惧垪鍥哄畾瀹藉害锛屽唴瀹瑰垪绛夊垎鍓╀綑瀹藉害锛� */
+.order-desc :deep(.el-descriptions__table) {
+  table-layout: fixed;
+  width: 100%;
+}
+/* 浣跨敤绫婚�夋嫨鍣ㄨ�岄潪 nth-child锛屾彁鍗囩ǔ瀹氭�э紝纭繚姣忚涓ゅ垪涓ユ牸瀵归綈 */
+.order-desc :deep(.el-descriptions__table tr:not(:first-child) .el-descriptions__label) {
+  width: 180px !important;
+  max-width: 180px !important;
+  box-sizing: border-box;
+}
+.order-desc :deep(.el-descriptions__table tr:not(:first-child) .el-descriptions__content) {
+  width: calc(50% - 180px) !important;
+}
+
+.desc-wrap {
+  white-space: pre-wrap;
+  line-height: 22px;
+}
+
+/* 瀹℃壒杩借釜鏍囩椤垫牱寮� */
+.approval-tabs {
+  margin-top: 15px;
+}
+
+/* 鎿嶄綔鎸夐挳鏍峰紡 */
+.action-buttons {
+  display: flex;
+  justify-content: center;
+  margin-top: 15px;
+  .el-button {
+    margin: 0 10px;
+  }
+}
+
+/* 鏂囦欢琛ㄦ牸鏍峰紡 */
+.file-table {
+  .file-name {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    
+    .file-icon {
+      font-size: 14px;
+      
+      &.doc {
+        color: #409eff;
+      }
+      
+      &.image {
+        color: #67c23a;
+      }
+      
+      &.video {
+        color: #e6a23c;
+      }
+    }
+    
+    .file-text {
+      color: #303133;
+      font-size: 14px;
+    }
+  }
+}
+
+/* 瀹℃壒鎰忚鍖哄煙 */
+.approval-section {
+  .section-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #303133;
+    margin-bottom: 15px;
+    padding-bottom: 8px;
+    border-bottom: 1px solid #e4e7ed;
+  }
+}
+
+/* 瀹℃壒鎿嶄綔鎸夐挳鏍峰紡 */
+.approval-actions {
+  display: flex;
+  justify-content: center;
+  margin-top: 20px;
+  gap: 20px;
+  
+  .back-btn {
+    background: #ffffff;
+    border: 1px solid #dcdfe6;
+    color: #606266;
+    
+    &:hover {
+      background: #f5f7fa;
+      border-color: #c0c4cc;
+    }
+  }
+  
+  .approve-btn {
+    background: #67c23a;
+    border-color: #67c23a;
+    color: #ffffff;
+    
+    &:hover {
+      background: #85ce61;
+      border-color: #85ce61;
+    }
+  }
+  
+  .reject-btn {
+    background: #f56c6c;
+    border-color: #f56c6c;
+    color: #ffffff;
+    
+    &:hover {
+      background: #f78989;
+      border-color: #f78989;
+    }
+  }
+}
+
+/* 鏂囦欢棰勮寮圭獥鏍峰紡 */
+.file-preview-dialog {
+  :deep(.el-dialog__body) {
+    padding: 0;
+    height: 70vh;
+  }
+  
+  .preview-content {
+    height: 100%;
+  }
+}
 </style>
 
 
diff --git a/src/views/approveManage/tradeApproval/list.vue b/src/views/approveManage/tradeApproval/list.vue
index 73d6f4b..cc335ab 100644
--- a/src/views/approveManage/tradeApproval/list.vue
+++ b/src/views/approveManage/tradeApproval/list.vue
@@ -148,13 +148,13 @@
                 <div v-if="row.isSpacer" class="spacer-cell"></div>
                 <div v-else-if="!row.isMainOrder" class="price-info">
                   <span v-if="row.priceType === 'points'" class="price-points">
-                    {{ row.unitPrice }}绉垎
+                    绉垎 {{ row.unitPrice }}
                   </span>
                   <span v-else-if="row.priceType === 'currency'" class="price-currency">
-                    楼{{ row.unitPrice }}
+                    璐у竵 {{ row.unitPrice }}
                   </span>
                   <span v-else-if="row.priceType === 'agreement'" class="price-agreement">
-                    {{ row.unitPrice }}
+                    鍗忚
                   </span>
                   <span v-else-if="row.priceType === 'free'" class="price-free">
                     鍏嶈垂
@@ -176,8 +176,8 @@
               <template #default="{ row }">
                 <div v-if="row.isSpacer" class="spacer-cell"></div>
                 <div v-else-if="!row.isMainOrder" class="period-info">
-                  <span>{{ row.period }}</span>
-                  <span v-if="row.isPermanent" class="permanent">姘镐箙</span>
+                  <span v-if="row.period === 0" class="permanent">姘镐箙</span>
+                  <span v-else>{{ row.period }}</span>
                 </div>
               </template>
             </el-table-column>
@@ -192,10 +192,35 @@
                   <div v-if="row.parentOrder && row.parentOrder.subOrders && row.parentOrder.subOrders.findIndex((sub: any) => sub.id === row.id) === 0" class="all-actions">
                     <div class="action-item">
                       <div class="action-buttons">
-                        <el-button v-if="row.parentOrder.canApprove" type="primary" link size="small" @click="toApprove(row.parentOrder)">瀹℃壒</el-button>
-                        <el-button v-if="row.parentOrder.canCheck" type="primary" link size="small" @click="toCheckFiles(row.parentOrder)">鏍告煡鏂囦欢</el-button>
-                        <el-button type="primary" link size="small" @click="toDetail(row.parentOrder)">鏌ョ湅</el-button>
-                        <el-button type="primary" link size="small" @click="toTrack(row.parentOrder)">杩借釜</el-button>
+                        <template v-for="action in getAvailableActions(row.parentOrder)" :key="action.type">
+                          <el-button 
+                            v-if="action.type === ActionType.AUTHORIZE"
+                            type="primary" 
+                            link 
+                            size="small" 
+                            @click="handleAction(action, row.parentOrder)"
+                          >
+                            鎺堟潈
+                          </el-button>
+                          <el-button 
+                            v-else-if="action.type === ActionType.VIEW"
+                            type="primary" 
+                            link 
+                            size="small" 
+                            @click="handleAction(action, row.parentOrder)"
+                          >
+                            鏌ョ湅
+                          </el-button>
+                          <el-button 
+                            v-else-if="action.type === ActionType.TRACK"
+                            type="primary" 
+                            link 
+                            size="small" 
+                            @click="handleAction(action, row.parentOrder)"
+                          >
+                            杩借釜
+                          </el-button>
+                        </template>
                       </div>
                     </div>
                   </div>
@@ -219,6 +244,12 @@
         />
       </div>
     </el-card>
+    
+    <!-- 璁㈠崟鐘舵�佸璇濇 -->
+    <ProductOrderStatusDialog 
+      v-model="orderStatusDialogVisible" 
+      :order-id="currentOrderId" 
+    />
   </div>
 </template>
 
@@ -227,18 +258,23 @@
 import { useRouter } from 'vue-router'
 import { Search, Refresh } from '@element-plus/icons-vue'
 import { fetchApprovalPage } from '@/api/approvalManage'
+import orderApi from '@/api/orderApi'
+import { authorizeApproval, fetchApprovalByOrderId } from '@/api/approvalManage'
+import { useUserInfo } from '@/stores/modules/userInfo'
+import ProductOrderStatusDialog from '@/views/productManage/productOrderStatusDialog/index.vue'
+import { OrderWorkflowController, OrderStatus, ActionType, PageType, StatusMapper } from '@/utils/orderWorkflow'
 
 const router = useRouter()
+const userStore = useUserInfo()
 
-// 鐘舵�侀�夐」
+// 鐘舵�侀�夐」锛堟洿鏂颁负鏂扮殑宸ヤ綔娴佺▼鐘舵�侊級
 const statusOptions = [
   { label: '鍏ㄩ儴', value: '' },
-  { label: '寰呭鏍�', value: 'WAIT_APPROVAL' },
   { label: '寰呬笂浼犳枃浠�', value: 'WAIT_UPLOAD' },
-  { label: '寰呮牳鏌ユ枃浠�', value: 'WAIT_CHECK' },
+  { label: '寰呮巿鏉�', value: 'WAIT_AUTHORIZE' },
   { label: '寰呬氦鏄撶‘璁�', value: 'WAIT_CONFIRM' },
-  { label: '宸查┏鍥�', value: 'REJECTED' },
-  { label: '宸插畬鎴�', value: 'FINISH' },
+  { label: '宸插畬鎴�', value: 'COMPLETED' },
+  { label: '宸茶瘎浠�', value: 'EVALUATED' },
 ]
 
 // 琛屼笟棰嗗煙閫夐」
@@ -289,209 +325,50 @@
 // 璁㈠崟鍒楄〃鏁版嵁锛堝寘鍚富璁㈠崟鍜屽瓙璁㈠崟锛�
 const orderList = ref<any[]>([])
 
-// 妯℃嫙鏁版嵁鐢ㄤ簬灞曠ず
-const mockData = [
-  {
-    id: '1',
-    isMainOrder: true,
-    applyTime: '2025-05-21 10:00:00',
-    orderNo: '4348442557619205545',
-    demandSide: '涓氦鏂硅繙寤鸿鏈夐檺鍏徃',
-    supplySide: '涓氦鏂硅繙绉戞妧鏈夐檺鍏徃',
-    status: 'WAIT_APPROVAL',
-    statusName: '寰呭鏍�',
-    canApprove: true,
-    canCheck: false,
-    subOrders: [
-      {
-        id: '1-1',
-        isMainOrder: false,
-        productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-        suiteName: '浼佷笟绉佹湁SaaS鐗堣鍙�',
-        salesForm: '涔版柇',
-        accountCount: 50,
-        customerObject: '浼佷笟',
-        concurrentCount: 50,
-        priceType: 'points',
-        unitPrice: '50,000',
-        quantity: 1,
-        period: 1,
-        isPermanent: true,
-      },
-      {
-        id: '1-2',
-        isMainOrder: false,
-        productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-        suiteName: '浼佷笟绉佹湁SaaS鐗圤TA鍗囩骇鏈嶅姟',
-        salesForm: 'OTA鏈嶅姟',
-        accountCount: 50,
-        customerObject: '浼佷笟',
-        concurrentCount: 50,
-        priceType: 'currency',
-        unitPrice: '7,500',
-        quantity: 1,
-        period: 1,
-        isPermanent: false,
-      },
-      {
-        id: '1-3',
-        isMainOrder: false,
-        productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-        suiteName: '浼佷笟绉佹湁SaaS鐗堢敤鎴峰閲忓寘',
-        salesForm: '绉佹湁澧為噺鍖�',
-        accountCount: 100,
-        customerObject: '浼佷笟',
-        concurrentCount: 100,
-        priceType: 'agreement',
-        unitPrice: '鍗忚浠�',
-        quantity: 1,
-        period: 1,
-        isPermanent: false,
-      },
-      {
-        id: '1-4',
-        isMainOrder: false,
-        productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-        suiteName: '涓汉鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉佹湁澧為噺鍖�',
-        accountCount: 50,
-        customerObject: '涓汉',
-        concurrentCount: 50,
-        priceType: 'free',
-        unitPrice: '0',
-        quantity: 1,
-        period: 3,
-        isPermanent: true,
-      },
-    ],
-  },
-  {
-    id: '2',
-    isMainOrder: true,
-    applyTime: '2025-05-20 10:00:00',
-    orderNo: '4347442557619205545',
-    demandSide: '鍗庝负鎶�鏈湁闄愬叕鍙�',
-    supplySide: '鍗庝负杞欢鎶�鏈湁闄愬叕鍙�',
-    status: 'WAIT_UPLOAD',
-    statusName: '寰呬笂浼犳枃浠�',
-    canApprove: false,
-    canCheck: false,
-    subOrders: [
-      {
-        id: '2-1',
-        isMainOrder: false,
-        productName: '鍩轰簬鍥戒骇鑺墖瀹界獎铻嶅悎鑷粍缃戣澶囩殑搴旂敤',
-        suiteName: '浼佷笟鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉熻祦',
-        accountCount: 100,
-        customerObject: '浼佷笟',
-        concurrentCount: 100,
-        priceType: 'currency',
-        unitPrice: '80,000',
-        quantity: 1,
-        period: 1,
-        isPermanent: false,
-      },
-    ],
-  },
-  {
-    id: '3',
-    isMainOrder: true,
-    applyTime: '2025-05-19 10:00:00',
-    orderNo: '4347342557619205545',
-    demandSide: '涓氦绗洓鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-    supplySide: '涓氦绗洓鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-    status: 'WAIT_CHECK',
-    statusName: '寰呮牳鏌ユ枃浠�',
-    canApprove: true,
-    canCheck: true,
-    subOrders: [
-      {
-        id: '3-1',
-        isMainOrder: false,
-        productName: '楂樻々鐮佸ご杈呭姪鍑哄浘宸ュ叿绠�',
-        suiteName: '椤圭洰鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉熻祦',
-        accountCount: 50,
-        customerObject: '椤圭洰閮�',
-        concurrentCount: 50,
-        priceType: 'currency',
-        unitPrice: '60,000',
-        quantity: 1,
-        period: 1,
-        isPermanent: false,
-      },
-    ],
-  },
-  {
-    id: '4',
-    isMainOrder: true,
-    applyTime: '2025-05-18 10:00:00',
-    orderNo: '4347442557619205545',
-    demandSide: '涓浗浜ら�氬缓璁捐偂浠芥湁闄愬叕鍙�',
-    supplySide: '涓氦鍏矾瑙勫垝璁捐闄㈡湁闄愬叕鍙�',
-    status: 'WAIT_CONFIRM',
-    statusName: '寰呬氦鏄撶‘璁�',
-    canApprove: false,
-    canCheck: false,
-    subOrders: [
-      {
-        id: '4-1',
-        isMainOrder: false,
-        productName: '鍏矾鏁板瓧鍖栨柟妗堣璁$郴缁�',
-        suiteName: '浼佷笟鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉熻祦',
-        accountCount: 100,
-        customerObject: '浼佷笟',
-        concurrentCount: 100,
-        priceType: 'currency',
-        unitPrice: '80,000',
-        quantity: 1,
-        period: 1,
-        isPermanent: false,
-      },
-    ],
-  },
-  {
-    id: '5',
-    isMainOrder: true,
-    applyTime: '2025-05-17 10:00:00',
-    orderNo: '4347342557619205545',
-    demandSide: '涓氦绗笁鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-    supplySide: '涓氦绗笁鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-    status: 'REJECTED',
-    statusName: '宸查┏鍥�',
-    canApprove: false,
-    canCheck: false,
-    subOrders: [
-      {
-        id: '5-1',
-        isMainOrder: false,
-        productName: '鍩轰簬鏃犱汉鏈虹殑浼佷笟绾у彲瑙嗗寲椤圭洰绠$悊绯荤粺',
-        suiteName: '椤圭洰鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉熻祦',
-        accountCount: 50,
-        customerObject: '椤圭洰閮�',
-        concurrentCount: 50,
-        priceType: 'free',
-        unitPrice: '0',
-        quantity: 1,
-        period: 1,
-        isPermanent: true,
-      },
-    ],
-  },
-]
+// 璁㈠崟鐘舵�佸璇濇鐩稿叧
+const orderStatusDialogVisible = ref(false)
+const currentOrderId = ref<string>('')
+
+// 浣跨敤宸ヤ綔娴佺▼鎺у埗鍣ㄧ殑鐘舵�佹槧灏�
+const statusUiToServer: Record<string, string> = {
+  WAIT_UPLOAD: OrderStatus.WAIT_UPLOAD,
+  WAIT_AUTHORIZE: OrderStatus.WAIT_AUTHORIZE,
+  WAIT_CONFIRM: OrderStatus.WAIT_CONFIRM,
+  COMPLETED: OrderStatus.COMPLETED,
+  EVALUATED: OrderStatus.EVALUATED,
+}
+
+const statusServerToUi: Record<string, string> = {
+  [OrderStatus.WAIT_UPLOAD]: 'WAIT_UPLOAD',
+  [OrderStatus.WAIT_AUTHORIZE]: 'WAIT_AUTHORIZE',
+  [OrderStatus.WAIT_CONFIRM]: 'WAIT_CONFIRM',
+  [OrderStatus.COMPLETED]: 'COMPLETED',
+  [OrderStatus.EVALUATED]: 'EVALUATED',
+}
+
+const formatDateTime = (val?: string) => {
+  if (!val) return ''
+  // 鍚庣 LocalDateTime 鍙兘鏄� 2025-05-21T10:00:00
+  return val.replace('T', ' ').slice(0, 19)
+}
+
+const normalizePriceType = (val?: string): 'points' | 'currency' | 'agreement' | 'free' => {
+  if (!val) return 'currency'
+  const s = String(val)
+  if (/(绉垎|points)/i.test(s)) return 'points'
+  if (/(鍗忚|agreement)/i.test(s)) return 'agreement'
+  if (/(鍏嶈垂|free)/i.test(s)) return 'free'
+  return 'currency'
+}
 
 // 鑾峰彇鐘舵�佺被鍨�
 const getStatusType = (status: string) => {
   const statusMap: Record<string, 'warning' | 'danger' | 'success' | 'info'> = {
-    WAIT_APPROVAL: 'warning',
     WAIT_UPLOAD: 'warning',
-    WAIT_CHECK: 'warning',
+    WAIT_AUTHORIZE: 'warning',
     WAIT_CONFIRM: 'warning',
-    REJECTED: 'danger',
-    FINISH: 'success',
+    COMPLETED: 'success',
+    EVALUATED: 'success',
   }
   return statusMap[status] || 'info'
 }
@@ -575,26 +452,79 @@
   }
 }
 
-// 鎼滅储澶勭悊
+// 鎼滅储澶勭悊锛堟帴鍏ョ湡瀹炲悗绔級
 const handleSearch = async () => {
-  // 妯℃嫙API璋冪敤锛屽疄闄呴」鐩腑杩欓噷浼氳皟鐢ㄧ湡瀹炵殑API
-  // const { data } = (await fetchApprovalPage({ ...query, pageNo: page.current, pageSize: page.size })) as any
-  
-  // 浣跨敤妯℃嫙鏁版嵁
-  const flatData: any[] = []
-  mockData.forEach(order => {
-    flatData.push(order)
-    if (order.subOrders) {
-      order.subOrders.forEach((subOrder: any) => {
-        flatData.push({ ...subOrder, parentOrder: order })
-      })
-    }
-    // 鍦ㄦ瘡涓鍗曞潡鐨勬湯灏炬彃鍏ヤ竴涓垎闅旂┖琛�
-    flatData.push({ isSpacer: true, isMainOrder: false, parentOrder: order })
+  const payload: any = {
+    pageNum: page.current,
+    pageSize: page.size,
+    productName: query.productName || undefined,
+    orderId: query.orderNo || undefined,
+  }
+  if (query.status) payload.orderStatus = statusUiToServer[query.status]
+  if (Array.isArray(query.dateRange) && query.dateRange.length === 2) {
+    payload.applyTimeStart = query.dateRange[0]
+    payload.applyTimeEnd = query.dateRange[1]
+  }
+
+  const res = (await fetchApprovalPage(payload)) as any
+  const pageData = res?.data
+  const list: any[] = Array.isArray(pageData?.list) ? pageData.list : []
+  page.total = Number(pageData?.total || 0)
+
+  // 骞跺彂鑾峰彇姣忎釜璁㈠崟鐨勮鎯咃紙鐢ㄤ簬鏋勯�犲瓙璁㈠崟琛岋級
+  const detailsArr = await Promise.all(
+    list.map(async (order: any) => {
+      try {
+        const detailRes = (await orderApi.getOrderDetail(order.orderId)) as any
+        return detailRes?.data
+      } catch (e) {
+        return null
+      }
+    })
+  )
+
+      const flatData: any[] = []
+    list.forEach((order: any, idx: number) => {
+      const uiStatus = statusServerToUi[order.orderStatus] || 'WAIT_UPLOAD'
+      const mainRow: any = {
+        id: order.orderId,
+        isMainOrder: true,
+        applyTime: formatDateTime(order.applyTime || ''),
+        orderNo: order.orderId,
+        demandSide: '',
+        supplySide: order.providerName || '',
+        status: uiStatus,
+        statusName: order.orderStatus || '',
+        orderStatus: StatusMapper.toUIStatus(order.orderStatus), // 杞崲涓烘爣鍑嗙姸鎬佹灇涓�
+      }
+
+    const detail = detailsArr[idx]
+    const subOrders: any[] = Array.isArray(detail?.orderDetails)
+      ? detail.orderDetails.map((d: any, i: number) => ({
+          id: `${order.orderId}-${i + 1}`,
+          isMainOrder: false,
+          productName: order.productName || '',
+          suiteName: d.suiteName,
+          salesForm: d.salesForm,
+          accountCount: d.accountLimit,
+          customerObject: d.customerType,
+          concurrentCount: d.concurrentNodes,
+          priceType: normalizePriceType(d.priceType),
+          unitPrice: d.unitPrice,
+          quantity: d.quantity,
+          period: d.duration,
+        }))
+      : []
+
+    // 渚涘悎骞堕�昏緫浣跨敤
+    ;(mainRow as any).subOrders = subOrders
+
+    flatData.push(mainRow)
+    subOrders.forEach((sub) => flatData.push({ ...sub, parentOrder: mainRow }))
+    flatData.push({ isSpacer: true, isMainOrder: false, parentOrder: mainRow })
   })
-  
+
   orderList.value = flatData
-  page.total = mockData.length
 }
 
 // 閲嶇疆
@@ -617,7 +547,40 @@
 const toApprove = (row: any) => router.push({ name: 'tradeApproval', params: { id: row.id } })
 const toCheckFiles = (row: any) => router.push({ name: 'tradeCheckFiles', params: { id: row.id } })
 const toDetail = (row: any) => router.push({ name: 'tradeOrderDetail', params: { id: row.id } })
-const toTrack = (row: any) => router.push({ name: 'tradeTrack', params: { id: row.id } })
+
+// 杩借釜璁㈠崟 - 鏄剧ず璁㈠崟鐘舵�佸璇濇
+const showOrderTrack = (row: any) => {
+  currentOrderId.value = row.id
+  orderStatusDialogVisible.value = true
+}
+
+// 鑾峰彇鍙敤鎿嶄綔鍒楄〃
+const getAvailableActions = (order: any) => {
+  if (!order.orderStatus) return []
+  return OrderWorkflowController.getAvailableActions(PageType.TRADE_APPROVAL, order.orderStatus)
+}
+
+// 澶勭悊鎿嶄綔鐐瑰嚮
+const handleAction = (action: any, order: any) => {
+  switch (action.type) {
+    case ActionType.VIEW:
+      toDetail(order)
+      break
+    case ActionType.TRACK:
+      showOrderTrack(order)
+      break
+    case ActionType.AUTHORIZE:
+      toAuthorize(order)
+      break
+    default:
+      console.warn('鏈煡鐨勬搷浣滅被鍨�:', action.type)
+  }
+}
+
+// 鎺堟潈锛氳烦杞埌鎺堟潈椤甸潰
+const toAuthorize = (row: any) => {
+  router.push({ name: 'tradeAuthorization', params: { id: row.id } })
+}
 
 onMounted(handleSearch)
 </script>
diff --git a/src/views/tradeManage/buyer/index.vue b/src/views/tradeManage/buyer/index.vue
index 73ccae5..dc072b9 100644
--- a/src/views/tradeManage/buyer/index.vue
+++ b/src/views/tradeManage/buyer/index.vue
@@ -86,10 +86,6 @@
                       <span class="value">{{ row.orderNo }}</span>
                     </div>
                     <div class="order-item">
-                      <span class="label">闇�姹傛柟:</span>
-                      <span class="value">{{ row.demandSide }}</span>
-                    </div>
-                    <div class="order-item">
                       <span class="label">渚涘簲鏂�:</span>
                       <span class="value">{{ row.supplySide }}</span>
                     </div>
@@ -148,16 +144,16 @@
                 <div v-if="row.isSpacer" class="spacer-cell"></div>
                 <div v-else-if="!row.isMainOrder" class="price-info">
                   <span v-if="row.priceType === 'points'" class="price-points">
-                    {{ row.unitPrice }}
+                    绉垎 {{ row.unitPrice }}
                   </span>
                   <span v-else-if="row.priceType === 'currency'" class="price-currency">
-                    {{ row.unitPrice }}
+                    璐у竵 {{ row.unitPrice }}
                   </span>
                   <span v-else-if="row.priceType === 'agreement'" class="price-agreement">
-                    {{ row.unitPrice }}
+                    鍗忚
                   </span>
                   <span v-else-if="row.priceType === 'free'" class="price-free">
-                    {{ row.unitPrice }}
+                    鍏嶈垂
                   </span>
                 </div>
               </template>
@@ -176,8 +172,8 @@
               <template #default="{ row }">
                 <div v-if="row.isSpacer" class="spacer-cell"></div>
                 <div v-else-if="!row.isMainOrder" class="period-info">
-                  <span>{{ row.period }}</span>
-                  <span v-if="row.isPermanent" class="permanent">姘镐箙</span>
+                  <span v-if="row.period === 0" class="permanent">姘镐箙</span>
+                  <span v-else>{{ row.period }}</span>
                 </div>
               </template>
             </el-table-column>
@@ -192,30 +188,61 @@
                   <div v-if="row.parentOrder && row.parentOrder.subOrders && row.parentOrder.subOrders.findIndex((sub: any) => sub.id === row.id) === 0" class="all-actions">
                     <div class="action-item">
                       <div class="action-buttons">
-                        <span v-if="row.parentOrder.status === 'WAIT_REVIEW'" class="op-text warning">寰呭鏍�</span>
-                        <template v-else-if="row.parentOrder.status === 'WAIT_UPLOAD'">
-                          <el-button type="danger" link size="small">鍙栨秷浜ゆ槗</el-button>
-                          <el-button type="primary" link size="small" @click="toUpload(row.parentOrder)">涓婁紶鏂囦欢</el-button>
-                          <el-button type="primary" link size="small" @click="toTrack(row.parentOrder)">杩借釜</el-button>
-                        </template>
-                        <template v-else-if="row.parentOrder.status === 'WAIT_CHECK'">
-                          <span class="op-text warning">寰呮牳鏌ユ枃浠�</span>
-                          <el-button type="primary" link size="small" @click="toDetail(row.parentOrder)">鏌ョ湅</el-button>
-                          <el-button type="primary" link size="small" @click="toTrack(row.parentOrder)">杩借釜</el-button>
-                        </template>
-                        <template v-else-if="row.parentOrder.status === 'WAIT_CONFIRM'">
-                          <span class="op-text warning">寰呬氦鏄撶‘璁�</span>
-                          <el-button type="primary" link size="small" @click="toConfirm(row.parentOrder)">纭浜ゆ槗</el-button>
-                          <el-button type="primary" link size="small" @click="toTrack(row.parentOrder)">杩借釜</el-button>
-                        </template>
-                        <template v-else-if="row.parentOrder.status === 'WAIT_EVALUATE'">
-                          <span class="op-text warning">寰呰瘎浠�</span>
-                          <el-button type="primary" link size="small" @click="toEvaluate(row.parentOrder)">璇勪环</el-button>
-                          <el-button type="primary" link size="small" @click="toTrack(row.parentOrder)">杩借釜</el-button>
-                        </template>
-                        <template v-else>
-                          <el-button type="primary" link size="small" @click="toDetail(row.parentOrder)">鏌ョ湅</el-button>
-                          <el-button type="primary" link size="small" @click="toTrack(row.parentOrder)">杩借釜</el-button>
+                        <template v-for="action in getAvailableActions(row.parentOrder)" :key="action.type">
+                          <el-button 
+                            v-if="action.type === ActionType.VIEW"
+                            type="primary" 
+                            link 
+                            size="small" 
+                            @click="handleAction(action, row.parentOrder)"
+                          >
+                            鏌ョ湅
+                          </el-button>
+                          <el-button 
+                            v-else-if="action.type === ActionType.TRACK"
+                            type="primary" 
+                            link 
+                            size="small" 
+                            @click="handleAction(action, row.parentOrder)"
+                          >
+                            杩借釜
+                          </el-button>
+                          <el-button 
+                            v-else-if="action.type === ActionType.UPLOAD_FILE"
+                            type="primary" 
+                            link 
+                            size="small" 
+                            @click="handleAction(action, row.parentOrder)"
+                          >
+                            鎻愪氦鏂囦欢
+                          </el-button>
+                          <el-button 
+                            v-else-if="action.type === ActionType.CONFIRM_TRADE"
+                            type="primary" 
+                            link 
+                            size="small" 
+                            @click="handleAction(action, row.parentOrder)"
+                          >
+                            浜ゆ槗纭
+                          </el-button>
+                          <el-button 
+                            v-else-if="action.type === ActionType.EVALUATE"
+                            type="primary" 
+                            link 
+                            size="small" 
+                            @click="handleAction(action, row.parentOrder)"
+                          >
+                            璇勪环
+                          </el-button>
+                          <el-button 
+                            v-else-if="action.type === ActionType.CANCEL_ORDER"
+                            type="danger" 
+                            link 
+                            size="small" 
+                            @click="handleAction(action, row.parentOrder)"
+                          >
+                            鍙栨秷璁㈠崟
+                          </el-button>
                         </template>
                       </div>
                     </div>
@@ -240,6 +267,12 @@
         />
       </div>
     </el-card>
+    
+    <!-- 璁㈠崟鐘舵�佸璇濇 -->
+    <ProductOrderStatusDialog 
+      v-model="orderStatusDialogVisible" 
+      :order-id="currentOrderId" 
+    />
   </div>
 </template>
 
@@ -247,17 +280,23 @@
 import { onMounted, reactive, ref } from 'vue'
 import { useRouter } from 'vue-router'
 import { Search, Refresh } from '@element-plus/icons-vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import orderApi from '@/api/orderApi'
+import { useUserInfo } from '@/stores/modules/userInfo'
+import ProductOrderStatusDialog from '@/views/productManage/productOrderStatusDialog/index.vue'
+import { OrderWorkflowController, OrderStatus, ActionType, PageType, StatusMapper } from '@/utils/orderWorkflow'
 
 const router = useRouter()
+const userStore = useUserInfo()
 
-// 鐘舵�侀�夐」
+// 鐘舵�侀�夐」锛堟洿鏂颁负鏂扮殑宸ヤ綔娴佺▼鐘舵�侊級
 const statusOptions = [
   { label: '鍏ㄩ儴', value: '' },
-  { label: '寰呭鏍�', value: 'WAIT_REVIEW' },
   { label: '寰呬笂浼犳枃浠�', value: 'WAIT_UPLOAD' },
-  { label: '寰呮牳鏌ユ枃浠�', value: 'WAIT_CHECK' },
+  { label: '寰呮巿鏉�', value: 'WAIT_AUTHORIZE' },
   { label: '寰呬氦鏄撶‘璁�', value: 'WAIT_CONFIRM' },
-  { label: '寰呰瘎浠�', value: 'WAIT_EVALUATE' },
+  { label: '宸插畬鎴�', value: 'COMPLETED' },
+  { label: '宸茶瘎浠�', value: 'EVALUATED' },
 ]
 
 // 琛屼笟棰嗗煙閫夐」
@@ -303,203 +342,54 @@
 })
 
 // 鍒嗛〉淇℃伅
-const page = reactive({ current: 1, size: 10, total: 18 })
+const page = reactive({ current: 1, size: 10, total: 0 })
 
 // 璁㈠崟鍒楄〃鏁版嵁锛堝寘鍚富璁㈠崟鍜屽瓙璁㈠崟锛�
 const orderList = ref<any[]>([])
 
-// 妯℃嫙鏁版嵁鐢ㄤ簬灞曠ず
-const mockData = [
-  {
-    id: '1',
-    isMainOrder: true,
-    applyTime: '2025-05-21 10:00:00',
-    orderNo: '4348442557619205545',
-    demandSide: '涓氦鏂硅繙寤鸿鏈夐檺鍏徃',
-    supplySide: '涓氦鏂硅繙绉戞妧鏈夐檺鍏徃',
-    status: 'WAIT_REVIEW',
-    statusName: '寰呭鏍�',
-    subOrders: [
-      {
-        id: '1-1',
-        isMainOrder: false,
-        productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-        suiteName: '浼佷笟绉佹湁SaaS鐗堣鍙�',
-        salesForm: '涔版柇',
-        accountCount: 50,
-        customerObject: '浼佷笟',
-        concurrentCount: 50,
-        priceType: 'points',
-        unitPrice: '绉垎: 50,000/濂�',
-        quantity: 1,
-        period: 1,
-        isPermanent: true,
-      },
-      {
-        id: '1-2',
-        isMainOrder: false,
-        productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-        suiteName: '浼佷笟绉佹湁SaaS鐗圤TA鍗囩骇鏈嶅姟',
-        salesForm: 'OTA鏈嶅姟',
-        accountCount: 50,
-        customerObject: '浼佷笟',
-        concurrentCount: 50,
-        priceType: 'currency',
-        unitPrice: '璐у竵: 7,500/濂�/骞�',
-        quantity: 1,
-        period: 1,
-        isPermanent: false,
-      },
-      {
-        id: '1-3',
-        isMainOrder: false,
-        productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-        suiteName: '浼佷笟绉佹湁SaaS鐗堢敤鎴峰閲忓寘',
-        salesForm: '绉佹湁澧為噺鍖�',
-        accountCount: 100,
-        customerObject: '浼佷笟',
-        concurrentCount: 100,
-        priceType: 'agreement',
-        unitPrice: '鍗忚:/骞�',
-        quantity: 1,
-        period: 1,
-        isPermanent: false,
-      },
-      {
-        id: '1-4',
-        isMainOrder: false,
-        productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-        suiteName: '涓汉鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉佹湁澧為噺鍖�',
-        accountCount: 50,
-        customerObject: '涓汉',
-        concurrentCount: 50,
-        priceType: 'free',
-        unitPrice: '鍏嶈垂:/骞�',
-        quantity: 3,
-        period: 1,
-        isPermanent: true,
-      },
-    ],
-  },
-  {
-    id: '2',
-    isMainOrder: true,
-    applyTime: '2025-05-20 10:00:00',
-    orderNo: '4347442557619205545',
-    demandSide: '鍗庝负鎶�鏈湁闄愬叕鍙�',
-    supplySide: '鍗庝负杞欢鎶�鏈湁闄愬叕鍙�',
-    status: 'WAIT_UPLOAD',
-    statusName: '寰呬笂浼犳枃浠�',
-    subOrders: [
-      {
-        id: '2-1',
-        isMainOrder: false,
-        productName: '鍩轰簬鍥戒骇鑺墖瀹界獎铻嶅悎鑷粍缃戣澶囩殑搴旂敤',
-        suiteName: '浼佷笟鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉熻祦',
-        accountCount: 100,
-        customerObject: '浼佷笟',
-        concurrentCount: 100,
-        priceType: 'currency',
-        unitPrice: '璐у竵: 80,000/骞�',
-        quantity: 1,
-        period: 2,
-        isPermanent: false,
-      },
-    ],
-  },
-  {
-    id: '3',
-    isMainOrder: true,
-    applyTime: '2025-05-19 10:00:00',
-    orderNo: '4347342557619205545',
-    demandSide: '涓氦绗洓鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-    supplySide: '涓氦绗洓鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-    status: 'WAIT_CHECK',
-    statusName: '寰呮牳鏌ユ枃浠�',
-    subOrders: [
-      {
-        id: '3-1',
-        isMainOrder: false,
-        productName: '楂樻々鐮佸ご杈呭姪鍑哄浘宸ュ叿绠�',
-        suiteName: '椤圭洰鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉熻祦',
-        accountCount: 50,
-        customerObject: '椤圭洰閮�',
-        concurrentCount: 50,
-        priceType: 'currency',
-        unitPrice: '璐у竵: 60,000/骞�',
-        quantity: 1,
-        period: 3,
-        isPermanent: false,
-      },
-    ],
-  },
-  {
-    id: '4',
-    isMainOrder: true,
-    applyTime: '2025-05-18 10:00:00',
-    orderNo: '4347442557619205545',
-    demandSide: '涓浗浜ら�氬缓璁捐偂浠芥湁闄愬叕鍙�',
-    supplySide: '涓氦鍏矾瑙勫垝璁捐闄㈡湁闄愬叕鍙�',
-    status: 'WAIT_CONFIRM',
-    statusName: '寰呬氦鏄撶‘璁�',
-    subOrders: [
-      {
-        id: '4-1',
-        isMainOrder: false,
-        productName: '鍏矾鏁板瓧鍖栨柟妗堣璁$郴缁�',
-        suiteName: '浼佷笟鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉熻祦',
-        accountCount: 100,
-        customerObject: '浼佷笟',
-        concurrentCount: 100,
-        priceType: 'currency',
-        unitPrice: '璐у竵: 80,000/骞�',
-        quantity: 1,
-        period: 1,
-        isPermanent: false,
-      },
-    ],
-  },
-  {
-    id: '5',
-    isMainOrder: true,
-    applyTime: '2025-05-17 10:00:00',
-    orderNo: '4347342557619205545',
-    demandSide: '涓氦绗笁鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-    supplySide: '涓氦绗笁鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-    status: 'WAIT_EVALUATE',
-    statusName: '寰呰瘎浠�',
-    subOrders: [
-      {
-        id: '5-1',
-        isMainOrder: false,
-        productName: '鍩轰簬鏃犱汉鏈虹殑浼佷笟绾у彲瑙嗗寲椤圭洰绠$悊绯荤粺',
-        suiteName: '椤圭洰鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉熻祦',
-        accountCount: 50,
-        customerObject: '椤圭洰閮�',
-        concurrentCount: 50,
-        priceType: 'free',
-        unitPrice: '鍏嶈垂:/骞�',
-        quantity: 1,
-        period: 1,
-        isPermanent: true,
-      },
-    ],
-  },
-]
+// 璁㈠崟鐘舵�佸璇濇鐩稿叧
+const orderStatusDialogVisible = ref(false)
+const currentOrderId = ref<string>('')
+
+// 浣跨敤宸ヤ綔娴佺▼鎺у埗鍣ㄧ殑鐘舵�佹槧灏�
+const statusUiToServer: Record<string, string> = {
+  WAIT_UPLOAD: OrderStatus.WAIT_UPLOAD,
+  WAIT_AUTHORIZE: OrderStatus.WAIT_AUTHORIZE,
+  WAIT_CONFIRM: OrderStatus.WAIT_CONFIRM,
+  COMPLETED: OrderStatus.COMPLETED,
+  EVALUATED: OrderStatus.EVALUATED,
+}
+
+const statusServerToUi: Record<string, string> = {
+  [OrderStatus.WAIT_UPLOAD]: 'WAIT_UPLOAD',
+  [OrderStatus.WAIT_AUTHORIZE]: 'WAIT_AUTHORIZE',
+  [OrderStatus.WAIT_CONFIRM]: 'WAIT_CONFIRM',
+  [OrderStatus.COMPLETED]: 'COMPLETED',
+  [OrderStatus.EVALUATED]: 'EVALUATED',
+}
+
+const formatDateTime = (val?: string) => {
+  if (!val) return ''
+  return val.replace('T', ' ').slice(0, 19)
+}
+
+const normalizePriceType = (val?: string): 'points' | 'currency' | 'agreement' | 'free' => {
+  if (!val) return 'currency'
+  const s = String(val)
+  if (/(绉垎|points)/i.test(s)) return 'points'
+  if (/(鍗忚|agreement)/i.test(s)) return 'agreement'
+  if (/(鍏嶈垂|free)/i.test(s)) return 'free'
+  return 'currency'
+}
 
 // 鑾峰彇鐘舵�佺被鍨�
 const getStatusType = (status: string) => {
   const statusMap: Record<string, 'warning' | 'danger' | 'success' | 'info'> = {
-    WAIT_REVIEW: 'warning',
     WAIT_UPLOAD: 'warning',
-    WAIT_CHECK: 'warning',
+    WAIT_AUTHORIZE: 'warning',
     WAIT_CONFIRM: 'warning',
-    WAIT_EVALUATE: 'warning',
+    COMPLETED: 'success',
+    EVALUATED: 'success',
   }
   return statusMap[status] || 'info'
 }
@@ -583,26 +473,79 @@
   }
 }
 
-// 鎼滅储澶勭悊
+// 鎼滅储澶勭悊锛堟帴鍏ョ湡瀹炲悗绔級
 const handleSearch = async () => {
-  // 妯℃嫙API璋冪敤锛屽疄闄呴」鐩腑杩欓噷浼氳皟鐢ㄧ湡瀹炵殑API
-  // const { data } = (await fetchOrderPage({ ...query, pageNo: page.current, pageSize: page.size })) as any
-  
-  // 浣跨敤妯℃嫙鏁版嵁
+  const payload: any = {
+    pageNum: page.current,
+    pageSize: page.size,
+    productName: query.productName || undefined,
+    orderId: query.orderNo || undefined,
+    userId: userStore.getUserId ? Number(userStore.getUserId) : undefined,
+  }
+  if (query.status) payload.orderStatus = statusUiToServer[query.status]
+  if (Array.isArray(query.dateRange) && query.dateRange.length === 2) {
+    payload.applyTimeStart = query.dateRange[0]
+    payload.applyTimeEnd = query.dateRange[1]
+  }
+
+  const res = (await orderApi.getBuyerOrderPage(payload)) as any
+  const pageData = res?.data
+  const list: any[] = Array.isArray(pageData?.list) ? pageData.list : []
+  page.total = Number(pageData?.total || 0)
+
+  // 骞跺彂鑾峰彇姣忎釜璁㈠崟鐨勮鎯咃紙鐢ㄤ簬鏋勯�犲瓙璁㈠崟琛岋級
+  const detailsArr = await Promise.all(
+    list.map(async (order: any) => {
+      try {
+        const detailRes = (await orderApi.getOrderDetail(order.orderId)) as any
+        return detailRes?.data
+      } catch (e) {
+        return null
+      }
+    })
+  )
+
   const flatData: any[] = []
-  mockData.forEach(order => {
-    flatData.push(order)
-    if (order.subOrders) {
-      order.subOrders.forEach((subOrder: any) => {
-        flatData.push({ ...subOrder, parentOrder: order })
-      })
+  list.forEach((order: any, idx: number) => {
+    const uiStatus = statusServerToUi[order.orderStatus] || 'WAIT_UPLOAD'
+    const mainRow: any = {
+      id: order.orderId,
+      isMainOrder: true,
+      applyTime: formatDateTime(order.applyTime || ''),
+      orderNo: order.orderId,
+      demandSide: '',
+      supplySide: order.providerName || '',
+      status: uiStatus,
+      statusName: order.orderStatus || '',
+      orderStatus: StatusMapper.toUIStatus(order.orderStatus), // 杞崲涓烘爣鍑嗙姸鎬佹灇涓�
     }
-    // 鍦ㄦ瘡涓鍗曞潡鐨勬湯灏炬彃鍏ヤ竴涓垎闅旂┖琛�
-    flatData.push({ isSpacer: true, isMainOrder: false, parentOrder: order })
+
+    const detail = detailsArr[idx]
+    const subOrders: any[] = Array.isArray(detail?.orderDetails)
+      ? detail.orderDetails.map((d: any, i: number) => ({
+          id: `${order.orderId}-${i + 1}`,
+          isMainOrder: false,
+          productName: order.productName || '',
+          suiteName: d.suiteName,
+          salesForm: d.salesForm,
+          accountCount: d.accountLimit,
+          customerObject: d.customerType,
+          concurrentCount: d.concurrentNodes,
+          priceType: normalizePriceType(d.priceType),
+          unitPrice: d.unitPrice,
+          quantity: d.quantity,
+          period: d.duration,
+        }))
+      : []
+
+    ;(mainRow as any).subOrders = subOrders
+
+    flatData.push(mainRow)
+    subOrders.forEach((sub) => flatData.push({ ...sub, parentOrder: mainRow }))
+    flatData.push({ isSpacer: true, isMainOrder: false, parentOrder: mainRow })
   })
-  
+
   orderList.value = flatData
-  page.total = 18
 }
 
 // 閲嶇疆
@@ -628,6 +571,70 @@
 const toEvaluate = (row: any) => router.push({ name: 'tradeOrderEvaluate', params: { id: row.id } })
 const toTrack = (row: any) => router.push({ name: 'tradeTrack', params: { id: row.id } })
 
+// 杩借釜璁㈠崟 - 鏄剧ず璁㈠崟鐘舵�佸璇濇
+const showOrderTrack = (row: any) => {
+  currentOrderId.value = row.id
+  orderStatusDialogVisible.value = true
+}
+
+// 鑾峰彇鍙敤鎿嶄綔鍒楄〃
+const getAvailableActions = (order: any) => {
+  if (!order.orderStatus) return []
+  return OrderWorkflowController.getAvailableActions(PageType.BUYER_CENTER, order.orderStatus)
+}
+
+// 澶勭悊鎿嶄綔鐐瑰嚮
+const handleAction = (action: any, order: any) => {
+  switch (action.type) {
+    case ActionType.VIEW:
+      toDetail(order)
+      break
+    case ActionType.TRACK:
+      showOrderTrack(order)
+      break
+    case ActionType.UPLOAD_FILE:
+      toUpload(order)
+      break
+    case ActionType.CONFIRM_TRADE:
+      toConfirm(order)
+      break
+    case ActionType.EVALUATE:
+      toEvaluate(order)
+      break
+    case ActionType.CANCEL_ORDER:
+      cancelOrder(order)
+      break
+    default:
+      console.warn('鏈煡鐨勬搷浣滅被鍨�:', action.type)
+  }
+}
+
+// 鍙栨秷璁㈠崟
+const cancelOrder = async (order: any) => {
+  try {
+    await ElMessageBox.confirm('纭畾瑕佸彇娑堣繖涓鍗曞悧锛熸鎿嶄綔灏嗗垹闄よ鍗曠殑鎵�鏈夌浉鍏充俊鎭紝鍖呮嫭璁㈠崟璇︽儏鍜岄檮浠舵枃浠讹紝涓斾笉鍙仮澶嶃��', '纭鍙栨秷璁㈠崟', {
+      confirmButtonText: '纭畾鍙栨秷',
+      cancelButtonText: '鍙栨秷',
+      type: 'warning',
+      confirmButtonClass: 'el-button--danger'
+    })
+    
+    const res = await orderApi.cancelOrder(order.id)
+    
+    if (res && res.code === 200) {
+      ElMessage.success('璁㈠崟鍙栨秷鎴愬姛')
+      handleSearch() // 鍒锋柊鍒楄〃
+    } else {
+      ElMessage.error(res?.msg || '鍙栨秷璁㈠崟澶辫触')
+    }
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('鍙栨秷璁㈠崟澶辫触:', error)
+      ElMessage.error('鍙栨秷璁㈠崟澶辫触锛岃閲嶈瘯')
+    }
+  }
+}
+
 onMounted(handleSearch)
 </script>
 
diff --git a/src/views/tradeManage/confirm/index.vue b/src/views/tradeManage/confirm/index.vue
index cec4efa..9c4a6d7 100644
--- a/src/views/tradeManage/confirm/index.vue
+++ b/src/views/tradeManage/confirm/index.vue
@@ -170,16 +170,29 @@
                {{ formatFileSize(row.size) }}
              </template>
            </el-table-column>
-           <el-table-column label="鎿嶄綔" width="100">
+           <el-table-column label="鎿嶄綔" width="180">
              <template #default="{ row }">
-               <el-button
-                 type="text"
-                 size="small"
-                 class="preview-btn"
-                 @click="handlePreview(row)"
-               >
-                 棰勮
-               </el-button>
+               <div class="file-actions">
+                 <el-button
+                   type="text"
+                   size="small"
+                   class="preview-btn"
+                   @click="handlePreview(row)"
+                   v-if="isPreviewable(row)"
+                   :disabled="!isFileUploaded(row)"
+                 >
+                   棰勮
+                 </el-button>
+                 <el-button
+                   type="text"
+                   size="small"
+                   class="download-btn"
+                   @click="handleDownload(row)"
+                   :disabled="!isFileUploaded(row)"
+                 >
+                   涓嬭浇
+                 </el-button>
+               </div>
              </template>
            </el-table-column>
          </el-table>
@@ -191,49 +204,24 @@
       <div class="title">浜ゆ槗淇℃伅澶囨敞</div>
       <el-table :data="form.items" border class="mt10 remark-table">
         <el-table-column label="璇︽儏" prop="name" min-width="200" />
-        <el-table-column label="鎺堟潈寮�濮嬫椂闂�" width="200">
-          <template #default="{ row, $index }">
-            <el-date-picker 
-              v-model="form.items[$index].start" 
-              type="date" 
-              value-format="YYYY-MM-DD" 
-              placeholder="閫夋嫨鏃ユ湡"
-              size="small"
-              style="width: 100%"
-            />
-          </template>
-        </el-table-column>
-        <el-table-column label="鎺堟潈缁撴潫鏃堕棿" width="200">
-          <template #default="{ row, $index }">
-            <div class="end-time-wrapper">
-              <el-date-picker 
-                v-model="form.items[$index].end" 
-                type="date" 
-                value-format="YYYY-MM-DD" 
-                placeholder="閫夋嫨鏃ユ湡"
-                size="small"
-                style="width: 100%"
-                :disabled="form.items[$index].forever"
-              />
-              <el-checkbox 
-                v-model="form.items[$index].forever" 
-                class="forever-checkbox"
-                @change="handleForeverChange($index)"
-              >
-                姘镐箙
-              </el-checkbox>
-            </div>
-          </template>
-        </el-table-column>
-        <el-table-column label="澶囨敞" min-width="300">
-          <template #default="{ row, $index }">
-            <el-input 
-              v-model="form.items[$index].remark" 
-              placeholder="璇疯緭鍏ュ娉�"
-              size="small"
-            />
-          </template>
-        </el-table-column>
+                 <el-table-column label="鎺堟潈寮�濮嬫椂闂�" width="200">
+           <template #default="{ row, $index }">
+             <span>{{ form.items[$index].start || '-' }}</span>
+           </template>
+         </el-table-column>
+         <el-table-column label="鎺堟潈缁撴潫鏃堕棿" width="200">
+           <template #default="{ row, $index }">
+             <div class="end-time-wrapper">
+               <span v-if="form.items[$index].forever" class="forever-text">姘镐箙</span>
+               <span v-else>{{ form.items[$index].end || '-' }}</span>
+             </div>
+           </template>
+         </el-table-column>
+         <el-table-column label="澶囨敞" min-width="300">
+           <template #default="{ row, $index }">
+             <span>{{ form.items[$index].remark || '-' }}</span>
+           </template>
+         </el-table-column>
       </el-table>
       <div class="action-buttons">
         <el-button @click="goBack">杩斿洖</el-button>
@@ -247,11 +235,14 @@
 import { onMounted, reactive, ref, computed, type CSSProperties } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import { Document, User, Goods, List } from '@element-plus/icons-vue'
-import { fetchOrderDetail, confirmTrade } from '@/api/tradeManage'
-import { ElMessage } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import orderApi from '@/api/orderApi'
+import { useUserInfo } from '@/stores/modules/userInfo'
+import createAxios from '@/utils/axios'
 
 const route = useRoute()
 const router = useRouter()
+const userStore = useUserInfo()
 const detail = reactive<any>({ items: [] })
 const form = reactive<any>({ items: [] })
 const fileList = ref<any[]>([])
@@ -277,123 +268,155 @@
   return [...detail.items, summaryRow]
 })
 
-onMounted(async () => {
-  // 浣跨敤鍓嶇妯℃嫙鏁版嵁浠ヤ究寮�鍙� UI锛堜笉鏀瑰姩鍚庣鏈嶅姟锛�
-  const mockDetail = {
-    orderNo: '4348442557619205545',
-    resourceTypeName: '杞欢浜у搧',
-    status: 'WAIT_CONFIRM',
-    statusName: '寰呯‘璁�',
-    applyTime: '2025-05-21 10:00:00',
-    unitName: '涓氦鏂硅繙寤鸿鏈夐檺鍏徃',
-    userName: '寮犻潤',
-    userAccount: 'L20159922',
-    userDept: '淇℃伅涓績',
-    userPhone: '13800000000',
-    productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-    supplier: '涓氦鏂硅繙绉戞妧鏈夐檺鍏徃',
-    industry: '寤虹瓚宸ョ▼',
-    projectUnit: '鍦熷缓宸ョ▼',
-    productType: '杞欢搴�',
-    productDesc:
-      '闈㈠悜宸ョ▼椤圭洰鐨勮川閲忓疄娴嬪疄閲忔暟瀛楀寲绠$悊绯荤粺锛屾敮鎸佹爣鍑嗗寲閲囬泦銆佽嚜鍔ㄧ粺璁′笌杩囩▼绠℃帶銆�',
-    items: [
-      {
-        id: '1',
-        name: '浼佷笟绉佹湁SaaS鐗堣鍙�',
-        saleType: '涔版柇',
-        accountCount: 50,
-        customerTarget: '浼佷笟',
-        concurrentNodes: 50,
-        pricePoint: 50000,
-        priceCash: 0,
-        quantity: 1,
-        period: 0,
-      },
-      {
-        id: '2',
-        name: '浼佷笟绉佹湁SaaS鐗圤TA鍗囩骇鏈嶅姟',
-        saleType: 'OTA鏈嶅姟',
-        accountCount: 50,
-        customerTarget: '浼佷笟',
-        concurrentNodes: 50,
-        pricePoint: 0,
-        priceCash: 7500,
-        quantity: 1,
-        period: 1,
-      },
-      {
-        id: '3',
-        name: '浼佷笟绉佹湁SaaS鐗堢敤鎴峰閲忓寘',
-        saleType: '绉佹湁澧為噺鍖�',
-        accountCount: 100,
-        customerTarget: '浼佷笟',
-        concurrentNodes: 100,
-        pricePoint: 0,
-        priceCash: 0,
-        priceProtocol: true,
-        quantity: 1,
-        period: 1,
-      },
-      {
-        id: '4',
-        name: '涓汉鍏湁SaaS鐗堣鍙�',
-        saleType: '绉佹湁澧為噺鍖�',
-        accountCount: 50,
-        customerTarget: '涓汉',
-        concurrentNodes: 50,
-        pricePoint: 0,
-        priceCash: 0,
-        quantity: 1,
-        period: 0,
-      },
-    ],
-    pointTotal: '50,000',
-    cashTotal: '7,500',
-  }
+// 鐘舵�佹槧灏勶紙鍚庣涓枃 -> 鍓嶇鏋氫妇锛�
+const statusServerToUi: Record<string, string> = {
+  '寰呬笂浼犳枃浠�': 'WAIT_UPLOAD',
+  '寰呮巿鏉�': 'WAIT_AUTHORIZE',
+  '寰呬氦鏄撶‘璁�': 'WAIT_CONFIRM',
+  '宸插畬鎴�': 'COMPLETED',
+  '宸茶瘎浠�': 'EVALUATED',
+}
 
-  Object.assign(detail, mockDetail)
-  form.items = (detail.items || []).map((item: any, index: number) => ({ 
-    name: item.name,
-    start: '2025-06-01', 
-    end: index === 0 || index === 3 ? '' : '2025-06-01', 
-    forever: index === 0 || index === 3, 
-    remark: index === 3 ? '寮�閫氱鐞嗗憳璐﹀彿1涓�,璐﹀彿admin' : '寮�閫氱鐞嗗憳璐﹀彿1涓�,璐﹀彿admin,鐧诲綍绠$悊鍛樿处鍙峰彲绠$悊鏅�氱敤鎴�' 
-  }))
+const formatDateTime = (val?: string) => (val ? val.replace('T', ' ').slice(0, 19) : '')
+
+const normalizePriceType = (val?: string): 'points' | 'currency' | 'agreement' | 'free' => {
+  if (!val) return 'currency'
+  const s = String(val)
+  if (/(绉垎|points)/i.test(s)) return 'points'
+  if (/(鍗忚|agreement)/i.test(s)) return 'agreement'
+  if (/(鍏嶈垂|free)/i.test(s)) return 'free'
+  return 'currency'
+}
+
+onMounted(async () => {
+  const orderId = String(route.params.id || '')
+  if (!orderId) return
   
-  // 娣诲姞妯℃嫙鏂囦欢鏁版嵁鐢ㄤ簬灞曠ず
-  fileList.value = [
-    {
-      name: '绛惧瓧鐩栫珷鏂囦欢.pdf',
-      size: 2621440, // 2.5MB
-      uid: '1',
-      status: 'success'
-    },
-    {
-      name: 'API Keys.txt',
-      size: 354, // 354 Bytes
-      uid: '2',
-      status: 'success'
+  try {
+    const res = (await orderApi.getOrderDetail(orderId)) as any
+    const data = res?.data || {}
+
+    const statusName: string = data.orderStatus || ''
+    const uiStatus = statusServerToUi[statusName] || 'INFO'
+
+    // 鏄犲皠璁㈠崟璇︽儏澶撮儴淇℃伅
+    const head = {
+      orderNo: data.orderId,
+      resourceTypeName: '杞欢浜у搧',
+      status: uiStatus,
+      statusName,
+      applyTime: formatDateTime(data.applyTime),
+      unitName: data.unitName || '-',
+      userName: data.userName || '-',
+      userAccount: data.userAccount || '-',
+      userDept: data.userDept || '-',
+      userPhone: data.userPhone || '-',
+      productName: data.productName || '-',
+      supplier: data.providerName || '-',
+      industry: data.industry || '-',
+      projectUnit: data.projectUnit || '-',
+      productType: data.productType || '-',
+      productDesc: data.productDesc || '-',
     }
-  ]
-  
-  // 娉ㄩ噴鎺夊師鏈夌殑API璋冪敤锛屼娇鐢ㄦā鎷熸暟鎹�
-  // const { data } = (await fetchOrderDetail({ id: route.params.id })) as any
-  // Object.assign(detail, data || {})
-  // form.items = (detail.items || []).map(() => ({ start: '', end: '', forever: false, remark: '' }))
+
+    // 鏄庣粏椤规槧灏�
+    const items: any[] = Array.isArray(data.orderDetails)
+      ? data.orderDetails.map((d: any, idx: number) => {
+          const pt = normalizePriceType(d.priceType)
+          return {
+            id: String(d.id ?? idx + 1),
+            name: d.suiteName,
+            saleType: d.salesForm,
+            accountCount: d.accountLimit,
+            customerTarget: d.customerType,
+            concurrentNodes: d.concurrentNodes,
+            pricePoint: pt === 'points' ? Number(d.unitPrice || 0) : 0,
+            priceCash: pt === 'currency' ? Number(d.unitPrice || 0) : 0,
+            priceProtocol: pt === 'agreement',
+            quantity: Number(d.quantity || 0),
+            period: Number(d.duration || 0),
+            remarks: d.remarks || '', // 鏂板 remarks 瀛楁
+          }
+        })
+      : []
+
+    // 姹囨�伙紙绠�鍗曠浉鍔狅細鍗曚环*鏁伴噺锛�
+    const pointTotalNum = items.reduce((sum, it) => sum + Number(it.pricePoint || 0) * Number(it.quantity || 0), 0)
+    const cashTotalNum = items.reduce((sum, it) => sum + Number(it.priceCash || 0) * Number(it.quantity || 0), 0)
+
+    Object.assign(detail, head, {
+      items,
+      pointTotal: pointTotalNum.toLocaleString(),
+      cashTotal: cashTotalNum.toLocaleString(),
+    })
+
+    // 鍒濆鍖栬〃鍗曟暟鎹�
+    form.items = (detail.items || []).map((item: any, index: number) => {
+      // 璁$畻鎺堟潈缁撴潫鏃堕棿
+      let endDate = ''
+      if (item.period > 0) {
+        // 濡傛灉鏈夋湡闄愶紝璁$畻缁撴潫鏃堕棿
+        const startDate = new Date(data.applyTime || new Date())
+        const endDateObj = new Date(startDate)
+        endDateObj.setFullYear(endDateObj.getFullYear() + item.period)
+        endDate = endDateObj.toISOString().split('T')[0] // 鏍煎紡鍖栦负 YYYY-MM-DD
+      }
+      
+      return { 
+        name: item.name,
+        start: data.applyTime ? data.applyTime.split('T')[0] : '', // 浣跨敤璁㈠崟鐢宠鏃堕棿
+        end: endDate, 
+        forever: item.period === 0, // 鏈熼檺涓�0鏃惰缃负姘镐箙
+        remark: item.remarks || '' // 浣跨敤濂椾欢淇℃伅涓殑remarks瀛楁
+      }
+    })
+
+    // 鑾峰彇璁㈠崟闄勪欢鍒楄〃锛堝鏋滄湁鐨勮瘽锛�
+    if (data.attachments && Array.isArray(data.attachments)) {
+      fileList.value = data.attachments.map((file: any) => ({
+        name: file.fileName || file.originalName,
+        size: file.fileSize || 0,
+        uid: file.id,
+        status: 'success',
+        url: file.fileUrl,
+        uploaded: true
+      }))
+    } else {
+      fileList.value = []
+    }
+  } catch (error) {
+    console.error('鑾峰彇璁㈠崟璇︽儏澶辫触:', error)
+    ElMessage.error('鑾峰彇璁㈠崟璇︽儏澶辫触')
+  }
 })
 
 const goBack = () => router.back()
 const submit = async () => {
-  // 妯℃嫙鎻愪氦鎴愬姛鍝嶅簲
-  const mockResponse = { code: 200 }
-  
-  // 娉ㄩ噴鎺夊師鏈夌殑API璋冪敤锛屼娇鐢ㄦā鎷熸暟鎹�
-  // const { code } = (await confirmTrade({ id: route.params.id, ...form })) as any
-  
-  if (mockResponse.code === 200) {
-    ElMessage.success('鎻愪氦鎴愬姛')
-    router.back()
+  try {
+    const orderId = String(route.params.id || '')
+    const userId = userStore.getUserId ? Number(userStore.getUserId) : undefined
+    
+    if (!orderId || !userId) {
+      ElMessage.error('璁㈠崟ID鎴栫敤鎴稩D涓嶈兘涓虹┖')
+      return
+    }
+
+    // 纭鎿嶄綔
+    await ElMessageBox.confirm('纭畾瑕佺‘璁や氦鏄擄紵', '纭鎿嶄綔', {
+      confirmButtonText: '纭畾',
+      cancelButtonText: '鍙栨秷',
+      type: 'warning'
+    })
+
+    // 鏇存柊璁㈠崟鐘舵�佽繘鍏ヤ笅涓�涓姸鎬�
+    await orderApi.updateOrderStatusToNext(orderId)
+    ElMessage.success('浜ゆ槗纭鎴愬姛')
+    router.back()    
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('浜ゆ槗纭澶辫触:', error)
+      ElMessage.error('浜ゆ槗纭澶辫触')
+    }
   }
 }
 
@@ -480,17 +503,202 @@
   return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
 };
 
-// 鏂囦欢棰勮澶勭悊
-const handlePreview = (file: any) => {
-  ElMessage.info(`棰勮鏂囦欢锛�${file.name}`)
+// 鍒ゆ柇鏂囦欢鏄惁鍙瑙�
+const isPreviewable = (file: any) => {
+  // 棣栧厛妫�鏌IME绫诲瀷
+  const previewableTypes = [
+    'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/bmp', 'image/webp',
+    'text/plain', 'text/html', 'text/css', 'text/javascript',
+    'application/pdf',
+    'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
+    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
+    'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
+  ]
+  
+  // 濡傛灉MIME绫诲瀷鍖归厤锛岀洿鎺ヨ繑鍥瀟rue
+  if (previewableTypes.includes(file.type || '')) {
+    return true
+  }
+  
+  // 濡傛灉MIME绫诲瀷涓虹┖鎴栦笉鍖归厤锛屾牴鎹枃浠舵墿灞曞悕鍒ゆ柇
+  const fileName = file.name || ''
+  const fileExtension = fileName.toLowerCase().split('.').pop()
+  
+  const previewableExtensions = [
+    'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp',
+    'txt', 'html', 'htm', 'css', 'js',
+    'pdf',
+    'docx', 'xlsx', 'pptx'
+  ]
+  
+  return previewableExtensions.includes(fileExtension)
 }
 
-// 姘镐箙澶嶉�夋鍙樺寲澶勭悊
-const handleForeverChange = (index: number) => {
-  if (form.items[index].forever) {
-    form.items[index].end = ''
+// 鍒ゆ柇鏂囦欢鏄惁宸蹭笂浼犳垚鍔�
+const isFileUploaded = (file: any) => {
+  // 鏂囦欢鏈塽rl涓旂姸鎬佷负success琛ㄧず宸蹭笂浼犳垚鍔�
+  return file.url && (file.status === 'success' || file.uploaded)
+}
+
+// 鏂囦欢棰勮
+const handlePreview = async (file: any) => {
+  if (!file.url) {
+    ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�')
+    return
+  }
+  
+  // 鑾峰彇鏂囦欢鎵╁睍鍚�
+  const fileName = file.name || ''
+  const fileExtension = fileName.toLowerCase().split('.').pop()
+  
+  let previewUrl = file.url
+  
+  // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼紭鍏堜娇鐢ㄩ瑙圲RL
+  if (file.url.includes('order-attachments')) {
+    try {
+      // 棣栧厛灏濊瘯鑾峰彇棰勮URL
+      const previewResponse = await createAxios({
+        url: `/admin/file/preview`,
+        method: 'GET',
+        params: {
+          fileName: file.url
+        }
+      })
+      
+      console.log('棰勮URL鍝嶅簲:', previewResponse)
+      
+      // 妫�鏌ュ搷搴旀牸寮�
+      const responseData = previewResponse as any
+      if (responseData && responseData.code === 200 && responseData.data) {
+        previewUrl = responseData.data
+        console.log('浣跨敤棰勮URL:', previewUrl)
+      } else {
+        console.log('棰勮URL鑾峰彇澶辫触锛屼娇鐢ㄤ笅杞芥柟寮�')
+        // 濡傛灉棰勮URL鑾峰彇澶辫触锛屽洖閫�鍒颁笅杞芥柟寮�
+        const response = await createAxios({
+          url: `/admin/file/download`,
+          method: 'GET',
+          responseType: 'blob',
+          params: {
+            fileName: file.url,
+            originalName: file.name
+          }
+        })
+        
+        // 鍒涘缓棰勮URL
+        const blob = new Blob([response as any])
+        previewUrl = window.URL.createObjectURL(blob)
+        console.log('浣跨敤Blob URL:', previewUrl)
+      }
+    } catch (error) {
+      console.error('鑾峰彇鏂囦欢澶辫触:', error)
+      ElMessage.error('鑾峰彇鏂囦欢澶辫触锛屾棤娉曢瑙�')
+      return
+    }
+  }
+  
+  // 鍥剧墖鏂囦欢鐩存帴鍦ㄦ柊绐楀彛鎵撳紑
+  if ((file.type && file.type.startsWith('image/')) || 
+      ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExtension)) {
+    console.log('棰勮鍥剧墖鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // PDF鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑
+  if (file.type === 'application/pdf' || fileExtension === 'pdf') {
+    console.log('棰勮PDF鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // 鏂囨湰鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑
+  if ((file.type && file.type.startsWith('text/')) || 
+      ['txt', 'html', 'htm', 'css', 'js'].includes(fileExtension)) {
+    console.log('棰勮鏂囨湰鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // Office鏂囨。鍜屽叾浠栨枃浠剁被鍨嬶紝灏濊瘯鍦ㄦ柊绐楀彛鎵撳紑
+  try {
+    console.log('棰勮鍏朵粬鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+  } catch (error) {
+    console.error('棰勮澶辫触:', error)
+    ElMessage.error('棰勮澶辫触锛岃涓嬭浇鍚庢煡鐪�')
   }
 }
+
+// 鏂囦欢涓嬭浇
+const handleDownload = async (file: any) => {
+  if (!file.url) {
+    ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�')
+    return
+  }
+  
+  console.log('寮�濮嬩笅杞芥枃浠�:', file.name, 'URL:', file.url)
+  
+  try {
+    // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼娇鐢ㄥ悗绔洿鎺ヤ笅杞紸PI
+    if (file.url.includes('order-attachments')) {
+      console.log('浣跨敤MinIO涓嬭浇API')
+      
+      // 浣跨敤axios閫氳繃浠g悊璁块棶鍚庣API
+      const response = await createAxios({
+        url: `/admin/file/download`,
+        method: 'GET',
+        responseType: 'blob',
+        params: {
+          fileName: file.url,
+          originalName: file.name
+        }
+      })
+      
+      console.log('涓嬭浇鍝嶅簲:', response)
+      
+      // 鍒涘缓涓嬭浇閾炬帴
+      const blob = new Blob([response as any])
+      const downloadUrl = window.URL.createObjectURL(blob)
+      
+      console.log('鍒涘缓涓嬭浇閾炬帴:', downloadUrl)
+      
+      const link = document.createElement('a')
+      link.href = downloadUrl
+      link.download = file.name || 'download'
+      link.target = '_blank'
+      link.rel = 'noopener noreferrer'
+      
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      
+      // 娓呯悊URL瀵硅薄
+      window.URL.revokeObjectURL(downloadUrl)
+      
+      ElMessage.success('鏂囦欢涓嬭浇鎴愬姛')
+    } else {
+      console.log('浣跨敤鐩存帴URL涓嬭浇')
+      // 鍏朵粬鎯呭喌鐩存帴浣跨敤鍘烾RL
+      const link = document.createElement('a')
+      link.href = file.url
+      link.download = file.name || 'download'
+      link.target = '_blank'
+      link.rel = 'noopener noreferrer'
+      
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      
+      ElMessage.success('寮�濮嬩笅杞芥枃浠�')
+    }
+  } catch (error) {
+    console.error('涓嬭浇澶辫触:', error)
+    ElMessage.error('涓嬭浇澶辫触锛岃閲嶈瘯')
+  }
+}
+
+
 
 // 鐥囩粨涓庝慨澶嶈鏄庯細
 // 1) Element Plus 鐨� el-table 瀛愬垪 width 鐧惧垎姣旀槸鐩稿浜庤〃鏍煎鍣ㄧ殑鍍忕礌瀹藉害璁$畻锛屼絾鍙湁鍦ㄨ〃鏍煎鍣ㄦ湁鏄庣‘瀹藉害鏃舵墠鐢熸晥銆�
@@ -694,6 +902,36 @@
   text-align: left !important;
 }
 
+/* 鏂囦欢鎿嶄綔鎸夐挳鏍峰紡 */
+.file-actions {
+  display: flex;
+  gap: 8px;
+  align-items: center;
+  justify-content: center;
+  
+  .preview-btn {
+    color: #409eff;
+    &:hover {
+      text-decoration: underline;
+    }
+    &:disabled {
+      color: #c0c4cc;
+      cursor: not-allowed;
+    }
+  }
+  
+  .download-btn {
+    color: #67c23a;
+    &:hover {
+      text-decoration: underline;
+    }
+    &:disabled {
+      color: #c0c4cc;
+      cursor: not-allowed;
+    }
+  }
+}
+
 /* 浜ゆ槗淇℃伅澶囨敞琛ㄦ牸鏍峰紡 */
 .remark-table {
   width: 100%;
@@ -701,8 +939,9 @@
     display: flex;
     align-items: center;
     gap: 10px;
-    .forever-checkbox {
-      margin-left: 10px;
+    .forever-text {
+      color: #409eff;
+      font-weight: 500;
     }
   }
 }
diff --git a/src/views/tradeManage/detail/index.vue b/src/views/tradeManage/detail/index.vue
index abfcfe1..098fffc 100644
--- a/src/views/tradeManage/detail/index.vue
+++ b/src/views/tradeManage/detail/index.vue
@@ -143,7 +143,87 @@
       </div>
 
       <!-- 绉婚櫎鍘熸潵鐨勮〃鏍煎簳閮ㄤ俊鎭紝鍥犱负宸茬粡绉诲埌琛ㄦ牸鏈�鍚庝竴琛� -->
-    </el-card>
+
+       <!-- 浜ゆ槗鏂囦欢锛堢Щ鍔ㄥ埌璁㈠崟璇︽儏涓嬮潰锛屽悓涓�鍗$墖鍐咃級 -->
+       <div class="file-section" v-if="isAgreementOrder && fileList.length > 0">
+         <el-table
+           :data="fileList"
+           border
+           class="file-table"
+           :header-cell-style="fileTableHeaderStyle"
+           :cell-style="fileTableCellStyle"
+         >
+           <el-table-column min-width="200">
+             <template #header>
+               <el-icon class="header-icon"><Document /></el-icon>
+               <span>浜ゆ槗鏂囦欢</span>
+             </template>
+             <template #default="{ row }">
+               <div class="file-name">
+                 <el-icon class="file-icon"><Document /></el-icon>
+                 <span>{{ row.name }}</span>
+               </div>
+             </template>
+           </el-table-column>
+           <el-table-column label="鏂囦欢澶у皬" prop="size" width="120">
+             <template #default="{ row }">
+               {{ formatFileSize(row.size) }}
+             </template>
+           </el-table-column>
+           <el-table-column label="鎿嶄綔" width="180">
+            <template #default="{ row }">
+              <div class="file-actions">
+                <el-button
+                  type="text"
+                  size="small"
+                  class="preview-btn"
+                  @click="handlePreview(row)"
+                  v-if="isPreviewable(row)"
+                  :disabled="!isFileUploaded(row)"
+                >
+                  棰勮
+                </el-button>
+                <el-button
+                  type="text"
+                  size="small"
+                  class="download-btn"
+                  @click="handleDownload(row)"
+                  :disabled="!isFileUploaded(row)"
+                >
+                  涓嬭浇
+                </el-button>
+              </div>
+            </template>
+          </el-table-column>
+         </el-table>
+       </div>
+     </el-card>
+
+     <!-- 浜ゆ槗淇℃伅澶囨敞锛堜粎鍦ㄨ鍗曠姸鎬佷负"寰呬氦鏄撶‘璁�"鎴栦箣鍚庢椂鏄剧ず锛� -->
+     <el-card class="mt15" shadow="never" v-if="shouldShowRemark">
+       <div class="title">浜ゆ槗淇℃伅澶囨敞</div>
+       <el-table :data="remarkItems" border class="mt10 remark-table">
+         <el-table-column label="璇︽儏" prop="name" min-width="200" />
+         <el-table-column label="鎺堟潈寮�濮嬫椂闂�" width="200">
+           <template #default="{ row, $index }">
+             <span>{{ remarkItems[$index].start || '-' }}</span>
+           </template>
+         </el-table-column>
+         <el-table-column label="鎺堟潈缁撴潫鏃堕棿" width="200">
+           <template #default="{ row, $index }">
+             <div class="end-time-wrapper">
+               <span v-if="remarkItems[$index].forever" class="forever-text">姘镐箙</span>
+               <span v-else>{{ remarkItems[$index].end || '-' }}</span>
+             </div>
+           </template>
+         </el-table-column>
+         <el-table-column label="澶囨敞" min-width="300">
+           <template #default="{ row, $index }">
+             <span>{{ remarkItems[$index].remark || '-' }}</span>
+           </template>
+         </el-table-column>
+       </el-table>
+     </el-card>
 
     <!-- 瀹℃壒杩借釜 -->
     <el-card class="mt15" shadow="never" v-if="detail.records?.length">
@@ -213,6 +293,9 @@
 import { onMounted, reactive, ref, computed, type CSSProperties } from 'vue'
 import { Document, User, Goods, List } from '@element-plus/icons-vue'
 import { useRoute, useRouter } from 'vue-router'
+import { ElMessage } from 'element-plus'
+import orderApi from '@/api/orderApi'
+import createAxios from '@/utils/axios'
 
 const route = useRoute()
 const router = useRouter()
@@ -221,6 +304,21 @@
 const activeTab = ref('records')
 const labelStyle = { width: '180px', maxWidth: '180px' }
 const contentStyle = { width: 'calc(50% - 180px)' }
+
+// 鏂囦欢鐩稿叧
+const fileList = ref<any[]>([])
+const isAgreementOrder = ref(false)
+
+// 浜ゆ槗淇℃伅澶囨敞
+const remarkItems = ref<any[]>([])
+const shouldShowRemark = computed(() => {
+  const statusName = detail.statusName || ''
+  // 褰撹鍗曠姸鎬佷负"寰呬氦鏄撶‘璁�"鎴栦箣鍚庣殑鐘舵�佹椂鏄剧ず浜ゆ槗淇℃伅澶囨敞
+  // "寰呬笂浼犳枃浠�"鍜�"寰呮巿鏉�"鐘舵�佷笉鏄剧ず浜ゆ槗淇℃伅澶囨敞
+  const statusOrder = ['WAIT_UPLOAD', 'WAIT_AUTHORIZE', 'WAIT_CONFIRM', 'COMPLETED', 'EVALUATED']
+  const currentStatus = statusServerToUi[statusName]
+  return currentStatus && statusOrder.indexOf(currentStatus) >= statusOrder.indexOf('WAIT_CONFIRM')
+})
 
 // 璁$畻琛ㄦ牸鏁版嵁锛屾坊鍔犳眹鎬昏
 const tableData = computed(() => {
@@ -240,120 +338,138 @@
   return [...detail.items, summaryRow]
 })
 
-onMounted(async () => {
-  // 浣跨敤鍓嶇妯℃嫙鏁版嵁浠ヤ究寮�鍙� UI锛堜笉鏀瑰姩鍚庣鏈嶅姟锛�
-  const mockDetail = {
-    orderNo: '4348442557619205545',
-    resourceTypeName: '杞欢浜у搧',
-    status: 'WAIT_APPROVAL',
-    statusName: '寰呭鏍�',
-    applyTime: '2025-05-21 10:00:00',
-    unitName: '涓氦鏂硅繙寤鸿鏈夐檺鍏徃',
-        userName: '寮犻潤',
-        userAccount: 'L20159922',
-    userDept: '淇℃伅涓績',
-    userPhone: '13800000000',
-    productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-    supplier: '涓氦鏂硅繙绉戞妧鏈夐檺鍏徃',
-    industry: '寤虹瓚宸ョ▼',
-    projectUnit: '鍦熷缓宸ョ▼',
-        productType: '杞欢搴�',
-    productDesc:
-      '闈㈠悜宸ョ▼椤圭洰鐨勮川閲忓疄娴嬪疄閲忔暟瀛楀寲绠$悊绯荤粺锛屾敮鎸佹爣鍑嗗寲閲囬泦銆佽嚜鍔ㄧ粺璁′笌杩囩▼绠℃帶銆�',
-    items: [
-      {
-        id: '1',
-        name: '浼佷笟绉佹湁SaaS鐗堣鍙�',
-        saleType: '涔版柇',
-        accountCount: 50,
-        customerTarget: '浼佷笟',
-        concurrentNodes: 50,
-        pricePoint: 50000,
-        priceCash: 0,
-        quantity: 1,
-        period: 0,
-      },
-      {
-        id: '2',
-        name: '浼佷笟绉佹湁SaaS鐗圤TA鍗囩骇鏈嶅姟',
-        saleType: 'OTA鏈嶅姟',
-        accountCount: 50,
-        customerTarget: '浼佷笟',
-        concurrentNodes: 50,
-        pricePoint: 0,
-        priceCash: 7500,
-        quantity: 1,
-        period: 1,
-      },
-      {
-        id: '3',
-        name: '浼佷笟绉佹湁SaaS鐗堢敤鎴峰閲忓寘',
-        saleType: '绉佹湁澧為噺鍖�',
-        accountCount: 100,
-        customerTarget: '浼佷笟',
-        concurrentNodes: 100,
-        pricePoint: 0,
-        priceCash: 0,
-        priceProtocol: true,
-        quantity: 1,
-        period: 1,
-      },
-      {
-        id: '4',
-        name: '涓汉鍏湁SaaS鐗堣鍙�',
-        saleType: '绉佹湁澧為噺鍖�',
-        accountCount: 50,
-        customerTarget: '涓汉',
-        concurrentNodes: 50,
-        pricePoint: 0,
-        priceCash: 0,
-        quantity: 1,
-        period: 0,
-      },
-    ],
-    pointTotal: '50,000',
-    cashTotal: '7,500',
-    records: [
-      {
-        nodeName: '鎻愪氦浜�',
-        approver: '寮犻潤',
-        department: '闂ㄦ埛绯荤粺涓存椂缁�',
-        startTime: '2025-05-21 16:08:09',
-        endTime: '2025-05-21 16:08:09',
-        statusName: '宸插畬鎴�',
-        opinion: '',
-      },
-      {
-        nodeName: '浜ゆ槗瀹℃壒',
-        approver: '鍠讳細宄�',
-        department: '闂ㄦ埛绯荤粺涓存椂缁�',
-        startTime: '2025-05-21 16:08:09',
-        endTime: '',
-        statusName: '瀹¢槄涓�',
-        opinion: '',
-      },
-    ],
-    nodes: [
-      {
-        nodeName: '鎻愪氦鐢宠',
-        nodeType: '寮�濮嬭妭鐐�',
-        handler: '寮犻潤',
-        department: '闂ㄦ埛绯荤粺涓存椂缁�',
-        status: 'completed',
-        statusName: '宸插畬鎴�',
-      },
-      {
-        nodeName: '浜ゆ槗瀹℃壒',
-        nodeType: '瀹℃壒鑺傜偣',
-        handler: '鍠讳細宄�',
-        department: '闂ㄦ埛绯荤粺涓存椂缁�',
-        status: 'processing',
-        statusName: '澶勭悊涓�',
-      },
-    ],
-  }
+// 鐘舵�佹槧灏勶紙鍚庣涓枃 -> 鍓嶇鏋氫妇锛�
+const statusServerToUi: Record<string, string> = {
+  '寰呬笂浼犳枃浠�': 'WAIT_UPLOAD',
+  '寰呮巿鏉�': 'WAIT_AUTHORIZE',
+  '寰呬氦鏄撶‘璁�': 'WAIT_CONFIRM',
+  '宸插畬鎴�': 'COMPLETED',
+  '宸茶瘎浠�': 'EVALUATED',
+}
 
-  Object.assign(detail, mockDetail)
+const formatDateTime = (val?: string) => (val ? val.replace('T', ' ').slice(0, 19) : '')
+
+const normalizePriceType = (val?: string): 'points' | 'currency' | 'agreement' | 'free' => {
+  if (!val) return 'currency'
+  const s = String(val)
+  if (/(绉垎|points)/i.test(s)) return 'points'
+  if (/(鍗忚|agreement)/i.test(s)) return 'agreement'
+  if (/(鍏嶈垂|free)/i.test(s)) return 'free'
+  return 'currency'
+}
+
+onMounted(async () => {
+  const orderId = String(route.params.id || '')
+  if (!orderId) return
+  
+  try {
+    // 骞惰鑾峰彇璁㈠崟璇︽儏鍜屽崗璁被鍨嬫鏌�
+    const [orderRes, agreementRes] = await Promise.all([
+      orderApi.getOrderDetail(orderId),
+      orderApi.checkAgreementPriceType(orderId)
+    ])
+    
+    const res = orderRes as any
+    const data = res?.data || {}
+    
+    // 璁剧疆鏄惁涓哄崗璁鍗�
+    const agreementResult = agreementRes as any
+    isAgreementOrder.value = agreementResult?.data === true
+
+    const statusName: string = data.orderStatus || ''
+    const uiStatus = statusServerToUi[statusName] || 'INFO'
+
+    // 鏄犲皠璁㈠崟璇︽儏澶撮儴淇℃伅
+    const head = {
+      orderNo: data.orderId,
+      resourceTypeName: '杞欢浜у搧',
+      status: uiStatus,
+      statusName,
+      applyTime: formatDateTime(data.applyTime),
+      unitName: data.unitName || '-',
+      userName: data.userName || '-',
+      userAccount: data.userAccount || '-',
+      userDept: data.userDept || '-',
+      userPhone: data.userPhone || '-',
+      productName: data.productName || '-',
+      supplier: data.providerName || '-',
+      industry: data.industry || '-',
+      projectUnit: data.projectUnit || '-',
+      productType: data.productType || '-',
+      productDesc: data.productDesc || '-',
+    }
+
+    // 鏄庣粏椤规槧灏�
+    const items: any[] = Array.isArray(data.orderDetails)
+      ? data.orderDetails.map((d: any, idx: number) => {
+          const pt = normalizePriceType(d.priceType)
+          return {
+            id: String(d.id ?? idx + 1),
+            name: d.suiteName,
+            saleType: d.salesForm,
+            accountCount: d.accountLimit,
+            customerTarget: d.customerType,
+            concurrentNodes: d.concurrentNodes,
+            pricePoint: pt === 'points' ? Number(d.unitPrice || 0) : 0,
+            priceCash: pt === 'currency' ? Number(d.unitPrice || 0) : 0,
+            priceProtocol: pt === 'agreement',
+            quantity: Number(d.quantity || 0),
+            period: Number(d.duration || 0),
+            remarks: d.remarks || '', // 鏂板 remarks 瀛楁
+          }
+        })
+      : []
+
+    // 姹囨�伙紙绠�鍗曠浉鍔狅細鍗曚环*鏁伴噺锛�
+    const pointTotalNum = items.reduce((sum, it) => sum + Number(it.pricePoint || 0) * Number(it.quantity || 0), 0)
+    const cashTotalNum = items.reduce((sum, it) => sum + Number(it.priceCash || 0) * Number(it.quantity || 0), 0)
+
+    Object.assign(detail, head, {
+      items,
+      pointTotal: pointTotalNum.toLocaleString(),
+      cashTotal: cashTotalNum.toLocaleString(),
+      records: [],
+      nodes: [],
+    })
+
+    // 鍒濆鍖栦氦鏄撲俊鎭娉ㄦ暟鎹�
+    remarkItems.value = (detail.items || []).map((item: any, index: number) => {
+      // 璁$畻鎺堟潈缁撴潫鏃堕棿
+      let endDate = ''
+      if (item.period > 0) {
+        // 濡傛灉鏈夋湡闄愶紝璁$畻缁撴潫鏃堕棿
+        const startDate = new Date(data.applyTime || new Date())
+        const endDateObj = new Date(startDate)
+        endDateObj.setFullYear(endDateObj.getFullYear() + item.period)
+        endDate = endDateObj.toISOString().split('T')[0] // 鏍煎紡鍖栦负 YYYY-MM-DD
+      }
+      
+      return { 
+        name: item.name,
+        start: data.applyTime ? data.applyTime.split('T')[0] : '', // 浣跨敤璁㈠崟鐢宠鏃堕棿
+        end: endDate, 
+        forever: item.period === 0, // 鏈熼檺涓�0鏃惰缃负姘镐箙
+        remark: item.remarks || '' // 浣跨敤濂椾欢淇℃伅涓殑remarks瀛楁
+      }
+    })
+
+    // 鑾峰彇璁㈠崟闄勪欢鍒楄〃锛堝鏋滄湁鐨勮瘽锛�
+    if (data.attachments && Array.isArray(data.attachments)) {
+      fileList.value = data.attachments.map((file: any) => ({
+        name: file.fileName || file.originalName,
+        size: file.fileSize || 0,
+        uid: file.id,
+        status: 'success',
+        url: file.fileUrl,
+        uploaded: true
+      }))
+    } else {
+      fileList.value = []
+    }
+  } catch (error) {
+    console.error('鑾峰彇璁㈠崟璇︽儏澶辫触:', error)
+    ElMessage.error('鑾峰彇璁㈠崟璇︽儏澶辫触')
+  }
 })
 
 // 涓庡垪琛ㄩ〉淇濇寔涓�鑷寸殑鐘舵�佺被鍨嬫槧灏勶紙UI灞曠ず鐢級
@@ -411,6 +527,15 @@
 }
 const recordTableCellStyle: CSSProperties = { fontSize: '12px' }
 
+// 鏂囦欢鍒楄〃琛ㄦ牸琛ㄥご鏂囧瓧灞呬腑锛屼絾绗竴鍒楃殑"浜ゆ槗鏂囦欢"鏂囧瓧闈犲乏瀵归綈
+const fileTableHeaderStyle: CSSProperties = { 
+  textAlign: 'center',
+  fontSize: '14px',
+  background: '#f3f6fb'
+}
+// 鏂囦欢鍒楄〃琛ㄦ牸琛ㄤ綋鏂囧瓧澶у皬
+const fileTableCellStyle: CSSProperties = { fontSize: '12px' }
+
 // 涓烘眹鎬昏娣诲姞鐗规畩鏍峰紡绫诲悕
 const getRowClassName = ({ row }: { row: any }) => {
   return row.isSummary ? 'summary-row' : ''
@@ -441,6 +566,210 @@
 
 // 杩斿洖鎸夐挳
 const goBack = () => router.back()
+
+// 鏂囦欢澶у皬鏍煎紡鍖�
+const formatFileSize = (size: number) => {
+  if (!size || size === 0) return '0 Bytes';
+  const k = 1024;
+  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+  const i = Math.floor(Math.log(size) / Math.log(k));
+  return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+};
+
+// 鍒ゆ柇鏂囦欢鏄惁鍙瑙�
+const isPreviewable = (file: any) => {
+  // 棣栧厛妫�鏌IME绫诲瀷
+  const previewableTypes = [
+    'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/bmp', 'image/webp',
+    'text/plain', 'text/html', 'text/css', 'text/javascript',
+    'application/pdf',
+    'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
+    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
+    'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
+  ]
+  
+  // 濡傛灉MIME绫诲瀷鍖归厤锛岀洿鎺ヨ繑鍥瀟rue
+  if (previewableTypes.includes(file.type || '')) {
+    return true
+  }
+  
+  // 濡傛灉MIME绫诲瀷涓虹┖鎴栦笉鍖归厤锛屾牴鎹枃浠舵墿灞曞悕鍒ゆ柇
+  const fileName = file.name || ''
+  const fileExtension = fileName.toLowerCase().split('.').pop()
+  
+  const previewableExtensions = [
+    'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp',
+    'txt', 'html', 'htm', 'css', 'js',
+    'pdf',
+    'docx', 'xlsx', 'pptx'
+  ]
+  
+  return previewableExtensions.includes(fileExtension)
+}
+
+// 鍒ゆ柇鏂囦欢鏄惁宸蹭笂浼犳垚鍔�
+const isFileUploaded = (file: any) => {
+  // 鏂囦欢鏈塽rl涓旂姸鎬佷负success琛ㄧず宸蹭笂浼犳垚鍔�
+  return file.url && (file.status === 'success' || file.uploaded)
+}
+
+// 鏂囦欢棰勮
+const handlePreview = async (file: any) => {
+  if (!file.url) {
+    ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�')
+    return
+  }
+  
+  // 鑾峰彇鏂囦欢鎵╁睍鍚�
+  const fileName = file.name || ''
+  const fileExtension = fileName.toLowerCase().split('.').pop()
+  
+  let previewUrl = file.url
+  
+  // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼紭鍏堜娇鐢ㄩ瑙圲RL
+  if (file.url.includes('order-attachments')) {
+    try {
+      // 棣栧厛灏濊瘯鑾峰彇棰勮URL
+      const previewResponse = await createAxios({
+        url: `/admin/file/preview`,
+        method: 'GET',
+        params: {
+          fileName: file.url
+        }
+      })
+      
+      console.log('棰勮URL鍝嶅簲:', previewResponse)
+      
+      // 妫�鏌ュ搷搴旀牸寮�
+      const responseData = previewResponse as any
+      if (responseData && responseData.code === 200 && responseData.data) {
+        previewUrl = responseData.data
+        console.log('浣跨敤棰勮URL:', previewUrl)
+      } else {
+        console.log('棰勮URL鑾峰彇澶辫触锛屼娇鐢ㄤ笅杞芥柟寮�')
+        // 濡傛灉棰勮URL鑾峰彇澶辫触锛屽洖閫�鍒颁笅杞芥柟寮�
+        const response = await createAxios({
+          url: `/admin/file/download`,
+          method: 'GET',
+          responseType: 'blob',
+          params: {
+            fileName: file.url,
+            originalName: file.name
+          }
+        })
+        
+        // 鍒涘缓棰勮URL
+        const blob = new Blob([response as any])
+        previewUrl = window.URL.createObjectURL(blob)
+        console.log('浣跨敤Blob URL:', previewUrl)
+      }
+    } catch (error) {
+      console.error('鑾峰彇鏂囦欢澶辫触:', error)
+      ElMessage.error('鑾峰彇鏂囦欢澶辫触锛屾棤娉曢瑙�')
+      return
+    }
+  }
+  
+  // 鍥剧墖鏂囦欢鐩存帴鍦ㄦ柊绐楀彛鎵撳紑
+  if ((file.type && file.type.startsWith('image/')) || 
+      ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExtension)) {
+    console.log('棰勮鍥剧墖鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // PDF鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑
+  if (file.type === 'application/pdf' || fileExtension === 'pdf') {
+    console.log('棰勮PDF鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // 鏂囨湰鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑
+  if ((file.type && file.type.startsWith('text/')) || 
+      ['txt', 'html', 'htm', 'css', 'js'].includes(fileExtension)) {
+    console.log('棰勮鏂囨湰鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // Office鏂囨。鍜屽叾浠栨枃浠剁被鍨嬶紝灏濊瘯鍦ㄦ柊绐楀彛鎵撳紑
+  try {
+    console.log('棰勮鍏朵粬鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+  } catch (error) {
+    console.error('棰勮澶辫触:', error)
+    ElMessage.error('棰勮澶辫触锛岃涓嬭浇鍚庢煡鐪�')
+  }
+}
+
+// 鏂囦欢涓嬭浇
+const handleDownload = async (file: any) => {
+  if (!file.url) {
+    ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�')
+    return
+  }
+  
+  console.log('寮�濮嬩笅杞芥枃浠�:', file.name, 'URL:', file.url)
+  
+  try {
+    // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼娇鐢ㄥ悗绔洿鎺ヤ笅杞紸PI
+    if (file.url.includes('order-attachments')) {
+      console.log('浣跨敤MinIO涓嬭浇API')
+      
+      // 浣跨敤axios閫氳繃浠g悊璁块棶鍚庣API
+      const response = await createAxios({
+        url: `/admin/file/download`,
+        method: 'GET',
+        responseType: 'blob',
+        params: {
+          fileName: file.url,
+          originalName: file.name
+        }
+      })
+      
+      console.log('涓嬭浇鍝嶅簲:', response)
+      
+      // 鍒涘缓涓嬭浇閾炬帴
+      const blob = new Blob([response as any])
+      const downloadUrl = window.URL.createObjectURL(blob)
+      
+      console.log('鍒涘缓涓嬭浇閾炬帴:', downloadUrl)
+      
+      const link = document.createElement('a')
+      link.href = downloadUrl
+      link.download = file.name || 'download'
+      link.target = '_blank'
+      link.rel = 'noopener noreferrer'
+      
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      
+      // 娓呯悊URL瀵硅薄
+      window.URL.revokeObjectURL(downloadUrl)
+      
+      ElMessage.success('鏂囦欢涓嬭浇鎴愬姛')
+    } else {
+      console.log('浣跨敤鐩存帴URL涓嬭浇')
+      // 鍏朵粬鎯呭喌鐩存帴浣跨敤鍘烾RL
+      const link = document.createElement('a')
+      link.href = file.url
+      link.download = file.name || 'download'
+      link.target = '_blank'
+      link.rel = 'noopener noreferrer'
+      
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      
+      ElMessage.success('寮�濮嬩笅杞芥枃浠�')
+    }
+  } catch (error) {
+    console.error('涓嬭浇澶辫触:', error)
+    ElMessage.error('涓嬭浇澶辫触锛岃閲嶈瘯')
+  }
+}
 
 // 鍗曞厓鏍煎悎骞舵柟娉�
 const arraySpanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
@@ -645,6 +974,81 @@
     margin: 0 10px;
   }
 }
+
+/* 鏂囦欢鍒楄〃琛ㄦ牸鏍峰紡 */
+.file-section {
+  margin-top: 15px;
+  .file-title {
+    font-weight: 600;
+    margin-bottom: 10px;
+  }
+  .file-table {
+    width: 100%;
+    .file-name {
+      display: flex;
+      align-items: center;
+      .file-icon {
+        margin-right: 8px;
+        color: #409eff;
+      }
+    }
+    .preview-btn {
+      color: #409eff;
+      &:hover {
+        text-decoration: underline;
+      }
+    }
+  }
+}
+
+/* 鏂囦欢琛ㄦ牸琛ㄥご绗竴鍒�"浜ゆ槗鏂囦欢"鏂囧瓧闈犲乏瀵归綈 */
+.file-table :deep(.el-table__header-wrapper thead tr th:first-child) {
+  text-align: left !important;
+}
+
+/* 鏂囦欢鎿嶄綔鎸夐挳鏍峰紡 */
+.file-actions {
+  display: flex;
+  gap: 8px;
+  align-items: center;
+  justify-content: center;
+  
+  .preview-btn {
+    color: #409eff;
+    &:hover {
+      text-decoration: underline;
+    }
+    &:disabled {
+      color: #c0c4cc;
+      cursor: not-allowed;
+    }
+  }
+  
+  .download-btn {
+    color: #67c23a;
+    &:hover {
+      text-decoration: underline;
+    }
+    &:disabled {
+      color: #c0c4cc;
+      cursor: not-allowed;
+    }
+  }
+}
+
+/* 浜ゆ槗淇℃伅澶囨敞琛ㄦ牸鏍峰紡 */
+.remark-table {
+  width: 100%;
+  .end-time-wrapper {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+    .forever-text {
+      color: #409eff;
+      font-weight: 500;
+    }
+  }
+}
 </style>
 
 
diff --git a/src/views/tradeManage/evaluate/index.vue b/src/views/tradeManage/evaluate/index.vue
index 0493cb9..f607372 100644
--- a/src/views/tradeManage/evaluate/index.vue
+++ b/src/views/tradeManage/evaluate/index.vue
@@ -142,6 +142,8 @@
         </el-table>
       </div>
 
+      <!-- 绉婚櫎鍘熸潵鐨勮〃鏍煎簳閮ㄤ俊鎭紝鍥犱负宸茬粡绉诲埌琛ㄦ牸鏈�鍚庝竴琛� -->
+
        <!-- 浜ゆ槗鏂囦欢锛堢Щ鍔ㄥ埌璁㈠崟璇︽儏涓嬮潰锛屽悓涓�鍗$墖鍐咃級 -->
        <div class="file-section" v-if="fileList.length > 0">
          <el-table
@@ -168,103 +170,189 @@
                {{ formatFileSize(row.size) }}
              </template>
            </el-table-column>
-           <el-table-column label="鎿嶄綔" width="100">
+           <el-table-column label="鎿嶄綔" width="180">
              <template #default="{ row }">
-               <el-button
-                 type="text"
-                 size="small"
-                 class="preview-btn"
-                 @click="handlePreview(row)"
-               >
-                 棰勮
-               </el-button>
-             </template>
-           </el-table-column>
-         </el-table>
-       </div>
-
-       <!-- 浜ゆ槗淇℃伅澶囨敞锛堢Щ鍔ㄥ埌浜ゆ槗鏂囦欢涓嬮潰锛屽悓涓�鍗$墖鍐咃級 -->
-       <div class="remark-section" v-if="remarkItems.length > 0">
-         <el-table
-           :data="remarkItems"
-           border
-           class="remark-table"
-           :header-cell-style="remarkTableHeaderStyle"
-           :cell-style="remarkTableCellStyle"
-         >
-           <el-table-column min-width="200">
-             <template #header>
-               <el-icon class="header-icon"><Document /></el-icon>
-               <span>浜ゆ槗淇℃伅澶囨敞</span>
-             </template>
-             <template #default="{ row }">
-               <div class="remark-name">
-                 <span>{{ row.name }}</span>
+               <div class="file-actions">
+                 <el-button
+                   type="text"
+                   size="small"
+                   class="preview-btn"
+                   @click="handlePreview(row)"
+                   v-if="isPreviewable(row)"
+                   :disabled="!isFileUploaded(row)"
+                 >
+                   棰勮
+                 </el-button>
+                 <el-button
+                   type="text"
+                   size="small"
+                   class="download-btn"
+                   @click="handleDownload(row)"
+                   :disabled="!isFileUploaded(row)"
+                 >
+                   涓嬭浇
+                 </el-button>
                </div>
-             </template>
-           </el-table-column>
-           <el-table-column label="鎺堟潈寮�濮嬫椂闂�" width="200">
-             <template #default="{ row }">
-               <div class="remark-date">{{ row.start }}</div>
-             </template>
-           </el-table-column>
-           <el-table-column label="鎺堟潈缁撴潫鏃堕棿" width="200">
-             <template #default="{ row }">
-               <div class="remark-date">
-                 {{ row.forever ? '姘镐箙' : row.end }}
-               </div>
-             </template>
-           </el-table-column>
-           <el-table-column label="澶囨敞" min-width="300">
-             <template #default="{ row }">
-               <div class="remark-content">{{ row.remark }}</div>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </el-card>
 
-     <!-- 浜ゆ槗璇勪环 -->
+     <!-- 浜ゆ槗淇℃伅澶囨敞 -->
     <el-card class="mt15" shadow="never">
-      <div class="title">浜ゆ槗璇勪环</div>
-      <el-form :model="form" label-width="120px" class="mt10" :rules="rules" ref="formRef">
-        <el-form-item label="缁煎悎璇勫垎" prop="score">
-          <el-rate v-model="form.score" />
-        </el-form-item>
-        <el-form-item label="璇勪环鍐呭" prop="content">
-          <el-input v-model="form.content" type="textarea" :autosize="{ minRows: 4 }" placeholder="璇疯緭鍏ヨ瘎浠峰唴瀹�" />
-        </el-form-item>
-      </el-form>
-      <div class="action-buttons">
-        <el-button @click="goBack">杩斿洖</el-button>
-        <el-button type="primary" @click="submit">鎻愪氦璇勪环</el-button>
-      </div>
-    </el-card>
-  </div>
-</template>
+      <div class="title">浜ゆ槗淇℃伅澶囨敞</div>
+      <el-table :data="form.items" border class="mt10 remark-table">
+        <el-table-column label="璇︽儏" prop="name" min-width="200" />
+                 <el-table-column label="鎺堟潈寮�濮嬫椂闂�" width="200">
+           <template #default="{ row, $index }">
+             <span>{{ form.items[$index].start || '-' }}</span>
+           </template>
+         </el-table-column>
+         <el-table-column label="鎺堟潈缁撴潫鏃堕棿" width="200">
+           <template #default="{ row, $index }">
+             <div class="end-time-wrapper">
+               <span v-if="form.items[$index].forever" class="forever-text">姘镐箙</span>
+               <span v-else>{{ form.items[$index].end || '-' }}</span>
+             </div>
+           </template>
+         </el-table-column>
+         <el-table-column label="澶囨敞" min-width="300">
+           <template #default="{ row, $index }">
+             <span>{{ form.items[$index].remark || '-' }}</span>
+           </template>
+         </el-table-column>
+             </el-table>
+     </el-card>
+
+     <!-- 浜ゆ槗璇勪环 -->
+     <el-card class="mt15" shadow="never">
+       <div class="title">浜ゆ槗璇勪环</div>
+       <div class="evaluation-content">
+         <div class="evaluation-form">
+                       <!-- 璇勫垎閮ㄥ垎 -->
+            <div class="rating-section">
+              <div class="rating-items">
+                <div class="rating-row">
+                  <div class="rating-item">
+                    <label class="required">缁煎悎璇勫垎:</label>
+                    <el-rate
+                      v-model="evaluationForm.overallRating"
+                      :max="5"
+                      :texts="['寰堝樊', '杈冨樊', '涓�鑸�', '杈冨ソ', '寰堝ソ']"
+                      show-text
+                      :colors="['#99A9BF', '#F7BA2A', '#FF9900']"
+                    />
+                  </div>
+                  <div class="rating-item">
+                    <label class="required">鏈嶅姟璇勫垎:</label>
+                    <el-rate
+                      v-model="evaluationForm.serviceRating"
+                      :max="5"
+                      :texts="['寰堝樊', '杈冨樊', '涓�鑸�', '杈冨ソ', '寰堝ソ']"
+                      show-text
+                      :colors="['#99A9BF', '#F7BA2A', '#FF9900']"
+                    />
+                  </div>
+                </div>
+                <div class="rating-row">
+                  <div class="rating-item">
+                    <label class="required">璐ㄩ噺璇勫垎:</label>
+                    <el-rate
+                      v-model="evaluationForm.qualityRating"
+                      :max="5"
+                      :texts="['寰堝樊', '杈冨樊', '涓�鑸�', '杈冨ソ', '寰堝ソ']"
+                      show-text
+                      :colors="['#99A9BF', '#F7BA2A', '#FF9900']"
+                    />
+                  </div>
+                  <div class="rating-item">
+                    <label class="required">閫熷害璇勫垎:</label>
+                    <el-rate
+                      v-model="evaluationForm.speedRating"
+                      :max="5"
+                      :texts="['寰堝樊', '杈冨樊', '涓�鑸�', '杈冨ソ', '寰堝ソ']"
+                      show-text
+                      :colors="['#99A9BF', '#F7BA2A', '#FF9900']"
+                    />
+                  </div>
+                </div>
+              </div>
+            </div>
+           
+                       <!-- 璇勪环鍐呭 -->
+            <div class="form-item">
+              <label class="required">璇勪环鍐呭:</label>
+              <el-input
+                v-model="evaluationForm.content"
+                type="textarea"
+                :rows="4"
+                placeholder="璇疯緭鍏ヨ瘎浠峰唴瀹�"
+                maxlength="500"
+                show-word-limit
+              />
+            </div>
+            
+            <!-- 鍖垮悕鍙戝竷閫夐」 -->
+            <div class="form-item">
+              <label></label>
+              <div class="anonymous-option">
+                <el-checkbox v-model="evaluationForm.isAnonymous">
+                  鍖垮悕鍙戝竷璇勪环
+                </el-checkbox>
+                <div class="anonymous-tip">
+                  <el-icon><InfoFilled /></el-icon>
+                  <span>閫夋嫨鍖垮悕鍙戝竷鍚庯紝鎮ㄧ殑濮撳悕灏嗕笉浼氬湪璇勪环涓樉绀�</span>
+                </div>
+              </div>
+            </div>
+         </div>
+         <div class="evaluation-actions">
+           <el-button @click="goBack">杩斿洖</el-button>
+           <el-button 
+             type="primary" 
+             @click="handleSubmitEvaluation"
+             :loading="evaluationLoading"
+           >
+             鎻愪氦璇勪环
+           </el-button>
+         </div>
+       </div>
+     </el-card>
+   </div>
+ </template>
 
 <script setup lang="ts">
 import { onMounted, reactive, ref, computed, type CSSProperties } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
-import { Document, User, Goods, List } from '@element-plus/icons-vue'
-import { fetchOrderDetail, submitEvaluate } from '@/api/tradeManage'
-import { ElMessage, FormInstance } from 'element-plus'
+import { Document, User, Goods, List, InfoFilled } from '@element-plus/icons-vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import orderApi from '@/api/orderApi'
+import { useUserInfo } from '@/stores/modules/userInfo'
+import createAxios from '@/utils/axios'
 
 const route = useRoute()
 const router = useRouter()
+const userStore = useUserInfo()
 const detail = reactive<any>({ items: [] })
-const formRef = ref<FormInstance>()
-const form = reactive({ score: 0, content: '' })
+const form = reactive<any>({ items: [] })
 const fileList = ref<any[]>([])
-const remarkItems = ref<any[]>([])
 const orderTableWrapRef = ref<HTMLElement | null>(null)
 const labelStyle = { width: '180px', maxWidth: '180px' }
 const contentStyle = { width: 'calc(50% - 180px)' }
 
-const rules = {
-  score: [{ required: true, message: '璇疯瘎鍒�', trigger: 'change' }],
-  content: [{ required: true, message: '璇疯緭鍏ヨ瘎浠峰唴瀹�', trigger: 'blur' }],
-}
+// 璇勪环琛ㄥ崟鏁版嵁
+const evaluationForm = reactive({
+  content: '',
+  overallRating: 0,    // 缁煎悎璇勫垎
+  serviceRating: 0,    // 鏈嶅姟璇勫垎
+  qualityRating: 0,    // 璐ㄩ噺璇勫垎
+  speedRating: 0,      // 閫熷害璇勫垎
+  isAnonymous: false   // 鏄惁鍖垮悕鍙戝竷
+})
+
+// 璇勪环loading鐘舵��
+const evaluationLoading = ref(false)
 
 // 璁$畻琛ㄦ牸鏁版嵁锛屾坊鍔犳眹鎬昏
 const tableData = computed(() => {
@@ -284,126 +372,169 @@
   return [...detail.items, summaryRow]
 })
 
+// 鐘舵�佹槧灏勶紙鍚庣涓枃 -> 鍓嶇鏋氫妇锛�
+const statusServerToUi: Record<string, string> = {
+  '寰呬笂浼犳枃浠�': 'WAIT_UPLOAD',
+  '寰呮巿鏉�': 'WAIT_AUTHORIZE',
+  '寰呬氦鏄撶‘璁�': 'WAIT_CONFIRM',
+  '宸插畬鎴�': 'COMPLETED',
+  '宸茶瘎浠�': 'EVALUATED',
+}
+
+const formatDateTime = (val?: string) => (val ? val.replace('T', ' ').slice(0, 19) : '')
+
+const normalizePriceType = (val?: string): 'points' | 'currency' | 'agreement' | 'free' => {
+  if (!val) return 'currency'
+  const s = String(val)
+  if (/(绉垎|points)/i.test(s)) return 'points'
+  if (/(鍗忚|agreement)/i.test(s)) return 'agreement'
+  if (/(鍏嶈垂|free)/i.test(s)) return 'free'
+  return 'currency'
+}
+
 onMounted(async () => {
-  // 浣跨敤鍓嶇妯℃嫙鏁版嵁浠ヤ究寮�鍙� UI锛堜笉鏀瑰姩鍚庣鏈嶅姟锛�
-  const mockDetail = {
-    orderNo: '4348442557619205545',
-    resourceTypeName: '杞欢浜у搧',
-    status: 'FINISH',
-    statusName: '宸插畬鎴�',
-    applyTime: '2025-05-21 10:00:00',
-    unitName: '涓氦鏂硅繙寤鸿鏈夐檺鍏徃',
-    userName: '寮犻潤',
-    userAccount: 'L20159922',
-    userDept: '淇℃伅涓績',
-    userPhone: '13800000000',
-    productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-    supplier: '涓氦鏂硅繙绉戞妧鏈夐檺鍏徃',
-    industry: '寤虹瓚宸ョ▼',
-    projectUnit: '鍦熷缓宸ョ▼',
-    productType: '杞欢搴�',
-    productDesc:
-      '闈㈠悜宸ョ▼椤圭洰鐨勮川閲忓疄娴嬪疄閲忔暟瀛楀寲绠$悊绯荤粺锛屾敮鎸佹爣鍑嗗寲閲囬泦銆佽嚜鍔ㄧ粺璁′笌杩囩▼绠℃帶銆�',
-    items: [
-      {
-        id: '1',
-        name: '浼佷笟绉佹湁SaaS鐗堣鍙�',
-        saleType: '涔版柇',
-        accountCount: 50,
-        customerTarget: '浼佷笟',
-        concurrentNodes: 50,
-        pricePoint: 50000,
-        priceCash: 0,
-        quantity: 1,
-        period: 0,
-      },
-      {
-        id: '2',
-        name: '浼佷笟绉佹湁SaaS鐗圤TA鍗囩骇鏈嶅姟',
-        saleType: 'OTA鏈嶅姟',
-        accountCount: 50,
-        customerTarget: '浼佷笟',
-        concurrentNodes: 50,
-        pricePoint: 0,
-        priceCash: 7500,
-        quantity: 1,
-        period: 1,
-      },
-      {
-        id: '3',
-        name: '浼佷笟绉佹湁SaaS鐗堢敤鎴峰閲忓寘',
-        saleType: '绉佹湁澧為噺鍖�',
-        accountCount: 100,
-        customerTarget: '浼佷笟',
-        concurrentNodes: 100,
-        pricePoint: 0,
-        priceCash: 0,
-        priceProtocol: true,
-        quantity: 1,
-        period: 1,
-      },
-      {
-        id: '4',
-        name: '涓汉鍏湁SaaS鐗堣鍙�',
-        saleType: '绉佹湁澧為噺鍖�',
-        accountCount: 50,
-        customerTarget: '涓汉',
-        concurrentNodes: 50,
-        pricePoint: 0,
-        priceCash: 0,
-        quantity: 1,
-        period: 0,
-      },
-    ],
-    pointTotal: '50,000',
-    cashTotal: '7,500',
-  }
-
-  Object.assign(detail, mockDetail)
+  const orderId = String(route.params.id || '')
+  if (!orderId) return
   
-  // 娣诲姞妯℃嫙鏂囦欢鏁版嵁鐢ㄤ簬灞曠ず
-  fileList.value = [
-    {
-      name: '绛惧瓧鐩栫珷鏂囦欢.pdf',
-      size: 2621440, // 2.5MB
-      uid: '1',
-      status: 'success'
-    },
-    {
-      name: 'API Keys.txt',
-      size: 354, // 354 Bytes
-      uid: '2',
-      status: 'success'
+  try {
+    const res = (await orderApi.getOrderDetail(orderId)) as any
+    const data = res?.data || {}
+
+    const statusName: string = data.orderStatus || ''
+    const uiStatus = statusServerToUi[statusName] || 'INFO'
+
+    // 鏄犲皠璁㈠崟璇︽儏澶撮儴淇℃伅
+    const head = {
+      orderNo: data.orderId,
+      resourceTypeName: '杞欢浜у搧',
+      status: uiStatus,
+      statusName,
+      applyTime: formatDateTime(data.applyTime),
+      unitName: data.unitName || '-',
+      userName: data.userName || '-',
+      userAccount: data.userAccount || '-',
+      userDept: data.userDept || '-',
+      userPhone: data.userPhone || '-',
+      productName: data.productName || '-',
+      supplier: data.providerName || '-',
+      industry: data.industry || '-',
+      projectUnit: data.projectUnit || '-',
+      productType: data.productType || '-',
+      productDesc: data.productDesc || '-',
     }
-  ]
 
-  // 娣诲姞妯℃嫙浜ゆ槗淇℃伅澶囨敞鏁版嵁
-  remarkItems.value = (detail.items || []).map((item: any, index: number) => ({ 
-    name: item.name,
-    start: '2025-06-01', 
-    end: index === 0 || index === 3 ? '' : '2025-06-01', 
-    forever: index === 0 || index === 3, 
-    remark: index === 3 ? '寮�閫氱鐞嗗憳璐﹀彿1涓�,璐﹀彿admin' : '寮�閫氱鐞嗗憳璐﹀彿1涓�,璐﹀彿admin,鐧诲綍绠$悊鍛樿处鍙峰彲绠$悊鏅�氱敤鎴�' 
-  }))
-  
-  // 娉ㄩ噴鎺夊師鏈夌殑API璋冪敤锛屼娇鐢ㄦā鎷熸暟鎹�
-  // const { data } = (await fetchOrderDetail({ id: route.params.id })) as any
-  // Object.assign(detail, data || {})
+    // 鏄庣粏椤规槧灏�
+    const items: any[] = Array.isArray(data.orderDetails)
+      ? data.orderDetails.map((d: any, idx: number) => {
+          const pt = normalizePriceType(d.priceType)
+          return {
+            id: String(d.id ?? idx + 1),
+            name: d.suiteName,
+            saleType: d.salesForm,
+            accountCount: d.accountLimit,
+            customerTarget: d.customerType,
+            concurrentNodes: d.concurrentNodes,
+            pricePoint: pt === 'points' ? Number(d.unitPrice || 0) : 0,
+            priceCash: pt === 'currency' ? Number(d.unitPrice || 0) : 0,
+            priceProtocol: pt === 'agreement',
+            quantity: Number(d.quantity || 0),
+            period: Number(d.duration || 0),
+            remarks: d.remarks || '', // 鏂板 remarks 瀛楁
+          }
+        })
+      : []
+
+    // 姹囨�伙紙绠�鍗曠浉鍔狅細鍗曚环*鏁伴噺锛�
+    const pointTotalNum = items.reduce((sum, it) => sum + Number(it.pricePoint || 0) * Number(it.quantity || 0), 0)
+    const cashTotalNum = items.reduce((sum, it) => sum + Number(it.priceCash || 0) * Number(it.quantity || 0), 0)
+
+    Object.assign(detail, head, {
+      items,
+      pointTotal: pointTotalNum.toLocaleString(),
+      cashTotal: cashTotalNum.toLocaleString(),
+    })
+
+    // 鍒濆鍖栬〃鍗曟暟鎹�
+    form.items = (detail.items || []).map((item: any, index: number) => {
+      // 璁$畻鎺堟潈缁撴潫鏃堕棿
+      let endDate = ''
+      if (item.period > 0) {
+        // 濡傛灉鏈夋湡闄愶紝璁$畻缁撴潫鏃堕棿
+        const startDate = new Date(data.applyTime || new Date())
+        const endDateObj = new Date(startDate)
+        endDateObj.setFullYear(endDateObj.getFullYear() + item.period)
+        endDate = endDateObj.toISOString().split('T')[0] // 鏍煎紡鍖栦负 YYYY-MM-DD
+      }
+      
+      return { 
+        name: item.name,
+        start: data.applyTime ? data.applyTime.split('T')[0] : '', // 浣跨敤璁㈠崟鐢宠鏃堕棿
+        end: endDate, 
+        forever: item.period === 0, // 鏈熼檺涓�0鏃惰缃负姘镐箙
+        remark: item.remarks || '' // 浣跨敤濂椾欢淇℃伅涓殑remarks瀛楁
+      }
+    })
+
+    // 鑾峰彇璁㈠崟闄勪欢鍒楄〃锛堝鏋滄湁鐨勮瘽锛�
+    if (data.attachments && Array.isArray(data.attachments)) {
+      fileList.value = data.attachments.map((file: any) => ({
+        name: file.fileName || file.originalName,
+        size: file.fileSize || 0,
+        uid: file.id,
+        status: 'success',
+        url: file.fileUrl,
+        uploaded: true
+      }))
+    } else {
+      fileList.value = []
+    }
+  } catch (error) {
+    console.error('鑾峰彇璁㈠崟璇︽儏澶辫触:', error)
+    ElMessage.error('鑾峰彇璁㈠崟璇︽儏澶辫触')
+  }
 })
 
 const goBack = () => router.back()
 const submit = async () => {
-  await formRef.value?.validate()
-  
-  // 妯℃嫙鎻愪氦鎴愬姛鍝嶅簲
-  const mockResponse = { code: 200 }
-  
-  // 娉ㄩ噴鎺夊師鏈夌殑API璋冪敤锛屼娇鐢ㄦā鎷熸暟鎹�
-  // const { code } = (await submitEvaluate({ id: route.params.id, ...form })) as any
-  
-  if (mockResponse.code === 200) {
-    ElMessage.success('鎻愪氦鎴愬姛')
-    router.back()
+  try {
+    const orderId = String(route.params.id || '')
+    const userId = userStore.getUserId ? Number(userStore.getUserId) : undefined
+    
+    if (!orderId || !userId) {
+      ElMessage.error('璁㈠崟ID鎴栫敤鎴稩D涓嶈兘涓虹┖')
+      return
+    }
+
+    // 纭鎿嶄綔
+    await ElMessageBox.confirm('纭畾瑕佺‘璁や氦鏄撳苟鎻愪氦瀹℃壒鍚楋紵', '纭鎿嶄綔', {
+      confirmButtonText: '纭畾',
+      cancelButtonText: '鍙栨秷',
+      type: 'warning'
+    })
+
+    // 璋冪敤鏇存柊璁㈠崟璇︽儏API锛屽皢鐘舵�佹洿鏂颁负"宸茶瘎浠�"
+    const updateData = {
+      orderId: orderId,
+      orderStatus: '宸茶瘎浠�', // 鏇存柊涓哄凡璇勪环鐘舵��
+      orderDetails: detail.items.map((item: any) => ({
+        id: item.id,
+        remarks: item.remarks || '' // 浣跨敤濂椾欢淇℃伅涓殑remarks瀛楁
+      }))
+    }
+
+    const res = (await orderApi.updateOrderDetail(updateData)) as any
+    
+    if (res?.code === 200) {
+      ElMessage.success('浜ゆ槗纭鎴愬姛锛屽凡鎻愪氦瀹℃壒')
+      router.back()
+    } else {
+      ElMessage.error(res?.msg || '浜ゆ槗纭澶辫触')
+    }
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('浜ゆ槗纭澶辫触:', error)
+      ElMessage.error('浜ゆ槗纭澶辫触')
+    }
   }
 }
 
@@ -481,15 +612,6 @@
 // 鏂囦欢鍒楄〃琛ㄦ牸琛ㄤ綋鏂囧瓧澶у皬
 const fileTableCellStyle: CSSProperties = { fontSize: '12px' }
 
-// 浜ゆ槗淇℃伅澶囨敞琛ㄦ牸琛ㄥご鏂囧瓧灞呬腑锛屼絾绗竴鍒楃殑"浜ゆ槗淇℃伅澶囨敞"鏂囧瓧闈犲乏瀵归綈
-const remarkTableHeaderStyle: CSSProperties = { 
-  textAlign: 'center',
-  fontSize: '14px',
-  background: '#f3f6fb'
-}
-// 浜ゆ槗淇℃伅澶囨敞琛ㄦ牸琛ㄤ綋鏂囧瓧澶у皬
-const remarkTableCellStyle: CSSProperties = { fontSize: '12px' }
-
 // 鏂囦欢澶у皬鏍煎紡鍖�
 const formatFileSize = (size: number) => {
   if (!size || size === 0) return '0 Bytes';
@@ -499,10 +621,265 @@
   return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
 };
 
-// 鏂囦欢棰勮澶勭悊
-const handlePreview = (file: any) => {
-  ElMessage.info(`棰勮鏂囦欢锛�${file.name}`)
+// 鍒ゆ柇鏂囦欢鏄惁鍙瑙�
+const isPreviewable = (file: any) => {
+  // 棣栧厛妫�鏌IME绫诲瀷
+  const previewableTypes = [
+    'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/bmp', 'image/webp',
+    'text/plain', 'text/html', 'text/css', 'text/javascript',
+    'application/pdf',
+    'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
+    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
+    'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
+  ]
+  
+  // 濡傛灉MIME绫诲瀷鍖归厤锛岀洿鎺ヨ繑鍥瀟rue
+  if (previewableTypes.includes(file.type || '')) {
+    return true
+  }
+  
+  // 濡傛灉MIME绫诲瀷涓虹┖鎴栦笉鍖归厤锛屾牴鎹枃浠舵墿灞曞悕鍒ゆ柇
+  const fileName = file.name || ''
+  const fileExtension = fileName.toLowerCase().split('.').pop()
+  
+  const previewableExtensions = [
+    'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp',
+    'txt', 'html', 'htm', 'css', 'js',
+    'pdf',
+    'docx', 'xlsx', 'pptx'
+  ]
+  
+  return previewableExtensions.includes(fileExtension)
 }
+
+// 鍒ゆ柇鏂囦欢鏄惁宸蹭笂浼犳垚鍔�
+const isFileUploaded = (file: any) => {
+  // 鏂囦欢鏈塽rl涓旂姸鎬佷负success琛ㄧず宸蹭笂浼犳垚鍔�
+  return file.url && (file.status === 'success' || file.uploaded)
+}
+
+// 鏂囦欢棰勮
+const handlePreview = async (file: any) => {
+  if (!file.url) {
+    ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�')
+    return
+  }
+  
+  // 鑾峰彇鏂囦欢鎵╁睍鍚�
+  const fileName = file.name || ''
+  const fileExtension = fileName.toLowerCase().split('.').pop()
+  
+  let previewUrl = file.url
+  
+  // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼紭鍏堜娇鐢ㄩ瑙圲RL
+  if (file.url.includes('order-attachments')) {
+    try {
+      // 棣栧厛灏濊瘯鑾峰彇棰勮URL
+      const previewResponse = await createAxios({
+        url: `/admin/file/preview`,
+        method: 'GET',
+        params: {
+          fileName: file.url
+        }
+      })
+      
+      console.log('棰勮URL鍝嶅簲:', previewResponse)
+      
+      // 妫�鏌ュ搷搴旀牸寮�
+      const responseData = previewResponse as any
+      if (responseData && responseData.code === 200 && responseData.data) {
+        previewUrl = responseData.data
+        console.log('浣跨敤棰勮URL:', previewUrl)
+      } else {
+        console.log('棰勮URL鑾峰彇澶辫触锛屼娇鐢ㄤ笅杞芥柟寮�')
+        // 濡傛灉棰勮URL鑾峰彇澶辫触锛屽洖閫�鍒颁笅杞芥柟寮�
+        const response = await createAxios({
+          url: `/admin/file/download`,
+          method: 'GET',
+          responseType: 'blob',
+          params: {
+            fileName: file.url,
+            originalName: file.name
+          }
+        })
+        
+        // 鍒涘缓棰勮URL
+        const blob = new Blob([response as any])
+        previewUrl = window.URL.createObjectURL(blob)
+        console.log('浣跨敤Blob URL:', previewUrl)
+      }
+    } catch (error) {
+      console.error('鑾峰彇鏂囦欢澶辫触:', error)
+      ElMessage.error('鑾峰彇鏂囦欢澶辫触锛屾棤娉曢瑙�')
+      return
+    }
+  }
+  
+  // 鍥剧墖鏂囦欢鐩存帴鍦ㄦ柊绐楀彛鎵撳紑
+  if ((file.type && file.type.startsWith('image/')) || 
+      ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExtension)) {
+    console.log('棰勮鍥剧墖鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // PDF鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑
+  if (file.type === 'application/pdf' || fileExtension === 'pdf') {
+    console.log('棰勮PDF鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // 鏂囨湰鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑
+  if ((file.type && file.type.startsWith('text/')) || 
+      ['txt', 'html', 'htm', 'css', 'js'].includes(fileExtension)) {
+    console.log('棰勮鏂囨湰鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // Office鏂囨。鍜屽叾浠栨枃浠剁被鍨嬶紝灏濊瘯鍦ㄦ柊绐楀彛鎵撳紑
+  try {
+    console.log('棰勮鍏朵粬鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+  } catch (error) {
+    console.error('棰勮澶辫触:', error)
+    ElMessage.error('棰勮澶辫触锛岃涓嬭浇鍚庢煡鐪�')
+  }
+}
+
+// 鏂囦欢涓嬭浇
+const handleDownload = async (file: any) => {
+  if (!file.url) {
+    ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�')
+    return
+  }
+  
+  console.log('寮�濮嬩笅杞芥枃浠�:', file.name, 'URL:', file.url)
+  
+  try {
+    // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼娇鐢ㄥ悗绔洿鎺ヤ笅杞紸PI
+    if (file.url.includes('order-attachments')) {
+      console.log('浣跨敤MinIO涓嬭浇API')
+      
+      // 浣跨敤axios閫氳繃浠g悊璁块棶鍚庣API
+      const response = await createAxios({
+        url: `/admin/file/download`,
+        method: 'GET',
+        responseType: 'blob',
+        params: {
+          fileName: file.url,
+          originalName: file.name
+        }
+      })
+      
+      console.log('涓嬭浇鍝嶅簲:', response)
+      
+      // 鍒涘缓涓嬭浇閾炬帴
+      const blob = new Blob([response as any])
+      const downloadUrl = window.URL.createObjectURL(blob)
+      
+      console.log('鍒涘缓涓嬭浇閾炬帴:', downloadUrl)
+      
+      const link = document.createElement('a')
+      link.href = downloadUrl
+      link.download = file.name || 'download'
+      link.target = '_blank'
+      link.rel = 'noopener noreferrer'
+      
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      
+      // 娓呯悊URL瀵硅薄
+      window.URL.revokeObjectURL(downloadUrl)
+      
+      ElMessage.success('鏂囦欢涓嬭浇鎴愬姛')
+    } else {
+      console.log('浣跨敤鐩存帴URL涓嬭浇')
+      // 鍏朵粬鎯呭喌鐩存帴浣跨敤鍘烾RL
+      const link = document.createElement('a')
+      link.href = file.url
+      link.download = file.name || 'download'
+      link.target = '_blank'
+      link.rel = 'noopener noreferrer'
+      
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      
+      ElMessage.success('寮�濮嬩笅杞芥枃浠�')
+    }
+  } catch (error) {
+    console.error('涓嬭浇澶辫触:', error)
+    ElMessage.error('涓嬭浇澶辫触锛岃閲嶈瘯')
+  }
+}
+
+// 鎻愪氦璇勪环澶勭悊
+const handleSubmitEvaluation = async () => {
+  // 楠岃瘉璇勫垎鏄惁宸插~鍐�
+  if (!evaluationForm.overallRating || !evaluationForm.serviceRating || 
+      !evaluationForm.qualityRating || !evaluationForm.speedRating) {
+    ElMessage.warning('璇峰畬鎴愭墍鏈夎瘎鍒嗛」鐩�')
+    return
+  }
+  
+  if (!evaluationForm.content.trim()) {
+    ElMessage.warning('璇疯緭鍏ヨ瘎浠峰唴瀹�')
+    return
+  }
+
+  try {
+    evaluationLoading.value = true
+    await ElMessageBox.confirm('纭畾瑕佹彁浜よ瘎浠峰悧锛�', '纭鎿嶄綔', {
+      confirmButtonText: '纭畾',
+      cancelButtonText: '鍙栨秷',
+      type: 'warning'
+    })
+
+    const orderId = String(route.params.id || '')
+    const userId = userStore.getUserId ? Number(userStore.getUserId) : undefined
+    const content = evaluationForm.content.trim()
+
+    if (!orderId || !userId) {
+      ElMessage.error('璁㈠崟ID鎴栫敤鎴稩D涓嶈兘涓虹┖')
+      evaluationLoading.value = false
+      return
+    }
+
+    // 璋冪敤鎻愪氦璇勪环API
+    const result = await orderApi.submitEvaluation({
+      orderId: orderId,
+      evaluationContent: content,
+      evaluatorId: userId,
+      evaluatorName: evaluationForm.isAnonymous ? '鍖垮悕鐢ㄦ埛' : (userStore.getUserDetail || '绠$悊鍛�'),
+      overallRating: evaluationForm.overallRating,
+      serviceRating: evaluationForm.serviceRating,
+      qualityRating: evaluationForm.qualityRating,
+      speedRating: evaluationForm.speedRating,
+      isAnonymous: evaluationForm.isAnonymous
+    })
+
+    if (result && result.code === 200) {
+      // 鏇存柊璁㈠崟鐘舵�佽繘鍏ヤ笅涓�涓姸鎬�
+      await orderApi.updateOrderStatusToNext(orderId)
+      ElMessage.success('璇勪环鎻愪氦鎴愬姛')
+      router.back()    
+      evaluationLoading.value = false
+    } else {
+      ElMessage.error(result?.msg || '璇勪环鎻愪氦澶辫触')
+    }
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('璇勪环鎻愪氦澶辫触:', error)
+      ElMessage.error('璇勪环鎻愪氦澶辫触')
+    }
+  } finally {
+    evaluationLoading.value = false
+  }
+}
+
 
 // 鐥囩粨涓庝慨澶嶈鏄庯細
 // 1) Element Plus 鐨� el-table 瀛愬垪 width 鐧惧垎姣旀槸鐩稿浜庤〃鏍煎鍣ㄧ殑鍍忕礌瀹藉害璁$畻锛屼絾鍙湁鍦ㄨ〃鏍煎鍣ㄦ湁鏄庣‘瀹藉害鏃舵墠鐢熸晥銆�
@@ -706,36 +1083,152 @@
   text-align: left !important;
 }
 
-/* 浜ゆ槗淇℃伅澶囨敞琛ㄦ牸鏍峰紡 */
-.remark-section {
-  margin-top: 15px;
-  .remark-table {
-    width: 100%;
-    .remark-name {
-      font-weight: 500;
+/* 鏂囦欢鎿嶄綔鎸夐挳鏍峰紡 */
+.file-actions {
+  display: flex;
+  gap: 8px;
+  align-items: center;
+  justify-content: center;
+  
+  .preview-btn {
+    color: #409eff;
+    &:hover {
+      text-decoration: underline;
     }
-    .remark-date {
-      color: #606266;
+    &:disabled {
+      color: #c0c4cc;
+      cursor: not-allowed;
     }
-    .remark-content {
-      color: #606266;
-      line-height: 1.4;
+  }
+  
+  .download-btn {
+    color: #67c23a;
+    &:hover {
+      text-decoration: underline;
+    }
+    &:disabled {
+      color: #c0c4cc;
+      cursor: not-allowed;
     }
   }
 }
 
-/* 浜ゆ槗淇℃伅澶囨敞琛ㄦ牸琛ㄥご绗竴鍒�"浜ゆ槗淇℃伅澶囨敞"鏂囧瓧闈犲乏瀵归綈 */
-.remark-table :deep(.el-table__header-wrapper thead tr th:first-child) {
-  text-align: left !important;
+/* 浜ゆ槗淇℃伅澶囨敞琛ㄦ牸鏍峰紡 */
+.remark-table {
+  width: 100%;
+  .end-time-wrapper {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+    .forever-text {
+      color: #409eff;
+      font-weight: 500;
+    }
+  }
 }
 
-/* 鎿嶄綔鎸夐挳鏍峰紡 */
-.action-buttons {
-  display: flex;
-  justify-content: flex-end;
-  margin-top: 15px;
-  .el-button {
-    margin-left: 10px;
+/* 浜ゆ槗璇勪环鏍峰紡 */
+.evaluation-content {
+  .evaluation-form {
+    /* 璇勫垎閮ㄥ垎鏍峰紡 */
+    .rating-section {
+      margin-bottom: 30px;
+      
+      .rating-title {
+        font-weight: 600;
+        margin-bottom: 15px;
+        color: #303133;
+      }
+      
+             .rating-items {
+         display: flex;
+         flex-direction: column;
+         gap: 20px;
+         
+         .rating-row {
+           display: flex;
+           gap: 40px;
+           
+           .rating-item {
+             flex: 1;
+             display: flex;
+             align-items: center;
+             
+             label {
+               width: 100px;
+               line-height: 32px;
+               margin-right: 15px;
+               font-weight: 500;
+               white-space: nowrap;
+               
+               &.required::before {
+                 content: '*';
+                 color: #f56c6c;
+                 margin-right: 4px;
+               }
+             }
+             
+             .el-rate {
+               flex: 1;
+             }
+           }
+         }
+       }
+    }
+    
+    .form-item {
+      display: flex;
+      align-items: flex-start;
+      margin-bottom: 20px;
+      
+      label {
+        width: 120px;
+        line-height: 32px;
+        margin-right: 10px;
+        font-weight: 500;
+        
+        &.required::before {
+          content: '*';
+          color: #f56c6c;
+          margin-right: 4px;
+        }
+      }
+      
+             .el-textarea {
+         flex: 1;
+       }
+       
+               /* 鍖垮悕閫夐」鏍峰紡 */
+        .anonymous-option {
+          display: flex;
+          align-items: center;
+          gap: 15px;
+          
+          .anonymous-tip {
+            display: flex;
+            align-items: center;
+            gap: 6px;
+            color: #909399;
+            font-size: 12px;
+            
+            .el-icon {
+              color: #409eff;
+              font-size: 14px;
+            }
+          }
+        }
+     }
+   }
+  
+  .evaluation-actions {
+    display: flex;
+    justify-content: center;
+    gap: 15px;
+    margin-top: 30px;
+    
+    .el-button {
+      min-width: 100px;
+    }
   }
 }
 </style>
diff --git a/src/views/tradeManage/seller/index.vue b/src/views/tradeManage/seller/index.vue
index 59d87cb..75068d4 100644
--- a/src/views/tradeManage/seller/index.vue
+++ b/src/views/tradeManage/seller/index.vue
@@ -89,10 +89,6 @@
                       <span class="label">闇�姹傛柟:</span>
                       <span class="value">{{ row.demandSide }}</span>
                     </div>
-                    <div class="order-item">
-                      <span class="label">渚涘簲鏂�:</span>
-                      <span class="value">{{ row.supplySide }}</span>
-                    </div>
                   </div>
                 </div>
                 <div v-else-if="row.isSpacer" class="spacer-cell"></div>
@@ -148,16 +144,16 @@
                 <div v-if="row.isSpacer" class="spacer-cell"></div>
                 <div v-else-if="!row.isMainOrder" class="price-info">
                   <span v-if="row.priceType === 'points'" class="price-points">
-                    {{ row.unitPrice }}
+                    绉垎 {{ row.unitPrice }}
                   </span>
                   <span v-else-if="row.priceType === 'currency'" class="price-currency">
-                    {{ row.unitPrice }}
+                    璐у竵 {{ row.unitPrice }}
                   </span>
                   <span v-else-if="row.priceType === 'agreement'" class="price-agreement">
-                    {{ row.unitPrice }}
+                    鍗忚
                   </span>
                   <span v-else-if="row.priceType === 'free'" class="price-free">
-                    {{ row.unitPrice }}
+                    鍏嶈垂
                   </span>
                 </div>
               </template>
@@ -176,8 +172,8 @@
               <template #default="{ row }">
                 <div v-if="row.isSpacer" class="spacer-cell"></div>
                 <div v-else-if="!row.isMainOrder" class="period-info">
-                  <span>{{ row.period }}</span>
-                  <span v-if="row.isPermanent" class="permanent">姘镐箙</span>
+                  <span v-if="row.period === 0" class="permanent">姘镐箙</span>
+                  <span v-else>{{ row.period }}</span>
                 </div>
               </template>
             </el-table-column>
@@ -192,10 +188,26 @@
                   <div v-if="row.parentOrder && row.parentOrder.subOrders && row.parentOrder.subOrders.findIndex((sub: any) => sub.id === row.id) === 0" class="all-actions">
                     <div class="action-item">
                       <div class="action-buttons">
-                        <span v-if="row.parentOrder.status === 'WAIT_CONFIRM'" class="op-text warning">寰呬氦鏄撶‘璁�</span>
-                        <span v-else-if="row.parentOrder.status === 'WAIT_EVALUATE'" class="op-text warning">寰呰瘎浠�</span>
-                        <span v-else-if="row.parentOrder.status === 'FINISH'" class="op-text">宸插畬鎴�</span>
-                        <el-button type="primary" link size="small" @click="toDetail(row.parentOrder)">鏌ョ湅</el-button>
+                        <template v-for="action in getAvailableActions(row.parentOrder)" :key="action.type">
+                          <el-button 
+                            v-if="action.type === ActionType.VIEW"
+                            type="primary" 
+                            link 
+                            size="small" 
+                            @click="handleAction(action, row.parentOrder)"
+                          >
+                            鏌ョ湅
+                          </el-button>
+                          <el-button 
+                            v-else-if="action.type === ActionType.TRACK"
+                            type="primary" 
+                            link 
+                            size="small" 
+                            @click="handleAction(action, row.parentOrder)"
+                          >
+                            杩借釜
+                          </el-button>
+                        </template>
                       </div>
                     </div>
                   </div>
@@ -219,6 +231,12 @@
         />
       </div>
     </el-card>
+    
+    <!-- 璁㈠崟鐘舵�佸璇濇 -->
+    <ProductOrderStatusDialog 
+      v-model="orderStatusDialogVisible" 
+      :order-id="currentOrderId" 
+    />
   </div>
 </template>
 
@@ -226,15 +244,23 @@
 import { onMounted, reactive, ref } from 'vue'
 import { useRouter } from 'vue-router'
 import { Search, Refresh } from '@element-plus/icons-vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import orderApi from '@/api/orderApi'
+import { useUserInfo } from '@/stores/modules/userInfo'
+import ProductOrderStatusDialog from '@/views/productManage/productOrderStatusDialog/index.vue'
+import { OrderWorkflowController, OrderStatus, ActionType, PageType, StatusMapper } from '@/utils/orderWorkflow'
 
 const router = useRouter()
+const userStore = useUserInfo()
 
-// 鐘舵�侀�夐」
+// 鐘舵�侀�夐」锛堟洿鏂颁负鏂扮殑宸ヤ綔娴佺▼鐘舵�侊級
 const statusOptions = [
   { label: '鍏ㄩ儴', value: '' },
+  { label: '寰呬笂浼犳枃浠�', value: 'WAIT_UPLOAD' },
+  { label: '寰呮巿鏉�', value: 'WAIT_AUTHORIZE' },
   { label: '寰呬氦鏄撶‘璁�', value: 'WAIT_CONFIRM' },
-  { label: '寰呰瘎浠�', value: 'WAIT_EVALUATE' },
-  { label: '宸插畬鎴�', value: 'FINISH' },
+  { label: '宸插畬鎴�', value: 'COMPLETED' },
+  { label: '宸茶瘎浠�', value: 'EVALUATED' },
 ]
 
 // 琛屼笟棰嗗煙閫夐」
@@ -282,215 +308,54 @@
 // 鍒嗛〉淇℃伅
 const page = reactive({ current: 1, size: 10, total: 0 })
 
-// 璁㈠崟鍒楄〃鏁版嵁
+// 璁㈠崟鍒楄〃鏁版嵁锛堝寘鍚富璁㈠崟鍜屽瓙璁㈠崟锛�
 const orderList = ref<any[]>([])
 
-// 妯℃嫙鏁版嵁鐢ㄤ簬灞曠ず
-const mockData = [
-  {
-    id: '1',
-    isMainOrder: true,
-    applyTime: '2025-05-21 10:00:00',
-    orderNo: '4348442557619205545',
-    demandSide: '涓浗璺ˉ宸ョ▼鏈夐檺鍏徃',
-    supplySide: '涓氦鏂硅繙绉戞妧鏈夐檺鍏徃',
-    status: 'WAIT_CONFIRM',
-    statusName: '寰呬氦鏄撶‘璁�',
-    subOrders: [
-      {
-        id: '1-1',
-        isMainOrder: false,
-        productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-        suiteName: '浼佷笟绉佹湁SaaS鐗堣鍙�',
-        salesForm: '涔版柇',
-        accountCount: 50,
-        demandSide: '涓浗璺ˉ宸ョ▼鏈夐檺鍏徃',
-        customerObject: '浼佷笟',
-        concurrentCount: 50,
-        priceType: 'points',
-        unitPrice: '绉垎: 50,000/濂�',
-        quantity: 1,
-        period: 1,
-        isPermanent: true,
-        status: 'WAIT_CONFIRM',
-      },
-      {
-        id: '1-2',
-        isMainOrder: false,
-        productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-        suiteName: '浼佷笟绉佹湁SaaS鐗圤TA鍗囩骇鏈嶅姟',
-        salesForm: 'OTA鏈嶅姟',
-        accountCount: 50,
-        demandSide: '涓浗璺ˉ宸ョ▼鏈夐檺鍏徃',
-        customerObject: '浼佷笟',
-        concurrentCount: 50,
-        priceType: 'currency',
-        unitPrice: '璐у竵: 7,500/濂�/骞�',
-        quantity: 1,
-        period: 1,
-        isPermanent: false,
-        status: 'WAIT_CONFIRM',
-      },
-      {
-        id: '1-3',
-        isMainOrder: false,
-        productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-        suiteName: '浼佷笟绉佹湁SaaS鐗堢敤鎴峰閲忓寘',
-        salesForm: '绉佹湁澧為噺鍖�',
-        accountCount: 100,
-        demandSide: '涓浗璺ˉ宸ョ▼鏈夐檺鍏徃',
-        customerObject: '浼佷笟',
-        concurrentCount: 100,
-        priceType: 'agreement',
-        unitPrice: '鍗忚:/骞�',
-        quantity: 1,
-        period: 1,
-        isPermanent: false,
-        status: 'WAIT_CONFIRM',
-      },
-      {
-        id: '1-4',
-        isMainOrder: false,
-        productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-        suiteName: '涓汉鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉佹湁澧為噺鍖�',
-        accountCount: 50,
-        demandSide: '涓浗璺ˉ宸ョ▼鏈夐檺鍏徃',
-        customerObject: '涓汉',
-        concurrentCount: 50,
-        priceType: 'free',
-        unitPrice: '鍏嶈垂:/骞�',
-        quantity: 3,
-        period: 3,
-        isPermanent: true,
-        status: 'WAIT_CONFIRM',
-      },
-    ],
-  },
-  {
-    id: '2',
-    isMainOrder: true,
-    applyTime: '2025-05-20 10:00:00',
-    orderNo: '4347442557619205545',
-    demandSide: '涓氦鍏矾瑙勫垝璁捐闄㈡湁闄愬叕鍙�',
-    supplySide: '鍗庝负杞欢鎶�鏈湁闄愬叕鍙�',
-    status: 'WAIT_CONFIRM',
-    statusName: '寰呬氦鏄撶‘璁�',
-    subOrders: [
-      {
-        id: '2-1',
-        isMainOrder: false,
-        productName: '鍩轰簬鍥戒骇鑺墖瀹界獎铻嶅悎鑷粍缃戣澶囩殑搴旂敤',
-        suiteName: '浼佷笟鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉熻祦',
-        accountCount: 100,
-        demandSide: '涓氦鍏矾瑙勫垝璁捐闄㈡湁闄愬叕鍙�',
-        customerObject: '浼佷笟',
-        concurrentCount: 100,
-        priceType: 'currency',
-        unitPrice: '璐у竵: 80,000/骞�',
-        quantity: 1,
-        period: 2,
-        isPermanent: false,
-        status: 'WAIT_CONFIRM',
-      },
-    ],
-  },
-  {
-    id: '3',
-    isMainOrder: true,
-    applyTime: '2025-05-19 10:00:00',
-    orderNo: '4347342557619205545',
-    demandSide: '涓氦绗洓鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-    supplySide: '涓氦绗洓鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-    status: 'WAIT_CONFIRM',
-    statusName: '寰呬氦鏄撶‘璁�',
-    subOrders: [
-      {
-        id: '3-1',
-        isMainOrder: false,
-        productName: '楂樻々鐮佸ご杈呭姪鍑哄浘宸ュ叿绠�',
-        suiteName: '椤圭洰鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉熻祦',
-        accountCount: 50,
-        demandSide: '涓氦绗洓鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-        customerObject: '椤圭洰閮�',
-        concurrentCount: 50,
-        priceType: 'currency',
-        unitPrice: '璐у竵: 60,000/骞�',
-        quantity: 1,
-        period: 3,
-        isPermanent: false,
-        status: 'WAIT_CONFIRM',
-      },
-    ],
-  },
-  {
-    id: '4',
-    isMainOrder: true,
-    applyTime: '2025-05-18 10:00:00',
-    orderNo: '4347442557619205545',
-    demandSide: '涓氦鍏矾瑙勫垝璁捐闄㈡湁闄愬叕鍙�',
-    supplySide: '涓氦鍏矾瑙勫垝璁捐闄㈡湁闄愬叕鍙�',
-    status: 'WAIT_EVALUATE',
-    statusName: '寰呰瘎浠�',
-    subOrders: [
-      {
-        id: '4-1',
-        isMainOrder: false,
-        productName: '鍏矾鏁板瓧鍖栨柟妗堣璁$郴缁�',
-        suiteName: '浼佷笟鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉熻祦',
-        accountCount: 100,
-        demandSide: '涓氦鍏矾瑙勫垝璁捐闄㈡湁闄愬叕鍙�',
-        customerObject: '浼佷笟',
-        concurrentCount: 100,
-        priceType: 'currency',
-        unitPrice: '璐у竵: 80,000/骞�',
-        quantity: 1,
-        period: 1,
-        isPermanent: false,
-        status: 'WAIT_EVALUATE',
-      },
-    ],
-  },
-  {
-    id: '5',
-    isMainOrder: true,
-    applyTime: '2025-05-17 10:00:00',
-    orderNo: '4347342557619205545',
-    demandSide: '涓氦绗洓鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-    supplySide: '涓氦绗笁鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-    status: 'FINISH',
-    statusName: '宸插畬鎴�',
-    subOrders: [
-      {
-        id: '5-1',
-        isMainOrder: false,
-        productName: '鍩轰簬鏃犱汉鏈虹殑浼佷笟绾у彲瑙嗗寲椤圭洰绠$悊绯荤粺',
-        suiteName: '椤圭洰鍏湁SaaS鐗堣鍙�',
-        salesForm: '绉熻祦',
-        accountCount: 50,
-        demandSide: '涓氦绗洓鑸姟宸ョ▼灞�鏈夐檺鍏徃',
-        customerObject: '椤圭洰閮�',
-        concurrentCount: 50,
-        priceType: 'free',
-        unitPrice: '鍏嶈垂:/骞�',
-        quantity: 1,
-        period: 1,
-        isPermanent: true,
-        status: 'FINISH',
-      },
-    ],
-  },
-]
+// 璁㈠崟鐘舵�佸璇濇鐩稿叧
+const orderStatusDialogVisible = ref(false)
+const currentOrderId = ref<string>('')
+
+// 浣跨敤宸ヤ綔娴佺▼鎺у埗鍣ㄧ殑鐘舵�佹槧灏�
+const statusUiToServer: Record<string, string> = {
+  WAIT_UPLOAD: OrderStatus.WAIT_UPLOAD,
+  WAIT_AUTHORIZE: OrderStatus.WAIT_AUTHORIZE,
+  WAIT_CONFIRM: OrderStatus.WAIT_CONFIRM,
+  COMPLETED: OrderStatus.COMPLETED,
+  EVALUATED: OrderStatus.EVALUATED,
+}
+
+const statusServerToUi: Record<string, string> = {
+  [OrderStatus.WAIT_UPLOAD]: 'WAIT_UPLOAD',
+  [OrderStatus.WAIT_AUTHORIZE]: 'WAIT_AUTHORIZE',
+  [OrderStatus.WAIT_CONFIRM]: 'WAIT_CONFIRM',
+  [OrderStatus.COMPLETED]: 'COMPLETED',
+  [OrderStatus.EVALUATED]: 'EVALUATED',
+}
+
+const formatDateTime = (val?: string) => {
+  if (!val) return ''
+  return val.replace('T', ' ').slice(0, 19)
+}
+
+const normalizePriceType = (val?: string): 'points' | 'currency' | 'agreement' | 'free' => {
+  if (!val) return 'currency'
+  const s = String(val)
+  if (/(绉垎|points)/i.test(s)) return 'points'
+  if (/(鍗忚|agreement)/i.test(s)) return 'agreement'
+  if (/(鍏嶈垂|free)/i.test(s)) return 'free'
+  return 'currency'
+}
+
+
 
 // 鑾峰彇鐘舵�佺被鍨�
 const getStatusType = (status: string) => {
   const statusMap: Record<string, 'warning' | 'danger' | 'success' | 'info'> = {
+    WAIT_UPLOAD: 'warning',
+    WAIT_AUTHORIZE: 'warning',
     WAIT_CONFIRM: 'warning',
-    WAIT_EVALUATE: 'warning',
-    FINISH: 'success',
+    COMPLETED: 'success',
+    EVALUATED: 'success',
   }
   return statusMap[status] || 'info'
 }
@@ -574,23 +439,90 @@
   }
 }
 
-// 鎼滅储澶勭悊
+// 鎼滅储澶勭悊锛堟帴鍏ョ湡瀹炲悗绔級
 const handleSearch = async () => {
-  // 浣跨敤妯℃嫙鏁版嵁
-  const flatData: any[] = []
-  mockData.forEach(order => {
-    flatData.push(order)
-    if (order.subOrders) {
-      order.subOrders.forEach((subOrder: any) => {
-        flatData.push({ ...subOrder, parentOrder: order })
-      })
+  try {
+    // 鑾峰彇鐢ㄦ埛ID浣滀负providerId锛屽鏋滄病鏈夊垯浣跨敤榛樿鍊�
+    const userId = userStore.getUserId
+    const providerId = userId ? Number(userId) : 1 // 浣跨敤榛樿鍊�1浣滀负涓存椂瑙e喅鏂规
+
+    const payload: any = {
+      pageNum: page.current,
+      pageSize: page.size,
+      productName: query.productName || undefined,
+      orderId: query.orderNo || undefined,
+      providerId: providerId,
     }
-    // 鍦ㄦ瘡涓鍗曞潡鐨勬湯灏炬彃鍏ヤ竴涓垎闅旂┖琛�
-    flatData.push({ isSpacer: true, isMainOrder: false, parentOrder: order })
-  })
-  
-  orderList.value = flatData
-  page.total = mockData.length
+    if (query.status) payload.orderStatus = statusUiToServer[query.status]
+    if (Array.isArray(query.dateRange) && query.dateRange.length === 2) {
+      payload.applyTimeStart = query.dateRange[0]
+      payload.applyTimeEnd = query.dateRange[1]
+    }
+
+    const res = (await orderApi.getSellerOrderPage(payload)) as any
+    const pageData = res?.data
+    const list: any[] = Array.isArray(pageData?.list) ? pageData.list : []
+    page.total = Number(pageData?.total || 0)
+
+    // 骞跺彂鑾峰彇姣忎釜璁㈠崟鐨勮鎯咃紙鐢ㄤ簬鏋勯�犲瓙璁㈠崟琛岋級
+    const detailsArr = await Promise.all(
+      list.map(async (order: any) => {
+        try {
+          const detailRes = (await orderApi.getOrderDetail(order.orderId)) as any
+          return detailRes?.data
+        } catch (e) {
+          return null
+        }
+      })
+    )
+
+    const flatData: any[] = []
+    list.forEach((order: any, idx: number) => {
+      const uiStatus = statusServerToUi[order.orderStatus] || 'WAIT_UPLOAD'
+      const mainRow: any = {
+        id: order.orderId,
+        isMainOrder: true,
+        applyTime: formatDateTime(order.applyTime || ''),
+        orderNo: order.orderId,
+        demandSide: order.demandSideName || '',
+        supplySide: order.providerName || '',
+        status: uiStatus,
+        statusName: order.orderStatus || '',
+        orderStatus: StatusMapper.toUIStatus(order.orderStatus), // 杞崲涓烘爣鍑嗙姸鎬佹灇涓�
+      }
+
+      const detail = detailsArr[idx]
+      const subOrders: any[] = Array.isArray(detail?.orderDetails)
+        ? detail.orderDetails.map((d: any, i: number) => ({
+            id: `${order.orderId}-${i + 1}`,
+            isMainOrder: false,
+            productName: order.productName || '',
+            suiteName: d.suiteName,
+            salesForm: d.salesForm,
+            accountCount: d.accountLimit,
+            customerObject: d.customerType,
+            concurrentCount: d.concurrentNodes,
+            priceType: normalizePriceType(d.priceType),
+            unitPrice: d.unitPrice,
+            quantity: d.quantity,
+            period: d.duration,
+          }))
+        : []
+
+      ;(mainRow as any).subOrders = subOrders
+
+      flatData.push(mainRow)
+      subOrders.forEach((sub) => flatData.push({ ...sub, parentOrder: mainRow }))
+      flatData.push({ isSpacer: true, isMainOrder: false, parentOrder: mainRow })
+    })
+
+    orderList.value = flatData
+  } catch (error: any) {
+    console.error('鏌ヨ鍗栧璁㈠崟鍒楄〃澶辫触:', error)
+    ElMessage.error(error?.message || '鏌ヨ鍗栧璁㈠崟鍒楄〃澶辫触')
+    orderList.value = []
+    page.total = 0
+  }
 }
 
 // 閲嶇疆
@@ -609,6 +541,32 @@
   handleSearch()
 }
 
+// 鑾峰彇鍙敤鎿嶄綔鍒楄〃
+const getAvailableActions = (order: any) => {
+  if (!order.orderStatus) return []
+  return OrderWorkflowController.getAvailableActions(PageType.SELLER_CENTER, order.orderStatus)
+}
+
+// 杩借釜璁㈠崟 - 鏄剧ず璁㈠崟鐘舵�佸璇濇
+const showOrderTrack = (row: any) => {
+  currentOrderId.value = row.id
+  orderStatusDialogVisible.value = true
+}
+
+// 澶勭悊鎿嶄綔鐐瑰嚮
+const handleAction = (action: any, order: any) => {
+  switch (action.type) {
+    case ActionType.VIEW:
+      toDetail(order)
+      break
+    case ActionType.TRACK:
+      showOrderTrack(order)
+      break
+    default:
+      console.warn('鏈煡鐨勬搷浣滅被鍨�:', action.type)
+  }
+}
+
 // 璺敱璺宠浆
 const toDetail = (row: any) => router.push({ name: 'tradeOrderDetail', params: { id: row.id } })
 
diff --git a/src/views/tradeManage/upload/index.vue b/src/views/tradeManage/upload/index.vue
index 344e497..eceaea1 100644
--- a/src/views/tradeManage/upload/index.vue
+++ b/src/views/tradeManage/upload/index.vue
@@ -163,6 +163,7 @@
           :on-exceed="onExceed"
           :on-remove="handleRemove"
           :show-file-list="false"
+          :before-upload="beforeUpload"
         >
           <el-button type="primary">閫夋嫨鏂囦欢</el-button>
         </el-upload>
@@ -190,16 +191,47 @@
               {{ formatFileSize(row.size) }}
             </template>
           </el-table-column>
-          <el-table-column label="鎿嶄綔" width="100">
+          <el-table-column label="鎿嶄綔" width="280">
             <template #default="{ row, $index }">
-              <el-button
-                type="text"
-                size="small"
-                class="delete-btn"
-                @click="handleRemove(row, fileList)"
-              >
-                鍒犻櫎
-              </el-button>
+              <div class="file-actions">
+                <el-button
+                  type="text"
+                  size="small"
+                  class="upload-btn"
+                  @click="handleUpload(row)"
+                  v-if="!row.status || row.status === 'ready'"
+                  :loading="row.uploading"
+                >
+                  {{ row.uploading ? '涓婁紶涓�' : '涓婁紶' }}
+                </el-button>
+                <el-button
+                  type="text"
+                  size="small"
+                  class="preview-btn"
+                  @click="handlePreview(row)"
+                  v-if="isPreviewable(row)"
+                  :disabled="!isFileUploaded(row)"
+                >
+                  棰勮
+                </el-button>
+                <el-button
+                  type="text"
+                  size="small"
+                  class="download-btn"
+                  @click="handleDownload(row)"
+                  :disabled="!isFileUploaded(row)"
+                >
+                  涓嬭浇
+                </el-button>
+                <el-button
+                  type="text"
+                  size="small"
+                  class="delete-btn"
+                  @click="handleRemove(row, fileList)"
+                >
+                  鍒犻櫎
+                </el-button>
+              </div>
             </template>
           </el-table-column>
         </el-table>
@@ -218,11 +250,15 @@
 import { onMounted, reactive, ref, computed, type CSSProperties } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import { Document, User, Goods, List } from '@element-plus/icons-vue'
-import { fetchOrderDetail, uploadTradeFile } from '@/api/tradeManage'
-import { ElMessage } from 'element-plus'
+import { uploadTradeFile } from '@/api/tradeManage'
+import orderApi from '@/api/orderApi'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { useUserInfo } from '@/stores/modules/userInfo'
+import createAxios from '@/utils/axios'
 
 const route = useRoute()
 const router = useRouter()
+const userStore = useUserInfo()
 const detail = reactive<any>({ items: [] })
 const fileList = ref<any[]>([])
 const orderTableWrapRef = ref<HTMLElement | null>(null)
@@ -247,116 +283,319 @@
   return [...detail.items, summaryRow]
 })
 
+// 鐘舵�佹槧灏勶紙鍚庣涓枃 -> 鍓嶇鏋氫妇锛�
+const statusServerToUi: Record<string, string> = {
+  '寰呬笂浼犳枃浠�': 'WAIT_UPLOAD',
+  '寰呮巿鏉�': 'WAIT_AUTHORIZE',
+  '寰呬氦鏄撶‘璁�': 'WAIT_CONFIRM',
+  '宸插畬鎴�': 'COMPLETED',
+  '宸茶瘎浠�': 'EVALUATED',
+}
+
+const formatDateTime = (val?: string) => (val ? val.replace('T', ' ').slice(0, 19) : '')
+
+const normalizePriceType = (val?: string): 'points' | 'currency' | 'agreement' | 'free' => {
+  if (!val) return 'currency'
+  const s = String(val)
+  if (/(绉垎|points)/i.test(s)) return 'points'
+  if (/(鍗忚|agreement)/i.test(s)) return 'agreement'
+  if (/(鍏嶈垂|free)/i.test(s)) return 'free'
+  return 'currency'
+}
+
 onMounted(async () => {
-  // 浣跨敤鍓嶇妯℃嫙鏁版嵁浠ヤ究寮�鍙� UI锛堜笉鏀瑰姩鍚庣鏈嶅姟锛�
-  const mockDetail = {
-    orderNo: '4348442557619205545',
-    resourceTypeName: '杞欢浜у搧',
-    status: 'WAIT_UPLOAD',
-    statusName: '寰呬笂浼犳枃浠�',
-    applyTime: '2025-05-21 10:00:00',
-    unitName: '涓氦鏂硅繙寤鸿鏈夐檺鍏徃',
-    userName: '寮犻潤',
-    userAccount: 'L20159922',
-    userDept: '淇℃伅涓績',
-    userPhone: '13800000000',
-    productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺',
-    supplier: '涓氦鏂硅繙绉戞妧鏈夐檺鍏徃',
-    industry: '寤虹瓚宸ョ▼',
-    projectUnit: '鍦熷缓宸ョ▼',
-    productType: '杞欢搴�',
-    productDesc:
-      '闈㈠悜宸ョ▼椤圭洰鐨勮川閲忓疄娴嬪疄閲忔暟瀛楀寲绠$悊绯荤粺锛屾敮鎸佹爣鍑嗗寲閲囬泦銆佽嚜鍔ㄧ粺璁′笌杩囩▼绠℃帶銆�',
-    items: [
-      {
-        id: '1',
-        name: '浼佷笟绉佹湁SaaS鐗堣鍙�',
-        saleType: '涔版柇',
-        accountCount: 50,
-        customerTarget: '浼佷笟',
-        concurrentNodes: 50,
-        pricePoint: 50000,
-        priceCash: 0,
-        quantity: 1,
-        period: 0,
-      },
-      {
-        id: '2',
-        name: '浼佷笟绉佹湁SaaS鐗圤TA鍗囩骇鏈嶅姟',
-        saleType: 'OTA鏈嶅姟',
-        accountCount: 50,
-        customerTarget: '浼佷笟',
-        concurrentNodes: 50,
-        pricePoint: 0,
-        priceCash: 7500,
-        quantity: 1,
-        period: 1,
-      },
-      {
-        id: '3',
-        name: '浼佷笟绉佹湁SaaS鐗堢敤鎴峰閲忓寘',
-        saleType: '绉佹湁澧為噺鍖�',
-        accountCount: 100,
-        customerTarget: '浼佷笟',
-        concurrentNodes: 100,
-        pricePoint: 0,
-        priceCash: 0,
-        priceProtocol: true,
-        quantity: 1,
-        period: 1,
-      },
-      {
-        id: '4',
-        name: '涓汉鍏湁SaaS鐗堣鍙�',
-        saleType: '绉佹湁澧為噺鍖�',
-        accountCount: 50,
-        customerTarget: '涓汉',
-        concurrentNodes: 50,
-        pricePoint: 0,
-        priceCash: 0,
-        quantity: 1,
-        period: 0,
-      },
-    ],
-    pointTotal: '50,000',
-    cashTotal: '7,500',
+  const orderId = String(route.params.id || '')
+  if (!orderId) {
+    ElMessage.error('璁㈠崟ID涓嶈兘涓虹┖')
+    return
   }
 
-  Object.assign(detail, mockDetail)
-  
-  // 娣诲姞妯℃嫙鏂囦欢鏁版嵁鐢ㄤ簬灞曠ず
-  fileList.value = [
-    {
-      name: '绛惧瓧鐩栫珷鏂囦欢.pdf',
-      size: 2621440, // 2.5MB
-      uid: '1',
-      status: 'success'
-    },
-    {
-      name: 'API Keys.txt',
-      size: 354, // 354 Bytes
-      uid: '2',
-      status: 'success'
+  try {
+    const res = (await orderApi.getOrderDetail(orderId)) as any
+    const data = res?.data || {}
+
+    const statusName: string = data.orderStatus || ''
+    const uiStatus = statusServerToUi[statusName] || 'INFO'
+
+    // 鏄犲皠璁㈠崟璇︽儏澶撮儴淇℃伅
+    const head = {
+      orderNo: data.orderId,
+      resourceTypeName: '杞欢浜у搧',
+      status: uiStatus,
+      statusName,
+      applyTime: formatDateTime(data.applyTime),
+      unitName: data.unitName || '-',
+      userName: data.userName || '-',
+      userAccount: data.userAccount || '-',
+      userDept: data.userDept || '-',
+      userPhone: data.userPhone || '-',
+      productName: data.productName || '-',
+      supplier: data.providerName || '-',
+      industry: data.industry || '-',
+      projectUnit: data.projectUnit || '-',
+      productType: data.productType || '-',
+      productDesc: data.productDesc || '-',
     }
-  ]
-  
-  // 娉ㄩ噴鎺夊師鏈夌殑API璋冪敤锛屼娇鐢ㄦā鎷熸暟鎹�
-  // const { data } = (await fetchOrderDetail({ id: route.params.id })) as any
-  // Object.assign(detail, data || {})
+
+    // 鏄庣粏椤规槧灏�
+    const items: any[] = Array.isArray(data.orderDetails)
+      ? data.orderDetails.map((d: any, idx: number) => {
+          const pt = normalizePriceType(d.priceType)
+          return {
+            id: String(d.id ?? idx + 1),
+            name: d.suiteName,
+            saleType: d.salesForm,
+            accountCount: d.accountLimit,
+            customerTarget: d.customerType,
+            concurrentNodes: d.concurrentNodes,
+            pricePoint: pt === 'points' ? Number(d.unitPrice || 0) : 0,
+            priceCash: pt === 'currency' ? Number(d.unitPrice || 0) : 0,
+            priceProtocol: pt === 'agreement',
+            quantity: Number(d.quantity || 0),
+            period: Number(d.duration || 0),
+          }
+        })
+      : []
+
+    // 姹囨�伙紙绠�鍗曠浉鍔狅細鍗曚环*鏁伴噺锛�
+    const pointTotalNum = items.reduce((sum, it) => sum + Number(it.pricePoint || 0) * Number(it.quantity || 0), 0)
+    const cashTotalNum = items.reduce((sum, it) => sum + Number(it.priceCash || 0) * Number(it.quantity || 0), 0)
+
+    Object.assign(detail, head, {
+      items,
+      pointTotal: pointTotalNum.toLocaleString(),
+      cashTotal: cashTotalNum.toLocaleString(),
+    })
+
+    // 濡傛灉鏈夊凡涓婁紶鐨勬枃浠讹紝鏄剧ず鍦ㄦ枃浠跺垪琛ㄤ腑
+    if (data.attachments && Array.isArray(data.attachments)) {
+      fileList.value = data.attachments.map((file: any) => ({
+        name: file.fileName,
+        size: file.fileSize,
+        uid: file.id,
+        status: 'success',
+        url: file.fileUrl
+      }))
+    }
+  } catch (error) {
+    console.error('鑾峰彇璁㈠崟璇︽儏澶辫触:', error)
+    ElMessage.error('鑾峰彇璁㈠崟璇︽儏澶辫触')
+  }
 })
 
 const onExceed = () => ElMessage.warning('鏈�澶氶�夋嫨5涓枃浠�')
+
+// 鏂囦欢涓婁紶鍓嶇殑楠岃瘉
+const beforeUpload = (file: File) => {
+  // 妫�鏌ユ枃浠跺ぇ灏忥紙闄愬埗涓�100MB锛�
+  const maxSize = 100 * 1024 * 1024
+  if (file.size > maxSize) {
+    ElMessage.error('鏂囦欢澶у皬涓嶈兘瓒呰繃100MB')
+    return false
+  }
+  
+  // 妫�鏌ユ枃浠跺悕闀垮害
+  if (file.name.length > 100) {
+    ElMessage.error('鏂囦欢鍚嶇О涓嶈兘瓒呰繃100瀛楃')
+    return false
+  }
+  
+  // 璁剧疆鏂囦欢鍒濆鐘舵��
+  const fileObj = {
+    name: file.name,
+    size: file.size,
+    type: file.type,
+    raw: file,
+    status: 'ready', // 鍒濆鐘舵�佷负鍑嗗涓婁紶
+    uploading: false,
+    uploaded: false
+  }
+  
+  // 灏嗘枃浠舵坊鍔犲埌鏂囦欢鍒楄〃
+  fileList.value.push(fileObj)
+  
+  return false // 闃绘鑷姩涓婁紶锛屾敼涓烘墜鍔ㄤ笂浼�
+}
+
+// 涓婁紶鍗曚釜鏂囦欢鍒版湇鍔″櫒
+const uploadSingleFile = async (file: File) => {
+  const formData = new FormData()
+  formData.append('file', file)
+  formData.append('folder', 'order-attachments')
+  
+  try {
+    console.log('寮�濮嬩笂浼犳枃浠�:', file.name, '澶у皬:', file.size)
+    
+    const response = await createAxios({
+      url: '/admin/file/upload',
+      method: 'POST',
+      headers: {
+        'Content-Type': 'multipart/form-data'
+      },
+      data: formData
+    })
+    
+    console.log('鏂囦欢涓婁紶鍝嶅簲:', response)
+    
+    // 妫�鏌ュ搷搴旀牸寮� - 鏍规嵁瀹為檯杩斿洖鏍煎紡璋冩暣
+    const responseData = response as any
+    
+    // 鏍规嵁瀹為檯鍝嶅簲鏍煎紡锛岀洿鎺ユ鏌� responseData.code
+    if (responseData && responseData.code === 200) {
+      console.log('鏂囦欢涓婁紶鎴愬姛锛岃繑鍥炴暟鎹�:', responseData.data)
+      return responseData.data // 杩斿洖鏂囦欢URL
+    } else if (responseData && responseData.data && responseData.data.code === 200) {
+      // 澶囩敤妫�鏌ワ細濡傛灉鍝嶅簲琚寘瑁呭湪 data 涓�
+      console.log('鏂囦欢涓婁紶鎴愬姛锛岃繑鍥炴暟鎹�:', responseData.data.data)
+      return responseData.data.data // 杩斿洖鏂囦欢URL
+    } else {
+      // 澶勭悊閿欒鎯呭喌
+      const errorMsg = responseData?.msg || responseData?.data?.msg || responseData?.message || responseData?.data?.message || '鏂囦欢涓婁紶澶辫触'
+      console.error('鏂囦欢涓婁紶澶辫触锛岄敊璇俊鎭�:', errorMsg)
+      throw new Error(errorMsg)
+    }
+  } catch (error) {
+    console.error('鏂囦欢涓婁紶寮傚父:', error)
+    throw error
+  }
+}
+
+// 淇濆瓨鏂囦欢淇℃伅鍒版暟鎹簱
+const saveFileInfo = async (fileData: any) => {
+  try {
+    console.log('寮�濮嬩繚瀛樻枃浠朵俊鎭�:', fileData)
+    
+    // 浣跨敤FormData鏍煎紡锛屽洜涓哄悗绔娇鐢ˊRequestParam鎺ユ敹鍙傛暟
+    const formData = new FormData()
+    formData.append('orderId', fileData.orderId)
+    formData.append('fileName', fileData.fileName)
+    formData.append('originalName', fileData.originalName)
+    formData.append('fileType', fileData.fileType)
+    formData.append('fileSize', fileData.fileSize.toString())
+    formData.append('fileUrl', fileData.fileUrl)
+    formData.append('bucketName', fileData.bucketName)
+    formData.append('objectName', fileData.objectName)
+    formData.append('uploadUserId', fileData.uploadUserId.toString())
+    formData.append('uploadUserName', fileData.uploadUserName)
+    formData.append('attachmentType', fileData.attachmentType)
+    formData.append('description', fileData.description)
+    
+    console.log('鍑嗗鍙戦�佺殑鏂囦欢淇℃伅:', {
+      orderId: fileData.orderId,
+      fileName: fileData.fileName,
+      fileSize: fileData.fileSize,
+      fileUrl: fileData.fileUrl,
+      uploadUserId: fileData.uploadUserId,
+      uploadUserName: fileData.uploadUserName
+    })
+    
+    const response = await createAxios({
+      url: '/admin/api/order/attachment/upload',
+      method: 'POST',
+      headers: {
+        'Content-Type': 'multipart/form-data'
+      },
+      data: formData
+    })
+    
+    console.log('淇濆瓨鏂囦欢淇℃伅鍝嶅簲:', response)
+    
+    // 浣跨敤涓庢枃浠朵笂浼犵浉鍚岀殑鍝嶅簲鍒ゆ柇閫昏緫
+    const responseData = response as any
+    
+    if (responseData && responseData.code === 200) {
+      console.log('鏂囦欢淇℃伅淇濆瓨鎴愬姛锛岃繑鍥炵殑闄勪欢ID:', responseData.data)
+      const attachmentId = responseData.data
+      
+      // 楠岃瘉attachmentId鏄惁涓烘湁鏁堢殑鏁板瓧
+      if (typeof attachmentId === 'number' && attachmentId > 0) {
+        return attachmentId
+      } else {
+        console.error('杩斿洖鐨勯檮浠禝D涓嶆槸鏈夋晥鏁板瓧:', attachmentId, typeof attachmentId)
+        throw new Error(`鏃犳晥鐨勯檮浠禝D: ${attachmentId}`)
+      }
+    } else if (responseData && responseData.data && responseData.data.code === 200) {
+      // 澶囩敤妫�鏌ワ細濡傛灉鍝嶅簲琚寘瑁呭湪 data 涓�
+      console.log('鏂囦欢淇℃伅淇濆瓨鎴愬姛锛堝鐢ㄦ鏌ワ級锛岃繑鍥炵殑闄勪欢ID:', responseData.data.data)
+      const attachmentId = responseData.data.data
+      
+      // 楠岃瘉attachmentId鏄惁涓烘湁鏁堢殑鏁板瓧
+      if (typeof attachmentId === 'number' && attachmentId > 0) {
+        return attachmentId
+      } else {
+        console.error('杩斿洖鐨勯檮浠禝D涓嶆槸鏈夋晥鏁板瓧锛堝鐢ㄦ鏌ワ級:', attachmentId, typeof attachmentId)
+        throw new Error(`鏃犳晥鐨勯檮浠禝D: ${attachmentId}`)
+      }
+    } else {
+      // 澶勭悊閿欒鎯呭喌
+      const errorMsg = responseData?.msg || responseData?.data?.msg || responseData?.message || responseData?.data?.message || '淇濆瓨鏂囦欢淇℃伅澶辫触'
+      console.error('鏂囦欢淇℃伅淇濆瓨澶辫触:', errorMsg)
+      throw new Error(errorMsg)
+    }
+  } catch (error) {
+    console.error('淇濆瓨鏂囦欢淇℃伅寮傚父:', error)
+    throw error
+  }
+}
+
+
+
 const goBack = () => router.back()
+
+// 鎻愪氦鏂囦欢骞舵洿鏂拌鍗曠姸鎬�
 const submit = async () => {
-  // 妯℃嫙鎻愪氦鎴愬姛鍝嶅簲
-  const mockResponse = { code: 200 }
-  
-  // 娉ㄩ噴鎺夊師鏈夌殑API璋冪敤锛屼娇鐢ㄦā鎷熸暟鎹�
-  // const { code } = (await uploadTradeFile({ id: route.params.id, files: fileList.value })) as any
-  
-  if (mockResponse.code === 200) {
+  if (fileList.value.length === 0) {
+    ElMessage.warning('璇疯嚦灏戜笂浼犱竴涓枃浠�')
+    return
+  }
+
+  // 妫�鏌ユ槸鍚︽湁鏈笂浼犵殑鏂囦欢
+  const unuploadedFiles = fileList.value.filter(file => !file.uploaded && !file.url)
+  if (unuploadedFiles.length > 0) {
+    ElMessage.warning('璇峰厛涓婁紶鎵�鏈夋枃浠�')
+    return
+  }
+
+  try {
+    const orderId = String(route.params.id || '')
+    const userId = userStore.getUserId
+    const userName = userStore.username || userStore.name || '鏈煡鐢ㄦ埛'
+
+    // 涓婁紶鎵�鏈夋湭涓婁紶鐨勬枃浠�
+    const uploadPromises = fileList.value
+      .filter(fileItem => fileItem.raw && !fileItem.uploaded)
+      .map(async (fileItem) => {
+        const fileUrl = await uploadSingleFile(fileItem.raw)
+        
+        // 淇濆瓨鏂囦欢淇℃伅鍒版暟鎹簱
+        const attachmentData = {
+          orderId: orderId,
+          fileName: fileItem.name,
+          originalName: fileItem.name,
+          fileType: fileItem.type || 'application/octet-stream',
+          fileSize: fileItem.size,
+          fileUrl: fileUrl,
+          bucketName: 'order-attachments',
+          objectName: fileUrl.split('/').pop(),
+          uploadUserId: userId,
+          uploadUserName: userName,
+          attachmentType: 'TRADE_FILE',
+          description: '浜ゆ槗鏂囦欢'
+        }
+
+        await saveFileInfo(attachmentData)
+      })
+
+    await Promise.all(uploadPromises)
+
+    // 鏇存柊璁㈠崟鐘舵�佽繘鍏ヤ笅涓�涓姸鎬�
+    await orderApi.updateOrderStatusToNext(orderId)
+
     ElMessage.success('鎻愪氦鎴愬姛')
     router.back()
+  } catch (error) {
+    console.error('鎻愪氦澶辫触:', error)
+    ElMessage.error(error instanceof Error ? error.message : '鎻愪氦澶辫触')
   }
 }
 
@@ -456,13 +695,365 @@
 // 鏂囦欢鍒楄〃琛ㄦ牸琛ㄤ綋鏂囧瓧澶у皬
 const fileTableCellStyle: CSSProperties = { fontSize: '12px' };
 
+// 鍒ゆ柇鏂囦欢鏄惁鍙瑙�
+const isPreviewable = (file: any) => {
+  // 棣栧厛妫�鏌IME绫诲瀷
+  const previewableTypes = [
+    'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/bmp', 'image/webp',
+    'text/plain', 'text/html', 'text/css', 'text/javascript',
+    'application/pdf',
+    'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
+    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
+    'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
+  ]
+  
+  // 濡傛灉MIME绫诲瀷鍖归厤锛岀洿鎺ヨ繑鍥瀟rue
+  if (previewableTypes.includes(file.type || '')) {
+    return true
+  }
+  
+  // 濡傛灉MIME绫诲瀷涓虹┖鎴栦笉鍖归厤锛屾牴鎹枃浠舵墿灞曞悕鍒ゆ柇
+  const fileName = file.name || ''
+  const fileExtension = fileName.toLowerCase().split('.').pop()
+  
+  const previewableExtensions = [
+    'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp',
+    'txt', 'html', 'htm', 'css', 'js',
+    'pdf',
+    'docx', 'xlsx', 'pptx'
+  ]
+  
+  return previewableExtensions.includes(fileExtension)
+}
+
+// 鏂囦欢棰勮
+const handlePreview = async (file: any) => {
+  if (!file.url) {
+    ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�')
+    return
+  }
+  
+  // 鑾峰彇鏂囦欢鎵╁睍鍚�
+  const fileName = file.name || ''
+  const fileExtension = fileName.toLowerCase().split('.').pop()
+  
+  let previewUrl = file.url
+  
+  // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼紭鍏堜娇鐢ㄩ瑙圲RL
+  if (file.url.includes('order-attachments')) {
+    try {
+      // 棣栧厛灏濊瘯鑾峰彇棰勮URL
+      const previewResponse = await createAxios({
+        url: `/admin/file/preview`,
+        method: 'GET',
+        params: {
+          fileName: file.url
+        }
+      })
+      
+      console.log('棰勮URL鍝嶅簲:', previewResponse)
+      
+      // 妫�鏌ュ搷搴旀牸寮�
+      const responseData = previewResponse as any
+      if (responseData && responseData.code === 200 && responseData.data) {
+        previewUrl = responseData.data
+        console.log('浣跨敤棰勮URL:', previewUrl)
+      } else {
+        console.log('棰勮URL鑾峰彇澶辫触锛屼娇鐢ㄤ笅杞芥柟寮�')
+        // 濡傛灉棰勮URL鑾峰彇澶辫触锛屽洖閫�鍒颁笅杞芥柟寮�
+        const response = await createAxios({
+          url: `/admin/file/download`,
+          method: 'GET',
+          responseType: 'blob',
+          params: {
+            fileName: file.url,
+            originalName: file.name
+          }
+        })
+        
+        // 鍒涘缓棰勮URL
+        const blob = new Blob([response as any])
+        previewUrl = window.URL.createObjectURL(blob)
+        console.log('浣跨敤Blob URL:', previewUrl)
+      }
+    } catch (error) {
+      console.error('鑾峰彇鏂囦欢澶辫触:', error)
+      ElMessage.error('鑾峰彇鏂囦欢澶辫触锛屾棤娉曢瑙�')
+      return
+    }
+  }
+  
+  // 鍥剧墖鏂囦欢鐩存帴鍦ㄦ柊绐楀彛鎵撳紑
+  if ((file.type && file.type.startsWith('image/')) || 
+      ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExtension)) {
+    console.log('棰勮鍥剧墖鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // PDF鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑
+  if (file.type === 'application/pdf' || fileExtension === 'pdf') {
+    console.log('棰勮PDF鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // 鏂囨湰鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑
+  if ((file.type && file.type.startsWith('text/')) || 
+      ['txt', 'html', 'htm', 'css', 'js'].includes(fileExtension)) {
+    console.log('棰勮鏂囨湰鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+    return
+  }
+  
+  // Office鏂囨。鍜屽叾浠栨枃浠剁被鍨嬶紝灏濊瘯鍦ㄦ柊绐楀彛鎵撳紑
+  try {
+    console.log('棰勮鍏朵粬鏂囦欢:', previewUrl)
+    window.open(previewUrl, '_blank')
+  } catch (error) {
+    console.error('棰勮澶辫触:', error)
+    ElMessage.error('棰勮澶辫触锛岃涓嬭浇鍚庢煡鐪�')
+  }
+}
+
+// 鍒ゆ柇鏂囦欢鏄惁宸蹭笂浼犳垚鍔�
+const isFileUploaded = (file: any) => {
+  // 鏂囦欢鏈塽rl涓旂姸鎬佷负success琛ㄧず宸蹭笂浼犳垚鍔�
+  return file.url && (file.status === 'success' || file.uploaded)
+}
+
+// 鍗曚釜鏂囦欢涓婁紶
+const handleUpload = async (file: any) => {
+  if (!file.raw) {
+    ElMessage.warning('鏂囦欢鏁版嵁涓嶅瓨鍦�')
+    return
+  }
+
+  // 璁剧疆涓婁紶鐘舵��
+  file.uploading = true
+  
+  try {
+    // 涓婁紶鏂囦欢鍒版湇鍔″櫒
+    const fileUrl = await uploadSingleFile(file.raw)
+    
+    // 淇濆瓨鏂囦欢淇℃伅鍒版暟鎹簱
+    const orderId = String(route.params.id || '')
+    const userId = userStore.getUserId
+    const userName = userStore.username || userStore.name || '鏈煡鐢ㄦ埛'
+    
+    const attachmentData = {
+      orderId: orderId,
+      fileName: file.name,
+      originalName: file.name,
+      fileType: file.type || 'application/octet-stream',
+      fileSize: file.size,
+      fileUrl: fileUrl,
+      bucketName: 'order-attachments',
+      objectName: fileUrl.split('/').pop(),
+      uploadUserId: userId,
+      uploadUserName: userName,
+      attachmentType: 'TRADE_FILE',
+      description: '浜ゆ槗鏂囦欢'
+    }
+
+    const attachmentId = await saveFileInfo(attachmentData)
+    
+    // 鏇存柊鏂囦欢鐘舵��
+    file.url = fileUrl
+    file.uid = attachmentId // 璁剧疆姝g‘鐨勯檮浠禝D
+    file.status = 'success'
+    file.uploaded = true
+    file.uploading = false
+    
+    ElMessage.success('鏂囦欢涓婁紶鎴愬姛')
+  } catch (error) {
+    console.error('鏂囦欢涓婁紶澶辫触:', error)
+    file.uploading = false
+    ElMessage.error(error instanceof Error ? error.message : '鏂囦欢涓婁紶澶辫触')
+  }
+}
+
+// 鏂囦欢涓嬭浇
+const handleDownload = async (file: any) => {
+  if (!file.url) {
+    ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�')
+    return
+  }
+  
+  console.log('寮�濮嬩笅杞芥枃浠�:', file.name, 'URL:', file.url)
+  
+  try {
+    // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼娇鐢ㄥ悗绔洿鎺ヤ笅杞紸PI
+    if (file.url.includes('order-attachments')) {
+      console.log('浣跨敤MinIO涓嬭浇API')
+      
+      // 浣跨敤axios閫氳繃浠g悊璁块棶鍚庣API
+      const response = await createAxios({
+        url: `/admin/file/download`,
+        method: 'GET',
+        responseType: 'blob',
+        params: {
+          fileName: file.url,
+          originalName: file.name
+        }
+      })
+      
+      console.log('涓嬭浇鍝嶅簲:', response)
+      
+      // 鍒涘缓涓嬭浇閾炬帴
+      const blob = new Blob([response as any])
+      const downloadUrl = window.URL.createObjectURL(blob)
+      
+      console.log('鍒涘缓涓嬭浇閾炬帴:', downloadUrl)
+      
+      const link = document.createElement('a')
+      link.href = downloadUrl
+      link.download = file.name || 'download'
+      link.target = '_blank'
+      link.rel = 'noopener noreferrer'
+      
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      
+      // 娓呯悊URL瀵硅薄
+      window.URL.revokeObjectURL(downloadUrl)
+      
+      ElMessage.success('鏂囦欢涓嬭浇鎴愬姛')
+    } else {
+      console.log('浣跨敤鐩存帴URL涓嬭浇')
+      // 鍏朵粬鎯呭喌鐩存帴浣跨敤鍘烾RL
+      const link = document.createElement('a')
+      link.href = file.url
+      link.download = file.name || 'download'
+      link.target = '_blank'
+      link.rel = 'noopener noreferrer'
+      
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+      
+      ElMessage.success('寮�濮嬩笅杞芥枃浠�')
+    }
+  } catch (error) {
+    console.error('涓嬭浇澶辫触:', error)
+    ElMessage.error('涓嬭浇澶辫触锛岃閲嶈瘯')
+  }
+}
+
+// 鍒犻櫎MinIO鏂囦欢
+const deleteMinioFile = async (fileName: string) => {
+  try {
+    console.log('寮�濮嬪垹闄inIO鏂囦欢:', fileName)
+    
+    const response = await createAxios({
+      url: `/admin/file/delete`,
+      method: 'DELETE',
+      params: {
+        fileName: fileName
+      }
+    })
+    
+    console.log('鍒犻櫎MinIO鏂囦欢鍝嶅簲:', response)
+    
+    const responseData = response as any
+    if (responseData && responseData.code === 200) {
+      console.log('MinIO鏂囦欢鍒犻櫎鎴愬姛')
+      return true
+    } else {
+      const errorMsg = responseData?.msg || responseData?.data?.msg || responseData?.message || responseData?.data?.message || '鍒犻櫎MinIO鏂囦欢澶辫触'
+      console.error('鍒犻櫎MinIO鏂囦欢澶辫触:', errorMsg)
+      throw new Error(errorMsg)
+    }
+  } catch (error) {
+    console.error('鍒犻櫎MinIO鏂囦欢寮傚父:', error)
+    throw error
+  }
+}
+
+// 鍒犻櫎鏁版嵁搴撻檮浠惰褰�
+const deleteAttachmentRecord = async (attachmentId: number) => {
+  try {
+    console.log('寮�濮嬪垹闄ゆ暟鎹簱闄勪欢璁板綍:', attachmentId)
+    
+    const response = await createAxios({
+      url: `/admin/api/order/attachment/delete/${attachmentId}`,
+      method: 'DELETE'
+    })
+    
+    console.log('鍒犻櫎鏁版嵁搴撻檮浠惰褰曞搷搴�:', response)
+    
+    const responseData = response as any
+    if (responseData && responseData.code === 200) {
+      console.log('鏁版嵁搴撻檮浠惰褰曞垹闄ゆ垚鍔�')
+      return true
+    } else {
+      const errorMsg = responseData?.msg || responseData?.data?.msg || responseData?.message || responseData?.data?.message || '鍒犻櫎鏁版嵁搴撻檮浠惰褰曞け璐�'
+      console.error('鍒犻櫎鏁版嵁搴撻檮浠惰褰曞け璐�:', errorMsg)
+      throw new Error(errorMsg)
+    }
+  } catch (error) {
+    console.error('鍒犻櫎鏁版嵁搴撻檮浠惰褰曞紓甯�:', error)
+    throw error
+  }
+}
+
 // 鏂囦欢鍒楄〃绉婚櫎鏂囦欢
-const handleRemove = (file: any, uploadFiles: any) => {
-  // 浠庢枃浠跺垪琛ㄤ腑绉婚櫎鎸囧畾鏂囦欢
-  const index = fileList.value.findIndex(item => item.uid === file.uid)
-  if (index > -1) {
-    fileList.value.splice(index, 1)
-    ElMessage.success('鏂囦欢宸插垹闄�')
+const handleRemove = async (file: any, uploadFiles: any) => {
+  try {
+    // 鏄剧ず纭瀵硅瘽妗�
+    await ElMessageBox.confirm(
+      `纭畾瑕佸垹闄ゆ枃浠� "${file.name}" 鍚楋紵`,
+      '鍒犻櫎纭',
+      {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning',
+        center: true
+      }
+    )
+
+    // 鐢ㄦ埛纭鍚庢墽琛屽垹闄ゆ搷浣�
+    // 濡傛灉鏄凡涓婁紶鐨勬枃浠讹紙鏈塽id涓斾负鏁板瓧锛岃〃绀烘暟鎹簱璁板綍ID锛�
+    if (file.uid && !isNaN(file.uid) && file.url) {
+      console.log('鍒犻櫎宸蹭笂浼犵殑鏂囦欢:', file.name, '闄勪欢ID:', file.uid)
+      
+      // 1. 鍒犻櫎MinIO涓殑鏂囦欢
+      if (file.url.includes('order-attachments')) {
+        await deleteMinioFile(file.url)
+      }
+      
+      // 2. 鍒犻櫎鏁版嵁搴撲腑鐨勯檮浠惰褰�
+      await deleteAttachmentRecord(file.uid)
+      
+      // 3. 浠庢枃浠跺垪琛ㄤ腑绉婚櫎
+      const index = fileList.value.findIndex(item => item.uid === file.uid)
+      if (index > -1) {
+        fileList.value.splice(index, 1)
+      }
+      
+      ElMessage.success('鏂囦欢鍒犻櫎鎴愬姛')
+    } else {
+      // 濡傛灉鏄湭涓婁紶鐨勬枃浠讹紙鍙湁raw鏂囦欢瀵硅薄锛�
+      console.log('鍒犻櫎鏈笂浼犵殑鏂囦欢:', file.name)
+      
+      // 鐩存帴浠庢枃浠跺垪琛ㄤ腑绉婚櫎
+      const index = fileList.value.findIndex(item => item.name === file.name && item.size === file.size)
+      if (index > -1) {
+        fileList.value.splice(index, 1)
+      }
+      
+      ElMessage.success('鏂囦欢宸插垹闄�')
+    }
+  } catch (error) {
+    // 濡傛灉鐢ㄦ埛鍙栨秷鍒犻櫎锛宔rror涓�'cancel'锛屼笉闇�瑕佹樉绀洪敊璇秷鎭�
+    if (error === 'cancel') {
+      console.log('鐢ㄦ埛鍙栨秷鍒犻櫎鎿嶄綔')
+      return
+    }
+    
+    console.error('鍒犻櫎鏂囦欢澶辫触:', error)
+    ElMessage.error(error instanceof Error ? error.message : '鍒犻櫎鏂囦欢澶辫触')
   }
 }
 </script>
@@ -649,10 +1240,50 @@
         color: #409eff;
       }
     }
-    .delete-btn {
-      color: #f56c6c;
-      &:hover {
-        text-decoration: underline;
+    .file-actions {
+      display: flex;
+      gap: 8px;
+      align-items: center;
+      justify-content: center;
+      
+      .upload-btn {
+        color: #e6a23c;
+        &:hover {
+          text-decoration: underline;
+        }
+        &:disabled {
+          color: #c0c4cc;
+          cursor: not-allowed;
+        }
+      }
+      
+      .preview-btn {
+        color: #409eff;
+        &:hover {
+          text-decoration: underline;
+        }
+        &:disabled {
+          color: #c0c4cc;
+          cursor: not-allowed;
+        }
+      }
+      
+      .download-btn {
+        color: #67c23a;
+        &:hover {
+          text-decoration: underline;
+        }
+        &:disabled {
+          color: #c0c4cc;
+          cursor: not-allowed;
+        }
+      }
+      
+      .delete-btn {
+        color: #f56c6c;
+        &:hover {
+          text-decoration: underline;
+        }
       }
     }
   }

--
Gitblit v1.8.0