From 9fae4a56c15392babde83d68db4073762900082d Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期五, 16 十月 2026 22:39:32 +0800
Subject: [PATCH] feat: 设备保养和巡检优化,项目拆分

---
 src/views/equipmentManagement/upkeep/index.vue                                           | 1103 ++++----
 src/views/equipmentManagement/inspectionManagement/components/InspectionItemManager.vue  |  326 ++
 src/views/equipmentManagement/upkeep/Form/PlanModal.vue                                  |  188 +
 src/views/equipmentManagement/inspectionManagement/components/formDia.vue                |  775 +++--
 src/views/equipmentManagement/upkeep/Form/MaintenanceItemSelector.vue                    |  181 +
 src/api/equipmentManagement/upkeep.js                                                    |   54 
 src/views/equipmentManagement/upkeep/Form/ItemManager.vue                                |  331 ++
 src/views/equipmentManagement/inspectionManagement/index.vue                             |  967 ++++---
 src/views/equipmentManagement/upkeep/Form/detailDia.vue                                  |  240 +
 src/views/equipmentManagement/inspectionManagement/components/InspectionItemSelector.vue |  172 +
 src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue                            |  226 +
 src/api/inspectionManagement/index.js                                                    |   85 
 src/views/equipmentManagement/upkeep/Form/formDia.vue                                    |  913 ++++--
 src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue            | 1167 +++++----
 src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue                           |  534 ++-
 15 files changed, 4,693 insertions(+), 2,569 deletions(-)

