From a80c78c89ff189fa2085e5570618a1dab40e48f6 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期六, 14 三月 2026 10:20:37 +0800
Subject: [PATCH] fix: 设备保养:可以在app上面进行设备保养计划新增,可多选设备(不需要设备编号),计划新增后,需定时生成多条任务(根据选择的多个设备生成多个任务)

---
 src/pages/equipmentManagement/upkeep/index.vue                  |  360 +++++++---
 src/pages/index.vue                                             |   31 
 src/pages.json                                                  |   11 
 src/pages/indexItem.vue                                         |    5 
 src/api/equipmentManagement/inspection.js                       |  212 +++---
 src/api/equipmentManagement/upkeep.js                           |   36 +
 src/pages/equipmentManagement/upkeepTask/index.vue              |  449 ++++++++++++++
 src/pages/equipmentManagement/upkeepTask/components/formDia.vue |  659 +++++++++++++++++++++
 src/pages/inspectionManagement/index.vue                        |   74 --
 9 files changed, 1,539 insertions(+), 298 deletions(-)

diff --git a/src/api/equipmentManagement/inspection.js b/src/api/equipmentManagement/inspection.js
index c3113a8..7813bc2 100644
--- a/src/api/equipmentManagement/inspection.js
+++ b/src/api/equipmentManagement/inspection.js
@@ -1,6 +1,6 @@
-import request from '@/utils/request'
+import request from "@/utils/request";
 
-// ==================== 宸℃浠诲姟绠$悊 ====================
+// ==================== 宸℃浠诲姟 ====================
 
 /**
  * @desc 鏌ヨ宸℃浠诲姟鍒楄〃
@@ -12,10 +12,10 @@
  */
 export function getInspectionTaskList(query) {
   return request({
-    url: '/equipment/inspection/task/list',
-    method: 'get',
-    params: query
-  })
+    url: "/equipment/inspection/task/list",
+    method: "get",
+    params: query,
+  });
 }
 
 /**
@@ -25,9 +25,9 @@
  */
 export function getInspectionTask(id) {
   return request({
-    url: '/equipment/inspection/task/' + id,
-    method: 'get'
-  })
+    url: "/equipment/inspection/task/" + id,
+    method: "get",
+  });
 }
 
 /**
@@ -37,10 +37,10 @@
  */
 export function createInspectionTask(data) {
   return request({
-    url: '/equipment/inspection/task',
-    method: 'post',
-    data: data
-  })
+    url: "/equipment/inspection/task",
+    method: "post",
+    data: data,
+  });
 }
 
 /**
@@ -50,10 +50,10 @@
  */
 export function updateInspectionTask(data) {
   return request({
-    url: '/equipment/inspection/task',
-    method: 'put',
-    data: data
-  })
+    url: "/equipment/inspection/task",
+    method: "put",
+    data: data,
+  });
 }
 
 /**
@@ -63,9 +63,9 @@
  */
 export function deleteInspectionTask(id) {
   return request({
-    url: '/equipment/inspection/task/' + id,
-    method: 'delete'
-  })
+    url: "/equipment/inspection/task/" + id,
+    method: "delete",
+  });
 }
 
 /**
@@ -75,9 +75,9 @@
  */
 export function startInspectionTask(taskId) {
   return request({
-    url: '/equipment/inspection/task/' + taskId + '/start',
-    method: 'post'
-  })
+    url: "/equipment/inspection/task/" + taskId + "/start",
+    method: "post",
+  });
 }
 
 /**
@@ -88,10 +88,10 @@
  */
 export function completeInspectionTask(taskId, data) {
   return request({
-    url: '/equipment/inspection/task/' + taskId + '/complete',
-    method: 'post',
-    data: data
-  })
+    url: "/equipment/inspection/task/" + taskId + "/complete",
+    method: "post",
+    data: data,
+  });
 }
 
 // ==================== 宸℃璁板綍绠$悊 ====================
@@ -103,10 +103,10 @@
  */
 export function submitInspectionRecord(data) {
   return request({
-    url: '/equipment/inspection/record/submit',
-    method: 'post',
-    data: data
-  })
+    url: "/equipment/inspection/record/submit",
+    method: "post",
+    data: data,
+  });
 }
 
 /**
@@ -116,10 +116,10 @@
  */
 export function getInspectionRecordList(query) {
   return request({
-    url: '/equipment/inspection/record/list',
-    method: 'get',
-    params: query
-  })
+    url: "/equipment/inspection/record/list",
+    method: "get",
+    params: query,
+  });
 }
 
 /**
@@ -129,9 +129,9 @@
  */
 export function getInspectionRecord(id) {
   return request({
-    url: '/equipment/inspection/record/' + id,
-    method: 'get'
-  })
+    url: "/equipment/inspection/record/" + id,
+    method: "get",
+  });
 }
 
 // ==================== 鏂囦欢涓婁紶 ====================
@@ -143,13 +143,13 @@
  */
 export function uploadInspectionImage(file) {
   return request({
-    url: '/equipment/inspection/upload/image',
-    method: 'post',
+    url: "/equipment/inspection/upload/image",
+    method: "post",
     data: file,
     headers: {
-      'Content-Type': 'multipart/form-data'
-    }
-  })
+      "Content-Type": "multipart/form-data",
+    },
+  });
 }
 
 /**
@@ -159,13 +159,13 @@
  */
 export function uploadInspectionVideo(file) {
   return request({
-    url: '/equipment/inspection/upload/video',
-    method: 'post',
+    url: "/equipment/inspection/upload/video",
+    method: "post",
     data: file,
     headers: {
-      'Content-Type': 'multipart/form-data'
-    }
-  })
+      "Content-Type": "multipart/form-data",
+    },
+  });
 }
 
 /**
@@ -175,13 +175,13 @@
  */
 export function batchUploadFiles(formData) {
   return request({
-    url: '/equipment/inspection/upload/batch',
-    method: 'post',
+    url: "/equipment/inspection/upload/batch",
+    method: "post",
     data: formData,
     headers: {
-      'Content-Type': 'multipart/form-data'
-    }
-  })
+      "Content-Type": "multipart/form-data",
+    },
+  });
 }
 
 // ==================== 寮傚父鎶ュ绠$悊 ====================
@@ -193,10 +193,10 @@
  */
 export function reportAbnormalSituation(data) {
   return request({
-    url: '/equipment/inspection/abnormal/report',
-    method: 'post',
-    data: data
-  })
+    url: "/equipment/inspection/abnormal/report",
+    method: "post",
+    data: data,
+  });
 }
 
 /**
@@ -206,10 +206,10 @@
  */
 export function getAbnormalReportList(query) {
   return request({
-    url: '/equipment/inspection/abnormal/list',
-    method: 'get',
-    params: query
-  })
+    url: "/equipment/inspection/abnormal/list",
+    method: "get",
+    params: query,
+  });
 }
 
 /**
@@ -219,9 +219,9 @@
  */
 export function getAbnormalReport(id) {
   return request({
-    url: '/equipment/inspection/abnormal/' + id,
-    method: 'get'
-  })
+    url: "/equipment/inspection/abnormal/" + id,
+    method: "get",
+  });
 }
 
 /**
@@ -232,10 +232,10 @@
  */
 export function handleAbnormalReport(id, data) {
   return request({
-    url: '/equipment/inspection/abnormal/' + id + '/handle',
-    method: 'post',
-    data: data
-  })
+    url: "/equipment/inspection/abnormal/" + id + "/handle",
+    method: "post",
+    data: data,
+  });
 }
 
 /**
@@ -246,10 +246,10 @@
  */
 export function transferAbnormalReport(id, data) {
   return request({
-    url: '/equipment/inspection/abnormal/' + id + '/transfer',
-    method: 'post',
-    data: data
-  })
+    url: "/equipment/inspection/abnormal/" + id + "/transfer",
+    method: "post",
+    data: data,
+  });
 }
 
 /**
@@ -260,10 +260,10 @@
  */
 export function closeAbnormalReport(id, data) {
   return request({
-    url: '/equipment/inspection/abnormal/' + id + '/close',
-    method: 'post',
-    data: data
-  })
+    url: "/equipment/inspection/abnormal/" + id + "/close",
+    method: "post",
+    data: data,
+  });
 }
 
 // ==================== 缁熻鍒嗘瀽 ====================
