From 97586104d7808d8ea8fb5f3e5d4c60e2a7943667 Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期六, 23 五月 2026 17:51:51 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_pro_河南鹤壁' into dev_pro_河南鹤壁

---
 src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue | 1194 ++++++++++++++++++++++++++++++-----------------------------
 1 files changed, 603 insertions(+), 591 deletions(-)

diff --git a/src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue b/src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue
index 36256c8..9abd042 100644
--- a/src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue
+++ b/src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue
@@ -1,117 +1,131 @@
 <template>
-  <FormDialog
-    v-model="dialogVisible"
-    title="涓婁紶宸℃璁板綍"
-    width="980px"
-    @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="1" 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 || "-" }}
           </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">
+                {{ tag }}
+              </el-tag>
+            </template>
+            <span v-else>--</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="棰戞">
+            {{ formatFrequencyType(taskInfo.frequencyType) || "-" }}
+          </el-descriptions-item>
+          <el-descriptions-item label="寮�濮嬫棩鏈熶笌鏃堕棿">
+            {{ formatFrequencyDetail(taskInfo.frequencyDetail) || "-" }}
+          </el-descriptions-item>
+          <el-descriptions-item label="鐧昏浜�">
+            {{ taskInfo.registrant || "-" }}
+          </el-descriptions-item>
+          <el-descriptions-item label="鐧昏鏃ユ湡">
+            {{ formatDateTime(taskInfo.createTime) || "-" }}
+          </el-descriptions-item>
           <el-descriptions-item label="澶囨敞">
             {{ taskInfo.remarks || "-" }}
           </el-descriptions-item>
         </el-descriptions>
       </el-card>
-
       <el-card class="section-card">
         <h3>宸℃鐘舵��</h3>
-        <el-radio-group v-model="hasException">
+        <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"
-          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">
-        <el-tabs v-model="currentUploadType">
-          <el-tab-pane label="鐢熶骇鍓�" name="before" />
-          <el-tab-pane label="鐢熶骇涓�" name="after" />
-          <el-tab-pane label="鐢熶骇鍚�" name="issue" />
-        </el-tabs>
-
-        <div class="upload-buttons">
-          <el-upload
-            :show-file-list="false"
-            :http-request="uploadFile"
-            :disabled="getCurrentFiles().length >= uploadConfig.limit || uploading"
-            accept="image/*"
-          >
-            <el-button type="primary" :loading="uploading">
-              <el-icon><Camera /></el-icon>
+      <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="getCurrentFiles().length >= uploadConfig.limit || uploading"
-            accept="video/*"
-          >
-            <el-button type="success" :loading="uploading">
-              <el-icon><VideoCamera /></el-icon>
+          <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>
               閫夋嫨瑙嗛
             </el-button>
           </el-upload>
         </div>
-
-        <el-progress
-          v-if="uploading"
-          :percentage="uploadProgress"
-          class="upload-progress"
-        />
-
-        <div v-if="getCurrentFiles().length" class="file-list">
-          <div
-            v-for="(file, index) in getCurrentFiles()"
-            :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-icon><VideoCamera /></el-icon>
+              <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"
-                @click="removeFile(index)"
-              >
-                <el-icon><Close /></el-icon>
+              <el-button class="delete-btn"
+                         type="danger"
+                         circle
+                         size="small"
+                         v-if="operationType !== 'view'"
+                         @click="removeFile(index)">
+                <el-icon>
+                  <Close />
+                </el-icon>
               </el-button>
             </div>
-
             <div class="file-info">
               <div class="file-name">
                 {{ file.bucketFilename || file.name || (file.type === "image" ? "鍥剧墖" : "瑙嗛") }}
@@ -120,561 +134,559 @@
             </div>
           </div>
         </div>
-
-        <el-empty
-          v-else
-          :description="`璇烽�夋嫨瑕佷笂浼犵殑${getUploadTypeText()}鍥剧墖鎴栬棰慲"
-        />
-
-        <el-alert
-          class="upload-summary"
-          type="info"
-          :closable="false"
-          :title="`鐢熶骇鍓嶏細${beforeModelValue.length}涓枃浠� | 鐢熶骇涓細${afterModelValue.length}涓枃浠� | 鐢熶骇鍚庯細${issueModelValue.length}涓枃浠禶"
-        />
+        <el-empty v-else
+                  :description="operationType === 'view' ? '鏆傛棤寮傚父鐓х墖鎴栬棰�' : '璇烽�夋嫨瑕佷笂浼犵殑宸℃鍥剧墖鎴栬棰�'" />
       </el-card>
-
-      <el-result
-        v-if="hasException === false"
-        icon="success"
-        title="璁惧杩愯姝e父"
-        sub-title="鏃犻渶涓婁紶鐓х墖"
-      />
+      <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" @click="submitUpload">鎻愪氦</el-button>
-        <el-button v-if="hasException === true" 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">鍙栨秷</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 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 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 afterModelValue = ref([]);
-const issueModelValue = ref([]);
+  const beforeModelValue = ref([]);
 