diff --git a/src/api/equipmentManagement/upkeep.js b/src/api/equipmentManagement/upkeep.js
index 234d2a5..b7233b6 100644
--- a/src/api/equipmentManagement/upkeep.js
+++ b/src/api/equipmentManagement/upkeep.js
@@ -73,7 +73,7 @@
 // 娣诲姞璁惧淇濆吇瀹氭椂浠诲姟
 export const deviceMaintenanceTaskAdd = (params) => {
   return request({
-    url: '/deviceMaintenanceTask/add',
+    url: "/deviceMaintenanceTask/add",
     method: "post",
     data: params,
   });
@@ -81,7 +81,7 @@
 // 淇敼璁惧淇濆吇瀹氭椂浠诲姟
 export const deviceMaintenanceTaskEdit = (params) => {
   return request({
-    url: '/deviceMaintenanceTask/update',
+    url: "/deviceMaintenanceTask/update",
     method: "post",
     data: params,
   });
@@ -89,7 +89,7 @@
 // 璁惧淇濆吇瀹氭椂浠诲姟鍒楄〃
 export const deviceMaintenanceTaskList = (params) => {
   return request({
-    url: '/deviceMaintenanceTask/listPage',
+    url: "/deviceMaintenanceTask/listPage",
     method: "get",
     params: params,
   });
@@ -97,8 +97,54 @@
 // 璁惧淇濆吇瀹氭椂浠诲姟鍒楄〃
 export const deviceMaintenanceTaskDel = (params) => {
   return request({
-    url: '/deviceMaintenanceTask/delete',
+    url: "/deviceMaintenanceTask/delete",
     method: "delete",
     data: params,
   });
 };
+
+export const getMaintenanceItemList = (params = {}) => {
+  return request({
+    url: "/deviceMaintenanceItem/list",
+    method: "get",
+    params,
+  });
+};
+
+export const getMaintenanceItemPage = (params = {}) => {
+  return request({
+    url: "/deviceMaintenanceItem/page",
+    method: "get",
+    params,
+  });
+};
+
+export const getActiveMaintenanceItems = () => {
+  return request({
+    url: "/deviceMaintenanceTask/items",
+    method: "get",
+  });
+};
+
+export const addMaintenanceItem = (data) => {
+  return request({
+    url: "/deviceMaintenanceItem",
+    method: "post",
+    data,
+  });
+};
+
+export const editMaintenanceItem = (data) => {
+  return request({
+    url: "/deviceMaintenanceItem",
+    method: "put",
+    data,
+  });
+};
+
+export const deleteMaintenanceItem = (id) => {
+  return request({
+    url: `/deviceMaintenanceItem/${id}`,
+    method: "delete",
+  });
+};
diff --git a/src/api/inspectionManagement/index.js b/src/api/inspectionManagement/index.js
index d0c444a..ca773d1 100644
--- a/src/api/inspectionManagement/index.js
+++ b/src/api/inspectionManagement/index.js
@@ -1,61 +1,72 @@
 // 宸℃绠$悊
-import request from '@/utils/request'
+import request from "@/utils/request";
 
 // 宸℃浠诲姟琛ㄨ〃鏌ヨ
 export function inspectionTaskList(query) {
-    return request({
-        url: '/inspectionTask/list',
-        method: 'get',
-        params: query
-    })
+  return request({
+    url: "/inspectionTask/list",
+    method: "get",
+    params: query,
+  });
 }
 // 宸℃浠诲姟琛ㄦ柊澧炰慨鏀�
 export function addOrEditInspectionTask(query) {
-    return request({
-        url: '/inspectionTask/addOrEditInspectionTask',
-        method: 'post',
-        data: query
-    })
+  return request({
+    url: "/inspectionTask/addOrEditInspectionTask",
+    method: "post",
+    data: query,
+  });
 }
 // 宸℃浠诲姟琛ㄥ垹闄�
 export function delInspectionTask(query) {
-    return request({
-        url: '/inspectionTask/delInspectionTask',
-        method: 'delete',
-        data: query
-    })
+  return request({
+    url: "/inspectionTask/delInspectionTask",
+    method: "delete",
+    data: query,
+  });
 }
 // 瀹氭椂宸℃浠诲姟琛ㄥ垹闄�
 export function delTimingTask(query) {
-    return request({
-        url: '/timingTask/delTimingTask',
-        method: 'delete',
-        data: query
-    })
+  return request({
+    url: "/timingTask/delTimingTask",
+    method: "delete",
+    data: query,
+  });
 }
 
 // /inspectionTask/addOrEditInspectionTask
 // 宸℃涓婁紶
 export function uploadInspectionTask(query) {
-    return request({
-        url: '/inspectionTask/addOrEditInspectionTask',
-        method: 'post',
-        data: query
-    })
+  return request({
+    url: "/inspectionTask/addOrEditInspectionTask",
+    method: "post",
+    data: query,
+  });
 }
 // 瀹氭椂宸℃浠诲姟琛ㄦ煡璇�
 export function timingTaskList(query) {
-    return request({
-        url: '/timingTask/list',
-        method: 'get',
-        params: query
-    })
+  return request({
+    url: "/timingTask/list",
+    method: "get",
+    params: query,
+  });
 }
 // 瀹氭椂宸℃浠诲姟琛ㄦ柊澧炰慨鏀�
 export function addOrEditTimingTask(query) {
-    return request({
-        url: '/timingTask/addOrEditTimingTask',
-        method: 'post',
-        data: query
-    })
-}
\ No newline at end of file
+  return request({
+    url: "/timingTask/addOrEditTimingTask",
+    method: "post",
+    data: query,
+  });
+}
+
+export const getInspectionItemList = (params = {}) =>
+  request({ url: "/inspectionItem/list", method: "get", params });
+export const getInspectionItemPage = (params = {}) =>
+  request({ url: "/inspectionItem/page", method: "get", params });
+export const addInspectionItem = (data) =>
+  request({ url: "/inspectionItem", method: "post", data });
+export const editInspectionItem = (data) =>
+  request({ url: "/inspectionItem", method: "put", data });
+export const deleteInspectionItem = (id) =>
+  request({ url: `/inspectionItem/${id}`, method: "delete" });
diff --git a/src/views/equipmentManagement/inspectionManagement/components/InspectionItemManager.vue b/src/views/equipmentManagement/inspectionManagement/components/InspectionItemManager.vue
new file mode 100644
index 0000000..ff88721
--- /dev/null
+++ b/src/views/equipmentManagement/inspectionManagement/components/InspectionItemManager.vue
@@ -0,0 +1,326 @@
+<template>
+  <div class="app-container">
+    <el-form :model="filters" :inline="true">
+      <el-form-item label="鎵�灞炶澶�">
+        <el-select
+          v-model="filters.deviceLedgerId"
+          clearable
+          filterable
+          placeholder="璇烽�夋嫨璁惧"
+          style="width: 220px"
+        >
+          <el-option
+            v-for="device in deviceOptions"
+            :key="device.id"
+            :label="device.deviceName"
+            :value="device.id"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="宸℃棰戠巼">
+        <el-select
+          v-model="filters.frequencyType"
+          clearable
+          placeholder="璇烽�夋嫨棰戠巼"
+          style="width: 180px"
+        >
+          <el-option
+            v-for="option in frequencyOptions"
+            :key="option.value"
+            :label="option.label"
+            :value="option.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="宸℃椤圭洰/鍐呭">
+        <el-input
+          v-model="keyword"
+          clearable
+          placeholder="璇疯緭鍏ラ」鐩垨鍐呭"
+          style="width: 240px"
+          @keyup.enter="search"
+          @clear="search"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="search">鎼滅储</el-button>
+        <el-button @click="resetFilters">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-card>
+      <div class="actions">
+        <el-text size="large">宸℃椤圭洰涓庡唴瀹规竻鍗�</el-text>
+        <el-button type="primary" @click="openAdd">鏂板宸℃鍐呭</el-button>
+      </div>
+      <el-table v-loading="loading" :data="items" border>
+        <el-table-column type="index" label="搴忓彿" width="80" align="center" :index="indexMethod" />
+        <el-table-column
+          prop="itemProject"
+          label="宸℃椤圭洰"
+          min-width="180"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="itemContent"
+          label="宸℃鍐呭"
+          min-width="300"
+          show-overflow-tooltip
+        />
+        <el-table-column label="鎵�灞炶澶�" min-width="180" align="center">
+          <template #default="{ row }">{{
+            row.deviceLedgerId ? deviceNameMap[row.deviceLedgerId] || "-" : "閫氱敤"
+          }}</template>
+        </el-table-column>
+        <el-table-column label="棰戠巼" width="120" align="center">
+          <template #default="{ row }">{{ frequencyLabel(row.frequencyType) }}</template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" width="150" align="center" fixed="right">
+          <template #default="{ row }">
+            <el-button link type="primary" @click="openEdit(row)">缂栬緫</el-button>
+            <el-button link type="danger" @click="removeItem(row)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+        <template #empty>
+          <el-empty description="杩樻病鏈夊贰妫�鍐呭锛岃閫愭潯娣诲姞">
+            <el-button type="primary" @click="openAdd">鏂板宸℃鍐呭</el-button>
+          </el-empty>
+        </template>
+      </el-table>
+      <div class="pagination-wrap">
+        <el-pagination
+          v-model:current-page="pageNum"
+          v-model:page-size="pageSize"
+          background
+          :page-sizes="[10, 20, 50]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="load"
+        />
+      </div>
+    </el-card>
+
+    <el-dialog
+      v-model="dialogVisible"
+      :title="form.id ? '缂栬緫宸℃鍐呭' : '鏂板宸℃鍐呭'"
+      width="620px"
+      align-center
+      destroy-on-close
+      :close-on-click-modal="false"
+    >
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="宸℃椤圭洰" prop="itemProject">
+          <el-input
+            v-model.trim="form.itemProject"
+            maxlength="200"
+            show-word-limit
+            placeholder="渚嬪锛氳澶囧瑙傛鏌�"
+          />
+        </el-form-item>
+        <el-form-item label="宸℃鍐呭" prop="itemContent">
+          <el-input
+            v-model.trim="form.itemContent"
+            type="textarea"
+            :rows="4"
+            resize="vertical"
+            maxlength="2000"
+            show-word-limit
+            placeholder="濉啓鍏蜂綋妫�鏌ュ唴瀹�"
+          />
+        </el-form-item>
+        <el-form-item label="鎵�灞炶澶�">
+          <el-select
+            v-model="form.deviceLedgerId"
+            clearable
+            filterable
+            style="width: 100%"
+            placeholder="涓嶉�夋嫨鍒欎负閫氱敤宸℃鍐呭"
+          >
+            <el-option
+              v-for="device in deviceOptions"
+              :key="device.id"
+              :label="device.deviceName"
+              :value="device.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="宸℃棰戠巼" prop="frequencyType">
+          <el-select v-model="form.frequencyType" style="width: 100%" placeholder="璇烽�夋嫨棰戠巼">
+            <el-option
+              v-for="option in frequencyOptions"
+              :key="option.value"
+              :label="option.label"
+              :value="option.value"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+        <el-button type="primary" :loading="saving" @click="save">淇濆瓨</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { computed, onMounted, reactive, ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import {
+  addInspectionItem,
+  deleteInspectionItem,
+  editInspectionItem,
+  getInspectionItemPage,
+} from "@/api/inspectionManagement";
+import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
+
+const items = ref([]);
+const loading = ref(false);
+const saving = ref(false);
+const dialogVisible = ref(false);
+const formRef = ref();
+const keyword = ref("");
+const pageNum = ref(1);
+const pageSize = ref(20);
+const total = ref(0);
+const deviceOptions = ref([]);
+const filters = reactive({ deviceLedgerId: undefined, frequencyType: "" });
+const frequencyOptions = [
+  { label: "姣忔棩", value: "DAILY" },
+  { label: "姣忓懆", value: "WEEKLY" },
+  { label: "姣忔湀", value: "MONTHLY" },
+  { label: "姣忓搴�", value: "QUARTERLY" },
+  { label: "閫氱敤棰戠巼", value: "ALL" },
+];
+const deviceNameMap = computed(() =>
+  Object.fromEntries(deviceOptions.value.map((device) => [String(device.id), device.deviceName]))
+);
+const frequencyLabel = (value) =>
+  frequencyOptions.find((option) => option.value === value)?.label || value || "-";
+const indexMethod = (index) => (pageNum.value - 1) * pageSize.value + index + 1;
+const form = reactive({
+  id: undefined,
+  itemProject: "",
+  itemContent: "",
+  deviceLedgerId: undefined,
+  frequencyType: "",
+  sortNum: 0,
+  isActive: 1,
+  remarks: "",
+});
+const rules = {
+  itemProject: [{ required: true, message: "璇疯緭鍏ュ贰妫�椤圭洰", trigger: "blur" }],
+  itemContent: [{ required: true, message: "璇疯緭鍏ュ贰妫�鍐呭", trigger: "blur" }],
+  frequencyType: [{ required: true, message: "璇烽�夋嫨宸℃棰戠巼", trigger: "change" }],
+};
+
+const load = async () => {
+  loading.value = true;
+  try {
+    const { code, data } = await getInspectionItemPage({
+      pageNum: pageNum.value,
+      pageSize: pageSize.value,
+      itemKeyword: keyword.value.trim(),
+      isActive: 1,
+      deviceLedgerId: filters.deviceLedgerId,
+      frequencyType: filters.frequencyType,
+      includeCommon: true,
+    });
+    if (code === 200) {
+      items.value = data?.records || [];
+      total.value = Number(data?.total || 0);
+    }
+  } finally {
+    loading.value = false;
+  }
+};
+const search = () => {
+  pageNum.value = 1;
+  load();
+};
+const resetFilters = () => {
+  filters.deviceLedgerId = undefined;
+  filters.frequencyType = "";
+  keyword.value = "";
+  search();
+};
+const handleSizeChange = () => {
+  pageNum.value = 1;
+  load();
+};
+const reset = () =>
+  Object.assign(form, {
+    id: undefined,
+    itemProject: "",
+    itemContent: "",
+    deviceLedgerId: undefined,
+    frequencyType: "",
+    sortNum: 0,
+    isActive: 1,
+    remarks: "",
+  });
+const openAdd = () => {
+  reset();
+  dialogVisible.value = true;
+};
+const openEdit = (row) => {
+  Object.assign(form, { ...row });
+  dialogVisible.value = true;
+};
+const save = async () => {
+  if (
+    !(await formRef.value
+      ?.validate()
+      .then(() => true)
+      .catch(() => false))
+  )
+    return;
+  saving.value = true;
+  try {
+    const { code } = form.id
+      ? await editInspectionItem({ ...form })
+      : await addInspectionItem({ ...form });
+    if (code === 200) {
+      ElMessage.success("淇濆瓨鎴愬姛");
+      dialogVisible.value = false;
+      await load();
+    }
+  } finally {
+    saving.value = false;
+  }
+};
+const removeItem = async (row) => {
+  try {
+    await ElMessageBox.confirm(`纭畾鍒犻櫎宸℃鍐呭鈥�${row.itemContent}鈥濆悧锛焋, "鎻愮ず", {
+      type: "warning",
+    });
+    const { code } = await deleteInspectionItem(row.id);
+    if (code === 200) {
+      ElMessage.success("鍒犻櫎鎴愬姛");
+      await load();
+    }
+  } catch (_) {
+    /* 鐢ㄦ埛鍙栨秷 */
+  }
+};
+onMounted(async () => {
+  const { data } = await getDeviceLedger();
+  deviceOptions.value = data || [];
+  await load();
+});
+</script>
+
+<style scoped>
+.actions {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 10px;
+}
+.pagination-wrap {
+  display: flex;
+  justify-content: flex-end;
+  padding-top: 12px;
+}
+</style>
diff --git a/src/views/equipmentManagement/inspectionManagement/components/InspectionItemSelector.vue b/src/views/equipmentManagement/inspectionManagement/components/InspectionItemSelector.vue
new file mode 100644
index 0000000..be21f84
--- /dev/null
+++ b/src/views/equipmentManagement/inspectionManagement/components/InspectionItemSelector.vue
@@ -0,0 +1,172 @@
+<template>
+  <el-dialog
+    v-model="dialogVisible"
+    title="閫夋嫨宸℃鍐呭"
+    width="820px"
+    append-to-body
+    destroy-on-close
+  >
+    <div class="selector-toolbar">
+      <el-input
+        v-model="keyword"
+        clearable
+        placeholder="鎸夐」鐩垨鍐呭鎼滅储"
+        @keyup.enter="search"
+        @clear="search"
+      />
+      <el-button type="primary" @click="search">鎼滅储</el-button>
+    </div>
+    <el-table v-loading="loading" :data="rows" border height="360">
+      <el-table-column label="閫夋嫨" width="70" align="center">
+        <template #default="{ row }"
+          ><el-checkbox
+            :model-value="isSelected(row.id)"
+            @change="(checked) => toggleItem(row, checked)"
+        /></template>
+      </el-table-column>
+      <el-table-column type="index" label="搴忓彿" width="70" />
+      <el-table-column label="绫诲瀷" width="90" align="center">
+        <template #default="{ row }"
+          ><el-tag :type="row.deviceLedgerId ? 'primary' : 'info'" size="small">{{
+            row.deviceLedgerId ? "鏈澶�" : "閫氱敤"
+          }}</el-tag></template
+        >
+      </el-table-column>
+      <el-table-column prop="itemProject" label="宸℃椤圭洰" min-width="170" show-overflow-tooltip />
+      <el-table-column prop="itemContent" label="宸℃鍐呭" min-width="270" show-overflow-tooltip />
+      <el-table-column label="棰戠巼" width="110" align="center">
+        <template #default="{ row }"
+          ><el-tag :type="row.frequencyType === 'ALL' ? 'info' : 'success'" size="small">{{
+            frequencyLabel(row.frequencyType)
+          }}</el-tag></template
+        >
+      </el-table-column>
+    </el-table>
+    <div class="selector-pagination">
+      <el-pagination
+        v-model:current-page="pageNum"
+        v-model:page-size="pageSize"
+        :page-sizes="[10, 20, 50]"
+        :total="total"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="load"
+      />
+    </div>
+    <template #footer>
+      <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+      <el-button type="primary" @click="confirm">纭畾閫夋嫨锛坽{ selected.size }}锛�</el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { computed, ref, watch } from "vue";
+import { getInspectionItemPage } from "@/api/inspectionManagement";
+
+const props = defineProps({
+  visible: { type: Boolean, default: false },
+  selectedItems: { type: Array, default: () => [] },
+  deviceLedgerId: { type: [Number, String], default: undefined },
+  frequencyType: { type: String, default: "" },
+});
+const emit = defineEmits(["update:visible", "confirm"]);
+const dialogVisible = computed({
+  get: () => props.visible,
+  set: (value) => emit("update:visible", value),
+});
+const rows = ref([]);
+const loading = ref(false);
+const keyword = ref("");
+const pageNum = ref(1);
+const pageSize = ref(10);
+const total = ref(0);
+const selected = ref(new Map());
+const frequencyLabel = (value) =>
+  ({ DAILY: "姣忔棩", WEEKLY: "姣忓懆", MONTHLY: "姣忔湀", QUARTERLY: "姣忓搴�", ALL: "閫氱敤棰戠巼" }[
+    value
+  ] ||
+  value ||
+  "-");
+
+watch(
+  () => props.visible,
+  (visible) => {
+    if (!visible) return;
+    keyword.value = "";
+    pageNum.value = 1;
+    selected.value = new Map(
+      (props.selectedItems || []).map((item) => [String(item.inspectionItemId || item.id), item])
+    );
+    load();
+  }
+);
+watch(
+  () => [props.deviceLedgerId, props.frequencyType],
+  () => {
+    if (!props.visible) return;
+    pageNum.value = 1;
+    load();
+  }
+);
+const load = async () => {
+  if (!props.deviceLedgerId || !props.frequencyType) {
+    rows.value = [];
+    total.value = 0;
+    return;
+  }
+  loading.value = true;
+  try {
+    const { code, data } = await getInspectionItemPage({
+      pageNum: pageNum.value,
+      pageSize: pageSize.value,
+      itemKeyword: keyword.value.trim(),
+      isActive: 1,
+      deviceLedgerId: props.deviceLedgerId,
+      frequencyType: props.frequencyType,
+      includeCommon: true,
+    });
+    if (code === 200) {
+      rows.value = data?.records || [];
+      total.value = Number(data?.total || 0);
+    }
+  } finally {
+    loading.value = false;
+  }
+};
+const search = () => {
+  pageNum.value = 1;
+  load();
+};
+const handleSizeChange = () => {
+  pageNum.value = 1;
+  load();
+};
+const isSelected = (id) => selected.value.has(String(id));
+const toggleItem = (item, checked) => {
+  const next = new Map(selected.value);
+  if (checked) next.set(String(item.id), item);
+  else next.delete(String(item.id));
+  selected.value = next;
+};
+const confirm = () => {
+  emit("confirm", Array.from(selected.value.values()));
+  dialogVisible.value = false;
+};
+</script>
+
+<style scoped>
+.selector-toolbar {
+  display: flex;
+  gap: 10px;
+  margin-bottom: 14px;
+}
+.selector-toolbar .el-input {
+  max-width: 440px;
+}
+.selector-pagination {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 14px;
+}
+</style>
diff --git a/src/views/equipmentManagement/inspectionManagement/components/formDia.vue b/src/views/equipmentManagement/inspectionManagement/components/formDia.vue
index 0f94f66..ef78caa 100644
--- a/src/views/equipmentManagement/inspectionManagement/components/formDia.vue
+++ b/src/views/equipmentManagement/inspectionManagement/components/formDia.vue
@@ -1,314 +1,503 @@
 <template>
-  <div>
-    <el-dialog :title="operationType === 'add' ? '鏂板宸℃浠诲姟' : '缂栬緫宸℃浠诲姟'"
-               v-model="dialogVisitable" width="800px" @close="cancel">
-      <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
-        <el-row>
-          <el-col :span="12">
-            <el-form-item label="璁惧鍚嶇О" prop="taskId">
-              <el-select v-model="form.taskId" @change="setDeviceModel">
+  <el-dialog
+    v-model="visible"
+    :title="editing ? '缂栬緫宸℃浠诲姟' : '鏂板宸℃浠诲姟'"
+    width="800px"
+    align-center
+    destroy-on-close
+    :close-on-click-modal="false"
+    @closed="reset"
+  >
+    <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
+      <el-row :gutter="24">
+        <el-col :span="12">
+          <el-form-item label="璁惧鍚嶇О" prop="taskId">
+            <el-select
+              v-model="form.taskId"
+              filterable
+              placeholder="璇烽�夋嫨璁惧"
+              style="width: 100%"
+              @change="changeDevice"
+            >
+              <el-option
+                v-for="device in deviceOptions"
+                :key="device.id"
+                :label="device.deviceName"
+                :value="device.id"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="宸℃浜�" prop="inspector">
+            <el-select
+              v-model="form.inspector"
+              placeholder="璇烽�夋嫨宸℃浜�"
+              multiple
+              clearable
+              filterable
+              style="width: 100%"
+            >
+              <el-option
+                v-for="user in userList"
+                :key="user.userId"
+                :label="user.nickName"
+                :value="user.userId"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="浠诲姟棰戠巼" prop="frequencyType">
+            <el-select
+              v-model="form.frequencyType"
+              placeholder="璇烽�夋嫨棰戠巼"
+              style="width: 100%"
+              @change="handleFrequencyChange"
+            >
+              <el-option label="姣忔棩" value="DAILY" />
+              <el-option label="姣忓懆" value="WEEKLY" />
+              <el-option label="姣忔湀" value="MONTHLY" />
+              <el-option label="姣忓搴�" value="QUARTERLY" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col v-if="form.frequencyType === 'DAILY'" :span="12">
+          <el-form-item label="鎵ц鏃堕棿" prop="frequencyDetail">
+            <el-time-picker
+              v-model="form.frequencyDetail"
+              placeholder="閫夋嫨鏃堕棿"
+              format="HH:mm"
+              value-format="HH:mm"
+              style="width: 100%"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col v-if="form.frequencyType === 'WEEKLY'" :span="12">
+          <el-form-item label="鎵ц鏃ユ湡" prop="frequencyDetail">
+            <div class="frequency-fields">
+              <el-select v-model="form.week" placeholder="鏄熸湡" style="width: 50%">
                 <el-option
-                  v-for="(item, index) in deviceOptions"
-                  :key="index"
-                  :label="item.deviceName"
-                  :value="item.id"
-                ></el-option>
+                  v-for="day in weekdays"
+                  :key="day.value"
+                  :label="day.label"
+                  :value="day.value"
+                />
               </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="宸℃浜�" prop="inspector">
-              <el-select v-model="form.inspector" placeholder="璇烽�夋嫨" multiple clearable>
-                <el-option v-for="item in userList" :label="item.nickName" :value="item.userId" :key="item.userId"/>
-              </el-select>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="12">
-            <el-form-item label="宸℃椤圭洰" prop="inspectionProject">
-              <el-input v-model="form.inspectionProject" placeholder="璇疯緭鍏ュ贰妫�椤圭洰" type="textarea" :autosize="{ minRows: 2, maxRows: 6 }" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="澶囨敞" prop="remarks">
-              <el-input v-model="form.remarks" placeholder="璇疯緭鍏ュ娉�" type="textarea" :autosize="{ minRows: 2, maxRows: 6 }" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="12">
-            <el-form-item label="鏄惁鍚敤" prop="isEnabled">
-              <el-radio-group v-model="form.isEnabled">
-                <el-radio :value="1">鏄�</el-radio>
-                <el-radio :value="0">鍚�</el-radio>
-              </el-radio-group>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="12">
-            <el-form-item label="浠诲姟棰戠巼" prop="frequencyType">
-              <el-select v-model="form.frequencyType" placeholder="璇烽�夋嫨" clearable>
-                <el-option label="姣忔棩" value="DAILY"/>
-                <el-option label="姣忓懆" value="WEEKLY"/>
-                <el-option label="姣忔湀" value="MONTHLY"/>
-                <!-- <el-option label="瀛e害" value="QUARTERLY"/> -->
-              </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType">
-            <el-form-item label="鏃ユ湡" prop="frequencyDetail">
-              <el-time-picker v-model="form.frequencyDetail" placeholder="閫夋嫨鏃堕棿" format="HH:mm"
-                              value-format="HH:mm" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
-            <el-form-item label="鏃ユ湡" prop="frequencyDetail">
-              <el-select v-model="form.week" placeholder="璇烽�夋嫨" clearable style="width: 50%">
-                <el-option label="鍛ㄤ竴" value="MON"/>
-                <el-option label="鍛ㄤ簩" value="TUE"/>
-                <el-option label="鍛ㄤ笁" value="WED"/>
-                <el-option label="鍛ㄥ洓" value="THU"/>
-                <el-option label="鍛ㄤ簲" value="FRI"/>
-                <el-option label="鍛ㄥ叚" value="SAT"/>
-                <el-option label="鍛ㄦ棩" value="SUN"/>
-              </el-select>
-              <el-time-picker v-model="form.time" placeholder="閫夋嫨鏃堕棿" format="HH:mm"
-                              value-format="HH:mm"  style="width: 50%"/>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
-            <el-form-item label="鏃ユ湡" prop="frequencyDetail">
-              <el-date-picker
-                  v-model="form.frequencyDetail"
-                  type="datetime"
-                  clearable
-                  placeholder="閫夋嫨寮�濮嬫棩鏈�"
-                  format="DD,HH:mm"
-                  value-format="DD,HH:mm"
+              <el-time-picker
+                v-model="form.time"
+                placeholder="鏃堕棿"
+                format="HH:mm"
+                value-format="HH:mm"
+                style="width: 50%"
               />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType">
-            <el-form-item label="鏃ユ湡" prop="frequencyDetail">
-              <el-date-picker
-                  v-model="form.frequencyDetail"
-                  type="datetime"
+            </div>
+          </el-form-item>
+        </el-col>
+        <el-col v-if="form.frequencyType === 'MONTHLY'" :span="12">
+          <el-form-item label="鎵ц鏃ユ湡" prop="frequencyDetail">
+            <el-date-picker
+              v-model="form.frequencyDetail"
+              type="datetime"
+              clearable
+              placeholder="閫夋嫨寮�濮嬫棩鏈�"
+              format="DD,HH:mm"
+              value-format="DD,HH:mm"
+              style="width: 100%"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col v-if="form.frequencyType === 'QUARTERLY'" :span="12">
+          <el-form-item label="鎵ц鏃ユ湡" prop="frequencyDetail">
+            <el-date-picker
+              v-model="form.frequencyDetail"
+              type="datetime"
+              clearable
+              placeholder="閫夋嫨寮�濮嬫棩鏈�"
+              format="MM,DD,HH:mm"
+              value-format="MM,DD,HH:mm"
+              style="width: 100%"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="鏄惁鍚敤" prop="isEnabled">
+            <el-radio-group v-model="form.isEnabled"
+              ><el-radio :value="1">鍚敤</el-radio
+              ><el-radio :value="0">鍋滅敤</el-radio></el-radio-group
+            >
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <el-form-item label="宸℃鍐呭" prop="inspectionItemIds">
+            <div class="items-field">
+              <div class="items-toolbar">
+                <el-button
+                  type="primary"
+                  plain
+                  :disabled="!form.taskId || !form.frequencyType"
+                  @click="selectorVisible = true"
+                  >閫夋嫨宸℃鍐呭</el-button
+                >
+                <span class="muted">{{ selectionHint }}</span>
+              </div>
+              <div class="custom-input">
+                <el-input
+                  v-model="customItemProject"
+                  maxlength="200"
                   clearable
-                  placeholder="閫夋嫨寮�濮嬫棩鏈�"
-                  format="MM,DD,HH:mm"
-                  value-format="MM,DD,HH:mm"
-              />
-            </el-form-item>
-          </el-col>
-        </el-row>
-      </el-form>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">淇濆瓨</el-button>
-          <el-button @click="cancel">鍙栨秷</el-button>
-        </div>
-      </template>
-    </el-dialog>
-  </div>
+                  placeholder="杈撳叆鏈换鍔′笓鐢ㄧ殑宸℃椤圭洰"
+                />
+                <el-input
+                  v-model="customItemContent"
+                  maxlength="2000"
+                  clearable
+                  placeholder="杈撳叆椤圭洰瀵瑰簲鐨勫贰妫�鍐呭"
+                  @keyup.enter="addCustomItem"
+                />
+                <el-button
+                  :disabled="!customItemProject.trim() || !customItemContent.trim()"
+                  @click="addCustomItem"
+                  >娣诲姞</el-button
+                >
+              </div>
+              <div v-if="displayItems.length" class="selected-items">
+                <div v-for="(item, index) in displayItems" :key="item.key" class="selected-item">
+                  <div class="selected-item-title">
+                    <b>{{ index + 1 }}. {{ item.itemProject }}</b>
+                    <el-button link type="danger" @click="removeTaskItem(item)">绉婚櫎</el-button>
+                  </div>
+                  <div class="selected-item-content">{{ item.itemContent }}</div>
+                </div>
+              </div>
+              <el-empty v-else description="鏆傛湭閫夋嫨宸℃鍐呭" :image-size="50" />
+            </div>
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <el-form-item label="澶囨敞"
+            ><el-input
+              v-model="form.remarks"
+              type="textarea"
+              :rows="2"
+              maxlength="500"
+              show-word-limit
+          /></el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template #footer>
+      <el-button @click="visible = false">鍙栨秷</el-button>
+      <el-button type="primary" :loading="saving" @click="submit">淇濆瓨</el-button>
+    </template>
+  </el-dialog>
+  <InspectionItemSelector
+    v-model:visible="selectorVisible"
+    :selected-items="form.inspectionItems"
+    :device-ledger-id="form.taskId"
+    :frequency-type="form.frequencyType"
+    @confirm="setSelectedItems"
+  />
 </template>
 
 <script setup>
-import {reactive, ref, getCurrentInstance, toRefs} from "vue";
-import useUserStore from '@/store/modules/user'
-import {addOrEditTimingTask} from "@/api/inspectionManagement/index.js";
-import {userListNoPageByTenantId} from "@/api/system/user.js";
+import { computed, getCurrentInstance, reactive, ref } from "vue";
+import useUserStore from "@/store/modules/user";
+import { addOrEditTimingTask, getInspectionItemList } from "@/api/inspectionManagement/index.js";
+import { userListNoPageByTenantId } from "@/api/system/user.js";
 import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
+import InspectionItemSelector from "./InspectionItemSelector.vue";
 
-const { proxy } = getCurrentInstance()
-const emit = defineEmits()
-const userStore = useUserStore()
-const dialogVisitable = ref(false);
-const operationType = ref('add');
+const { proxy } = getCurrentInstance();
+const emit = defineEmits(["closeDia"]);
+const userStore = useUserStore();
+const visible = ref(false);
+const editing = ref(false);
+const saving = ref(false);
+const selectorVisible = ref(false);
+const formRef = ref();
 const deviceOptions = ref([]);
-const data = reactive({
-  form: {
-    taskId: undefined,
-    taskName: undefined,
-    inspector: '',
-    inspectorIds: '',
-    inspectionProject: '',
-    isEnabled: 1,
-    remarks: '',
-    frequencyType: '',
-    frequencyDetail: '',
-    week: '',
-    time: ''
-  },
-	rules: {
-		taskId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" },],
-		inspector: [{ required: true, message: "璇疯緭鍏ュ贰妫�浜�", trigger: "blur" },],
-		dateStr: [{ required: true, message: "璇烽�夋嫨鐧昏鏃堕棿", trigger: "change" }],
-		frequencyType: [{ required: true, message: "璇烽�夋嫨浠诲姟棰戠巼", trigger: "change" }],
-		frequencyDetail: [
-			{
-				required: true,
-				message: "璇烽�夋嫨鏃ユ湡",
-				trigger: "change",
-				validator: (rule, value, callback) => {
-					if (!form.value.frequencyType) {
-						callback()
-						return
-					}
-					if (form.value.frequencyType === 'WEEKLY') {
-						if (!form.value.week || !form.value.time) {
-							callback(new Error("璇烽�夋嫨鏃ユ湡鍜屾椂闂�"))
-						} else {
-							callback()
-						}
-					} else {
-						if (!value) {
-							callback(new Error("璇烽�夋嫨鏃ユ湡"))
-						} else {
-							callback()
-						}
-					}
-				}
-			}
-		],
-		week: [
-			{
-				required: true,
-				message: "璇烽�夋嫨鏄熸湡",
-				trigger: "change",
-				validator: (rule, value, callback) => {
-					if (form.value.frequencyType === 'WEEKLY' && !value) {
-						callback(new Error("璇烽�夋嫨鏄熸湡"))
-					} else {
-						callback()
-					}
-				}
-			}
-		],
-		time: [
-			{
-				required: true,
-				message: "璇烽�夋嫨鏃堕棿",
-				trigger: "change",
-				validator: (rule, value, callback) => {
-					if (form.value.frequencyType === 'WEEKLY' && !value) {
-						callback(new Error("璇烽�夋嫨鏃堕棿"))
-					} else {
-						callback()
-					}
-				}
-			}
-		]
-	}
-})
-const { form, rules } = toRefs(data)
-const userList = ref([])
-
-const loadDeviceName = async () => {
-  const { data } = await getDeviceLedger();
-  deviceOptions.value = data;
+const userList = ref([]);
+const customItems = ref([]);
+const customItemProject = ref("");
+const customItemContent = ref("");
+let defaultItemsRequestId = 0;
+const weekdays = [
+  { label: "鍛ㄤ竴", value: "MON" },
+  { label: "鍛ㄤ簩", value: "TUE" },
+  { label: "鍛ㄤ笁", value: "WED" },
+  { label: "鍛ㄥ洓", value: "THU" },
+  { label: "鍛ㄤ簲", value: "FRI" },
+  { label: "鍛ㄥ叚", value: "SAT" },
+  { label: "鍛ㄦ棩", value: "SUN" },
+];
+const blankForm = () => ({
+  id: undefined,
+  taskId: undefined,
+  taskName: "",
+  inspector: [],
+  inspectorIds: "",
+  inspectionItemIds: [],
+  inspectionItems: [],
+  isEnabled: 1,
+  remarks: "",
+  frequencyType: "",
+  frequencyDetail: "",
+  week: "",
+  time: "",
+});
+const form = reactive(blankForm());
+const rules = {
+  taskId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" }],
+  inspector: [{ required: true, message: "璇烽�夋嫨宸℃浜�", trigger: "change" }],
+  frequencyType: [{ required: true, message: "璇烽�夋嫨浠诲姟棰戠巼", trigger: "change" }],
+  frequencyDetail: [
+    {
+      validator: (_, value, callback) => {
+        const valid =
+          form.frequencyType === "DAILY"
+            ? !!value
+            : form.frequencyType === "WEEKLY"
+            ? !!form.week && !!form.time
+            : form.frequencyType === "MONTHLY"
+            ? !!form.frequencyDetail
+            : form.frequencyType === "QUARTERLY"
+            ? !!form.frequencyDetail
+            : false;
+        valid ? callback() : callback(new Error("璇烽�夋嫨宸℃鎵ц鏃ユ湡鍜屾椂闂�"));
+      },
+      trigger: "change",
+    },
+  ],
+  inspectionItemIds: [
+    {
+      validator: (_, value, callback) =>
+        form.inspectionItems.length || customItems.value.length
+          ? callback()
+          : callback(new Error("璇烽�夋嫨鎴栨坊鍔犺嚦灏戜竴涓贰妫�鍐呭")),
+      trigger: "change",
+    },
+  ],
 };
+const displayItems = computed(() => [
+  ...form.inspectionItems.map((item) => ({ ...item, key: `item-${item.id}` })),
+  ...customItems.value.map((item) => ({ ...item, key: item.key, isCustom: true })),
+]);
+const frequencyDetail = computed(() => {
+  if (form.frequencyType === "WEEKLY") return `${form.week},${form.time}`;
+  if (form.frequencyType === "MONTHLY") return form.frequencyDetail;
+  return form.frequencyDetail;
+});
+const selectionHint = computed(() => {
+  if (!form.taskId || !form.frequencyType)
+    return "璇峰厛閫夋嫨璁惧鍜岄鐜囷紝鍖归厤鐨勮澶囧贰妫�鍐呭灏嗚嚜鍔ㄥ甫鍑�";
+  return displayItems.value.length
+    ? `宸查�� ${displayItems.value.length} 椤癸紝鍙户缁坊鍔犳湰浠诲姟涓撶敤鍐呭鎴栭�夋嫨閫氱敤鍐呭`
+    : "璇ヨ澶囧拰棰戠巼鏆傛棤榛樿宸℃鍐呭锛屽彲鎵嬪姩娣诲姞鎴栭�夋嫨閫氱敤鍐呭";
+});
 
-const setDeviceModel = (id) => {
-  const option = deviceOptions.value.find((item) => item.id === id);
-  if (option) {
-    form.value.taskName = option.deviceName;
-  }
-}
-
-// 鎵撳紑寮规
 const openDialog = async (type, row) => {
-  dialogVisitable.value = true
-  operationType.value = type
-  
-  // 閲嶇疆琛ㄥ崟
-  resetForm();
-  
-  // 鍔犺浇鐢ㄦ埛鍒楄〃
-  userListNoPageByTenantId().then((res) => {
-    userList.value = res.data;
-  });
-  
-  // 鍔犺浇璁惧鍒楄〃
-  await loadDeviceName();
-  
-  if (type === 'edit' && row) {
-    form.value = {...row}
-    form.value.inspector = form.value.inspectorIds.split(',').map(Number)
-    
-    // 澶勭悊WEEKLY棰戠巼鐨勫洖鏄撅細灏唂requencyDetail鎷嗗垎涓簑eek鍜宼ime
-    if (form.value.frequencyType === 'WEEKLY' && form.value.frequencyDetail) {
-      const parts = form.value.frequencyDetail.split(',')
-      form.value.week = parts[0] || ''
-      form.value.time = parts[1] || ''
-      form.value.frequencyDetail = ''
-    }
-    
-    // 濡傛灉鏈夎澶嘔D锛岃嚜鍔ㄨ缃澶囦俊鎭�
-    if (form.value.taskId) {
-      setDeviceModel(form.value.taskId);
+  editing.value = type === "edit";
+  Object.assign(form, blankForm());
+  customItems.value = [];
+  customItemProject.value = "";
+  customItemContent.value = "";
+  await Promise.all([
+    getDeviceLedger().then(({ data }) => {
+      deviceOptions.value = data || [];
+    }),
+    userListNoPageByTenantId().then(({ data }) => {
+      userList.value = data || [];
+    }),
+  ]);
+  if (editing.value && row) {
+    Object.assign(form, blankForm(), row);
+    form.inspector = String(row.inspectorIds || "")
+      .split(",")
+      .filter(Boolean)
+      .map(Number);
+    const taskItems = row.inspectionItems || [];
+    form.inspectionItems = taskItems
+      .filter((item) => item.inspectionItemId != null)
+      .map((item) => ({ ...item, id: item.inspectionItemId }));
+    customItems.value = taskItems
+      .filter((item) => item.inspectionItemId == null)
+      .map((item, index) => ({ ...item, key: `custom-saved-${index}` }));
+    if (form.frequencyType === "WEEKLY" && form.frequencyDetail) {
+      [form.week, form.time] = form.frequencyDetail.split(",");
     }
   }
-}
+  visible.value = true;
+};
+const setDeviceModel = (id) => {
+  const device = deviceOptions.value.find((item) => item.id === id);
+  if (device) form.taskName = device.deviceName;
+};
+const syncInspectionItems = (items) => {
+  form.inspectionItems = items.map((item) => ({ ...item, id: item.inspectionItemId || item.id }));
+  form.inspectionItemIds = form.inspectionItems.map((item) => item.id);
+};
+const clearInspectionItems = () => syncInspectionItems([]);
+const loadDefaultInspectionItems = async () => {
+  const requestId = ++defaultItemsRequestId;
+  const deviceLedgerId = form.taskId;
+  const frequencyType = form.frequencyType;
+  clearInspectionItems();
+  if (!deviceLedgerId || !frequencyType) return;
 
-// 鍏抽棴瀵硅瘽妗�
-const cancel = () => {
-  resetForm()
-  dialogVisitable.value = false
-  emit('closeDia')
-}
-
-// 閲嶇疆琛ㄥ崟鍑芥暟
-const resetForm = () => {
-  if (proxy.$refs.formRef) {
-    proxy.$refs.formRef.resetFields()
-  }
-  // 閲嶇疆琛ㄥ崟鏁版嵁纭繚璁惧淇℃伅姝g‘閲嶇疆
-  form.value = {
-    taskId: undefined,
-    taskName: undefined,
-    inspector: '',
-    inspectorIds: '',
-    inspectionProject: '',
-    isEnabled: 1,
-    remarks: '',
-    frequencyType: '',
-    frequencyDetail: '',
-    week: '',
-    time: ''
-  }
-}
-
-// 鎻愪氦琛ㄥ崟
-const submitForm = () => {
-  proxy.$refs["formRef"].validate(async valid => {
-    if (valid) {
-      try {
-        form.value.inspectorIds = form.value.inspector.join(',')
-        delete form.value.inspector
-        
-        if (form.value.frequencyType === 'WEEKLY') {
-          let frequencyDetail = ''
-          frequencyDetail = form.value.week + ',' + form.value.time
-          form.value.frequencyDetail = frequencyDetail
-        }
-        
-        let res = await userStore.getInfo()
-        form.value.registrantId = res.user.userId
-        
-        await addOrEditTimingTask(form.value)
-        cancel()
-        proxy.$modal.msgSuccess('鎻愪氦鎴愬姛')
-      } catch (error) {
-        proxy.$modal.msgError('鎻愪氦澶辫触锛岃閲嶈瘯')
-      }
+  try {
+    const { code, data } = await getInspectionItemList({
+      deviceLedgerId,
+      frequencyType,
+      isActive: 1,
+    });
+    if (
+      requestId !== defaultItemsRequestId ||
+      deviceLedgerId !== form.taskId ||
+      frequencyType !== form.frequencyType
+    )
+      return;
+    if (code === 200) syncInspectionItems(data || []);
+  } catch (error) {
+    if (requestId === defaultItemsRequestId) {
+      proxy.$modal.msgError(error?.message || "鍔犺浇榛樿宸℃鍐呭澶辫触");
     }
-  })
-}
-defineExpose({ openDialog })
+  }
+};
+const changeDevice = (id) => {
+  setDeviceModel(id);
+  loadDefaultInspectionItems();
+};
+const handleFrequencyChange = () => loadDefaultInspectionItems();
+const setSelectedItems = (items) => {
+  syncInspectionItems(items);
+  formRef.value?.validateField("inspectionItemIds");
+};
+const addCustomItem = () => {
+  const itemProject = customItemProject.value.trim();
+  const itemContent = customItemContent.value.trim();
+  if (!itemProject || !itemContent) return;
+  if (displayItems.value.some((item) => item.itemProject === itemProject)) {
+    proxy.$modal.msgWarning("宸插瓨鍦ㄧ浉鍚岀殑宸℃椤圭洰");
+    return;
+  }
+  customItems.value = [
+    ...customItems.value,
+    { key: `custom-${Date.now()}`, itemProject, itemContent },
+  ];
+  customItemProject.value = "";
+  customItemContent.value = "";
+  formRef.value?.validateField("inspectionItemIds");
+};
+const removeTaskItem = (item) => {
+  if (item.isCustom)
+    customItems.value = customItems.value.filter((custom) => custom.key !== item.key);
+  else
+    form.inspectionItems = form.inspectionItems.filter(
+      (selected) => String(selected.id) !== String(item.id)
+    );
+  form.inspectionItemIds = form.inspectionItems.map((item) => item.id);
+  formRef.value?.validateField("inspectionItemIds");
+};
+const reset = () => {
+  defaultItemsRequestId += 1;
+  Object.assign(form, blankForm());
+  customItems.value = [];
+  customItemProject.value = "";
+  customItemContent.value = "";
+  formRef.value?.clearValidate();
+};
+const submit = async () => {
+  const valid = await formRef.value
+    ?.validate()
+    .then(() => true)
+    .catch(() => false);
+  if (!valid) return;
+  saving.value = true;
+  try {
+    const userInfo = await userStore.getInfo();
+    const payload = {
+      ...form,
+      inspectorIds: form.inspector.join(","),
+      frequencyDetail: frequencyDetail.value,
+      registrantId: userInfo.user.userId,
+      inspectionItemIds: form.inspectionItems.map((item) => item.id),
+      customItems: customItems.value.map((item) => ({
+        itemProject: item.itemProject,
+        itemContent: item.itemContent,
+      })),
+    };
+    delete payload.inspector;
+    delete payload.inspectionItems;
+    delete payload.week;
+    delete payload.time;
+    await addOrEditTimingTask(payload);
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    visible.value = false;
+    emit("closeDia");
+  } catch (error) {
+    proxy.$modal.msgError(error?.message || "鎻愪氦澶辫触锛岃閲嶈瘯");
+  } finally {
+    saving.value = false;
+  }
+};
+defineExpose({ openDialog });
 </script>
 
 <style scoped>
-
-</style>
\ No newline at end of file
+.frequency-fields {
+  display: flex;
+  width: 100%;
+  gap: 8px;
+}
+.items-field {
+  width: 100%;
+}
+.items-toolbar {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  margin-bottom: 10px;
+}
+.custom-input {
+  display: flex;
+  gap: 8px;
+  margin-bottom: 10px;
+}
+.custom-input .el-input:first-child {
+  flex: 0 0 30%;
+}
+.custom-input .el-input:nth-child(2) {
+  flex: 1;
+  min-width: 0;
+}
+.muted {
+  color: #909399;
+  font-size: 13px;
+}
+.selected-items {
+  max-height: 250px;
+  overflow-y: auto;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+}
+.selected-item {
+  padding: 10px 12px;
+  border-bottom: 1px solid #ebeef5;
+}
+.selected-item:last-child {
+  border-bottom: 0;
+}
+.selected-item-title {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  color: #303133;
+}
+.selected-item-content {
+  margin-top: 6px;
+  color: #606266;
+  white-space: pre-wrap;
+  overflow-wrap: anywhere;
+}
+</style>
diff --git a/src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue b/src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue
index 481ea85..de550dfb 100644
--- a/src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue
+++ b/src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue
@@ -1,27 +1,29 @@
 <template>
-  <FormDialog v-model="dialogVisible"
-              :title="operationType === 'view' ? '宸℃璁板綍璇︽儏' : '涓婁紶宸℃璁板綍'"
-              width="980px"
-              :operation-type="operationType"
-              @close="handleClose"
-              @cancel="handleClose">
+  <FormDialog
+    v-model="dialogVisible"
+    :title="operationType === 'view' ? '宸℃璁板綍璇︽儏' : '涓婁紶宸℃璁板綍'"
+    width="980px"
+    :operation-type="operationType"
+    @close="handleClose"
+    @cancel="handleClose"
+  >
     <main class="upload-content">
-      <el-card v-if="taskInfo"
-               class="section-card">
-        <el-descriptions :column="2"
-                         border>
+      <el-card v-if="taskInfo" class="section-card">
+        <el-descriptions :column="2" border>
           <el-descriptions-item label="宸℃浠诲姟鍚嶇О">
             {{ taskInfo.taskName || "-" }}
           </el-descriptions-item>
           <el-descriptions-item label="宸℃椤圭洰">
-            {{ taskInfo.inspectionProject || "-" }}
+            {{ inspectionProjectSummary || "-" }}
           </el-descriptions-item>
           <el-descriptions-item label="鎵ц宸℃浜�">
             <template v-if="formattedInspector && formattedInspector.length">
-              <el-tag v-for="tag in formattedInspector"
-                      :key="tag"
-                      size="small"
-                      style="margin-right: 4px">
+              <el-tag
+                v-for="tag in formattedInspector"
+                :key="tag"
+                size="small"
+                style="margin-right: 4px"
+              >
                 {{ tag }}
               </el-tag>
             </template>
@@ -44,47 +46,66 @@
           </el-descriptions-item>
         </el-descriptions>
       </el-card>
+      <el-card v-if="inspectionItems.length" class="section-card inspection-items-card">
+        <div class="section-heading">
+          <h3>宸℃鍐呭</h3>
+          <span>宸插畬鎴� {{ completedItemIds.length }} / {{ inspectionItems.length }} 椤�</span>
+        </div>
+        <div v-for="(item, index) in inspectionItems" :key="item.id" class="inspection-item-row">
+          <div class="inspection-item-copy">
+            <div class="inspection-item-title">{{ index + 1 }}. {{ item.itemProject }}</div>
+            <div class="inspection-item-content">{{ item.itemContent }}</div>
+          </div>
+          <el-checkbox
+            :model-value="isItemCompleted(item)"
+            :disabled="operationType === 'view'"
+            @change="(checked) => toggleItem(item, checked)"
+          >
+            {{ isItemCompleted(item) ? "宸插畬鎴�" : "鏈畬鎴�" }}
+          </el-checkbox>
+        </div>
+      </el-card>
       <el-card class="section-card">
         <h3>宸℃鐘舵��</h3>
-        <el-radio-group v-model="hasException"
-                        :disabled="operationType === 'view'">
+        <el-radio-group v-model="hasException" :disabled="operationType === 'view'">
           <el-radio-button :value="false">姝e父</el-radio-button>
           <el-radio-button :value="true">瀛樺湪寮傚父</el-radio-button>
         </el-radio-group>
       </el-card>
-      <el-card v-if="hasException === true"
-               class="section-card">
+      <el-card v-if="hasException === true" class="section-card">
         <h3>寮傚父鎻忚堪</h3>
-        <el-input v-model="abnormalDescription"
-                  type="textarea"
-                  maxlength="500"
-                  show-word-limit
-                  :rows="4"
-                  :disabled="operationType === 'view'"
-                  placeholder="璇锋弿杩板紓甯告儏鍐�..." />
+        <el-input
+          v-model="abnormalDescription"
+          type="textarea"
+          maxlength="500"
+          show-word-limit
+          :rows="4"
+          :disabled="operationType === 'view'"
+          placeholder="璇锋弿杩板紓甯告儏鍐�..."
+        />
       </el-card>
-      <el-card v-if="hasException === true"
-               class="section-card">
-        <div class="upload-buttons"
-             v-if="operationType !== 'view'">
-          <el-upload :show-file-list="false"
-                     :http-request="uploadFile"
-                     :disabled="beforeModelValue.length >= uploadConfig.limit || uploading"
-                     accept="image/*">
-            <el-button type="primary"
-                       :loading="uploading">
+      <el-card v-if="hasException === true" class="section-card">
+        <div class="upload-buttons" v-if="operationType !== 'view'">
+          <el-upload
+            :show-file-list="false"
+            :http-request="uploadFile"
+            :disabled="beforeModelValue.length >= uploadConfig.limit || uploading"
+            accept="image/*"
+          >
+            <el-button type="primary" :loading="uploading">
               <el-icon>
                 <Camera />
               </el-icon>
               閫夋嫨鍥剧墖
             </el-button>
           </el-upload>
-          <el-upload :show-file-list="false"
-                     :http-request="uploadFile"
-                     :disabled="beforeModelValue.length >= uploadConfig.limit || uploading"
-                     accept="video/*">
-            <el-button type="success"
-                       :loading="uploading">
+          <el-upload
+            :show-file-list="false"
+            :http-request="uploadFile"
+            :disabled="beforeModelValue.length >= uploadConfig.limit || uploading"
+            accept="video/*"
+          >
+            <el-button type="success" :loading="uploading">
               <el-icon>
                 <VideoCamera />
               </el-icon>
@@ -92,35 +113,36 @@
             </el-button>
           </el-upload>
         </div>
-        <el-progress v-if="uploading"
-                     :percentage="uploadProgress"
-                     class="upload-progress" />
-        <div v-if="beforeModelValue.length"
-             class="file-list">
-          <div v-for="(file, index) in beforeModelValue"
-               :key="file.uid || file.id || index"
-               class="file-item">
+        <el-progress v-if="uploading" :percentage="uploadProgress" class="upload-progress" />
+        <div v-if="beforeModelValue.length" class="file-list">
+          <div
+            v-for="(file, index) in beforeModelValue"
+            :key="file.uid || file.id || index"
+            class="file-item"
+          >
             <div class="file-preview-container">
-              <el-image v-if="file.type === 'image' || !file.type"
-                        :src="file.url || file.tempFilePath || file.path || file.downloadUrl"
-                        fit="cover"
-                        class="file-preview"
-                        :preview-src-list="[file.url || file.tempFilePath || file.path || file.downloadUrl]"
-                        preview-teleported />
-              <div v-else
-                   class="video-preview"
-                   @click="previewVideo(file)">
+              <el-image
+                v-if="file.type === 'image' || !file.type"
+                :src="file.url || file.tempFilePath || file.path || file.downloadUrl"
+                fit="cover"
+                class="file-preview"
+                :preview-src-list="[file.url || file.tempFilePath || file.path || file.downloadUrl]"
+                preview-teleported
+              />
+              <div v-else class="video-preview" @click="previewVideo(file)">
                 <el-icon>
                   <VideoCamera />
                 </el-icon>
                 <span>瑙嗛</span>
               </div>
-              <el-button class="delete-btn"
-                         type="danger"
-                         circle
-                         size="small"
-                         v-if="operationType !== 'view'"
-                         @click="removeFile(index)">
+              <el-button
+                class="delete-btn"
+                type="danger"
+                circle
+                size="small"
+                v-if="operationType !== 'view'"
+                @click="removeFile(index)"
+              >
                 <el-icon>
                   <Close />
                 </el-icon>
@@ -134,559 +156,614 @@
             </div>
           </div>
         </div>
-        <el-empty v-else
-                  :description="operationType === 'view' ? '鏆傛棤寮傚父鐓х墖鎴栬棰�' : '璇烽�夋嫨瑕佷笂浼犵殑宸℃鍥剧墖鎴栬棰�'" />
+        <el-empty
+          v-else
+          :description="
+            operationType === 'view' ? '鏆傛棤寮傚父鐓х墖鎴栬棰�' : '璇烽�夋嫨瑕佷笂浼犵殑宸℃鍥剧墖鎴栬棰�'
+          "
+        />
       </el-card>
-      <el-result v-if="hasException === false"
-                 icon="success"
-                 title="璁惧杩愯姝e父"
-                 :sub-title="operationType === 'view' ? '' : '鏃犻渶涓婁紶鐓х墖'" />
+      <el-result
+        v-if="hasException === false"
+        icon="success"
+        title="璁惧杩愯姝e父"
+        :sub-title="operationType === 'view' ? '' : '鏃犻渶涓婁紶鐓х墖'"
+      />
     </main>
     <template #footer>
       <footer class="footer-buttons">
-        <el-button type="primary"
-                   v-if="operationType !== 'view'"
-                   @click="submitUpload">鎻愪氦</el-button>
-        <el-button v-if="hasException === true && operationType !== 'view'"
-                   type="warning"
-                   @click="goToRepair">
+        <el-button type="primary" v-if="operationType !== 'view'" @click="submitUpload"
+          >鎻愪氦</el-button
+        >
+        <el-button
+          v-if="hasException === true && operationType !== 'view'"
+          type="warning"
+          @click="goToRepair"
+        >
           鏂板鎶ヤ慨
         </el-button>
-        <el-button @click="handleClose">{{ operationType === 'view' ? '鍏抽棴' : '鍙栨秷' }}</el-button>
+        <el-button @click="handleClose">{{ operationType === "view" ? "鍏抽棴" : "鍙栨秷" }}</el-button>
       </footer>
     </template>
   </FormDialog>
-  <el-dialog v-model="showVideoDialog"
-             :title="currentVideoFile?.originalFilename || currentVideoFile?.name || '瑙嗛棰勮'"
-             width="720px">
-    <video v-if="currentVideoFile"
-           :src="currentVideoFile.url || currentVideoFile.downloadUrl"
-           class="video-player"
-           controls
-           autoplay />
+  <el-dialog
+    v-model="showVideoDialog"
+    :title="currentVideoFile?.originalFilename || currentVideoFile?.name || '瑙嗛棰勮'"
+    width="720px"
+  >
+    <video
+      v-if="currentVideoFile"
+      :src="currentVideoFile.url || currentVideoFile.downloadUrl"
+      class="video-player"
+      controls
+      autoplay
+    />
   </el-dialog>
 </template>
 
 <script setup>
-  import { computed, ref } from "vue";
-  import { useRouter } from "vue-router";
-  import { ElLoading, ElMessage, ElMessageBox } from "element-plus";
-  import { Camera, Close, VideoCamera } from "@element-plus/icons-vue";
-  import axios from "axios";
-  import dayjs from "dayjs";
-  import FormDialog from "@/components/Dialog/FormDialog.vue";
-  import { uploadInspectionTask } from "@/api/inspectionManagement/index.js";
-  import { getToken } from "@/utils/auth";
+import { computed, ref } from "vue";
+import { useRouter } from "vue-router";
+import { ElLoading, ElMessage, ElMessageBox } from "element-plus";
+import { Camera, Close, VideoCamera } from "@element-plus/icons-vue";
+import axios from "axios";
+import dayjs from "dayjs";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { uploadInspectionTask } from "@/api/inspectionManagement/index.js";
+import { getToken } from "@/utils/auth";
 
-  const emit = defineEmits(["closeDia", "success"]);
-  const router = useRouter();
+const emit = defineEmits(["closeDia", "success"]);
+const router = useRouter();
 
-  const dialogVisible = ref(false);
-  const taskInfo = ref(null);
-  const uploading = ref(false);
-  const uploadProgress = ref(0);
-  const operationType = ref("add"); // add, view
+const dialogVisible = ref(false);
+const taskInfo = ref(null);
+const uploading = ref(false);
+const uploadProgress = ref(0);
+const operationType = ref("add"); // add, view
 
-  const beforeModelValue = ref([]);
+const beforeModelValue = ref([]);
+const inspectionItems = ref([]);
+const completedItemIds = ref([]);
+const inspectionProjectSummary = computed(() =>
+  [...new Set(inspectionItems.value.map((item) => item.itemProject).filter(Boolean))].join("銆�")
+);
 
-  const formattedInspector = computed(() => {
-    if (!taskInfo.value?.inspector) return [];
-    if (Array.isArray(taskInfo.value.inspector)) return taskInfo.value.inspector;
-    if (typeof taskInfo.value.inspector === "string") {
-      return taskInfo.value.inspector
-        .split(",")
-        .map(s => s.trim())
-        .filter(s => s);
+const formattedInspector = computed(() => {
+  if (!taskInfo.value?.inspector) return [];
+  if (Array.isArray(taskInfo.value.inspector)) return taskInfo.value.inspector;
+  if (typeof taskInfo.value.inspector === "string") {
+    return taskInfo.value.inspector
+      .split(",")
+      .map((s) => s.trim())
+      .filter((s) => s);
+  }
+  return [taskInfo.value.inspector];
+});
+
+const formatFrequencyType = (type) => {
+  const mapping = {
+    DAILY: "姣忔棩",
+    WEEKLY: "姣忓懆",
+    MONTHLY: "姣忔湀",
+    QUARTERLY: "瀛e害",
+  };
+  return mapping[type] || type;
+};
+
+const formatFrequencyDetail = (detail) => {
+  if (typeof detail !== "string") return detail;
+  const replacements = {
+    MON: "鍛ㄤ竴",
+    TUE: "鍛ㄤ簩",
+    WED: "鍛ㄤ笁",
+    THU: "鍛ㄥ洓",
+    FRI: "鍛ㄤ簲",
+    SAT: "鍛ㄥ叚",
+    SUN: "鍛ㄦ棩",
+  };
+  return detail.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, (match) => replacements[match]);
+};
+
+const formatDateTime = (date) => {
+  if (!date) return "-";
+  return dayjs(date).format("YYYY-MM-DD");
+};
+
+const hasException = ref(null);
+const abnormalDescription = ref("");
+
+const showVideoDialog = ref(false);
+const currentVideoFile = ref(null);
+
+const uploadConfig = {
+  action: "/common/upload",
+  limit: 10,
+  fileSize: 50,
+  fileType: ["jpg", "jpeg", "png", "mp4", "mov"],
+};
+
+const uploadFileUrl = computed(() => `${import.meta.env.VITE_APP_BASE_API}${uploadConfig.action}`);
+
+const processFileUrl = (fileUrl) => {
+  if (!fileUrl) return "";
+
+  let currentUrl = String(fileUrl);
+  if (currentUrl.includes("\\")) {
+    const uploadsIndex = currentUrl.toLowerCase().indexOf("uploads");
+    if (uploadsIndex > -1) {
+      currentUrl = `/${currentUrl.substring(uploadsIndex).replace(/\\/g, "/")}`;
+    } else {
+      const fileName = currentUrl.split("\\").pop();
+      currentUrl = `/uploads/${fileName}`;
     }
-    return [taskInfo.value.inspector];
+  }
+
+  if (currentUrl && !currentUrl.startsWith("http")) {
+    if (!currentUrl.startsWith("/")) {
+      currentUrl = `/${currentUrl}`;
+    }
+    currentUrl = __BASE_API__ + currentUrl;
+  }
+
+  return currentUrl;
+};
+
+const normalizeList = (list, fileType) => {
+  if (!Array.isArray(list)) return [];
+
+  return list.filter(Boolean).map((item) => {
+    let currentType = item.type;
+    if (!currentType && item.contentType) {
+      currentType = item.contentType.startsWith("video") ? "video" : "image";
+    } else if (!currentType) {
+      currentType = fileType || "image";
+    }
+
+    return {
+      ...item,
+      url: processFileUrl(item.url || item.previewURL || item.downloadUrl || item.path || ""),
+      downloadUrl: processFileUrl(
+        item.downloadUrl || item.url || item.previewURL || item.path || ""
+      ),
+      name: item.name || item.originalFilename || item.bucketFilename,
+      tempId: item.tempId || item.id || item.tempFileId,
+      tempFileId: item.tempFileId || item.tempId || item.id,
+      size: item.size || item.byteSize || 0,
+      type: currentType,
+      status: "success",
+      uid: item.uid || `${Date.now()}-${Math.random()}`,
+    };
   });
+};
 
-  const formatFrequencyType = type => {
-    const mapping = {
-      DAILY: "姣忔棩",
-      WEEKLY: "姣忓懆",
-      MONTHLY: "姣忔湀",
-      QUARTERLY: "瀛e害",
-    };
-    return mapping[type] || type;
-  };
+const resetState = () => {
+  taskInfo.value = null;
+  beforeModelValue.value = [];
+  inspectionItems.value = [];
+  completedItemIds.value = [];
+  hasException.value = null;
+  abnormalDescription.value = "";
+  uploading.value = false;
+  uploadProgress.value = 0;
+  showVideoDialog.value = false;
+  currentVideoFile.value = null;
+  operationType.value = "add";
+};
 
-  const formatFrequencyDetail = detail => {
-    if (typeof detail !== "string") return detail;
-    const replacements = {
-      MON: "鍛ㄤ竴",
-      TUE: "鍛ㄤ簩",
-      WED: "鍛ㄤ笁",
-      THU: "鍛ㄥ洓",
-      FRI: "鍛ㄤ簲",
-      SAT: "鍛ㄥ叚",
-      SUN: "鍛ㄦ棩",
-    };
-    return detail.replace(
-      /MON|TUE|WED|THU|FRI|SAT|SUN/g,
-      match => replacements[match]
-    );
-  };
+const openDialog = (type, row) => {
+  operationType.value = type || "add";
+  const raw = JSON.parse(JSON.stringify(row?.__raw || row || {}));
+  taskInfo.value = raw;
+  inspectionItems.value = Array.isArray(raw.inspectionItems) ? raw.inspectionItems : [];
+  completedItemIds.value = inspectionItems.value
+    .filter((item) => Number(item.itemStatus) === 1)
+    .map((item) => item.id);
 
-  const formatDateTime = date => {
-    if (!date) return "-";
-    return dayjs(date).format("YYYY-MM-DD");
-  };
-
-  const hasException = ref(null);
-  const abnormalDescription = ref("");
-
-  const showVideoDialog = ref(false);
-  const currentVideoFile = ref(null);
-
-  const uploadConfig = {
-    action: "/common/upload",
-    limit: 10,
-    fileSize: 50,
-    fileType: ["jpg", "jpeg", "png", "mp4", "mov"],
-  };
-
-  const uploadFileUrl = computed(
-    () => `${import.meta.env.VITE_APP_BASE_API}${uploadConfig.action}`
+  beforeModelValue.value = normalizeList(
+    raw.commonFileListBeforeVO || raw.commonFileListBefore || [],
+    "image"
   );
 
-  const processFileUrl = fileUrl => {
-    if (!fileUrl) return "";
+  abnormalDescription.value = raw.abnormalDescription || "";
 
-    let currentUrl = String(fileUrl);
-    if (currentUrl.includes("\\")) {
-      const uploadsIndex = currentUrl.toLowerCase().indexOf("uploads");
-      if (uploadsIndex > -1) {
-        currentUrl = `/${currentUrl.substring(uploadsIndex).replace(/\\/g, "/")}`;
-      } else {
-        const fileName = currentUrl.split("\\").pop();
-        currentUrl = `/uploads/${fileName}`;
-      }
-    }
-
-    if (currentUrl && !currentUrl.startsWith("http")) {
-      if (!currentUrl.startsWith("/")) {
-        currentUrl = `/${currentUrl}`;
-      }
-      currentUrl = __BASE_API__ + currentUrl;
-    }
-
-    return currentUrl;
-  };
-
-  const normalizeList = (list, fileType) => {
-    if (!Array.isArray(list)) return [];
-
-    return list.filter(Boolean).map(item => {
-      let currentType = item.type;
-      if (!currentType && item.contentType) {
-        currentType = item.contentType.startsWith("video") ? "video" : "image";
-      } else if (!currentType) {
-        currentType = fileType || "image";
-      }
-
-      return {
-        ...item,
-        url: processFileUrl(
-          item.url || item.previewURL || item.downloadUrl || item.path || ""
-        ),
-        downloadUrl: processFileUrl(
-          item.downloadUrl || item.url || item.previewURL || item.path || ""
-        ),
-        name: item.name || item.originalFilename || item.bucketFilename,
-        tempId: item.tempId || item.id || item.tempFileId,
-        tempFileId: item.tempFileId || item.tempId || item.id,
-        size: item.size || item.byteSize || 0,
-        type: currentType,
-        status: "success",
-        uid: item.uid || `${Date.now()}-${Math.random()}`,
-      };
-    });
-  };
-
-  const resetState = () => {
-    taskInfo.value = null;
-    beforeModelValue.value = [];
+  if (raw.hasException !== undefined && raw.hasException !== null) {
+    hasException.value = raw.hasException;
+  } else if (raw.inspectionResult !== undefined && raw.inspectionResult !== null) {
+    hasException.value = String(raw.inspectionResult) === "0";
+  } else {
     hasException.value = null;
-    abnormalDescription.value = "";
-    uploading.value = false;
-    uploadProgress.value = 0;
-    showVideoDialog.value = false;
-    currentVideoFile.value = null;
-    operationType.value = "add";
-  };
+  }
 
-  const openDialog = (type, row) => {
-    operationType.value = type || "add";
-    const raw = JSON.parse(JSON.stringify(row?.__raw || row || {}));
-    taskInfo.value = raw;
+  if (hasException.value !== true && beforeModelValue.value.length) {
+    hasException.value = true;
+  }
 
-    beforeModelValue.value = normalizeList(
-      raw.commonFileListBeforeVO || raw.commonFileListBefore || [],
-      "image"
+  dialogVisible.value = true;
+};
+
+const isItemCompleted = (item) => completedItemIds.value.includes(item.id);
+const toggleItem = (item, checked) => {
+  const completed = new Set(completedItemIds.value);
+  if (checked) completed.add(item.id);
+  else completed.delete(item.id);
+  completedItemIds.value = [...completed];
+};
+
+const handleClose = () => {
+  dialogVisible.value = false;
+  resetState();
+  emit("closeDia");
+};
+
+const previewVideo = (file) => {
+  currentVideoFile.value = file;
+  showVideoDialog.value = true;
+};
+
+const uploadFile = async (uploadRequest) => {
+  const rawFile = uploadRequest.file;
+
+  if (beforeModelValue.value.length >= uploadConfig.limit) {
+    ElMessage.warning(`鏈�澶氬彧鑳介�夋嫨${uploadConfig.limit}涓枃浠禶);
+    return;
+  }
+
+  const ext = rawFile.name.split(".").pop()?.toLowerCase();
+  if (!uploadConfig.fileType.includes(ext)) {
+    ElMessage.warning(`鏂囦欢鏍煎紡涓嶆敮鎸侊紝璇蜂笂浼� ${uploadConfig.fileType.join("/")} 鏍煎紡`);
+    return;
+  }
+
+  if (rawFile.size > uploadConfig.fileSize * 1024 * 1024) {
+    ElMessage.warning(`鏂囦欢澶у皬涓嶈兘瓒呰繃 ${uploadConfig.fileSize}MB`);
+    return;
+  }
+
+  const token = getToken();
+  if (!token) {
+    ElMessage.warning("鐢ㄦ埛鏈櫥褰�");
+    return;
+  }
+
+  const formData = new FormData();
+  formData.append("files", rawFile);
+  formData.append("type", 10); // 鐢熶骇鍓嶅浐瀹氫负10
+
+  uploading.value = true;
+  uploadProgress.value = 0;
+
+  try {
+    const { data } = await axios.post(uploadFileUrl.value, formData, {
+      headers: {
+        Authorization: `Bearer ${token}`,
+        "Content-Type": "multipart/form-data",
+      },
+      onUploadProgress: (event) => {
+        if (event.total) {
+          uploadProgress.value = Math.round((event.loaded / event.total) * 100);
+        }
+      },
+    });
+
+    if (data.code !== 200) {
+      ElMessage.error(data.msg || "涓婁紶澶辫触");
+      return;
+    }
+
+    const resultData = Array.isArray(data.data) ? data.data[0] : data.data;
+    const finalUrl = processFileUrl(
+      resultData.url || resultData.previewURL || resultData.downloadUrl || ""
     );
+    const finalName = resultData.name || resultData.originalFilename || resultData.bucketFilename;
+    const finalId = resultData.tempId || resultData.id || resultData.tempFileId;
 
-    abnormalDescription.value = raw.abnormalDescription || "";
+    const uploadedFile = {
+      ...resultData,
+      url: finalUrl,
+      downloadUrl: finalUrl,
+      name: finalName,
+      tempId: finalId,
+      tempFileId: resultData.tempFileId || finalId,
+      size: rawFile.size || resultData.size || resultData.byteSize || 0,
+      type: rawFile.type?.startsWith("video") ? "video" : "image",
+      status: "success",
+      uid: `${Date.now()}-${Math.random()}`,
+    };
 
-    if (raw.hasException !== undefined && raw.hasException !== null) {
-      hasException.value = raw.hasException;
-    } else if (
-      raw.inspectionResult !== undefined &&
-      raw.inspectionResult !== null
-    ) {
-      hasException.value = String(raw.inspectionResult) === "0";
-    } else {
-      hasException.value = null;
-    }
+    beforeModelValue.value.push(uploadedFile);
+    ElMessage.success("涓婁紶鎴愬姛");
+  } catch (error) {
+    ElMessage.error(error?.message || "涓婁紶澶辫触");
+  } finally {
+    uploading.value = false;
+  }
+};
 
-    if (hasException.value !== true && beforeModelValue.value.length) {
-      hasException.value = true;
-    }
+const buildFileItem = (item) => ({
+  id: item?.id,
+  tempId: item?.tempId,
+  tempFileId: item?.tempFileId,
+  url: item?.downloadUrl || item?.url || "",
+  downloadUrl: item?.downloadUrl || item?.url || "",
+  name: item?.name,
+  bucketFilename: item?.bucketFilename || item?.name,
+  originalFilename: item?.originalFilename || item?.name,
+  size: item?.size || 0,
+  byteSize: item?.byteSize || item?.size || 0,
+  contentType: item?.contentType || "",
+  type: item?.type,
+});
 
-    dialogVisible.value = true;
-  };
+const submitUpload = async () => {
+  if (hasException.value === null) {
+    ElMessage.warning("璇烽�夋嫨宸℃鐘舵��");
+    return;
+  }
 
-  const handleClose = () => {
-    dialogVisible.value = false;
-    resetState();
-    emit("closeDia");
-  };
+  if (hasException.value === true) {
+    const totalFiles = beforeModelValue.value.length;
 
-  const previewVideo = file => {
-    currentVideoFile.value = file;
-    showVideoDialog.value = true;
-  };
-
-  const uploadFile = async uploadRequest => {
-    const rawFile = uploadRequest.file;
-
-    if (beforeModelValue.value.length >= uploadConfig.limit) {
-      ElMessage.warning(`鏈�澶氬彧鑳介�夋嫨${uploadConfig.limit}涓枃浠禶);
+    if (!totalFiles) {
+      ElMessage.warning("璇蜂笂浼犲紓甯哥収鐗囨垨瑙嗛");
       return;
     }
 
-    const ext = rawFile.name.split(".").pop()?.toLowerCase();
-    if (!uploadConfig.fileType.includes(ext)) {
-      ElMessage.warning(
-        `鏂囦欢鏍煎紡涓嶆敮鎸侊紝璇蜂笂浼� ${uploadConfig.fileType.join("/")} 鏍煎紡`
-      );
+    if (!abnormalDescription.value.trim()) {
+      ElMessage.warning("璇峰~鍐欏紓甯告弿杩�");
       return;
     }
+  }
 
-    if (rawFile.size > uploadConfig.fileSize * 1024 * 1024) {
-      ElMessage.warning(`鏂囦欢澶у皬涓嶈兘瓒呰繃 ${uploadConfig.fileSize}MB`);
-      return;
-    }
-
-    const token = getToken();
-    if (!token) {
-      ElMessage.warning("鐢ㄦ埛鏈櫥褰�");
-      return;
-    }
-
-    const formData = new FormData();
-    formData.append("files", rawFile);
-    formData.append("type", 10); // 鐢熶骇鍓嶅浐瀹氫负10
-
-    uploading.value = true;
-    uploadProgress.value = 0;
-
-    try {
-      const { data } = await axios.post(uploadFileUrl.value, formData, {
-        headers: {
-          Authorization: `Bearer ${token}`,
-          "Content-Type": "multipart/form-data",
-        },
-        onUploadProgress: event => {
-          if (event.total) {
-            uploadProgress.value = Math.round((event.loaded / event.total) * 100);
-          }
-        },
-      });
-
-      if (data.code !== 200) {
-        ElMessage.error(data.msg || "涓婁紶澶辫触");
-        return;
-      }
-
-      const resultData = Array.isArray(data.data) ? data.data[0] : data.data;
-      const finalUrl = processFileUrl(
-        resultData.url || resultData.previewURL || resultData.downloadUrl || ""
-      );
-      const finalName =
-        resultData.name ||
-        resultData.originalFilename ||
-        resultData.bucketFilename;
-      const finalId = resultData.tempId || resultData.id || resultData.tempFileId;
-
-      const uploadedFile = {
-        ...resultData,
-        url: finalUrl,
-        downloadUrl: finalUrl,
-        name: finalName,
-        tempId: finalId,
-        tempFileId: resultData.tempFileId || finalId,
-        size: rawFile.size || resultData.size || resultData.byteSize || 0,
-        type: rawFile.type?.startsWith("video") ? "video" : "image",
-        status: "success",
-        uid: `${Date.now()}-${Math.random()}`,
-      };
-
-      beforeModelValue.value.push(uploadedFile);
-      ElMessage.success("涓婁紶鎴愬姛");
-    } catch (error) {
-      ElMessage.error(error?.message || "涓婁紶澶辫触");
-    } finally {
-      uploading.value = false;
-    }
-  };
-
-  const buildFileItem = item => ({
-    id: item?.id,
-    tempId: item?.tempId,
-    tempFileId: item?.tempFileId,
-    url: item?.downloadUrl || item?.url || "",
-    downloadUrl: item?.downloadUrl || item?.url || "",
-    name: item?.name,
-    bucketFilename: item?.bucketFilename || item?.name,
-    originalFilename: item?.originalFilename || item?.name,
-    size: item?.size || 0,
-    byteSize: item?.byteSize || item?.size || 0,
-    contentType: item?.contentType || "",
-    type: item?.type,
+  const loading = ElLoading.service({
+    text: "鎻愪氦涓�...",
+    background: "rgba(0, 0, 0, 0.3)",
   });
 
-  const submitUpload = async () => {
-    if (hasException.value === null) {
-      ElMessage.warning("璇烽�夋嫨宸℃鐘舵��");
-      return;
-    }
+  try {
+    const allFiles = [...beforeModelValue.value];
 
-    if (hasException.value === true) {
-      const totalFiles = beforeModelValue.value.length;
+    const tempFileIds = allFiles
+      .map((item) => item?.tempId ?? item?.tempFileId ?? item?.id)
+      .filter(Boolean);
 
-      if (!totalFiles) {
-        ElMessage.warning("璇蜂笂浼犲紓甯哥収鐗囨垨瑙嗛");
-        return;
-      }
+    const {
+      createTime,
+      updateTime,
+      storageBlobDTO,
+      commonFileListAfterVO,
+      commonFileListVO,
+      commonFileListBeforeVO,
+      commonFileListAfter,
+      commonFileList,
+      commonFileListBefore,
+      __raw,
+      ...baseTaskInfo
+    } = taskInfo.value || {};
 
-      if (!abnormalDescription.value.trim()) {
-        ElMessage.warning("璇峰~鍐欏紓甯告弿杩�");
-        return;
-      }
-    }
-
-    const loading = ElLoading.service({
-      text: "鎻愪氦涓�...",
-      background: "rgba(0, 0, 0, 0.3)",
-    });
-
-    try {
-      const allFiles = [...beforeModelValue.value];
-
-      const tempFileIds = allFiles
-        .map(item => item?.tempId ?? item?.tempFileId ?? item?.id)
-        .filter(Boolean);
-
-      const {
-        createTime,
-        updateTime,
-        storageBlobDTO,
-        commonFileListAfterVO,
-        commonFileListVO,
-        commonFileListBeforeVO,
-        commonFileListAfter,
-        commonFileList,
-        commonFileListBefore,
-        __raw,
-        ...baseTaskInfo
-      } = taskInfo.value || {};
-
-      const submitData = {
-        ...baseTaskInfo,
-        commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem),
-        commonFileListDTO: [],
-        commonFileListAfterDTO: [],
-        hasException: hasException.value,
-        inspectionResult: hasException.value ? 0 : 1,
-        abnormalDescription: abnormalDescription.value,
-        tempFileIds,
-      };
-
-      const result = await uploadInspectionTask(submitData);
-
-      if (result && (result.code === 200 || result.success)) {
-        ElMessage.success("鎻愪氦鎴愬姛");
-        dialogVisible.value = false;
-        resetState();
-        emit("success");
-        emit("closeDia");
-      } else {
-        ElMessage.error(result?.msg || result?.message || "鎻愪氦澶辫触");
-      }
-    } catch (error) {
-      ElMessage.error(error?.message || "鎻愪氦澶辫触");
-    } finally {
-      loading.close();
-    }
-  };
-
-  const removeFile = async index => {
-    try {
-      await ElMessageBox.confirm("纭畾瑕佸垹闄よ繖涓枃浠跺悧锛�", "纭鍒犻櫎", {
-        type: "warning",
-      });
-      beforeModelValue.value.splice(index, 1);
-    } catch {}
-  };
-
-  const goToRepair = () => {
-    const taskData = {
-      taskId: taskInfo.value?.taskId || taskInfo.value?.id,
-      taskName: taskInfo.value?.taskName,
-      inspectionLocation: taskInfo.value?.inspectionLocation,
-      inspector: taskInfo.value?.inspector,
-      hasException: hasException.value,
-      inspectionResult: hasException.value ? 0 : 1,
+    const submitData = {
+      ...baseTaskInfo,
+      inspectionItems: inspectionItems.value.map((item) => ({
+        id: item.id,
+        itemStatus: completedItemIds.value.includes(item.id) ? 1 : 0,
+        remarks: item.remarks || "",
+      })),
       commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem),
       commonFileListDTO: [],
       commonFileListAfterDTO: [],
-      uploadedFiles: {
-        before: beforeModelValue.value,
-        after: [],
-        issue: [],
-      },
+      hasException: hasException.value,
+      inspectionResult: hasException.value ? 0 : 1,
+      abnormalDescription: abnormalDescription.value,
+      tempFileIds,
     };
 
-    sessionStorage.setItem("repairTaskInfo", JSON.stringify(taskData));
-    router.push("/equipmentManagement/repair/add");
-  };
+    const result = await uploadInspectionTask(submitData);
 
-  const formatFileSize = size => {
-    if (!size) return "0 B";
-
-    const units = ["B", "KB", "MB", "GB"];
-    let index = 0;
-    let fileSize = size;
-
-    while (fileSize >= 1024 && index < units.length - 1) {
-      fileSize /= 1024;
-      index += 1;
+    if (result && (result.code === 200 || result.success)) {
+      ElMessage.success("鎻愪氦鎴愬姛");
+      dialogVisible.value = false;
+      resetState();
+      emit("success");
+      emit("closeDia");
+    } else {
+      ElMessage.error(result?.msg || result?.message || "鎻愪氦澶辫触");
     }
+  } catch (error) {
+    ElMessage.error(error?.message || "鎻愪氦澶辫触");
+  } finally {
+    loading.close();
+  }
+};
 
-    return `${fileSize.toFixed(2)} ${units[index]}`;
+const removeFile = async (index) => {
+  try {
+    await ElMessageBox.confirm("纭畾瑕佸垹闄よ繖涓枃浠跺悧锛�", "纭鍒犻櫎", {
+      type: "warning",
+    });
+    beforeModelValue.value.splice(index, 1);
+  } catch {}
+};
+
+const goToRepair = () => {
+  const taskData = {
+    taskId: taskInfo.value?.taskId || taskInfo.value?.id,
+    taskName: taskInfo.value?.taskName,
+    inspectionLocation: taskInfo.value?.inspectionLocation,
+    inspector: taskInfo.value?.inspector,
+    hasException: hasException.value,
+    inspectionResult: hasException.value ? 0 : 1,
+    commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem),
+    commonFileListDTO: [],
+    commonFileListAfterDTO: [],
+    uploadedFiles: {
+      before: beforeModelValue.value,
+      after: [],
+      issue: [],
+    },
   };
 
-  defineExpose({
-    openDialog,
-  });
+  sessionStorage.setItem("repairTaskInfo", JSON.stringify(taskData));
+  router.push("/equipmentManagement/repair/add");
+};
+
+const formatFileSize = (size) => {
+  if (!size) return "0 B";
+
+  const units = ["B", "KB", "MB", "GB"];
+  let index = 0;
+  let fileSize = size;
+
+  while (fileSize >= 1024 && index < units.length - 1) {
+    fileSize /= 1024;
+    index += 1;
+  }
+
+  return `${fileSize.toFixed(2)} ${units[index]}`;
+};
+
+defineExpose({
+  openDialog,
+});
 </script>
 
 <style scoped>
-  .inspection-upload-page {
-    min-height: 70vh;
-    background: #f5f7fa;
-    padding: 20px 20px 90px;
-    box-sizing: border-box;
-  }
+.inspection-upload-page {
+  min-height: 70vh;
+  background: #f5f7fa;
+  padding: 20px 20px 90px;
+  box-sizing: border-box;
+}
 
-  .upload-content {
-    max-width: 960px;
-    margin: 20px auto 0;
-  }
+.upload-content {
+  max-width: 960px;
+  margin: 20px auto 0;
+}
 
-  .section-card {
-    margin-bottom: 16px;
-  }
+.section-card {
+  margin-bottom: 16px;
+}
 
-  .section-card h3 {
-    margin: 0 0 16px;
-    font-size: 16px;
-  }
+.section-card h3 {
+  margin: 0 0 16px;
+  font-size: 16px;
+}
 
-  .upload-buttons {
-    display: flex;
-    gap: 12px;
-    margin: 16px 0;
-  }
+.section-heading {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 10px;
+  color: #909399;
+}
+.section-heading h3 {
+  margin: 0;
+  color: #303133;
+}
+.inspection-item-row {
+  display: flex;
+  align-items: flex-start;
+  justify-content: space-between;
+  gap: 20px;
+  padding: 14px 8px;
+  border-top: 1px solid #ebeef5;
+}
+.inspection-item-copy {
+  min-width: 0;
+  flex: 1;
+}
+.inspection-item-title {
+  font-weight: 600;
+  color: #303133;
+}
+.inspection-item-content {
+  margin: 6px 0 0 20px;
+  color: #606266;
+  white-space: pre-wrap;
+  overflow-wrap: anywhere;
+}
 
-  .upload-progress {
-    margin-bottom: 16px;
-  }
+.upload-buttons {
+  display: flex;
+  gap: 12px;
+  margin: 16px 0;
+}
 
-  .file-list {
-    display: grid;
-    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
-    gap: 12px;
-  }
+.upload-progress {
+  margin-bottom: 16px;
+}
 
-  .file-preview-container {
-    position: relative;
-    aspect-ratio: 1;
-    border-radius: 8px;
-    overflow: hidden;
-    background: #f2f3f5;
-  }
+.file-list {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
+  gap: 12px;
+}
 
-  .file-preview {
-    width: 100%;
-    height: 100%;
-  }
+.file-preview-container {
+  position: relative;
+  aspect-ratio: 1;
+  border-radius: 8px;
+  overflow: hidden;
+  background: #f2f3f5;
+}
 
-  .video-preview {
-    width: 100%;
-    height: 100%;
-    background: #303133;
-    color: #fff;
-    display: flex;
-    gap: 6px;
-    align-items: center;
-    justify-content: center;
-    cursor: pointer;
-  }
+.file-preview {
+  width: 100%;
+  height: 100%;
+}
 
-  .delete-btn {
-    position: absolute;
-    top: 6px;
-    right: 6px;
-  }
+.video-preview {
+  width: 100%;
+  height: 100%;
+  background: #303133;
+  color: #fff;
+  display: flex;
+  gap: 6px;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+}
 
-  .file-info {
-    margin-top: 6px;
-    font-size: 12px;
-  }
+.delete-btn {
+  position: absolute;
+  top: 6px;
+  right: 6px;
+}
 
-  .file-name {
-    color: #606266;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-  }
+.file-info {
+  margin-top: 6px;
+  font-size: 12px;
+}
 
-  .file-size {
-    color: #909399;
-    margin-top: 2px;
-  }
+.file-name {
+  color: #606266;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
 
-  .upload-summary {
-    margin-top: 16px;
-  }
+.file-size {
+  color: #909399;
+  margin-top: 2px;
+}
 
-  .footer-buttons {
-    position: sticky;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    padding: 14px 20px 0;
-    background: #f5f7fa;
-    display: flex;
-    justify-content: center;
-    gap: 12px;
-  }
+.upload-summary {
+  margin-top: 16px;
+}
 
-  .video-player {
-    width: 100%;
-    max-height: 70vh;
-    background: #000;
-  }
+.footer-buttons {
+  position: sticky;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  padding: 14px 20px 0;
+  background: #f5f7fa;
+  display: flex;
+  justify-content: center;
+  gap: 12px;
+}
+
+.video-player {
+  width: 100%;
+  max-height: 70vh;
+  background: #000;
+}
 </style>
diff --git a/src/views/equipmentManagement/inspectionManagement/index.vue b/src/views/equipmentManagement/inspectionManagement/index.vue
index c6c21d9..f080161 100644
--- a/src/views/equipmentManagement/inspectionManagement/index.vue
+++ b/src/views/equipmentManagement/inspectionManagement/index.vue
@@ -1,461 +1,592 @@
 <template>
   <div class="app-container">
-    <el-form :inline="true"
-             :model="queryParams"
-             class="search-form">
-      <el-form-item label="宸℃浠诲姟鍚嶇О">
-        <el-input v-model="queryParams.taskName"
-                  placeholder="璇疯緭鍏ュ贰妫�浠诲姟鍚嶇О"
-                  clearable
-                  style="width: 200px " />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary"
-                   @click="handleQuery">鏌ヨ</el-button>
-        <el-button @click="resetQuery">閲嶇疆</el-button>
-      </el-form-item>
-    </el-form>
-    <el-card>
-      <div style="display: flex;flex-direction: row;justify-content: space-between;margin-bottom: 10px;">
-        <el-radio-group v-model="activeRadio"
-                        @change="radioChange">
-          <el-radio-button v-for="tab in radios"
-                           :key="tab.name"
-                           :label="tab.label"
-                           :value="tab.name" />
-        </el-radio-group>
-        <!-- 鎿嶄綔鎸夐挳鍖� -->
-        <el-space v-if="activeRadio !== 'task'">
-          <el-button type="primary"
-                     :icon="Plus"
-                     @click="handleAdd(undefined)">鏂板缓</el-button>
-          <el-button type="danger"
-                     :icon="Delete"
-                     @click="handleDelete">鍒犻櫎</el-button>
-          <el-button @click="handleOut">瀵煎嚭</el-button>
-        </el-space>
-        <el-space v-else>
-          <el-button @click="handleOut">瀵煎嚭</el-button>
-        </el-space>
+    <el-tabs v-model="activeRadio" @tab-change="radioChange">
+      <el-tab-pane v-for="tab in radios" :key="tab.name" :label="tab.label" :name="tab.name" />
+    </el-tabs>
+    <InspectionItemManager v-if="activeRadio === 'items'" />
+    <template v-else>
+      <div class="search_form">
+        <el-form :inline="true" :model="queryParams">
+          <el-form-item label="宸℃浠诲姟鍚嶇О">
+            <el-input
+              v-model="queryParams.taskName"
+              placeholder="璇疯緭鍏ュ贰妫�浠诲姟鍚嶇О"
+              clearable
+              style="width: 240px"
+              @keyup.enter="handleQuery"
+            />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="handleQuery">鎼滅储</el-button>
+            <el-button @click="resetQuery">閲嶇疆</el-button>
+          </el-form-item>
+        </el-form>
       </div>
-      <div>
-        <PIMTable :table-loading="tableLoading"
-                  :table-data="tableData"
-                  :column="tableColumns"
-                  @selection-change="handleSelectionChange"
-                  @pagination="handlePagination"
-                  :is-selection="true"
-                  :border="true"
-                  :page="{
-                  current: pageNum,
-                  size: pageSize,
-                  total: total,
-                  layout: 'total, sizes, prev, pager, next, jumper'
-                }"
-                  height="calc(100vh - 23em)"
-                  :table-style="{ width: '100%' }">
+      <div class="table_list">
+        <div class="actions">
+          <el-text size="large">{{ activeRadio === "task" ? "宸℃璁板綍" : "宸℃浠诲姟" }}</el-text>
+          <div class="action-buttons">
+            <template v-if="activeRadio !== 'task'">
+              <el-button type="primary" :icon="Plus" @click="handleAdd(undefined)">鏂板缓</el-button>
+              <el-button
+                type="danger"
+                :icon="Delete"
+                :disabled="selectedRows.length === 0"
+                @click="handleDelete"
+                >鍒犻櫎</el-button
+              >
+            </template>
+            <el-button @click="handleOut">瀵煎嚭</el-button>
+          </div>
+        </div>
+        <PIMTable
+          :table-loading="tableLoading"
+          :table-data="tableData"
+          :column="tableColumns"
+          @selection-change="handleSelectionChange"
+          @pagination="handlePagination"
+          :is-selection="true"
+          :border="true"
+          :page="{
+            current: pageNum,
+            size: pageSize,
+            total: total,
+            layout: 'total, sizes, prev, pager, next, jumper',
+          }"
+        >
           <template #inspector="{ row }">
             <div class="person-tags">
               <!-- 璋冭瘯淇℃伅锛屼笂绾挎椂鍒犻櫎 -->
               <!-- {{ console.log('inspector data:', row.inspector) }} -->
               <template v-if="row.inspector && row.inspector.length > 0">
-                <el-tag v-for="(person, index) in row.inspector"
-                        :key="index"
-                        size="small"
-                        type="primary"
-                        class="person-tag">
+                <el-tag
+                  v-for="(person, index) in row.inspector"
+                  :key="index"
+                  size="small"
+                  type="primary"
+                  class="person-tag"
+                >
                   {{ person }}
                 </el-tag>
               </template>
-              <span v-else
-                    class="no-data">--</span>
+              <span v-else class="no-data">--</span>
             </div>
           </template>
           <template #isEnabled="{ row }">
-            <el-tag :type="row.isEnabled === 1 ? 'success' : 'danger'"
-                    size="small">
-              {{ row.isEnabled == 1 ? '鏄�' : '鍚�' }}
+            <el-tag :type="row.isEnabled === 1 ? 'success' : 'danger'" size="small">
+              {{ row.isEnabled == 1 ? "鏄�" : "鍚�" }}
             </el-tag>
           </template>
         </PIMTable>
       </div>
-    </el-card>
-    <form-dia ref="formDia"
-              @closeDia="handleQuery"></form-dia>
-    <view-files ref="viewFiles"></view-files>
-    <upload-files ref="uploadFiles"
-                  @success="handleQuery"
-                  @closeDia="handleQuery"></upload-files>
+      <form-dia ref="formDia" @closeDia="handleQuery" />
+      <view-files ref="viewFiles" />
+      <upload-files ref="uploadFiles" @success="handleQuery" @closeDia="handleQuery" />
+      <el-dialog v-model="taskDetailVisible" title="宸℃浠诲姟璇︽儏" width="900px">
+        <template v-if="taskDetail">
+          <el-descriptions :column="2" border>
+            <el-descriptions-item label="宸℃浠诲姟鍚嶇О">{{
+              taskDetail.taskName || "-"
+            }}</el-descriptions-item>
+            <el-descriptions-item label="鎵ц宸℃浜�">{{
+              formatInspector(taskDetail.inspector)
+            }}</el-descriptions-item>
+            <el-descriptions-item label="棰戞">{{
+              formatFrequencyType(taskDetail.frequencyType)
+            }}</el-descriptions-item>
+            <el-descriptions-item label="寮�濮嬫棩鏈熶笌鏃堕棿">{{
+              formatFrequencyDetail(taskDetail.frequencyDetail)
+            }}</el-descriptions-item>
+            <el-descriptions-item label="鐧昏浜�">{{
+              taskDetail.registrant || "-"
+            }}</el-descriptions-item>
+            <el-descriptions-item label="鐧昏鏃ユ湡">{{
+              taskDetail.createTime ? dayjs(taskDetail.createTime).format("YYYY-MM-DD") : "-"
+            }}</el-descriptions-item>
+            <el-descriptions-item label="澶囨敞" :span="2">{{
+              taskDetail.remarks || "-"
+            }}</el-descriptions-item>
+          </el-descriptions>
+          <div class="task-detail-items">
+            <div class="task-detail-heading">
+              宸℃鍐呭锛坽{ taskDetail.inspectionItems?.length || 0 }}椤癸級
+            </div>
+            <el-empty v-if="!taskDetail.inspectionItems?.length" description="鏆傛棤宸℃鍐呭" />
+            <div
+              v-for="(item, index) in taskDetail.inspectionItems"
+              :key="item.id || index"
+              class="task-detail-item"
+            >
+              <div class="task-detail-project">
+                {{ index + 1 }}. {{ item.itemProject || "鏈懡鍚嶉」鐩�" }}
+              </div>
+              <div class="task-detail-content">{{ item.itemContent || "-" }}</div>
+            </div>
+          </div>
+        </template>
+        <template #footer>
+          <el-button @click="taskDetailVisible = false">鍏抽棴</el-button>
+        </template>
+      </el-dialog>
+    </template>
   </div>
 </template>
 
 <script setup>
-  import { Delete, Plus } from "@element-plus/icons-vue";
-  import { onMounted, ref, reactive, getCurrentInstance, nextTick } from "vue";
-  import { ElMessageBox } from "element-plus";
-  import dayjs from "dayjs";
+import { Delete, Plus } from "@element-plus/icons-vue";
+import { onMounted, ref, reactive, getCurrentInstance, nextTick } from "vue";
+import { ElMessageBox } from "element-plus";
+import dayjs from "dayjs";
 
-  // 缁勪欢寮曞叆
-  import PIMTable from "@/components/PIMTable/PIMTable.vue";
-  import FormDia from "@/views/equipmentManagement/inspectionManagement/components/formDia.vue";
-  import UploadFiles from "@/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue";
-  import ViewFiles from "@/views/equipmentManagement/inspectionManagement/components/viewFiles.vue";
+// 缁勪欢寮曞叆
+import PIMTable from "@/components/PIMTable/PIMTable.vue";
+import FormDia from "@/views/equipmentManagement/inspectionManagement/components/formDia.vue";
+import UploadFiles from "@/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue";
+import ViewFiles from "@/views/equipmentManagement/inspectionManagement/components/viewFiles.vue";
+import InspectionItemManager from "@/views/equipmentManagement/inspectionManagement/components/InspectionItemManager.vue";
 
-  // 鎺ュ彛寮曞叆
-  import {
-    delTimingTask,
-    inspectionTaskList,
-    timingTaskList,
-  } from "@/api/inspectionManagement/index.js";
+// 鎺ュ彛寮曞叆
+import {
+  delTimingTask,
+  inspectionTaskList,
+  timingTaskList,
+} from "@/api/inspectionManagement/index.js";
 
-  // 鍏ㄥ眬鍙橀噺
-  const { proxy } = getCurrentInstance();
-  const formDia = ref();
-  const viewFiles = ref();
-  const uploadFiles = ref();
+// 鍏ㄥ眬鍙橀噺
+const { proxy } = getCurrentInstance();
+const formDia = ref();
+const viewFiles = ref();
+const uploadFiles = ref();
+const taskDetailVisible = ref(false);
+const taskDetail = ref(null);
 
-  // 鏌ヨ鍙傛暟
-  const queryParams = reactive({
-    taskName: "",
-  });
+// 鏌ヨ鍙傛暟
+const queryParams = reactive({
+  taskName: "",
+});
 
-  // 鍗曢�夋閰嶇疆
-  const activeRadio = ref("taskManage");
-  const radios = reactive([
-    { name: "taskManage", label: "宸℃浠诲姟" },
-    { name: "task", label: "宸℃璁板綍" },
-  ]);
+// 鍗曢�夋閰嶇疆
+const activeRadio = ref("taskManage");
+const radios = reactive([
+  { name: "taskManage", label: "宸℃浠诲姟" },
+  { name: "task", label: "宸℃璁板綍" },
+  { name: "items", label: "宸℃鍐呭" },
+]);
 
-  // 琛ㄦ牸鏁版嵁
-  const selectedRows = ref([]);
-  const tableData = ref([]);
-  const operationsArr = ref([]);
-  const tableColumns = ref([]);
-  const tableLoading = ref(false);
-  const total = ref(0);
-  const pageNum = ref(1);
-  const pageSize = ref(10);
+// 琛ㄦ牸鏁版嵁
+const selectedRows = ref([]);
+const tableData = ref([]);
+const operationsArr = ref([]);
+const tableColumns = ref([]);
+const tableLoading = ref(false);
+const total = ref(0);
+const pageNum = ref(1);
+const pageSize = ref(10);
 
-  // 鍒楅厤缃�
-  const columns = ref([
-    { prop: "taskName", label: "宸℃浠诲姟鍚嶇О", minWidth: 200 },
-    { prop: "inspectionProject", label: "宸℃椤圭洰", minWidth: 180 },
-    { prop: "remarks", label: "澶囨敞", minWidth: 180 },
-    { prop: "inspector", label: "鎵ц宸℃浜�", minWidth: 180, slot: "inspector" },
-    {
-      prop: "isEnabled",
-      label: "鏄惁鍚敤",
-      minWidth: 100,
-      dataType: "slot",
-      slot: "isEnabled",
+// 鍒楅厤缃�
+const taskColumns = [
+  { prop: "taskName", label: "宸℃浠诲姟鍚嶇О", minWidth: 200 },
+  { prop: "inspector", label: "鎵ц宸℃浜�", minWidth: 180, slot: "inspector" },
+  {
+    prop: "isEnabled",
+    label: "鏄惁鍚敤",
+    minWidth: 100,
+    dataType: "slot",
+    slot: "isEnabled",
+  },
+  {
+    prop: "frequencyType",
+    label: "棰戞",
+    minWidth: 120,
+    formatData: (params) => {
+      return params === "DAILY"
+        ? "姣忔棩"
+        : params === "WEEKLY"
+        ? "姣忓懆"
+        : params === "MONTHLY"
+        ? "姣忔湀"
+        : params === "QUARTERLY"
+        ? "瀛e害"
+        : "";
     },
-    {
-      prop: "frequencyType",
-      label: "棰戞",
-      minWidth: 120,
-      formatData: params => {
-        return params === "DAILY"
-          ? "姣忔棩"
-          : params === "WEEKLY"
-          ? "姣忓懆"
-          : params === "MONTHLY"
-          ? "姣忔湀"
-          : params === "QUARTERLY"
-          ? "瀛e害"
-          : "";
-      },
+  },
+  {
+    prop: "frequencyDetail",
+    label: "寮�濮嬫棩鏈熶笌鏃堕棿",
+    minWidth: 200,
+    formatter: (row, column, cellValue) => {
+      // 鍏堝垽鏂槸鍚︽槸瀛楃涓�
+      if (typeof cellValue !== "string") return "";
+      let val = cellValue;
+      const replacements = {
+        MON: "鍛ㄤ竴",
+        TUE: "鍛ㄤ簩",
+        WED: "鍛ㄤ笁",
+        THU: "鍛ㄥ洓",
+        FRI: "鍛ㄤ簲",
+        SAT: "鍛ㄥ叚",
+        SUN: "鍛ㄦ棩",
+      };
+      // 浣跨敤姝e垯涓�娆℃�ф浛鎹㈡墍鏈夊尮閰嶉」
+      return val.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, (match) => replacements[match]);
     },
-    {
-      prop: "frequencyDetail",
-      label: "寮�濮嬫棩鏈熶笌鏃堕棿",
-      minWidth: 200,
-      formatter: (row, column, cellValue) => {
-        // 鍏堝垽鏂槸鍚︽槸瀛楃涓�
-        if (typeof cellValue !== "string") return "";
-        let val = cellValue;
-        const replacements = {
-          MON: "鍛ㄤ竴",
-          TUE: "鍛ㄤ簩",
-          WED: "鍛ㄤ笁",
-          THU: "鍛ㄥ洓",
-          FRI: "鍛ㄤ簲",
-          SAT: "鍛ㄥ叚",
-          SUN: "鍛ㄦ棩",
-        };
-        // 浣跨敤姝e垯涓�娆℃�ф浛鎹㈡墍鏈夊尮閰嶉」
-        return val.replace(
-          /MON|TUE|WED|THU|FRI|SAT|SUN/g,
-          match => replacements[match]
-        );
-      },
-    },
-    { prop: "registrant", label: "鐧昏浜�", minWidth: 120 },
-    {
-      prop: "createTime",
-      label: "鐧昏鏃ユ湡",
-      minWidth: 180,
-      formatData: cell => {
-        if (!cell) return "-";
-        try {
-          return dayjs(cell).format("YYYY-MM-DD");
-        } catch {
-          return cell;
-        }
-      },
-    },
-    // {
-    //   prop: "inspectionResult",
-    //   label: "宸℃缁撴灉",
-    //   minWidth: 100,
-    //   dataType: "tag",
-    //   formatData: val => {
-    //     return val == 1 ? "姝e父" : "寮傚父";
-    //   },
-    //   formatType: val => {
-    //     return val == 1 ? "success" : "danger";
-    //   },
-    // },
-    { prop: "abnormalDescription", label: "寮傚父鎻忚堪", minWidth: 150 },
-  ]);
-
-  // 鎿嶄綔鍒楅厤缃�
-  const getOperationColumn = operations => {
-    if (!operations || operations.length === 0) return null;
-
-    const operationConfig = {
-      label: "鎿嶄綔",
-      width: operations.length > 1 ? 180 : 130,
-      fixed: "right",
-      align: "center",
-      dataType: "action",
-      operation: operations
-        .map(op => {
-          switch (op) {
-            case "view":
-              return {
-                name: "璇︽儏",
-                clickFun: openViewDialog,
-                color: "#409EFF",
-              };
-            case "edit":
-              return {
-                name: "缂栬緫",
-                clickFun: handleAdd,
-                color: "#409EFF",
-              };
-            case "upload":
-              return {
-                name: "涓婁紶",
-                clickFun: openUploadDialog,
-                color: "#409EFF",
-              };
-            case "viewFile":
-              return {
-                name: "鏌ョ湅闄勪欢",
-                clickFun: viewFile,
-                color: "#67C23A",
-              };
-            default:
-              return null;
-          }
-        })
-        .filter(Boolean),
-    };
-
-    return operationConfig;
-  };
-
-  onMounted(() => {
-    radioChange("taskManage");
-  });
-
-  // 鍗曢�夊彉鍖�
-  const radioChange = value => {
-    if (value === "taskManage") {
-      const operationColumn = getOperationColumn(["edit"]);
-      tableColumns.value = [
-        ...columns.value,
-        ...(operationColumn ? [operationColumn] : []),
-      ];
-      operationsArr.value = ["edit"];
-    } else if (value === "task") {
-      const operationColumn = getOperationColumn(["view", "upload", "viewFile"]);
-      // 宸℃璁板綍涓嶅睍绀�"鏄惁鍚敤"鍒�
-      const taskColumns = columns.value.filter(col => col.prop !== "isEnabled");
-      tableColumns.value = [
-        ...taskColumns,
-        ...(operationColumn ? [operationColumn] : []),
-      ];
-      operationsArr.value = ["view", "upload", "viewFile"];
-    }
-    pageNum.value = 1;
-    pageSize.value = 10;
-    getList();
-  };
-
-  // 鏌ヨ鎿嶄綔
-  const handleQuery = () => {
-    pageNum.value = 1;
-    pageSize.value = 10;
-    getList();
-  };
-  // 鍒嗛〉澶勭悊
-  const handlePagination = val => {
-    pageNum.value = val.page;
-    pageSize.value = val.limit;
-    getList();
-  };
-  // 鑾峰彇鍒楄〃鏁版嵁
-  const getList = () => {
-    tableLoading.value = true;
-
-    const params = {
-      ...queryParams,
-      size: pageSize.value,
-      current: pageNum.value,
-    };
-
-    let apiCall;
-    if (activeRadio.value === "task") {
-      apiCall = inspectionTaskList(params);
-    } else {
-      apiCall = timingTaskList(params);
-    }
-
-    apiCall
-      .then(res => {
-        const rawData = res.data.records || [];
-        // 澶勭悊 inspector 瀛楁锛屽皢瀛楃涓茶浆鎹负鏁扮粍锛堥�傜敤浜庢墍鏈夋儏鍐碉級
-        tableData.value = rawData.map(item => {
-          const processedItem = { ...item };
-          processedItem.__raw = { ...item };
-
-          // 澶勭悊 inspector 瀛楁
-          if (processedItem.inspector) {
-            if (typeof processedItem.inspector === "string") {
-              // 瀛楃涓叉寜閫楀彿鍒嗗壊
-              processedItem.inspector = processedItem.inspector
-                .split(",")
-                .map(s => s.trim())
-                .filter(s => s);
-            } else if (!Array.isArray(processedItem.inspector)) {
-              // 闈炴暟缁勮浆涓烘暟缁�
-              processedItem.inspector = [processedItem.inspector];
-            }
-          } else {
-            // 绌哄�艰涓虹┖鏁扮粍
-            processedItem.inspector = [];
-          }
-
-          return processedItem;
-        });
-        total.value = res.data.total || 0;
-      })
-      .finally(() => {
-        tableLoading.value = false;
-      });
-  };
-
-  // 閲嶇疆鏌ヨ
-  const resetQuery = () => {
-    for (const key in queryParams) {
-      if (!["pageNum", "pageSize"].includes(key)) {
-        queryParams[key] = "";
+  },
+  { prop: "registrant", label: "鐧昏浜�", minWidth: 120 },
+  {
+    prop: "createTime",
+    label: "鐧昏鏃ユ湡",
+    minWidth: 180,
+    formatData: (cell) => {
+      if (!cell) return "-";
+      try {
+        return dayjs(cell).format("YYYY-MM-DD");
+      } catch {
+        return cell;
       }
-    }
-    handleQuery();
-  };
+    },
+  },
+  { prop: "remarks", label: "澶囨敞", minWidth: 180, showOverflowTooltip: true },
+];
+const recordColumns = [
+  { prop: "taskName", label: "宸℃浠诲姟鍚嶇О", minWidth: 200 },
+  { prop: "inspector", label: "鎵ц宸℃浜�", minWidth: 180, slot: "inspector" },
+  {
+    prop: "frequencyType",
+    label: "棰戞",
+    minWidth: 120,
+    formatData: (params) => formatFrequencyType(params),
+  },
+  {
+    prop: "frequencyDetail",
+    label: "寮�濮嬫棩鏈熶笌鏃堕棿",
+    minWidth: 200,
+    formatter: (row, column, cellValue) => formatFrequencyDetail(cellValue),
+  },
+  { prop: "registrant", label: "鐧昏浜�", minWidth: 120 },
+  {
+    prop: "createTime",
+    label: "鐧昏鏃ユ湡",
+    minWidth: 180,
+    formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : "-"),
+  },
+  { prop: "abnormalDescription", label: "寮傚父鎻忚堪", minWidth: 150, showOverflowTooltip: true },
+  { prop: "remarks", label: "澶囨敞", minWidth: 180, showOverflowTooltip: true },
+];
 
-  // 鏂板 / 缂栬緫
-  const handleAdd = row => {
-    const type = row ? "edit" : "add";
-    nextTick(() => {
-      formDia.value?.openDialog(type, row);
-    });
-  };
+// 鎿嶄綔鍒楅厤缃�
+const getOperationColumn = (operations) => {
+  if (!operations || operations.length === 0) return null;
 
-  // 鏌ョ湅闄勪欢
-  const viewFile = row => {
-    nextTick(() => {
-      viewFiles.value?.openDialog(row);
-    });
-  };
-
-  const openUploadDialog = row => {
-    nextTick(() => {
-      uploadFiles.value?.openDialog("add", row);
-    });
-  };
-
-  const openViewDialog = row => {
-    nextTick(() => {
-      uploadFiles.value?.openDialog("view", row);
-    });
-  };
-
-  // 鍒犻櫎鎿嶄綔
-  const handleDelete = () => {
-    if (!selectedRows.value.length) {
-      proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
-      return;
-    }
-
-    const deleteIds = selectedRows.value.map(item => item.id);
-
-    proxy.$modal
-      .confirm("鏄惁纭鍒犻櫎鎵�閫夋暟鎹」锛�")
-      .then(() => {
-        return delTimingTask(deleteIds);
-      })
-      .then(() => {
-        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-        handleQuery();
-      })
-      .catch(() => {});
-  };
-
-  // 澶氶�夊彉鏇�
-  const handleSelectionChange = selection => {
-    selectedRows.value = selection;
-  };
-
-  // 瀵煎嚭
-  const handleOut = () => {
-    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
-      confirmButtonText: "纭",
-      cancelButtonText: "鍙栨秷",
-      type: "warning",
-    })
-      .then(() => {
-        // 鏍规嵁褰撳墠閫変腑鐨勬爣绛鹃〉璋冪敤涓嶅悓鐨勫鍑烘帴鍙�
-        if (activeRadio.value === "taskManage") {
-          // 宸℃浠诲姟
-          proxy.download("/timingTask/export", {}, "宸℃浠诲姟.xlsx");
-        } else if (activeRadio.value === "task") {
-          // 宸℃璁板綍
-          proxy.download("/inspectionTask/export", {}, "宸℃璁板綍.xlsx");
+  const operationConfig = {
+    label: "鎿嶄綔",
+    width: operations.length > 1 ? 180 : 130,
+    fixed: "right",
+    align: "center",
+    dataType: "action",
+    operation: operations
+      .map((op) => {
+        switch (op) {
+          case "view":
+            return {
+              name: "璇︽儏",
+              clickFun: openViewDialog,
+              color: "#409EFF",
+            };
+          case "viewTask":
+            return {
+              name: "璇︽儏",
+              clickFun: openTaskDetail,
+              color: "#409EFF",
+            };
+          case "edit":
+            return {
+              name: "缂栬緫",
+              clickFun: handleAdd,
+              color: "#409EFF",
+            };
+          case "upload":
+            return {
+              name: "涓婁紶",
+              clickFun: openUploadDialog,
+              color: "#409EFF",
+            };
+          case "viewFile":
+            return {
+              name: "鏌ョ湅闄勪欢",
+              clickFun: viewFile,
+              color: "#67C23A",
+            };
+          default:
+            return null;
         }
       })
-      .catch(() => {
-        proxy.$modal.msg("宸插彇娑�");
-      });
+      .filter(Boolean),
   };
+
+  return operationConfig;
+};
+
+onMounted(() => {
+  radioChange("taskManage");
+});
+
+// 鍗曢�夊彉鍖�
+const radioChange = (value) => {
+  if (value === "taskManage") {
+    const operationColumn = getOperationColumn(["viewTask", "edit"]);
+    tableColumns.value = [...taskColumns, ...(operationColumn ? [operationColumn] : [])];
+    operationsArr.value = ["viewTask", "edit"];
+  } else if (value === "task") {
+    const operationColumn = getOperationColumn(["view", "upload", "viewFile"]);
+    tableColumns.value = [...recordColumns, ...(operationColumn ? [operationColumn] : [])];
+    operationsArr.value = ["view", "upload", "viewFile"];
+  } else {
+    tableColumns.value = [];
+    operationsArr.value = [];
+    return;
+  }
+  pageNum.value = 1;
+  pageSize.value = 10;
+  getList();
+};
+
+// 鏌ヨ鎿嶄綔
+const handleQuery = () => {
+  pageNum.value = 1;
+  pageSize.value = 10;
+  getList();
+};
+// 鍒嗛〉澶勭悊
+const handlePagination = (val) => {
+  pageNum.value = val.page;
+  pageSize.value = val.limit;
+  getList();
+};
+// 鑾峰彇鍒楄〃鏁版嵁
+const getList = () => {
+  if (activeRadio.value === "items") return;
+  tableLoading.value = true;
+
+  const params = {
+    ...queryParams,
+    size: pageSize.value,
+    current: pageNum.value,
+  };
+
+  let apiCall;
+  if (activeRadio.value === "task") {
+    apiCall = inspectionTaskList(params);
+  } else {
+    apiCall = timingTaskList(params);
+  }
+
+  apiCall
+    .then((res) => {
+      const rawData = res.data.records || [];
+      // 澶勭悊 inspector 瀛楁锛屽皢瀛楃涓茶浆鎹负鏁扮粍锛堥�傜敤浜庢墍鏈夋儏鍐碉級
+      tableData.value = rawData.map((item) => {
+        const processedItem = { ...item };
+        processedItem.__raw = { ...item };
+
+        // 澶勭悊 inspector 瀛楁
+        if (processedItem.inspector) {
+          if (typeof processedItem.inspector === "string") {
+            // 瀛楃涓叉寜閫楀彿鍒嗗壊
+            processedItem.inspector = processedItem.inspector
+              .split(",")
+              .map((s) => s.trim())
+              .filter((s) => s);
+          } else if (!Array.isArray(processedItem.inspector)) {
+            // 闈炴暟缁勮浆涓烘暟缁�
+            processedItem.inspector = [processedItem.inspector];
+          }
+        } else {
+          // 绌哄�艰涓虹┖鏁扮粍
+          processedItem.inspector = [];
+        }
+
+        return processedItem;
+      });
+      total.value = res.data.total || 0;
+    })
+    .finally(() => {
+      tableLoading.value = false;
+    });
+};
+
+// 閲嶇疆鏌ヨ
+const resetQuery = () => {
+  for (const key in queryParams) {
+    if (!["pageNum", "pageSize"].includes(key)) {
+      queryParams[key] = "";
+    }
+  }
+  handleQuery();
+};
+
+// 鏂板 / 缂栬緫
+const handleAdd = (row) => {
+  const type = row ? "edit" : "add";
+  nextTick(() => {
+    formDia.value?.openDialog(type, row);
+  });
+};
+
+const openTaskDetail = (row) => {
+  taskDetail.value = row;
+  taskDetailVisible.value = true;
+};
+
+const formatInspector = (value) => {
+  if (Array.isArray(value)) return value.join("銆�") || "-";
+  return value || "-";
+};
+
+const formatFrequencyType = (type) =>
+  ({
+    DAILY: "姣忔棩",
+    WEEKLY: "姣忓懆",
+    MONTHLY: "姣忔湀",
+    QUARTERLY: "瀛e害",
+  }[type] || "-");
+
+const formatFrequencyDetail = (detail) => {
+  if (typeof detail !== "string" || !detail) return "-";
+  const replacements = {
+    MON: "鍛ㄤ竴",
+    TUE: "鍛ㄤ簩",
+    WED: "鍛ㄤ笁",
+    THU: "鍛ㄥ洓",
+    FRI: "鍛ㄤ簲",
+    SAT: "鍛ㄥ叚",
+    SUN: "鍛ㄦ棩",
+  };
+  return detail.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, (match) => replacements[match]);
+};
+
+// 鏌ョ湅闄勪欢
+const viewFile = (row) => {
+  nextTick(() => {
+    viewFiles.value?.openDialog(row);
+  });
+};
+
+const openUploadDialog = (row) => {
+  nextTick(() => {
+    uploadFiles.value?.openDialog("add", row);
+  });
+};
+
+const openViewDialog = (row) => {
+  nextTick(() => {
+    uploadFiles.value?.openDialog("view", row);
+  });
+};
+
+// 鍒犻櫎鎿嶄綔
+const handleDelete = () => {
+  if (!selectedRows.value.length) {
+    proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
+    return;
+  }
+
+  const deleteIds = selectedRows.value.map((item) => item.id);
+
+  proxy.$modal
+    .confirm("鏄惁纭鍒犻櫎鎵�閫夋暟鎹」锛�")
+    .then(() => {
+      return delTimingTask(deleteIds);
+    })
+    .then(() => {
+      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      handleQuery();
+    })
+    .catch(() => {});
+};
+
+// 澶氶�夊彉鏇�
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+};
+
+// 瀵煎嚭
+const handleOut = () => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      // 鏍规嵁褰撳墠閫変腑鐨勬爣绛鹃〉璋冪敤涓嶅悓鐨勫鍑烘帴鍙�
+      if (activeRadio.value === "taskManage") {
+        // 宸℃浠诲姟
+        proxy.download("/timingTask/export", {}, "宸℃浠诲姟.xlsx");
+      } else if (activeRadio.value === "task") {
+        // 宸℃璁板綍
+        proxy.download("/inspectionTask/export", {}, "宸℃璁板綍.xlsx");
+      }
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
 </script>
 
 <style scoped>
-  .person-tags {
-    display: flex;
-    flex-wrap: wrap;
-    gap: 4px;
-  }
+.actions {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 10px;
+}
+.action-buttons {
+  display: flex;
+  gap: 8px;
+}
+.table_list {
+  margin-top: unset;
+}
+.person-tags {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 4px;
+}
 
-  .person-tag {
-    margin-right: 4px;
-    margin-bottom: 2px;
-  }
+.person-tag {
+  margin-right: 4px;
+  margin-bottom: 2px;
+}
 
-  .no-data {
-    color: #909399;
-    font-size: 14px;
-  }
+.no-data {
+  color: #909399;
+  font-size: 14px;
+}
+.task-detail-items {
+  margin-top: 20px;
+  border: 1px solid var(--el-border-color-lighter);
+  border-radius: 4px;
+}
+.task-detail-heading {
+  padding: 12px 16px;
+  font-weight: 600;
+  border-bottom: 1px solid var(--el-border-color-lighter);
+}
+.task-detail-item {
+  padding: 14px 16px;
+  border-bottom: 1px solid var(--el-border-color-lighter);
+}
+.task-detail-item:last-child {
+  border-bottom: 0;
+}
+.task-detail-project {
+  font-weight: 600;
+  color: var(--el-text-color-primary);
+}
+.task-detail-content {
+  margin: 6px 0 0 20px;
+  color: var(--el-text-color-regular);
+  white-space: pre-wrap;
+  overflow-wrap: anywhere;
+}
 </style>
diff --git a/src/views/equipmentManagement/upkeep/Form/ItemManager.vue b/src/views/equipmentManagement/upkeep/Form/ItemManager.vue
new file mode 100644
index 0000000..982616e
--- /dev/null
+++ b/src/views/equipmentManagement/upkeep/Form/ItemManager.vue
@@ -0,0 +1,331 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <el-form :model="filters" :inline="true">
+        <el-form-item label="鎵�灞炶澶�">
+          <el-select
+            v-model="filters.deviceLedgerId"
+            clearable
+            filterable
+            placeholder="璇烽�夋嫨璁惧"
+            style="width: 220px"
+          >
+            <el-option
+              v-for="device in deviceOptions"
+              :key="device.id"
+              :label="device.deviceName"
+              :value="device.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="淇濆吇棰戠巼">
+          <el-select
+            v-model="filters.frequencyType"
+            clearable
+            placeholder="璇烽�夋嫨棰戠巼"
+            style="width: 200px"
+          >
+            <el-option
+              v-for="item in frequencyOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="淇濆吇鍐呭">
+          <el-input
+            v-model="keyword"
+            clearable
+            placeholder="璇疯緭鍏ヤ繚鍏诲唴瀹�"
+            style="width: 240px"
+            :prefix-icon="Search"
+            @keyup.enter="search"
+            @clear="search"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="search">鎼滅储</el-button>
+          <el-button @click="resetFilters">閲嶇疆</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+    <div class="table_list">
+      <div class="actions">
+        <el-text size="large">淇濆吇鍐呭娓呭崟</el-text>
+        <el-button type="primary" icon="Plus" @click="openAdd">鏂板淇濆吇鍐呭</el-button>
+      </div>
+      <el-table v-loading="loading" :data="items" border>
+        <el-table-column type="index" label="搴忓彿" width="80" align="center" :index="indexMethod" />
+        <el-table-column
+          prop="itemProject"
+          label="淇濆吇椤圭洰"
+          min-width="160"
+          show-overflow-tooltip
+        />
+        <el-table-column prop="itemName" label="淇濆吇鍐呭" min-width="280" show-overflow-tooltip />
+        <el-table-column label="鎵�灞炶澶�" min-width="180" align="center" show-overflow-tooltip>
+          <template #default="{ row }">{{
+            row.deviceLedgerId ? deviceNameMap[row.deviceLedgerId] || "-" : "閫氱敤"
+          }}</template>
+        </el-table-column>
+        <el-table-column label="棰戠巼" width="120" align="center">
+          <template #default="{ row }">{{ frequencyLabel(row.frequencyType) }}</template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" width="150" align="center" fixed="right">
+          <template #default="{ row }">
+            <el-button link type="primary" @click="openEdit(row)">缂栬緫</el-button>
+            <el-button link type="danger" @click="removeItem(row)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+        <template #empty>
+          <el-empty description="杩樻病鏈変繚鍏诲唴瀹癸紝璇峰厛閫愭潯娣诲姞">
+            <el-button type="primary" icon="Plus" @click="openAdd">鏂板淇濆吇鍐呭</el-button>
+          </el-empty>
+        </template>
+      </el-table>
+      <div class="pagination-wrap">
+        <el-pagination
+          v-model:current-page="pageNum"
+          v-model:page-size="pageSize"
+          background
+          :page-sizes="[10, 20, 50]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="load"
+        />
+      </div>
+    </div>
+
+    <el-dialog
+      v-model="dialogVisible"
+      :title="form.id ? '缂栬緫淇濆吇鍐呭' : '鏂板淇濆吇鍐呭'"
+      width="520px"
+      align-center
+      destroy-on-close
+      :close-on-click-modal="false"
+    >
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="90px" label-position="right">
+        <el-form-item label="淇濆吇椤圭洰" prop="itemProject">
+          <el-input
+            v-model.trim="form.itemProject"
+            placeholder="璇疯緭鍏ヤ繚鍏婚」鐩�"
+            maxlength="200"
+            show-word-limit
+          />
+        </el-form-item>
+        <el-form-item label="淇濆吇鍐呭" prop="itemName">
+          <el-input
+            v-model.trim="form.itemName"
+            type="textarea"
+            :rows="4"
+            resize="vertical"
+            placeholder="璇疯緭鍏ヤ繚鍏诲唴瀹�"
+            maxlength="2000"
+            show-word-limit
+          />
+        </el-form-item>
+        <el-form-item label="鎵�灞炶澶�">
+          <el-select
+            v-model="form.deviceLedgerId"
+            clearable
+            filterable
+            placeholder="涓嶉�夋嫨鍒欎负閫氱敤淇濆吇鍐呭"
+            no-data-text="鏆傛棤璁惧锛岃鍏堝湪璁惧鍙拌处涓坊鍔�"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="device in deviceOptions"
+              :key="device.id"
+              :label="device.deviceName"
+              :value="device.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="淇濆吇棰戠巼" prop="frequencyType">
+          <el-select v-model="form.frequencyType" placeholder="璇烽�夋嫨淇濆吇棰戠巼" style="width: 100%">
+            <el-option
+              v-for="item in frequencyOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+        <el-button type="primary" :loading="saving" @click="save">淇濆瓨</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { computed, onMounted, reactive, ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { Search } from "@element-plus/icons-vue";
+import {
+  addMaintenanceItem,
+  deleteMaintenanceItem,
+  editMaintenanceItem,
+  getMaintenanceItemPage,
+} from "@/api/equipmentManagement/upkeep";
+import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
+
+const items = ref([]);
+const loading = ref(false);
+const saving = ref(false);
+const dialogVisible = ref(false);
+const formRef = ref();
+const keyword = ref("");
+const pageNum = ref(1);
+const pageSize = ref(20);
+const total = ref(0);
+const deviceOptions = ref([]);
+const filters = reactive({ deviceLedgerId: undefined, frequencyType: "" });
+const frequencyOptions = [
+  { label: "姣忔棩", value: "DAILY" },
+  { label: "姣忓懆", value: "WEEKLY" },
+  { label: "姣忔湀", value: "MONTHLY" },
+  { label: "姣忓搴�", value: "QUARTERLY" },
+  { label: "閫氱敤棰戠巼", value: "ALL" },
+];
+const deviceNameMap = computed(() =>
+  Object.fromEntries(deviceOptions.value.map((device) => [String(device.id), device.deviceName]))
+);
+const frequencyLabel = (value) =>
+  frequencyOptions.find((item) => item.value === value)?.label || value || "-";
+const indexMethod = (index) => (pageNum.value - 1) * pageSize.value + index + 1;
+const form = reactive({
+  id: undefined,
+  itemProject: "",
+  itemName: "",
+  deviceLedgerId: undefined,
+  frequencyType: "",
+  sortNum: 0,
+  isActive: 1,
+  remarks: "",
+});
+const rules = {
+  itemProject: [{ required: true, message: "璇疯緭鍏ヤ繚鍏婚」鐩�", trigger: "blur" }],
+  itemName: [{ required: true, message: "璇疯緭鍏ヤ繚鍏诲唴瀹�", trigger: "blur" }],
+  frequencyType: [{ required: true, message: "璇烽�夋嫨淇濆吇棰戠巼", trigger: "change" }],
+};
+
+const load = async () => {
+  loading.value = true;
+  try {
+    const { code, data } = await getMaintenanceItemPage({
+      pageNum: pageNum.value,
+      pageSize: pageSize.value,
+      itemName: keyword.value.trim(),
+      isActive: 1,
+      deviceLedgerId: filters.deviceLedgerId,
+      frequencyType: filters.frequencyType,
+      includeCommon: true,
+    });
+    if (code === 200) {
+      items.value = data?.records || [];
+      total.value = Number(data?.total || 0);
+    }
+  } finally {
+    loading.value = false;
+  }
+};
+
+const search = () => {
+  pageNum.value = 1;
+  load();
+};
+const resetFilters = () => {
+  filters.deviceLedgerId = undefined;
+  filters.frequencyType = "";
+  keyword.value = "";
+  search();
+};
+const handleSizeChange = () => {
+  pageNum.value = 1;
+  load();
+};
+
+const reset = () =>
+  Object.assign(form, {
+    id: undefined,
+    itemProject: "",
+    itemName: "",
+    deviceLedgerId: undefined,
+    frequencyType: "",
+    sortNum: 0,
+    isActive: 1,
+    remarks: "",
+  });
+const openAdd = () => {
+  reset();
+  dialogVisible.value = true;
+};
+const openEdit = (row) => {
+  Object.assign(form, { ...row });
+  dialogVisible.value = true;
+};
+
+const save = async () => {
+  if (
+    !(await formRef.value
+      ?.validate()
+      .then(() => true)
+      .catch(() => false))
+  )
+    return;
+  saving.value = true;
+  try {
+    const { code } = form.id
+      ? await editMaintenanceItem({ ...form })
+      : await addMaintenanceItem({ ...form });
+    if (code === 200) {
+      ElMessage.success("淇濆瓨鎴愬姛");
+      dialogVisible.value = false;
+      pageNum.value = 1;
+      await load();
+    }
+  } finally {
+    saving.value = false;
+  }
+};
+
+const removeItem = async (row) => {
+  try {
+    await ElMessageBox.confirm(`纭畾鍒犻櫎淇濆吇鍐呭鈥�${row.itemName}鈥濆悧锛焋, "鎻愮ず", {
+      type: "warning",
+    });
+    const { code } = await deleteMaintenanceItem(row.id);
+    if (code === 200) {
+      ElMessage.success("鍒犻櫎鎴愬姛");
+      await load();
+    }
+  } catch (_) {
+    // 鐢ㄦ埛鍙栨秷
+  }
+};
+
+onMounted(async () => {
+  const { data } = await getDeviceLedger();
+  deviceOptions.value = data || [];
+  await load();
+});
+</script>
+
+<style scoped>
+.actions {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 10px;
+}
+.pagination-wrap {
+  display: flex;
+  justify-content: flex-end;
+  padding-top: 12px;
+}
+</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/MaintenanceItemSelector.vue b/src/views/equipmentManagement/upkeep/Form/MaintenanceItemSelector.vue
new file mode 100644
index 0000000..a485f24
--- /dev/null
+++ b/src/views/equipmentManagement/upkeep/Form/MaintenanceItemSelector.vue
@@ -0,0 +1,181 @@
+<template>
+  <el-dialog
+    v-model="dialogVisible"
+    title="閫夋嫨淇濆吇椤圭洰"
+    width="760px"
+    append-to-body
+    destroy-on-close
+  >
+    <div class="selector-toolbar">
+      <el-input
+        v-model="keyword"
+        clearable
+        placeholder="鎸変繚鍏婚」鐩悳绱�"
+        @keyup.enter="search"
+        @clear="search"
+      />
+      <el-button type="primary" @click="search">鎼滅储</el-button>
+    </div>
+
+    <el-table v-loading="loading" :data="rows" border height="360">
+      <el-table-column label="閫夋嫨" width="70" align="center">
+        <template #default="{ row }">
+          <el-checkbox
+            :model-value="isSelected(row.id)"
+            @change="(checked) => toggleItem(row, checked)"
+          />
+        </template>
+      </el-table-column>
+      <el-table-column type="index" label="搴忓彿" width="70" />
+      <el-table-column label="绫诲瀷" width="90" align="center">
+        <template #default="{ row }">
+          <el-tag :type="row.deviceLedgerId ? 'primary' : 'info'" size="small">{{
+            row.deviceLedgerId ? "鏈澶�" : "閫氱敤"
+          }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="itemProject" label="淇濆吇椤圭洰" min-width="300" show-overflow-tooltip />
+      <el-table-column label="棰戠巼" width="110" align="center">
+        <template #default="{ row }">
+          <el-tag :type="row.frequencyType === 'ALL' ? 'info' : 'success'" size="small">{{
+            frequencyLabel(row.frequencyType)
+          }}</el-tag>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <div class="selector-pagination">
+      <el-pagination
+        v-model:current-page="pageNum"
+        v-model:page-size="pageSize"
+        :page-sizes="[10, 20, 50]"
+        :total="total"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="load"
+      />
+    </div>
+
+    <template #footer>
+      <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+      <el-button type="primary" @click="confirm">纭畾閫夋嫨</el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { computed, ref, watch } from "vue";
+import { getMaintenanceItemPage } from "@/api/equipmentManagement/upkeep";
+
+const props = defineProps({
+  visible: { type: Boolean, default: false },
+  selectedItems: { type: Array, default: () => [] },
+  deviceLedgerId: { type: [Number, String], default: undefined },
+  frequencyType: { type: String, default: "" },
+});
+const emit = defineEmits(["update:visible", "confirm"]);
+
+const dialogVisible = computed({
+  get: () => props.visible,
+  set: (value) => emit("update:visible", value),
+});
+const rows = ref([]);
+const loading = ref(false);
+const keyword = ref("");
+const pageNum = ref(1);
+const pageSize = ref(10);
+const total = ref(0);
+const selected = ref(new Map());
+const selectedList = computed(() => Array.from(selected.value.values()));
+const frequencyLabel = (value) =>
+  ({ DAILY: "姣忔棩", WEEKLY: "姣忓懆", MONTHLY: "姣忔湀", QUARTERLY: "姣忓搴�", ALL: "閫氱敤棰戠巼" }[
+    value
+  ] ||
+  value ||
+  "閫氱敤棰戠巼");
+
+watch(
+  () => props.visible,
+  (visible) => {
+    if (!visible) return;
+    keyword.value = "";
+    pageNum.value = 1;
+    selected.value = new Map((props.selectedItems || []).map((item) => [String(item.id), item]));
+    if (props.deviceLedgerId && props.frequencyType) load();
+    else {
+      rows.value = [];
+      total.value = 0;
+    }
+  }
+);
+watch(
+  () => [props.deviceLedgerId, props.frequencyType],
+  ([deviceId, frequency]) => {
+    if (!props.visible) return;
+    selected.value = new Map();
+    rows.value = [];
+    total.value = 0;
+    if (deviceId && frequency) {
+      pageNum.value = 1;
+      load();
+    }
+  }
+);
+
+const load = async () => {
+  loading.value = true;
+  try {
+    const { code, data } = await getMaintenanceItemPage({
+      pageNum: pageNum.value,
+      pageSize: pageSize.value,
+      itemProject: keyword.value.trim(),
+      isActive: 1,
+      deviceLedgerId: props.deviceLedgerId,
+      frequencyType: props.frequencyType,
+      includeCommon: true,
+    });
+    if (code === 200) {
+      rows.value = data?.records || [];
+      total.value = Number(data?.total || 0);
+    }
+  } finally {
+    loading.value = false;
+  }
+};
+
+const search = () => {
+  pageNum.value = 1;
+  load();
+};
+const handleSizeChange = () => {
+  pageNum.value = 1;
+  load();
+};
+const isSelected = (id) => selected.value.has(String(id));
+const toggleItem = (item, checked) => {
+  const next = new Map(selected.value);
+  if (checked) next.set(String(item.id), item);
+  else next.delete(String(item.id));
+  selected.value = next;
+};
+const confirm = () => {
+  emit("confirm", selectedList.value);
+  dialogVisible.value = false;
+};
+</script>
+
+<style scoped>
+.selector-toolbar {
+  display: flex;
+  gap: 10px;
+  margin-bottom: 14px;
+}
+.selector-toolbar .el-input {
+  max-width: 420px;
+}
+.selector-pagination {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 14px;
+}
+</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue b/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
index 0fcccb2..fd71e1a 100644
--- a/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
+++ b/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
@@ -1,71 +1,122 @@
 <template>
-  <FormDialog v-model="visible"
-              :title="'璁惧淇濆吇'"
-              width="500px"
-              @confirm="sendForm"
-              @cancel="handleCancel"
-              @close="handleClose">
-    <el-form :model="form"
-             label-width="100px">
+  <FormDialog
+    v-model="visible"
+    :title="'璁惧淇濆吇'"
+    width="1080px"
+    @confirm="sendForm"
+    @cancel="handleCancel"
+    @close="handleClose"
+  >
+    <el-form :model="form" label-width="100px">
       <el-form-item label="瀹為檯淇濆吇浜�">
-        <el-input v-model="form.maintenanceActuallyName"
-                  placeholder="璇疯緭鍏ュ疄闄呬繚鍏讳汉"></el-input>
+        <el-input v-model="form.maintenanceActuallyName" placeholder="璇疯緭鍏ュ疄闄呬繚鍏讳汉"></el-input>
       </el-form-item>
       <el-form-item label="瀹為檯淇濆吇鏃ユ湡">
-        <el-date-picker v-model="form.maintenanceActuallyTime"
-                        placeholder="璇烽�夋嫨瀹為檯淇濆吇鏃ユ湡"
-                        format="YYYY-MM-DD HH:mm:ss"
-                        value-format="YYYY-MM-DD HH:mm:ss"
-                        type="datetime"
-                        clearable
-                        style="width: 100%" />
+        <el-date-picker
+          v-model="form.maintenanceActuallyTime"
+          placeholder="璇烽�夋嫨瀹為檯淇濆吇鏃ユ湡"
+          format="YYYY-MM-DD HH:mm:ss"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="datetime"
+          clearable
+          style="width: 100%"
+        />
+      </el-form-item>
+      <el-form-item label="淇濆吇鍐呭" required>
+        <div v-if="form.maintenanceItems.length" class="maintenance-checklist">
+          <div class="maintenance-checklist__header">
+            <span
+              >宸插畬鎴� {{ completedCount }} /
+              {{ form.maintenanceItems.length }} 椤癸紝璇峰嬀閫夊凡淇濆吇鐨勫唴瀹�</span
+            >
+            <el-button link type="primary" @click="toggleAll">{{
+              completedCount === form.maintenanceItems.length ? "鍏ㄩ儴鍙栨秷" : "鍏ㄩ儴鍕鹃��"
+            }}</el-button>
+          </div>
+          <div
+            v-for="(item, index) in form.maintenanceItems"
+            :key="item.id"
+            class="maintenance-checklist__item"
+            :class="{ 'is-done': item.itemStatus === 1 }"
+          >
+            <el-checkbox
+              class="maintenance-checklist__check"
+              :model-value="item.itemStatus === 1"
+              @change="(checked) => (item.itemStatus = checked ? 1 : 0)"
+              >宸插畬鎴�</el-checkbox
+            >
+            <div class="maintenance-checklist__body">
+              <div class="maintenance-checklist__content">
+                <span class="maintenance-checklist__number">{{ index + 1 }}.</span
+                ><span>{{ item.itemName || item.itemProject || "鏈~鍐欎繚鍏诲唴瀹�" }}</span>
+              </div>
+            </div>
+          </div>
+        </div>
+        <el-empty v-else description="璇ヤ繚鍏昏褰曟病鏈変繚鍏诲唴瀹�" :image-size="60" />
       </el-form-item>
       <el-form-item label="淇濆吇鐘舵��">
         <el-select v-model="form.status">
-          <el-option label="寰呬繚鍏�"
-                     :value="0"></el-option>
-          <el-option label="瀹岀粨"
-                     :value="1"></el-option>
-          <el-option label="澶辫触"
-                     :value="2"></el-option>
+          <el-option label="寰呬繚鍏�" :value="0"></el-option>
+          <el-option label="瀹岀粨" :value="1"></el-option>
+          <el-option label="澶辫触" :value="2"></el-option>
         </el-select>
       </el-form-item>
       <el-form-item label="淇濆吇缁撴灉">
-        <el-input v-model="form.maintenanceResult"
-                  placeholder="璇疯緭鍏ヤ繚鍏荤粨鏋�"
-                  type="text" />
+        <el-input v-model="form.maintenanceResult" placeholder="璇疯緭鍏ヤ繚鍏荤粨鏋�" type="text" />
       </el-form-item>
       <el-form-item label="璁惧澶囦欢">
-        <el-select v-model="form.sparePartsIds"
-                   :loading="loadingSparePartOptions"
-                   placeholder="璇烽�夋嫨璁惧澶囦欢"
-                   multiple
-                   filterable>
-          <el-option v-for="item in sparePartOptions"
-                     :key="item.id"
-                     :label="item.name"
-                     :value="item.id" />
+        <el-select
+          v-model="form.sparePartsIds"
+          :loading="loadingSparePartOptions"
+          placeholder="璇烽�夋嫨璁惧澶囦欢"
+          multiple
+          filterable
+        >
+          <el-option
+            v-for="item in sparePartOptions"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id"
+          />
         </el-select>
       </el-form-item>
-      <el-form-item v-if="selectedSpareParts.length"
-                    label="棰嗙敤鏁伴噺">
+      <el-form-item v-if="selectedSpareParts.length" label="棰嗙敤鏁伴噺">
         <div style="width: 100%">
-          <div v-for="item in selectedSpareParts"
-               :key="item.id"
-               style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;">
-            <div style="flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
+          <div
+            v-for="item in selectedSpareParts"
+            :key="item.id"
+            style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px"
+          >
+            <div
+              style="
+                flex: 1;
+                min-width: 0;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                white-space: nowrap;
+              "
+            >
               {{ item.name }}
-              <span v-if="item.quantity !== null && item.quantity !== undefined"
-                    style="color: #909399;">
+              <span
+                v-if="item.quantity !== null && item.quantity !== undefined"
+                style="color: #909399"
+              >
                 锛堝簱瀛橈細{{ item.quantity }}锛�
               </span>
             </div>
-            <el-input-number v-model="sparePartQtyMap[item.id]"
-                             :min="1"
-                             :max="item.quantity !== null && item.quantity !== undefined ? Number(item.quantity) : undefined"
-                             :step="1"
-                             controls-position="right"
-                             style="width: 180px" />
+            <el-input-number
+              v-model="sparePartQtyMap[item.id]"
+              :min="1"
+              :max="
+                item.quantity !== null && item.quantity !== undefined
+                  ? Number(item.quantity)
+                  : undefined
+              "
+              :step="1"
+              controls-position="right"
+              style="width: 180px"
+            />
           </div>
         </div>
       </el-form-item>
@@ -77,177 +128,256 @@
 </template>
 
 <script setup>
-  import FormDialog from "@/components/Dialog/FormDialog.vue";
-  import FileUpload from "@/components/AttachmentUpload/file/index.vue";
-  import { addMaintenance } from "@/api/equipmentManagement/upkeep";
-  import useFormData from "@/hooks/useFormData";
-  import dayjs from "dayjs";
-  import useUserStore from "@/store/modules/user";
-  import { ElMessage } from "element-plus";
-  import { computed, ref, nextTick, getCurrentInstance } from "vue";
-  import { getSparePartsList } from "@/api/equipmentManagement/spareParts.js";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import FileUpload from "@/components/AttachmentUpload/file/index.vue";
+import { addMaintenance } from "@/api/equipmentManagement/upkeep";
+import useFormData from "@/hooks/useFormData";
+import dayjs from "dayjs";
+import useUserStore from "@/store/modules/user";
+import { ElMessage } from "element-plus";
+import { computed, ref, nextTick, getCurrentInstance } from "vue";
+import { getSparePartsList } from "@/api/equipmentManagement/spareParts.js";
 
-  defineOptions({
-    name: "淇濆吇妯℃�佹",
-  });
+defineOptions({
+  name: "淇濆吇妯℃�佹",
+});
 
-  const emits = defineEmits(["ok"]);
+const emits = defineEmits(["ok"]);
 
-  const { proxy } = getCurrentInstance();
-  // 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
-  const planId = ref();
-  const visible = ref(false);
-  const loading = ref(false);
-  const userStore = useUserStore();
+const { proxy } = getCurrentInstance();
+// 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
+const planId = ref();
+const visible = ref(false);
+const loading = ref(false);
+const userStore = useUserStore();
 
-  const { form, resetForm } = useFormData({
-    maintenanceActuallyName: undefined, // 瀹為檯淇濆吇浜�
-    maintenanceActuallyTime: undefined, // 瀹為檯淇濆吇鏃ユ湡
-    maintenanceResult: undefined, // 淇濆吇缁撴灉
-    status: 0, // 淇濆吇鐘舵��
-    sparePartsIds: [],
-    storageBlobDTOs: [],
-  });
+const { form, resetForm } = useFormData({
+  maintenanceActuallyName: undefined, // 瀹為檯淇濆吇浜�
+  maintenanceActuallyTime: undefined, // 瀹為檯淇濆吇鏃ユ湡
+  maintenanceResult: undefined, // 淇濆吇缁撴灉
+  status: 0, // 淇濆吇鐘舵��
+  maintenanceItems: [],
+  sparePartsIds: [],
+  storageBlobDTOs: [],
+});
 
-  const sparePartOptions = ref([]);
-  const loadingSparePartOptions = ref(true);
-  const sparePartQtyMap = ref({});
+const sparePartOptions = ref([]);
+const loadingSparePartOptions = ref(true);
+const sparePartQtyMap = ref({});
 
-  const selectedSpareParts = computed(() => {
-    const ids = Array.isArray(form.sparePartsIds) ? form.sparePartsIds : [];
-    const set = new Set(ids.map(i => String(i)));
-    return (sparePartOptions.value || []).filter(p => set.has(String(p.id)));
-  });
+const selectedSpareParts = computed(() => {
+  const ids = Array.isArray(form.sparePartsIds) ? form.sparePartsIds : [];
+  const set = new Set(ids.map((i) => String(i)));
+  return (sparePartOptions.value || []).filter((p) => set.has(String(p.id)));
+});
 
-  const setForm = data => {
-    form.maintenanceActuallyName =
-      data.maintenanceActuallyName ?? userStore.nickName;
-    form.maintenanceActuallyTime = data.maintenanceActuallyTime
-      ? dayjs(data.maintenanceActuallyTime).format("YYYY-MM-DD HH:mm:ss")
-      : dayjs().format("YYYY-MM-DD HH:mm:ss");
-    form.maintenanceResult = data.maintenanceResult;
-    form.status = 1; // 榛樿鐘舵�佷负瀹岀粨
-    // multiple 閫夋嫨鍣ㄨ姹傛暟缁勶紱鍚庣甯歌繑鍥� "1,2,3"
-    if (Array.isArray(data?.sparePartsIds)) {
-      form.sparePartsIds = data.sparePartsIds
-        .map(v => Number(v))
-        .filter(v => Number.isFinite(v));
-    } else if (typeof data?.sparePartsIds === "string") {
-      form.sparePartsIds = data.sparePartsIds
-        .split(",")
-        .map(s => Number(String(s).trim()))
-        .filter(v => Number.isFinite(v));
-    } else if (typeof data?.sparePartsIds === "number") {
-      form.sparePartsIds = [data.sparePartsIds];
-    } else {
-      form.sparePartsIds = [];
+const completedCount = computed(
+  () => form.maintenanceItems.filter((item) => item.itemStatus === 1).length
+);
+const toggleAll = () => {
+  const status = completedCount.value === form.maintenanceItems.length ? 0 : 1;
+  form.maintenanceItems.forEach((item) => (item.itemStatus = status));
+};
+
+const setForm = (data) => {
+  form.maintenanceActuallyName = data.maintenanceActuallyName ?? userStore.nickName;
+  form.maintenanceActuallyTime = data.maintenanceActuallyTime
+    ? dayjs(data.maintenanceActuallyTime).format("YYYY-MM-DD HH:mm:ss")
+    : dayjs().format("YYYY-MM-DD HH:mm:ss");
+  form.maintenanceResult = data.maintenanceResult;
+  form.status = 1; // 榛樿鐘舵�佷负瀹岀粨
+  form.maintenanceItems = (data.maintenanceItems || []).map((item) => ({
+    ...item,
+    itemStatus: Number(item.itemStatus || 0),
+  }));
+  // multiple 閫夋嫨鍣ㄨ姹傛暟缁勶紱鍚庣甯歌繑鍥� "1,2,3"
+  if (Array.isArray(data?.sparePartsIds)) {
+    form.sparePartsIds = data.sparePartsIds.map((v) => Number(v)).filter((v) => Number.isFinite(v));
+  } else if (typeof data?.sparePartsIds === "string") {
+    form.sparePartsIds = data.sparePartsIds
+      .split(",")
+      .map((s) => Number(String(s).trim()))
+      .filter((v) => Number.isFinite(v));
+  } else if (typeof data?.sparePartsIds === "number") {
+    form.sparePartsIds = [data.sparePartsIds];
+  } else {
+    form.sparePartsIds = [];
+  }
+  form.storageBlobDTOs = data.storageBlobVOs || [];
+};
+
+/**
+ * @desc 淇濆瓨淇濆吇
+ */
+const sendForm = async () => {
+  loading.value = true;
+  try {
+    if (!form.maintenanceItems.length) {
+      ElMessage.warning("褰撳墠璁板綍娌℃湁淇濆吇鍐呭锛岃鍏堢紪杈戜繚鍏讳换鍔�");
+      return;
     }
-    form.storageBlobDTOs = data.storageBlobVOs || [];
-  };
-
-  /**
-   * @desc 淇濆瓨淇濆吇
-   */
-  const sendForm = async () => {
-    loading.value = true;
-    try {
-      // 棰嗙敤鏁伴噺鏍¢獙
-      if (Array.isArray(form.sparePartsIds) && form.sparePartsIds.length > 0) {
-        for (const partId of form.sparePartsIds) {
-          const qty = Number(sparePartQtyMap.value?.[partId]);
-          if (!Number.isFinite(qty) || qty <= 0) {
-            proxy?.$modal?.msgError?.("璇峰~鍐欏浠堕鐢ㄦ暟閲�");
+    // 棰嗙敤鏁伴噺鏍¢獙
+    if (Array.isArray(form.sparePartsIds) && form.sparePartsIds.length > 0) {
+      for (const partId of form.sparePartsIds) {
+        const qty = Number(sparePartQtyMap.value?.[partId]);
+        if (!Number.isFinite(qty) || qty <= 0) {
+          proxy?.$modal?.msgError?.("璇峰~鍐欏浠堕鐢ㄦ暟閲�");
+          return;
+        }
+        const part = sparePartOptions.value.find((p) => String(p.id) === String(partId));
+        const stock = part?.quantity;
+        if (stock !== null && stock !== undefined && Number.isFinite(Number(stock))) {
+          if (qty > Number(stock)) {
+            proxy?.$modal?.msgError?.(
+              `澶囦欢銆�${part?.name || ""}銆嶉鐢ㄦ暟閲忎笉鑳借秴杩囧簱瀛橈紙${stock}锛塦
+            );
             return;
           }
-          const part = sparePartOptions.value.find(
-            p => String(p.id) === String(partId)
-          );
-          const stock = part?.quantity;
-          if (
-            stock !== null &&
-            stock !== undefined &&
-            Number.isFinite(Number(stock))
-          ) {
-            if (qty > Number(stock)) {
-              proxy?.$modal?.msgError?.(
-                `澶囦欢銆�${part?.name || ""}銆嶉鐢ㄦ暟閲忎笉鑳借秴杩囧簱瀛橈紙${stock}锛塦
-              );
-              return;
-            }
-          }
         }
       }
-      const data = {
-        id: planId.value,
-        ...form,
-        sparePartsIds: form.sparePartsIds ? form.sparePartsIds.join(",") : "",
-        sparePartsQty: form.sparePartsIds
-          ? form.sparePartsIds
-              .map(id => sparePartQtyMap.value?.[id] ?? 1)
-              .join(",")
-          : "",
-        sparePartsUseList: form.sparePartsIds
-          ? form.sparePartsIds.map(id => ({
-              id,
-              quantity: sparePartQtyMap.value?.[id] ?? 1,
-            }))
-          : [],
-      };
-      const { code } = await addMaintenance(data);
-      if (code == 200) {
-        ElMessage.success("淇濆吇鎴愬姛");
-        emits("ok");
-        resetForm();
-        sparePartQtyMap.value = {};
-        visible.value = false;
-      }
-    } finally {
-      loading.value = false;
     }
-  };
+    const data = {
+      id: planId.value,
+      ...form,
+      maintenanceItems: form.maintenanceItems.map((item) => ({
+        id: item.id,
+        itemStatus: item.itemStatus,
+      })),
+      sparePartsIds: form.sparePartsIds ? form.sparePartsIds.join(",") : "",
+      sparePartsQty: form.sparePartsIds
+        ? form.sparePartsIds.map((id) => sparePartQtyMap.value?.[id] ?? 1).join(",")
+        : "",
+      sparePartsUseList: form.sparePartsIds
+        ? form.sparePartsIds.map((id) => ({
+            id,
+            quantity: sparePartQtyMap.value?.[id] ?? 1,
+          }))
+        : [],
+    };
+    const { code } = await addMaintenance(data);
+    if (code == 200) {
+      ElMessage.success("淇濆吇鎴愬姛");
+      emits("ok");
+      resetForm();
+      sparePartQtyMap.value = {};
+      visible.value = false;
+    }
+  } finally {
+    loading.value = false;
+  }
+};
 
-  const fetchSparePartOptions = () => {
-    loadingSparePartOptions.value = true;
-    // 鍜屽浠剁鐞嗛〉涓�鑷达細/spareParts/listPage 鈫� res.data.records
-    getSparePartsList({ current: 1, size: 1000 })
-      .then(res => {
-        if (res.code === 200) {
-          sparePartOptions.value = res?.data?.records || [];
-        } else {
-          sparePartOptions.value = [];
-        }
-      })
-      .catch(() => {
+const fetchSparePartOptions = () => {
+  loadingSparePartOptions.value = true;
+  // 鍜屽浠剁鐞嗛〉涓�鑷达細/spareParts/listPage 鈫� res.data.records
+  getSparePartsList({ current: 1, size: 1000 })
+    .then((res) => {
+      if (res.code === 200) {
+        sparePartOptions.value = res?.data?.records || [];
+      } else {
         sparePartOptions.value = [];
-      })
-      .finally(() => {
-        loadingSparePartOptions.value = false;
-      });
-  };
+      }
+    })
+    .catch(() => {
+      sparePartOptions.value = [];
+    })
+    .finally(() => {
+      loadingSparePartOptions.value = false;
+    });
+};
 
-  const handleCancel = () => {
-    resetForm();
-    sparePartQtyMap.value = {};
-    visible.value = false;
-  };
+const handleCancel = () => {
+  resetForm();
+  sparePartQtyMap.value = {};
+  visible.value = false;
+};
 
-  const handleClose = () => {
-    resetForm();
-    sparePartQtyMap.value = {};
-    visible.value = false;
-  };
+const handleClose = () => {
+  resetForm();
+  sparePartQtyMap.value = {};
+  visible.value = false;
+};
 
-  const open = async (id, row) => {
-    planId.value = id; // 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
-    visible.value = true;
-    await nextTick();
-    fetchSparePartOptions();
-    setForm(row);
-  };
+const open = async (id, row) => {
+  planId.value = id; // 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
+  visible.value = true;
+  await nextTick();
+  fetchSparePartOptions();
+  setForm(row);
+};
 
-  defineExpose({
-    open,
-  });
+defineExpose({
+  open,
+});
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.maintenance-checklist {
+  width: 100%;
+  border: 1px solid #bfc7cf;
+  background: #fff;
+  overflow: hidden;
+}
+.maintenance-checklist__header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 11px 16px;
+  background: #f3f5f7;
+  border-bottom: 1px solid #bfc7cf;
+  color: #303946;
+  font-size: 14px;
+  font-weight: 600;
+}
+.maintenance-checklist__item {
+  display: grid;
+  grid-template-columns: 42px minmax(0, 1fr) 110px;
+  align-items: start;
+  gap: 12px;
+  padding: 15px 16px;
+  border-bottom: 1px solid #d8dde2;
+}
+.maintenance-checklist__item:last-child {
+  border-bottom: none;
+}
+.maintenance-checklist__item.is-done {
+  background: #f6faf5;
+}
+.maintenance-checklist__check {
+  grid-column: 3;
+  grid-row: 1;
+  justify-self: center;
+  margin: 0;
+}
+.maintenance-checklist__body {
+  grid-column: 1 / 3;
+  grid-row: 1;
+  min-width: 0;
+}
+.maintenance-checklist__content {
+  display: grid;
+  grid-template-columns: 32px minmax(0, 1fr);
+  line-height: 1.75;
+  color: #303946;
+  white-space: pre-wrap;
+  overflow-wrap: anywhere;
+}
+.maintenance-checklist__number {
+  color: #606a75;
+  font-weight: 600;
+}
+:deep(.el-dialog) {
+  max-width: calc(100vw - 32px);
+}
+:deep(.el-dialog__body) {
+  max-height: calc(100vh - 190px);
+  overflow-y: auto;
+}
+@media (max-width: 720px) {
+  .maintenance-checklist__item {
+    grid-template-columns: 30px minmax(0, 1fr) 78px;
+    gap: 8px;
+    padding: 12px 8px;
+  }
+}
+</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/PlanModal.vue b/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
index 29e218a..acb8f7b 100644
--- a/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
+++ b/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
@@ -2,7 +2,7 @@
   <FormDialog
     v-model="visible"
     :title="id ? '缂栬緫璁惧淇濆吇璁″垝' : '鏂板璁惧淇濆吇璁″垝'"
-    width="500px"
+    width="960px"
     @confirm="sendForm"
     @cancel="handleCancel"
     @close="handleClose"
@@ -26,18 +26,46 @@
         </el-select>
       </el-form-item>
       <el-form-item label="瑙勬牸鍨嬪彿">
-        <el-input
-          v-model="form.deviceModel"
-          placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
-          disabled
-        />
+        <el-input v-model="form.deviceModel" placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�" disabled />
       </el-form-item>
-      <el-form-item label="淇濆吇椤圭洰">
-        <el-input
-            v-model="form.machineryCategory"
-            type="textarea"
-            placeholder="璇疯緭鍏ヤ繚鍏婚」鐩�"
-        />
+      <el-form-item label="淇濆吇棰戠巼">
+        <el-select
+          v-model="form.frequencyType"
+          placeholder="璇峰厛閫夋嫨淇濆吇棰戠巼"
+          @change="clearSelectedItems"
+        >
+          <el-option label="姣忔棩" value="DAILY" />
+          <el-option label="姣忓懆" value="WEEKLY" />
+          <el-option label="姣忔湀" value="MONTHLY" />
+          <el-option label="姣忓搴�" value="QUARTERLY" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="淇濆吇鍐呭">
+        <div class="maintenance-selection">
+          <el-button
+            type="primary"
+            plain
+            :disabled="!form.deviceLedgerId || !form.frequencyType"
+            @click="itemSelectorVisible = true"
+            >閫夋嫨淇濆吇鍐呭</el-button
+          >
+          <div v-if="selectedMaintenanceItems.length" class="paper-list">
+            <div class="paper-list__heading">
+              <strong>淇濆吇椤圭洰娓呭崟</strong>
+              <span>鍏� {{ selectedMaintenanceItems.length }} 椤�</span>
+            </div>
+            <div
+              v-for="(item, index) in selectedMaintenanceItems"
+              :key="item.id"
+              class="paper-list__row"
+            >
+              <span class="paper-list__number">{{ index + 1 }}</span>
+              <span class="paper-list__content">{{ item.itemName }}</span>
+              <el-button link type="danger" @click="removeMaintenanceItem(item.id)">绉婚櫎</el-button>
+            </div>
+          </div>
+          <el-empty v-else description="閫夋嫨璁惧鍜岄鐜囧悗锛屾坊鍔犳湰璁″垝鐨勪繚鍏婚」鐩�" :image-size="54" />
+        </div>
       </el-form-item>
       <el-form-item label="褰曞叆浜�">
         <el-select
@@ -64,11 +92,7 @@
         </el-select>
       </el-form-item>
       <el-form-item label="淇濆吇浜�">
-        <el-input
-          v-model="form.maintenancePerson"
-          placeholder="璇疯緭鍏ヤ繚鍏讳汉濮撳悕"
-          clearable
-        />
+        <el-input v-model="form.maintenancePerson" placeholder="璇疯緭鍏ヤ繚鍏讳汉濮撳悕" clearable />
       </el-form-item>
       <el-form-item label="璁″垝淇濆吇鏃ユ湡">
         <el-date-picker
@@ -90,22 +114,26 @@
       </el-row>
     </el-form>
   </FormDialog>
+  <MaintenanceItemSelector
+    v-model:visible="itemSelectorVisible"
+    :selected-items="selectedMaintenanceItems"
+    :device-ledger-id="form.deviceLedgerId"
+    :frequency-type="form.frequencyType"
+    @confirm="applyMaintenanceItems"
+  />
 </template>
 
 <script setup>
 import FormDialog from "@/components/Dialog/FormDialog.vue";
-import {
-  addUpkeep,
-  editUpkeep,
-  getUpkeepById,
-} from "@/api/equipmentManagement/upkeep";
+import { addUpkeep, editUpkeep, getUpkeepById } from "@/api/equipmentManagement/upkeep";
 import { ElMessage } from "element-plus";
 import useFormData from "@/hooks/useFormData";
 import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
-import { onMounted } from "vue";
+import { computed, onMounted } from "vue";
 import dayjs from "dayjs";
 import { userListNoPage } from "@/api/system/user.js";
 import FileUpload from "@/components/AttachmentUpload/file/index.vue";
+import MaintenanceItemSelector from "./MaintenanceItemSelector.vue";
 
 defineOptions({
   name: "璁惧淇濆吇鏂板璁″垝",
@@ -116,8 +144,10 @@
 const id = ref();
 const visible = ref(false);
 const loading = ref(false);
+const itemSelectorVisible = ref(false);
 
 const deviceOptions = ref([]);
+const maintenanceItemOptions = ref([]);
 const loadDeviceName = async () => {
   const { data } = await getDeviceLedger();
   deviceOptions.value = data;
@@ -130,14 +160,39 @@
   maintenancePlanTime: undefined, // 璁″垝淇濆吇鏃ユ湡
   createUser: undefined, // 褰曞叆浜�
   status: 0, //淇濅慨鐘舵��
-  machineryCategory: undefined,
+  maintenanceItemIds: [],
+  frequencyType: "",
   storageBlobDTOs: [],
   maintenancePerson: undefined, // 淇濆吇浜�
 });
 
+const selectedMaintenanceItems = computed(() => {
+  const ids = new Set((form.maintenanceItemIds || []).map(String));
+  return maintenanceItemOptions.value.filter((item) => ids.has(String(item.id)));
+});
+const applyMaintenanceItems = (items) => {
+  maintenanceItemOptions.value = items;
+  form.maintenanceItemIds = items.map((item) => item.id);
+};
+const clearSelectedItems = () => {
+  form.maintenanceItemIds = [];
+  maintenanceItemOptions.value = [];
+};
+const removeMaintenanceItem = (id) => {
+  form.maintenanceItemIds = form.maintenanceItemIds.filter(
+    (itemId) => String(itemId) !== String(id)
+  );
+  maintenanceItemOptions.value = maintenanceItemOptions.value.filter(
+    (item) => String(item.id) !== String(id)
+  );
+};
+
 const setDeviceModel = (deviceId) => {
   const option = deviceOptions.value.find((item) => item.id === deviceId);
-  form.deviceModel = option.deviceModel;
+  if (option) {
+    form.deviceModel = option.deviceModel;
+    clearSelectedItems();
+  }
 };
 
 /**
@@ -146,16 +201,21 @@
  */
 const setForm = (data) => {
   form.deviceLedgerId = data.deviceLedgerId;
+  form.frequencyType = data.frequencyType;
   form.deviceName = data.deviceName;
   form.deviceModel = data.deviceModel;
   form.createUser = Number(data.createUser);
   form.status = data.status;
-  form.machineryCategory = data.machineryCategory;
+  form.maintenanceItemIds =
+    data.maintenanceItemIds || data.maintenanceItems?.map((item) => item.maintenanceItemId) || [];
+  maintenanceItemOptions.value = (data.maintenanceItems || []).map((item) => ({
+    id: item.maintenanceItemId,
+    itemName: item.itemName,
+    isActive: item.isActive,
+  }));
   form.maintenancePerson = data.maintenancePerson;
   if (data.maintenancePlanTime) {
-    form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format(
-      "YYYY-MM-DD HH:mm:ss"
-    );
+    form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format("YYYY-MM-DD HH:mm:ss");
   }
   form.storageBlobDTOs = data.storageBlobVOs || [];
 };
@@ -179,6 +239,14 @@
 };
 
 const sendForm = async () => {
+  if (!form.deviceLedgerId || !form.frequencyType) {
+    ElMessage.warning("璇烽�夋嫨璁惧鍜屼繚鍏婚鐜�");
+    return;
+  }
+  if (!form.maintenanceItemIds?.length) {
+    ElMessage.warning("璇烽�夋嫨鑷冲皯涓�涓繚鍏婚」鐩�");
+    return;
+  }
   loading.value = true;
   try {
     const { code } = id.value
@@ -195,11 +263,13 @@
 };
 
 const handleCancel = () => {
+  itemSelectorVisible.value = false;
   resetForm();
   visible.value = false;
 };
 
 const handleClose = () => {
+  itemSelectorVisible.value = false;
   resetForm();
   visible.value = false;
 };
@@ -207,6 +277,7 @@
 const openModal = () => {
   id.value = undefined;
   visible.value = true;
+  maintenanceItemOptions.value = [];
 };
 
 defineExpose({
@@ -215,4 +286,61 @@
 });
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.maintenance-selection {
+  width: 100%;
+}
+.paper-list {
+  margin-top: 12px;
+  border: 1px solid #cbd2d9;
+  background: #fff;
+}
+.paper-list__heading {
+  display: flex;
+  justify-content: space-between;
+  padding: 10px 14px;
+  border-bottom: 1px solid #cbd2d9;
+  background: #f5f7fa;
+  color: #303946;
+}
+.paper-list__heading span {
+  color: #606a75;
+  font-size: 13px;
+  font-weight: normal;
+}
+.paper-list__row {
+  display: grid;
+  grid-template-columns: 38px minmax(0, 1fr) 52px;
+  align-items: start;
+  gap: 10px;
+  padding: 12px 14px;
+  border-bottom: 1px solid #e1e5e9;
+}
+.paper-list__row:last-child {
+  border-bottom: 0;
+}
+.paper-list__number {
+  color: #596575;
+  text-align: center;
+}
+.paper-list__content {
+  color: #303946;
+  line-height: 1.7;
+  white-space: pre-wrap;
+  overflow-wrap: anywhere;
+}
+:deep(.el-dialog) {
+  max-width: calc(100vw - 32px);
+}
+:deep(.el-dialog__body) {
+  max-height: calc(100vh - 180px);
+  overflow-y: auto;
+}
+@media (max-width: 720px) {
+  .paper-list__row {
+    grid-template-columns: 28px minmax(0, 1fr) 42px;
+    gap: 6px;
+    padding: 10px 8px;
+  }
+}
+</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue b/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue
index 074628c..3c60c3a 100644
--- a/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue
+++ b/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue
@@ -1,99 +1,191 @@
 <template>
-	<FormDialog
-		v-model="dialogVisitable"
-		title="淇濆吇璁板綍璇︽儏"
-		width="800px"
-		operation-type="detail"
-		@close="cancel"
-	>
-		<el-descriptions border :column="2">
-			<el-descriptions-item label="璁惧鍚嶇О">
-				{{ detailData.deviceName || '--' }}
-			</el-descriptions-item>
-			<el-descriptions-item label="瑙勬牸鍨嬪彿">
-				{{ detailData.deviceModel || '--' }}
-			</el-descriptions-item>
-			<el-descriptions-item label="璁″垝淇濆吇鏃ユ湡">
-				{{ formatDate(detailData.maintenancePlanTime) }}
-			</el-descriptions-item>
-			<el-descriptions-item label="褰曞叆浜�">
-				{{ detailData.createUserName || '--' }}
-			</el-descriptions-item>
-			<el-descriptions-item label="淇濆吇椤圭洰" :span="2">
-				{{ detailData.machineryCategory || '--' }}
-			</el-descriptions-item>
-			<el-descriptions-item label="瀹為檯淇濆吇浜�">
-				{{ detailData.maintenanceActuallyName || '--' }}
-			</el-descriptions-item>
-			<el-descriptions-item label="瀹為檯淇濆吇鏃ユ湡">
-				{{ formatDate(detailData.maintenanceActuallyTime) }}
-			</el-descriptions-item>
-			<el-descriptions-item label="淇濆吇缁撴灉" :span="2">
-				{{ detailData.maintenanceResult || '--' }}
-			</el-descriptions-item>
-			<el-descriptions-item label="鐘舵��" :span="2">
-				<el-tag v-if="detailData.status === 2" type="danger">澶辫触</el-tag>
-				<el-tag v-else-if="detailData.status === 1" type="success">瀹岀粨</el-tag>
-				<el-tag v-else type="warning">寰呬繚鍏�</el-tag>
-			</el-descriptions-item>
-		</el-descriptions>
+  <FormDialog
+    v-model="dialogVisitable"
+    title="淇濆吇璁板綍璇︽儏"
+    width="860px"
+    operation-type="detail"
+    @close="cancel"
+  >
+    <el-descriptions border :column="2" label-width="110px">
+      <el-descriptions-item label="璁惧鍚嶇О">
+        {{ detailData.deviceName || "--" }}
+      </el-descriptions-item>
+      <el-descriptions-item label="瑙勬牸鍨嬪彿">
+        {{ detailData.deviceModel || "--" }}
+      </el-descriptions-item>
+      <el-descriptions-item label="璁″垝淇濆吇鏃ユ湡">
+        {{ formatDate(detailData.maintenancePlanTime) }}
+      </el-descriptions-item>
+      <el-descriptions-item label="褰曞叆浜�">
+        {{ detailData.createUserName || "--" }}
+      </el-descriptions-item>
+      <el-descriptions-item label="瀹為檯淇濆吇浜�">
+        {{ detailData.maintenanceActuallyName || "--" }}
+      </el-descriptions-item>
+      <el-descriptions-item label="瀹為檯淇濆吇鏃ユ湡">
+        {{ formatDate(detailData.maintenanceActuallyTime) }}
+      </el-descriptions-item>
+      <el-descriptions-item label="淇濆吇缁撴灉" :span="2">
+        {{ detailData.maintenanceResult || "--" }}
+      </el-descriptions-item>
+      <el-descriptions-item label="鐘舵��" :span="2">
+        <el-tag v-if="detailData.status === 2" type="danger" size="small">澶辫触</el-tag>
+        <el-tag v-else-if="detailData.status === 1" type="success" size="small">瀹岀粨</el-tag>
+        <el-tag v-else type="warning" size="small">寰呬繚鍏�</el-tag>
+      </el-descriptions-item>
+    </el-descriptions>
 
-		<div v-if="fileList && fileList.length > 0" class="image-section">
-			<div class="image-title">淇濆吇闄勪欢(鍥剧墖)锛�</div>
-			<AttachmentUploadImage
-				v-model:fileList="fileList"
-				:disabled="true"
-			/>
-		</div>
-	</FormDialog>
+    <div class="detail-section">
+      <div class="section-title">
+        <span>淇濆吇鍐呭</span>
+        <span class="section-count">鍏� {{ itemCount }} 椤癸紝宸插畬鎴� {{ doneCount }} 椤�</span>
+      </div>
+      <div v-if="itemCount" class="item-list">
+        <div
+          v-for="(item, index) in detailData.maintenanceItems"
+          :key="item.id || index"
+          class="item-row"
+        >
+          <span class="item-index">{{ index + 1 }}</span>
+          <div class="item-body">
+            <div class="item-head">
+              <span class="item-project">{{ item.itemProject || "鏈~鍐欎繚鍏婚」鐩�" }}</span>
+              <el-tag size="small" effect="light" :type="statusMeta(item.itemStatus).type">{{
+                statusMeta(item.itemStatus).label
+              }}</el-tag>
+            </div>
+            <div class="item-content">{{ item.itemName }}</div>
+          </div>
+        </div>
+      </div>
+      <el-empty v-else :image-size="48" description="鏆傛棤淇濆吇鍐呭" />
+    </div>
+
+    <div v-if="fileList && fileList.length > 0" class="image-section">
+      <div class="image-title">淇濆吇闄勪欢(鍥剧墖)锛�</div>
+      <AttachmentUploadImage v-model:fileList="fileList" :disabled="true" />
+    </div>
+  </FormDialog>
 </template>
 
 <script setup>
 import FormDialog from "@/components/Dialog/FormDialog.vue";
-import { ref } from "vue";
+import { computed, ref } from "vue";
 import dayjs from "dayjs";
 import { attachmentList } from "@/api/basicData/storageAttachment.js";
-import AttachmentUploadImage from '@/components/AttachmentUpload/image/index.vue';
+import AttachmentUploadImage from "@/components/AttachmentUpload/image/index.vue";
 
 const dialogVisitable = ref(false);
 const detailData = ref({});
 const fileList = ref([]);
+const itemCount = computed(() => detailData.value.maintenanceItems?.length || 0);
+const doneCount = computed(
+  () => (detailData.value.maintenanceItems || []).filter((item) => item.itemStatus === 1).length
+);
 
 const formatDate = (date) => {
-	return date ? dayjs(date).format("YYYY-MM-DD") : "--";
+  return date ? dayjs(date).format("YYYY-MM-DD") : "--";
+};
+
+const statusMeta = (status) => {
+  if (status === 1) return { label: "宸插畬鎴�", type: "success" };
+  if (status === 2) return { label: "寮傚父", type: "danger" };
+  if (Number(detailData.value.status) === 1) return { label: "鏈畬鎴�", type: "warning" };
+  return { label: "寰呭畬鎴�", type: "info" };
 };
 
 const openDialog = (row) => {
-	dialogVisitable.value = true;
-	detailData.value = { ...row };
-	fileList.value = [];
+  dialogVisitable.value = true;
+  detailData.value = { ...row };
+  fileList.value = [];
 
-	if (row.id) {
-		attachmentList({
-			recordType: 'device_maintenance',
-			recordId: row.id,
-		}).then(res => {
-			if (res && res.data) {
-				fileList.value = res.data || [];
-			}
-		});
-	}
+  if (row.id) {
+    attachmentList({
+      recordType: "device_maintenance",
+      recordId: row.id,
+    }).then((res) => {
+      if (res && res.data) {
+        fileList.value = res.data || [];
+      }
+    });
+  }
 };
 
 const cancel = () => {
-	dialogVisitable.value = false;
+  dialogVisitable.value = false;
 };
 
 defineExpose({ openDialog });
 </script>
 
 <style scoped>
+.detail-section {
+  margin-top: 16px;
+}
+.section-title {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 10px;
+  font-weight: 600;
+  color: #303133;
+}
+.section-count {
+  font-size: 12px;
+  font-weight: normal;
+  color: #909399;
+}
+.item-list {
+  border: 1px solid #ebeef5;
+  border-radius: 4px;
+  overflow: hidden;
+}
+.item-row {
+  display: flex;
+  gap: 12px;
+  padding: 12px 14px;
+  border-bottom: 1px solid #ebeef5;
+}
+.item-row:last-child {
+  border-bottom: none;
+}
+.item-index {
+  flex-shrink: 0;
+  width: 24px;
+  height: 24px;
+  line-height: 24px;
+  text-align: center;
+  border-radius: 50%;
+  background: #ecf5ff;
+  color: #409eff;
+  font-size: 12px;
+}
+.item-body {
+  flex: 1;
+  min-width: 0;
+}
+.item-head {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 4px;
+}
+.item-project {
+  font-weight: 600;
+  color: #303133;
+}
+.item-content {
+  line-height: 1.6;
+  color: #606266;
+  white-space: pre-wrap;
+  word-break: break-all;
+}
 .image-section {
-	margin-top: 20px;
+  margin-top: 20px;
 }
 .image-title {
-	font-weight: bold;
-	margin-bottom: 10px;
-	color: #606266;
+  font-weight: bold;
+  margin-bottom: 10px;
+  color: #606266;
 }
 </style>
diff --git a/src/views/equipmentManagement/upkeep/Form/detailDia.vue b/src/views/equipmentManagement/upkeep/Form/detailDia.vue
index c80691a..ddf9be4 100644
--- a/src/views/equipmentManagement/upkeep/Form/detailDia.vue
+++ b/src/views/equipmentManagement/upkeep/Form/detailDia.vue
@@ -1,118 +1,190 @@
 <template>
-	<FormDialog
-		v-model="dialogVisitable"
-		title="淇濆吇浠诲姟璇︽儏"
-		width="800px"
-		operation-type="detail"
-		@close="cancel"
-	>
-		<el-descriptions border :column="2">
-			<el-descriptions-item label="璁惧鍚嶇О">
-				{{ detailData.taskName || '--' }}
-			</el-descriptions-item>
-			<el-descriptions-item label="瑙勬牸鍨嬪彿">
-				{{ detailData.deviceModel || '--' }}
-			</el-descriptions-item>
-			<el-descriptions-item label="褰曞叆浜�">
-				{{ detailData.registrant || '--' }}
-			</el-descriptions-item>
-			<el-descriptions-item label="鐧昏鏃堕棿">
-				{{ detailData.registrationDate || '--' }}
-			</el-descriptions-item>
-			<el-descriptions-item label="淇濆吇椤圭洰" :span="2">
-				{{ detailData.machineryCategory || '--' }}
-			</el-descriptions-item>
-			<el-descriptions-item label="淇濆吇浜�">
-				{{ detailData.maintenancePerson || '--' }}
-			</el-descriptions-item>
-			<el-descriptions-item label="浠诲姟棰戠巼">
-				{{ formatFrequencyType(detailData.frequencyType) }}
-			</el-descriptions-item>
-			<el-descriptions-item label="鎵ц鏃堕棿">
-				{{ formatFrequencyDetail(detailData.frequencyDetail) }}
-			</el-descriptions-item>
-			<el-descriptions-item label="瀹氭椂浠诲姟">
-				<el-tag :type="detailData.isActive === 1 ? 'success' : 'info'">
-					{{ detailData.isActive === 1 ? '寮�鍚�' : '鍏抽棴' }}
-				</el-tag>
-			</el-descriptions-item>
-			<el-descriptions-item label="澶囨敞" :span="2">
-				{{ detailData.remarks || '--' }}
-			</el-descriptions-item>
-		</el-descriptions>
+  <FormDialog
+    v-model="dialogVisitable"
+    title="淇濆吇浠诲姟璇︽儏"
+    width="860px"
+    operation-type="detail"
+    @close="cancel"
+  >
+    <el-descriptions border :column="2" label-width="100px">
+      <el-descriptions-item label="璁惧鍚嶇О">
+        {{ detailData.taskName || "--" }}
+      </el-descriptions-item>
+      <el-descriptions-item label="瑙勬牸鍨嬪彿">
+        {{ detailData.deviceModel || "--" }}
+      </el-descriptions-item>
+      <el-descriptions-item label="褰曞叆浜�">
+        {{ detailData.registrant || "--" }}
+      </el-descriptions-item>
+      <el-descriptions-item label="鐧昏鏃堕棿">
+        {{ detailData.registrationDate || "--" }}
+      </el-descriptions-item>
+      <el-descriptions-item label="淇濆吇浜�">
+        {{ detailData.maintenancePerson || "--" }}
+      </el-descriptions-item>
+      <el-descriptions-item label="浠诲姟棰戠巼">
+        {{ formatFrequencyType(detailData.frequencyType) }}
+      </el-descriptions-item>
+      <el-descriptions-item label="鎵ц鏃堕棿">
+        {{ formatFrequencyDetail(detailData.frequencyDetail) }}
+      </el-descriptions-item>
+      <el-descriptions-item label="瀹氭椂浠诲姟">
+        <el-tag :type="detailData.isActive === 1 ? 'success' : 'info'" size="small">
+          {{ detailData.isActive === 1 ? "寮�鍚�" : "鍏抽棴" }}
+        </el-tag>
+      </el-descriptions-item>
+      <el-descriptions-item label="澶囨敞" :span="2">
+        {{ detailData.remarks || "--" }}
+      </el-descriptions-item>
+    </el-descriptions>
 
-		<div v-if="fileList && fileList.length > 0" class="image-section">
-			<div class="image-title">璁惧鍥剧墖锛�</div>
-			<AttachmentUploadImage
-				v-model:fileList="fileList"
-				:disabled="true"
-			/>
-		</div>
-	</FormDialog>
+    <div class="detail-section">
+      <div class="section-title">
+        <span>淇濆吇鍐呭</span>
+        <span class="section-count">鍏� {{ itemCount }} 椤�</span>
+      </div>
+      <div v-if="itemCount" class="item-list">
+        <div
+          v-for="(item, index) in detailData.maintenanceItems"
+          :key="item.id || index"
+          class="item-row"
+        >
+          <span class="item-index">{{ index + 1 }}</span>
+          <div class="item-body">
+            <div class="item-project">{{ item.itemProject || "鏈~鍐欎繚鍏婚」鐩�" }}</div>
+            <div class="item-content">{{ item.itemName }}</div>
+          </div>
+        </div>
+      </div>
+      <el-empty v-else :image-size="48" description="鏆傛棤淇濆吇鍐呭" />
+    </div>
+
+    <div v-if="fileList && fileList.length > 0" class="image-section">
+      <div class="image-title">璁惧鍥剧墖锛�</div>
+      <AttachmentUploadImage v-model:fileList="fileList" :disabled="true" />
+    </div>
+  </FormDialog>
 </template>
 
 <script setup>
 import FormDialog from "@/components/Dialog/FormDialog.vue";
-import { ref } from "vue";
+import { computed, ref } from "vue";
 import { getLedgerById } from "@/api/equipmentManagement/ledger";
-import AttachmentUploadImage from '@/components/AttachmentUpload/image/index.vue';
+import AttachmentUploadImage from "@/components/AttachmentUpload/image/index.vue";
 
 const dialogVisitable = ref(false);
 const detailData = ref({});
 const fileList = ref([]);
+const itemCount = computed(() => detailData.value.maintenanceItems?.length || 0);
 
 const formatFrequencyType = (type) => {
-	const map = {
-		DAILY: "姣忔棩",
-		WEEKLY: "姣忓懆",
-		MONTHLY: "姣忔湀",
-		QUARTERLY: "瀛e害",
-	};
-	return map[type] || "--";
+  const map = {
+    DAILY: "姣忔棩",
+    WEEKLY: "姣忓懆",
+    MONTHLY: "姣忔湀",
+    QUARTERLY: "瀛e害",
+  };
+  return map[type] || "--";
 };
 
 const formatFrequencyDetail = (detail) => {
-	if (!detail) return "--";
-	const replacements = {
-		MON: "鍛ㄤ竴",
-		TUE: "鍛ㄤ簩",
-		WED: "鍛ㄤ笁",
-		THU: "鍛ㄥ洓",
-		FRI: "鍛ㄤ簲",
-		SAT: "鍛ㄥ叚",
-		SUN: "鍛ㄦ棩",
-	};
-	return detail.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, match => replacements[match]);
+  if (!detail) return "--";
+  const replacements = {
+    MON: "鍛ㄤ竴",
+    TUE: "鍛ㄤ簩",
+    WED: "鍛ㄤ笁",
+    THU: "鍛ㄥ洓",
+    FRI: "鍛ㄤ簲",
+    SAT: "鍛ㄥ叚",
+    SUN: "鍛ㄦ棩",
+  };
+  return detail.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, (match) => replacements[match]);
 };
 
 const openDialog = (row) => {
-	dialogVisitable.value = true;
-	detailData.value = { ...row };
-	fileList.value = [];
+  dialogVisitable.value = true;
+  detailData.value = { ...row };
+  fileList.value = [];
 
-	if (row.taskId) {
-		getLedgerById(row.taskId).then(res => {
-			if (res.code === 200 && res.data) {
-				fileList.value = res.data.storageBlobVOs || [];
-			}
-		});
-	}
+  if (row.taskId) {
+    getLedgerById(row.taskId).then((res) => {
+      if (res.code === 200 && res.data) {
+        fileList.value = res.data.storageBlobVOs || [];
+      }
+    });
+  }
 };
 
 const cancel = () => {
-	dialogVisitable.value = false;
+  dialogVisitable.value = false;
 };
 
 defineExpose({ openDialog });
 </script>
 
 <style scoped>
+.detail-section {
+  margin-top: 16px;
+}
+.section-title {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 10px;
+  font-weight: 600;
+  color: #303133;
+}
+.section-count {
+  font-size: 12px;
+  font-weight: normal;
+  color: #909399;
+}
+.item-list {
+  border: 1px solid #ebeef5;
+  border-radius: 4px;
+  overflow: hidden;
+}
+.item-row {
+  display: flex;
+  gap: 12px;
+  padding: 12px 14px;
+  border-bottom: 1px solid #ebeef5;
+}
+.item-row:last-child {
+  border-bottom: none;
+}
+.item-index {
+  flex-shrink: 0;
+  width: 24px;
+  height: 24px;
+  line-height: 24px;
+  text-align: center;
+  border-radius: 50%;
+  background: #ecf5ff;
+  color: #409eff;
+  font-size: 12px;
+}
+.item-body {
+  flex: 1;
+  min-width: 0;
+}
+.item-project {
+  margin-bottom: 4px;
+  font-weight: 600;
+  color: #303133;
+}
+.item-content {
+  line-height: 1.6;
+  color: #606266;
+  white-space: pre-wrap;
+  word-break: break-all;
+}
 .image-section {
-	margin-top: 20px;
+  margin-top: 20px;
 }
 .image-title {
-	font-weight: bold;
-	margin-bottom: 10px;
-	color: #606266;
+  font-weight: bold;
+  margin-bottom: 10px;
+  color: #606266;
 }
 </style>
diff --git a/src/views/equipmentManagement/upkeep/Form/formDia.vue b/src/views/equipmentManagement/upkeep/Form/formDia.vue
index 60dda54..a7a8211 100644
--- a/src/views/equipmentManagement/upkeep/Form/formDia.vue
+++ b/src/views/equipmentManagement/upkeep/Form/formDia.vue
@@ -1,349 +1,640 @@
 <template>
-	<FormDialog
-		v-model="dialogVisitable"
-		:title="operationType === 'add' ? '鏂板淇濆吇浠诲姟' : '缂栬緫淇濆吇浠诲姟'"
-		width="800px"
-		:operation-type="operationType"
-		@confirm="submitForm"
-		@cancel="cancel"
-		@close="cancel"
-	>
-		<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
-			<el-row>
-				<el-col :span="12">
-					<el-form-item label="璁惧鍚嶇О" prop="taskId">
-						<el-select v-model="form.taskId" @change="setDeviceModel" filterable>
-							<el-option
-								v-for="(item, index) in deviceOptions"
-								:key="index"
-								:label="item.deviceName"
-								:value="item.id"
-							></el-option>
-						</el-select>
-					</el-form-item>
-				</el-col>
-				<el-col :span="12">
-					<el-form-item label="瑙勬牸鍨嬪彿">
-						<el-input
-							v-model="form.deviceModel"
-							placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
-							disabled
-						/>
-					</el-form-item>
-				</el-col>
-			</el-row>
-			<el-row>
-				<el-col :span="12">
-					<el-form-item label="褰曞叆浜�" prop="inspector">
-						<el-select
-							v-model="form.inspector"
-							filterable
-							default-first-option
-							:reserve-keyword="false"
-							placeholder="璇烽�夋嫨"
-							clearable
-						>
-							<el-option
-								v-for="item in userList"
-								:label="item.nickName"
-								:value="item.userId"
-								:key="item.userId"
-							/>
-						</el-select>
-					</el-form-item>
-				</el-col>
-				<el-col :span="12">
-					<el-form-item label="鐧昏鏃堕棿" prop="registrationDate">
-						<el-date-picker
-							v-model="form.registrationDate"
-							type="date"
-							placeholder="閫夋嫨鐧昏鏃ユ湡"
-							format="YYYY-MM-DD"
-							value-format="YYYY-MM-DD"
-							style="width: 100%"
-						/>
-					</el-form-item>
-				</el-col>
-			</el-row>
-			<el-row>
-				<el-col :span="12">
-					<el-form-item label="淇濆吇椤圭洰" prop="machineryCategory">
-						<el-input
-							v-model.trim="form.machineryCategory"
-							type="textarea"
-							placeholder="璇疯緭鍏ヤ繚鍏婚」鐩�"
-							clearable
-						/>
-					</el-form-item>
-				</el-col>
-				<el-col :span="12">
-					<el-form-item label="淇濆吇浜�" prop="maintenancePerson">
-						<el-input
-							v-model.trim="form.maintenancePerson"
-							placeholder="璇疯緭鍏ヤ繚鍏讳汉濮撳悕"
-							maxlength="100"
-							clearable
-						/>
-					</el-form-item>
-				</el-col>
-			</el-row>
-			<el-row>
-				<el-col :span="12">
-					<el-form-item label="浠诲姟棰戠巼" prop="frequencyType">
-						<el-select v-model="form.frequencyType" placeholder="璇烽�夋嫨" clearable>
-							<el-option label="姣忔棩" value="DAILY"/>
-							<el-option label="姣忓懆" value="WEEKLY"/>
-							<el-option label="姣忔湀" value="MONTHLY"/>
-							<el-option label="瀛e害" value="QUARTERLY"/>
-						</el-select>
-					</el-form-item>
-				</el-col>
-				<el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType">
-					<el-form-item label="鏃ユ湡" prop="frequencyDetail">
-						<el-time-picker v-model="form.frequencyDetail" placeholder="閫夋嫨鏃堕棿" format="HH:mm"
-													value-format="HH:mm" />
-					</el-form-item>
-				</el-col>
-				<el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
-					<el-form-item label="鏃ユ湡" prop="frequencyDetail">
-						<el-select v-model="form.week" placeholder="璇烽�夋嫨" clearable style="width: 50%">
-							<el-option label="鍛ㄤ竴" value="MON"/>
-							<el-option label="鍛ㄤ簩" value="TUE"/>
-							<el-option label="鍛ㄤ笁" value="WED"/>
-							<el-option label="鍛ㄥ洓" value="THU"/>
-							<el-option label="鍛ㄤ簲" value="FRI"/>
-							<el-option label="鍛ㄥ叚" value="SAT"/>
-							<el-option label="鍛ㄦ棩" value="SUN"/>
-						</el-select>
-						<el-time-picker v-model="form.time" placeholder="閫夋嫨鏃堕棿" format="HH:mm"
-													value-format="HH:mm"  style="width: 50%"/>
-					</el-form-item>
-				</el-col>
-				<el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
-					<el-form-item label="鏃ユ湡" prop="frequencyDetail">
-						<el-date-picker
-							v-model="form.frequencyDetail"
-							type="datetime"
-							clearable
-							placeholder="閫夋嫨寮�濮嬫棩鏈�"
-							format="DD,HH:mm"
-							value-format="DD,HH:mm"
-						/>
-					</el-form-item>
-				</el-col>
-				<el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType">
-					<el-form-item label="鏃ユ湡" prop="frequencyDetail">
-						<el-date-picker
-							v-model="form.frequencyDetail"
-							type="datetime"
-							clearable
-							placeholder="閫夋嫨寮�濮嬫棩鏈�"
-							format="MM,DD,HH:mm"
-							value-format="MM,DD,HH:mm"
-						/>
-					</el-form-item>
-				</el-col>
-			</el-row>
-			<el-row>
-				<el-col :span="24">
-					<el-form-item label="瀹氭椂浠诲姟">
-						<el-switch
-							v-model="form.isActive"
-							:active-value="1"
-							:inactive-value="0"
-							active-text="寮�鍚�"
-							inactive-text="鍏抽棴"
-							inline-prompt
-						/>
-						<span style="margin-left: 12px; color: #909399; font-size: 12px;">
-							{{ form.isActive === 1 ? '浠诲姟灏嗘寜璁″垝鎵ц' : '浠诲姟鏆傚仠鎵ц' }}
-						</span>
-					</el-form-item>
-				</el-col>
-			</el-row>
-			<el-row>
-				<el-col :span="12">
-					<el-form-item label="澶囨敞" prop="remarks">
-						<el-input v-model="form.remarks" placeholder="璇疯緭鍏ュ娉�" type="textarea" />
-					</el-form-item>
-				</el-col>
-			</el-row>
-		</el-form>
-	</FormDialog>
+  <FormDialog
+    v-model="dialogVisitable"
+    :title="operationType === 'add' ? '鏂板淇濆吇浠诲姟' : '缂栬緫淇濆吇浠诲姟'"
+    width="800px"
+    :operation-type="operationType"
+    @confirm="submitForm"
+    @cancel="cancel"
+    @close="cancel"
+  >
+    <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="璁惧鍚嶇О" prop="taskId">
+            <el-select v-model="form.taskId" @change="setDeviceModel" filterable>
+              <el-option
+                v-for="(item, index) in deviceOptions"
+                :key="index"
+                :label="item.deviceName"
+                :value="item.id"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="瑙勬牸鍨嬪彿">
+            <el-input v-model="form.deviceModel" placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�" disabled />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="褰曞叆浜�" prop="inspector">
+            <el-select
+              v-model="form.inspector"
+              filterable
+              default-first-option
+              :reserve-keyword="false"
+              placeholder="璇烽�夋嫨"
+              clearable
+            >
+              <el-option
+                v-for="item in userList"
+                :label="item.nickName"
+                :value="item.userId"
+                :key="item.userId"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="鐧昏鏃堕棿" prop="registrationDate">
+            <el-date-picker
+              v-model="form.registrationDate"
+              type="date"
+              placeholder="閫夋嫨鐧昏鏃ユ湡"
+              format="YYYY-MM-DD"
+              value-format="YYYY-MM-DD"
+              style="width: 100%"
+            />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="淇濆吇浜�" prop="maintenancePerson">
+            <el-input
+              v-model.trim="form.maintenancePerson"
+              placeholder="璇疯緭鍏ヤ繚鍏讳汉濮撳悕"
+              maxlength="100"
+              clearable
+            />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="浠诲姟棰戠巼" prop="frequencyType">
+            <el-select
+              v-model="form.frequencyType"
+              placeholder="璇烽�夋嫨锛堟棩銆佸懆銆佹湀銆佸搴︼級"
+              clearable
+              @change="onFrequencyChange"
+            >
+              <el-option label="姣忔棩" value="DAILY" />
+              <el-option label="姣忓懆" value="WEEKLY" />
+              <el-option label="姣忔湀" value="MONTHLY" />
+              <el-option label="瀛e害" value="QUARTERLY" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType">
+          <el-form-item label="鏃ユ湡" prop="frequencyDetail">
+            <el-time-picker
+              v-model="form.frequencyDetail"
+              placeholder="閫夋嫨鏃堕棿"
+              format="HH:mm"
+              value-format="HH:mm"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
+          <el-form-item label="鏃ユ湡" prop="frequencyDetail">
+            <el-select v-model="form.week" placeholder="璇烽�夋嫨" clearable style="width: 50%">
+              <el-option label="鍛ㄤ竴" value="MON" />
+              <el-option label="鍛ㄤ簩" value="TUE" />
+              <el-option label="鍛ㄤ笁" value="WED" />
+              <el-option label="鍛ㄥ洓" value="THU" />
+              <el-option label="鍛ㄤ簲" value="FRI" />
+              <el-option label="鍛ㄥ叚" value="SAT" />
+              <el-option label="鍛ㄦ棩" value="SUN" />
+            </el-select>
+            <el-time-picker
+              v-model="form.time"
+              placeholder="閫夋嫨鏃堕棿"
+              format="HH:mm"
+              value-format="HH:mm"
+              style="width: 50%"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
+          <el-form-item label="鏃ユ湡" prop="frequencyDetail">
+            <el-date-picker
+              v-model="form.frequencyDetail"
+              type="datetime"
+              clearable
+              placeholder="閫夋嫨寮�濮嬫棩鏈�"
+              format="DD,HH:mm"
+              value-format="DD,HH:mm"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType">
+          <el-form-item label="鏃ユ湡" prop="frequencyDetail">
+            <el-date-picker
+              v-model="form.frequencyDetail"
+              type="datetime"
+              clearable
+              placeholder="閫夋嫨寮�濮嬫棩鏈�"
+              format="MM,DD,HH:mm"
+              value-format="MM,DD,HH:mm"
+            />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="淇濆吇椤圭洰" prop="maintenanceItemIds">
+            <div class="maintenance-selection">
+              <div class="selection-toolbar">
+                <el-button
+                  type="primary"
+                  plain
+                  :disabled="!form.taskId || !form.frequencyType"
+                  @click="itemSelectorVisible = true"
+                  >閫夋嫨淇濆吇椤圭洰</el-button
+                >
+                <span v-if="!form.taskId || !form.frequencyType" class="selection-hint"
+                  >璇峰厛閫夋嫨璁惧鍜屼换鍔¢鐜囷紝璁惧缁戝畾鐨勪繚鍏婚」鐩皢鑷姩甯﹀嚭</span
+                >
+                <span v-else class="selection-hint"
+                  >璁惧缁戝畾椤圭洰宸茶嚜鍔ㄥ甫鍑猴紝鍙澶栭�夋嫨閫氱敤椤圭洰锛屾垨娣诲姞鏈换鍔′笓鐢ㄩ」鐩�</span
+                >
+              </div>
+              <div class="custom-input">
+                <el-input
+                  v-model="customItemProject"
+                  maxlength="200"
+                  clearable
+                  placeholder="杈撳叆鏈换鍔′笓鐢ㄧ殑淇濆吇椤圭洰"
+                />
+                <el-input
+                  v-model="customItemName"
+                  maxlength="2000"
+                  clearable
+                  placeholder="杈撳叆椤圭洰瀵瑰簲鐨勪繚鍏诲唴瀹�"
+                  @keyup.enter="addCustomItem"
+                />
+                <el-button
+                  :disabled="!customItemProject.trim() || !customItemName.trim()"
+                  @click="addCustomItem"
+                  >娣诲姞</el-button
+                >
+              </div>
+              <div class="selected-panel">
+                <div class="selected-header">
+                  <span class="selected-title">宸查�� {{ selectedList.length }} 椤�</span>
+                  <span v-if="sourceStats.length" class="selected-stats">
+                    <span v-for="stat in sourceStats" :key="stat.source" class="selected-stat"
+                      >{{ stat.label }} {{ stat.count }}</span
+                    >
+                  </span>
+                </div>
+                <ol v-if="selectedList.length" class="selected-list">
+                  <li v-for="(item, index) in selectedList" :key="item.key" class="selected-row">
+                    <span class="row-index">{{ index + 1 }}</span>
+                    <el-tag size="small" effect="light" :type="sourceMeta[item.source].type">{{
+                      sourceMeta[item.source].label
+                    }}</el-tag>
+                    <span class="row-text" :title="item.itemProject">{{ item.itemProject }}</span>
+                    <el-button link type="danger" @click="removeSelectedItem(item)">绉婚櫎</el-button>
+                  </li>
+                </ol>
+                <el-empty v-else :image-size="56" description="灏氭湭閫夋嫨淇濆吇椤圭洰" />
+              </div>
+            </div>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="瀹氭椂浠诲姟">
+            <el-switch
+              v-model="form.isActive"
+              :active-value="1"
+              :inactive-value="0"
+              active-text="寮�鍚�"
+              inactive-text="鍏抽棴"
+              inline-prompt
+            />
+            <span style="margin-left: 12px; color: #909399; font-size: 12px">
+              {{ form.isActive === 1 ? "浠诲姟灏嗘寜璁″垝鎵ц" : "浠诲姟鏆傚仠鎵ц" }}
+            </span>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="澶囨敞" prop="remarks">
+            <el-input v-model="form.remarks" placeholder="璇疯緭鍏ュ娉�" type="textarea" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+  </FormDialog>
+  <MaintenanceItemSelector
+    v-model:visible="itemSelectorVisible"
+    :selected-items="selectedItems"
+    :device-ledger-id="form.taskId"
+    :frequency-type="form.frequencyType"
+    @confirm="applyMaintenanceItems"
+  />
 </template>
 
 <script setup>
 import FormDialog from "@/components/Dialog/FormDialog.vue";
-import { reactive, ref, getCurrentInstance, toRefs } from "vue";
-import {userListNoPageByTenantId} from "@/api/system/user.js";
+import { computed, reactive, ref, getCurrentInstance, toRefs } from "vue";
+import { userListNoPageByTenantId } from "@/api/system/user.js";
 import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
-import { deviceMaintenanceTaskAdd, deviceMaintenanceTaskEdit } from "@/api/equipmentManagement/upkeep";
+import {
+  deviceMaintenanceTaskAdd,
+  deviceMaintenanceTaskEdit,
+  getMaintenanceItemList,
+} from "@/api/equipmentManagement/upkeep";
 import { getCurrentDate } from "@/utils/index.js";
 import useUserStore from "@/store/modules/user.js";
+import MaintenanceItemSelector from "./MaintenanceItemSelector.vue";
 
-const { proxy } = getCurrentInstance()
-const emit = defineEmits()
+const { proxy } = getCurrentInstance();
+const emit = defineEmits();
 const dialogVisitable = ref(false);
-const operationType = ref('add');
+const operationType = ref("add");
 const deviceOptions = ref([]);
+const itemSelectorVisible = ref(false);
 const userStore = useUserStore();
 const data = reactive({
-	form: {
-		taskId: undefined,
-		taskName: undefined,
-		// 褰曞叆浜猴細鍗曢�変竴涓敤鎴� id
-		inspector: undefined,
-		machineryCategory: "",
-		remarks: '',
-		frequencyType: '',
-		frequencyDetail: '',
-		week: '',
-		time: '',
-		deviceModel: undefined, // 瑙勬牸鍨嬪彿
-		registrationDate: '',
-		maintenancePerson: '', // 淇濆吇浜�
-		isActive: 0 // 瀹氭椂浠诲姟寮�鍏筹細0=鍏抽棴锛�1=寮�鍚�
-	},
-	rules: {
-		taskId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" },],
-		inspector: [{ required: true, message: "璇烽�夋嫨褰曞叆浜�", trigger: "blur" },],
-		registrationDate: [{ required: true, message: "璇烽�夋嫨鐧昏鏃堕棿", trigger: "change" }],
-		machineryCategory: [{ required: true, message: "璇疯緭鍏ヤ繚鍏婚」鐩�", trigger: "blur" }]
-	}
-})
-const { form, rules } = toRefs(data)
-const userList = ref([])
+  form: {
+    taskId: undefined,
+    taskName: undefined,
+    // 褰曞叆浜猴細鍗曢�変竴涓敤鎴� id
+    inspector: undefined,
+    maintenanceItemIds: [],
+    remarks: "",
+    frequencyType: "",
+    frequencyDetail: "",
+    week: "",
+    time: "",
+    deviceModel: undefined, // 瑙勬牸鍨嬪彿
+    registrationDate: "",
+    maintenancePerson: "", // 淇濆吇浜�
+    isActive: 0, // 瀹氭椂浠诲姟寮�鍏筹細0=鍏抽棴锛�1=寮�鍚�
+  },
+  rules: {
+    taskId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" }],
+    inspector: [{ required: true, message: "璇烽�夋嫨褰曞叆浜�", trigger: "blur" }],
+    registrationDate: [{ required: true, message: "璇烽�夋嫨鐧昏鏃堕棿", trigger: "change" }],
+    maintenanceItemIds: [
+      { type: "array", required: true, min: 1, message: "璇峰嬀閫変繚鍏婚」鐩�", trigger: "change" },
+    ],
+    frequencyType: [{ required: true, message: "璇烽�夋嫨浠诲姟棰戠巼", trigger: "change" }],
+    frequencyDetail: [
+      {
+        validator: (_, value, callback) => {
+          const valid =
+            form.value.frequencyType === "WEEKLY"
+              ? Boolean(form.value.week && form.value.time)
+              : Boolean(value);
+          callback(valid ? undefined : new Error("璇烽�夋嫨鎵ц鏃ユ湡鍜屾椂闂�"));
+        },
+        trigger: "change",
+      },
+    ],
+  },
+});
+const { form, rules } = toRefs(data);
+const userList = ref([]);
+// 浠庝繚鍏诲唴瀹规竻鍗曚腑閫変腑鐨勯」锛堣澶囩粦瀹氭垨閫氱敤锛�
+const selectedItems = ref([]);
+// 浠呭睘浜庢湰浠诲姟鐨勮嚜瀹氫箟鍐呭锛屼笉鍐欏叆淇濆吇鍐呭娓呭崟
+const customItems = ref([]);
+const customItemProject = ref("");
+const customItemName = ref("");
+const sourceMeta = {
+  device: { label: "鏈澶�", type: "primary" },
+  common: { label: "閫氱敤", type: "info" },
+  custom: { label: "鑷畾涔�", type: "warning" },
+  other: { label: "鍏跺畠璁惧", type: "danger" },
+  saved: { label: "宸蹭繚瀛�", type: "success" },
+};
+const getSource = (item) => {
+  if (item.deviceLedgerId === undefined) return "saved";
+  if (item.deviceLedgerId === null) return "common";
+  return String(item.deviceLedgerId) === String(form.value.taskId) ? "device" : "other";
+};
+const selectedList = computed(() => [
+  ...selectedItems.value.map((item) => ({
+    key: `item-${item.id}`,
+    id: item.id,
+    itemProject: item.itemProject,
+    source: getSource(item),
+  })),
+  ...customItems.value.map((item) => ({
+    key: item.key,
+    id: null,
+    itemProject: item.itemProject,
+    itemName: item.itemName,
+    source: "custom",
+  })),
+]);
+const sourceStats = computed(() =>
+  Object.keys(sourceMeta)
+    .map((source) => ({
+      source,
+      label: sourceMeta[source].label,
+      count: selectedList.value.filter((item) => item.source === source).length,
+    }))
+    .filter((stat) => stat.count > 0)
+);
+const syncItemIds = () => {
+  form.value.maintenanceItemIds = [
+    ...selectedItems.value.map((item) => item.id),
+    ...customItems.value.map((item) => item.key),
+  ];
+  proxy.$refs.formRef?.clearValidate("maintenanceItemIds");
+};
+const applyMaintenanceItems = (items) => {
+  selectedItems.value = items;
+  syncItemIds();
+};
+const addCustomItem = () => {
+  const project = customItemProject.value.trim();
+  const name = customItemName.value.trim();
+  if (!project || !name) return;
+  if (selectedList.value.some((item) => item.itemProject === project)) {
+    proxy.$modal.msgWarning("宸插瓨鍦ㄧ浉鍚岀殑淇濆吇椤圭洰");
+    return;
+  }
+  customItems.value = [
+    ...customItems.value,
+    { key: `custom-${Date.now()}`, itemProject: project, itemName: name },
+  ];
+  customItemProject.value = "";
+  customItemName.value = "";
+  syncItemIds();
+};
+const removeSelectedItem = (item) => {
+  if (item.source === "custom")
+    customItems.value = customItems.value.filter((custom) => custom.key !== item.key);
+  else
+    selectedItems.value = selectedItems.value.filter(
+      (selected) => String(selected.id) !== String(item.id)
+    );
+  syncItemIds();
+};
 
 const loadDeviceName = async () => {
-	const { data } = await getDeviceLedger();
-	deviceOptions.value = data;
+  const { data } = await getDeviceLedger();
+  deviceOptions.value = data;
 };
 
 // 閫夋嫨璁惧鏃讹紝鍥炲~璁惧鍚嶇О(taskName)鍜岃鏍煎瀷鍙�(deviceModel)
-const setDeviceModel = (id) => {
-	const option = deviceOptions.value.find((item) => item.id === id);
-	if (option) {
-		form.value.taskId = option.id;
-		form.value.taskName = option.deviceName;
-		form.value.deviceModel = option.deviceModel;
-	}
-}
+const setDeviceModel = (id, preserveItems = false) => {
+  const option = deviceOptions.value.find((item) => item.id === id);
+  if (option) {
+    form.value.taskId = option.id;
+    form.value.taskName = option.deviceName;
+    form.value.deviceModel = option.deviceModel;
+    if (!preserveItems) autoFillBoundItems(id);
+  }
+};
+const clearSelectedItems = () => {
+  selectedItems.value = [];
+  syncItemIds();
+};
+const onFrequencyChange = () => autoFillBoundItems();
+// 鎸夎澶囧拰棰戠巼鑷姩甯﹀嚭璇ヨ澶囩粦瀹氱殑淇濆吇鍐呭锛涢�氱敤鍐呭锛堟棤璁惧锛夐渶鐢ㄦ埛鎵嬪姩棰濆閫夋嫨
+const autoFillBoundItems = async (deviceId) => {
+  const id = deviceId ?? form.value.taskId;
+  const frequency = form.value.frequencyType;
+  if (!id || !frequency) return clearSelectedItems();
+  const { code, data } = await getMaintenanceItemList({
+    deviceLedgerId: id,
+    frequencyType: frequency,
+    isActive: 1,
+  });
+  if (code !== 200 || id !== form.value.taskId || frequency !== form.value.frequencyType) return;
+  applyMaintenanceItems(data || []);
+};
 
 // 鎵撳紑寮规
 const openDialog = async (type, row) => {
-	dialogVisitable.value = true
-	operationType.value = type
-	
-	// 閲嶇疆琛ㄥ崟
-	resetForm();
-	
-	// 鍔犺浇鐢ㄦ埛鍒楄〃
-	userListNoPageByTenantId().then((res) => {
-		userList.value = res.data;
-	});
-	
-	// 鍔犺浇璁惧鍒楄〃
-	await loadDeviceName();
-	
-	if (type === 'edit' && row) {
-		form.value = { ...row }
-		// 缂栬緫鏃剁敤鎺ュ彛杩斿洖鐨� registrantId 鍥炴樉褰曞叆浜�
-		if (row.registrantId) {
-			form.value.inspector = row.registrantId
-		}
+  dialogVisitable.value = true;
+  operationType.value = type;
 
-		// 濡傛灉鏈夎澶嘔D锛岃嚜鍔ㄨ缃澶囦俊鎭�
-		if (form.value.taskId) {
-			setDeviceModel(form.value.taskId);
-		}
-	} else if (type === 'add') {
-		// 鏂板鏃惰缃櫥璁版棩鏈熶负褰撳ぉ
-		form.value.registrationDate = getCurrentDate();
-		// 鏂板鏃惰缃綍鍏ヤ汉涓哄綋鍓嶇櫥褰曡处鎴�
-		form.value.inspector = userStore.id;
-	}
-}
+  // 閲嶇疆琛ㄥ崟
+  resetForm();
+
+  // 鍔犺浇鐢ㄦ埛鍒楄〃
+  userListNoPageByTenantId().then((res) => {
+    userList.value = res.data;
+  });
+  // 鍔犺浇璁惧鍒楄〃
+  await loadDeviceName();
+
+  if (type === "edit" && row) {
+    form.value = { ...row };
+    const savedItems = row.maintenanceItems || [];
+    selectedItems.value = savedItems
+      .filter((item) => item.maintenanceItemId != null)
+      .map((item) => ({
+        id: item.maintenanceItemId,
+        itemProject: item.itemProject,
+        itemName: item.itemName,
+      }));
+    customItems.value = savedItems
+      .filter((item) => item.maintenanceItemId == null)
+      .map((item, index) => ({
+        key: `custom-saved-${index}`,
+        itemProject: item.itemProject,
+        itemName: item.itemName,
+      }));
+    syncItemIds();
+    // 缂栬緫鏃剁敤鎺ュ彛杩斿洖鐨� registrantId 鍥炴樉褰曞叆浜�
+    if (row.registrantId) {
+      form.value.inspector = row.registrantId;
+    }
+
+    // 濡傛灉鏈夎澶嘔D锛岃嚜鍔ㄨ缃澶囦俊鎭�
+    if (form.value.taskId) {
+      setDeviceModel(form.value.taskId, true);
+    }
+  } else if (type === "add") {
+    // 鏂板鏃惰缃櫥璁版棩鏈熶负褰撳ぉ
+    form.value.registrationDate = getCurrentDate();
+    // 鏂板鏃惰缃綍鍏ヤ汉涓哄綋鍓嶇櫥褰曡处鎴�
+    form.value.inspector = userStore.id;
+  }
+};
 
 // 鍏抽棴瀵硅瘽妗�
 const cancel = () => {
-	resetForm()
-	dialogVisitable.value = false
-	emit('closeDia')
-}
+  itemSelectorVisible.value = false;
+  resetForm();
+  dialogVisitable.value = false;
+  emit("closeDia");
+};
 
 // 閲嶇疆琛ㄥ崟鍑芥暟
 const resetForm = () => {
-	if (proxy.$refs.formRef) {
-		proxy.$refs.formRef.resetFields()
-	}
-	// 閲嶇疆琛ㄥ崟鏁版嵁纭繚璁惧淇℃伅姝g‘閲嶇疆
-	form.value = {
-		taskId: undefined,
-		taskName: undefined,
-		inspector: undefined,
-		machineryCategory: "",
-		remarks: '',
-		frequencyType: '',
-		frequencyDetail: '',
-		week: '',
-		time: '',
-		deviceModel: undefined,
-		registrationDate: '',
-		maintenancePerson: '',
-		isActive: 0
-	}
-}
+  itemSelectorVisible.value = false;
+  selectedItems.value = [];
+  customItems.value = [];
+  customItemProject.value = "";
+  customItemName.value = "";
+  if (proxy.$refs.formRef) {
+    proxy.$refs.formRef.resetFields();
+  }
+  // 閲嶇疆琛ㄥ崟鏁版嵁纭繚璁惧淇℃伅姝g‘閲嶇疆
+  form.value = {
+    taskId: undefined,
+    taskName: undefined,
+    inspector: undefined,
+    maintenanceItemIds: [],
+    remarks: "",
+    frequencyType: "",
+    frequencyDetail: "",
+    week: "",
+    time: "",
+    deviceModel: undefined,
+    registrationDate: "",
+    maintenancePerson: "",
+    isActive: 0,
+  };
+};
 
 // 鎻愪氦琛ㄥ崟
 const submitForm = () => {
-	proxy.$refs["formRef"].validate(async valid => {
-		if (valid) {
-			try {
-				const payload = { ...form.value }
-				// 涓嶅啀鍚戝悗绔紶淇濆吇浜哄瓧娈碉紝浠呬娇鐢ㄦ帴鍙h姹傜殑 registrant / registrantId
-				// 鏍规嵁閫夋嫨鐨�"褰曞叆浜�"璁剧疆 registrant / registrantId
-				if (payload.inspector) {
-					const selectedUser = userList.value.find(
-						(u) => String(u.userId) === String(payload.inspector)
-					)
-					if (selectedUser) {
-						payload.registrantId = selectedUser.userId
-						payload.registrant = selectedUser.nickName
-					}
-				}
-				delete payload.inspector
-				delete payload.inspectorIds
-				delete payload.active
+  proxy.$refs["formRef"].validate(async (valid) => {
+    if (valid) {
+      try {
+        const payload = { ...form.value };
+        payload.maintenanceItemIds = selectedItems.value.map((item) => item.id);
+        payload.customItems = customItems.value.map((item) => ({
+          itemProject: item.itemProject,
+          itemName: item.itemName,
+        }));
+        // 涓嶅啀鍚戝悗绔紶淇濆吇浜哄瓧娈碉紝浠呬娇鐢ㄦ帴鍙h姹傜殑 registrant / registrantId
+        // 鏍规嵁閫夋嫨鐨�"褰曞叆浜�"璁剧疆 registrant / registrantId
+        if (payload.inspector) {
+          const selectedUser = userList.value.find(
+            (u) => String(u.userId) === String(payload.inspector)
+          );
+          if (selectedUser) {
+            payload.registrantId = selectedUser.userId;
+            payload.registrant = selectedUser.nickName;
+          }
+        }
+        delete payload.inspector;
+        delete payload.inspectorIds;
+        delete payload.active;
 
-				if (payload.frequencyType === 'WEEKLY') {
-					let frequencyDetail = ''
-					frequencyDetail = payload.week + ',' + payload.time
-					payload.frequencyDetail = frequencyDetail
-				}
+        if (payload.frequencyType === "WEEKLY") {
+          let frequencyDetail = "";
+          frequencyDetail = payload.week + "," + payload.time;
+          payload.frequencyDetail = frequencyDetail;
+        }
 
-				// 褰曞叆鏃ユ湡锛氱洿鎺ヤ娇鐢ㄨ〃鍗曢噷鐨� registrationDate 瀛楁
-				// 涓�浜涢粯璁ょ姸鎬佸瓧娈�
-				if (payload.status === undefined || payload.status === null || payload.status === '') {
-					payload.status = '0' // 榛樿鐘舵�侊紝鍙寜瀹為檯鏋氫妇璋冩暣
-				}
-				payload.deleted = 0
+        // 褰曞叆鏃ユ湡锛氱洿鎺ヤ娇鐢ㄨ〃鍗曢噷鐨� registrationDate 瀛楁
+        // 涓�浜涢粯璁ょ姸鎬佸瓧娈�
+        if (payload.status === undefined || payload.status === null || payload.status === "") {
+          payload.status = "0"; // 榛樿鐘舵�侊紝鍙寜瀹為檯鏋氫妇璋冩暣
+        }
+        payload.deleted = 0;
 
-				if (operationType.value === 'edit') {
-					await deviceMaintenanceTaskEdit(payload)
-				} else {
-					await deviceMaintenanceTaskAdd(payload)
-				}
-				cancel()
-				proxy.$modal.msgSuccess('鎻愪氦鎴愬姛')
-			} catch (error) {
-				proxy.$modal.msgError('鎻愪氦澶辫触锛岃閲嶈瘯')
-			}
-		}
-	})
-}
-defineExpose({ openDialog })
+        if (operationType.value === "edit") {
+          await deviceMaintenanceTaskEdit(payload);
+        } else {
+          await deviceMaintenanceTaskAdd(payload);
+        }
+        cancel();
+        proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+      } catch (error) {
+        proxy.$modal.msgError("鎻愪氦澶辫触锛岃閲嶈瘯");
+      }
+    }
+  });
+};
+defineExpose({ openDialog });
 </script>
 
 <style scoped>