@@ -275,10 +275,10 @@
  */
 export function getInspectionStats(params) {
   return request({
-    url: '/equipment/inspection/stats',
-    method: 'get',
-    params: params
-  })
+    url: "/equipment/inspection/stats",
+    method: "get",
+    params: params,
+  });
 }
 
 /**
@@ -288,10 +288,10 @@
  */
 export function getAbnormalStats(params) {
   return request({
-    url: '/equipment/inspection/abnormal/stats',
-    method: 'get',
-    params: params
-  })
+    url: "/equipment/inspection/abnormal/stats",
+    method: "get",
+    params: params,
+  });
 }
 
 /**
@@ -301,11 +301,11 @@
  */
 export function exportInspectionReport(params) {
   return request({
-    url: '/equipment/inspection/export/report',
-    method: 'get',
+    url: "/equipment/inspection/export/report",
+    method: "get",
     params: params,
-    responseType: 'blob'
-  })
+    responseType: "blob",
+  });
 }
 
 /**
@@ -315,11 +315,11 @@
  */
 export function exportAbnormalRecords(params) {
   return request({
-    url: '/equipment/inspection/abnormal/export',
-    method: 'get',
+    url: "/equipment/inspection/abnormal/export",
+    method: "get",
     params: params,
-    responseType: 'blob'
-  })
+    responseType: "blob",
+  });
 }
 
 // ==================== 璁惧浜岀淮鐮� ====================
@@ -332,8 +332,8 @@
 export function getDeviceQRCode(deviceId) {
   return request({
     url: `/equipment/device/${deviceId}/qrcode`,
-    method: 'get'
-  })
+    method: "get",
+  });
 }
 
 /**
@@ -343,10 +343,10 @@
  */
 export function verifyDeviceQRCode(data) {
   return request({
-    url: '/equipment/device/qrcode/verify',
-    method: 'post',
-    data: data
-  })
+    url: "/equipment/device/qrcode/verify",
+    method: "post",
+    data: data,
+  });
 }
 
 // ==================== 妯℃澘绠$悊 ====================
@@ -358,10 +358,10 @@
  */
 export function getInspectionTemplateList(query) {
   return request({
-    url: '/equipment/inspection/template/list',
-    method: 'get',
-    params: query
-  })
+    url: "/equipment/inspection/template/list",
+    method: "get",
+    params: query,
+  });
 }
 
 /**
@@ -371,7 +371,7 @@
  */
 export function getInspectionTemplate(id) {
   return request({
-    url: '/equipment/inspection/template/' + id,
-    method: 'get'
-  })
-}
\ No newline at end of file
+    url: "/equipment/inspection/template/" + id,
+    method: "get",
+  });
+}
diff --git a/src/api/equipmentManagement/upkeep.js b/src/api/equipmentManagement/upkeep.js
index d6814af..cf536f0 100644
--- a/src/api/equipmentManagement/upkeep.js
+++ b/src/api/equipmentManagement/upkeep.js
@@ -97,6 +97,42 @@
   });
 }
 
