yuan
2026-05-23 97586104d7808d8ea8fb5f3e5d4c60e2a7943667
src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue
@@ -1,117 +1,131 @@
<template>
  <FormDialog
    v-model="dialogVisible"
    title="上传巡检记录"
  <FormDialog v-model="dialogVisible"
              :title="operationType === 'view' ? '巡检记录详情' : '上传巡检记录'"
    width="980px"
              :operation-type="operationType"
    @close="handleClose"
    @cancel="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">正常</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"
        <el-input v-model="abnormalDescription"
          type="textarea"
          maxlength="500"
          show-word-limit
          :rows="4"
          placeholder="请描述异常情况..."
        />
                  :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"
      <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="getCurrentFiles().length >= uploadConfig.limit || uploading"
            accept="image/*"
          >
            <el-button type="primary" :loading="uploading">
              <el-icon><Camera /></el-icon>
                     :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"
          <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>
                     :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"
        <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()"
                     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"
          >
               class="file-item">
            <div class="file-preview-container">
              <el-image
                v-if="file.type === 'image' || !file.type"
              <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>
                        preview-teleported />
              <div v-else
                   class="video-preview"
                   @click="previewVideo(file)">
                <el-icon>
                  <VideoCamera />
                </el-icon>
                <span>视频</span>
              </div>
              <el-button
                class="delete-btn"
              <el-button class="delete-btn"
                type="danger"
                circle
                size="small"
                @click="removeFile(index)"
              >
                <el-icon><Close /></el-icon>
                         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,51 +134,36 @@
            </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"
      <el-result v-if="hasException === false"
        icon="success"
        title="设备运行正常"
        sub-title="无需上传照片"
      />
                 :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"
  <el-dialog v-model="showVideoDialog"
    :title="currentVideoFile?.originalFilename || currentVideoFile?.name || '视频预览'"
    width="720px"
  >
    <video
      v-if="currentVideoFile"
             width="720px">
    <video v-if="currentVideoFile"
      :src="currentVideoFile.url || currentVideoFile.downloadUrl"
      class="video-player"
      controls
      autoplay
    />
           autoplay />
  </el-dialog>
</template>
@@ -174,6 +173,7 @@
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";
@@ -185,12 +185,54 @@
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 currentUploadType = ref("before");
  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: "季度",
    };
    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 HH:mm:ss");
  };
const hasException = ref(null);
const abnormalDescription = ref("");
@@ -245,7 +287,9 @@
    return {
      ...item,
      url: processFileUrl(item.url || item.previewURL || item.downloadUrl || item.path || ""),
        url: processFileUrl(
          item.url || item.previewURL || item.downloadUrl || item.path || ""
        ),
      downloadUrl: processFileUrl(
        item.downloadUrl || item.url || item.previewURL || item.path || ""
      ),
@@ -263,18 +307,17 @@
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;
    operationType.value = "add";
};
const openDialog = row => {
  const openDialog = (type, row) => {
    operationType.value = type || "add";
  const raw = JSON.parse(JSON.stringify(row?.__raw || row || {}));
  taskInfo.value = raw;
@@ -282,29 +325,21 @@
    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) {
    } 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)
  ) {
    if (hasException.value !== true && beforeModelValue.value.length) {
    hasException.value = true;
  }
@@ -317,27 +352,6 @@
  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;
@@ -346,14 +360,16 @@
const uploadFile = async uploadRequest => {
  const rawFile = uploadRequest.file;
  if (getCurrentFiles().length >= uploadConfig.limit) {
    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("/")} 格式`);
      ElMessage.warning(
        `文件格式不支持,请上传 ${uploadConfig.fileType.join("/")} 格式`
      );
    return;
  }
@@ -370,7 +386,7 @@
  const formData = new FormData();
  formData.append("files", rawFile);
  formData.append("type", getTabType());
    formData.append("type", 10); // 生产前固定为10
  uploading.value = true;
  uploadProgress.value = 0;
@@ -397,7 +413,10 @@
    const finalUrl = processFileUrl(
      resultData.url || resultData.previewURL || resultData.downloadUrl || ""
    );
    const finalName = resultData.name || resultData.originalFilename || resultData.bucketFilename;
      const finalName =
        resultData.name ||
        resultData.originalFilename ||
        resultData.bucketFilename;
    const finalId = resultData.tempId || resultData.id || resultData.tempFileId;
    const uploadedFile = {
@@ -413,7 +432,7 @@
      uid: `${Date.now()}-${Math.random()}`,
    };
    getCurrentFiles().push(uploadedFile);
      beforeModelValue.value.push(uploadedFile);
    ElMessage.success("上传成功");
  } catch (error) {
    ElMessage.error(error?.message || "上传失败");
@@ -444,10 +463,7 @@
  }
  if (hasException.value === true) {
    const totalFiles =
      beforeModelValue.value.length +
      afterModelValue.value.length +
      issueModelValue.value.length;
      const totalFiles = beforeModelValue.value.length;
    if (!totalFiles) {
      ElMessage.warning("请上传异常照片或视频");
@@ -466,11 +482,7 @@
  });
  try {
    const allFiles = [
      ...beforeModelValue.value,
      ...afterModelValue.value,
      ...issueModelValue.value,
    ];
      const allFiles = [...beforeModelValue.value];
    const tempFileIds = allFiles
      .map(item => item?.tempId ?? item?.tempFileId ?? item?.id)
@@ -493,8 +505,8 @@
    const submitData = {
      ...baseTaskInfo,
      commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem),
      commonFileListDTO: afterModelValue.value.map(buildFileItem),
      commonFileListAfterDTO: issueModelValue.value.map(buildFileItem),
        commonFileListDTO: [],
        commonFileListAfterDTO: [],
      hasException: hasException.value,
      inspectionResult: hasException.value ? 0 : 1,
      abnormalDescription: abnormalDescription.value,
@@ -524,7 +536,7 @@
    await ElMessageBox.confirm("确定要删除这个文件吗?", "确认删除", {
      type: "warning",
    });
    getCurrentFiles().splice(index, 1);
      beforeModelValue.value.splice(index, 1);
  } catch {}
};
@@ -537,12 +549,12 @@
    hasException: hasException.value,
    inspectionResult: hasException.value ? 0 : 1,
    commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem),
    commonFileListDTO: afterModelValue.value.map(buildFileItem),
    commonFileListAfterDTO: issueModelValue.value.map(buildFileItem),
      commonFileListDTO: [],
      commonFileListAfterDTO: [],
    uploadedFiles: {
      before: beforeModelValue.value,
      after: afterModelValue.value,
      issue: issueModelValue.value,
        after: [],
        issue: [],
    },
  };