-const currentUploadType = ref("before");
-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}`;
+  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);
     }
-  }
-
-  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 = [];
-  afterModelValue.value = [];
-  issueModelValue.value = [];
-  currentUploadType.value = "before";
-  hasException.value = null;
-  abnormalDescription.value = "";
-  uploading.value = false;
-  uploadProgress.value = 0;
-  showVideoDialog.value = false;
-  currentVideoFile.value = null;
-};
-
-const openDialog = row => {
-  const raw = JSON.parse(JSON.stringify(row?.__raw || row || {}));
-  taskInfo.value = raw;
-
-  beforeModelValue.value = normalizeList(
-    raw.commonFileListBeforeVO || raw.commonFileListBefore || [],
-    "image"
-  );
-  afterModelValue.value = normalizeList(
-    raw.commonFileListVO || raw.commonFileList || [],
-    "image"
-  );
-  issueModelValue.value = normalizeList(
-    raw.commonFileListAfterVO || raw.commonFileListAfter || [],
-    "image"
-  );
-
-  abnormalDescription.value = raw.abnormalDescription || "";
-
-  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;
-  }
-
-  if (
-    hasException.value !== true &&
-    (beforeModelValue.value.length || afterModelValue.value.length || issueModelValue.value.length)
-  ) {
-    hasException.value = true;
-  }
-
-  dialogVisible.value = true;
-};
-
-const handleClose = () => {
-  dialogVisible.value = false;
-  resetState();
-  emit("closeDia");
-};
-
-const getCurrentFiles = () => {
-  if (currentUploadType.value === "before") return beforeModelValue.value;
-  if (currentUploadType.value === "after") return afterModelValue.value;
-  if (currentUploadType.value === "issue") return issueModelValue.value;
-  return [];
-};
-
-const getUploadTypeText = () => {
-  if (currentUploadType.value === "before") return "鐢熶骇鍓�";
-  if (currentUploadType.value === "after") return "鐢熶骇涓�";
-  if (currentUploadType.value === "issue") return "鐢熶骇鍚�";
-  return "";
-};
-
-const getTabType = () => {
-  if (currentUploadType.value === "before") return 10;
-  if (currentUploadType.value === "after") return 11;
-  if (currentUploadType.value === "issue") return 12;
-  return 10;
-};
-
-const previewVideo = file => {
-  currentVideoFile.value = file;
-  showVideoDialog.value = true;
-};
-
-const uploadFile = async uploadRequest => {
-  const rawFile = uploadRequest.file;
-
-  if (getCurrentFiles().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", getTabType());
-
-  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()}`,
-    };
-
-    getCurrentFiles().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 submitUpload = async () => {
-  if (hasException.value === null) {
-    ElMessage.warning("璇烽�夋嫨宸℃鐘舵��");
-    return;
-  }
-
-  if (hasException.value === true) {
-    const totalFiles =
-      beforeModelValue.value.length +
-      afterModelValue.value.length +
-      issueModelValue.value.length;
-
-    if (!totalFiles) {
-      ElMessage.warning("璇蜂笂浼犲紓甯哥収鐗囨垨瑙嗛");
-      return;
-    }
-
-    if (!abnormalDescription.value.trim()) {
-      ElMessage.warning("璇峰~鍐欏紓甯告弿杩�");
-      return;
-    }
-  }
-
-  const loading = ElLoading.service({
-    text: "鎻愪氦涓�...",
-    background: "rgba(0, 0, 0, 0.3)",
+    return [taskInfo.value.inspector];
   });
 
-  try {
-    const allFiles = [
-      ...beforeModelValue.value,
-      ...afterModelValue.value,
-      ...issueModelValue.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: afterModelValue.value.map(buildFileItem),
-      commonFileListAfterDTO: issueModelValue.value.map(buildFileItem),
-      hasException: hasException.value,
-      inspectionResult: hasException.value ? 0 : 1,
-      abnormalDescription: abnormalDescription.value,
-      tempFileIds,
+  const formatFrequencyType = type => {
+    const mapping = {
+      DAILY: "姣忔棩",
+      WEEKLY: "姣忓懆",
+      MONTHLY: "姣忔湀",
+      QUARTERLY: "瀛e害",
     };
-
-    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",
-    });
-    getCurrentFiles().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: afterModelValue.value.map(buildFileItem),
-    commonFileListAfterDTO: issueModelValue.value.map(buildFileItem),
-    uploadedFiles: {
-      before: beforeModelValue.value,
-      after: afterModelValue.value,
-      issue: issueModelValue.value,
-    },
+    return mapping[type] || type;
   };
 
-  sessionStorage.setItem("repairTaskInfo", JSON.stringify(taskData));
-  router.push("/equipmentManagement/repair/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 formatFileSize = size => {
-  if (!size) return "0 B";
+  const formatDateTime = date => {
+    if (!date) return "-";
+    return dayjs(date).format("YYYY-MM-DD HH:mm:ss");
+  };
 
-  const units = ["B", "KB", "MB", "GB"];
-  let index = 0;
-  let fileSize = size;
+  const hasException = ref(null);
+  const abnormalDescription = ref("");
 
-  while (fileSize >= 1024 && index < units.length - 1) {
-    fileSize /= 1024;
-    index += 1;
-  }
+  const showVideoDialog = ref(false);
+  const currentVideoFile = ref(null);
 
-  return `${fileSize.toFixed(2)} ${units[index]}`;
-};
+  const uploadConfig = {
+    action: "/common/upload",
+    limit: 10,
+    fileSize: 50,
+    fileType: ["jpg", "jpeg", "png", "mp4", "mov"],
+  };
 
-defineExpose({
-  openDialog,
-});
+  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}`;
+      }
+    }
+
+    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 = [];
+    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;
+
+    beforeModelValue.value = normalizeList(
+      raw.commonFileListBeforeVO || raw.commonFileListBefore || [],
+      "image"
+    );
+
+    abnormalDescription.value = raw.abnormalDescription || "";
+
+    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;
+    }
+
+    if (hasException.value !== true && beforeModelValue.value.length) {
+      hasException.value = true;
+    }
+
+    dialogVisible.value = true;
+  };
+
+  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;
+
+      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 submitUpload = async () => {
+    if (hasException.value === null) {
+      ElMessage.warning("璇烽�夋嫨宸℃鐘舵��");
+      return;
+    }
+
+    if (hasException.value === true) {
+      const totalFiles = beforeModelValue.value.length;
+
+      if (!totalFiles) {
+        ElMessage.warning("璇蜂笂浼犲紓甯哥収鐗囨垨瑙嗛");
+        return;
+      }
+
+      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,
+      commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem),
+      commonFileListDTO: [],
+      commonFileListAfterDTO: [],
+      uploadedFiles: {
+        before: beforeModelValue.value,
+        after: [],
+        issue: [],
+      },
+    };
+
+    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;
-}
+  .upload-buttons {
+    display: flex;
+    gap: 12px;
+    margin: 16px 0;
+  }
 
-.upload-progress {
-  margin-bottom: 16px;
-}
+  .upload-progress {
+    margin-bottom: 16px;
+  }
 
-.file-list {
-  display: grid;
-  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
-  gap: 12px;
-}
+  .file-list {
+    display: grid;
+    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
+    gap: 12px;
+  }
 
-.file-preview-container {
-  position: relative;
-  aspect-ratio: 1;
-  border-radius: 8px;
-  overflow: hidden;
-  background: #f2f3f5;
-}
+  .file-preview-container {
+    position: relative;
+    aspect-ratio: 1;
+    border-radius: 8px;
+    overflow: hidden;
+    background: #f2f3f5;
+  }
 
-.file-preview {
-  width: 100%;
-  height: 100%;
-}
+  .file-preview {
+    width: 100%;
+    height: 100%;
+  }
 
-.video-preview {
-  width: 100%;
-  height: 100%;
-  background: #303133;
-  color: #fff;
-  display: flex;
-  gap: 6px;
-  align-items: center;
-  justify-content: center;
-  cursor: pointer;
-}
+  .video-preview {
+    width: 100%;
+    height: 100%;
+    background: #303133;
+    color: #fff;
+    display: flex;
+    gap: 6px;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+  }
 
-.delete-btn {
-  position: absolute;
-  top: 6px;
-  right: 6px;
-}
+  .delete-btn {
+    position: absolute;
+    top: 6px;
+    right: 6px;
+  }
 
-.file-info {
-  margin-top: 6px;
-  font-size: 12px;
-}
+  .file-info {
+    margin-top: 6px;
+    font-size: 12px;
+  }
 
-.file-name {
-  color: #606266;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
+  .file-name {
+    color: #606266;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
 
-.file-size {
-  color: #909399;
-  margin-top: 2px;
-}
+  .file-size {
+    color: #909399;
+    margin-top: 2px;
+  }
 
-.upload-summary {
-  margin-top: 16px;
-}
+  .upload-summary {
+    margin-top: 16px;
+  }
 
-.footer-buttons {
-  position: sticky;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  padding: 14px 20px 0;
-  background: #f5f7fa;
-  display: flex;
-  justify-content: center;
-  gap: 12px;
-}
+  .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;
-}
+  .video-player {
+    width: 100%;
+    max-height: 70vh;
+    background: #000;
+  }
 </style>

--
Gitblit v1.9.3