| | |
| | | @click="showSparePartPicker" /> |
| | | </template> |
| | | </u-form-item> |
| | | |
| | | <u-form-item v-if="selectedSpareParts.length" |
| | | label="领用数量" |
| | | border-bottom> |
| | | <view class="spare-qty-list"> |
| | | <view v-for="item in selectedSpareParts" |
| | | :key="String(item.id || item.value)" |
| | | class="spare-qty-row"> |
| | | <view class="spare-qty-name"> |
| | | <text class="spare-name">{{ item.name }}</text> |
| | | <text v-if="item.quantity !== null && item.quantity !== undefined" |
| | | class="spare-stock">(库存:{{ item.quantity }})</text> |
| | | </view> |
| | | <up-number-box v-model="sparePartQtyMap[item.id || item.value]" |
| | | :min="1" |
| | | :max="item.quantity !== null && item.quantity !== undefined ? Number(item.quantity) : undefined" /> |
| | | </view> |
| | | </view> |
| | | </u-form-item> |
| | | <!-- 上传附件 --> |
| | | <u-form-item v-if="form.status == '1'" |
| | | label="保养附件" |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted } from "vue"; |
| | | import { ref, onMounted, reactive } from "vue"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { |
| | | addMaintenance, |
| | | getSparePartsOptions, |
| | | } from "@/api/equipmentManagement/upkeep"; |
| | | import { getSparePartsList } from "@/api/equipmentManagement/spareParts"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import dayjs from "dayjs"; |
| | | import { formatDateToYMD } from "@/utils/ruoyi"; |
| | |
| | | const maintenancestatusText = ref(""); |
| | | const selectedSpareParts = ref([]); |
| | | const tempSelectedSpareParts = ref([]); |
| | | const sparePartQtyMap = reactive({}); |
| | | const sparePartsQtyRaw = ref(""); |
| | | |
| | | // 文件上传相关 |
| | | const uploadFiles = ref([]); |
| | |
| | | maintenancestatusText.value = ""; |
| | | selectedSpareParts.value = []; |
| | | tempSelectedSpareParts.value = []; |
| | | Object.keys(sparePartQtyMap).forEach((k) => delete sparePartQtyMap[k]); |
| | | sparePartsQtyRaw.value = ""; |
| | | }; |
| | | |
| | | const resetFormAndValidate = () => { |
| | |
| | | loading.value = false; |
| | | return; |
| | | } |
| | | // 准备提交数据,maintenanceActuallyTime 加上当前时分秒 |
| | | // 领用数量校验 |
| | | const spareIds = Array.isArray(form.value.sparePartsIds) ? form.value.sparePartsIds : []; |
| | | if (spareIds.length > 0) { |
| | | for (const partId of spareIds) { |
| | | const qty = Number(sparePartQtyMap?.[partId]); |
| | | if (!Number.isFinite(qty) || qty <= 0) { |
| | | showToast("请填写备件领用数量"); |
| | | loading.value = false; |
| | | return; |
| | | } |
| | | 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 (qty > Number(stock)) { |
| | | showToast(`备件「${part?.name || ""}」领用数量不能超过库存(${stock})`); |
| | | loading.value = false; |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | const submitData = { |
| | | ...form.value, |
| | | imagesFile: form.value.status == "1" ? uploadFiles.value : [], |
| | | sparePartsIds: form.value.sparePartsIds |
| | | ? form.value.sparePartsIds.join(",") |
| | | : "", |
| | | 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 })) : [], |
| | | }; |
| | | const { code } = await addMaintenance({ id: id, ...submitData }); |
| | | |
| | |
| | | return null; |
| | | } |
| | | dataform.value = JSON.parse(dataStr); |
| | | fetchSparePartOptions(dataform.value.deviceLedgerId); |
| | | sparePartsQtyRaw.value = dataform.value?.sparePartsQty || ""; |
| | | fetchSparePartOptions(); |
| | | return JSON.parse(dataStr); |
| | | } catch (e) { |
| | | console.error("解析设备数据失败:", e); |
| | |
| | | // 显示设备备件选择器 |
| | | const showSparePartPicker = () => { |
| | | tempSelectedSpareParts.value = [...selectedSpareParts.value]; |
| | | 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) { |
| | | sparePartQtyMap[pid] = 1; |
| | | } |
| | | } |
| | | }); |
| | | showSparePart.value = true; |
| | | }; |
| | | |
| | |
| | | ); |
| | | if (index > -1) { |
| | | tempSelectedSpareParts.value.splice(index, 1); |
| | | delete sparePartQtyMap[itemId]; |
| | | } else { |
| | | tempSelectedSpareParts.value.push(item); |
| | | 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); |
| | | 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) { |
| | | sparePartQtyMap[pid] = 1; |
| | | } |
| | | } |
| | | }); |
| | | showSparePart.value = false; |
| | | }; |
| | | |
| | | // 移除已选备件 |
| | | const removeSparePart = index => { |
| | | selectedSpareParts.value.splice(index, 1); |
| | | form.value.sparePartsIds = selectedSpareParts.value.map(item => item.id); |
| | | const removed = selectedSpareParts.value.splice(index, 1)[0]; |
| | | 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]; |
| | | }; |
| | | const sparePartsIds = ref([]); |
| | | // 初始化表单数据 |
| | |
| | | // 先获取备件选项,再初始化表单 |
| | | const pageId = getPageId(); |
| | | if (pageId) { |
| | | await fetchSparePartOptions(pageId); |
| | | await fetchSparePartOptions(); |
| | | } |
| | | // 页面显示时初始化表单 |
| | | }); |
| | | const sparePartOptions = ref([]); |
| | | const fetchSparePartOptions = deviceLedgerId => { |
| | | // 备件列表接口对齐维修页/PC:/spareParts/listPage → res.data.records |
| | | const fetchSparePartOptions = () => { |
| | | return new Promise((resolve, reject) => { |
| | | getSparePartsOptions({ deviceLedgerId: deviceLedgerId }) |
| | | getSparePartsList({ current: 1, size: 1000 }) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | sparePartOptions.value = res.data || []; |
| | | sparePartOptions.value = res?.data?.records || []; |
| | | const idArray = |
| | | typeof sparePartsIds.value === "string" |
| | | ? sparePartsIds.value.split(",") |
| | | : sparePartsIds.value; |
| | | : (Array.isArray(sparePartsIds.value) ? sparePartsIds.value : []); |
| | | |
| | | if (idArray.length > 0) { |
| | | selectedSpareParts.value = sparePartOptions.value |
| | |
| | | name: option.name, |
| | | code: option.code, |
| | | value: option.id || option.value, |
| | | quantity: option.quantity, |
| | | })); |
| | | // 设置备件IDs |
| | | form.value.sparePartsIds = idArray.join(","); |
| | | // 设置备件IDs(保持数组,提交时再 join) |
| | | 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())); |
| | | 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) { |
| | | sparePartQtyMap[pid] = q; |
| | | } |
| | | }); |
| | | } |
| | | |
| | | // 默认数量兜底 |
| | | 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) { |
| | | sparePartQtyMap[pid] = 1; |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | resolve(res.data); |
| | | resolve(res?.data?.records || []); |
| | | } else { |
| | | resolve([]); |
| | | } |
| | |
| | | font-size: 14px; |
| | | } |
| | | |
| | | /* 领用数量样式 */ |
| | | .spare-qty-list { |
| | | width: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 12px; |
| | | padding: 4px 0; |
| | | } |
| | | |
| | | .spare-qty-row { |
| | | width: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .spare-qty-name { |
| | | flex: 1; |
| | | min-width: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | gap: 6px; |
| | | } |
| | | |
| | | .spare-name { |
| | | max-width: 220px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | color: #303133; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .spare-stock { |
| | | color: #909399; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | /* 备件选择弹窗样式 */ |
| | | .spare-part-popup { |
| | | padding: 16px; |