-
+.maintenance-selection {
+  width: 100%;
+}
+.selection-toolbar {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.selection-hint {
+  color: #909399;
+  font-size: 12px;
+}
+.custom-input {
+  display: flex;
+  gap: 8px;
+  margin-top: 10px;
+}
+.custom-input .el-input:first-child {
+  flex: 0 0 30%;
+}
+.custom-input .el-input:nth-child(2) {
+  flex: 1;
+  min-width: 0;
+}
+.selected-panel {
+  margin-top: 10px;
+  border: 1px solid #ebeef5;
+  border-radius: 4px;
+  background: #fafafa;
+}
+.selected-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 8px 12px;
+  border-bottom: 1px solid #ebeef5;
+}
+.selected-title {
+  font-weight: 600;
+  color: #303133;
+}
+.selected-stats {
+  display: flex;
+  gap: 12px;
+  color: #909399;
+  font-size: 12px;
+}
+.selected-list {
+  max-height: 220px;
+  margin: 0;
+  padding: 4px 0;
+  overflow-y: auto;
+  list-style: none;
+}
+.selected-row {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  padding: 6px 12px;
+}
+.selected-row:hover {
+  background: #f0f7ff;
+}
+.row-index {
+  width: 24px;
+  flex-shrink: 0;
+  color: #909399;
+  text-align: right;
+}
+.row-text {
+  flex: 1;
+  min-width: 0;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  color: #303133;
+}
 </style>
