From 9069f337c18c44406c5d841d2354193c61988bd9 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期四, 23 四月 2026 13:05:19 +0800
Subject: [PATCH] 新增报修图片管理功能,包括图片上传、删除和列表查询,优化报修页面的图片处理逻辑

---
 src/api/equipmentManagement/repair.js          |   24 ++++
 src/pages/equipmentManagement/repair/index.vue |    3 
 src/pages/equipmentManagement/repair/add.vue   |  318 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 328 insertions(+), 17 deletions(-)

diff --git a/src/api/equipmentManagement/repair.js b/src/api/equipmentManagement/repair.js
index 927d5fb..6b19027 100644
--- a/src/api/equipmentManagement/repair.js
+++ b/src/api/equipmentManagement/repair.js
@@ -76,4 +76,28 @@
     method: "get",
     params,
   });
+};
+
+/**
+ * @desc 鏌ヨ鎶ヤ慨鍥剧墖鍒楄〃
+ * @param {鎶ヤ慨id} id
+ * @returns
+ */
+export const getRepairFileList = (id) => {
+  return request({
+    url: `/device/repair/file/${id}`,
+    method: "get",
+  });
+};
+
+/**
+ * @desc 鍒犻櫎鎶ヤ慨鍥剧墖
+ * @param {鏂囦欢id} fileId
+ * @returns
+ */
+export const delRepairFile = (fileId) => {
+  return request({
+    url: `/device/repair/file/${fileId}`,
+    method: "delete",
+  });
 };
\ No newline at end of file
diff --git a/src/pages/equipmentManagement/repair/add.vue b/src/pages/equipmentManagement/repair/add.vue
index 71de940..5ff1828 100644
--- a/src/pages/equipmentManagement/repair/add.vue
+++ b/src/pages/equipmentManagement/repair/add.vue
@@ -80,6 +80,34 @@
                       count
                       maxlength="200" />
         </u-form-item>
+      <u-form-item label="鏁呴殰鍥剧墖"
+                   border-bottom>
+        <view class="repair-image-upload">
+          <u-button type="primary"
+                    @click="chooseRepairImage"
+                    :loading="uploading"
+                    :disabled="uploading">
+            {{ uploading ? "涓婁紶涓�..." : "涓婁紶鏁呴殰鍥剧墖" }}
+          </u-button>
+          <view v-if="repairImageList.length"
+                class="repair-image-list">
+            <view v-for="(file, index) in repairImageList"
+                  :key="file.id || index"
+                  class="repair-image-item">
+              <image :src="normalizeFileUrl(file.url || file.tempFilePath)"
+                     mode="aspectFill"
+                     class="repair-image-preview"
+                     @click="previewRepairImage(index)" />
+              <view class="repair-image-delete"
+                    @click="removeRepairImage(file, index)">
+                <u-icon name="close"
+                        size="12"
+                        color="#fff" />
+              </view>
+            </view>
+          </view>
+        </view>
+      </u-form-item>
       </u-cell-group>
       <!-- 鎻愪氦鎸夐挳 -->
       <view class="footer-btns">
@@ -108,12 +136,16 @@
 
 <script setup>
   import { ref, computed, onMounted, onUnmounted } from "vue";
-  import { onShow } from "@dcloudio/uni-app";
+  import { onLoad, onShow } from "@dcloudio/uni-app";
   import PageHeader from "@/components/PageHeader.vue";
+  import config from "@/config";
+  import { getToken } from "@/utils/auth";
   import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
   import {
     addRepair,
+    delRepairFile,
     editRepair,
+    getRepairFileList,
     getRepairById,
   } from "@/api/equipmentManagement/repair";
   import dayjs from "dayjs";
@@ -136,6 +168,10 @@
   const showDevice = ref(false);
   const showDate = ref(false);
   const pickerDateValue = ref(Date.now());
+  const uploading = ref(false);
+  const repairImageList = ref([]);
+  const currentRepairId = ref(undefined);
+  const pageInited = ref(false);
 
   // 璁惧閫夐」
   const deviceOptions = ref([]);
@@ -171,6 +207,200 @@
     repairName: undefined, // 鎶ヤ慨浜�
     remark: undefined, // 鏁呴殰鐜拌薄
   });
