| | |
| | | @click="showSparePartPicker" /> |
| | | </template> |
| | | </u-form-item> |
| | | |
| | | <u-form-item v-if="selectedSpareParts.length" |
| | | label="领用数量" |
| | | border-bottom> |
| | |
| | | <!-- 上传附件 --> |
| | | <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"> |
| | |
| | | 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"; |
| | |
| | | const sparePartsQtyRaw = ref(""); |
| | | |
| | | // 文件上传相关 |
| | | const uploadFiles = ref([]); |
| | | const uploading = ref(false); |
| | | const uploadProgress = ref(0); |
| | | const number = ref(0); |
| | |
| | | maintenanceResult: undefined, // 保养结果 |
| | | maintenanceActuallyTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), // 实际保养日期(只显示日期) |
| | | sparePartsIds: undefined, // 设备备件ID |
| | | storageBlobDTOs: [], // 保养附件 |
| | | }); |
| | | |
| | | // 清除表单校验状态 |
| | |
| | | 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 = ""; |
| | | }; |
| | | |
| | |
| | | } 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 = "请上传保养照片"; |
| | | } |
| | |
| | | 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]); |
| | |
| | | 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; |
| | | } |
| | |
| | | |
| | | 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 }); |
| | | |
| | |
| | | // 显示设备备件选择器 |
| | | 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; |
| | | } |
| | | } |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | // 确认备件选择 |
| | | 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; |
| | | } |
| | | } |
| | |
| | | // 移除已选备件 |
| | | 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]; |
| | | }; |
| | |
| | | // 重置选择的备件 |
| | | selectedSpareParts.value = []; |
| | | // 重置上传的文件 |
| | | uploadFiles.value = []; |
| | | form.value.storageBlobDTOs = []; |
| | | uploading.value = false; |
| | | uploadProgress.value = 0; |
| | | maintenancestatusText.value = ""; |
| | |
| | | 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, |
| | |
| | | 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, |
| | |
| | | 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 |
| | |
| | | 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; |
| | | } |
| | | } |