+// ---------- 璁惧淇濆吇瀹氭椂浠诲姟锛堝畾鏃朵换鍔$鐞嗭級 ----------
+/** 璁惧淇濆吇瀹氭椂浠诲姟鍒嗛〉鍒楄〃 */
+export const deviceMaintenanceTaskList = (params) => {
+  return request({
+    url: "/deviceMaintenanceTask/listPage",
+    method: "get",
+    params,
+  });
+};
+
+/** 鏂板璁惧淇濆吇瀹氭椂浠诲姟 */
+export const deviceMaintenanceTaskAdd = (data) => {
+  return request({
+    url: "/deviceMaintenanceTask/add",
+    method: "post",
+    data,
+  });
+};
+
+/** 淇敼璁惧淇濆吇瀹氭椂浠诲姟 */
+export const deviceMaintenanceTaskEdit = (data) => {
+  return request({
+    url: "/deviceMaintenanceTask/update",
+    method: "post",
+    data,
+  });
+};
+
+/** 鍒犻櫎璁惧淇濆吇瀹氭椂浠诲姟 */
+export const deviceMaintenanceTaskDel = (ids) => {
+  return request({
+    url: "/deviceMaintenanceTask/delete",
+    method: "delete",
+    data: Array.isArray(ids) ? ids : [ids],
+  });
+};
 
 // 鏌ヨ澶囦欢閫夐」
 export const getSparePartsOptions = (params) => {
diff --git a/src/pages.json b/src/pages.json
index a6d3cf9..d11cdea 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -541,6 +541,15 @@
       }
     },
     {
+      "path": "pages/equipmentManagement/upkeepTask/index",
+      "style": {
+        "navigationBarTitleText": "璁惧淇濆吇浠诲姟",
+        "navigationStyle": "custom",
+        "enablePullDownRefresh": true,
+        "backgroundColor": "#f8f8f8"
+      }
+    },
+    {
       "path": "pages/equipmentManagement/upkeep/detail",
       "style": {
         "navigationBarTitleText": "淇濆吇璇︽儏",
@@ -615,7 +624,7 @@
     {
       "path": "pages/inspectionManagement/index",
       "style": {
-        "navigationBarTitleText": "宸℃浠诲姟绠$悊",
+        "navigationBarTitleText": "宸℃浠诲姟",
         "navigationStyle": "custom",
         "enablePullDownRefresh": true,
         "backgroundColor": "#f8f8f8"
diff --git a/src/pages/equipmentManagement/upkeep/index.vue b/src/pages/equipmentManagement/upkeep/index.vue
index f14712f..7e043c3 100644
--- a/src/pages/equipmentManagement/upkeep/index.vue
+++ b/src/pages/equipmentManagement/upkeep/index.vue
@@ -1,92 +1,82 @@
 <template>
-  <view class="sales-account">
-    <!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
+  <view class="upkeep-page">
     <PageHeader title="璁惧淇濆吇"
                 @back="goBack" />
-    <!-- 鎼滅储鍖哄煙 -->
-    <view class="search-section">
-      <view class="search-bar">
-        <view class="search-input">
-          <up-input class="search-text"
-                    placeholder="璇疯緭鍏ヨ澶囧悕绉版悳绱�"
-                    v-model="searchKeyword"
-                    @change="getList"
-                    clearable />
-        </view>
-        <view class="filter-button"
-              @click="getList">
-          <up-icon name="search"
-                   size="24"
-                   color="#999"></up-icon>
+    <view class="toolbar">
+      <view class="search-section">
+        <view class="search-bar">
+          <view class="search-input">
+            <up-input class="search-text"
+                      placeholder="璇疯緭鍏ヨ澶囧悕绉版悳绱�"
+                      v-model="searchKeyword"
+                      clearable />
+          </view>
+          <view class="search-button"
+                @click="handleQuery">
+            <up-icon name="search"
+                     size="24"
+                     color="#999"></up-icon>
+          </view>
         </view>
       </view>
+      <view class="meta-bar">
+        <text class="meta-text">鍏� {{ total }} 鏉�</text>
+      </view>
     </view>
-    <!-- 璁惧淇濆吇鍒楄〃 -->
-    <view class="ledger-list"
-          v-if="upkeepList.length > 0">
+    <view class="list-section">
       <view v-for="(item, index) in upkeepList"
-            :key="index">
-        <view class="ledger-item"
-              @click="toggleSelection(item)">
-          <view class="item-header">
-            <view class="item-left">
-              <view class="document-icon">
-                <up-icon name="file-text"
-                         size="16"
-                         color="#ffffff"></up-icon>
-              </view>
-              <text class="item-id">璁惧鍚嶇О锛歿{ item.deviceName }}</text>
+            :key="item.id || index"
+            class="ledger-item">
+        <view class="item-header">
+          <view class="item-left">
+            <view class="document-icon">
+              <up-icon name="file-text"
+                       size="14"
+                       color="#ffffff"></up-icon>
             </view>
-            <view class="status-tag">
-              <u-tag v-if="item.status === 1"
-                     type="success">瀹岀粨</u-tag>
-              <u-tag v-if="item.status === 0"
-                     type="warning">寰呬繚鍏�</u-tag>
-              <u-tag v-if="item.status === 2"
-                     type="error">澶辫触</u-tag>
-            </view>
+            <text class="item-id">{{ item.deviceName || "--" }}</text>
+          </view>
+          <view class="item-right">
+            <u-tag v-if="item.status === 1"
+                   type="success">瀹岀粨</u-tag>
+            <u-tag v-if="item.status === 0"
+                   type="warning">寰呬繚鍏�</u-tag>
+            <u-tag v-if="item.status === 2"
+                   type="error">澶辫触</u-tag>
+          </view>
+        </view>
+        <up-divider></up-divider>
+        <view class="item-details">
+          <view class="detail-row">
+            <text class="detail-label">瑙勬牸鍨嬪彿</text>
+            <text class="detail-value">{{ item.deviceModel || "--" }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">璁″垝淇濆吇鏃ユ湡</text>
+            <text class="detail-value">{{ formatDate(item.maintenancePlanTime) || "--" }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">褰曞叆浜�</text>
+            <text class="detail-value">{{ item.createUserName || "--" }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">褰曞叆鏃ユ湡</text>
+            <text class="detail-value">{{ formatDateTime(item.createTime) || "--" }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">瀹為檯淇濆吇浜�</text>
+            <text class="detail-value">{{ item.maintenanceActuallyName || "--" }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">瀹為檯淇濆吇鏃ユ湡</text>
+            <text class="detail-value">{{ formatDateTime(item.maintenanceActuallyTime) || "--" }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">淇濆吇缁撴灉</text>
+            <text class="detail-value">{{ item.maintenanceResult || "--" }}</text>
           </view>
           <up-divider></up-divider>
-          <view class="item-details">
-            <view class="detail-row">
-              <text class="detail-label">瑙勬牸鍨嬪彿</text>
-              <text class="detail-value">{{ item.deviceModel || '-' }}</text>
-            </view>
-            <view class="detail-row">
-              <text class="detail-label">璁″垝淇濆吇鏃ユ湡</text>
-              <text class="detail-value">{{ formatDate(item.maintenancePlanTime) || '-' }}</text>
-            </view>
-            <view class="detail-row">
-              <text class="detail-label">褰曞叆浜�</text>
-              <text class="detail-value">{{ item.createUserName || '-' }}</text>
-            </view>
-            <view class="detail-row">
-              <text class="detail-label">褰曞叆鏃ユ湡</text>
-              <text class="detail-value">{{ formatDateTime(item.createTime) || '-' }}</text>
-            </view>
-            <view class="detail-row">
-              <text class="detail-label">瀹為檯淇濆吇浜�</text>
-              <text class="detail-value">{{ item.maintenanceActuallyName || '-' }}</text>
-            </view>
-            <view class="detail-row">
-              <text class="detail-label">瀹為檯淇濆吇鏃ユ湡</text>
-              <text class="detail-value">{{ formatDateTime(item.maintenanceActuallyTime) || '-' }}</text>
-            </view>
-            <view class="detail-row">
-              <text class="detail-label">淇濆吇缁撴灉</text>
-              <text class="detail-value">{{item.maintenanceResult || '-'}}
-              </text>
-            </view>
-          </view>
-          <!-- 鎸夐挳鍖哄煙 -->
-          <view class="action-buttons">
-            <!-- <u-button type="primary"
-                      size="small"
-                      class="action-btn"
-                      :disabled="item.status === 1"
-                      @click.stop="edit(item.id)">
-              缂栬緫
-            </u-button> -->
+          <view class="card-actions">
             <u-button type="warning"
                       size="small"
                       class="action-btn"
@@ -107,21 +97,14 @@
                       @click.stop="viewDetail(item)">
               璇︽儏
             </u-button>
-            <!-- <u-button type="warning"
-                      size="small"
-                      class="action-btn"
-                      @click.stop="addFile(item.id)">
-              闄勪欢
-            </u-button> -->
           </view>
         </view>
       </view>
+      <view v-if="!loading && upkeepList.length === 0"
+            class="no-data">
+        <text>鏆傛棤璁惧淇濆吇鏁版嵁</text>
+      </view>
     </view>
-    <view v-else
-          class="no-data">
-      <text>鏆傛棤璁惧淇濆吇鏁版嵁</text>
-    </view>
-    <!-- 娴姩鏂板鎸夐挳 -->
     <view class="fab-button"
           @click="addPlan">
       <up-icon name="plus"
@@ -154,7 +137,10 @@
   // 璁惧淇濆吇鏁版嵁
   const upkeepList = ref([]);
 
-  // 澶氶�夊垪琛�
+  const total = ref(0);
+  const loading = ref(false);
+
+  // 澶氶�夊垪琛紙淇濆吇鎸夐挳鏈紶 id 鏃剁敤锛�
   const multipleList = ref([]);
 
   // 杩斿洖涓婁竴椤�
@@ -174,9 +160,13 @@
     return dayjs(dateStr).format("YYYY-MM-DD HH:mm:ss");
   };
 
+  const handleQuery = () => {
+    getList();
+  };
+
   // 鏌ヨ鍒楄〃
   const getList = () => {
-    showLoadingToast("鍔犺浇涓�...");
+    loading.value = true;
     const params = {
       current: -1,
       size: -1,
@@ -184,13 +174,16 @@
     };
     getUpkeepPage(params)
       .then(res => {
-        // 濡傛灉res.data涓嶆槸鏁扮粍锛岃缃负绌烘暟缁�
-        upkeepList.value = res.records || res.data?.records || [];
-        closeToast();
+        const records = res?.records ?? res?.data?.records ?? [];
+        upkeepList.value = records;
+        total.value = Array.isArray(records) ? records.length : Number(res?.total ?? res?.data?.total ?? 0);
       })
       .catch(() => {
-        closeToast();
+        upkeepList.value = [];
         showToast("鑾峰彇鏁版嵁澶辫触");
+      })
+      .finally(() => {
+        loading.value = false;
       });
   };
   // 鏂板闄勪欢 - 璺宠浆鍒伴檮浠堕〉闈�
@@ -322,45 +315,182 @@
 </script>
 
 <style scoped lang="scss">
-  @import "@/styles/sales-common.scss";
-
-  // 璁惧淇濆吇鐗规湁鏍峰紡
-  .sales-account {
-    padding-bottom: 80px; // 涓烘诞鍔ㄦ寜閽暀鍑虹┖闂�
+  .upkeep-page {
+    min-height: 100vh;
+    background: #f6f7fb;
   }
 
-  .action-section {
-    padding: 10px 20px;
+  .toolbar {
+    padding: 20rpx 24rpx;
+    background: #fff;
+    border-bottom: 1rpx solid #f0f0f0;
+    position: sticky;
+    top: 0;
+    z-index: 10;
+  }
+
+  .search-section {
+    margin-top: 0;
+  }
+
+  .search-bar {
+    display: flex;
+    align-items: center;
+    background: #f7f8fa;
+    border-radius: 14rpx;
+    padding: 8rpx 12rpx 8rpx 16rpx;
+    border: 1rpx solid #eef1f5;
+  }
+
+  .search-input {
+    flex: 1;
+    min-width: 0;
+  }
+
+  .search-text {
+    background: transparent !important;
+  }
+
+  :deep(.search-text .u-input__content),
+  :deep(.search-text .up-input__content) {
+    background: transparent !important;
+    padding: 0 !important;
+  }
+
+  .search-button {
+    width: 64rpx;
+    height: 64rpx;
+    border-radius: 12rpx;
     background: #ffffff;
-    border-bottom: 1px solid #f0f0f0;
+    display: flex;
+    align-items: center;
+    justify-content: center;
   }
 
-  .action-section .action-buttons {
-    gap: 8px; // 涓庡叕鍏辨牱寮忎腑鐨� 12px 涓嶅悓
-    justify-content: flex-start;
+  .meta-bar {
+    margin-top: 16rpx;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    background: #f7f9fc;
+    border-radius: 12rpx;
+    padding: 10rpx 16rpx;
   }
 
-  .checkbox-wrapper {
+  .meta-text {
+    color: #5c6b8a;
+    font-size: 22rpx;
+  }
+
+  .list-section {
+    padding: 20rpx 24rpx;
+    padding-bottom: calc(132rpx + env(safe-area-inset-bottom));
+  }
+
+  .ledger-item {
+    background: #ffffff;
+    border-radius: 20rpx;
+    margin-bottom: 16rpx;
+    overflow: hidden;
+    box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.05);
+    padding: 0 20rpx;
+  }
+
+  .item-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 22rpx 0;
+  }
+
+  .item-left {
+    display: flex;
+    align-items: center;
+    gap: 10rpx;
+    flex: 1;
+    min-width: 0;
+  }
+
+  .item-right {
     display: flex;
     align-items: center;
   }
 
-  .status-tag {
+  .document-icon {
+    width: 38rpx;
+    height: 38rpx;
+    border-radius: 8rpx;
+    background: #2979ff;
     display: flex;
     align-items: center;
+    justify-content: center;
+  }
+
+  .item-id {
+    font-size: 28rpx;
+    color: #1f1f1f;
+    font-weight: 600;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+
+  .item-details {
+    padding: 18rpx 0 20rpx;
+  }
+
+  .detail-row {
+    display: flex;
+    align-items: flex-end;
+    justify-content: space-between;
+    margin-bottom: 12rpx;
   }
 
   .detail-label {
-    min-width: 80px; // 涓庡叕鍏辨牱寮忎腑鐨� 60px 涓嶅悓
+    min-width: 160rpx;
+    color: #777;
+    font-size: 24rpx;
   }
 
   .detail-value {
-    display: flex;
-    justify-content: flex-end;
-    align-items: center;
+    flex: 1;
+    color: #333;
+    font-size: 24rpx;
+    text-align: right;
+    word-break: break-all;
+    margin-left: 12rpx;
   }
 
-  .ledger-item .action-buttons {
-    gap: 8px; // 涓庡叕鍏辨牱寮忎腑鐨� 12px 涓嶅悓
+  .card-actions {
+    padding-top: 8rpx;
+    display: flex;
+    justify-content: flex-end;
+    flex-wrap: wrap;
+    gap: 12rpx;
+  }
+
+  .action-btn {
+    min-width: 100rpx;
+  }
+
+  .fab-button {
+    position: fixed;
+    bottom: calc(30px + env(safe-area-inset-bottom));
+    right: 30px;
+    width: 56px;
+    height: 56px;
+    background: #2979ff;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    box-shadow: 0 4px 16px rgba(41, 121, 255, 0.3);
+    z-index: 1000;
+  }
+
+  .no-data {
+    padding: 40rpx 0;
+    text-align: center;
+    color: #999;
   }
 </style>
\ No newline at end of file
diff --git a/src/pages/equipmentManagement/upkeepTask/components/formDia.vue b/src/pages/equipmentManagement/upkeepTask/components/formDia.vue
new file mode 100644
index 0000000..15fe952
--- /dev/null
+++ b/src/pages/equipmentManagement/upkeepTask/components/formDia.vue
@@ -0,0 +1,659 @@
+<template>
+  <u-popup :show="dialogVisitable"
+           mode="center"
+           :round="12"
+           :zIndex="900"
+           @close="cancel">
+    <view class="popup-content">
+      <view class="popup-title">{{ operationType === "add" ? "鏂板淇濆吇浠诲姟" : "缂栬緫淇濆吇浠诲姟" }}</view>
+      <view class="form-body">
+        <view class="form-item">
+          <text class="label">浠诲姟鍚嶇О</text>
+          <up-input v-model="form.taskName"
+                    placeholder="璇疯緭鍏ヤ换鍔″悕绉�"
+                    border="none"
+                    customStyle="background: #f7f8fa; padding: 0 20rpx; min-height: 72rpx; border-radius: 12rpx;" />
+        </view>
+        <view class="form-item">
+          <text class="label">璁惧</text>
+          <view class="picker-value inspector-picker"
+                @click="openDevicePopup">
+            <text>{{ deviceNamesText || "璇烽�夋嫨璁惧" }}</text>
+            <u-icon name="arrow-right"
+                    size="14"
+                    color="#999" />
+          </view>
+          <view class="inspector-tags"
+                v-if="form.deviceIds?.length">
+            <view v-for="id in form.deviceIds"
+                  :key="id"
+                  class="inspector-tag"
+                  @click="toggleDevice(id)">
+              <text>{{ getDeviceName(id) }}</text>
+              <u-icon name="close"
+                      size="11"
+                      color="#1677ff" />
+            </view>
+          </view>
+        </view>
+        <view class="form-item">
+          <text class="label">褰曞叆浜�</text>
+          <picker mode="selector"
+                  :range="userList"
+                  range-key="nickName"
+                  :value="inspectorIndex"
+                  @change="onInspectorChange">
+            <view class="picker-value">{{ form.registrant || "璇烽�夋嫨褰曞叆浜�" }}</view>
+          </picker>
+        </view>
+        <view class="form-item">
+          <text class="label">鐧昏鏃堕棿</text>
+          <picker mode="date"
+                  :value="form.registrationDate || todayStr"
+                  @change="onRegistrationDateChange">
+            <view class="picker-value">{{ form.registrationDate || "璇烽�夋嫨鐧昏鏃堕棿" }}</view>
+          </picker>
+        </view>
+        <view class="form-item">
+          <text class="label">浠诲姟棰戠巼</text>
+          <picker mode="selector"
+                  :range="frequencyOptions"
+                  range-key="label"
+                  :value="frequencyIndex"
+                  @change="onFrequencyChange">
+            <view class="picker-value">{{ currentFrequencyLabel || "璇烽�夋嫨浠诲姟棰戠巼" }}</view>
+          </picker>
+        </view>
+        <view class="form-item"
+              v-if="form.frequencyType === 'DAILY'">
+          <text class="label">鏃堕棿</text>
+          <picker mode="time"
+                  :value="form.frequencyDetail || '08:00'"
+                  @change="onDailyTimeChange">
+            <view class="picker-value">{{ form.frequencyDetail || "璇烽�夋嫨鏃堕棿" }}</view>
+          </picker>
+        </view>
+        <view class="form-item"
+              v-if="form.frequencyType === 'WEEKLY'">
+          <text class="label">姣忓懆鏃ユ湡</text>
+          <picker mode="selector"
+                  :range="weekOptions"
+                  range-key="label"
+                  :value="weekIndex"
+                  @change="onWeekChange">
+            <view class="picker-value">{{ currentWeekLabel || "璇烽�夋嫨鏄熸湡" }}</view>
+          </picker>
+        </view>
+        <view class="form-item"
+              v-if="form.frequencyType === 'WEEKLY'">
+          <text class="label">姣忓懆鏃堕棿</text>
+          <picker mode="time"
+                  :value="form.time || '08:00'"
+                  @change="onWeekTimeChange">
+            <view class="picker-value">{{ form.time || "璇烽�夋嫨鏃堕棿" }}</view>
+          </picker>
+        </view>
+        <view class="form-item"
+              v-if="form.frequencyType === 'MONTHLY'">
+          <text class="label">姣忔湀鏃ユ湡涓庢椂闂�</text>
+          <picker mode="date"
+                  fields="day"
+                  :value="monthlyDate"
+                  @change="onMonthlyDateChange">
+            <view class="picker-value">{{ monthlyDate || "璇烽�夋嫨鏃ユ湡" }}</view>
+          </picker>
+          <picker mode="time"
+                  :value="monthlyTime"
+                  @change="onMonthlyTimeChange">
+            <view class="picker-value">{{ monthlyTime || "璇烽�夋嫨鏃堕棿" }}</view>
+          </picker>
+        </view>
+        <view class="form-item"
+              v-if="form.frequencyType === 'QUARTERLY'">
+          <text class="label">瀛e害鏃ユ湡涓庢椂闂�</text>
+          <picker mode="date"
+                  :value="quarterlyDate"
+                  @change="onQuarterlyDateChange">
+            <view class="picker-value">{{ quarterlyDate || "璇烽�夋嫨鏃ユ湡" }}</view>
+          </picker>
+          <picker mode="time"
+                  :value="quarterlyTime"
+                  @change="onQuarterlyTimeChange">
+            <view class="picker-value">{{ quarterlyTime || "璇烽�夋嫨鏃堕棿" }}</view>
+          </picker>
+        </view>
+        <view class="form-item">
+          <text class="label">澶囨敞</text>
+          <u-textarea v-model="form.remarks"
+                      placeholder="璇疯緭鍏ュ娉�"
+                      :height="80"
+                      count />
+        </view>
+      </view>
+      <view class="popup-footer">
+        <u-button @click="cancel">鍙栨秷</u-button>
+        <u-button type="primary"
+                  @click="submitForm">淇濆瓨</u-button>
+      </view>
+    </view>
+  </u-popup>
+  <u-popup :show="showDevicePopup"
+           mode="bottom"
+           :round="16"
+           :zIndex="1100"
+           @close="closeDevicePopup">
+    <view class="inspector-popup">
+      <view class="inspector-header">
+        <text class="inspector-title">閫夋嫨璁惧</text>
+      </view>
+      <scroll-view scroll-y
+                   class="inspector-list">
+        <view v-for="item in deviceOptions"
+              :key="item.id"
+              class="inspector-row"
+              @click="toggleDevice(item.id)">
+          <text class="inspector-name">{{ item.deviceName }}</text>
+          <u-icon v-if="(form.deviceIds || []).includes(item.id)"
+                  name="checkmark-circle-fill"
+                  color="#1677ff"
+                  size="20" />
+          <u-icon v-else
+                  name=""
+                  color="#d5d8de"
+                  size="20" />
+        </view>
+      </scroll-view>
+      <view class="inspector-footer">
+        <u-button @click="closeDevicePopup">纭畾</u-button>
+      </view>
+    </view>
+  </u-popup>
+</template>
+
+<script setup>
+  import { computed, reactive, ref } from "vue";
+  import useUserStore from "@/store/modules/user";
+  import {
+    deviceMaintenanceTaskAdd,
+    deviceMaintenanceTaskEdit,
+  } from "@/api/equipmentManagement/upkeep.js";
+  import { userListNoPageByTenantId } from "@/api/system/user.js";
+  import { getDeviceLedger } from "@/api/equipmentManagement/ledger.js";
+
+  const emit = defineEmits(["closeDia"]);
+  const userStore = useUserStore();
+  const dialogVisitable = ref(false);
+  const operationType = ref("add");
+  const deviceOptions = ref([]);
+  const userList = ref([]);
+  const showDevicePopup = ref(false);
+
+  const todayStr = ref("");
+  try {
+    const d = new Date();
+    todayStr.value = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
+  } catch (e) {}
+
+  const defaultForm = () => ({
+    id: undefined,
+    taskName: "",
+    deviceIds: [],
+    registrantId: undefined,
+    registrant: "",
+    registrationDate: "",
+    remarks: "",
+    frequencyType: "",
+    frequencyDetail: "",
+    week: "",
+    time: "",
+  });
+
+  const form = reactive(defaultForm());
+
+  const frequencyOptions = [
+    { label: "姣忔棩", value: "DAILY" },
+    { label: "姣忓懆", value: "WEEKLY" },
+    { label: "姣忔湀", value: "MONTHLY" },
+    { label: "瀛e害", value: "QUARTERLY" },
+  ];
+
+  const weekOptions = [
+    { label: "鍛ㄤ竴", value: "MON" },
+    { label: "鍛ㄤ簩", value: "TUE" },
+    { label: "鍛ㄤ笁", value: "WED" },
+    { label: "鍛ㄥ洓", value: "THU" },
+    { label: "鍛ㄤ簲", value: "FRI" },
+    { label: "鍛ㄥ叚", value: "SAT" },
+    { label: "鍛ㄦ棩", value: "SUN" },
+  ];
+
+  const monthlyDate = ref("");
+  const monthlyTime = ref("");
+  const quarterlyDate = ref("");
+  const quarterlyTime = ref("");
+
+  const frequencyIndex = computed(() => {
+    const index = frequencyOptions.findIndex(item => item.value === form.frequencyType);
+    return index >= 0 ? index : 0;
+  });
+
+  const weekIndex = computed(() => {
+    const index = weekOptions.findIndex(item => item.value === form.week);
+    return index >= 0 ? index : 0;
+  });
+
+  const currentFrequencyLabel = computed(() => {
+    return frequencyOptions.find(item => item.value === form.frequencyType)?.label || "";
+  });
+
+  const currentWeekLabel = computed(() => {
+    return weekOptions.find(item => item.value === form.week)?.label || "";
+  });
+
+  const inspectorIndex = computed(() => {
+    const index = userList.value.findIndex(item => String(item.userId) === String(form.registrantId));
+    return index >= 0 ? index : 0;
+  });
+
+  const deviceNamesText = computed(() => {
+    if (!form.deviceIds?.length) return "";
+    return form.deviceIds
+      .map(id => getDeviceName(id))
+      .filter(Boolean)
+      .join("銆�");
+  });
+
+  function getDeviceName(id) {
+    const d = deviceOptions.value.find(item => String(item.id) === String(id));
+    return d?.deviceName || "";
+  }
+
+  const resetForm = () => {
+    Object.assign(form, defaultForm());
+    monthlyDate.value = "";
+    monthlyTime.value = "";
+    quarterlyDate.value = "";
+    quarterlyTime.value = "";
+    showDevicePopup.value = false;
+  };
+
+  const normalizeIdList = val => {
+    if (!val) return [];
+    if (Array.isArray(val)) return val.map(v => (Number.isNaN(Number(v)) ? v : Number(v)));
+    if (typeof val === "string") {
+      const s = val.trim();
+      if (s.startsWith("[") && s.endsWith("]")) {
+        try {
+          const arr = JSON.parse(s);
+          return Array.isArray(arr) ? arr : [];
+        } catch {
+          return [];
+        }
+      }
+      return s.split(",").map(v => v.trim()).filter(Boolean).map(v => (Number.isNaN(Number(v)) ? v : Number(v)));
+    }
+    return [];
+  };
+
+  const parseWeeklyDetail = detail => {
+    if (!detail || typeof detail !== "string" || !detail.includes(",")) return;
+    const [week, time] = detail.split(",");
+    form.week = week || "";
+    form.time = time || "";
+  };
+
+  const parseMonthlyDetail = detail => {
+    if (!detail || typeof detail !== "string" || !detail.includes(",")) return;
+    const [day, time] = detail.split(",");
+    if (day) {
+      const y = new Date().getFullYear();
+      const m = new Date().getMonth() + 1;
+      monthlyDate.value = `${y}-${String(m).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
+    }
+    if (time) monthlyTime.value = time;
+  };
+
+  const parseQuarterlyDetail = detail => {
+    if (!detail || typeof detail !== "string") return;
+    const parts = detail.split(",");
+    if (parts.length >= 3) {
+      const [mm, dd, time] = parts;
+      const y = new Date().getFullYear();
+      quarterlyDate.value = `${y}-${String(mm).padStart(2, "0")}-${String(dd).padStart(2, "0")}`;
+      quarterlyTime.value = time || "";
+    }
+  };
+
+  const openDialog = async (type, row) => {
+    operationType.value = type;
+    dialogVisitable.value = true;
+    resetForm();
+    try {
+      const [userRes, deviceRes] = await Promise.all([
+        userListNoPageByTenantId(),
+        getDeviceLedger(),
+      ]);
+      userList.value = userRes?.data || [];
+      deviceOptions.value = deviceRes?.data || [];
+      if (type === "edit" && row) {
+        Object.assign(form, {
+          ...defaultForm(),
+          ...row,
+          deviceIds: normalizeIdList(row.deviceIds ?? row.taskIds ?? row.deviceIds),
+        });
+        if (!form.registrationDate && row.registrationDate) form.registrationDate = row.registrationDate;
+        if (row.registrantId) form.registrantId = row.registrantId;
+        if (row.registrant) form.registrant = row.registrant;
+        if (form.frequencyType === "WEEKLY") parseWeeklyDetail(form.frequencyDetail);
+        if (form.frequencyType === "MONTHLY") parseMonthlyDetail(form.frequencyDetail);
+        if (form.frequencyType === "QUARTERLY") parseQuarterlyDetail(form.frequencyDetail);
+      } else {
+        form.registrationDate = todayStr.value;
+        const userInfo = await userStore.getInfo();
+        if (userInfo?.user?.userId) {
+          form.registrantId = userInfo.user.userId;
+          form.registrant = userInfo.user.nickName || userInfo.user.userName || "";
+        }
+      }
+    } catch (error) {
+      uni.showToast({
+        title: "鍒濆鍖栧け璐�",
+        icon: "none",
+      });
+    }
+  };
+
+  const openDevicePopup = () => {
+    showDevicePopup.value = true;
+  };
+
+  const closeDevicePopup = () => {
+    showDevicePopup.value = false;
+  };
+
+  const toggleDevice = id => {
+    const ids = form.deviceIds || [];
+    if (ids.includes(id)) {
+      form.deviceIds = ids.filter(i => i !== id);
+    } else {
+      form.deviceIds = [...ids, id];
+    }
+  };
+
+  const onInspectorChange = e => {
+    const index = Number(e?.detail?.value ?? 0);
+    const user = userList.value[index];
+    if (user) {
+      form.registrantId = user.userId;
+      form.registrant = user.nickName || "";
+    }
+  };
+
+  const onRegistrationDateChange = e => {
+    form.registrationDate = e?.detail?.value || "";
+  };
+
+  const onFrequencyChange = e => {
+    const index = Number(e?.detail?.value ?? 0);
+    const selected = frequencyOptions[index];
+    form.frequencyType = selected?.value || "";
+    form.frequencyDetail = "";
+    form.week = "";
+    form.time = "";
+    monthlyDate.value = "";
+    monthlyTime.value = "";
+    quarterlyDate.value = "";
+    quarterlyTime.value = "";
+  };
+
+  const onDailyTimeChange = e => {
+    form.frequencyDetail = e?.detail?.value || "";
+  };
+
+  const onWeekChange = e => {
+    const index = Number(e?.detail?.value ?? 0);
+    const selected = weekOptions[index];
+    form.week = selected?.value || "";
+  };
+
+  const onWeekTimeChange = e => {
+    form.time = e?.detail?.value || "";
+  };
+
+  const onMonthlyDateChange = e => {
+    monthlyDate.value = e?.detail?.value || "";
+  };
+
+  const onMonthlyTimeChange = e => {
+    monthlyTime.value = e?.detail?.value || "";
+  };
+
+  const onQuarterlyDateChange = e => {
+    quarterlyDate.value = e?.detail?.value || "";
+  };
+
+  const onQuarterlyTimeChange = e => {
+    quarterlyTime.value = e?.detail?.value || "";
+  };
+
+  const validateForm = () => {
+    if (!form.taskName?.trim()) {
+      uni.showToast({ title: "璇疯緭鍏ヤ换鍔″悕绉�", icon: "none" });
+      return false;
+    }
+    if (!form.deviceIds?.length) {
+      uni.showToast({ title: "璇烽�夋嫨璁惧", icon: "none" });
+      return false;
+    }
+    if (!form.registrantId && !form.registrant) {
+      uni.showToast({ title: "璇烽�夋嫨褰曞叆浜�", icon: "none" });
+      return false;
+    }
+    if (!form.registrationDate) {
+      uni.showToast({ title: "璇烽�夋嫨鐧昏鏃堕棿", icon: "none" });
+      return false;
+    }
+    if (!form.frequencyType) {
+      uni.showToast({ title: "璇烽�夋嫨浠诲姟棰戠巼", icon: "none" });
+      return false;
+    }
+    if (form.frequencyType === "DAILY" && !form.frequencyDetail) {
+      uni.showToast({ title: "璇烽�夋嫨鏃堕棿", icon: "none" });
+      return false;
+    }
+    if (form.frequencyType === "WEEKLY" && (!form.week || !form.time)) {
+      uni.showToast({ title: "璇烽�夋嫨姣忓懆鏃ユ湡鍜屾椂闂�", icon: "none" });
+      return false;
+    }
+    if (form.frequencyType === "MONTHLY" && (!monthlyDate.value || !monthlyTime.value)) {
+      uni.showToast({ title: "璇烽�夋嫨姣忔湀鏃ユ湡鍜屾椂闂�", icon: "none" });
+      return false;
+    }
+    if (form.frequencyType === "QUARTERLY" && (!quarterlyDate.value || !quarterlyTime.value)) {
+      uni.showToast({ title: "璇烽�夋嫨瀛e害鏃ユ湡鍜屾椂闂�", icon: "none" });
+      return false;
+    }
+    return true;
+  };
+
+  const buildFrequencyDetail = () => {
+    if (form.frequencyType === "WEEKLY") return `${form.week},${form.time}`;
+    if (form.frequencyType === "MONTHLY") {
+      const day = monthlyDate.value.split("-")[2] || "";
+      return `${day},${monthlyTime.value}`;
+    }
+    if (form.frequencyType === "QUARTERLY") {
+      const [y, m, d] = (quarterlyDate.value || "").split("-");
+      return `${m},${d},${quarterlyTime.value}`;
+    }
+    return form.frequencyDetail || "";
+  };
+
+  const submitForm = async () => {
+    if (!validateForm()) return;
+    try {
+      const payload = {
+        id: form.id,
+        taskName: form.taskName.trim(),
+        deviceIds: JSON.stringify(form.deviceIds || []),
+        registrantId: form.registrantId,
+        registrant: form.registrant,
+        registrationDate: form.registrationDate,
+        frequencyType: form.frequencyType,
+        frequencyDetail: buildFrequencyDetail(),
+        remarks: form.remarks || "",
+        status: "0",
+        active: true,
+        deleted: 0,
+      };
+      if (operationType.value === "edit" && form.id) {
+        await deviceMaintenanceTaskEdit(payload);
+      } else {
+        delete payload.id;
+        await deviceMaintenanceTaskAdd(payload);
+      }
+      uni.showToast({
+        title: "鎻愪氦鎴愬姛",
+        icon: "success",
+      });
+      cancel();
+    } catch (error) {
+      uni.showToast({
+        title: "鎻愪氦澶辫触锛岃閲嶈瘯",
+        icon: "none",
+      });
+    }
+  };
+
+  const cancel = () => {
+    dialogVisitable.value = false;
+    resetForm();
+    emit("closeDia");
+  };
+
+  defineExpose({ openDialog });
+</script>
+
+<style scoped lang="scss">
+  :deep(.uni-picker-container) {
+    z-index: 1200 !important;
+  }
+
+  .popup-content {
+    width: 88vw;
+    max-height: 80vh;
+    background: #fff;
+    border-radius: 20rpx;
+    overflow: hidden;
+  }
+
+  .popup-title {
+    text-align: center;
+    font-size: 32rpx;
+    color: #1f1f1f;
+    font-weight: 600;
+    padding: 24rpx 20rpx;
+    border-bottom: 1rpx solid #f0f0f0;
+  }
+
+  .form-body {
+    padding: 24rpx;
+    max-height: 56vh;
+    overflow-y: auto;
+  }
+
+  .form-item {
+    margin-bottom: 20rpx;
+  }
+
+  .label {
+    display: block;
+    margin-bottom: 10rpx;
+    font-size: 24rpx;
+    color: #666;
+  }
+
+  .picker-value {
+    min-height: 72rpx;
+    background: #f7f8fa;
+    border-radius: 12rpx;
+    padding: 0 20rpx;
+    display: flex;
+    align-items: center;
+    color: #333;
+    font-size: 26rpx;
+  }
+
+  .inspector-picker {
+    justify-content: space-between;
+  }
+
+  .inspector-tags {
+    display: flex;
+    flex-wrap: wrap;
+    margin-top: 10rpx;
+    gap: 10rpx;
+  }
+
+  .inspector-tag {
+    display: flex;
+    align-items: center;
+    gap: 8rpx;
+    background: #edf3ff;
+    color: #1677ff;
+    font-size: 22rpx;
+    border-radius: 999rpx;
+    padding: 6rpx 14rpx;
+  }
+
+  .popup-footer {
+    display: flex;
+    gap: 16rpx;
+    padding: 20rpx 24rpx 24rpx;
+    border-top: 1rpx solid #f0f0f0;
+  }
+
+  .inspector-popup {
+    background: #fff;
+    border-radius: 24rpx 24rpx 0 0;
+    overflow: hidden;
+    max-height: 70vh;
+    padding-bottom: env(safe-area-inset-bottom);
+  }
+
+  .inspector-header {
+    padding: 24rpx;
+    text-align: center;
+    border-bottom: 1rpx solid #f0f0f0;
+  }
+
+  .inspector-title {
+    color: #1f1f1f;
+    font-size: 30rpx;
+    font-weight: 600;
+  }
+
+  .inspector-list {
+    max-height: 46vh;
+    padding: 0 24rpx;
+  }
+
+  .inspector-row {
+    min-height: 82rpx;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    border-bottom: 1rpx solid #f5f5f5;
+  }
+
+  .inspector-name {
+    font-size: 26rpx;
+    color: #333;
+  }
+
+  .inspector-footer {
+    display: flex;
+    gap: 16rpx;
+    padding: 20rpx 24rpx 24rpx;
+  }
+</style>
diff --git a/src/pages/equipmentManagement/upkeepTask/index.vue b/src/pages/equipmentManagement/upkeepTask/index.vue
new file mode 100644
index 0000000..5f0181a
--- /dev/null
+++ b/src/pages/equipmentManagement/upkeepTask/index.vue
@@ -0,0 +1,449 @@
+<template>
+  <view class="upkeep-task-page">
+    <PageHeader title="瀹氭椂浠诲姟绠$悊"
+                @back="goBack" />
+    <view class="toolbar">
+      <view class="search-section">
+        <view class="search-bar">
+          <view class="search-input">
+            <up-input class="search-text"
+                      placeholder="璇疯緭鍏ヤ繚鍏讳换鍔″悕绉�"
+                      v-model="queryParams.taskName"
+                      clearable />
+          </view>
+          <view class="search-button"
+                @click="handleQuery">
+            <up-icon name="search"
+                     size="24"
+                     color="#999"></up-icon>
+          </view>
+        </view>
+      </view>
+      <view class="meta-bar">
+        <text class="meta-text">鍏� {{ total }} 鏉�</text>
+      </view>
+    </view>
+    <view class="list-section">
+      <uni-swipe-action>
+        <uni-swipe-action-item v-for="item in tableData"
+                               :key="item.id"
+                               :right-options="swipeOptions"
+                               @click="onSwipeActionClick($event, item)">
+          <view class="ledger-item">
+            <view class="item-header">
+              <view class="item-left">
+                <view class="document-icon">
+                  <up-icon name="file-text"
+                           size="14"
+                           color="#ffffff"></up-icon>
+                </view>
+                <text class="item-id">{{ item.taskName || "--" }}</text>
+              </view>
+              <view class="item-right">
+                <u-tag :type="getFrequencyTagType(item.frequencyType)"
+                       :text="formatFrequency(item.frequencyType) || '鏈煡棰戞'" />
+              </view>
+            </view>
+            <up-divider></up-divider>
+            <view class="item-details">
+              <view class="detail-row">
+                <text class="detail-label">浠诲姟缂栧彿</text>
+                <text class="detail-value">{{ item.id || "--" }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">璁惧</text>
+                <text class="detail-value">{{ item.deviceName || "--" }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">寮�濮嬫棩鏈熶笌鏃堕棿</text>
+                <text class="detail-value highlight">{{ formatFrequencyDetail(item.frequencyDetail) }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">鐧昏浜�</text>
+                <text class="detail-value">{{ item.registrant || "--" }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">鐧昏鏃ユ湡</text>
+                <text class="detail-value">{{ item.registrationDate || item.createTime || "--" }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">澶囨敞</text>
+                <text class="detail-value">{{ item.remarks || "鏃�" }}</text>
+              </view>
+              <up-divider></up-divider>
+              <view class="card-actions">
+                <u-button type="primary"
+                          size="small"
+                          class="action-btn"
+                          @click.stop="handleAdd(item)">缂栬緫</u-button>
+              </view>
+            </view>
+          </view>
+        </uni-swipe-action-item>
+      </uni-swipe-action>
+      <uni-load-more :status="loadMoreStatus"></uni-load-more>
+      <view v-if="!loading && tableData.length === 0"
+            class="no-data">
+        <text>鏆傛棤鏁版嵁</text>
+      </view>
+    </view>
+    <view class="fab-button"
+          @click="handleAdd()">
+      <up-icon name="plus"
+               size="24"
+               color="#ffffff"></up-icon>
+    </view>
+    <form-dia ref="formDia"
+              @closeDia="handleQuery" />
+  </view>
+</template>
+
+<script setup>
+  import { ref, reactive, computed, nextTick } from "vue";
+  import { onShow, onReachBottom, onPullDownRefresh } from "@dcloudio/uni-app";
+  import PageHeader from "@/components/PageHeader.vue";
+  import FormDia from "@/pages/equipmentManagement/upkeepTask/components/formDia.vue";
+  import {
+    deviceMaintenanceTaskDel,
+    deviceMaintenanceTaskList,
+  } from "@/api/equipmentManagement/upkeep.js";
+
+  const formDia = ref();
+  const queryParams = reactive({
+    taskName: "",
+  });
+  const pageParams = reactive({
+    current: 1,
+    size: 10,
+  });
+  const total = ref(0);
+  const loading = ref(false);
+  const tableData = ref([]);
+  const swipeOptions = [
+    {
+      text: "鍒犻櫎",
+      style: {
+        backgroundColor: "#ee0a24",
+      },
+    },
+  ];
+
+  const noMore = computed(() => tableData.value.length >= total.value);
+  const loadMoreStatus = computed(() => {
+    if (loading.value) return "loading";
+    if (noMore.value) return "noMore";
+    return "more";
+  });
+
+  const goBack = () => {
+    uni.navigateBack();
+  };
+
+  const formatFrequency = value => {
+    if (value === "DAILY") return "姣忔棩";
+    if (value === "WEEKLY") return "姣忓懆";
+    if (value === "MONTHLY") return "姣忔湀";
+    if (value === "QUARTERLY") return "瀛e害";
+    return "";
+  };
+
+  const getFrequencyTagType = value => {
+    if (value === "DAILY") return "success";
+    if (value === "WEEKLY") return "primary";
+    if (value === "MONTHLY") return "warning";
+    return "info";
+  };
+
+  const formatFrequencyDetail = value => {
+    if (!value || typeof value !== "string") return "--";
+    return value.replace(
+      /MON|TUE|WED|THU|FRI|SAT|SUN/g,
+      item =>
+        ({
+          MON: "鍛ㄤ竴",
+          TUE: "鍛ㄤ簩",
+          WED: "鍛ㄤ笁",
+          THU: "鍛ㄥ洓",
+          FRI: "鍛ㄤ簲",
+          SAT: "鍛ㄥ叚",
+          SUN: "鍛ㄦ棩",
+        })[item] || item
+    );
+  };
+
+  const getList = async () => {
+    if (loading.value) return;
+    loading.value = true;
+    try {
+      const params = {
+        ...queryParams,
+        current: pageParams.current,
+        size: pageParams.size,
+      };
+      const res = await deviceMaintenanceTaskList(params);
+      const records = res?.data?.records || res?.records || [];
+      if (pageParams.current === 1) {
+        tableData.value = records;
+      } else {
+        tableData.value = [...tableData.value, ...records];
+      }
+      total.value = Number(res?.data?.total ?? res?.total ?? 0);
+    } catch (error) {
+      if (pageParams.current === 1) {
+        tableData.value = [];
+      }
+      uni.showToast({
+        title: "鑾峰彇鏁版嵁澶辫触",
+        icon: "none",
+      });
+    } finally {
+      loading.value = false;
+    }
+  };
+
+  const handleQuery = () => {
+    pageParams.current = 1;
+    total.value = 0;
+    getList();
+  };
+
+  const loadMore = () => {
+    if (loading.value || noMore.value) return;
+    pageParams.current += 1;
+    getList();
+  };
+
+  const handleAdd = row => {
+    nextTick(() => {
+      formDia.value?.openDialog(row ? "edit" : "add", row);
+    });
+  };
+
+  const deleteOne = async row => {
+    if (!row?.id) return;
+    const canDelete = await new Promise(resolve => {
+      uni.showModal({
+        title: "鎻愮ず",
+        content: "鏄惁纭鍒犻櫎璇ヤ繚鍏讳换鍔★紵",
+        success: modalRes => resolve(Boolean(modalRes.confirm)),
+        fail: () => resolve(false),
+      });
+    });
+    if (!canDelete) return;
+    try {
+      await deviceMaintenanceTaskDel([row.id]);
+      uni.showToast({
+        title: "鍒犻櫎鎴愬姛",
+        icon: "success",
+      });
+      handleQuery();
+    } catch (error) {
+      uni.showToast({
+        title: "鍒犻櫎澶辫触",
+        icon: "none",
+      });
+    }
+  };
+
+  const onSwipeActionClick = (event, row) => {
+    if (event?.position !== "right") return;
+    deleteOne(row);
+  };
+
+  onShow(() => {
+    handleQuery();
+  });
+
+  onReachBottom(() => {
+    loadMore();
+  });
+
+  onPullDownRefresh(() => {
+    handleQuery();
+    uni.stopPullDownRefresh();
+  });
+</script>
+
+<style scoped>
+  .upkeep-task-page {
+    min-height: 100vh;
+    background: #f6f7fb;
+  }
+
+  .toolbar {
+    padding: 20rpx 24rpx;
+    background: #fff;
+    border-bottom: 1rpx solid #f0f0f0;
+    position: sticky;
+    top: 0;
+    z-index: 10;
+  }
+
+  .search-section {
+    margin-top: 0;
+  }
+
+  .search-bar {
+    display: flex;
+    align-items: center;
+    background: #f7f8fa;
+    border-radius: 14rpx;
+    padding: 8rpx 12rpx 8rpx 16rpx;
+    border: 1rpx solid #eef1f5;
+  }
+
+  .search-input {
+    flex: 1;
+    min-width: 0;
+  }
+
+  .search-text {
+    background: transparent !important;
+  }
+
+  :deep(.search-text .u-input__content),
+  :deep(.search-text .up-input__content) {
+    background: transparent !important;
+    padding: 0 !important;
+  }
+
+  .search-button {
+    width: 64rpx;
+    height: 64rpx;
+    border-radius: 12rpx;
+    background: #ffffff;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  .meta-bar {
+    margin-top: 16rpx;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    background: #f7f9fc;
+    border-radius: 12rpx;
+    padding: 10rpx 16rpx;
+  }
+
+  .meta-text {
+    color: #5c6b8a;
+    font-size: 22rpx;
+  }
+
+  .list-section {
+    padding: 20rpx 24rpx;
+    padding-bottom: calc(132rpx + env(safe-area-inset-bottom));
+  }
+
+  .ledger-item {
+    background: #ffffff;
+    border-radius: 20rpx;
+    margin-bottom: 16rpx;
+    overflow: hidden;
+    box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.05);
+    padding: 0 20rpx;
+  }
+
+  .item-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 22rpx 0;
+  }
+
+  .item-left {
+    display: flex;
+    align-items: center;
+    gap: 10rpx;
+    flex: 1;
+    min-width: 0;
+  }
+
+  .item-right {
+    display: flex;
+    align-items: center;
+  }
+
+  .document-icon {
+    width: 38rpx;
+    height: 38rpx;
+    border-radius: 8rpx;
+    background: #2979ff;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  .item-id {
+    font-size: 28rpx;
+    color: #1f1f1f;
+    font-weight: 600;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+
+  .item-details {
+    padding: 18rpx 0 20rpx;
+  }
+
+  .detail-row {
+    display: flex;
+    align-items: flex-end;
+    justify-content: space-between;
+    margin-bottom: 12rpx;
+  }
+
+  .detail-label {
+    min-width: 160rpx;
+    color: #777;
+    font-size: 24rpx;
+  }
+
+  .detail-value {
+    flex: 1;
+    color: #333;
+    font-size: 24rpx;
+    text-align: right;
+    word-break: break-all;
+    margin-left: 12rpx;
+  }
+
+  .detail-value.highlight {
+    color: #2979ff;
+    font-weight: 500;
+  }
+
+  .card-actions {
+    padding-top: 8rpx;
+    display: flex;
+    justify-content: flex-end;
+  }
+
+  .action-btn {
+    min-width: 140rpx;
+  }
+
+  .fab-button {
+    position: fixed;
+    bottom: calc(30px + env(safe-area-inset-bottom));
+    right: 30px;
+    width: 56px;
+    height: 56px;
+    background: #2979ff;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    box-shadow: 0 4px 16px rgba(41, 121, 255, 0.3);
+    z-index: 1000;
+  }
+
+  .no-data {
+    padding: 40rpx 0;
+    text-align: center;
+    color: #999;
+  }
+</style>
diff --git a/src/pages/index.vue b/src/pages/index.vue
index 127bcba..00f37cd 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -433,12 +433,13 @@
     },
     {
       icon: "/static/images/icon/xunjianshangchuan@2x.png",
-      label: "宸℃绠$悊",
+      label: "宸℃浠诲姟",
     },
     {
       icon: "/static/images/icon/xunjianshangchuan@2x.png",
-      label: "宸℃浠诲姟绠$悊",
-    }
+      label: "宸℃绠$悊",
+    },
+    
   ]);
 
   // 澶勭悊甯哥敤鍔熻兘鐐瑰嚮
@@ -653,6 +654,11 @@
           url: "/pages/equipmentManagement/repair/index",
         });
         break;
+      case "璁惧淇濆吇浠诲姟":
+        uni.navigateTo({
+          url: "/pages/equipmentManagement/upkeepTask/index",
+        });
+        break;
       case "璁惧淇濆吇":
         uni.navigateTo({
           url: "/pages/equipmentManagement/upkeep/index",
@@ -663,7 +669,7 @@
           url: "/pages/inspectionUpload/index",
         });
         break;
-      case "宸℃浠诲姟绠$悊":
+      case "宸℃浠诲姟":
         uni.navigateTo({
           url: "/pages/inspectionManagement/index",
         });
@@ -1040,17 +1046,26 @@
     const originalEquipment = [
       { icon: "/static/images/icon/shbeibaoxiu@2x.png", label: "杩愯绠$悊" },
       { icon: "/static/images/icon/shbeibaoxiu@2x.png", label: "璁惧鎶ヤ慨" },
+      { icon: "/static/images/icon/shbeibaoyang@2x.png", label: "璁惧淇濆吇浠诲姟" },
       { icon: "/static/images/icon/shbeibaoyang@2x.png", label: "璁惧淇濆吇" },
+      { icon: "/static/images/icon/xunjianshangchuan@2x.png", label: "宸℃浠诲姟" },
       { icon: "/static/images/icon/xunjianshangchuan@2x.png", label: "宸℃绠$悊" },
-      { icon: "/static/images/icon/xunjianshangchuan@2x.png", label: "宸℃浠诲姟绠$悊" },
     ];
     const filteredEquipment = originalEquipment.filter(item => {
       return allowedMenuTitles.has(item.label);
     });
+    if (filteredEquipment.some(i => i.label === "璁惧淇濆吇")) {
+      const upkeepTask = originalEquipment.find(i => i.label === "璁惧淇濆吇浠诲姟");
+      if (upkeepTask && !filteredEquipment.some(i => i.label === "璁惧淇濆吇浠诲姟")) {
+        const upkeepIndex = filteredEquipment.findIndex(i => i.label === "璁惧淇濆吇");
+        filteredEquipment.splice(upkeepIndex, 0, upkeepTask);
+      }
+    }
     if (filteredEquipment.some(i => i.label === "宸℃绠$悊")) {
-      const task = originalEquipment.find(i => i.label === "宸℃浠诲姟绠$悊");
-      if (task && !filteredEquipment.some(i => i.label === "宸℃浠诲姟绠$悊")) {
-        filteredEquipment.push(task);
+      const task = originalEquipment.find(i => i.label === "宸℃浠诲姟");
+      if (task && !filteredEquipment.some(i => i.label === "宸℃浠诲姟")) {
+        const manageIndex = filteredEquipment.findIndex(i => i.label === "宸℃绠$悊");
+        filteredEquipment.splice(manageIndex, 0, task);
       }
     }
     equipmentItems.splice(0, equipmentItems.length, ...filteredEquipment);
diff --git a/src/pages/indexItem.vue b/src/pages/indexItem.vue
index 7e78b6b..b38db48 100644
--- a/src/pages/indexItem.vue
+++ b/src/pages/indexItem.vue
@@ -325,6 +325,11 @@
           url: "/pages/equipmentManagement/repair/index",
         });
         break;
+      case "璁惧淇濆吇浠诲姟":
+        uni.navigateTo({
+          url: "/pages/equipmentManagement/upkeepTask/index",
+        });
+        break;
       case "璁惧淇濆吇":
         uni.navigateTo({
           url: "/pages/equipmentManagement/upkeep/index",
diff --git a/src/pages/inspectionManagement/index.vue b/src/pages/inspectionManagement/index.vue
index 349d1d0..4fe2335 100644
--- a/src/pages/inspectionManagement/index.vue
+++ b/src/pages/inspectionManagement/index.vue
@@ -1,17 +1,8 @@
 <template>
   <view class="inspection-management-page">
-    <PageHeader title="宸℃浠诲姟绠$悊"
+    <PageHeader title="瀹氭椂浠诲姟绠$悊"
                 @back="goBack" />
     <view class="toolbar">
-      <view class="tab-wrap">
-        <view v-for="tab in tabs"
-              :key="tab.name"
-              class="tab-item"
-              :class="{ active: activeTab === tab.name }"
-              @click="switchTab(tab.name)">
-          {{ tab.label }}
-        </view>
-      </view>
       <view class="search-section">
         <view class="search-bar">
           <view class="search-input">
@@ -36,8 +27,7 @@
       <uni-swipe-action>
         <uni-swipe-action-item v-for="item in tableData"
                                :key="item.id"
-                               :right-options="activeTab === 'taskManage' ? swipeOptions : []"
-                               :disabled="activeTab !== 'taskManage'"
+                               :right-options="swipeOptions"
                                @click="onSwipeActionClick($event, item)">
           <view class="ledger-item">
             <view class="item-header">
@@ -92,16 +82,10 @@
               </view>
               <up-divider></up-divider>
               <view class="card-actions">
-                <u-button v-if="activeTab === 'taskManage'"
-                          type="primary"
+                <u-button type="primary"
                           size="small"
                           class="action-btn"
                           @click.stop="handleAdd(item)">缂栬緫</u-button>
-                <u-button v-else
-                          type="success"
-                          size="small"
-                          class="action-btn"
-                          @click.stop="viewFile(item)">鏌ョ湅闄勪欢</u-button>
               </view>
             </view>
           </view>
@@ -113,8 +97,7 @@
         <text>鏆傛棤鏁版嵁</text>
       </view>
     </view>
-    <view v-if="activeTab === 'taskManage'"
-          class="fab-button"
+    <view class="fab-button"
           @click="handleAdd()">
       <up-icon name="plus"
                size="24"
@@ -122,7 +105,6 @@
     </view>
     <form-dia ref="formDia"
               @closeDia="handleQuery" />
-    <view-files ref="viewFiles" />
   </view>
 </template>
 
@@ -131,20 +113,12 @@
   import { onShow, onReachBottom, onPullDownRefresh } from "@dcloudio/uni-app";
   import PageHeader from "@/components/PageHeader.vue";
   import FormDia from "@/pages/inspectionManagement/components/formDia.vue";
-  import ViewFiles from "@/pages/inspectionManagement/components/viewFiles.vue";
   import {
     delTimingTask,
-    inspectionTaskList,
     timingTaskList,
   } from "@/api/inspectionManagement/index.js";
 
   const formDia = ref();
-  const viewFiles = ref();
-  const activeTab = ref("taskManage");
-  const tabs = [
-    { name: "taskManage", label: "瀹氭椂浠诲姟绠$悊" },
-    { name: "task", label: "瀹氭椂浠诲姟璁板綍" },
-  ];
   const queryParams = reactive({
     taskName: "",
   });
@@ -219,12 +193,6 @@
     return [String(val)];
   };
 
-  const switchTab = tabName => {
-    if (activeTab.value === tabName) return;
-    activeTab.value = tabName;
-    handleQuery();
-  };
-
   const getList = async () => {
     if (loading.value) return;
     loading.value = true;
@@ -234,8 +202,7 @@
         current: pageParams.current,
         size: pageParams.size,
       };
-      const request = activeTab.value === "task" ? inspectionTaskList : timingTaskList;
-      const res = await request(params);
+      const res = await timingTaskList(params);
       const records = res?.data?.records || [];
       const normalized = records.map(item => ({
         ...item,
@@ -278,12 +245,6 @@
     });
   };
 
-  const viewFile = row => {
-    nextTick(() => {
-      viewFiles.value?.openDialog(row);
-    });
-  };
-
   const deleteOne = async row => {
     if (!row?.id) return;
     const canDelete = await new Promise(resolve => {
@@ -311,7 +272,6 @@
   };
 
   const onSwipeActionClick = (event, row) => {
-    if (activeTab.value !== "taskManage") return;
     if (event?.position !== "right") return;
     deleteOne(row);
   };
@@ -345,30 +305,8 @@
     z-index: 10;
   }
 
-  .tab-wrap {
-    display: flex;
-    background: #f4f5f8;
-    border-radius: 16rpx;
-    padding: 6rpx;
-  }
-
-  .tab-item {
-    flex: 1;
-    text-align: center;
-    padding: 14rpx 0;
-    font-size: 26rpx;
-    color: #666;
-    border-radius: 12rpx;
-  }
-
-  .tab-item.active {
-    background: #1677ff;
-    color: #fff;
-    font-weight: 600;
-  }
-
   .search-section {
-    margin-top: 20rpx;
+    margin-top: 0;
   }
 
   .search-bar {

--
Gitblit v1.9.3