From 4d9eac00f0c1613d6279fbc75affd9ce31df5c6d Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期四, 10 九月 2026 15:33:27 +0800
Subject: [PATCH] fix: 对接时效接口

---
 src/pages.json                      |    8 
 src/pages/timely/detail.vue         |  817 +++++++++++++++++++----
 src/api/timeSensitiveTask.ts        |  243 ++++++
 src/pages/timely/index.vue          |  711 --------------------
 src/pages/timely/materialDetail.vue |  315 +++++++++
 5 files changed, 1,226 insertions(+), 868 deletions(-)

diff --git a/src/api/timeSensitiveTask.ts b/src/api/timeSensitiveTask.ts
index b24d32e..7318dd4 100644
--- a/src/api/timeSensitiveTask.ts
+++ b/src/api/timeSensitiveTask.ts
@@ -24,9 +24,15 @@
   inspectorName: string;
 }
 
-export interface TimeSensitiveTaskStartForm extends TimeSensitiveTaskForm {
+export interface TimeSensitiveTaskStartForm {
   id: number | string;
+  initiatorName: string;
+  initiateTime: string;
+  setTemperature: number | string;
+  agingDuration: number | string;
+  machineName: string;
   furnaceInTime: string;
+  inspectorName: string;
 }
 
 export interface TimeSensitiveCandidateQuery {
@@ -34,8 +40,15 @@
   size?: number;
   taskId: number | string;
   materialType: TimelinessMaterialType;
+  categoryName?: string;
   model?: string;
   materialCode?: string;
+}
+
+export interface TimeSensitiveTaskItemInput {
+  itemId: number | string;
+  /** 鍗曚笣浼犫�滈搧鏋跺彿-閾佺墝搴忓彿鈥濓紝缁炵嚎浼犳暟瀛楀簭鍙枫�� */
+  ironPlateNo: number | string;
 }
 
 export interface TimelinessInspectionDetailForm {
@@ -50,8 +63,8 @@
   timelinessInspectionId?: number | string;
 }
 
-/** 鑱旇皟瀹屾垚鍚庢敼涓� false 鍗冲彲鎭㈠涓嬫柟鐪熷疄鎺ュ彛銆� */
-export const USE_TIME_SENSITIVE_MOCK = true;
+/** 鏈湴婕旂ず寮�鍏筹紱姝e父杩愯鏃跺缁堣姹備笌 PC 绔竴鑷寸殑鐪熷疄鎺ュ彛銆� */
+export const USE_TIME_SENSITIVE_MOCK = false;
 
 const mockTasks: any[] = [
   {
@@ -197,6 +210,161 @@
   ],
 };
 
+const mockMaterialDetails: Record<string, Record<string, any>> = {
+  "9101": {
+    qualitySetTemperature: 180,
+    qualitySetDuration: "2+4+1",
+    confirmTime: "2026-09-04 08:35:00",
+    confirmUserName: "寮犲伐",
+    status: 0,
+    ledgerNo: "SO2609010188",
+    schedulingDetailNo: "LS-PC-260904-001",
+    deviceCode: "LS006",
+    clientName: "灞变笢鍏冩椇鐢靛伐绉戞妧鏈夐檺鍏徃",
+    productionDate: "2026-09-04",
+    groupTeam: "鐧界彮",
+    groupTeamLeader: "鐜嬬彮闀�",
+    productionNumber: 1,
+    unit: "鐩�",
+  },
+  "9102": {
+    qualitySetTemperature: 175,
+    qualitySetDuration: "2+3+1",
+    confirmTime: "2026-09-04 08:42:00",
+    confirmUserName: "寮犲伐",
+    status: 0,
+    ledgerNo: "SO2609010192",
+    schedulingDetailNo: "LS-PC-260904-002",
+    deviceCode: "LS008",
+    clientName: "鍗庝笢鐢电紗鏈夐檺鍏徃",
+    productionDate: "2026-09-04",
+    groupTeam: "鐧界彮",
+    groupTeamLeader: "鐜嬬彮闀�",
+    productionNumber: 1,
+    unit: "鐩�",
+  },
+  "9301": {
+    qualitySetTemperature: 180,
+    qualitySetDuration: "2+4+1",
+    confirmTime: "2026-09-05 09:15:00",
+    confirmUserName: "鏉庡伐",
+    status: 0,
+    ledgerNo: "SO2609050106",
+    schedulingDetailNo: "LS-PC-260905-006",
+    deviceCode: "LS003",
+    clientName: "灞变笢鍏冩椇鐢靛伐绉戞妧鏈夐檺鍏徃",
+    productionDate: "2026-09-05",
+    groupTeam: "鐧界彮",
+    groupTeamLeader: "璧电彮闀�",
+    productionNumber: 1,
+    unit: "鐩�",
+  },
+  "9302": {
+    qualitySetTemperature: 180,
+    qualitySetDuration: "2+4+1",
+    confirmTime: "2026-09-05 09:32:00",
+    confirmUserName: "鏉庡伐",
+    status: 0,
+    ledgerNo: "SO2609050112",
+    schedulingDetailNo: "LS-PC-260905-007",
+    deviceCode: "LS005",
+    clientName: "鍗庡寳绾跨紗鏈夐檺鍏徃",
+    productionDate: "2026-09-05",
+    groupTeam: "鐧界彮",
+    groupTeamLeader: "璧电彮闀�",
+    productionNumber: 1,
+    unit: "鐩�",
+  },
+  "9501": {
+    qualitySetTemperature: 180,
+    qualitySetDuration: "2+4+1",
+    confirmTime: "2026-09-03 10:20:00",
+    confirmUserName: "鍒樺伐",
+    status: 2,
+    ledgerNo: "SO2609030088",
+    schedulingDetailNo: "LS-PC-260903-003",
+    deviceCode: "LS002",
+    clientName: "椴佷腑鐢电紗鏈夐檺鍏徃",
+    productionDate: "2026-09-03",
+    groupTeam: "涓彮",
+    groupTeamLeader: "瀛欑彮闀�",
+    productionNumber: 1,
+    unit: "鐩�",
+  },
+  "9201": {
+    qualitySetTemperature: 175,
+    qualitySetDuration: "2+3+1",
+    confirmTime: "2026-09-04 09:05:00",
+    confirmUserName: "鐜嬪伐",
+    status: 1,
+    ledgerNo: "SO2609020116",
+    schedulingDetailNo: "JX-PC-260904-001",
+    deviceCode: "JX003",
+    clientName: "鍗庡寳鐢电紗鏈夐檺鍏徃",
+    productionDate: "2026-09-04",
+    groupTeam: "涓彮",
+    groupTeamLeader: "璧电彮闀�",
+    productionNumber: 1,
+    productionWeight: 1180,
+    unit: "鐩�",
+  },
+  "9202": {
+    qualitySetTemperature: 175,
+    qualitySetDuration: "2+3+1",
+    confirmTime: "2026-09-04 09:12:00",
+    confirmUserName: "鐜嬪伐",
+    status: 1,
+    ledgerNo: "SO2609020118",
+    schedulingDetailNo: "JX-PC-260904-002",
+    deviceCode: "JX004",
+    clientName: "鍗庡寳鐢电紗鏈夐檺鍏徃",
+    productionDate: "2026-09-04",
+    groupTeam: "涓彮",
+    groupTeamLeader: "璧电彮闀�",
+    productionNumber: 1,
+    productionWeight: 1260,
+    unit: "鐩�",
+  },
+  "9401": {
+    qualitySetTemperature: 175,
+    qualitySetDuration: "2+3+1",
+    confirmTime: "2026-09-05 10:10:00",
+    confirmUserName: "鏉庡伐",
+    status: 0,
+    ledgerNo: "SO2609050216",
+    schedulingDetailNo: "JX-PC-260905-002",
+    deviceCode: "JX006",
+    clientName: "鍗庡寳鐢电紗鏈夐檺鍏徃",
+    productionDate: "2026-09-05",
+    groupTeam: "涓彮",
+    groupTeamLeader: "璧电彮闀�",
+    productionNumber: 1,
+    productionWeight: 1380,
+    unit: "鐩�",
+  },
+  "9402": {
+    qualitySetTemperature: 175,
+    qualitySetDuration: "2+3+1",
+    confirmTime: "2026-09-05 10:22:00",
+    confirmUserName: "鏉庡伐",
+    status: 0,
+    ledgerNo: "SO2609050220",
+    schedulingDetailNo: "JX-PC-260905-003",
+    deviceCode: "JX007",
+    clientName: "鍗庡崡鐢电紗鏈夐檺鍏徃",
+    productionDate: "2026-09-05",
+    groupTeam: "涓彮",
+    groupTeamLeader: "璧电彮闀�",
+    productionNumber: 1,
+    productionWeight: 1460,
+    unit: "鐩�",
+  },
+};
+
+[...mockMaterialPool.鍗曚笣, ...mockMaterialPool.缁炵嚎].forEach((item) => {
+  Object.assign(item, mockMaterialDetails[String(item.id)] || {});
+});
+
 const findMockMaterial = (id: number | string) =>
   [...mockMaterialPool.鍗曚笣, ...mockMaterialPool.缁炵嚎].find(
     (item) => String(item.id) === String(id)
@@ -207,10 +375,19 @@
   return item ? { ...item } : undefined;
 };
 
+const cloneMockMaterialWithIronPlate = (id: number | string, ironPlateNo: number | string) => {
+  const item = cloneMockMaterial(id);
+  return item ? { ...item, ironPlateNo } : undefined;
+};
+
 const mockItems: Record<string, any[]> = {
-  "9001": [cloneMockMaterial(9101), cloneMockMaterial(9102)].filter(Boolean),
-  "9002": [cloneMockMaterial(9201), cloneMockMaterial(9202)].filter(Boolean),
-  "9003": [cloneMockMaterial(9501)].filter(Boolean),
+  "9001": [cloneMockMaterialWithIronPlate(9101, 1), cloneMockMaterialWithIronPlate(9102, 2)].filter(
+    Boolean
+  ),
+  "9002": [cloneMockMaterialWithIronPlate(9201, 1), cloneMockMaterialWithIronPlate(9202, 2)].filter(
+    Boolean
+  ),
+  "9003": [cloneMockMaterialWithIronPlate(9501, 1)].filter(Boolean),
 };
 
 const mockInspections: Record<string, any[]> = {
@@ -376,7 +553,7 @@
     }
     return request<BaseResult<PageResult>>({
       url: "/timeSensitiveTask/queryPage",
-      method: "GET",
+      method: "POST",
       data: params,
     });
   },
@@ -387,8 +564,8 @@
     }
     return request<BaseResult<any>>({
       url: "/timeSensitiveTask/getDetailById",
-      method: "GET",
-      data: { id },
+      method: "POST",
+      data: id as any,
     });
   },
 
@@ -398,8 +575,8 @@
     }
     return request<BaseResult<any[]>>({
       url: "/timeSensitiveTask/getItems",
-      method: "GET",
-      data: { taskId },
+      method: "POST",
+      data: taskId as any,
     });
   },
 
@@ -468,8 +645,8 @@
     }
     return request<BaseResult<any>>({
       url: "/timeSensitiveTask/delete",
-      method: "DELETE",
-      data: { id },
+      method: "POST",
+      data: id as any,
     });
   },
 
@@ -507,8 +684,8 @@
     }
     return request<BaseResult<any>>({
       url: "/timeSensitiveTask/checkEnd",
-      method: "GET",
-      data: { id },
+      method: "POST",
+      data: id as any,
     });
   },
 