diff --git a/src/views/equipmentManagement/upkeep/index.vue b/src/views/equipmentManagement/upkeep/index.vue
index cd1adff..4c55031 100644
--- a/src/views/equipmentManagement/upkeep/index.vue
+++ b/src/views/equipmentManagement/upkeep/index.vue
@@ -1,192 +1,173 @@
 <template>
   <div class="app-container">
-    <el-tabs v-model="activeTab"
-             @tab-change="handleTabChange">
+    <el-tabs v-model="activeTab" @tab-change="handleTabChange">
       <!-- 淇濆吇浠诲姟tab -->
-      <el-tab-pane label="淇濆吇浠诲姟"
-                   name="scheduled">
+      <el-tab-pane label="淇濆吇浠诲姟" name="scheduled">
         <div class="search_form">
-          <el-form :model="scheduledFilters"
-                   :inline="true">
+          <el-form :model="scheduledFilters" :inline="true">
             <el-form-item label="浠诲姟鍚嶇О">
-              <el-input v-model="scheduledFilters.taskName"
-                        style="width: 240px"
-                        placeholder="璇疯緭鍏ヤ换鍔″悕绉�"
-                        clearable
-                        :prefix-icon="Search"
-                        @change="getScheduledTableData" />
+              <el-input
+                v-model="scheduledFilters.taskName"
+                style="width: 240px"
+                placeholder="璇疯緭鍏ヤ换鍔″悕绉�"
+                clearable
+                :prefix-icon="Search"
+                @change="getScheduledTableData"
+              />
             </el-form-item>
             <el-form-item label="浠诲姟鐘舵��">
