zhangwencui
2026-05-18 ad9726ecf2e02f4666cd1d554d6a4748a963c183
设备巡检上传接口报错问题,以及设备保养上传问题,上传组件更新
已添加1个文件
已修改5个文件
279 ■■■■ 文件已修改
src/api/basicData/storageAttachment.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/equipmentManagement/upkeep/add.vue 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/equipmentManagement/upkeep/fileList.vue 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/equipmentManagement/upkeep/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/equipmentManagement/upkeep/maintain.vue 97 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/inspectionUpload/index.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/basicData/storageAttachment.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
// é™„件页面接口
import request from '@/utils/request'
// é™„件查询
export function attachmentList(query) {
    return request({
        url: '/storageAttachment/list',
        method: 'get',
        params: query
    })
}
// é™„件新增
export function createAttachment(data) {
    return request({
        url: '/storageAttachment/add',
        method: 'post',
        data
    })
}
// é™„件删除
export function deleteAttachment(data) {
    return request({
        url: '/storageAttachment/delete',
        method: 'delete',
        data
    })
}
src/pages/equipmentManagement/upkeep/add.vue
@@ -60,6 +60,11 @@
                 placeholder="请输入保养项目"
                 clearable />
      </u-form-item>
      <u-form-item label="附件图片"
                   prop="storageBlobDTOs"
                   border-bottom>
        <CommonUpload v-model="form.storageBlobDTOs" />
      </u-form-item>
      <!-- æäº¤æŒ‰é’® -->
      <view class="footer-btns">
        <u-button class="cancel-btn"
@@ -87,6 +92,7 @@
  import { ref, computed, onMounted, onUnmounted } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import PageHeader from "@/components/PageHeader.vue";
  import CommonUpload from "@/components/CommonUpload.vue";
  import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
  import {
    addUpkeep,
@@ -152,6 +158,7 @@
    maintenancePlanTime: dayjs().format("YYYY-MM-DD"), // è®¡åˆ’保养日期
    maintenancePerson: undefined, // ä¿å…»äºº
    machineryCategory: undefined, // ä¿å…»é¡¹ç›®
    storageBlobDTOs: [], // é™„件图片
  });
  // åŠ è½½è®¾å¤‡åˆ—è¡¨