@@ -537,7 +714,9 @@
   queryCandidates(params: TimeSensitiveCandidateQuery) {
     if (USE_TIME_SENSITIVE_MOCK) {
       const existingIds = new Set(
-        (mockItems[String(params.taskId)] || []).map((item) => String(item.id))
+        Object.values(mockItems)
+          .flat()
+          .map((item) => String(item.id))
       );
       let rows = mockMaterialPool[params.materialType]
         .filter((item) => !existingIds.has(String(item.id)))
@@ -571,19 +750,25 @@
     }
     return request<BaseResult<PageResult>>({
       url: "/timeSensitiveTask/queryCandidates",
-      method: "GET",
+      method: "POST",
       data: params,
     });
   },
 
-  addItems(data: { taskId: number | string; itemIds: Array<number | string> }) {
+  addItems(data: {
+    taskId: number | string;
+    itemIds: Array<number | string>;
+    items: TimeSensitiveTaskItemInput[];
+  }) {
     if (USE_TIME_SENSITIVE_MOCK) {
       const key = String(data.taskId);
       mockItems[key] ||= [];
       const existingIds = new Set(mockItems[key].map((item) => String(item.id)));
-      data.itemIds.forEach((id) => {
-        const material = cloneMockMaterial(id);
-        if (material && !existingIds.has(String(id))) mockItems[key].push(material);
+      data.items.forEach(({ itemId, ironPlateNo }) => {
+        const material = cloneMockMaterial(itemId);
+        if (material && !existingIds.has(String(itemId))) {
+          mockItems[key].push({ ...material, ironPlateNo });
+        }
       });
       updateMockItemCount(data.taskId);
       const task = mockTasks.find((item) => String(item.id) === key);
@@ -593,10 +778,10 @@
         "鏂板鏄庣粏",
         "寰呭紑濮�",
         "寰呭紑濮�",
-        `鏂板 ${data.itemIds.length} 鏉℃椂鏁堟槑缁哷,
+        `棰嗙敤 ${data.itemIds.length} 鏉$墿鏂檂,
         task?.initiatorName || "鎿嶄綔浜�"
       );
-      return mockResult(true, "鏃舵晥鏄庣粏鏂板鎴愬姛");
+      return mockResult(true, "鐗╂枡棰嗙敤鎴愬姛");
     }
     return request<BaseResult<any>>({
       url: "/timeSensitiveTask/addItems",
@@ -618,10 +803,10 @@
         "鍒犻櫎鏄庣粏",
         "寰呭紑濮�",
         "寰呭紑濮�",
-        `鍒犻櫎 ${data.itemIds.length} 鏉℃椂鏁堟槑缁哷,
+        `鍒犻櫎 ${data.itemIds.length} 鏉¢鐢ㄧ墿鏂檂,
         task?.initiatorName || "鎿嶄綔浜�"
       );
-      return mockResult(true, "鏃舵晥鏄庣粏鍒犻櫎鎴愬姛");
+      return mockResult(true, "棰嗙敤鐗╂枡鍒犻櫎鎴愬姛");
     }
     return request<BaseResult<any>>({
       url: "/timeSensitiveTask/deleteItems",
@@ -646,6 +831,14 @@
     });
   },
 
+  /** 涓� PC 绔� aging_rack_number 瀛楀吀涓�鑷达紝鐢ㄤ綔鍗曚笣棰嗙敤閾佹灦鍙枫�� */
+  getAgingRackNumbers() {
+    return request<BaseResult<any[]>>({
+      url: "/system/dict/data/type/aging_rack_number",
+      method: "GET",
+    });
+  },
+
   getOperationRecords(recordId: number | string) {
     if (USE_TIME_SENSITIVE_MOCK) {
       return mockResult<any[]>(
diff --git a/src/pages.json b/src/pages.json
index 09dedb4..17e025e 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -274,7 +274,13 @@
     {
       "path": "pages/timely/detail",
       "style": {
-        "navigationBarTitleText": "鏃舵晥浠诲姟鏄庣粏"
+        "navigationBarTitleText": "棰嗙敤鐗╂枡"
+      }
+    },
+    {
+      "path": "pages/timely/materialDetail",
+      "style": {
+        "navigationBarTitleText": "鐗╂枡璇︽儏"
       }
     },
     {
diff --git a/src/pages/timely/detail.vue b/src/pages/timely/detail.vue
index da96719..69f966d 100644
--- a/src/pages/timely/detail.vue
+++ b/src/pages/timely/detail.vue
@@ -1,21 +1,14 @@
 <template>
   <view class="detail-page">
     <view class="detail-header">
-      <CardTitle title="鏃舵晥浠诲姟鏄庣粏" :hideAction="false">
+      <CardTitle title="棰嗙敤鐗╂枡" :hideAction="false">
         <template #action>
-          <wd-button
-            v-if="isWaiting && USE_TIME_SENSITIVE_MOCK"
-            size="small"
-            plain
-            @click="simulateScan"
-          >
-            妯℃嫙鎵爜
-          </wd-button>
           <wd-button
             v-if="isWaiting"
             type="icon"
             icon="scan"
             color="#0D867F"
+            custom-class="header-icon-button"
             :loading="scanSubmitting"
             @click="openScan"
           />
@@ -24,6 +17,7 @@
             type="icon"
             icon="add-circle"
             color="#0D867F"
+            custom-class="header-icon-button"
             @click="openCandidatePopup"
           />
         </template>
@@ -44,7 +38,7 @@
             {{ materialType }}
           </view>
           <view>
-            <text class="label">鏄庣粏</text>
+            <text class="label">宸查鐢�</text>
             {{ items.length }} 浠�
           </view>
           <view>
@@ -67,15 +61,31 @@
       </wd-card>
 
       <view class="section-title">
-        <text>鏃舵晥鏄庣粏锛坽{ items.length }}锛�</text>
-        <view v-if="isWaiting" class="section-actions">
-          <text class="section-link" @click="toggleSelectAll">
-            {{ allItemsSelected ? "鍙栨秷鍏ㄩ��" : "鍏ㄩ��" }}
-          </text>
-          <text class="section-link danger" @click="deleteSelectedItems">
-            鍒犻櫎鎵�閫�({{ selectedItems.length }})
-          </text>
-          <text class="section-link" @click="openCandidatePopup">鎵嬪姩娣诲姞</text>
+        <text>
+          {{ materialType === "鍗曚笣" ? "褰撳墠閾佹灦" : "棰嗙敤鐗╂枡" }}锛坽{ displayItems.length }}锛�
+        </text>
+      </view>
+      <view v-if="isWaiting && materialType === '鍗曚笣'" class="section-actions">
+        <wd-button block plain custom-class="section-action-button" @click="openRackSelector">
+          閫夋嫨閾佹灦鍙�
+        </wd-button>
+      </view>
+
+      <view v-if="materialType === '鍗曚笣'" class="layer-tabs-wrap">
+        <view v-if="rackLoading" class="layer-loading">
+          <wd-loading size="16px" />
+          <text>鍔犺浇閾佹灦鍙�...</text>
+        </view>
+        <wd-tabs v-else-if="rackTabs.length" v-model="activeRackNo" slidable="always">
+          <wd-tab
+            v-for="layer in rackTabs"
+            :key="layer.value"
+            :name="layer.value"
+            :title="`${layer.label}(${getLayerItemCount(layer.value)})`"
+          />
+        </wd-tabs>
+        <view v-else class="layer-empty">
+          {{ rackOptions.length ? "璇峰厛閫夋嫨閾佹灦鍙�" : "鏆傛棤鍙敤閾佹灦鍙�" }}
         </view>
       </view>
 
@@ -83,15 +93,23 @@
         <wd-loading />
         <text>鍔犺浇涓�...</text>
       </view>
-      <view v-else-if="!items.length" class="state-box">
-        <wd-status-tip image="content" tip="鏆傛棤鏃舵晥鏄庣粏" />
+      <view v-else-if="!displayItems.length" class="state-box">
+        <wd-status-tip
+          image="content"
+          :tip="
+            materialType === '鍗曚笣'
+              ? activeRackNo
+                ? '褰撳墠閾佹灦鏆傛棤棰嗙敤鍗曚笣'
+                : '璇峰厛閫夋嫨閾佹灦鍙�'
+              : '鏆傛棤棰嗙敤鐗╂枡'
+          "
+        />
       </view>
       <view v-else class="item-list">
-        <wd-card v-for="(item, index) in items" :key="getItemKey(item, index)">
+        <wd-card v-for="(item, index) in displayItems" :key="getItemKey(item, index)">
           <template #title>
             <view class="item-title">
               <view class="item-title-main">
-                <wd-checkbox v-if="isWaiting" v-model="item._selected" @click.stop />
                 <text>{{ getMaterialCode(item) || `鏄庣粏${index + 1}` }}</text>
                 <wd-tag
                   size="small"
@@ -104,18 +122,15 @@
                   {{ normalizeMaterialType(item.materialType || materialType) }}
                 </wd-tag>
               </view>
-              <wd-button
-                v-if="isWaiting"
-                type="text"
-                size="small"
-                custom-class="delete-button"
-                @click="deleteItem(item)"
-              >
-                鍒犻櫎
-              </wd-button>
             </view>
           </template>
           <wd-cell-group>
+            <wd-cell
+              v-if="normalizeMaterialType(item.materialType || materialType) === '鍗曚笣'"
+              title="閾佹灦鍙�"
+              :value="getLayerLabel(getSingleWireLayer(item))"
+            />
+            <wd-cell title="閾佺墝搴忓彿" :value="String(getDisplayIronPlateNo(item))" />
             <wd-cell title="瑙勬牸鍨嬪彿" :value="item.model || '-'" />
             <wd-cell
               v-if="normalizeMaterialType(item.materialType || materialType) === '鍗曚笣'"
@@ -128,12 +143,77 @@
               :value="item.rodNo || item.poleNumber || '-'"
             />
             <wd-cell title="娴佽浆鐮�/鎵规鍙�" :value="getMaterialCode(item) || '-'" />
-            <wd-cell title="閲嶉噺(kg)" :value="String(item.weight ?? '-')" />
-            <wd-cell v-if="item.supplier" title="鍘傚" :value="item.supplier" />
+            <wd-cell title="璐ㄦ娓╁害(鈩�)" :value="String(getQualitySetTemperature(item))" />
+            <wd-cell title="璐ㄦ鏃堕暱" :value="String(getQualitySetDuration(item))" />
+            <wd-cell
+              :title="materialType === '鍗曚笣' ? '閲嶉噺(kg)' : '鐢熶骇閲嶉噺'"
+              :value="String(getCandidateWeight(item))"
+            />
           </wd-cell-group>
+          <view class="material-detail-link" @click="openMaterialDetail(item)">
+            <text>鏌ョ湅璇︽儏</text>
+            <wd-icon name="arrow-right" size="14px" color="#0d867f" />
+          </view>
         </wd-card>
       </view>
     </scroll-view>
+
+    <wd-popup
+      v-model="rackSelectorVisible"
+      position="bottom"
+      :z-index="32"
+      :close-on-click-modal="false"
+      custom-style="height: 58vh; border-radius: 24rpx 24rpx 0 0;"
+    >
+      <view class="popup-layout">
+        <view class="popup-header">
+          <view>
+            <text class="popup-title">閫夋嫨閾佹灦鍙�</text>
+          </view>
+          <wd-icon name="close" size="20px" @click="rackSelectorVisible = false" />
+        </view>
+
+        <scroll-view class="rack-option-list" scroll-y>
+          <view v-if="rackLoading" class="state-box">
+            <wd-loading />
+            <text>鍔犺浇閾佹灦鍙�...</text>
+          </view>
+          <wd-status-tip
+            v-else-if="!rackSelectionRows.length"
+            image="content"
+            tip="鏆傛棤鍙敤閾佹灦鍙�"
+          />
+          <block v-else>
+            <view
+              v-for="rack in rackSelectionRows"
+              :key="rack.value"
+              class="rack-option-item"
+              @click="rack.selected = !rack.selected"
+            >
+              <wd-checkbox v-model="rack.selected" @click.stop />
+              <text>{{ rack.label }}</text>
+            </view>
+          </block>
+        </scroll-view>
+
+        <view class="popup-footer">
+          <text>宸查�� {{ pendingRackCount }} 涓�</text>
+          <view class="footer-buttons">
+            <wd-button
+              type="info"
+              plain
+              custom-class="footer-action-button"
+              @click="rackSelectorVisible = false"
+            >
+              鍙栨秷
+            </wd-button>
+            <wd-button custom-class="footer-action-button" @click="confirmRackSelection">
+              纭
+            </wd-button>
+          </view>
+        </view>
+      </view>
+    </wd-popup>
 
     <wd-popup
       v-model="candidatePopupVisible"
@@ -145,10 +225,28 @@
       <view class="popup-layout">
         <view class="popup-header">
           <view>
-            <text class="popup-title">鏂板鏃舵晥鏄庣粏</text>
+            <text class="popup-title">棰嗙敤鐗╂枡</text>
             <text class="popup-subtitle">{{ materialType }}</text>
           </view>
           <wd-icon name="close" size="20px" @click="candidatePopupVisible = false" />
+        </view>
+
+        <view v-if="materialType === '鍗曚笣'" class="candidate-layer-tabs">
+          <text class="candidate-layer-label">鍏堥�夋嫨閾佹灦鍙�</text>
+          <wd-tabs
+            v-if="candidateRackTabs.length"
+            v-model="candidateRackNo"
+            slidable="always"
+            @change="handleCandidateLayerChange"
+          >
+            <wd-tab
+              v-for="layer in candidateRackTabs"
+              :key="layer.value"
+              :name="layer.value"
+              :title="layer.label"
+            />
+          </wd-tabs>
+          <view v-else class="layer-empty">鏆傛棤鍙敤閾佹灦鍙凤紝璇峰厛缁存姢鏃舵晥閾佹灦鍙峰瓧鍏�</view>
         </view>
 
         <scroll-view class="candidate-list" scroll-y>
@@ -163,22 +261,56 @@
             v-for="(candidate, index) in candidates"
             :key="getItemKey(candidate, index)"
             class="candidate-item"
-            @click="candidate._selected = !candidate._selected"
           >
-            <wd-checkbox v-model="candidate._selected" @click.stop />
-            <view class="candidate-info">
-              <text class="candidate-code">{{ getMaterialCode(candidate) || "-" }}</text>
-              <text>{{ candidate.model || "-" }} 路 {{ candidate.weight ?? "-" }} kg</text>
-              <text v-if="materialType === '鍗曚笣'" class="candidate-meta">
-                {{ candidate.poleModel || candidate.rodModel || "-" }} 路
-                {{ candidate.rodNo || candidate.poleNumber || "-" }}
-              </text>
+            <view class="candidate-header" @click="toggleCandidate(candidate)">
+              <wd-checkbox
+                v-model="candidate._selected"
+                @click.stop
+                @change="recalculateCandidateIronPlateNumbers"
+              />
+              <view class="candidate-info">
+                <text class="candidate-code">{{ getMaterialCode(candidate) || "-" }}</text>
+                <text>{{ candidate.model || "-" }}</text>
+              </view>
+            </view>
+            <wd-cell-group>
+              <wd-input
+                v-model="candidate.ironPlateNo"
+                label="閾佺墝搴忓彿"
+                type="number"
+                required
+                :readonly="materialType === '鍗曚笣'"
+                placeholder="璇疯緭鍏ユ鏁存暟"
+              />
+              <wd-cell title="瑙勬牸鍨嬪彿" :value="candidate.model || '-'" />
+              <wd-cell
+                v-if="materialType === '鍗曚笣'"
+                title="閾濇潌鍨嬪彿"
+                :value="candidate.poleModel || candidate.rodModel || '-'"
+              />
+              <wd-cell
+                v-if="materialType === '鍗曚笣'"
+                title="閾濇潌鍙�"
+                :value="candidate.rodNo || candidate.poleNumber || '-'"
+              />
+              <wd-cell title="娴佽浆鐮�/鎵规鍙�" :value="getMaterialCode(candidate) || '-'" />
+              <wd-cell title="璐ㄦ娓╁害(鈩�)" :value="String(getQualitySetTemperature(candidate))" />
+              <wd-cell title="璐ㄦ鏃堕暱" :value="String(getQualitySetDuration(candidate))" />
+              <wd-cell
+                :title="materialType === '鍗曚笣' ? '閲嶉噺(kg)' : '鐢熶骇閲嶉噺'"
+                :value="String(getCandidateWeight(candidate))"
+              />
+            </wd-cell-group>
+            <view class="material-detail-link" @click="openMaterialDetail(candidate)">
+              <text>鏌ョ湅璇︽儏</text>
+              <wd-icon name="arrow-right" size="14px" color="#0d867f" />
             </view>
           </view>
           <wd-button
             v-if="candidates.length < candidateTotal"
             block
             plain
+            custom-class="load-more-button"
             :loading="candidateLoading"
             @click="loadMoreCandidates"
           >
@@ -189,9 +321,20 @@
         <view class="popup-footer">
           <text>宸查�� {{ selectedCandidates.length }} 鏉�</text>
           <view class="footer-buttons">
-            <wd-button type="info" plain @click="candidatePopupVisible = false">鍙栨秷</wd-button>
-            <wd-button :loading="candidateSubmitting" @click="addSelectedCandidates">
-              纭畾娣诲姞
+            <wd-button
+              type="info"
+              plain
+              custom-class="footer-action-button"
+              @click="candidatePopupVisible = false"
+            >
+              鍙栨秷
+            </wd-button>
+            <wd-button
+              custom-class="footer-action-button"
+              :loading="candidateSubmitting"
+              @click="addSelectedCandidates"
+            >
+              纭棰嗙敤
             </wd-button>
           </view>
         </view>
@@ -231,6 +374,14 @@
 const candidateTotal = ref(0);
 const candidatePage = ref(1);
 const candidatePageSize = 20;
+const UNASSIGNED_LAYER = "__unassigned__";
+const rackLoading = ref(false);
+const rackOptions = ref<Array<{ label: string; value: string }>>([]);
+const selectedRackNos = ref<string[]>([]);
+const rackSelectorVisible = ref(false);
+const rackSelectionRows = ref<Array<{ label: string; value: string; selected: boolean }>>([]);
+const activeRackNo = ref("");
+const candidateRackNo = ref("");
 const materialType = computed<TimelinessMaterialType>(() =>
   normalizeMaterialType(task.value.materialType)
 );
@@ -254,10 +405,37 @@
   const value = task.value.agingDuration ?? task.value.duration;
   return value === undefined || value === "" ? "-" : `${value} 灏忔椂`;
 });
-const selectedItems = computed(() => items.value.filter((item) => item._selected));
-const allItemsSelected = computed(
-  () => items.value.length > 0 && selectedItems.value.length === items.value.length
+const pendingRackCount = computed(
+  () => rackSelectionRows.value.filter((item) => item.selected).length
 );
+const rackTabs = computed(() => {
+  const tabs = selectedRackNos.value.map((value) => {
+    const option = rackOptions.value.find((item) => item.value === value);
+    return option || { label: value, value };
+  });
+  const knownValues = new Set(tabs.map((item) => item.value));
+  items.value.forEach((item) => {
+    const frameNo = getSingleWireLayer(item);
+    const value = frameNo || UNASSIGNED_LAYER;
+    if (knownValues.has(value)) return;
+    tabs.push({
+      value,
+      label: frameNo || "鏈垎閰嶉搧鏋跺彿",
+    });
+    knownValues.add(value);
+  });
+  return tabs;
+});
+const candidateRackTabs = computed(() =>
+  rackTabs.value.filter((item) => item.value !== UNASSIGNED_LAYER)
+);
+const displayItems = computed(() => {
+  if (materialType.value !== "鍗曚笣") return items.value;
+  if (!activeRackNo.value) return [];
+  return items.value.filter(
+    (item) => (getSingleWireLayer(item) || UNASSIGNED_LAYER) === activeRackNo.value
+  );
+});
 const selectedCandidates = computed(() => candidates.value.filter((item) => item._selected));
 
 function normalizeStatus(value: any) {
@@ -273,6 +451,45 @@
 function normalizeMaterialType(value: unknown): TimelinessMaterialType {
   const text = String(value ?? "");
   return text.includes("缁�") || text === "鎴愬搧" ? "缁炵嚎" : "鍗曚笣";
+}
+
+function parseSingleWireIronPlateNo(item: any) {
+  const explicitLayer = String(
+    item?.ironFrameNo ?? item?.ironRackNo ?? item?.rackNo ?? item?.frameNo ?? ""
+  ).trim();
+  const rawIronPlateNo = item?.ironPlateNo;
+  if (explicitLayer) return { layer: explicitLayer, plateNo: rawIronPlateNo };
+
+  const combinedNo = String(rawIronPlateNo ?? "").trim();
+  const separatorIndex = combinedNo.lastIndexOf("-");
+  if (separatorIndex > 0 && separatorIndex < combinedNo.length - 1) {
+    return {
+      layer: combinedNo.slice(0, separatorIndex),
+      plateNo: combinedNo.slice(separatorIndex + 1),
+    };
+  }
+  return { layer: "", plateNo: rawIronPlateNo };
+}
+
+function getSingleWireLayer(item: any) {
+  return parseSingleWireIronPlateNo(item).layer;
+}
+
+function getDisplayIronPlateNo(item: any) {
+  if (normalizeMaterialType(item?.materialType || materialType.value) !== "鍗曚笣") {
+    return item?.ironPlateNo ?? "-";
+  }
+  return parseSingleWireIronPlateNo(item).plateNo ?? "-";
+}
+
+function getLayerLabel(value: string) {
+  if (!value || value === UNASSIGNED_LAYER) return "鏈垎閰嶉搧鏋跺彿";
+  return rackTabs.value.find((item) => item.value === value)?.label || value;
+}
+
+function getLayerItemCount(value: string) {
+  return items.value.filter((item) => (getSingleWireLayer(item) || UNASSIGNED_LAYER) === value)
+    .length;
 }
 
 function getMaterialCode(item: any) {
@@ -296,6 +513,218 @@
   return getCandidateId(item) || getMaterialCode(item) || index;
 }
 
+function getQualitySetTemperature(item: any) {
+  const value =
+    item.qualitySetTemperature ??
+    item.qualityTemperature ??
+    item.inspectionTemperature ??
+    item.temperature;
+  return value === undefined || value === null || value === "" ? "-" : value;
+}
+
+function getQualitySetDuration(item: any) {
+  return (
+    item.qualitySetDuration ||
+    item.qualityDuration ||
+    item.inspectionDuration ||
+    item.duration ||
+    "-"
+  );
+}
+
+function getCandidateWeight(item: any) {
+  return item.weight ?? item.productionWeight ?? item.weightSum ?? "-";
+}
+
+function openMaterialDetail(item: any) {
+  uni.navigateTo({
+    url: "/pages/timely/materialDetail",
+    success: (result) => {
+      result.eventChannel.emit("materialDetail", {
+        ...item,
+        materialType: normalizeMaterialType(item.materialType || materialType.value),
+      });
+    },
+  });
+}
+
+function syncActiveRackNo() {
+  const tabs = rackTabs.value;
+  if (!tabs.length) {
+    activeRackNo.value = "";
+    candidateRackNo.value = "";
+    return;
+  }
+  if (!tabs.some((item) => item.value === activeRackNo.value)) {
+    const firstUsedLayer = items.value
+      .map((item) => getSingleWireLayer(item) || UNASSIGNED_LAYER)
+      .find((value) => tabs.some((tab) => tab.value === value));
+    activeRackNo.value = firstUsedLayer || tabs[0].value;
+  }
+  if (!candidateRackTabs.value.some((item) => item.value === candidateRackNo.value)) {
+    candidateRackNo.value =
+      candidateRackTabs.value.find((item) => item.value === activeRackNo.value)?.value ||
+      candidateRackTabs.value[0]?.value ||
+      "";
+  }
+}
+
+async function loadRackOptions() {
+  if (rackOptions.value.length || rackLoading.value) return;
+  rackLoading.value = true;
+  try {
+    const { data } = await TimeSensitiveTaskApi.getAgingRackNumbers();
+    const rows = Array.isArray(data) ? data : (data as any)?.records || [];
+    const seen = new Set<string>();
+    rackOptions.value = rows
+      .map((item: any) => ({
+        label: String(
+          item?.dictLabel ?? item?.label ?? item?.dictValue ?? item?.value ?? ""
+        ).trim(),
+        value: String(item?.dictValue ?? item?.value ?? "").trim(),
+      }))
+      .filter((item: { label: string; value: string }) => {
+        if (!item.value || seen.has(item.value)) return false;
+        seen.add(item.value);
+        return true;
+      });
+    syncActiveRackNo();
+  } catch (error: any) {
+    toast.error(error?.message || "鑾峰彇鏃舵晥閾佹灦鍙峰け璐�");
+  } finally {
+    rackLoading.value = false;
+  }
+}
+
+async function openRackSelector() {
+  if (!isWaiting.value) return;
+  rackSelectorVisible.value = true;
+  await loadRackOptions();
+  const selected = new Set(selectedRackNos.value);
+  rackSelectionRows.value = rackOptions.value.map((item) => ({
+    ...item,
+    selected: selected.has(item.value),
+  }));
+}
+
+function confirmRackSelection() {
+  selectedRackNos.value = rackSelectionRows.value
+    .filter((item) => item.selected)
+    .map((item) => item.value);
+  syncActiveRackNo();
+  rackSelectorVisible.value = false;
+}
+
+function fillIronPlateNumbers(rows: any[], otherCandidates: any[] = []) {
+  if (materialType.value === "鍗曚笣") {
+    return rows.map((item) => ({ ...item, ironPlateNo: undefined, _selected: false }));
+  }
+  const used = new Set(
+    [...items.value, ...otherCandidates]
+      .map((item) => Number(item.ironPlateNo))
+      .filter((value) => Number.isInteger(value) && value > 0)
+  );
+  let nextNumber = 1;
+  return rows.map((item) => {
+    const original = Number(item.ironPlateNo);
+    if (Number.isInteger(original) && original > 0 && !used.has(original)) {
+      used.add(original);
+      return { ...item, ironPlateNo: original, _selected: false };
+    }
+    while (used.has(nextNumber)) nextNumber += 1;
+    const result = { ...item, ironPlateNo: nextNumber, _selected: false };
+    used.add(nextNumber);
+    nextNumber += 1;
+    return result;
+  });
+}
+
+function recalculateCandidateIronPlateNumbers() {
+  if (materialType.value !== "鍗曚笣") return;
+  if (!candidateRackNo.value) {
+    candidates.value.forEach((item) => (item.ironPlateNo = undefined));
+    return;
+  }
+  const used = new Set(
+    items.value
+      .filter((item) => getSingleWireLayer(item) === candidateRackNo.value)
+      .map((item) => Number(getDisplayIronPlateNo(item)))
+      .filter((value) => Number.isInteger(value) && value > 0)
+  );
+  candidates.value.forEach((item) => {
+    if (!item._selected) {
+      item.ironPlateNo = undefined;
+      return;
+    }
+    let nextNumber = 1;
+    while (used.has(nextNumber)) nextNumber += 1;
+    item.ironPlateNo = nextNumber;
+    used.add(nextNumber);
+  });
+}
+
+function toggleCandidate(candidate: any) {
+  candidate._selected = !candidate._selected;
+  recalculateCandidateIronPlateNumbers();
+}
+
+function getNextIronPlateNo(layer = activeRackNo.value) {
+  const used = new Set(
+    items.value
+      .filter((item) => materialType.value !== "鍗曚笣" || getSingleWireLayer(item) === layer)
+      .map((item) => Number(getDisplayIronPlateNo(item)))
+      .filter((value) => Number.isInteger(value) && value > 0)
+  );
+  let nextNumber = 1;
+  while (used.has(nextNumber)) nextNumber += 1;
+  return nextNumber;
+}
+
+function validateIronPlateNumbers(rows: any[], layer = candidateRackNo.value) {
+  if (materialType.value === "鍗曚笣" && (!layer || layer === UNASSIGNED_LAYER)) {
+    return "璇峰厛閫夋嫨閾佹灦鍙�";
+  }
+  const numbers = rows.map((item) => Number(item.ironPlateNo));
+  if (numbers.some((value) => !Number.isInteger(value) || value <= 0)) {
+    return "璇峰~鍐欐纭殑閾佺墝搴忓彿";
+  }
+  const existingNumbers = new Set(
+    items.value
+      .filter((item) => materialType.value !== "鍗曚笣" || getSingleWireLayer(item) === layer)
+      .map((item) => Number(getDisplayIronPlateNo(item)))
+      .filter((value) => Number.isInteger(value) && value > 0)
+  );
+  if (
+    new Set(numbers).size !== numbers.length ||
+    numbers.some((value) => existingNumbers.has(value))
+  ) {
+    return materialType.value === "鍗曚笣" ? "鍚屼竴閾佹灦鍙峰唴閾佺墝搴忓彿涓嶈兘閲嶅" : "閾佺墝搴忓彿涓嶈兘閲嶅";
+  }
+  return "";
+}
+
+function requestIronPlateNo(defaultValue: number) {
+  return new Promise<number | undefined>((resolve) => {
+    uni.showModal({
+      title: "濉啓閾佺墝搴忓彿",
+      content: String(defaultValue),
+      editable: true,
+      placeholderText: "璇疯緭鍏ユ鏁存暟",
+      confirmText: "纭棰嗙敤",
+      success: (result) => {
+        if (!result.confirm) return resolve(undefined);
+        const value = Number((result as any).content);
+        if (!Number.isInteger(value) || value <= 0) {
+          toast.error("璇峰~鍐欐纭殑閾佺墝搴忓彿");
+          return resolve(undefined);
+        }
+        resolve(value);
+      },
+      fail: () => resolve(undefined),
+    });
+  });
+}
+
 async function loadTask() {
   if (!taskId.value) return;
   loading.value = true;
@@ -310,66 +739,41 @@
       ? itemData
       : itemData?.records || itemData?.list || itemData?.items || [];
     items.value = list.map((item: any) => ({ ...item, _selected: false }));
+    if (materialType.value === "鍗曚笣") await loadRackOptions();
+    syncActiveRackNo();
   } catch (error: any) {
-    toast.error(error?.message || "鑾峰彇鏃舵晥浠诲姟鏄庣粏澶辫触");
+    toast.error(error?.message || "鑾峰彇棰嗙敤鐗╂枡澶辫触");
   } finally {
     loading.value = false;
   }
 }
 
-function showConfirm(title: string, content: string, confirmText = "纭畾") {
-  return new Promise<boolean>((resolve) => {
-    uni.showModal({
-      title,
-      content,
-      confirmText,
-      success: (result) => resolve(Boolean(result.confirm)),
-      fail: () => resolve(false),
-    });
-  });
-}
-
-async function deleteItems(rows: any[]) {
-  if (!isWaiting.value) return toast.error("鍙湁寰呭紑濮嬬殑浠诲姟鍙互鍒犻櫎鏄庣粏");
-  if (!rows.length) return toast.error("璇疯嚦灏戦�夋嫨涓�鏉℃椂鏁堟槑缁�");
-  const itemIds = rows
-    .map((item) => getCandidateId(item))
-    .filter((id): id is number | string => id !== undefined && id !== null && id !== "");
-  if (!itemIds.length) return toast.error("鏄庣粏ID涓嶅瓨鍦紝鏃犳硶鍒犻櫎");
-  const confirmed = await showConfirm(
-    "鍒犻櫎鏄庣粏",
-    `纭畾鍒犻櫎閫変腑鐨� ${itemIds.length} 鏉℃椂鏁堟槑缁嗗悧锛熷垹闄ゅ悗鍙噸鏂版坊鍔犮�俙,
-    "鍒犻櫎"
-  );
-  if (!confirmed) return;
-  try {
-    await TimeSensitiveTaskApi.deleteItems({ taskId: taskId.value, itemIds });
-    toast.success("鏃舵晥鏄庣粏鍒犻櫎鎴愬姛");
-    await loadTask();
-  } catch (error: any) {
-    toast.error(error?.message || "鍒犻櫎鏃舵晥鏄庣粏澶辫触");
-  }
-}
-
-function deleteItem(item: any) {
-  deleteItems([item]);
-}
-
-function deleteSelectedItems() {
-  deleteItems(selectedItems.value);
-}
-
-function toggleSelectAll() {
-  const nextValue = !allItemsSelected.value;
-  items.value.forEach((item) => {
-    item._selected = nextValue;
-  });
-}
-
-function openCandidatePopup() {
+async function openCandidatePopup() {
   if (!isWaiting.value) return toast.error("鍙湁寰呭紑濮嬬殑浠诲姟鍙互鏂板鏄庣粏");
+  if (materialType.value === "鍗曚笣") {
+    await loadRackOptions();
+    syncActiveRackNo();
+    if (!candidateRackTabs.value.length) {
+      if (!rackOptions.value.length) {
+        return toast.error("鏆傛棤鍙敤閾佹灦鍙凤紝璇峰厛缁存姢鏃舵晥閾佹灦鍙峰瓧鍏�");
+      }
+      toast.error("璇峰厛閫夋嫨閾佹灦鍙�");
+      openRackSelector();
+      return;
+    }
+    candidateRackNo.value =
+      candidateRackTabs.value.find((item) => item.value === activeRackNo.value)?.value ||
+      candidateRackTabs.value[0].value;
+  }
   candidatePopupVisible.value = true;
   loadCandidates(true);
+}
+
+function handleCandidateLayerChange() {
+  candidates.value.forEach((item) => {
+    item._selected = false;
+    if (materialType.value === "鍗曚笣") item.ironPlateNo = undefined;
+  });
 }
 
 async function loadCandidates(reset = false) {
@@ -385,11 +789,12 @@
       taskId: taskId.value,
       materialType: materialType.value,
     });
-    const rows = (data?.records || []).map((item: any) => ({ ...item, _selected: false }));
+    const rows = fillIronPlateNumbers(data?.records || [], reset ? [] : candidates.value);
     candidates.value = reset ? rows : [...candidates.value, ...rows];
+    recalculateCandidateIronPlateNumbers();
     candidateTotal.value = Number(data?.total || candidates.value.length);
   } catch (error: any) {
-    toast.error(error?.message || "鏌ヨ鍙�夋椂鏁堟槑缁嗗け璐�");
+    toast.error(error?.message || "鏌ヨ鍙鐢ㄧ墿鏂欏け璐�");
   } finally {
     candidateLoading.value = false;
   }
@@ -401,24 +806,48 @@
   loadCandidates(false);
 }
 
-async function addCandidates(rows: any[], successMessage = "鏃舵晥鏄庣粏鏂板鎴愬姛") {
+async function addCandidates(
+  rows: any[],
+  successMessage = "鐗╂枡棰嗙敤鎴愬姛",
+  layer = candidateRackNo.value
+) {
+  const validationMessage = validateIronPlateNumbers(rows, layer);
+  if (validationMessage) {
+    toast.error(validationMessage);
+    return false;
+  }
   const itemIds = rows
     .map((item) => getCandidateId(item))
     .filter((id): id is number | string => id !== undefined && id !== null && id !== "");
-  if (!itemIds.length) return toast.error("鎵�閫夌墿鏂欑己灏戞槑缁咺D");
-  await TimeSensitiveTaskApi.addItems({ taskId: taskId.value, itemIds });
+  if (itemIds.length !== rows.length) {
+    toast.error("鎵�閫夌墿鏂欑己灏戞槑缁咺D");
+    return false;
+  }
+  await TimeSensitiveTaskApi.addItems({
+    taskId: taskId.value,
+    itemIds,
+    items: rows.map((item, index) => ({
+      itemId: itemIds[index],
+      ironPlateNo:
+        materialType.value === "鍗曚笣"
+          ? `${layer}-${Number(item.ironPlateNo)}`
+          : Number(item.ironPlateNo),
+    })),
+  });
   toast.success(successMessage);
   await loadTask();
+  if (materialType.value === "鍗曚笣") activeRackNo.value = layer;
+  return true;
 }
 
 async function addSelectedCandidates() {
   if (!selectedCandidates.value.length) return toast.error("璇疯嚦灏戦�夋嫨涓�鏉″緟鏃舵晥鏁版嵁");
   candidateSubmitting.value = true;
   try {
-    await addCandidates(selectedCandidates.value);
-    candidatePopupVisible.value = false;
+    const added = await addCandidates(selectedCandidates.value);
+    if (added) candidatePopupVisible.value = false;
   } catch (error: any) {
-    toast.error(error?.message || "鏂板鏃舵晥鏄庣粏澶辫触");
+    toast.error(error?.message || "棰嗙敤鐗╂枡澶辫触");
   } finally {
     candidateSubmitting.value = false;
   }
@@ -438,7 +867,8 @@
   }
   const directCode = getMaterialCode(parsed);
   const outputId = parsed.id ?? parsed.outPutId ?? parsed.outputId;
-  if (directCode) return { raw, parsed, outputId, materialCode: directCode };
+  const ironPlateNo = parsed.ironPlateNo ?? parsed.ironPlateNumber;
+  if (directCode) return { raw, parsed, outputId, ironPlateNo, materialCode: directCode };
 
   const parts = raw.split(/[锛�,\s]/).filter(Boolean);
   const singleWireCode = parts.find((part) => part.startsWith("75"));
@@ -446,6 +876,7 @@
     raw,
     parsed,
     outputId,
+    ironPlateNo,
     materialCode: singleWireCode || (!Object.keys(parsed).length ? raw : ""),
   };
 }
@@ -469,6 +900,12 @@
 async function handleScan(event: any) {
   if (!pageVisible.value || scanSubmitting.value) return;
   if (!isWaiting.value) return toast.error("鍙湁寰呭紑濮嬬殑浠诲姟鍙互鎵爜鏂板鏄庣粏");
+  if (
+    materialType.value === "鍗曚笣" &&
+    (!activeRackNo.value || activeRackNo.value === UNASSIGNED_LAYER)
+  ) {
+    return toast.error("璇峰厛閫夋嫨鍗曚笣棰嗙敤閾佹灦鍙�");
+  }
   scanSubmitting.value = true;
   try {
     const scan = readScanPayload(event);
@@ -491,25 +928,30 @@
     if (!candidate) {
       return toast.error(`鏈壘鍒板彲娣诲姞鐨�${materialType.value}锛屽彲鑳藉凡娣诲姞鎴栦笉鍦ㄥ緟鏃舵晥鑼冨洿`);
     }
-    await addCandidates([candidate], "鎵爜娣诲姞鎴愬姛");
+    const suggestedNumber = Number(scan.ironPlateNo) || getNextIronPlateNo(activeRackNo.value);
+    const ironPlateNo =
+      materialType.value === "鍗曚笣" ? suggestedNumber : await requestIronPlateNo(suggestedNumber);
+    if (ironPlateNo === undefined) return;
+    await addCandidates([{ ...candidate, ironPlateNo }], "鎵爜棰嗙敤鎴愬姛", activeRackNo.value);
   } catch (error: any) {
-    toast.error(error?.message || "鎵爜娣诲姞鏃舵晥鏄庣粏澶辫触");
+    toast.error(error?.message || "鎵爜棰嗙敤鐗╂枡澶辫触");
   } finally {
     scanSubmitting.value = false;
   }
 }
 
-function openScan() {
+async function openScan() {
   if (!isWaiting.value) return toast.error("鍙湁寰呭紑濮嬬殑浠诲姟鍙互鎵爜鏂板鏄庣粏");
+  if (materialType.value === "鍗曚笣") {
+    await loadRackOptions();
+    syncActiveRackNo();
+    if (!activeRackNo.value || activeRackNo.value === UNASSIGNED_LAYER) {
+      toast.error("璇峰厛閫夋嫨鍗曚笣棰嗙敤閾佹灦鍙�");
+      openRackSelector();
+      return;
+    }
+  }
   scanRef.value?.triggerScan();
-}
-
-function simulateScan() {
-  const mockIds = materialType.value === "鍗曚笣" ? [9301, 9302, 9501] : [9401, 9402, 9201, 9202];
-  const existingIds = new Set(items.value.map((item) => String(getCandidateId(item))));
-  const nextId = mockIds.find((id) => !existingIds.has(String(id)));
-  if (!nextId) return toast.error(`娌℃湁鏇村鍙ā鎷熸壂鐮佺殑${materialType.value}`);
-  handleScan({ code: JSON.stringify({ id: nextId }) });
 }
 
 onLoad((options: any) => {
@@ -548,6 +990,16 @@
 .detail-header {
   flex-shrink: 0;
   background: #ffffff;
+}
+
+.detail-header :deep(.header-icon-button) {
+  width: 48px;
+  height: 48px;
+  margin-left: 6px;
+}
+
+.detail-header :deep(.header-icon-button .wd-icon) {
+  font-size: 26px !important;
 }
 
 .detail-scroll {
@@ -611,28 +1063,79 @@
 }
 
 .section-title {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  padding: 4px 12px 10px;
+  padding: 4px 16px 10px;
+  font-size: 18px;
   font-weight: 600;
 }
 
 .section-actions {
+  display: grid;
+  grid-template-columns: 1fr;
+  padding: 0 12px 12px;
+}
+
+.section-actions :deep(.section-action-button) {
+  height: 50px;
+  font-size: 17px;
+  font-weight: 600;
+  border-radius: 10px;
+}
+
+.layer-tabs-wrap,
+.candidate-layer-tabs {
+  margin: 0 10px 10px;
+  overflow: hidden;
+  background: #ffffff;
+  border-radius: 10px;
+}
+
+.candidate-layer-tabs {
+  flex-shrink: 0;
+  margin: 10px 12px 0;
+}
+
+.candidate-layer-label {
+  display: block;
+  padding: 10px 12px 4px;
+  font-size: 12px;
+  color: #666666;
+}
+
+.layer-loading,
+.layer-empty {
   display: flex;
-  flex-wrap: wrap;
-  gap: 10px;
-  justify-content: flex-end;
+  gap: 6px;
+  align-items: center;
+  justify-content: center;
+  min-height: 44px;
+  padding: 0 12px;
+  font-size: 12px;
+  color: #999999;
 }
 
-.section-link {
-  font-size: 13px;
-  font-weight: 400;
-  color: #0d867f;
+.layer-tabs-wrap :deep(.wd-tabs__nav),
+.candidate-layer-tabs :deep(.wd-tabs__nav) {
+  background: #ffffff;
 }
 
-.section-link.danger {
-  color: #fa4350;
+.rack-option-list {
+  flex: 1;
+  height: 0;
+  padding: 10px 12px;
+  box-sizing: border-box;
+}
+
+.rack-option-item {
+  display: flex;
+  gap: 12px;
+  align-items: center;
+  min-height: 58px;
+  padding: 0 14px;
+  margin-bottom: 8px;
+  font-size: 17px;
+  background: #ffffff;
+  border: 1px solid #eeeeee;
+  border-radius: 10px;
 }
 
 .item-list {
@@ -643,8 +1146,16 @@
   margin: 0 0 10px;
 }
 
-:deep(.delete-button .wd-button__content) {
-  color: #fa4350;
+.material-detail-link {
+  display: flex;
+  gap: 6px;
+  align-items: center;
+  justify-content: flex-end;
+  padding: 10px 12px;
+  font-size: 13px;
+  color: #0d867f;
+  background: #f8fbfa;
+  border-top: 1px solid #edf2f0;
 }
 
 .state-box {
@@ -690,13 +1201,23 @@
 
 .candidate-item {
   display: flex;
-  gap: 10px;
-  align-items: center;
-  padding: 12px;
+  flex-direction: column;
+  overflow: hidden;
   margin-bottom: 8px;
   background: #ffffff;
   border: 1px solid #eeeeee;
-  border-radius: 8px;
+  border-radius: 10px;
+}
+
+.candidate-header {
+  display: flex;
+  gap: 10px;
+  align-items: center;
+  width: 100%;
+  padding: 12px;
+  box-sizing: border-box;
+  background: #f8fbfa;
+  border-bottom: 1px solid #edf2f0;
 }
 
 .candidate-info {
@@ -720,8 +1241,22 @@
 .popup-footer {
   flex-shrink: 0;
   padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
-  font-size: 13px;
+  font-size: 15px;
   background: #ffffff;
   border-top: 1px solid #eeeeee;
 }
+
+.popup-footer :deep(.footer-action-button) {
+  min-width: 96px;
+  height: 48px;
+  font-size: 16px;
+  font-weight: 600;
+  border-radius: 10px;
+}
+
+:deep(.load-more-button) {
+  height: 48px;
+  font-size: 16px;
+  border-radius: 10px;
+}
 </style>
diff --git a/src/pages/timely/index.vue b/src/pages/timely/index.vue
index 3063f91..1d018e5 100644
--- a/src/pages/timely/index.vue
+++ b/src/pages/timely/index.vue
@@ -9,68 +9,7 @@
     >
       <template #top>
         <view class="page-top">
-          <CardTitle title="鏃舵晥浠诲姟鍙拌处" :hideAction="false">
-            <template #action>
-              <wd-tag type="warning" size="small">Mock</wd-tag>
-              <wd-button size="small" icon="add" @click="openCreatePopup">鏂板浠诲姟</wd-button>
-            </template>
-          </CardTitle>
-
-          <view class="date-filter-card">
-            <view class="date-filter-heading">
-              <view class="date-filter-title">
-                <view class="date-filter-icon">
-                  <wd-icon name="calendar" size="18px" color="#078568" />
-                </view>
-                <view>
-                  <view class="date-filter-name">閫夋嫨鏃ユ湡</view>
-                  <view class="date-filter-tip">鎸変换鍔″彂璧锋棩鏈熸煡璇�</view>
-                </view>
-              </view>
-              <text v-if="hasDateFilter" class="date-filter-clear" @click="resetFilters">娓呴櫎</text>
-            </view>
-            <view class="date-filter-fields">
-              <view class="date-filter-field">
-                <wd-datetime-picker v-model="filters.startTimestamp" type="date">
-                  <view class="date-picker-trigger">
-                    <text class="date-picker-label">寮�濮嬫棩鏈�</text>
-                    <view class="date-picker-value">
-                      <text :class="{ 'is-placeholder': !filters.startTimestamp }">
-                        {{
-                          filters.startTimestamp
-                            ? formatDateOnly(Number(filters.startTimestamp))
-                            : "璇烽�夋嫨"
-                        }}
-                      </text>
-                      <wd-icon name="arrow-right" size="13px" color="#aebbb7" />
-                    </view>
-                  </view>
-                </wd-datetime-picker>
-              </view>
-              <view class="date-filter-separator">鑷�</view>
-              <view class="date-filter-field">
-                <wd-datetime-picker v-model="filters.endTimestamp" type="date">
-                  <view class="date-picker-trigger">
-                    <text class="date-picker-label">缁撴潫鏃ユ湡</text>
-                    <view class="date-picker-value">
-                      <text :class="{ 'is-placeholder': !filters.endTimestamp }">
-                        {{
-                          filters.endTimestamp
-                            ? formatDateOnly(Number(filters.endTimestamp))
-                            : "璇烽�夋嫨"
-                        }}
-                      </text>
-                      <wd-icon name="arrow-right" size="13px" color="#aebbb7" />
-                    </view>
-                  </view>
-                </wd-datetime-picker>
-              </view>
-            </view>
-            <view class="date-filter-actions">
-              <wd-button size="small" type="info" plain @click="resetFilters">閲嶇疆</wd-button>
-              <wd-button size="small" icon="search" @click="applyFilters">鏌ヨ浠诲姟</wd-button>
-            </view>
-          </view>
+          <CardTitle title="鏃舵晥浠诲姟鍙拌处" :hideAction="false" />
         </view>
       </template>
 
@@ -118,7 +57,7 @@
                 <text>{{ task.machineName || task.machine || "-" }}</text>
               </view>
               <view class="info-item">
-                <text class="info-label">鏃舵晥浠舵暟</text>
+                <text class="info-label">棰嗘枡鏁伴噺</text>
                 <text>{{ task.itemCount ?? task.count ?? task.detailCount ?? 0 }} 浠�</text>
               </view>
             </view>
@@ -138,150 +77,14 @@
 
           <template #footer>
             <view class="task-actions">
-              <wd-button size="small" plain @click="openDetail(task)">鏄庣粏</wd-button>
-              <wd-button
-                v-if="isWaiting(task)"
-                size="small"
-                plain
-                type="warning"
-                @click="openEditPopup(task)"
-              >
-                缂栬緫
-              </wd-button>
-              <wd-button v-if="isWaiting(task)" size="small" plain @click="startTask(task)">
-                寮�濮嬫椂鏁�
-              </wd-button>
-              <wd-button
-                v-if="isWaiting(task)"
-                size="small"
-                plain
-                type="error"
-                @click="deleteTask(task)"
-              >
-                鍒犻櫎
-              </wd-button>
-              <wd-button
-                v-if="isRunning(task)"
-                size="small"
-                plain
-                type="error"
-                @click="endTask(task)"
-              >
-                缁撴潫鏃舵晥
-              </wd-button>
-              <wd-button
-                v-if="!isWaiting(task)"
-                size="small"
-                plain
-                type="success"
-                @click="openInspection(task)"
-              >
-                宸℃璁板綍
+              <wd-button block custom-class="claim-button" @click="openDetail(task)">
+                {{ isWaiting(task) ? "棰嗘枡" : "鏌ョ湅棰嗘枡璁板綍" }}
               </wd-button>
             </view>
           </template>
         </wd-card>
       </view>
     </z-paging>
-
-    <wd-popup
-      v-model="taskPopupVisible"
-      position="bottom"
-      :z-index="30"
-      :close-on-click-modal="false"
-      custom-style="height: 88vh; border-radius: 24rpx 24rpx 0 0;"
-    >
-      <view class="popup-layout">
-        <view class="popup-header">
-          <text class="popup-title">{{ editingTaskId ? "缂栬緫鏃舵晥浠诲姟" : "鏂板鏃舵晥浠诲姟" }}</text>
-          <wd-icon name="close" size="20px" @click="taskPopupVisible = false" />
-        </view>
-        <scroll-view class="popup-body" scroll-y>
-          <wd-form ref="taskFormRef" :model="taskForm">
-            <wd-cell-group border>
-              <wd-picker
-                v-model="taskForm.materialType"
-                :columns="materialTypeOptions"
-                label="浠诲姟绫诲瀷"
-                required
-                :z-index="40"
-              />
-              <wd-picker
-                v-model="taskForm.initiatorName"
-                :columns="userOptions"
-                label="鍙戣捣浠诲姟浜�"
-                placeholder="璇烽�夋嫨"
-                required
-                :loading="optionsLoading"
-                :z-index="40"
-              />
-              <wd-datetime-picker
-                v-model="taskForm.initiateTimestamp"
-                label="鍙戣捣鏃堕棿"
-                type="datetime"
-                required
-                use-second
-                :z-index="40"
-              />
-              <wd-picker
-                v-model="taskForm.inspectorName"
-                :columns="userOptions"
-                label="宸℃鍛�"
-                placeholder="璇烽�夋嫨"
-                required
-                :loading="optionsLoading"
-                :z-index="40"
-              />
-              <wd-input
-                v-model="taskForm.setTemperature"
-                label="璁惧畾娓╁害(鈩�)"
-                type="digit"
-                required
-                placeholder="璇疯緭鍏�"
-              />
-              <wd-cell title="鏃舵晥鏃堕暱(灏忔椂)" required />
-              <view class="duration-row">
-                <wd-input
-                  v-model="taskForm.durationRise"
-                  type="digit"
-                  placeholder="鍗囨俯"
-                  no-border
-                />
-                <text>+</text>
-                <wd-input
-                  v-model="taskForm.durationHold"
-                  type="digit"
-                  placeholder="淇濇俯"
-                  no-border
-                />
-                <text>+</text>
-                <wd-input
-                  v-model="taskForm.durationSoak"
-                  type="digit"
-                  placeholder="鐒栫倝"
-                  no-border
-                />
-              </view>
-              <wd-picker
-                v-model="taskForm.machineName"
-                :columns="machineOptions"
-                label="璁惧畾鏈哄彴"
-                placeholder="璇烽�夋嫨鏃舵晥鏈哄彴"
-                required
-                :loading="optionsLoading"
-                :z-index="40"
-              />
-            </wd-cell-group>
-          </wd-form>
-        </scroll-view>
-        <view class="popup-footer">
-          <wd-button type="info" plain @click="taskPopupVisible = false">鍙栨秷</wd-button>
-          <wd-button :loading="taskSubmitting" @click="submitTask">
-            {{ editingTaskId ? "淇濆瓨淇敼" : "纭畾鏂板" }}
-          </wd-button>
-        </view>
-      </view>
-    </wd-popup>
 
     <wd-toast />
   </view>
@@ -293,82 +96,18 @@
 import type { TagType } from "wot-design-uni/components/wd-tag/types";
 import CardTitle from "@/components/card-title/index.vue";
 import zPaging from "@/components/z-paging/z-paging.vue";
-import TimeSensitiveTaskApi, {
-  type TimelinessMaterialType,
-  type TimeSensitiveTaskForm,
-} from "@/api/timeSensitiveTask";
-import { useUserStore } from "@/store/modules/user";
+import TimeSensitiveTaskApi, { type TimelinessMaterialType } from "@/api/timeSensitiveTask";
 
 const toast = useToast();
-const userStore = useUserStore();
 const pagingRef = ref();
-const taskFormRef = ref();
 const taskList = ref<any[]>([]);
-const taskPopupVisible = ref(false);
-const taskSubmitting = ref(false);
-const optionsLoading = ref(false);
-const editingTaskId = ref<number | string | undefined>();
 const pageReady = ref(false);
-
-const materialTypeOptions = [
-  { label: "鍗曚笣", value: "鍗曚笣" },
-  { label: "缁炵嚎", value: "缁炵嚎" },
-];
 
 const statusOptions = [
   { label: "寰呭紑濮�", value: 0 },
   { label: "鏃舵晥涓�", value: 1 },
   { label: "鏃舵晥缁撴潫", value: 2 },
 ];
-
-const filters = reactive({
-  startTimestamp: "" as "" | number,
-  endTimestamp: "" as "" | number,
-});
-const hasDateFilter = computed(() => Boolean(filters.startTimestamp || filters.endTimestamp));
-
-const taskForm = reactive({
-  materialType: "鍗曚笣" as TimelinessMaterialType,
-  initiatorName: "",
-  initiateTimestamp: Date.now() as number,
-  setTemperature: "" as string | number,
-  durationRise: 2 as string | number,
-  durationHold: "" as string | number,
-  durationSoak: "" as string | number,
-  machineName: "",
-  inspectorName: "",
-});
-
-const userOptions = ref<Array<{ label: string; value: string }>>([]);
-const machineOptions = ref<Array<{ label: string; value: string }>>([]);
-
-function pad(value: number) {
-  return String(value).padStart(2, "0");
-}
-
-function formatDateTime(value: number | Date) {
-  const date = value instanceof Date ? value : new Date(value);
-  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(
-    date.getHours()
-  )}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
-}
-
-function formatDate(value: number, endOfDay = false) {
-  const date = new Date(value);
-  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${
-    endOfDay ? "23:59:59" : "00:00:00"
-  }`;
-}
-
-function formatDateOnly(value: number) {
-  return formatDate(value).slice(0, 10);
-}
-
-function parseDateTime(value: unknown) {
-  if (!value) return Date.now();
-  const timestamp = new Date(String(value).replace(/-/g, "/")).getTime();
-  return Number.isFinite(timestamp) ? timestamp : Date.now();
-}
 
 function normalizeStatus(task: any) {
   const key = String(task?.taskStatus ?? task?.timelinessStatus ?? task?.status ?? "")
@@ -387,10 +126,6 @@
 
 function isWaiting(task: any) {
   return normalizeStatus(task) === 0;
-}
-
-function isRunning(task: any) {
-  return normalizeStatus(task) === 1;
 }
 
 function getStatusLabel(task: any) {
@@ -428,8 +163,6 @@
     const { data } = await TimeSensitiveTaskApi.queryPage({
       current: pageNo,
       size: pageSize,
-      startTime: filters.startTimestamp ? formatDate(Number(filters.startTimestamp)) : undefined,
-      endTime: filters.endTimestamp ? formatDate(Number(filters.endTimestamp), true) : undefined,
     });
     pagingRef.value?.complete(data?.records || []);
   } catch (error: any) {
@@ -440,285 +173,8 @@
   }
 }
 
-function applyFilters() {
-  if (
-    filters.startTimestamp &&
-    filters.endTimestamp &&
-    Number(filters.startTimestamp) > Number(filters.endTimestamp)
-  ) {
-    toast.error("寮�濮嬫棩鏈熶笉鑳芥櫄浜庣粨鏉熸棩鏈�");
-    return;
-  }
-  pagingRef.value?.reload();
-}
-
-function resetFilters() {
-  Object.assign(filters, {
-    startTimestamp: "",
-    endTimestamp: "",
-  });
-  applyFilters();
-}
-
-function getCurrentPerson() {
-  const user = userStore.userInfo as any;
-  return user?.nickName || user?.nickname || user?.userName || user?.username || "";
-}
-
-function getPersonName(item: any) {
-  return String(item?.nickName || item?.nickname || item?.userName || item?.username || "");
-}
-
-function getMachineName(item: any) {
-  return String(item?.deviceModel || item?.device_model || item?.deviceName || item?.name || "");
-}
-
-async function loadOptions() {
-  if (userOptions.value.length && machineOptions.value.length) return;
-  optionsLoading.value = true;
-  try {
-    const [usersResult, machinesResult] = await Promise.all([
-      TimeSensitiveTaskApi.getUsers(),
-      TimeSensitiveTaskApi.getMachines(),
-    ]);
-    userOptions.value = (usersResult.data || [])
-      .map((item: any) => getPersonName(item))
-      .filter(Boolean)
-      .map((name: string) => ({ label: name, value: name }));
-    machineOptions.value = (machinesResult.data || [])
-      .map((item: any) => getMachineName(item))
-      .filter(Boolean)
-      .map((name: string) => ({ label: name, value: name }));
-  } catch (error: any) {
-    toast.error(error?.message || "鑾峰彇浜哄憳鎴栨椂鏁堟満鍙板け璐�");
-  } finally {
-    optionsLoading.value = false;
-  }
-}
-
-function resetTaskForm() {
-  const currentPerson = getCurrentPerson();
-  Object.assign(taskForm, {
-    materialType: "鍗曚笣",
-    initiatorName: currentPerson,
-    initiateTimestamp: Date.now(),
-    setTemperature: "",
-    durationRise: 2,
-    durationHold: "",
-    durationSoak: "",
-    machineName: "",
-    inspectorName: currentPerson,
-  });
-}
-
-function parseDuration(value: unknown) {
-  const parts = String(value ?? "")
-    .replace(/灏忔椂/g, "")
-    .split("+")
-    .map((item) => Number(item.trim()));
-  if (parts.length >= 3 && parts.every(Number.isFinite)) return parts;
-  return [2, Number.isFinite(parts[0]) ? parts[0] : "", ""];
-}
-
-async function openCreatePopup() {
-  editingTaskId.value = undefined;
-  resetTaskForm();
-  taskPopupVisible.value = true;
-  await loadOptions();
-}
-
-async function openEditPopup(task: any) {
-  if (!isWaiting(task)) return;
-  try {
-    const { data } = await TimeSensitiveTaskApi.getDetail(task.id);
-    const detail = { ...task, ...(data || {}) };
-    const duration = parseDuration(detail.agingDuration ?? detail.duration);
-    editingTaskId.value = detail.id;
-    Object.assign(taskForm, {
-      materialType: normalizeMaterialType(detail.materialType),
-      initiatorName: getInitiator(detail) === "-" ? "" : getInitiator(detail),
-      initiateTimestamp: parseDateTime(
-        detail.initiateTime || detail.startTime || detail.createTime
-      ),
-      setTemperature: detail.setTemperature ?? detail.temperature ?? "",
-      durationRise: duration[0],
-      durationHold: duration[1],
-      durationSoak: duration[2],
-      machineName: detail.machineName || detail.machine || "",
-      inspectorName: getInspector(detail) === "-" ? "" : getInspector(detail),
-    });
-    taskPopupVisible.value = true;
-    await loadOptions();
-  } catch (error: any) {
-    toast.error(error?.message || "鑾峰彇鏃舵晥浠诲姟璇︽儏澶辫触");
-  }
-}
-
-function buildTaskPayload(): TimeSensitiveTaskForm | null {
-  if (!taskForm.materialType) return (toast.error("璇烽�夋嫨浠诲姟绫诲瀷"), null);
-  if (!taskForm.initiatorName) return (toast.error("璇烽�夋嫨鍙戣捣浠诲姟浜�"), null);
-  if (!taskForm.initiateTimestamp) return (toast.error("璇烽�夋嫨鍙戣捣鏃堕棿"), null);
-  if (taskForm.setTemperature === "") return (toast.error("璇疯緭鍏ヨ瀹氭俯搴�"), null);
-  if (taskForm.durationHold === "") return (toast.error("璇疯緭鍏ヤ繚娓╂椂闀�"), null);
-  if (!taskForm.machineName) return (toast.error("璇烽�夋嫨璁惧畾鏈哄彴"), null);
-  if (!taskForm.inspectorName) return (toast.error("璇烽�夋嫨宸℃鍛�"), null);
-
-  return {
-    materialType: taskForm.materialType,
-    initiatorName: taskForm.initiatorName,
-    initiateTime: formatDateTime(Number(taskForm.initiateTimestamp)),
-    setTemperature: taskForm.setTemperature,
-    agingDuration: `${taskForm.durationRise || 0}+${taskForm.durationHold || 0}+${
-      taskForm.durationSoak || 0
-    }`,
-    machineName: taskForm.machineName,
-    inspectorName: taskForm.inspectorName,
-  };
-}
-
-async function submitTask() {
-  const payload = buildTaskPayload();
-  if (!payload || taskSubmitting.value) return;
-  taskSubmitting.value = true;
-  try {
-    const result = editingTaskId.value
-      ? await TimeSensitiveTaskApi.update({ id: editingTaskId.value, ...payload })
-      : await TimeSensitiveTaskApi.create(payload);
-    taskPopupVisible.value = false;
-    toast.success(editingTaskId.value ? "鏃舵晥浠诲姟淇敼鎴愬姛" : "鏂板鎴愬姛锛岃娣诲姞鏃舵晥鏄庣粏");
-    pagingRef.value?.reload();
-    if (!editingTaskId.value) {
-      const resultData = result.data;
-      const newId =
-        resultData && typeof resultData === "object"
-          ? resultData.id || resultData.taskId
-          : resultData;
-      if (newId) {
-        setTimeout(() => {
-          uni.navigateTo({ url: `/pages/timely/detail?id=${newId}` });
-        }, 500);
-      }
-    }
-  } catch (error: any) {
-    toast.error(error?.message || `${editingTaskId.value ? "淇敼" : "鏂板"}鏃舵晥浠诲姟澶辫触`);
-  } finally {
-    taskSubmitting.value = false;
-  }
-}
-
-function showConfirm(title: string, content: string, confirmText = "纭畾") {
-  return new Promise<boolean>((resolve) => {
-    uni.showModal({
-      title,
-      content,
-      confirmText,
-      success: (result) => resolve(Boolean(result.confirm)),
-      fail: () => resolve(false),
-    });
-  });
-}
-
-async function deleteTask(task: any) {
-  if (!isWaiting(task)) return toast.error("鍙湁寰呭紑濮嬬殑浠诲姟鍙互鍒犻櫎");
-  const confirmed = await showConfirm(
-    "鍒犻櫎浠诲姟",
-    `纭畾鍒犻櫎鏃舵晥浠诲姟鈥�${task.taskCode || task.id}鈥濆悧锛熶换鍔℃槑缁嗕篃浼氫竴骞跺垹闄ゃ�俙,
-    "鍒犻櫎"
-  );
-  if (!confirmed) return;
-  try {
-    await TimeSensitiveTaskApi.delete(task.id);
-    toast.success("鏃舵晥浠诲姟鍒犻櫎鎴愬姛");
-    pagingRef.value?.reload();
-  } catch (error: any) {
-    toast.error(error?.message || "鍒犻櫎鏃舵晥浠诲姟澶辫触");
-  }
-}
-
-async function startTask(task: any) {
-  if (!isWaiting(task)) return;
-  try {
-    const [detailResult, itemsResult] = await Promise.all([
-      TimeSensitiveTaskApi.getDetail(task.id),
-      TimeSensitiveTaskApi.getItems(task.id),
-    ]);
-    const detail = { ...task, ...(detailResult.data || {}) };
-    const items = Array.isArray(itemsResult.data)
-      ? itemsResult.data
-      : (itemsResult.data as any)?.records || [];
-    const payload = {
-      id: task.id,
-      materialType: normalizeMaterialType(detail.materialType),
-      initiatorName: getInitiator(detail) === "-" ? "" : getInitiator(detail),
-      initiateTime: detail.initiateTime || detail.startTime || detail.createTime || "",
-      setTemperature: detail.setTemperature ?? detail.temperature ?? "",
-      agingDuration: detail.agingDuration ?? detail.duration ?? "",
-      machineName: detail.machineName || detail.machine || "",
-      furnaceInTime: detail.furnaceInTime || formatDateTime(new Date()),
-      inspectorName: getInspector(detail) === "-" ? "" : getInspector(detail),
-    };
-    if (
-      Object.values(payload).some(
-        (value) => value === undefined || value === null || String(value) === ""
-      )
-    ) {
-      return toast.error("浠诲姟鍩虹淇℃伅涓嶅畬鏁达紝璇峰厛缂栬緫瀹屽杽");
-    }
-    if (!items.length) return toast.error("褰撳墠浠诲姟娌℃湁鏃舵晥鏄庣粏锛屼笉鑳藉紑濮嬫椂鏁�");
-    const confirmed = await showConfirm(
-      "寮�濮嬫椂鏁�",
-      `浠诲姟锛�${task.taskCode || task.id}\n鏄庣粏锛�${items.length}浠禱n鏈哄彴锛�${payload.machineName}\n纭寮�濮嬫椂鏁堝悧锛焋,
-      "寮�濮�"
-    );
-    if (!confirmed) return;
-    await TimeSensitiveTaskApi.start(payload);
-    toast.success("鏃舵晥宸插紑濮�");
-    pagingRef.value?.reload();
-  } catch (error: any) {
-    toast.error(error?.message || "寮�濮嬫椂鏁堝け璐�");
-  }
-}
-
-function parseCanEnd(data: any) {
-  if (typeof data === "boolean") return data;
-  return Boolean(data?.canEnd ?? data?.reachedDuration);
-}
-
-async function endTask(task: any) {
-  if (!isRunning(task)) return;
-  try {
-    const { data } = await TimeSensitiveTaskApi.checkEnd(task.id);
-    const canEnd = parseCanEnd(data);
-    const durationText =
-      data?.elapsedMinutes != null && data?.requiredMinutes != null
-        ? `褰撳墠宸叉椂鏁� ${data.elapsedMinutes} 鍒嗛挓锛岃瀹氭椂闀� ${data.requiredMinutes} 鍒嗛挓銆俙
-        : "褰撳墠灏氭湭杈惧埌璁惧畾鏃舵晥鏃堕暱銆�";
-    const confirmed = await showConfirm(
-      canEnd ? "缁撴潫鏃舵晥" : "鏃堕暱鏈揪鍒�",
-      canEnd
-        ? "宸茶揪鍒拌瀹氭椂鏁堟椂闀匡紝纭畾缁撴潫鏃舵晥鍚楋紵"
-        : `${data?.message || durationText}鏄惁浠嶈缁撴潫鏃舵晥锛焋,
-      canEnd ? "缁撴潫" : "浠嶇劧缁撴潫"
-    );
-    if (!confirmed) return;
-    await TimeSensitiveTaskApi.end({ id: task.id, forceEnd: !canEnd });
-    toast.success("鏃舵晥宸茬粨鏉�");
-    pagingRef.value?.reload();
-  } catch (error: any) {
-    toast.error(error?.message || "缁撴潫鏃舵晥澶辫触");
-  }
-}
-
 function openDetail(task: any) {
   uni.navigateTo({ url: `/pages/timely/detail?id=${task.id}` });
-}
-
-function openInspection(task: any) {
-  const inspectionId = task.timelinessInspectionId || task.inspectionId || task.id;
-  const readonly = normalizeStatus(task) === 2 ? 1 : 0;
-  uni.navigateTo({
-    url: `/pages/timely/inspection?id=${inspectionId}&readonly=${readonly}`,
-  });
 }
 
 onShow(() => {
@@ -736,117 +192,17 @@
   background: #ffffff;
 }
 
-.date-filter-card {
-  padding: 12px;
-  margin: 0 10px 10px;
-  background: linear-gradient(135deg, #f3fbf8 0%, #ffffff 72%);
-  border: 1px solid rgba(7, 133, 104, 0.12);
-  border-radius: 12px;
-  box-shadow: 0 4px 14px rgba(19, 94, 78, 0.06);
-}
-
-.date-filter-heading,
-.date-filter-title,
-.date-filter-fields,
-.date-filter-actions,
-.popup-footer,
 .task-actions {
   display: flex;
+  width: 100%;
   align-items: center;
 }
 
-.date-filter-heading {
-  justify-content: space-between;
-  margin-bottom: 10px;
-}
-
-.date-filter-title {
-  gap: 8px;
-}
-
-.date-filter-icon {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 32px;
-  height: 32px;
-  background: rgba(7, 133, 104, 0.1);
-  border-radius: 9px;
-}
-
-.date-filter-name {
-  font-size: 14px;
+:deep(.claim-button) {
+  height: 42px;
+  font-size: 15px;
   font-weight: 600;
-  color: #243832;
-}
-
-.date-filter-tip {
-  margin-top: 2px;
-  font-size: 11px;
-  color: #91a09c;
-}
-
-.date-filter-clear {
-  padding: 5px 0 5px 10px;
-  font-size: 12px;
-  color: #078568;
-}
-
-.date-filter-fields {
-  gap: 7px;
-}
-
-.date-filter-field {
-  flex: 1;
-  min-width: 0;
-  background: #ffffff;
-  border: 1px solid #e5efec;
-  border-radius: 8px;
-}
-
-.date-picker-trigger {
-  padding: 9px 10px;
-}
-
-.date-picker-label {
-  display: block;
-  margin-bottom: 5px;
-  font-size: 11px;
-  color: #8c9b97;
-}
-
-.date-picker-value {
-  display: flex;
-  gap: 4px;
-  align-items: center;
-  justify-content: space-between;
-  font-size: 13px;
-  font-weight: 500;
-  color: #2b3c37;
-}
-
-.is-placeholder {
-  font-weight: 400;
-  color: #b7c1be;
-}
-
-.date-filter-separator {
-  flex: none;
-  font-size: 12px;
-  color: #8c9b97;
-}
-
-.date-filter-actions {
-  gap: 8px;
-  justify-content: flex-end;
-  margin-top: 10px;
-}
-
-.popup-footer,
-.task-actions {
-  flex-wrap: wrap;
-  gap: 8px;
-  justify-content: flex-end;
+  border-radius: 10px;
 }
 
 .task-list {
@@ -905,52 +261,5 @@
 .info-label {
   font-size: 12px;
   color: #999999;
-}
-
-.popup-layout {
-  display: flex;
-  flex-direction: column;
-  height: 100%;
-  background: #f7f8fa;
-}
-
-.popup-header {
-  display: flex;
-  flex-shrink: 0;
-  align-items: center;
-  justify-content: space-between;
-  padding: 16px;
-  background: #ffffff;
-  border-bottom: 1px solid #eeeeee;
-}
-
-.popup-title {
-  font-size: 17px;
-  font-weight: 600;
-}
-
-.popup-body {
-  flex: 1;
-  height: 0;
-}
-
-.popup-footer {
-  flex-shrink: 0;
-  padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
-  background: #ffffff;
-  border-top: 1px solid #eeeeee;
-}
-
-.duration-row {
-  display: grid;
-  grid-template-columns: 1fr auto 1fr auto 1fr;
-  gap: 4px;
-  align-items: center;
-  padding: 0 12px 10px;
-  background: #ffffff;
-}
-
-.duration-row :deep(.wd-input) {
-  padding: 0;
 }
 </style>
diff --git a/src/pages/timely/materialDetail.vue b/src/pages/timely/materialDetail.vue
new file mode 100644
index 0000000..89d34ef
--- /dev/null
+++ b/src/pages/timely/materialDetail.vue
@@ -0,0 +1,315 @@
+<template>
+  <scroll-view class="material-page" scroll-y>
+    <view v-if="materialReady" class="page-content">
+      <view class="hero-card">
+        <view class="hero-top">
+          <wd-tag :type="materialType === '鍗曚笣' ? 'primary' : 'success'" size="small">
+            {{ materialType }}
+          </wd-tag>
+          <view class="iron-plate">閾佺洏鍙� {{ material.ironPlateNo ?? "-" }}</view>
+        </view>
+        <text class="material-code">{{ materialCode || "-" }}</text>
+        <text class="material-model">{{ material.model || "瑙勬牸鍨嬪彿鏈~鍐�" }}</text>
+      </view>
+
+      <view class="detail-card">
+        <view class="section-heading">鐗╂枡淇℃伅</view>
+        <view class="detail-row">
+          <text class="detail-label">瑙勬牸鍨嬪彿</text>
+          <text class="detail-value">{{ material.model || "-" }}</text>
+        </view>
+        <view v-if="materialType === '鍗曚笣'" class="detail-row">
+          <text class="detail-label">閾濇潌鍨嬪彿</text>
+          <text class="detail-value">{{ material.poleModel || material.rodModel || "-" }}</text>
+        </view>
+        <view v-if="materialType === '鍗曚笣'" class="detail-row">
+          <text class="detail-label">閾濇潌鍙�</text>
+          <text class="detail-value">{{ material.rodNo || material.poleNumber || "-" }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">娴佽浆鐮�/鎵规鍙�</text>
+          <text class="detail-value">{{ materialCode || "-" }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">{{ materialType === "鍗曚笣" ? "閲嶉噺(kg)" : "鐢熶骇閲嶉噺" }}</text>
+          <text class="detail-value">{{ materialWeight }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">鍗曚綅</text>
+          <text class="detail-value">{{ material.unit || "-" }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">鍘傚</text>
+          <text class="detail-value">{{ material.supplier || "-" }}</text>
+        </view>
+      </view>
+
+      <view class="detail-card">
+        <view class="section-heading">璐ㄦ淇℃伅</view>
+        <view class="quality-grid">
+          <view class="quality-item">
+            <text class="quality-label">璐ㄦ娓╁害</text>
+            <text class="quality-value">{{ qualityTemperature }}</text>
+          </view>
+          <view class="quality-item">
+            <text class="quality-label">璐ㄦ鏃堕暱</text>
+            <text class="quality-value">{{ qualityDuration }}</text>
+          </view>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">鐘舵��</text>
+          <wd-tag :type="statusType" size="small">{{ materialStatus }}</wd-tag>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">纭鏃舵晥鏃堕棿</text>
+          <text class="detail-value">{{ confirmTime }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">纭浜�</text>
+          <text class="detail-value">{{ confirmUser }}</text>
+        </view>
+      </view>
+
+      <view class="detail-card">
+        <view class="section-heading">鐢熶骇淇℃伅</view>
+        <view class="detail-row">
+          <text class="detail-label">閿�鍞悎鍚屽彿</text>
+          <text class="detail-value">{{ material.ledgerNo || "-" }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">鎺掍骇鏄庣粏鍙�</text>
+          <text class="detail-value">{{ material.schedulingDetailNo || "-" }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">璁惧缂栧彿</text>
+          <text class="detail-value">{{ material.deviceCode || "-" }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">瀹㈡埛鍚嶇О</text>
+          <text class="detail-value">{{ material.clientName || "-" }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">鐢熶骇鏃ユ湡</text>
+          <text class="detail-value">{{ material.productionDate || "-" }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">鐝</text>
+          <text class="detail-value">{{ material.groupTeam || "-" }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">鐝粍闀�</text>
+          <text class="detail-value">{{ material.groupTeamLeader || "-" }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="detail-label">鐢熶骇鏁伴噺</text>
+          <text class="detail-value">{{ material.productionNumber ?? "-" }}</text>
+        </view>
+      </view>
+    </view>
+
+    <view v-else class="empty-state">
+      <wd-status-tip image="content" tip="鏈幏鍙栧埌鐗╂枡璇︽儏" />
+    </view>
+  </scroll-view>
+</template>
+
+<script setup lang="ts">
+import { onLoad } from "@dcloudio/uni-app";
+import type { TagType } from "wot-design-uni/components/wd-tag/types";
+
+const material = ref<any>({});
+const materialReady = computed(() => Object.keys(material.value).length > 0);
+const materialType = computed(() => {
+  const value = String(material.value.materialType || "");
+  return value.includes("缁�") || value === "鎴愬搧" ? "缁炵嚎" : "鍗曚笣";
+});
+const materialCode = computed(() =>
+  String(
+    material.value.flowCode ||
+      material.value.batchCode ||
+      material.value.monofilamentNumber ||
+      material.value.monofilamentnumber ||
+      material.value.materialCode ||
+      material.value.systemNo ||
+      material.value.systemno ||
+      ""
+  ).trim()
+);
+const materialWeight = computed(
+  () => material.value.weight ?? material.value.productionWeight ?? material.value.weightSum ?? "-"
+);
+const qualityTemperature = computed(() => {
+  const value =
+    material.value.qualitySetTemperature ??
+    material.value.qualityTemperature ??
+    material.value.inspectionTemperature ??
+    material.value.temperature;
+  return value === undefined || value === null || value === "" ? "-" : `${value}鈩僠;
+});
+const qualityDuration = computed(
+  () =>
+    material.value.qualitySetDuration ||
+    material.value.qualityDuration ||
+    material.value.inspectionDuration ||
+    material.value.duration ||
+    "-"
+);
+const confirmTime = computed(
+  () =>
+    material.value.confirmTime ||
+    material.value.confirmTimelinessTime ||
+    material.value.createTime ||
+    "-"
+);
+const confirmUser = computed(
+  () =>
+    material.value.confirmUserName ||
+    material.value.confirmPerson ||
+    material.value.createUserName ||
+    material.value.userName ||
+    "-"
+);
+const materialStatus = computed(() => {
+  const value = material.value.status ?? material.value.timelinessStatus;
+  if (value === 1 || value === "1" || value === "PROCESSING") return "鏃舵晥涓�";
+  if (value === 2 || value === "2" || value === "FINISHED") return "鏃舵晥缁撴潫";
+  return "寰呮椂鏁�";
+});
+const statusType = computed<TagType>(() => {
+  if (materialStatus.value === "鏃舵晥涓�") return "primary";
+  if (materialStatus.value === "鏃舵晥缁撴潫") return "success";
+  return "warning";
+});
+
+onLoad(() => {
+  const pages = getCurrentPages();
+  const currentPage = pages[pages.length - 1] as any;
+  const eventChannel = currentPage?.getOpenerEventChannel?.();
+  eventChannel?.on("materialDetail", (data: any) => {
+    material.value = data || {};
+  });
+});
+</script>
+
+<style lang="scss" scoped>
+.material-page {
+  height: calc(100vh - 50px);
+  background: #f3f9f8;
+}
+
+.page-content {
+  padding: 12px 12px calc(24px + env(safe-area-inset-bottom));
+}
+
+.hero-card,
+.detail-card {
+  overflow: hidden;
+  margin-bottom: 12px;
+  background: #ffffff;
+  border: 1px solid rgba(13, 134, 127, 0.08);
+  border-radius: 14px;
+  box-shadow: 0 5px 18px rgba(35, 91, 82, 0.06);
+}
+
+.hero-card {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  padding: 16px;
+  background: linear-gradient(135deg, #ffffff 0%, #ecf8f5 100%);
+}
+
+.hero-top {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.iron-plate {
+  padding: 5px 9px;
+  font-size: 12px;
+  font-weight: 600;
+  color: #087d72;
+  background: rgba(13, 134, 127, 0.1);
+  border-radius: 999px;
+}
+
+.material-code {
+  overflow-wrap: anywhere;
+  font-size: 20px;
+  font-weight: 700;
+  color: #20322e;
+}
+
+.material-model {
+  font-size: 14px;
+  color: #697a76;
+}
+
+.section-heading {
+  padding: 14px 15px 10px;
+  font-size: 15px;
+  font-weight: 700;
+  color: #263a35;
+  border-bottom: 1px solid #edf2f0;
+}
+
+.detail-row {
+  display: flex;
+  gap: 18px;
+  align-items: flex-start;
+  justify-content: space-between;
+  padding: 12px 15px;
+  font-size: 14px;
+  border-bottom: 1px solid #f1f4f3;
+}
+
+.detail-row:last-child {
+  border-bottom: 0;
+}
+
+.detail-label {
+  flex: none;
+  color: #7e8d89;
+}
+
+.detail-value {
+  min-width: 0;
+  color: #293a36;
+  text-align: right;
+  overflow-wrap: anywhere;
+}
+
+.quality-grid {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 10px;
+  padding: 12px 15px;
+  background: #fbfdfc;
+  border-bottom: 1px solid #f1f4f3;
+}
+
+.quality-item {
+  display: flex;
+  flex-direction: column;
+  gap: 5px;
+  padding: 12px;
+  background: #f0f8f6;
+  border-radius: 10px;
+}
+
+.quality-label {
+  font-size: 12px;
+  color: #788984;
+}
+
+.quality-value {
+  font-size: 17px;
+  font-weight: 700;
+  color: #0d867f;
+}
+
+.empty-state {
+  padding-top: 80px;
+}
+</style>

--
Gitblit v1.9.3