-              <el-select v-model="scheduledFilters.status"
-                         placeholder="璇烽�夋嫨浠诲姟鐘舵��"
-                         clearable
-                         style="width: 200px">
-                <el-option label="鍚敤"
-                           value="1" />
-                <el-option label="鍋滅敤"
-                           value="0" />
+              <el-select
+                v-model="scheduledFilters.status"
+                placeholder="璇烽�夋嫨浠诲姟鐘舵��"
+                clearable
+                style="width: 200px"
+              >
+                <el-option label="鍚敤" value="1" />
+                <el-option label="鍋滅敤" value="0" />
               </el-select>
             </el-form-item>
             <el-form-item>
-              <el-button type="primary"
-                         @click="getScheduledTableData">鎼滅储</el-button>
+              <el-button type="primary" @click="getScheduledTableData">鎼滅储</el-button>
               <el-button @click="resetScheduledFilters">閲嶇疆</el-button>
             </el-form-item>
           </el-form>
         </div>
         <div class="table_list">
           <div class="actions">
-            <el-text class="mx-1"
-                     size="large">淇濆吇浠诲姟</el-text>
+            <el-text class="mx-1" size="large">淇濆吇浠诲姟</el-text>
             <div>
-              <el-button type="primary"
-                         icon="Plus"
-                         @click="addScheduledTask">
-                鏂板浠诲姟
-              </el-button>
-              <el-button type="danger"
-                         icon="Delete"
-                         :disabled="scheduledMultipleList.length <= 0"
-                         @click="delScheduledTaskByIds(scheduledMultipleList.map((item) => item.id))">
+              <el-button type="primary" icon="Plus" @click="addScheduledTask"> 鏂板浠诲姟 </el-button>
+              <el-button
+                type="danger"
+                icon="Delete"
+                :disabled="scheduledMultipleList.length <= 0"
+                @click="delScheduledTaskByIds(scheduledMultipleList.map((item) => item.id))"
+              >
                 鎵归噺鍒犻櫎
               </el-button>
             </div>
           </div>
