zhangwencui
2026-07-02 91dec349aa88c58c587199d9601529d60824e1d0
src/pages/equipmentManagement/upkeep/maintain.vue
@@ -79,7 +79,6 @@
                  @click="showSparePartPicker" />
        </template>
      </u-form-item>
      <u-form-item v-if="selectedSpareParts.length"
                   label="领用数量"
                   border-bottom>
@@ -101,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">
@@ -236,10 +163,9 @@
  import { ref, onMounted, reactive } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import PageHeader from "@/components/PageHeader.vue";
  import {
    addMaintenance,
  } from "@/api/equipmentManagement/upkeep";
  import { getSparePartsList } from "@/api/equipmentManagement/spareParts";
  import CommonUpload from "@/components/CommonUpload.vue";
  import { addMaintenance } from "@/api/equipmentManagement/upkeep";
  import { getSparePartsList } from "@/api/equipmentManagement/repair";
  import useUserStore from "@/store/modules/user";
  import dayjs from "dayjs";
  import { formatDateToYMD } from "@/utils/ruoyi";
@@ -278,7 +204,6 @@
  const sparePartsQtyRaw = ref("");
  // 文件上传相关
  const uploadFiles = ref([]);
  const uploading = ref(false);
  const uploadProgress = ref(0);
  const number = ref(0);
@@ -319,6 +244,7 @@
    maintenanceResult: undefined, // 保养结果
    maintenanceActuallyTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), // 实际保养日期(只显示日期)
    sparePartsIds: undefined, // 设备备件ID
    storageBlobDTOs: [], // 保养附件
  });
  // 清除表单校验状态
@@ -333,11 +259,12 @@
      maintenanceResult: undefined,
      maintenanceActuallyTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
      sparePartsIds: [],
      storageBlobDTOs: [],
    };
    maintenancestatusText.value = "";
    selectedSpareParts.value = [];
    tempSelectedSpareParts.value = [];
    Object.keys(sparePartQtyMap).forEach((k) => delete sparePartQtyMap[k]);
    Object.keys(sparePartQtyMap).forEach(k => delete sparePartQtyMap[k]);
    sparePartsQtyRaw.value = "";
  };
@@ -377,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 = "请上传保养照片";
      }