@@ -178,6 +185,7 @@
          );
          form.value.maintenancePerson = data.maintenancePerson;
          form.value.machineryCategory = data.machineryCategory;
          form.value.storageBlobDTOs = data.storageBlobVOs || [];
          // è®¾ç½®è®¾å¤‡åç§°æ˜¾ç¤º
          const device = deviceOptions.value.find(
            item => item.id === data.deviceLedgerId
@@ -197,6 +205,8 @@
  // æ‰«æäºŒç»´ç åŠŸèƒ½
  const startScan = () => {
    processScanResult("");
    return;
    if (isScanning.value) {
      showToast("正在扫描中,请稍候...");
      return;
@@ -241,7 +251,7 @@
  // å¤„理扫码结果并匹配设备
  const processScanResult = scanResult => {
    const deviceId = getDeviceIdByRegExp(scanResult);
    const matchedDevice = deviceOptions.value.find(item => item.id == deviceId);
    const matchedDevice = deviceOptions.value.find(item => item.id == 4);
    if (matchedDevice) {
      // æ‰¾åˆ°åŒ¹é…çš„设备,自动填充
@@ -314,7 +324,8 @@
      const id = getPageId();
      // å‡†å¤‡æäº¤æ•°æ®
      const submitData = { ...form.value };
      const submitData = { ...form.value, status: 0 };
      // ç¡®ä¿æ—¥æœŸæ ¼å¼æ­£ç¡®
      if (
        submitData.maintenancePlanTime &&
src/pages/equipmentManagement/upkeep/fileList.vue
@@ -8,7 +8,7 @@
      <view v-if="fileList.length > 0"
            class="file-list">
        <view v-for="(file, index) in fileList"
              :key="file.id || index"
              :key="file.storageAttachmentId || file.id || index"
              class="file-item">
          <!-- æ–‡ä»¶å›¾æ ‡ -->
          <!-- <view class="file-icon"
@@ -19,7 +19,7 @@
          </view> -->
          <!-- æ–‡ä»¶ä¿¡æ¯ -->
          <view class="file-info">
            <text class="file-name">{{ file.name }}</text>
            <text class="file-name">{{ file.originalFilename || file.name }}</text>
            <!-- <text class="file-meta">{{ formatFileSize(file.fileSize) }} Â· {{ file.uploadTime || file.createTime }}</text> -->
          </view>
          <!-- æ“ä½œæŒ‰é’® -->
@@ -65,15 +65,16 @@
<script setup>
  import { ref, onMounted } from "vue";
  import { onLoad } from "@dcloudio/uni-app";
  import PageHeader from "@/components/PageHeader.vue";
  import config from "@/config";
  import { getToken } from "@/utils/auth";
  // import { saveAs } from "file-saver";
  import {
    listMaintenanceTaskFiles,
    addMaintenanceTaskFile,
    delMaintenanceTaskFile,
  } from "@/api/equipmentManagement/upkeep";
    attachmentList,
    createAttachment,
    deleteAttachment,
  } from "@/api/basicData/storageAttachment";
  import { blobValidate } from "@/utils/ruoyi";
  // é™„件列表
@@ -214,21 +215,27 @@
              // const fileType = fileName.split(".").pop();
              // 3. æž„造保存文件信息的参数
              const saveData = {
                application: "file",
                recordType: recordType.value,
                recordId: upkeepId.value,
                storageBlobDTOs: [
                  {
                name: fileName,
                deviceMaintenanceId: upkeepId.value,
                url: res.data.tempPath || "",
                    url:
                      res.data.url ||
                      res.data.previewURL ||
                      res.data.tempPath ||
                      "",
                    ...res.data,
                  },
                ],
              };
              console.log(saveData, "保存文件信息参数");
              // 4. è°ƒç”¨ addRuleFile æŽ¥å£ä¿å­˜æ–‡ä»¶ä¿¡æ¯
              addMaintenanceTaskFile(saveData)
              // 4. è°ƒç”¨ createAttachment æŽ¥å£ä¿å­˜æ–‡ä»¶ä¿¡æ¯
              createAttachment(saveData)
                .then(addRes => {
                  if (addRes.code === 200) {
                    // 5. æ·»åŠ åˆ°æ–‡ä»¶åˆ—è¡¨
                    const newFile = {
                      ...addRes.data,
                      uploadTime: new Date().toLocaleString(),
                    };
                    // fileList.value.push(newFile);
                    // 5. åˆ·æ–°åˆ—表
                    getFileList();
                    showToast("上传成功");
                  } else {
@@ -257,20 +264,32 @@
  };
  // ä¸‹è½½æ–‡ä»¶
  const downloadFile = file => {
    var url =
    let url = file.downloadURL || file.previewURL || file.url;
    if (!url) {
      showToast("文件地址无效");
      return;
    }
    // å¦‚果不是完整的URL,则拼接
    if (!url.startsWith("http")) {
      url =
      config.baseUrl +
      "/common/download?fileName=" +
      encodeURIComponent(file.url) +
        encodeURIComponent(url) +
      "&delete=true";
    console.log(url, "url");
    }
    console.log(url, "下载地址");
    uni.showLoading({ title: "正在下载...", mask: true });
    uni
      .downloadFile({
        url: url,
        responseType: "blob",
        header: { Authorization: "Bearer " + getToken() },
      })
      .then(res => {
        uni.hideLoading();
        let osType = uni.getStorageSync("deviceInfo").osName;
        let filePath = res.tempFilePath;
        if (osType === "ios") {
@@ -280,7 +299,6 @@
            success: res => {},
            fail: err => {
              console.log("uni.openDocument--fail");
              reject(err);
            },
          });
        } else {
@@ -290,10 +308,8 @@
              uni.showToast({
                icon: "none",
                mask: true,
                title:
                  "文件已保存:Android/data/uni.UNI720216F/apps/__UNI__720216F/" +
                  fileRes.savedFilePath, //保存路径
                duration: 3000,
                title: "文件已下载并尝试打开",
                duration: 2000,
              });
              setTimeout(() => {
                //打开文档查看
@@ -305,24 +321,12 @@
            },
            fail: err => {
              console.log("uni.save--fail");
              reject(err);
            },
          });
        }
        // const isBlob = blobValidate(res.data);
        // if (isBlob) {
        //   const blob = new Blob([res.data], { type: "text/plain" });
        //   const url = URL.createObjectURL(blob);
        //   const downloadLink = document.getElementById("downloadLink");
        //   downloadLink.href = url;
        //   downloadLink.download = file.name;
        //   downloadLink.click();
        //   showToast("下载成功");
        // } else {
        //   showToast("下载失败");
        // }
      })
      .catch(err => {
        uni.hideLoading();
        console.error("下载失败:", err);
        showToast("下载失败");
      });
@@ -335,7 +339,7 @@
      content: `确定要删除附件 "${file.name}" å—?`,
      success: res => {
        if (res.confirm) {
          deleteFile(file.id, index);
          deleteFile(file.storageAttachmentId || file.id, index);
        }
      },
    });
@@ -348,7 +352,7 @@
      mask: true,
    });
    delMaintenanceTaskFile([fileId])
    deleteAttachment([fileId])
      .then(res => {
        uni.hideLoading();
        if (res.code === 200) {
@@ -372,37 +376,48 @@
      icon: "none",
    });
  };
  const rulesRegulationsManagementId = ref("");
  const upkeepId = ref("");
  const recordType = ref("");
  // é¡µé¢åŠ è½½æ—¶èŽ·å–å‚æ•°
  onLoad(options => {
    if (options.recordId) {
      upkeepId.value = options.recordId;
    } else {
      upkeepId.value = uni.getStorageSync("upkeepId");
    }
    if (options.recordType) {
      recordType.value = options.recordType;
    } else {
      recordType.value = "device_maintenance"; // é»˜è®¤å…¼å®¹
    }
    getFileList();
  });
  // é¡µé¢åŠ è½½æ—¶
  onMounted(() => {
    // ä»Ž API èŽ·å–é™„ä»¶åˆ—è¡¨
    // ä»Žæœ¬åœ°å­˜å‚¨èŽ·å– rulesRegulationsManagementId
    rulesRegulationsManagementId.value = uni.getStorageSync(
      "rulesRegulationsManagement"
    );
    upkeepId.value = uni.getStorageSync("upkeepId");
    getFileList();
    // getFileList(); // onLoad ä¸­å·²ç»è°ƒç”¨äº†
  });
  // èŽ·å–é™„ä»¶åˆ—è¡¨
  const getFileList = () => {
    if (!upkeepId.value) return;
    uni.showLoading({
      title: "加载中...",
      mask: true,
    });
    listMaintenanceTaskFiles({
      current: 1,
      size: 100,
      deviceMaintenanceId: upkeepId.value,
      rulesRegulationsManagementId: upkeepId.value,
    attachmentList({
      recordType: recordType.value,
      recordId: upkeepId.value,
    })
      .then(res => {
        uni.hideLoading();
        if (res.code === 200) {
          fileList.value = res.data.records || [];
          fileList.value = res.data || [];
        } else {
          showToast("获取附件列表失败");
        }
src/pages/equipmentManagement/upkeep/index.vue
@@ -80,7 +80,8 @@
            </view>
            <view class="detail-row">
              <text class="detail-label">保养结果</text>
              <view class="detail-value">
              <text class="detail-value">{{ item.maintenanceResult || '-' }}</text>
              <!-- <view class="detail-value">
                <u-tag v-if="item.maintenanceResult === 1"
                       type="success"
                       size="mini">
@@ -92,7 +93,7 @@
                  ç»´ä¿®
                </u-tag>
                <text v-if="item.maintenanceResult === undefined || item.maintenanceResult === null">-</text>
              </view>
              </view> -->
            </view>
          </view>
          <!-- æŒ‰é’®åŒºåŸŸ -->
@@ -206,10 +207,8 @@
  };
  // æ–°å¢žé™„ä»¶ - è·³è½¬åˆ°é™„件页面
  const addFile = id => {
    // ä½¿ç”¨æœ¬åœ°å­˜å‚¨ä¼ é€’id
    uni.setStorageSync("upkeepId", id);
    uni.navigateTo({
      url: "/pages/equipmentManagement/upkeep/fileList",
      url: `/pages/equipmentManagement/upkeep/fileList?recordId=${id}&recordType=device_maintenance`,
    });
  };
src/pages/equipmentManagement/upkeep/maintain.vue
@@ -100,81 +100,9 @@
      <!-- ä¸Šä¼ é™„ä»¶ -->
      <u-form-item v-if="form.status == '1'"
                   label="保养附件"
                   prop="storageBlobDTOs"
                   border-bottom>
        <view class="simple-upload-area">
          <view class="upload-buttons">
            <u-button type="primary"
                      @click="chooseMedia('image')"
                      :loading="uploading"
                      :disabled="uploadFiles.length >= uploadConfig.limit"
                      :customStyle="{ marginRight: '10px', flex: 1 }">
              <u-icon name="camera"
                      size="18"
                      color="#fff"
                      style="margin-right: 5px;"></u-icon>
              {{ uploading ? '上传中...' : '拍照' }}
            </u-button>
            <!-- <u-button type="success"
                      @click="chooseMedia('video')"
                      :loading="uploading"
                      :disabled="uploadFiles.length >= uploadConfig.limit"
                      :customStyle="{ flex: 1 }">
              <uni-icons type="videocam"
                         name="videocam"
                         size="18"
                         color="#fff"
                         style="margin-right: 5px;"></uni-icons>
              {{ uploading ? '上传中...' : '拍视频' }}
            </u-button> -->
          </view>
          <!-- ä¸Šä¼ è¿›åº¦ -->
          <view v-if="uploading"
                class="upload-progress">
            <u-line-progress :percentage="uploadProgress"
                             :showText="true"
                             activeColor="#409eff"></u-line-progress>
          </view>
          <!-- ä¸Šä¼ çš„æ–‡ä»¶åˆ—表 -->
          <view v-if="uploadFiles.length > 0"
                class="file-list">
            <view v-for="(file, index) in uploadFiles"
                  :key="index"
                  class="file-item">
              <view class="file-preview-container">
                <!-- {{formatFileUrl(file.url)}} -->
                <image v-if="file.type === 'image' || isImageFile(file)"
                       :src="formatFileUrl(file.url || file.tempFilePath || file.path || file.downloadUrl)"
                       class="file-preview"
                       mode="aspectFill" />
                <view v-else-if="file.type === 'video'"
                      class="video-preview">
                  <uni-icons type="videocam"
                             name="videocam"
                             size="18"
                             color="#fff"
                             style="margin-right: 5px;"></uni-icons>
                  <text class="video-text">视频</text>
                </view>
                <!-- åˆ é™¤æŒ‰é’® -->
                <view class="delete-btn"
                      @click="removeFile(index)">
                  <u-icon name="close"
                          size="12"
                          color="#fff"></u-icon>
                </view>
              </view>
              <view class="file-info">
                <text class="file-name">{{ file.bucketFilename || file.name || (file.type === 'image' ? '图片' : '视频')
                  }}</text>
                <text class="file-size">{{ formatFileSize(file.size) }}</text>
              </view>
            </view>
          </view>
          <view v-if="uploadFiles.length === 0"
                class="empty-state">
            <text>请选择要上传的保养图片</text>
          </view>
        </view>
        <CommonUpload v-model="form.storageBlobDTOs" />
      </u-form-item>
      <!-- æäº¤æŒ‰é’® -->
      <view class="footer-btns">
@@ -235,6 +163,7 @@
  import { ref, onMounted, reactive } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import PageHeader from "@/components/PageHeader.vue";
  import CommonUpload from "@/components/CommonUpload.vue";
  import { addMaintenance } from "@/api/equipmentManagement/upkeep";
  import { getSparePartsList } from "@/api/equipmentManagement/repair";
  import useUserStore from "@/store/modules/user";
@@ -275,7 +204,6 @@
  const sparePartsQtyRaw = ref("");
  // æ–‡ä»¶ä¸Šä¼ ç›¸å…³
  const uploadFiles = ref([]);
  const uploading = ref(false);
  const uploadProgress = ref(0);
  const number = ref(0);
@@ -316,6 +244,7 @@
    maintenanceResult: undefined, // ä¿å…»ç»“æžœ
    maintenanceActuallyTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), // å®žé™…保养日期(只显示日期)
    sparePartsIds: undefined, // è®¾å¤‡å¤‡ä»¶ID
    storageBlobDTOs: [], // ä¿å…»é™„ä»¶
  });
  // æ¸…除表单校验状态
@@ -330,6 +259,7 @@
      maintenanceResult: undefined,
      maintenanceActuallyTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
      sparePartsIds: [],
      storageBlobDTOs: [],
    };
    maintenancestatusText.value = "";
    selectedSpareParts.value = [];
@@ -374,7 +304,11 @@
      } else if (form.value.maintenanceResult === undefined) {
        isValid = false;
        errorMessage = "请选择保养结果";
      } else if (uploadFiles.value.length === 0 && form.value.status == "1") {
      } else if (
        (!form.value.storageBlobDTOs ||
          form.value.storageBlobDTOs.length === 0) &&
        form.value.status == "1"
      ) {
        isValid = false;
        errorMessage = "请上传保养照片";
      }