-          <PIMTable rowKey="id"
-                    isSelection
-                    :column="scheduledColumns"
-                    :tableData="scheduledDataList"
-                    :page="{
+          <PIMTable
+            rowKey="id"
+            isSelection
+            :column="scheduledColumns"
+            :tableData="scheduledDataList"
+            :page="{
               current: scheduledPagination.currentPage,
               size: scheduledPagination.pageSize,
               total: scheduledPagination.total,
             }"
-                    @selection-change="handleScheduledSelectionChange"
-                    @pagination="changeScheduledPage">
+            @selection-change="handleScheduledSelectionChange"
+            @pagination="changeScheduledPage"
+          >
             <template #isActiveRef="{ row }">
-              <el-tag v-if="row.isActive === 1"
-                      type="success">寮�鍚�</el-tag>
-              <el-tag v-else
-                      type="info">鍏抽棴</el-tag>
+              <el-tag v-if="row.isActive === 1" type="success">寮�鍚�</el-tag>
+              <el-tag v-else type="info">鍏抽棴</el-tag>
             </template>
             <template #statusRef="{ row }">
-              <el-tag v-if="row.status === 1"
-                      type="success">鍚敤</el-tag>
-              <el-tag v-if="row.status === 0"
-                      type="danger">鍋滅敤</el-tag>
+              <el-tag v-if="row.status === 1" type="success">鍚敤</el-tag>
+              <el-tag v-if="row.status === 0" type="danger">鍋滅敤</el-tag>
             </template>
             <template #operation="{ row }">