@@ -406,7 +337,9 @@
        return;
      }
      // 领用数量校验
      const spareIds = Array.isArray(form.value.sparePartsIds) ? form.value.sparePartsIds : [];
      const spareIds = Array.isArray(form.value.sparePartsIds)
        ? form.value.sparePartsIds
        : [];
      if (spareIds.length > 0) {
        for (const partId of spareIds) {
          const qty = Number(sparePartQtyMap?.[partId]);
@@ -415,11 +348,19 @@
            loading.value = false;
            return;
          }
          const part = sparePartOptions.value.find((p) => String(p.id || p.value) === String(partId));
          const part = sparePartOptions.value.find(
            p => String(p.id || p.value) === String(partId)
          );
          const stock = part?.quantity;
          if (stock !== null && stock !== undefined && Number.isFinite(Number(stock))) {
          if (
            stock !== null &&
            stock !== undefined &&
            Number.isFinite(Number(stock))
          ) {
            if (qty > Number(stock)) {
              showToast(`备件「${part?.name || ""}」领用数量不能超过库存(${stock})`);
              showToast(
                `备件「${part?.name || ""}」领用数量不能超过库存(${stock})`
              );
              loading.value = false;
              return;
            }
@@ -429,10 +370,16 @@
      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(",") : "",
        sparePartsUseList: spareIds.length ? spareIds.map((pid) => ({ id: pid, quantity: sparePartQtyMap?.[pid] ?? 1 })) : [],
        sparePartsQty: spareIds.length
          ? spareIds.map(pid => sparePartQtyMap?.[pid] ?? 1).join(",")
          : "",
        sparePartsUseList: spareIds.length
          ? spareIds.map(pid => ({
              id: pid,
              quantity: sparePartQtyMap?.[pid] ?? 1,
            }))
          : [],
      };
      const { code } = await addMaintenance({ id: id, ...submitData });
@@ -512,10 +459,13 @@
  // 显示设备备件选择器
  const showSparePartPicker = () => {
    tempSelectedSpareParts.value = [...selectedSpareParts.value];
    tempSelectedSpareParts.value.forEach((p) => {
    tempSelectedSpareParts.value.forEach(p => {
      const pid = p?.id ?? p?.value;
      if (pid !== null && pid !== undefined) {
        if (!Number.isFinite(Number(sparePartQtyMap[pid])) || Number(sparePartQtyMap[pid]) <= 0) {
        if (
          !Number.isFinite(Number(sparePartQtyMap[pid])) ||
          Number(sparePartQtyMap[pid]) <= 0
        ) {
          sparePartQtyMap[pid] = 1;
        }
      }
@@ -541,7 +491,10 @@
      delete sparePartQtyMap[itemId];
    } else {
      tempSelectedSpareParts.value.push(item);
      if (!Number.isFinite(Number(sparePartQtyMap[itemId])) || Number(sparePartQtyMap[itemId]) <= 0) {
      if (
        !Number.isFinite(Number(sparePartQtyMap[itemId])) ||
        Number(sparePartQtyMap[itemId]) <= 0
      ) {
        sparePartQtyMap[itemId] = 1;
      }
    }
@@ -550,11 +503,16 @@
  // 确认备件选择
  const confirmSparePartSelection = () => {
    selectedSpareParts.value = [...tempSelectedSpareParts.value];
    form.value.sparePartsIds = selectedSpareParts.value.map(item => item.id || item.value);
    selectedSpareParts.value.forEach((p) => {
    form.value.sparePartsIds = selectedSpareParts.value.map(
      item => item.id || item.value
    );
    selectedSpareParts.value.forEach(p => {
      const pid = p?.id ?? p?.value;
      if (pid !== null && pid !== undefined) {
        if (!Number.isFinite(Number(sparePartQtyMap[pid])) || Number(sparePartQtyMap[pid]) <= 0) {
        if (
          !Number.isFinite(Number(sparePartQtyMap[pid])) ||
          Number(sparePartQtyMap[pid]) <= 0
        ) {
          sparePartQtyMap[pid] = 1;
        }
      }
@@ -565,7 +523,9 @@
  // 移除已选备件
  const removeSparePart = index => {
    const removed = selectedSpareParts.value.splice(index, 1)[0];
    form.value.sparePartsIds = selectedSpareParts.value.map(item => item.id || item.value);
    form.value.sparePartsIds = selectedSpareParts.value.map(
      item => item.id || item.value
    );
    const rid = removed?.id ?? removed?.value;
    if (rid !== null && rid !== undefined) delete sparePartQtyMap[rid];
  };
@@ -578,7 +538,7 @@
    // 重置选择的备件
    selectedSpareParts.value = [];
    // 重置上传的文件
    uploadFiles.value = [];
    form.value.storageBlobDTOs = [];
    uploading.value = false;
    uploadProgress.value = 0;
    maintenancestatusText.value = "";
@@ -628,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,
@@ -641,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,
@@ -671,7 +633,9 @@
            const idArray =
              typeof sparePartsIds.value === "string"
                ? sparePartsIds.value.split(",")
                : (Array.isArray(sparePartsIds.value) ? sparePartsIds.value : []);
                : Array.isArray(sparePartsIds.value)
                ? sparePartsIds.value
                : [];
            if (idArray.length > 0) {
              selectedSpareParts.value = sparePartOptions.value
@@ -688,28 +652,41 @@
                  quantity: option.quantity,
                }));
              // 设置备件IDs(保持数组,提交时再 join)
              form.value.sparePartsIds = idArray.map((v) => {
              form.value.sparePartsIds = idArray.map(v => {
                const n = Number(String(v).trim());
                return Number.isFinite(n) ? n : String(v).trim();
              });
              // 回显领用数量(若有 sparePartsQty)
              if (typeof sparePartsQtyRaw.value === "string" && sparePartsQtyRaw.value.trim()) {
                const qtyArr = sparePartsQtyRaw.value.split(",").map((s) => Number(String(s).trim()));
              if (
                typeof sparePartsQtyRaw.value === "string" &&
                sparePartsQtyRaw.value.trim()
              ) {
                const qtyArr = sparePartsQtyRaw.value
                  .split(",")
                  .map(s => Number(String(s).trim()));
                selectedSpareParts.value.forEach((p, idx) => {
                  const pid = p?.id ?? p?.value;
                  const q = qtyArr[idx];
                  if (pid !== null && pid !== undefined && Number.isFinite(q) && q > 0) {
                  if (
                    pid !== null &&
                    pid !== undefined &&
                    Number.isFinite(q) &&
                    q > 0
                  ) {
                    sparePartQtyMap[pid] = q;
                  }
                });
              }
              // 默认数量兜底
              selectedSpareParts.value.forEach((p) => {
              selectedSpareParts.value.forEach(p => {
                const pid = p?.id ?? p?.value;
                if (pid !== null && pid !== undefined) {
                  if (!Number.isFinite(Number(sparePartQtyMap[pid])) || Number(sparePartQtyMap[pid]) <= 0) {
                  if (
                    !Number.isFinite(Number(sparePartQtyMap[pid])) ||
                    Number(sparePartQtyMap[pid]) <= 0
                  ) {
                    sparePartQtyMap[pid] = 1;
                  }
                }