+
+  const normalizeFileUrl = (rawUrl = "") => {
+    let fileUrl = rawUrl || "";
+    const javaApi = config.baseUrl;
+    const localPrefixes = ["wxfile://", "file://", "content://", "blob:", "data:"];
+
+    if (localPrefixes.some(prefix => fileUrl.startsWith(prefix))) {
+      return fileUrl;
+    }
+
+    if (fileUrl && fileUrl.indexOf("\\") > -1) {
+      const lowerPath = fileUrl.toLowerCase();
+      const uploadPathIndex = lowerPath.indexOf("uploadpath");
+
+      if (uploadPathIndex > -1) {
+        fileUrl = fileUrl.substring(uploadPathIndex).replace(/\\/g, "/");
+      } else {
+        fileUrl = fileUrl.replace(/\\/g, "/");
+      }
+    }
+    fileUrl = fileUrl.replace(/^\/?uploadPath/, "/profile");
+
+    if (fileUrl && !fileUrl.startsWith("http")) {
+      if (!fileUrl.startsWith("/")) fileUrl = "/" + fileUrl;
+      fileUrl = javaApi + fileUrl;
+    }
+
+    return fileUrl;
+  };
+
+  const normalizeId = raw => {
+    if (raw === null || raw === undefined) return undefined;
+    const val = String(raw).trim();
+    if (!val || val === "undefined" || val === "null") return undefined;
+    return val;
+  };
+
+  const resolveRepairId = () => {
+    const pages = getCurrentPages();
+    const currentPage = pages[pages.length - 1] || {};
+    const routeId = normalizeId(currentPage?.options?.id);
+    const memoryId = normalizeId(currentRepairId.value);
+    const storageId = normalizeId(uni.getStorageSync("repairId"));
+    return memoryId || routeId || storageId;
+  };
+
+  const getPageId = () => {
+    const id = resolveRepairId();
+    currentRepairId.value = id;
+    return id;
+  };
+
+  const fetchRepairFileList = async id => {
+    if (!id) {
+      repairImageList.value = [];
+      return;
+    }
+    try {
+      const { code, data } = await getRepairFileList(id);
+      if (code === 200) {
+        repairImageList.value = Array.isArray(data) ? data : [];
+      } else {
+        repairImageList.value = [];
+      }
+    } catch (e) {
+      repairImageList.value = [];
+    }
+  };
+
+  const chooseRepairImage = () => {
+    uni.chooseImage({
+      count: 9,
+      sizeType: ["original", "compressed"],
+      sourceType: ["album", "camera"],
+      success: res => {
+        const id = getPageId();
+        const files = res.tempFiles || [];
+        if (!files.length) return;
+        if (id) {
+          uploadRepairImages(files, id);
+          return;
+        }
+        if (operationType.value === "edit") {
+          showToast("鏈幏鍙栧埌鎶ヤ慨ID锛岃杩斿洖鍒楄〃鍚庨噸璇�");
+          return;
+        }
+        // 鏂板妯″紡涓存椂涓婁紶锛氬厛鏈湴鏆傚瓨锛屼繚瀛樻姤淇悗鍐嶈嚜鍔ㄤ笂浼犵粦瀹�
+        const tempItems = files.map((file, idx) => {
+          const filePath = file.path || file.tempFilePath;
+          return {
+            id: `temp_${Date.now()}_${idx}`,
+            url: filePath,
+            tempFilePath: filePath,
+            name: file.name || `temp_${Date.now()}_${idx}.jpg`,
+            isTemp: true,
+          };
+        });
+        repairImageList.value = [...repairImageList.value, ...tempItems];
+        showToast("宸蹭复鏃舵坊鍔狅紝淇濆瓨鎶ヤ慨鍚庤嚜鍔ㄤ笂浼�");
+      },
+      fail: () => {
+        showToast("閫夋嫨鍥剧墖澶辫触");
+      },
+    });
+  };
+
+  const uploadRepairImages = async (files, repairId) => {
+    const commonId = normalizeId(repairId);
+    if (!commonId) {
+      showToast("鏈幏鍙栧埌鎶ヤ慨ID锛屼笂浼犲け璐�");
+      return;
+    }
+    const token = getToken();
+    if (!token) {
+      showToast("鐧诲綍宸插け鏁堬紝璇烽噸鏂扮櫥褰�");
+      return;
+    }
+    uploading.value = true;
+    try {
+      for (const file of files) {
+        const filePath = file.path || file.tempFilePath;
+        if (!filePath) continue;
+        await new Promise((resolve, reject) => {
+          uni.uploadFile({
+            url: `${config.baseUrl}/device/repair/uploadFile`,
+            filePath,
+            name: "file",
+            formData: {
+              deviceRepairId: commonId,
+              type: 13,
+            },
+            header: {
+              Authorization: `Bearer ${token}`,
+            },
+            success: uploadRes => {
+              try {
+                const parsed = JSON.parse(uploadRes.data || "{}");
+                if (uploadRes.statusCode === 200 && parsed.code === 200) {
+                  resolve(parsed);
+                } else {
+                  reject(new Error(parsed.msg || "涓婁紶澶辫触"));
+                }
+              } catch (err) {
+                reject(new Error("涓婁紶鍝嶅簲瑙f瀽澶辫触"));
+              }
+            },
+            fail: () => reject(new Error("涓婁紶澶辫触")),
+          });
+        });
+      }
+      showToast("涓婁紶鎴愬姛");
+      await fetchRepairFileList(commonId);
+    } catch (e) {
+      showToast(e?.message || "涓婁紶澶辫触");
+    } finally {
+      uploading.value = false;
+    }
+  };
+
+  const previewRepairImage = index => {
+    const urls = repairImageList.value
+      .map(item => normalizeFileUrl(item.url || item.tempFilePath))
+      .filter(Boolean);
+    if (!urls.length) return;
+    uni.previewImage({
+      urls,
+      current: urls[index] || urls[0],
+    });
+  };
+
+  const removeRepairImage = (file, index) => {
+    if (!file?.id || file?.isTemp) {
+      repairImageList.value.splice(index, 1);
+      return;
+    }
+    uni.showModal({
+      title: "鎻愮ず",
+      content: "纭鍒犻櫎璇ュ浘鐗囧悧锛�",
+      success: async res => {
+        if (!res.confirm) return;
+        try {
+          const { code } = await delRepairFile(file.id);
+          if (code === 200) {
+            repairImageList.value.splice(index, 1);
+            showToast("鍒犻櫎鎴愬姛");
+          } else {
+            showToast("鍒犻櫎澶辫触");
+          }
+        } catch (e) {
+          showToast("鍒犻櫎澶辫触");
+        }
+      },
+    });
+  };
 
   // 鎶ヤ慨鐘舵�侀�夐」
   const repairStatusOptions = ref([
@@ -222,6 +452,7 @@
           form.value.repairTime = dayjs(data.repairTime).format("YYYY-MM-DD");
           form.value.repairName = data.repairName;
           form.value.remark = data.remark;
+          await fetchRepairFileList(id);
           repairStatusText.value =
             repairStatusOptions.value.find(item => item.value == data.status)
               ?.name || "";
@@ -327,15 +558,23 @@
     showDate.value = false;
   };
 
+  onLoad(options => {
+    const routeId = normalizeId(options?.id);
+    const storageId = normalizeId(uni.getStorageSync("repairId"));
+    const id = routeId || storageId;
+    currentRepairId.value = id || undefined;
+    pageInited.value = true;
+  });
+
   onShow(() => {
-    // 椤甸潰鏄剧ず鏃惰幏鍙栧弬鏁�
+    // onLoad 宸叉嬁鍒� id 鍚庯紝鍐嶆寜褰撳墠 id 鍒濆鍖栭〉闈�
+    if (!pageInited.value) return;
     getPageParams();
   });
 
   onMounted(() => {
-    // 椤甸潰鍔犺浇鏃惰幏鍙栬澶囧垪琛ㄥ拰鍙傛暟
+    // 椤甸潰鍔犺浇鏃跺厛鑾峰彇璁惧鍒楄〃
     loadDeviceName();
-    getPageParams();
   });
 
   // 缁勪欢鍗歌浇鏃舵竻鐞嗗畾鏃跺櫒
@@ -376,11 +615,28 @@
       // 鍑嗗鎻愪氦鏁版嵁
       const submitData = { ...form.value };
 
-      const { code } = id
+      const result = id
         ? await editRepair({ id: id, ...submitData })
         : await addRepair(submitData);
+      const { code, data } = result || {};
 
       if (code == 200) {
+        // 鏂板鍦烘櫙锛氫复鏃跺浘鐗囧湪淇濆瓨鎴愬姛鍚庤嚜鍔ㄤ笂浼犲苟缁戝畾鏂版姤淇崟
+        if (!id) {
+          const newId = data?.id || data?.repairId || data;
+          if (newId) {
+            currentRepairId.value = newId;
+            const tempFiles = repairImageList.value
+              .filter(item => item?.isTemp && (item.tempFilePath || item.url))
+              .map(item => ({
+                path: item.tempFilePath || item.url,
+                tempFilePath: item.tempFilePath || item.url,
+              }));
+            if (tempFiles.length) {
+              await uploadRepairImages(tempFiles, newId);
+            }
+          }
+        }
         showToast(`${id ? "缂栬緫" : "鏂板"}鎶ヤ慨鎴愬姛`);
         setTimeout(() => {
           uni.navigateBack();
@@ -402,26 +658,19 @@
 
   // 鑾峰彇椤甸潰鍙傛暟
   const getPageParams = () => {
-    // 浣跨敤uni.getStorageSync鑾峰彇id
-    const id = uni.getStorageSync("repairId");
+    const id = resolveRepairId();
+    currentRepairId.value = id || undefined;
 
     // 鏍规嵁鏄惁鏈塱d鍙傛暟鏉ュ垽鏂槸鏂板杩樻槸缂栬緫
     if (id) {
       // 缂栬緫妯″紡锛岃幏鍙栬鎯�
       loadForm(id);
-      // 鍙�夛細鑾峰彇鍚庢竻闄ゅ瓨鍌ㄧ殑id锛岄伩鍏嶅奖鍝嶅悗缁搷浣�
-      uni.removeStorageSync("repairId");
     } else {
       // 鏂板妯″紡
+      currentRepairId.value = undefined;
+      repairImageList.value = [];
       loadForm();
     }
-  };
-
-  // 鑾峰彇椤甸潰ID
-  const getPageId = () => {
-    // 浣跨敤uni.getStorageSync鑾峰彇id
-    const id = uni.getStorageSync("repairId");
-    return id;
   };
 </script>
 
@@ -486,4 +735,41 @@
     margin-left: 8px;
     cursor: pointer;
   }
+
+  .repair-image-upload {
+    width: 100%;
+  }
+
+  .repair-image-list {
+    margin-top: 12px;
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+  }
+
+  .repair-image-item {
+    position: relative;
+    width: 80px;
+    height: 80px;
+  }
+
+  .repair-image-preview {
+    width: 80px;
+    height: 80px;
+    border-radius: 6px;
+    background: #f5f5f5;
+  }
+
+  .repair-image-delete {
+    position: absolute;
+    top: -6px;
+    right: -6px;
+    width: 18px;
+    height: 18px;
+    border-radius: 50%;
+    background: rgba(0, 0, 0, 0.65);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
 </style>
\ No newline at end of file
diff --git a/src/pages/equipmentManagement/repair/index.vue b/src/pages/equipmentManagement/repair/index.vue
index e280595..a3c1eba 100644
--- a/src/pages/equipmentManagement/repair/index.vue
+++ b/src/pages/equipmentManagement/repair/index.vue
@@ -199,6 +199,7 @@
 
   // 鏂板鎶ヤ慨 - 璺宠浆鍒版姤淇〉闈�
   const addRepair = () => {
+    uni.removeStorageSync("repairId");
     uni.navigateTo({
       url: "/pages/equipmentManagement/repair/add",
     });
@@ -210,7 +211,7 @@
     // 浣跨敤uni.setStorageSync瀛樺偍id
     uni.setStorageSync("repairId", id);
     uni.navigateTo({
-      url: "/pages/equipmentManagement/repair/add",
+      url: `/pages/equipmentManagement/repair/add?id=${id}`,
     });
   };
 

--
Gitblit v1.9.3