-              <el-button type="primary"
-                         link
-                         @click="handleDetail(row)">
-                璇︽儏
-              </el-button>
-              <el-button type="primary"
-                         link
-                         @click="editScheduledTask(row)">
-                缂栬緫
-              </el-button>
-              <el-button type="danger"
-                         link
-                         @click="delScheduledTaskByIds(row.id)">
+              <el-button type="primary" link @click="handleDetail(row)"> 璇︽儏 </el-button>
+              <el-button type="primary" link @click="editScheduledTask(row)"> 缂栬緫 </el-button>
+              <el-button type="danger" link @click="delScheduledTaskByIds(row.id)">
                 鍒犻櫎
               </el-button>
             </template>
           </PIMTable>
         </div>
       </el-tab-pane>
+      <el-tab-pane label="淇濆吇鍐呭" name="items">
+        <ItemManager />
+      </el-tab-pane>
       <!-- 淇濆吇璁板綍tab锛堝師璁惧淇濆吇椤甸潰锛� -->
-      <el-tab-pane label="淇濆吇璁板綍"
-                   name="record">
+      <el-tab-pane label="淇濆吇璁板綍" name="record">
         <div class="search_form">
-          <el-form :model="filters"
-                   :inline="true">
+          <el-form :model="filters" :inline="true">
             <el-form-item label="璁惧鍚嶇О">
-              <el-input v-model="filters.deviceName"
-                        style="width: 240px"
-                        placeholder="璇疯緭鍏ヨ澶囧悕绉�"
-                        clearable
-                        :prefix-icon="Search"
-                        @change="getTableData" />
+              <el-input
+                v-model="filters.deviceName"
+                style="width: 240px"
+                placeholder="璇疯緭鍏ヨ澶囧悕绉�"
+                clearable
+                :prefix-icon="Search"
+                @change="getTableData"
+              />
             </el-form-item>
             <el-form-item label="璁″垝淇濆吇鏃ユ湡">
-              <el-date-picker v-model="filters.maintenancePlanTime"
-                              type="date"
-                              placeholder="璇烽�夋嫨璁″垝淇濆吇鏃ユ湡"
-                              size="default"
-                              @change="(date) => handleDateChange(date,2)" />
+              <el-date-picker
+                v-model="filters.maintenancePlanTime"
+                type="date"
+                placeholder="璇烽�夋嫨璁″垝淇濆吇鏃ユ湡"
+                size="default"
+                @change="(date) => handleDateChange(date, 2)"
+              />
             </el-form-item>
             <el-form-item label="瀹為檯淇濆吇鏃ユ湡">
-              <el-date-picker v-model="filters.maintenanceActuallyTime"
-                              type="date"
-                              placeholder="璇烽�夋嫨瀹為檯淇濆吇鏃ユ湡"
-                              size="default"
-                              @change="(date) => handleDateChange(date,1)" />
+              <el-date-picker
+                v-model="filters.maintenanceActuallyTime"
+                type="date"
+                placeholder="璇烽�夋嫨瀹為檯淇濆吇鏃ユ湡"
+                size="default"
+                @change="(date) => handleDateChange(date, 1)"
+              />
             </el-form-item>
             <el-form-item label="瀹為檯淇濆吇浜�">
-              <el-input v-model="filters.maintenanceActuallyName"
-                        style="width: 240px"
-                        placeholder="璇疯緭鍏ュ疄闄呬繚鍏讳汉"
-                        clearable
-                        :prefix-icon="Search"
-                        @change="getTableData" />
+              <el-input
+                v-model="filters.maintenanceActuallyName"
+                style="width: 240px"
+                placeholder="璇疯緭鍏ュ疄闄呬繚鍏讳汉"
+                clearable
+                :prefix-icon="Search"
+                @change="getTableData"
+              />
             </el-form-item>
             <el-form-item>
-              <el-button type="primary"
-                         @click="getTableData">鎼滅储</el-button>
+              <el-button type="primary" @click="getTableData">鎼滅储</el-button>
               <el-button @click="resetFilters">閲嶇疆</el-button>
             </el-form-item>
           </el-form>
         </div>
         <div class="table_list">
           <div class="actions">
-            <el-text class="mx-1"
-                     size="large">淇濆吇璁板綍</el-text>
+            <el-text class="mx-1" size="large">淇濆吇璁板綍</el-text>
             <div>
