| | |
| | | @click="showDatePicker = true"></u-icon> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="设å¤å¤ä»¶" |
| | | prop="sparePartsIds" |
| | | border-bottom> |
| | | <view class="spare-parts-container" |
| | | @click="showSparePart = true"> |
| | | <view v-if="selectedSpareParts.length > 0" |
| | | class="spare-parts-list"> |
| | | <view v-for="(item, index) in selectedSpareParts" |
| | | :key="String(item.id)" |
| | | class="spare-part-tag"> |
| | | <text>{{ item.name }}</text> |
| | | <u-icon name="close" |
| | | size="12" |
| | | color="#fff" |
| | | @click.stop="removeSparePart(index)" /> |
| | | </view> |
| | | </view> |
| | | <text v-else |
| | | class="placeholder">è¯·éæ©è®¾å¤å¤ä»¶</text> |
| | | </view> |
| | | <template #right> |
| | | <u-icon name="arrow-right" |
| | | @click.stop="showSparePart = true"></u-icon> |
| | | </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)" |
| | | 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]" |
| | | :min="1" |
| | | :max="item.quantity !== null && item.quantity !== undefined ? Number(item.quantity) : undefined" /> |
| | | </view> |
| | | </view> |
| | | </u-form-item> |
| | | </u-cell-group> |
| | | <!-- æäº¤æé® --> |
| | | <view class="footer-btns"> |
| | |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | @confirm="onDateConfirm" |
| | | @cancel="showDatePicker = false" /> |
| | | |
| | | <!-- 设å¤å¤ä»¶éæ©å¨ --> |
| | | <up-popup :show="showSparePart" |
| | | mode="bottom" |
| | | :closeable="true" |
| | | @close="showSparePart = false"> |
| | | <view class="spare-part-popup"> |
| | | <view class="popup-header"> |
| | | <text class="popup-title">éæ©è®¾å¤å¤ä»¶</text> |
| | | </view> |
| | | <view class="spare-part-options"> |
| | | <view v-for="(item, index) in sparePartOptions" |
| | | :key="index" |
| | | class="spare-part-option" |
| | | :class="{ selected: isSparePartSelected(item.id) }" |
| | | @click="toggleSparePartSelection(item)"> |
| | | <text class="spare-part-option-text">{{ item.name }}</text> |
| | | <u-icon v-if="isSparePartSelected(item.id)" |
| | | name="checkmark" |
| | | color="#2c7be5" /> |
| | | </view> |
| | | </view> |
| | | <up-button type="primary" |
| | | size="small" |
| | | :customStyle="{ borderRadius: '6px', padding: '4px 12px' }" |
| | | @click="confirmSparePartSelection">ç¡®å®</up-button> |
| | | </view> |
| | | </up-popup> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted } from "vue"; |
| | | import { ref, onMounted, reactive, watch } from "vue"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { addMaintain } from "@/api/equipmentManagement/repair"; |
| | | import { getSparePartsList } from "@/api/equipmentManagement/spareParts"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import dayjs from "dayjs"; |
| | | |
| | |
| | | const loading = ref(false); |
| | | const showDatePicker = ref(false); |
| | | const pickerDateValue = ref(Date.now()); // ä½¿ç¨æ¶é´æ³ |
| | | const showSparePart = ref(false); |
| | | const sparePartOptions = ref([]); |
| | | const selectedSpareParts = ref([]); |
| | | const tempSelectedSpareParts = ref([]); |
| | | const sparePartQtyMap = reactive({}); |
| | | |
| | | // 表åéªè¯è§å |
| | | const formRules = { |
| | |
| | | maintenanceName: userStore.nickName || "", // é»è®¤ä½¿ç¨å½åç¨æ·æµç§° |
| | | maintenanceResult: undefined, // ç»´ä¿®ç»æ |
| | | maintenanceTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), // ç»´ä¿®æ¥æï¼åªæ¾ç¤ºæ¥æï¼ |
| | | status: "1", |
| | | sparePartsIds: [], |
| | | }); |
| | | |
| | | // èªå®ä¹showToast彿° |
| | |
| | | maintenanceName: userStore.nickName || "", |
| | | maintenanceResult: undefined, |
| | | maintenanceTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), |
| | | status: "1", |
| | | sparePartsIds: [], |
| | | }; |
| | | selectedSpareParts.value = []; |
| | | tempSelectedSpareParts.value = []; |
| | | Object.keys(sparePartQtyMap).forEach((k) => delete sparePartQtyMap[k]); |
| | | }; |
| | | |
| | | const resetFormAndValidate = () => { |
| | |
| | | return; |
| | | } |
| | | form.value.status = Number(form.value.status); |
| | | // åå¤æäº¤æ°æ®ï¼maintenanceTime å ä¸å½åæ¶åç§ |
| | | const submitData = { ...form.value }; |
| | | // é¢ç¨æ°éæ ¡éª |
| | | if (Array.isArray(form.value.sparePartsIds) && form.value.sparePartsIds.length > 0) { |
| | | for (const partId of form.value.sparePartsIds) { |
| | | 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) === 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 spareIds = Array.isArray(form.value.sparePartsIds) ? form.value.sparePartsIds : []; |
| | | const submitData = { |
| | | ...form.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 })) : [], |
| | | }; |
| | | |
| | | const { code } = await addMaintain({ id: id, ...submitData }); |
| | | |
| | |
| | | showDatePicker.value = false; |
| | | }; |
| | | |
| | | const fetchSparePartOptions = async () => { |
| | | try { |
| | | const res = await getSparePartsList({ current: 1, size: 1000 }); |
| | | if (res?.code === 200) { |
| | | sparePartOptions.value = res?.data?.records || []; |
| | | } else { |
| | | sparePartOptions.value = []; |
| | | } |
| | | } catch (e) { |
| | | sparePartOptions.value = []; |
| | | } |
| | | }; |
| | | |
| | | const isSparePartSelected = (id) => { |
| | | return tempSelectedSpareParts.value.some((p) => String(p.id) === String(id)); |
| | | }; |
| | | |
| | | const toggleSparePartSelection = (item) => { |
| | | const idx = tempSelectedSpareParts.value.findIndex((p) => String(p.id) === String(item.id)); |
| | | if (idx >= 0) { |
| | | tempSelectedSpareParts.value.splice(idx, 1); |
| | | delete sparePartQtyMap[item.id]; |
| | | } else { |
| | | tempSelectedSpareParts.value.push({ |
| | | id: item.id, |
| | | name: item.name, |
| | | quantity: item.quantity, |
| | | }); |
| | | if (!Number.isFinite(Number(sparePartQtyMap[item.id]))) { |
| | | sparePartQtyMap[item.id] = 1; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const confirmSparePartSelection = () => { |
| | | selectedSpareParts.value = [...tempSelectedSpareParts.value]; |
| | | form.value.sparePartsIds = selectedSpareParts.value.map((i) => i.id); |
| | | // ä¿åºç»æªå¡«çæ°éèµå¼ |
| | | selectedSpareParts.value.forEach((p) => { |
| | | if (!Number.isFinite(Number(sparePartQtyMap[p.id])) || Number(sparePartQtyMap[p.id]) <= 0) { |
| | | sparePartQtyMap[p.id] = 1; |
| | | } |
| | | }); |
| | | showSparePart.value = false; |
| | | }; |
| | | |
| | | const removeSparePart = (index) => { |
| | | const removed = selectedSpareParts.value.splice(index, 1)[0]; |
| | | tempSelectedSpareParts.value = [...selectedSpareParts.value]; |
| | | form.value.sparePartsIds = selectedSpareParts.value.map((i) => i.id); |
| | | if (removed?.id !== null && removed?.id !== undefined) { |
| | | delete sparePartQtyMap[removed.id]; |
| | | } |
| | | }; |
| | | |
| | | // åå§åè¡¨åæ°æ® |
| | | const initForm = () => { |
| | | const initForm = async () => { |
| | | form.value.status = "1"; |
| | | // 设置æ¥ä¿®äººä¸ºå½åç¨æ·æµç§° |
| | | form.value.maintenanceName = userStore.nickName || ""; |
| | | // 设置å½åæ¥æï¼åªå
å«å¹´ææ¥ï¼ |
| | | form.value.maintenanceTime = dayjs().format("YYYY-MM-DD HH:mm:ss"); |
| | | |
| | | // æåå¤ä»¶å表ï¼å¯¹é½ PCï¼/spareParts/listPageï¼ |
| | | await fetchSparePartOptions(); |
| | | }; |
| | | |
| | | onShow(() => { |
| | |
| | | // 页é¢å è½½æ¶åå§å表å |
| | | initForm(); |
| | | }); |
| | | |
| | | watch(showSparePart, (val) => { |
| | | if (val) { |
| | | tempSelectedSpareParts.value = [...selectedSpareParts.value]; |
| | | tempSelectedSpareParts.value.forEach((p) => { |
| | | if (!Number.isFinite(Number(sparePartQtyMap[p.id])) || Number(sparePartQtyMap[p.id]) <= 0) { |
| | | sparePartQtyMap[p.id] = 1; |
| | | } |
| | | }); |
| | | |
| | | // å
åºï¼å¦æè¿æ²¡å è½½å¤ä»¶åè¡¨ï¼æå¼å¼¹çªæ¶åæä¸æ¬¡ |
| | | if (!Array.isArray(sparePartOptions.value) || sparePartOptions.value.length === 0) { |
| | | fetchSparePartOptions().catch(() => {}); |
| | | } |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | |
| | | padding-bottom: 5rem; |
| | | } |
| | | |
| | | .spare-parts-container { |
| | | width: 100%; |
| | | min-height: 72rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | gap: 12rpx; |
| | | } |
| | | |
| | | .spare-parts-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 12rpx; |
| | | } |
| | | |
| | | .spare-part-tag { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | gap: 8rpx; |
| | | padding: 10rpx 14rpx; |
| | | background: #2c7be5; |
| | | border-radius: 999rpx; |
| | | color: #fff; |
| | | font-size: 24rpx; |
| | | } |
| | | |
| | | .placeholder { |
| | | color: #c0c4cc; |
| | | font-size: 28rpx; |
| | | } |
| | | |
| | | .spare-qty-list { |
| | | width: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 18rpx; |
| | | padding: 6rpx 0; |
| | | } |
| | | |
| | | .spare-qty-row { |
| | | width: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 18rpx; |
| | | } |
| | | |
| | | .spare-qty-name { |
| | | flex: 1; |
| | | min-width: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | gap: 8rpx; |
| | | } |
| | | |
| | | .spare-name { |
| | | max-width: 420rpx; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | color: #303133; |
| | | font-size: 28rpx; |
| | | } |
| | | |
| | | .spare-stock { |
| | | color: #909399; |
| | | font-size: 24rpx; |
| | | } |
| | | |
| | | .spare-part-popup { |
| | | padding: 24rpx; |
| | | } |
| | | |
| | | .popup-header { |
| | | padding-bottom: 12rpx; |
| | | } |
| | | |
| | | .popup-title { |
| | | font-size: 32rpx; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | |
| | | .spare-part-options { |
| | | max-height: 60vh; |
| | | overflow: auto; |
| | | margin: 16rpx 0 24rpx 0; |
| | | border-radius: 12rpx; |
| | | background: #fff; |
| | | } |
| | | |
| | | .spare-part-option { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 22rpx 18rpx; |
| | | border-bottom: 1rpx solid #f2f3f5; |
| | | } |
| | | |
| | | .spare-part-option.selected { |
| | | background: #f3f8ff; |
| | | } |
| | | |
| | | .spare-part-option-text { |
| | | color: #303133; |
| | | font-size: 28rpx; |
| | | } |
| | | |
| | | .footer-btns { |
| | | position: fixed; |
| | | left: 0; |