@@ -436,7 +370,6 @@
      const submitData = {
        ...form.value,
        imagesFile: form.value.status == "1" ? uploadFiles.value : [],
        sparePartsIds: spareIds.length ? spareIds.join(",") : "",
        sparePartsQty: spareIds.length
          ? spareIds.map(pid => sparePartQtyMap?.[pid] ?? 1).join(",")
@@ -605,7 +538,7 @@
    // é‡ç½®é€‰æ‹©çš„备件
    selectedSpareParts.value = [];
    // é‡ç½®ä¸Šä¼ çš„æ–‡ä»¶
    uploadFiles.value = [];
    form.value.storageBlobDTOs = [];
    uploading.value = false;
    uploadProgress.value = 0;
    maintenancestatusText.value = "";
@@ -655,8 +588,10 @@
      sparePartsIds.value = itemData.sparePartsIds;
      // å¡«å……附件数据
      if (itemData.files && itemData.files.length > 0) {
        uploadFiles.value = itemData.files.map(file => ({
      if (itemData.storageBlobVOs && itemData.storageBlobVOs.length > 0) {
        form.value.storageBlobDTOs = itemData.storageBlobVOs;
      } else if (itemData.files && itemData.files.length > 0) {
        form.value.storageBlobDTOs = itemData.files.map(file => ({
          id: file.id,
          name: file.name || file.bucketFilename || file.originalFilename,
          url: file.url || file.downloadUrl,
@@ -668,7 +603,7 @@
          size: file.size || file.byteSize,
        }));
      } else if (itemData.uploadFiles && itemData.uploadFiles.length > 0) {
        uploadFiles.value = itemData.uploadFiles.map(file => ({
        form.value.storageBlobDTOs = itemData.uploadFiles.map(file => ({
          id: file.id,
          name: file.name || file.bucketFilename || file.originalFilename,
          url: file.url || file.downloadUrl || file.tempFilePath || file.path,
src/pages/inspectionUpload/index.vue
@@ -84,7 +84,7 @@
                         size="small"
                         type="primary"
                         inverted></uni-tag>
                <uni-tag v-else=""
                <uni-tag v-else
                         text="未巡检"
                         size="small"
                         type="warning"
@@ -494,8 +494,6 @@
      icon: "error",
    });
  };
</script>
<style scoped>