-              <el-button type="success"
-                         icon="Van"
-                         @click="addPlan">
-                鏂板璁″垝
-              </el-button>
-              <el-button @click="handleOut">
-                瀵煎嚭
-              </el-button>
-              <el-button type="danger"
-                         icon="Delete"
-                         :disabled="multipleList.length <= 0 || hasFinishedStatus"
-                         @click="delRepairByIds(multipleList.map((item) => item.id))">
+              <el-button type="success" icon="Van" @click="addPlan"> 鏂板璁″垝 </el-button>
+              <el-button @click="handleOut"> 瀵煎嚭 </el-button>
+              <el-button
+                type="danger"
+                icon="Delete"
+                :disabled="multipleList.length <= 0 || hasFinishedStatus"
+                @click="delRepairByIds(multipleList.map((item) => item.id))"
+              >
                 鎵归噺鍒犻櫎
               </el-button>
             </div>
           </div>
-          <PIMTable rowKey="id"
-                    isSelection
-                    :column="columns"
-                    :tableData="dataList"
-                    :page="{
-          current: pagination.currentPage,
-          size: pagination.pageSize,
-          total: pagination.total,
-        }"
-                    @selection-change="handleSelectionChange"
-                    @pagination="changePage">
+          <PIMTable
+            rowKey="id"
+            isSelection
+            :column="columns"
+            :tableData="dataList"
+            :page="{
+              current: pagination.currentPage,
+              size: pagination.pageSize,
+              total: pagination.total,
+            }"
+            @selection-change="handleSelectionChange"
+            @pagination="changePage"
+          >
             <template #maintenanceResultRef="{ row }">
-              <div>{{ row.maintenanceResult || '-' }}</div>
+              <div>{{ row.maintenanceResult || "-" }}</div>
             </template>
             <template #statusRef="{ row }">
-              <el-tag v-if="row.status === 2"
-                      type="danger">澶辫触</el-tag>
-              <el-tag v-if="row.status === 1"
-                      type="success">瀹岀粨</el-tag>
-              <el-tag v-if="row.status === 0"
-                      type="warning">寰呬繚鍏�</el-tag>
+              <el-tag v-if="row.status === 2" type="danger">澶辫触</el-tag>
+              <el-tag v-if="row.status === 1" type="success">瀹岀粨</el-tag>
+              <el-tag v-if="row.status === 0" type="warning">寰呬繚鍏�</el-tag>
             </template>
             <template #operation="{ row }">
-              <el-button type="primary"
-                         link
-                         @click="handleRecordDetail(row)">
-                璇︽儏
-              </el-button>
+              <el-button type="primary" link @click="handleRecordDetail(row)"> 璇︽儏 </el-button>
               <!-- 杩欎釜鍔熻兘璺熸柊澧炰繚鍏诲姛鑳戒竴妯′竴鏍凤紝鏈夊暐鎰忎箟锛� -->
               <!-- <el-button
               type="primary"
@@ -195,509 +176,475 @@
           >
             鏂板淇濆吇
           </el-button> -->
-              <el-button type="primary"
-                         link
-                         :disabled="row.status === 1"
-                         @click="editPlan(row.id)">
+              <el-button type="primary" link :disabled="row.status === 1" @click="editPlan(row.id)">
                 缂栬緫
               </el-button>
-              <el-button type="success"
-                         link
-                         :disabled="row.status === 1"
-                         @click="addMaintain(row)">
+              <el-button type="success" link :disabled="row.status === 1" @click="addMaintain(row)">
                 淇濆吇
               </el-button>
-              <el-button type="danger"
-                         link
-                         :disabled="row.status === 1"
-                         @click="delRepairByIds(row.id)">
+              <el-button
+                type="danger"
+                link
+                :disabled="row.status === 1"
+                @click="delRepairByIds(row.id)"
+              >
                 鍒犻櫎
               </el-button>
-              <el-button type="primary"
-                         link
-                         @click="openFileDialog(row)">
-                闄勪欢
-              </el-button>
+              <el-button type="primary" link @click="openFileDialog(row)"> 闄勪欢 </el-button>
             </template>
           </PIMTable>
         </div>
       </el-tab-pane>
     </el-tabs>
-    <PlanModal ref="planModalRef"
-               @ok="getTableData" />
-    <MaintenanceModal ref="maintainModalRef"
-                      @ok="getTableData" />
-    <FormDia ref="formDiaRef"
-             @closeDia="getScheduledTableData" />
+    <PlanModal ref="planModalRef" @ok="getTableData" />
+    <MaintenanceModal ref="maintainModalRef" @ok="getTableData" />
+    <FormDia ref="formDiaRef" @closeDia="getScheduledTableData" />
     <DetailDia ref="detailDiaRef" />
     <RecordDetailDia ref="recordDetailDiaRef" />
-    <FileList v-if="fileDialogVisible"
-              v-model:visible="fileDialogVisible"
-              :record-type="'device_maintenance'"
-              :record-id="currentMaintenanceTaskId" />
+    <FileList
+      v-if="fileDialogVisible"
+      v-model:visible="fileDialogVisible"
+      :record-type="'device_maintenance'"
+      :record-id="currentMaintenanceTaskId"
+    />
   </div>
 </template>
 
 <script setup>
-  import {
-    ref,
-    onMounted,
-    reactive,
-    getCurrentInstance,
-    nextTick,
-    computed,
-    defineAsyncComponent,
-  } from "vue";
-  import { Search } from "@element-plus/icons-vue";
-  import { ElMessage, ElMessageBox } from "element-plus";
-  import PlanModal from "./Form/PlanModal.vue";
-  import MaintenanceModal from "./Form/MaintenanceModal.vue";
-  import FormDia from "./Form/formDia.vue";
-  import DetailDia from "./Form/detailDia.vue";
-  import RecordDetailDia from "./Form/RecordDetailDia.vue";
-  import {
-    getUpkeepPage,
-    delUpkeep,
-    deviceMaintenanceTaskList,
-    deviceMaintenanceTaskDel,
-  } from "@/api/equipmentManagement/upkeep";
-  import dayjs from "dayjs";
+import {
+  ref,
+  onMounted,
+  reactive,
+  getCurrentInstance,
+  nextTick,
+  computed,
+  defineAsyncComponent,
+} from "vue";
+import { Search } from "@element-plus/icons-vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import PlanModal from "./Form/PlanModal.vue";
+import MaintenanceModal from "./Form/MaintenanceModal.vue";
+import FormDia from "./Form/formDia.vue";
+import DetailDia from "./Form/detailDia.vue";
+import RecordDetailDia from "./Form/RecordDetailDia.vue";
+import ItemManager from "./Form/ItemManager.vue";
+import {
+  getUpkeepPage,
+  delUpkeep,
+  deviceMaintenanceTaskList,
+  deviceMaintenanceTaskDel,
+} from "@/api/equipmentManagement/upkeep";
+import dayjs from "dayjs";
 
-  const { proxy } = getCurrentInstance();
-  const FileList = defineAsyncComponent(() =>
-    import("@/components/Dialog/FileList.vue")
-  );
+const { proxy } = getCurrentInstance();
+const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
 
-  // Tab鐩稿叧
-  const activeTab = ref("scheduled");
+// Tab鐩稿叧
+const activeTab = ref("scheduled");
 
-  // 璁″垝寮圭獥鎺у埗鍣�
-  const planModalRef = ref();
-  // 淇濆吇寮圭獥鎺у埗鍣�
-  const maintainModalRef = ref();
-  // 瀹氭椂浠诲姟寮圭獥鎺у埗鍣�
-  const formDiaRef = ref();
-  // 瀹氭椂浠诲姟璇︽儏寮圭獥鎺у埗鍣�
-  const detailDiaRef = ref();
-  // 淇濆吇璁板綍璇︽儏寮圭獥鎺у埗鍣�
-  const recordDetailDiaRef = ref();
-  // 闄勪欢寮圭獥
-  const fileListDialogRef = ref(null);
-  const fileDialogVisible = ref(false);
-  const currentMaintenanceTaskId = ref(null);
+// 璁″垝寮圭獥鎺у埗鍣�
+const planModalRef = ref();
+// 淇濆吇寮圭獥鎺у埗鍣�
+const maintainModalRef = ref();
+// 瀹氭椂浠诲姟寮圭獥鎺у埗鍣�
+const formDiaRef = ref();
+// 瀹氭椂浠诲姟璇︽儏寮圭獥鎺у埗鍣�
+const detailDiaRef = ref();
+// 淇濆吇璁板綍璇︽儏寮圭獥鎺у埗鍣�
+const recordDetailDiaRef = ref();
+// 闄勪欢寮圭獥
+const fileListDialogRef = ref(null);
+const fileDialogVisible = ref(false);
+const currentMaintenanceTaskId = ref(null);
 
-  // 淇濆吇璁板綍tab锛堝師璁惧淇濆吇椤甸潰锛夌浉鍏冲彉閲�
-  const filters = reactive({
-    deviceName: "",
-    maintenancePlanTime: "",
-    maintenanceActuallyTime: "",
-    maintenanceActuallyName: "",
-  });
+// 淇濆吇璁板綍tab锛堝師璁惧淇濆吇椤甸潰锛夌浉鍏冲彉閲�
+const filters = reactive({
+  deviceName: "",
+  maintenancePlanTime: "",
+  maintenanceActuallyTime: "",
+  maintenanceActuallyName: "",
+});
 
-  const dataList = ref([]);
-  const pagination = ref({
-    currentPage: 1,
-    pageSize: 10,
-    total: 0,
-  });
-  const multipleList = ref([]);
+const dataList = ref([]);
+const pagination = ref({
+  currentPage: 1,
+  pageSize: 10,
+  total: 0,
+});
+const multipleList = ref([]);
 
-  // 淇濆吇浠诲姟tab鐩稿叧鍙橀噺
-  const scheduledFilters = reactive({
-    taskName: "",
-    status: "",
-  });
+// 淇濆吇浠诲姟tab鐩稿叧鍙橀噺
+const scheduledFilters = reactive({
+  taskName: "",
+  status: "",
+});
 
-  const scheduledDataList = ref([]);
-  const scheduledPagination = reactive({
-    currentPage: 1,
-    pageSize: 10,
-    total: 0,
-  });
-  const scheduledMultipleList = ref([]);
+const scheduledDataList = ref([]);
+const scheduledPagination = reactive({
+  currentPage: 1,
+  pageSize: 10,
+  total: 0,
+});
+const scheduledMultipleList = ref([]);
 
-  // 淇濆吇浠诲姟琛ㄦ牸鍒楅厤缃�
-  const scheduledColumns = ref([
-    { prop: "taskName", label: "璁惧鍚嶇О" },
-    {
-      label: "瑙勬牸鍨嬪彿",
-      prop: "deviceModel",
-    },
-    {
-      label: "淇濆吇椤圭洰",
-      prop: "machineryCategory",
-      minWidth: 120,
-      formatData: cell => cell || "--",
-    },
-    {
-      prop: "frequencyType",
-      label: "棰戞",
-      minWidth: 80,
-      // PIMTable 浣跨敤鐨勬槸 formatData锛岃�屼笉鏄� Element-Plus 鐨� formatter
-      formatData: cell =>
-        ({
-          DAILY: "姣忔棩",
-          WEEKLY: "姣忓懆",
-          MONTHLY: "姣忔湀",
-          QUARTERLY: "瀛e害",
-        }[cell] || ""),
-    },
-    {
-      prop: "frequencyDetail",
-      label: "寮�濮嬫棩鏈熶笌鏃堕棿",
-      minWidth: 130,
-      // 鍚屾牱鏀圭敤 formatData锛孭IMTable 鍐呴儴浼氭妸鍗曞厓鏍煎�间紶杩涙潵
-      formatData: cell => {
-        if (typeof cell !== "string") return "";
-        let val = cell;
-        const replacements = {
-          MON: "鍛ㄤ竴",
-          TUE: "鍛ㄤ簩",
-          WED: "鍛ㄤ笁",
-          THU: "鍛ㄥ洓",
-          FRI: "鍛ㄤ簲",
-          SAT: "鍛ㄥ叚",
-          SUN: "鍛ㄦ棩",
-        };
-        // 浣跨敤姝e垯涓�娆℃�ф浛鎹㈡墍鏈夊尮閰嶉」
-        return val.replace(
-          /MON|TUE|WED|THU|FRI|SAT|SUN/g,
-          match => replacements[match]
-        );
-      },
-    },
-    {
-      prop: "isActive",
-      label: "瀹氭椂浠诲姟",
-      dataType: "slot",
-      slot: "isActiveRef",
-      align: "center",
-      minWidth: 100,
-    },
-    { prop: "maintenancePerson", label: "淇濆吇浜�", minWidth: 100 },
-    { prop: "registrant", label: "鐧昏浜�", minWidth: 100 },
-    {
-      prop: "registrationDate",
-      label: "鐧昏鏃ユ湡",
-      minWidth: 100,
-      formatData: cell =>
-        cell ? dayjs(cell).format("YYYY-MM-DD") : "-",
-    },
-    {
-      fixed: "right",
-      label: "鎿嶄綔",
-      dataType: "slot",
-      slot: "operation",
-      align: "center",
-      width: "160px",
-    },
-  ]);
-
-  // 淇濆吇璁板綍琛ㄦ牸鍒楅厤缃紙鍘熻澶囦繚鍏昏〃鏍煎垪锛�
-  const columns = ref([
-    {
-      label: "璁惧鍚嶇О",
-      align: "center",
-      prop: "deviceName",
-    },
-    {
-      label: "瑙勬牸鍨嬪彿",
-      align: "center",
-      prop: "deviceModel",
-    },
-    {
-      label: "璁″垝淇濆吇鏃ユ湡",
-      align: "center",
-      prop: "maintenancePlanTime",
-      formatData: cell => {
-        return cell == null ? "-" : dayjs(cell).format("YYYY-MM-DD");
-      },
-    },
-    {
-      label: "褰曞叆浜�",
-      align: "center",
-      prop: "createUserName",
-    },
-    {
-      label: "淇濆吇椤圭洰",
-      align: "center",
-      prop: "machineryCategory",
-      formatData: cell => cell || "--",
-    },
-    // {
-    //   label: "褰曞叆鏃ユ湡",
-    //   align: "center",
-    //   prop: "createTime",
-    //   formatData: (cell) => dayjs(cell).format("YYYY-MM-DD HH:mm:ss"),
-    //   width: 200,
-    // },
-    {
-      label: "瀹為檯淇濆吇浜�",
-      align: "center",
-      prop: "maintenanceActuallyName",
-    },
-    {
-      label: "瀹為檯淇濆吇鏃ユ湡",
-      align: "center",
-      prop: "maintenanceActuallyTime",
-      formatData: cell =>
-        cell ? dayjs(cell).format("YYYY-MM-DD") : "-",
-    },
-    {
-      label: "淇濆吇缁撴灉",
-      align: "center",
-      prop: "maintenanceResult",
-      dataType: "slot",
-      slot: "maintenanceResultRef",
-    },
-    {
-      label: "鐘舵��",
-      align: "center",
-      prop: "status",
-      dataType: "slot",
-      slot: "statusRef",
-    },
-    {
-      fixed: "right",
-      label: "鎿嶄綔",
-      dataType: "slot",
-      slot: "operation",
-      align: "center",
-      width: "250px",
-    },
-  ]);
-
-  // Tab鍒囨崲澶勭悊
-  const handleTabChange = tabName => {
-    if (tabName === "record") {
-      getTableData();
-    } else if (tabName === "scheduled") {
-      getScheduledTableData();
-    }
-  };
-
-  // 淇濆吇浠诲姟鐩稿叧鏂规硶
-  const getScheduledTableData = async () => {
-    try {
-      const params = {
-        current: scheduledPagination.currentPage,
-        size: scheduledPagination.pageSize,
-        taskName: scheduledFilters.taskName || undefined,
-        status: scheduledFilters.status || undefined,
+// 淇濆吇浠诲姟琛ㄦ牸鍒楅厤缃�
+const scheduledColumns = ref([
+  { prop: "taskName", label: "璁惧鍚嶇О" },
+  {
+    label: "瑙勬牸鍨嬪彿",
+    prop: "deviceModel",
+  },
+  {
+    prop: "frequencyType",
+    label: "棰戞",
+    minWidth: 80,
+    // PIMTable 浣跨敤鐨勬槸 formatData锛岃�屼笉鏄� Element-Plus 鐨� formatter
+    formatData: (cell) =>
+      ({
+        DAILY: "姣忔棩",
+        WEEKLY: "姣忓懆",
+        MONTHLY: "姣忔湀",
+        QUARTERLY: "瀛e害",
+      }[cell] || ""),
+  },
+  {
+    prop: "frequencyDetail",
+    label: "寮�濮嬫棩鏈熶笌鏃堕棿",
+    minWidth: 130,
+    // 鍚屾牱鏀圭敤 formatData锛孭IMTable 鍐呴儴浼氭妸鍗曞厓鏍煎�间紶杩涙潵
+    formatData: (cell) => {
+      if (typeof cell !== "string") return "";
+      let val = cell;
+      const replacements = {
+        MON: "鍛ㄤ竴",
+        TUE: "鍛ㄤ簩",
+        WED: "鍛ㄤ笁",
+        THU: "鍛ㄥ洓",
+        FRI: "鍛ㄤ簲",
+        SAT: "鍛ㄥ叚",
+        SUN: "鍛ㄦ棩",
       };
-      const { code, data } = await deviceMaintenanceTaskList(params);
-      if (code === 200) {
-        scheduledDataList.value = data?.records || [];
-        scheduledPagination.total = data?.total || 0;
-      }
-    } catch (error) {
-      ElMessage.error("鑾峰彇瀹氭椂浠诲姟鍒楄〃澶辫触");
+      // 浣跨敤姝e垯涓�娆℃�ф浛鎹㈡墍鏈夊尮閰嶉」
+      return val.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, (match) => replacements[match]);
+    },
+  },
+  {
+    prop: "isActive",
+    label: "瀹氭椂浠诲姟",
+    dataType: "slot",
+    slot: "isActiveRef",
+    align: "center",
+    minWidth: 100,
+  },
+  { prop: "maintenancePerson", label: "淇濆吇浜�", minWidth: 100 },
+  { prop: "registrant", label: "鐧昏浜�", minWidth: 100 },
+  {
+    prop: "registrationDate",
+    label: "鐧昏鏃ユ湡",
+    minWidth: 100,
+    formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : "-"),
+  },
+  {
+    fixed: "right",
+    label: "鎿嶄綔",
+    dataType: "slot",
+    slot: "operation",
+    align: "center",
+    width: "160px",
+  },
+]);
+
+// 淇濆吇璁板綍琛ㄦ牸鍒楅厤缃紙鍘熻澶囦繚鍏昏〃鏍煎垪锛�
+const columns = ref([
+  {
+    label: "璁惧鍚嶇О",
+    align: "center",
+    prop: "deviceName",
+  },
+  {
+    label: "瑙勬牸鍨嬪彿",
+    align: "center",
+    prop: "deviceModel",
+  },
+  {
+    label: "璁″垝淇濆吇鏃ユ湡",
+    align: "center",
+    prop: "maintenancePlanTime",
+    formatData: (cell) => {
+      return cell == null ? "-" : dayjs(cell).format("YYYY-MM-DD");
+    },
+  },
+  {
+    label: "褰曞叆浜�",
+    align: "center",
+    prop: "createUserName",
+  },
+  // {
+  //   label: "褰曞叆鏃ユ湡",
+  //   align: "center",
+  //   prop: "createTime",
+  //   formatData: (cell) => dayjs(cell).format("YYYY-MM-DD HH:mm:ss"),
+  //   width: 200,
+  // },
+  {
+    label: "瀹為檯淇濆吇浜�",
+    align: "center",
+    prop: "maintenanceActuallyName",
+  },
+  {
+    label: "瀹為檯淇濆吇鏃ユ湡",
+    align: "center",
+    prop: "maintenanceActuallyTime",
+    formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : "-"),
+  },
+  {
+    label: "淇濆吇缁撴灉",
+    align: "center",
+    prop: "maintenanceResult",
+    dataType: "slot",
+    slot: "maintenanceResultRef",
+  },
+  {
+    label: "鐘舵��",
+    align: "center",
+    prop: "status",
+    dataType: "slot",
+    slot: "statusRef",
+  },
+  {
+    fixed: "right",
+    label: "鎿嶄綔",
+    dataType: "slot",
+    slot: "operation",
+    align: "center",
+    width: "250px",
+  },
+]);
+
+// Tab鍒囨崲澶勭悊
+const handleTabChange = (tabName) => {
+  if (tabName === "record") {
+    getTableData();
+  } else if (tabName === "scheduled") {
+    getScheduledTableData();
+  }
+};
+
+// 淇濆吇浠诲姟鐩稿叧鏂规硶
+const getScheduledTableData = async () => {
+  try {
+    const params = {
+      current: scheduledPagination.currentPage,
+      size: scheduledPagination.pageSize,
+      taskName: scheduledFilters.taskName || undefined,
+      status: scheduledFilters.status || undefined,
+    };
+    const { code, data } = await deviceMaintenanceTaskList(params);
+    if (code === 200) {
+      scheduledDataList.value = data?.records || [];
+      scheduledPagination.total = data?.total || 0;
     }
-  };
+  } catch (error) {
+    ElMessage.error("鑾峰彇瀹氭椂浠诲姟鍒楄〃澶辫触");
+  }
+};
 
-  const resetScheduledFilters = () => {
-    scheduledFilters.taskName = "";
-    scheduledFilters.status = "";
-    getScheduledTableData();
-  };
+const resetScheduledFilters = () => {
+  scheduledFilters.taskName = "";
+  scheduledFilters.status = "";
+  getScheduledTableData();
+};
 
-  const handleScheduledSelectionChange = selection => {
-    scheduledMultipleList.value = selection;
-  };
+const handleScheduledSelectionChange = (selection) => {
+  scheduledMultipleList.value = selection;
+};
 
-  const changeScheduledPage = page => {
-    scheduledPagination.currentPage = page.page;
-    scheduledPagination.pageSize = page.limit;
-    getScheduledTableData();
-  };
+const changeScheduledPage = (page) => {
+  scheduledPagination.currentPage = page.page;
+  scheduledPagination.pageSize = page.limit;
+  getScheduledTableData();
+};
 
-  const addScheduledTask = () => {
+const addScheduledTask = () => {
+  nextTick(() => {
+    formDiaRef.value?.openDialog("add");
+  });
+};
+
+const editScheduledTask = (row) => {
+  if (row) {
     nextTick(() => {
-      formDiaRef.value?.openDialog("add");
+      formDiaRef.value?.openDialog("edit", row);
     });
-  };
+  }
+};
 
-  const editScheduledTask = row => {
-    if (row) {
-      nextTick(() => {
-        formDiaRef.value?.openDialog("edit", row);
-      });
+const handleDetail = (row) => {
+  if (row) {
+    nextTick(() => {
+      detailDiaRef.value?.openDialog(row);
+    });
+  }
+};
+
+const delScheduledTaskByIds = async (ids) => {
+  try {
+    await ElMessageBox.confirm("纭畾鍒犻櫎閫変腑鐨勫畾鏃朵换鍔″悧锛�", "鎻愮ず", {
+      type: "warning",
+    });
+    const payload = Array.isArray(ids) ? ids : [ids];
+    await deviceMaintenanceTaskDel(payload);
+    ElMessage.success("鍒犻櫎瀹氭椂浠诲姟鎴愬姛");
+    getScheduledTableData();
+  } catch (error) {
+    // 鐢ㄦ埛鍙栨秷鍒犻櫎
+  }
+};
+
+const handleScheduledOut = () => {
+  ElMessage.info("瀵煎嚭瀹氭椂浠诲姟鍔熻兘寰呭疄鐜�");
+};
+
+// 淇濆吇璁板綍鐩稿叧鏂规硶锛堝師璁惧淇濆吇椤甸潰鏂规硶锛�
+const getTableData = async () => {
+  try {
+    const params = {
+      current: pagination.value.currentPage,
+      size: pagination.value.pageSize,
+      deviceName: filters.deviceName || undefined,
+      maintenancePlanTime: filters.maintenancePlanTime
+        ? dayjs(filters.maintenancePlanTime).format("YYYY-MM-DD")
+        : undefined,
+      maintenanceActuallyTime: filters.maintenanceActuallyTime
+        ? dayjs(filters.maintenanceActuallyTime).format("YYYY-MM-DD")
+        : undefined,
+      maintenanceActuallyName: filters.maintenanceActuallyName || undefined,
+    };
+
+    const { code, data } = await getUpkeepPage(params);
+    if (code === 200) {
+      dataList.value = data.records;
+      pagination.value.total = data.total;
     }
-  };
+  } catch (error) {
+    console.log(error);
+  }
+};
 
-  const handleDetail = row => {
-    if (row) {
-      nextTick(() => {
-        detailDiaRef.value?.openDialog(row);
-      });
-    }
-  };
+const resetFilters = () => {
+  filters.deviceName = "";
+  filters.maintenancePlanTime = "";
+  filters.maintenanceActuallyTime = "";
+  filters.maintenanceActuallyName = "";
+  getTableData();
+};
 
-  const delScheduledTaskByIds = async ids => {
-    try {
-      await ElMessageBox.confirm("纭畾鍒犻櫎閫変腑鐨勫畾鏃朵换鍔″悧锛�", "鎻愮ず", {
-        type: "warning",
-      });
-      const payload = Array.isArray(ids) ? ids : [ids];
-      await deviceMaintenanceTaskDel(payload);
-      ElMessage.success("鍒犻櫎瀹氭椂浠诲姟鎴愬姛");
-      getScheduledTableData();
-    } catch (error) {
-      // 鐢ㄦ埛鍙栨秷鍒犻櫎
-    }
-  };
+const handleSelectionChange = (selection) => {
+  multipleList.value = selection;
+};
 
-  const handleScheduledOut = () => {
-    ElMessage.info("瀵煎嚭瀹氭椂浠诲姟鍔熻兘寰呭疄鐜�");
-  };
+// 妫�鏌ラ�変腑鐨勮褰曚腑鏄惁鏈夊畬缁撶姸鎬佺殑
+const hasFinishedStatus = computed(() => {
+  return multipleList.value.some((item) => item.status === 1);
+});
 
-  // 淇濆吇璁板綍鐩稿叧鏂规硶锛堝師璁惧淇濆吇椤甸潰鏂规硶锛�
-  const getTableData = async () => {
-    try {
-      const params = {
-        current: pagination.value.currentPage,
-        size: pagination.value.pageSize,
-        deviceName: filters.deviceName || undefined,
-        maintenancePlanTime: filters.maintenancePlanTime
-          ? dayjs(filters.maintenancePlanTime).format("YYYY-MM-DD")
-          : undefined,
-        maintenanceActuallyTime: filters.maintenanceActuallyTime
-          ? dayjs(filters.maintenanceActuallyTime).format("YYYY-MM-DD")
-          : undefined,
-        maintenanceActuallyName: filters.maintenanceActuallyName || undefined,
-      };
+const changePage = (page) => {
+  pagination.value.currentPage = page.page;
+  pagination.value.pageSize = page.limit;
+  getTableData();
+};
 
-      const { code, data } = await getUpkeepPage(params);
-      if (code === 200) {
-        dataList.value = data.records;
-        pagination.value.total = data.total;
-      }
-    } catch (error) {
-      console.log(error);
-    }
-  };
+const addMaintain = (row) => {
+  maintainModalRef.value.open(row.id, row);
+};
 
-  const resetFilters = () => {
-    filters.deviceName = "";
-    filters.maintenancePlanTime = "";
-    filters.maintenanceActuallyTime = "";
-    filters.maintenanceActuallyName = "";
-    getTableData();
-  };
+const handleRecordDetail = (row) => {
+  if (row) {
+    nextTick(() => {
+      recordDetailDiaRef.value?.openDialog(row);
+    });
+  }
+};
 
-  const handleSelectionChange = selection => {
-    multipleList.value = selection;
-  };
+const addPlan = () => {
+  planModalRef.value.openModal();
+};
 
-  // 妫�鏌ラ�変腑鐨勮褰曚腑鏄惁鏈夊畬缁撶姸鎬佺殑
-  const hasFinishedStatus = computed(() => {
-    return multipleList.value.some(item => item.status === 1);
-  });
+const editPlan = (id) => {
+  planModalRef.value.openEdit(id);
+};
 
-  const changePage = page => {
-    pagination.value.currentPage = page.page;
-    pagination.value.pageSize = page.limit;
-    getTableData();
-  };
+const delRepairByIds = async (ids) => {
+  // 妫�鏌ユ槸鍚︽湁瀹岀粨鐘舵�佺殑璁板綍
+  const hasFinished = multipleList.value.some((item) => item.status === 1);
+  if (hasFinished) {
+    ElMessage.warning("涓嶈兘鍒犻櫎鐘舵�佷负瀹岀粨鐨勮褰�");
+    return;
+  }
 
-  const addMaintain = row => {
-    maintainModalRef.value.open(row.id, row);
-  };
-
-  const handleRecordDetail = row => {
-    if (row) {
-      nextTick(() => {
-        recordDetailDiaRef.value?.openDialog(row);
-      });
-    }
-  };
-
-  const addPlan = () => {
-    planModalRef.value.openModal();
-  };
-
-  const editPlan = id => {
-    planModalRef.value.openEdit(id);
-  };
-
-  const delRepairByIds = async ids => {
-    // 妫�鏌ユ槸鍚︽湁瀹岀粨鐘舵�佺殑璁板綍
-    const hasFinished = multipleList.value.some(item => item.status === 1);
-    if (hasFinished) {
-      ElMessage.warning("涓嶈兘鍒犻櫎鐘舵�佷负瀹岀粨鐨勮褰�");
-      return;
-    }
-
-    try {
-      await ElMessageBox.confirm("纭鍒犻櫎淇濆吇鏁版嵁, 姝ゆ搷浣滀笉鍙��?", "璀﹀憡", {
-        confirmButtonText: "纭畾",
-        cancelButtonText: "鍙栨秷",
-        type: "warning",
-      });
-
-      const { code } = await delUpkeep(ids);
-      if (code === 200) {
-        ElMessage.success("鍒犻櫎鎴愬姛");
-        getTableData();
-      }
-    } catch (error) {
-      // 鐢ㄦ埛鍙栨秷鍒犻櫎
-    }
-  };
-
-  const handleOut = () => {
-    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
-      confirmButtonText: "纭",
+  try {
+    await ElMessageBox.confirm("纭鍒犻櫎淇濆吇鏁版嵁, 姝ゆ搷浣滀笉鍙��?", "璀﹀憡", {
+      confirmButtonText: "纭畾",
       cancelButtonText: "鍙栨秷",
       type: "warning",
-    })
-      .then(() => {
-        proxy.download("/device/maintenance/export", {}, "璁惧淇濆吇.xlsx");
-      })
-      .catch(() => {
-        ElMessage.info("宸插彇娑�");
-      });
-  };
+    });
 
-  const handleDateChange = (date, type) => {
-    if (type === 1) {
-      filters.maintenanceActuallyTime = date
-        ? dayjs(date).format("YYYY-MM-DD")
-        : "";
-    } else {
-      filters.maintenancePlanTime = date ? dayjs(date).format("YYYY-MM-DD") : "";
-    }
-    getTableData();
-  };
-
-  // 鎵撳紑闄勪欢寮圭獥
-  const openFileDialog = async row => {
-    currentMaintenanceTaskId.value = row.id;
-    fileDialogVisible.value = true;
-  };
-
-  onMounted(() => {
-    // 鏍规嵁榛樿婵�娲荤殑 Tab 璋冪敤瀵瑰簲鐨勬煡璇㈡帴鍙�
-    if (activeTab.value === "scheduled") {
-      getScheduledTableData();
-    } else {
+    const { code } = await delUpkeep(ids);
+    if (code === 200) {
+      ElMessage.success("鍒犻櫎鎴愬姛");
       getTableData();
     }
-  });
+  } catch (error) {
+    // 鐢ㄦ埛鍙栨秷鍒犻櫎
+  }
+};
+
+const handleOut = () => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      proxy.download("/device/maintenance/export", {}, "璁惧淇濆吇.xlsx");
+    })
+    .catch(() => {
+      ElMessage.info("宸插彇娑�");
+    });
+};
+
+const handleDateChange = (date, type) => {
+  if (type === 1) {
+    filters.maintenanceActuallyTime = date ? dayjs(date).format("YYYY-MM-DD") : "";
+  } else {
+    filters.maintenancePlanTime = date ? dayjs(date).format("YYYY-MM-DD") : "";
+  }
+  getTableData();
+};
+
+// 鎵撳紑闄勪欢寮圭獥
+const openFileDialog = async (row) => {
+  currentMaintenanceTaskId.value = row.id;
+  fileDialogVisible.value = true;
+};
+
+onMounted(() => {
+  // 鏍规嵁榛樿婵�娲荤殑 Tab 璋冪敤瀵瑰簲鐨勬煡璇㈡帴鍙�
+  if (activeTab.value === "scheduled") {
+    getScheduledTableData();
+  } else {
+    getTableData();
+  }
+});
 </script>
 
 <style lang="scss" scoped>
-  .table_list {
-    margin-top: unset;
-  }
-  .actions {
-    display: flex;
-    justify-content: space-between;
-    margin-bottom: 10px;
-  }
+.table_list {
+  margin-top: unset;
+}
+.actions {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 10px;
+}
 </style>
-
-
-
-
-

--
Gitblit v1.9.3