| | |
| | | url: `/device/repair/file/${fileId}`, |
| | | method: "delete", |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * @desc è®¾å¤æ¥ä¿®éªæ¶ |
| | | * @param {éªæ¶åæ°} data |
| | | * @returns |
| | | */ |
| | | export const acceptRepair = (data) => { |
| | | return request({ |
| | | url: "/device/repair/acceptance", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | }; |
| | |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/equipmentManagement/repair/detail", |
| | | "style": { |
| | | "navigationBarTitleText": "è®¾å¤æ¥ä¿®è¯¦æ
", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/equipmentManagement/repair/acceptance", |
| | | "style": { |
| | | "navigationBarTitleText": "è®¾å¤æ¥ä¿®éªæ¶", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/equipmentManagement/upkeep/index", |
| | | "style": { |
| | | "navigationBarTitleText": "设å¤ä¿å
»", |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="repair-acceptance"> |
| | | <PageHeader title="è®¾å¤æ¥ä¿®éªæ¶" |
| | | @back="goBack" /> |
| | | <view class="section" |
| | | v-if="detail"> |
| | | <view class="section-title">æ¥ä¿®ä¿¡æ¯</view> |
| | | <view class="info-item"> |
| | | <text class="info-label">设å¤åç§°</text> |
| | | <text class="info-value">{{ detail.deviceName || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">éªæ¶äºº</text> |
| | | <text class="info-value">{{ detail.acceptanceName || '-' }}</text> |
| | | </view> |
| | | </view> |
| | | <u-form ref="formRef" |
| | | :model="form" |
| | | label-width="110"> |
| | | <u-cell-group title="éªæ¶ä¿¡æ¯"> |
| | | <u-form-item label="éªæ¶äºº" |
| | | border-bottom> |
| | | <u-input v-model="form.acceptanceName" |
| | | disabled |
| | | placeholder="éªæ¶äºº" /> |
| | | </u-form-item> |
| | | <u-form-item label="éªæ¶æ¶é´" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="form.acceptanceTime" |
| | | placeholder="è¯·éæ©éªæ¶æ¶é´" |
| | | readonly |
| | | @click="showDatePicker = true" /> |
| | | <template #right> |
| | | <u-icon name="arrow-right" |
| | | @click="showDatePicker = true" /> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="éªæ¶å¤æ³¨" |
| | | required |
| | | border-bottom> |
| | | <u-textarea v-model="form.acceptanceRemark" |
| | | placeholder="请è¾å
¥éªæ¶å¤æ³¨" |
| | | :maxlength="200" |
| | | count |
| | | :autoHeight="true" /> |
| | | </u-form-item> |
| | | </u-cell-group> |
| | | <view class="footer-btns"> |
| | | <u-button class="cancel-btn" |
| | | @click="goBack">åæ¶</u-button> |
| | | <u-button class="save-btn" |
| | | type="primary" |
| | | :loading="loading" |
| | | @click="submitAcceptance">ç¡®è®¤éªæ¶</u-button> |
| | | </view> |
| | | </u-form> |
| | | <up-datetime-picker :show="showDatePicker" |
| | | v-model="pickerDateValue" |
| | | mode="datetime" |
| | | @confirm="onDateConfirm" |
| | | @cancel="showDatePicker = false" /> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getRepairById, acceptRepair } from "@/api/equipmentManagement/repair"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | defineOptions({ name: "è®¾å¤æ¥ä¿®éªæ¶" }); |
| | | |
| | | const userStore = useUserStore(); |
| | | const repairId = ref(""); |
| | | const detail = ref(null); |
| | | const loading = ref(false); |
| | | const showDatePicker = ref(false); |
| | | const pickerDateValue = ref(Date.now()); |
| | | |
| | | const form = ref({ |
| | | id: "", |
| | | acceptanceName: "", |
| | | acceptanceTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), |
| | | acceptanceRemark: "", |
| | | }); |
| | | |
| | | const showToast = message => { |
| | | uni.showToast({ title: message, icon: "none" }); |
| | | }; |
| | | |
| | | const getCurrentUserName = () => |
| | | (userStore.nickName || userStore.name || "").trim(); |
| | | |
| | | const canAccept = acceptanceName => { |
| | | const current = getCurrentUserName(); |
| | | const target = (acceptanceName || "").trim(); |
| | | return current && target && current === target; |
| | | }; |
| | | |
| | | const loadDetail = async () => { |
| | | if (!repairId.value) { |
| | | showToast("åæ°é误"); |
| | | return; |
| | | } |
| | | try { |
| | | uni.showLoading({ title: "å è½½ä¸...", mask: true }); |
| | | const { code, data } = await getRepairById(repairId.value); |
| | | if (code !== 200) { |
| | | showToast("è·å详æ
失败"); |
| | | return; |
| | | } |
| | | detail.value = data; |
| | | if (Number(data.status) !== 3) { |
| | | showToast("å½åç¶æä¸å¯éªæ¶"); |
| | | setTimeout(() => goBack(), 1500); |
| | | return; |
| | | } |
| | | if (!canAccept(data.acceptanceName)) { |
| | | showToast("ä»
æå®éªæ¶äººå¯è¿è¡éªæ¶"); |
| | | setTimeout(() => goBack(), 1500); |
| | | return; |
| | | } |
| | | form.value.id = data.id; |
| | | form.value.acceptanceName = data.acceptanceName || ""; |
| | | form.value.acceptanceTime = dayjs().format("YYYY-MM-DD HH:mm:ss"); |
| | | } catch (e) { |
| | | showToast("è·å详æ
失败"); |
| | | } finally { |
| | | uni.hideLoading(); |
| | | } |
| | | }; |
| | | |
| | | const onDateConfirm = e => { |
| | | form.value.acceptanceTime = dayjs(e.value).format("YYYY-MM-DD HH:mm:ss"); |
| | | pickerDateValue.value = e.value; |
| | | showDatePicker.value = false; |
| | | }; |
| | | |
| | | const submitAcceptance = async () => { |
| | | if (!form.value.acceptanceTime?.trim()) { |
| | | showToast("è¯·éæ©éªæ¶æ¶é´"); |
| | | return; |
| | | } |
| | | if (!form.value.acceptanceRemark?.trim()) { |
| | | showToast("请è¾å
¥éªæ¶å¤æ³¨"); |
| | | return; |
| | | } |
| | | try { |
| | | loading.value = true; |
| | | const { code, msg } = await acceptRepair({ |
| | | id: form.value.id, |
| | | acceptanceTime: form.value.acceptanceTime, |
| | | acceptanceRemark: form.value.acceptanceRemark.trim(), |
| | | }); |
| | | if (code === 200) { |
| | | showToast("éªæ¶æå"); |
| | | setTimeout(() => goBack(), 1500); |
| | | } else { |
| | | showToast(msg || "éªæ¶å¤±è´¥"); |
| | | loading.value = false; |
| | | } |
| | | } catch (e) { |
| | | loading.value = false; |
| | | showToast("éªæ¶å¤±è´¥"); |
| | | } |
| | | }; |
| | | |
| | | const goBack = () => { |
| | | uni.removeStorageSync("repairId"); |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | onLoad(options => { |
| | | repairId.value = options?.id || uni.getStorageSync("repairId") || ""; |
| | | form.value.id = repairId.value; |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | loadDetail(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "@/static/scss/form-common.scss"; |
| | | |
| | | .repair-acceptance { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 5rem; |
| | | } |
| | | |
| | | .section { |
| | | margin: 12px 16px; |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); |
| | | } |
| | | |
| | | .section-title { |
| | | padding: 14px 16px; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | padding: 12px 16px; |
| | | border-bottom: 1px solid #f8f8f8; |
| | | } |
| | | |
| | | .info-label { |
| | | width: 90px; |
| | | font-size: 14px; |
| | | color: #606266; |
| | | } |
| | | |
| | | .info-value { |
| | | flex: 1; |
| | | font-size: 14px; |
| | | color: #303133; |
| | | text-align: right; |
| | | } |
| | | |
| | | .footer-btns { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 0.75rem 0; |
| | | box-shadow: 0 -0.125rem 0.5rem rgba(0, 0, 0, 0.05); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .cancel-btn { |
| | | font-size: 1rem; |
| | | color: #ffffff; |
| | | width: 6.375rem; |
| | | background: #c7c9cc; |
| | | border-radius: 2.5rem; |
| | | } |
| | | |
| | | .save-btn { |
| | | font-size: 1rem; |
| | | color: #ffffff; |
| | | width: 14rem; |
| | | background: linear-gradient(140deg, #00baff 0%, #006cfb 100%); |
| | | border-radius: 2.5rem; |
| | | } |
| | | </style> |
| | |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="æ¥ä¿®äºº" |
| | | prop="repairName" |
| | | prop="maintenanceName" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="form.repairName" |
| | | <u-input v-model="form.maintenanceName" |
| | | placeholder="请è¾å
¥æ¥ä¿®äºº" |
| | | clearable /> |
| | | </u-form-item> |
| | | <u-form-item label="éªæ¶äºº" |
| | | prop="acceptanceName" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="form.acceptanceName" |
| | | placeholder="请è¾å
¥éªæ¶äºº" |
| | | clearable /> |
| | | </u-form-item> |
| | | <u-form-item label="æ
éç°è±¡" |
| | |
| | | } from "@/api/equipmentManagement/repair"; |
| | | import dayjs from "dayjs"; |
| | | import { formatDateToYMD } from "@/utils/ruoyi"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | |
| | | const userStore = useUserStore(); |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | | title: message, |
| | |
| | | repairTime: [ |
| | | { required: true, trigger: "change", message: "è¯·éæ©æ¥ä¿®æ¥æ" }, |
| | | ], |
| | | repairName: [{ required: true, trigger: "blur", message: "请è¾å
¥æ¥ä¿®äºº" }], |
| | | maintenanceName: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥æ¥ä¿®äºº" }, |
| | | ], |
| | | acceptanceName: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥éªæ¶äºº" }, |
| | | ], |
| | | remark: [{ required: true, trigger: "blur", message: "请è¾å
¥æ
éç°è±¡" }], |
| | | }; |
| | | |
| | |
| | | deviceLedgerId: undefined, // 设å¤ID |
| | | deviceModel: undefined, // è§æ ¼åå· |
| | | repairTime: dayjs().format("YYYY-MM-DD"), // æ¥ä¿®æ¥æ |
| | | repairName: undefined, // æ¥ä¿®äºº |
| | | status: "0", |
| | | maintenanceName: userStore.nickName || userStore.name || "", // æ¥ä¿®äºº |
| | | acceptanceName: undefined, // éªæ¶äºº |
| | | remark: undefined, // æ
éç°è±¡ |
| | | }); |
| | | |
| | |
| | | // æ¥ä¿®ç¶æé项 |
| | | const repairStatusOptions = ref([ |
| | | { name: "å¾
ç»´ä¿®", value: "0" }, |
| | | { name: "å®ç»", value: "1" }, |
| | | { name: "失败", value: "2" }, |
| | | { name: "å¾
éªæ¶", value: "3" }, |
| | | { name: "宿", value: "1" }, |
| | | { name: "维修失败", value: "2" }, |
| | | ]); |
| | | const repairStatusText = ref(""); |
| | | const repairStatusText = ref("å¾
ç»´ä¿®"); |
| | | |
| | | // æå¼æ¥ä¿®ç¶æéæ©å¨ |
| | | const openRepairStatusPicker = () => { |
| | |
| | | form.value.deviceLedgerId = data.deviceLedgerId; |
| | | form.value.deviceModel = data.deviceModel; |
| | | form.value.repairTime = dayjs(data.repairTime).format("YYYY-MM-DD"); |
| | | form.value.repairName = data.repairName; |
| | | form.value.maintenanceName = |
| | | data.maintenanceName || data.repairName || ""; |
| | | form.value.acceptanceName = data.acceptanceName || ""; |
| | | form.value.remark = data.remark; |
| | | form.value.status = |
| | | data.status !== undefined && data.status !== null |
| | | ? String(data.status) |
| | | : "0"; |
| | | await fetchRepairFileList(id); |
| | | repairStatusText.value = |
| | | repairStatusOptions.value.find(item => item.value == data.status) |
| | | ?.name || ""; |
| | | repairStatusOptions.value.find( |
| | | item => item.value == String(data.status) |
| | | )?.name || "å¾
ç»´ä¿®"; |
| | | // 设置设å¤åç§°æ¾ç¤º |
| | | const device = deviceOptions.value.find( |
| | | item => item.id === data.deviceLedgerId |
| | |
| | | showToast("è·å详æ
失败"); |
| | | } |
| | | } else { |
| | | // æ°å¢æ¨¡å¼ |
| | | operationType.value = "add"; |
| | | form.value.status = "0"; |
| | | repairStatusText.value = "å¾
ç»´ä¿®"; |
| | | if (!form.value.maintenanceName) { |
| | | form.value.maintenanceName = |
| | | userStore.nickName || userStore.name || ""; |
| | | } |
| | | } |
| | | }; |
| | | |
| | |
| | | } else if (!form.value.repairTime || form.value.repairTime.trim() === "") { |
| | | isValid = false; |
| | | errorMessage = "è¯·éæ©æ¥ä¿®æ¥æ"; |
| | | } else if (!form.value.repairName || form.value.repairName.trim() === "") { |
| | | } else if ( |
| | | !form.value.maintenanceName || |
| | | form.value.maintenanceName.trim() === "" |
| | | ) { |
| | | isValid = false; |
| | | errorMessage = "请è¾å
¥æ¥ä¿®äºº"; |
| | | } else if ( |
| | | !form.value.acceptanceName || |
| | | form.value.acceptanceName.trim() === "" |
| | | ) { |
| | | isValid = false; |
| | | errorMessage = "请è¾å
¥éªæ¶äºº"; |
| | | } else if (!form.value.remark || form.value.remark.trim() === "") { |
| | | isValid = false; |
| | | errorMessage = "请è¾å
¥æ
éç°è±¡"; |
| | |
| | | const id = getPageId(); |
| | | |
| | | // åå¤æäº¤æ°æ® |
| | | const submitData = { ...form.value }; |
| | | const submitData = { |
| | | ...form.value, |
| | | status: Number(form.value.status ?? 0), |
| | | repairName: form.value.maintenanceName, |
| | | }; |
| | | |
| | | const result = id |
| | | ? await editRepair({ id: id, ...submitData }) |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="repair-detail"> |
| | | <PageHeader title="è®¾å¤æ¥ä¿®è¯¦æ
" |
| | | @back="goBack" /> |
| | | <view v-if="detail" |
| | | class="detail-content"> |
| | | <!-- 1. æ¥ä¿®ç»è®° --> |
| | | <view class="section"> |
| | | <view class="section-title"> |
| | | <text class="section-num">1</text> |
| | | <text>æ¥ä¿®ç»è®°</text> |
| | | </view> |
| | | <view class="info-grid"> |
| | | <view class="info-item"> |
| | | <text class="info-label">设å¤åç§°</text> |
| | | <text class="info-value">{{ detail.deviceName || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">è§æ ¼åå·</text> |
| | | <text class="info-value">{{ detail.deviceModel || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">æ¥ä¿®æ¥æ</text> |
| | | <text class="info-value">{{ formatDate(detail.repairTime) || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">æ¥ä¿®äºº</text> |
| | | <text class="info-value">{{ detail.repairName || detail.maintenanceName || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">éªæ¶äºº</text> |
| | | <text class="info-value">{{ detail.acceptanceName || '-' }}</text> |
| | | </view> |
| | | <view class="info-item" |
| | | v-if="Number(detail.status) !== 0"> |
| | | <text class="info-label">维修人</text> |
| | | <text class="info-value">{{ detail.maintenancePerson || detail.maintenanceName || '-' }}</text> |
| | | </view> |
| | | <view class="info-item full"> |
| | | <text class="info-label">æ
éç°è±¡</text> |
| | | <text class="info-value">{{ detail.remark || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å½åç¶æ</text> |
| | | <view class="info-value"> |
| | | <u-tag :type="getStatusTagType(detail.status)" |
| | | size="small">{{ getStatusText(detail.status) }}</u-tag> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view class="image-section"> |
| | | <text class="image-title">设å¤é®é¢å¾ç</text> |
| | | <view v-if="repairImageList.length" |
| | | class="image-list"> |
| | | <image v-for="(file, index) in repairImageList" |
| | | :key="file.id || index" |
| | | :src="getFileAccessUrl(file)" |
| | | mode="aspectFill" |
| | | class="repair-image" |
| | | @click="previewImage(index)" /> |
| | | </view> |
| | | <view v-else |
| | | class="no-image"> |
| | | <up-icon name="photo" |
| | | size="40" |
| | | color="#c0c4cc" /> |
| | | <text>ææ è®¾å¤é®é¢å¾ç</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 2. ç»´ä¿®å¤ç --> |
| | | <view class="section" |
| | | v-if="showMaintenanceSection"> |
| | | <view class="section-title"> |
| | | <text class="section-num">2</text> |
| | | <text>ç»´ä¿®å¤ç</text> |
| | | </view> |
| | | <view class="info-grid"> |
| | | <view class="info-item"> |
| | | <text class="info-label">维修人</text> |
| | | <text class="info-value">{{ detail.maintenancePerson || detail.maintenanceName || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">ç»´ä¿®æ¶é´</text> |
| | | <text class="info-value">{{ formatDateTime(detail.maintenanceTime) || '-' }}</text> |
| | | </view> |
| | | <view class="info-item full"> |
| | | <text class="info-label">ç»´ä¿®ç»æ</text> |
| | | <text class="info-value">{{ detail.maintenanceResult || '-' }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 3. éªæ¶ --> |
| | | <view class="section" |
| | | v-if="showAcceptanceSection"> |
| | | <view class="section-title"> |
| | | <text class="section-num">3</text> |
| | | <text>éªæ¶</text> |
| | | </view> |
| | | <view class="info-grid"> |
| | | <view class="info-item"> |
| | | <text class="info-label">éªæ¶äºº</text> |
| | | <text class="info-value">{{ detail.acceptanceName || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">éªæ¶æ¶é´</text> |
| | | <text class="info-value">{{ formatDateTime(detail.acceptanceTime) || '-' }}</text> |
| | | </view> |
| | | <view class="info-item full"> |
| | | <text class="info-label">éªæ¶å¤æ³¨</text> |
| | | <text class="info-value">{{ detail.acceptanceRemark || '-' }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else |
| | | class="loading-wrap"> |
| | | <text>å è½½ä¸...</text> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed, onMounted } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import config from "@/config"; |
| | | import { |
| | | getRepairById, |
| | | getRepairFileList, |
| | | } from "@/api/equipmentManagement/repair"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | defineOptions({ name: "è®¾å¤æ¥ä¿®è¯¦æ
" }); |
| | | |
| | | const repairId = ref(""); |
| | | const detail = ref(null); |
| | | const repairImageList = ref([]); |
| | | |
| | | const STATUS_MAP = { |
| | | 0: "å¾
ç»´ä¿®", |
| | | 3: "å¾
éªæ¶", |
| | | 1: "宿", |
| | | 2: "维修失败", |
| | | }; |
| | | |
| | | const getStatusText = status => STATUS_MAP[Number(status)] || "-"; |
| | | |
| | | const getStatusTagType = status => { |
| | | const map = { 0: "error", 3: "warning", 1: "success", 2: "error" }; |
| | | return map[Number(status)] || "info"; |
| | | }; |
| | | |
| | | const showMaintenanceSection = computed(() => Number(detail.value?.status) !== 0); |
| | | |
| | | const showAcceptanceSection = computed(() => Number(detail.value?.status) === 1); |
| | | |
| | | const formatDate = dateStr => { |
| | | if (!dateStr) return ""; |
| | | return dayjs(dateStr).format("YYYY-MM-DD"); |
| | | }; |
| | | |
| | | const formatDateTime = dateStr => { |
| | | if (!dateStr) return ""; |
| | | return dayjs(dateStr).format("YYYY-MM-DD HH:mm:ss"); |
| | | }; |
| | | |
| | | const normalizeFileUrl = (rawUrl = "") => { |
| | | let fileUrl = rawUrl || ""; |
| | | const javaApi = config.baseUrl; |
| | | const localPrefixes = ["wxfile://", "file://", "content://", "blob:", "data:"]; |
| | | |
| | | if (localPrefixes.some(prefix => fileUrl.startsWith(prefix))) { |
| | | return fileUrl; |
| | | } |
| | | |
| | | if (fileUrl && fileUrl.indexOf("\\") > -1) { |
| | | const lowerPath = fileUrl.toLowerCase(); |
| | | const uploadPathIndex = lowerPath.indexOf("uploadpath"); |
| | | if (uploadPathIndex > -1) { |
| | | fileUrl = fileUrl.substring(uploadPathIndex).replace(/\\/g, "/"); |
| | | } else { |
| | | fileUrl = fileUrl.replace(/\\/g, "/"); |
| | | } |
| | | } |
| | | fileUrl = fileUrl.replace(/^\/?uploadPath/, "/profile"); |
| | | |
| | | if (fileUrl && !fileUrl.startsWith("http")) { |
| | | if (!fileUrl.startsWith("/")) fileUrl = "/" + fileUrl; |
| | | fileUrl = javaApi + fileUrl; |
| | | } |
| | | return fileUrl; |
| | | }; |
| | | |
| | | const getFileAccessUrl = (file = {}) => { |
| | | if (file?.link) { |
| | | if (String(file.link).startsWith("http")) return file.link; |
| | | return normalizeFileUrl(file.link); |
| | | } |
| | | return normalizeFileUrl(file?.url || ""); |
| | | }; |
| | | |
| | | const previewImage = index => { |
| | | const urls = repairImageList.value |
| | | .map(item => getFileAccessUrl(item)) |
| | | .filter(Boolean); |
| | | if (!urls.length) return; |
| | | uni.previewImage({ urls, current: urls[index] || urls[0] }); |
| | | }; |
| | | |
| | | const loadDetail = async () => { |
| | | if (!repairId.value) return; |
| | | try { |
| | | uni.showLoading({ title: "å è½½ä¸...", mask: true }); |
| | | const { code, data } = await getRepairById(repairId.value); |
| | | if (code === 200) { |
| | | detail.value = data; |
| | | } else { |
| | | uni.showToast({ title: "è·å详æ
失败", icon: "none" }); |
| | | } |
| | | const fileRes = await getRepairFileList(repairId.value); |
| | | if (fileRes?.code === 200) { |
| | | repairImageList.value = Array.isArray(fileRes.data) ? fileRes.data : []; |
| | | } |
| | | } catch (e) { |
| | | uni.showToast({ title: "è·å详æ
失败", icon: "none" }); |
| | | } finally { |
| | | uni.hideLoading(); |
| | | } |
| | | }; |
| | | |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | onLoad(options => { |
| | | repairId.value = options?.id || uni.getStorageSync("repairId") || ""; |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | loadDetail(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .repair-detail { |
| | | min-height: 100vh; |
| | | background: #f5f6f8; |
| | | padding-bottom: 24px; |
| | | } |
| | | |
| | | .detail-content { |
| | | padding: 12px 16px; |
| | | } |
| | | |
| | | .section { |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | margin-bottom: 16px; |
| | | overflow: hidden; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); |
| | | } |
| | | |
| | | .section-title { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | padding: 14px 16px; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .section-num { |
| | | width: 22px; |
| | | height: 22px; |
| | | line-height: 22px; |
| | | text-align: center; |
| | | border-radius: 50%; |
| | | background: #2c7be5; |
| | | color: #fff; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .info-grid { |
| | | padding: 8px 16px 12px; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .info-item { |
| | | width: 50%; |
| | | padding: 10px 8px 10px 0; |
| | | box-sizing: border-box; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | |
| | | &.full { |
| | | width: 100%; |
| | | } |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 13px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .info-value { |
| | | font-size: 14px; |
| | | color: #303133; |
| | | word-break: break-all; |
| | | } |
| | | |
| | | .image-section { |
| | | padding: 0 16px 16px; |
| | | border-top: 1px solid #f5f5f5; |
| | | margin-top: 4px; |
| | | padding-top: 12px; |
| | | } |
| | | |
| | | .image-title { |
| | | font-size: 13px; |
| | | color: #909399; |
| | | display: block; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .image-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .repair-image { |
| | | width: 80px; |
| | | height: 80px; |
| | | border-radius: 6px; |
| | | background: #f5f5f5; |
| | | } |
| | | |
| | | .no-image { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 24px; |
| | | color: #c0c4cc; |
| | | font-size: 13px; |
| | | gap: 8px; |
| | | background: #fafafa; |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .loading-wrap { |
| | | padding: 40px; |
| | | text-align: center; |
| | | color: #909399; |
| | | } |
| | | </style> |
| | |
| | | <text class="item-id">设å¤åç§°ï¼{{ item.deviceName }}</text> |
| | | </view> |
| | | <view class="status-tag"> |
| | | <u-tag v-if="item.status === 1" |
| | | type="success">å®ç»</u-tag> |
| | | <u-tag v-if="item.status === 0" |
| | | type="error">å¾
ç»´ä¿®</u-tag> |
| | | <u-tag :type="getStatusTagType(item.status)" |
| | | size="small">{{ getStatusText(item.status) }}</u-tag> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ¥ä¿®äºº</text> |
| | | <text class="detail-value">{{ item.repairName || '-' }}</text> |
| | | <text class="detail-value">{{ item.maintenanceName || item.repairName || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">éªæ¶äºº</text> |
| | | <text class="detail-value">{{ item.acceptanceName || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ
éç°è±¡</text> |
| | | <text class="detail-value">{{ item.remark || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <view class="detail-row" |
| | | v-if="Number(item.status) !== 0"> |
| | | <text class="detail-label">维修人</text> |
| | | <text class="detail-value">{{ item.maintenanceName || '-' }}</text> |
| | | <text class="detail-value">{{ item.maintenancePerson || item.maintenanceName || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç»´ä¿®ç»æ</text> |
| | |
| | | </view> |
| | | <!-- æé®åºå --> |
| | | <view class="action-buttons"> |
| | | <u-button type="info" |
| | | size="small" |
| | | plain |
| | | class="action-btn" |
| | | @click="goDetail(item.id)"> |
| | | 详æ
|
| | | </u-button> |
| | | <u-button type="primary" |
| | | size="small" |
| | | class="action-btn" |
| | | :disabled="item.status === 1" |
| | | :disabled="Number(item.status) !== 0" |
| | | @click="edit(item.id)"> |
| | | ç¼è¾ |
| | | </u-button> |
| | | <u-button type="warning" |
| | | size="small" |
| | | class="action-btn" |
| | | :disabled="item.status === 1" |
| | | :disabled="Number(item.status) !== 0" |
| | | @click="addMaintain(item.id)"> |
| | | æ°å¢ç»´ä¿® |
| | | </u-button> |
| | | <u-button type="success" |
| | | size="small" |
| | | class="action-btn" |
| | | :disabled="!canAccept(item)" |
| | | @click="goAcceptance(item.id)"> |
| | | éªæ¶ |
| | | </u-button> |
| | | <u-button type="error" |
| | | size="small" |
| | |
| | | }; |
| | | |
| | | const userStore = useUserStore(); |
| | | |
| | | const STATUS_MAP = { |
| | | 0: "å¾
ç»´ä¿®", |
| | | 3: "å¾
éªæ¶", |
| | | 1: "宿", |
| | | 2: "维修失败", |
| | | }; |
| | | |
| | | const getStatusText = status => STATUS_MAP[Number(status)] || "-"; |
| | | |
| | | const getStatusTagType = status => { |
| | | const map = { 0: "error", 3: "warning", 1: "success", 2: "error" }; |
| | | return map[Number(status)] || "info"; |
| | | }; |
| | | |
| | | const getCurrentUserName = () => |
| | | (userStore.nickName || userStore.name || "").trim(); |
| | | |
| | | const canAccept = item => { |
| | | if (Number(item?.status) !== 3) return false; |
| | | const current = getCurrentUserName(); |
| | | const target = (item?.acceptanceName || "").trim(); |
| | | return Boolean(current && target && current === target); |
| | | }; |
| | | |
| | | // æç´¢å
³é®è¯ |
| | | const searchKeyword = ref(""); |
| | |
| | | }); |
| | | }; |
| | | |
| | | const goDetail = id => { |
| | | if (!id) return; |
| | | uni.navigateTo({ |
| | | url: `/pages/equipmentManagement/repair/detail?id=${id}`, |
| | | }); |
| | | }; |
| | | |
| | | const goAcceptance = id => { |
| | | if (!id) { |
| | | showToast("åæ°é误"); |
| | | return; |
| | | } |
| | | uni.setStorageSync("repairId", id); |
| | | uni.navigateTo({ |
| | | url: `/pages/equipmentManagement/repair/acceptance?id=${id}`, |
| | | }); |
| | | }; |
| | | |
| | | // ç¼è¾ - 跳转å°add页é¢ï¼éè¿idåºåæ°å¢è¿æ¯ç¼è¾ |
| | | const edit = id => { |
| | | if (!id) return; |
| | |
| | | } |
| | | |
| | | .action-buttons { |
| | | gap: 8px; // ä¸å
Œ
±æ ·å¼ä¸ç 12px ä¸å |
| | | flex-wrap: wrap; |
| | | gap: 8px; |
| | | } |
| | | </style> |
| | |
| | | <u-cell-group title="维修信æ¯" |
| | | inset> |
| | | <u-form-item prop="maintenanceName" |
| | | label="æ¥ä¿®äºº" |
| | | label="维修人" |
| | | required> |
| | | <u-input v-model="form.maintenanceName" |
| | | placeholder="请è¾å
¥æ¥ä¿®äºº" |
| | | placeholder="请è¾å
¥ç»´ä¿®äºº" |
| | | clearable /> |
| | | </u-form-item> |
| | | <u-form-item prop="maintenanceResult" |
| | |
| | | // 表åéªè¯è§å |
| | | const formRules = { |
| | | maintenanceName: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥æ¥ä¿®äºº" }, |
| | | { required: true, trigger: "blur", message: "请è¾å
¥ç»´ä¿®äºº" }, |
| | | ], |
| | | maintenanceResult: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥ç»´ä¿®ç»æ" }, |
| | |
| | | ], |
| | | }; |
| | | const repairStatusOptions = ref([ |
| | | { name: "å¾
ç»´ä¿®", value: "0" }, |
| | | { name: "å®ç»", value: "1" }, |
| | | { name: "失败", value: "2" }, |
| | | { name: "å¾
éªæ¶", value: "3" }, |
| | | { name: "宿", value: "1" }, |
| | | { name: "维修失败", value: "2" }, |
| | | ]); |
| | | const repairStatusText = ref("å®ç»"); |
| | | const repairStatusText = ref("å¾
éªæ¶"); |
| | | // æå¼æ¥ä¿®ç¶æéæ©å¨ |
| | | const openRepairStatusPicker = () => { |
| | | uni.showActionSheet({ |
| | |
| | | }; |
| | | // ä½¿ç¨ ref 声æè¡¨åæ°æ® |
| | | const form = ref({ |
| | | maintenanceName: userStore.nickName || "", // é»è®¤ä½¿ç¨å½åç¨æ·æµç§° |
| | | maintenanceResult: undefined, // ç»´ä¿®ç»æ |
| | | maintenanceTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), // ç»´ä¿®æ¥æï¼åªæ¾ç¤ºæ¥æï¼ |
| | | status: "1", |
| | | maintenanceName: userStore.nickName || userStore.name || "", |
| | | maintenanceResult: undefined, |
| | | maintenanceTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), |
| | | status: "3", |
| | | sparePartsIds: [], |
| | | }); |
| | | |
| | |
| | | // éç½®è¡¨åæ°æ®åæ ¡éªç¶æ |
| | | const resetForm = () => { |
| | | form.value = { |
| | | maintenanceName: userStore.nickName || "", |
| | | maintenanceName: userStore.nickName || userStore.name || "", |
| | | maintenanceResult: undefined, |
| | | maintenanceTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), |
| | | status: "1", |
| | | status: "3", |
| | | sparePartsIds: [], |
| | | }; |
| | | selectedSpareParts.value = []; |
| | |
| | | |
| | | // åå§åè¡¨åæ°æ® |
| | | const initForm = async () => { |
| | | form.value.status = "1"; |
| | | // 设置æ¥ä¿®äººä¸ºå½åç¨æ·æµç§° |
| | | form.value.maintenanceName = userStore.nickName || ""; |
| | | form.value.status = "3"; |
| | | form.value.maintenanceName = userStore.nickName || userStore.name || ""; |
| | | repairStatusText.value = "å¾
éªæ¶"; |
| | | // 设置å½åæ¥æï¼åªå
å«å¹´ææ¥ï¼ |
| | | form.value.maintenanceTime = dayjs().format("YYYY-MM-DD HH:mm:ss"); |
| | | |
| | |
| | | placeholder="请è¾å
¥åä½" |
| | | disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="æ°é" |
| | | <up-form-item label="æ»æ°é" |
| | | prop="quantity" |
| | | required |
| | | border-bottom> |
| | | <up-input v-model="form.quantity" |
| | | type="number" |
| | | placeholder="请è¾å
¥æ°é" |
| | | placeholder="请è¾å
¥æ»æ°é" |
| | | :disabled="processQuantityDisabled" /> |
| | | </up-form-item> |
| | | <up-form-item label="åæ ¼æ°é" |
| | | prop="qualifiedQuantity" |
| | | required |
| | | border-bottom> |
| | | <up-input v-model="form.qualifiedQuantity" |
| | | type="number" |
| | | placeholder="请è¾å
¥åæ ¼æ°é" |
| | | clearable /> |
| | | </up-form-item> |
| | | <up-form-item label="ä¸åæ ¼æ°é" |
| | | prop="unqualifiedQuantity" |
| | | required |
| | | border-bottom> |
| | | <up-input v-model="form.unqualifiedQuantity" |
| | | type="number" |
| | | placeholder="请è¾å
¥ä¸åæ ¼æ°é" |
| | | clearable /> |
| | | </up-form-item> |
| | | <up-form-item label="æ£æµåä½" |
| | | prop="checkCompany" |
| | |
| | | <up-input v-model="form.checkCompany" |
| | | placeholder="请è¾å
¥æ£æµåä½" |
| | | clearable /> |
| | | </up-form-item> |
| | | <up-form-item label="æ£æµç»æ" |
| | | prop="checkResult" |
| | | required |
| | | border-bottom> |
| | | <up-input v-model="form.checkResult" |
| | | placeholder="è¯·éæ©æ£æµç»æ" |
| | | readonly |
| | | @click="showResultSheet" /> |
| | | <template #right> |
| | | <up-icon @click="showResultSheet = true" |
| | | name="arrow-right" /> |
| | | </template> |
| | | </up-form-item> |
| | | <up-form-item label="æ£éªå" |
| | | prop="checkName" |
| | |
| | | @select="selectModel" |
| | | @close="showModelSheet = false" |
| | | title="éæ©è§æ ¼åå·" /> |
| | | <!-- æ£æµç»æéæ© --> |
| | | <up-action-sheet :show="showResultSheet" |
| | | :actions="resultSheetOptions" |
| | | @select="selectResult" |
| | | @close="showResultSheet = false" |
| | | title="éæ©æ£æµç»æ" /> |
| | | <!-- æ£éªåéæ© --> |
| | | <up-action-sheet :show="showInspectorSheet" |
| | | :actions="userSheetOptions" |
| | |
| | | const showProductTree = ref(false); |
| | | // è§æ ¼åå·éæ© |
| | | const showModelSheet = ref(false); |
| | | // æ£æµç»æéæ© |
| | | const showResultSheet = ref(false); |
| | | // æ£éªåéæ© |
| | | const showInspectorSheet = ref(false); |
| | | // ææ éæ© |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | qualifiedQuantity: "", |
| | | unqualifiedQuantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | productMainId: null, |
| | | purchaseLedgerId: null, |
| | | }); |
| | |
| | | const modelOptions = ref([]); |
| | | // æ£éªåå表 |
| | | const userList = ref([]); |
| | | // æ£æµç»æé项 |
| | | const resultOptions = ref([ |
| | | { label: "åæ ¼", value: "åæ ¼" }, |
| | | { label: "ä¸åæ ¼", value: "ä¸åæ ¼" }, |
| | | ]); |
| | | // ææ é项 |
| | | const testStandardOptions = ref([]); |
| | | // å½å产åID |
| | |
| | | return modelOptions.value.map(item => ({ |
| | | name: item.model, |
| | | value: item.id, |
| | | })); |
| | | }); |
| | | |
| | | const resultSheetOptions = computed(() => { |
| | | return resultOptions.value.map(item => ({ |
| | | name: item.label, |
| | | value: item.value, |
| | | })); |
| | | }); |
| | | |
| | |
| | | ], |
| | | unit: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | checkCompany: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | checkResult: [ |
| | | { required: true, message: "è¯·éæ©æ£æµç»æ", trigger: "change" }, |
| | | qualifiedQuantity: [ |
| | | { required: true, message: "请è¾å
¥åæ ¼æ°é", trigger: "blur" }, |
| | | ], |
| | | unqualifiedQuantity: [ |
| | | { required: true, message: "请è¾å
¥ä¸åæ ¼æ°é", trigger: "blur" }, |
| | | ], |
| | | checkCompany: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | }; |
| | | |
| | | // æ¯å¦ä¸ºç¼è¾æ¨¡å¼ |
| | |
| | | modelOptions.value.find(item => item.id == value)?.model || ""; |
| | | form.value.unit = |
| | | modelOptions.value.find(item => item.id == value)?.unit || ""; |
| | | }; |
| | | |
| | | // éæ©æ£æµç»æ |
| | | const selectResult = e => { |
| | | form.value.checkResult = e.value; |
| | | showResultSheet.value = false; |
| | | }; |
| | | |
| | | // éæ©æ£éªå |
| | |
| | | // showToast("è¯·éæ©å·¥åº"); |
| | | // return; |
| | | // } |
| | | if (!form.value.quantity) { |
| | | showToast("请è¾å
¥æ°é"); |
| | | if (!form.value.quantity && form.value.quantity !== 0) { |
| | | showToast("请è¾å
¥æ»æ°é"); |
| | | return; |
| | | } |
| | | if ( |
| | | form.value.qualifiedQuantity === "" || |
| | | form.value.qualifiedQuantity === undefined |
| | | ) { |
| | | showToast("请è¾å
¥åæ ¼æ°é"); |
| | | return; |
| | | } |
| | | if ( |
| | | form.value.unqualifiedQuantity === "" || |
| | | form.value.unqualifiedQuantity === undefined |
| | | ) { |
| | | showToast("请è¾å
¥ä¸åæ ¼æ°é"); |
| | | return; |
| | | } |
| | | const qty = Number(form.value.quantity); |
| | | const qf = Number(form.value.qualifiedQuantity); |
| | | const uq = Number(form.value.unqualifiedQuantity); |
| | | if (Number.isNaN(qty) || qty < 0) { |
| | | showToast("æ»æ°éæ ¼å¼ä¸æ£ç¡®"); |
| | | return; |
| | | } |
| | | if (Number.isNaN(qf) || qf < 0 || Number.isNaN(uq) || uq < 0) { |
| | | showToast("åæ ¼/ä¸åæ ¼æ°éæ ¼å¼ä¸æ£ç¡®"); |
| | | return; |
| | | } |
| | | if (qf + uq !== qty) { |
| | | showToast("åæ ¼æ°éä¸ä¸åæ ¼æ°éä¹åé¡»çäºæ»æ°é"); |
| | | return; |
| | | } |
| | | if (!form.value.productId) { |
| | | showToast("è¯·éæ©äº§å"); |
| | | return; |
| | | } |
| | | if (!form.value.checkResult) { |
| | | showToast("è¯·éæ©æ£æµç»æ"); |
| | | return; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | const data = { ...form.value, qualityInspectParams: tableData.value }; |
| | | data.quantity = Number(data.quantity); |
| | | data.quantity = qty; |
| | | data.qualifiedQuantity = qf; |
| | | data.unqualifiedQuantity = uq; |
| | | if (isEdit.value) { |
| | | const res = await qualityInspectUpdate(data); |
| | | showToast("ä¿åæå"); |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | qualifiedQuantity: "", |
| | | unqualifiedQuantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | productMainId: null, |
| | | purchaseLedgerId: null, |
| | | }; |
| | |
| | | testStandardId: "1", |
| | | unit: "kg", |
| | | quantity: 1000, |
| | | qualifiedQuantity: 1000, |
| | | unqualifiedQuantity: 0, |
| | | checkCompany: "ç¬¬ä¸æ¹æ£æµæºæ", |
| | | checkResult: "åæ ¼", |
| | | productMainId: null, |
| | | purchaseLedgerId: null, |
| | | }; |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | qualifiedQuantity: "", |
| | | unqualifiedQuantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | productMainId: null, |
| | | purchaseLedgerId: null, |
| | | }; |
| | |
| | | </view> |
| | | <text class="header-title">{{ detailData.productName || '-' }}</text> |
| | | <view class="status-tags"> |
| | | <u-tag :type="getTagType(detailData.checkResult)" |
| | | <u-tag :type="getPassRateTagType(detailData.passRate)" |
| | | size="small" |
| | | class="status-tag"> |
| | | {{ detailData.checkResult || '-' }} |
| | | åæ ¼ç {{ formatPassRate(detailData.passRate) }} |
| | | </u-tag> |
| | | <u-tag :type="getStateTagType(detailData.inspectState)" |
| | | size="small" |
| | |
| | | <text class="detail-value">{{ detailData.unit || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ°é</text> |
| | | <text class="detail-value">{{ detailData.quantity || 0 }}</text> |
| | | <text class="detail-label">æ»æ°é</text> |
| | | <text class="detail-value">{{ detailData.quantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åæ ¼æ°é</text> |
| | | <text class="detail-value">{{ detailData.qualifiedQuantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¸åæ ¼æ°é</text> |
| | | <text class="detail-value">{{ detailData.unqualifiedQuantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åæ ¼ç</text> |
| | | <text class="detail-value">{{ formatPassRate(detailData.passRate) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ£æµåä½</text> |
| | |
| | | return dayjs(date).format("YYYY-MM-DD"); |
| | | }; |
| | | |
| | | // è·åæ ç¾ç±»å |
| | | const getTagType = result => { |
| | | switch (result) { |
| | | case "åæ ¼": |
| | | return "success"; |
| | | case "ä¸åæ ¼": |
| | | return "error"; |
| | | default: |
| | | return "info"; |
| | | } |
| | | const formatPassRate = val => { |
| | | if (val === null || val === undefined || val === "") return "-"; |
| | | const n = Number(val); |
| | | if (Number.isNaN(n)) return String(val); |
| | | if (n > 0 && n <= 1) return `${(n * 100).toFixed(1)}%`; |
| | | return `${Number.isInteger(n) ? n : Number(n.toFixed(1))}%`; |
| | | }; |
| | | |
| | | const getPassRateTagType = val => { |
| | | if (val === null || val === undefined || val === "") return "info"; |
| | | let n = Number(val); |
| | | if (Number.isNaN(n)) return "info"; |
| | | if (n > 0 && n <= 1) n *= 100; |
| | | if (n >= 100) return "success"; |
| | | if (n >= 60) return "warning"; |
| | | return "error"; |
| | | }; |
| | | |
| | | // è·åç¶ææ ç¾ç±»å |
| | |
| | | </view> |
| | | </view> |
| | | <view class="status-tags"> |
| | | <u-tag :type="getTagType(item.checkResult)" |
| | | v-if="item.checkResult!=null" |
| | | <u-tag :type="getPassRateTagType(item.passRate)" |
| | | v-if="item.passRate != null && item.passRate !== ''" |
| | | size="mini" |
| | | class="status-tag"> |
| | | {{ item.checkResult }} |
| | | {{ formatPassRate(item.passRate) }} |
| | | </u-tag> |
| | | <u-tag :type="getStateTagType(item.inspectState)" |
| | | size="mini" |
| | |
| | | <text class="detail-value">{{ item.checkName || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ°é</text> |
| | | <text class="detail-label">æ»æ°é</text> |
| | | <text class="detail-value">{{ item.quantity || 0 }} {{ item.unit || '' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åæ ¼æ°é</text> |
| | | <text class="detail-value">{{ item.qualifiedQuantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¸åæ ¼æ°é</text> |
| | | <text class="detail-value">{{ item.unqualifiedQuantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ£æµåä½</text> |
| | |
| | | return inspectState ? "checkmark-circle" : "time"; |
| | | }; |
| | | |
| | | // è·åæ ç¾ç±»å |
| | | const getTagType = checkResult => { |
| | | if (checkResult === "åæ ¼") return "success"; |
| | | if (checkResult === "ä¸åæ ¼") return "error"; |
| | | return "default"; |
| | | const formatPassRate = val => { |
| | | if (val === null || val === undefined || val === "") return "-"; |
| | | const n = Number(val); |
| | | if (Number.isNaN(n)) return String(val); |
| | | if (n > 0 && n <= 1) return `${(n * 100).toFixed(1)}%`; |
| | | return `${Number.isInteger(n) ? n : Number(n.toFixed(1))}%`; |
| | | }; |
| | | |
| | | const getPassRateTagType = val => { |
| | | if (val === null || val === undefined || val === "") return "default"; |
| | | let n = Number(val); |
| | | if (Number.isNaN(n)) return "default"; |
| | | if (n > 0 && n <= 1) n *= 100; |
| | | if (n >= 100) return "success"; |
| | | if (n >= 60) return "warning"; |
| | | return "error"; |
| | | }; |
| | | |
| | | const isFullPassByPassRate = item => { |
| | | const v = item.passRate; |
| | | if (v === null || v === undefined || v === "") return false; |
| | | const n = Number(v); |
| | | if (Number.isNaN(n)) return false; |
| | | if (n > 0 && n <= 1) return n >= 1; |
| | | return n >= 100; |
| | | }; |
| | | |
| | | // è·åç¶ææ ç¾ç±»å |
| | |
| | | item => !item.inspectState |
| | | ).length; |
| | | qualifiedCount.value = inspectionList.value.filter( |
| | | item => item.checkResult === "åæ ¼" |
| | | isFullPassByPassRate |
| | | ).length; |
| | | }) |
| | | .catch(err => { |
| | |
| | | placeholder="请è¾å
¥åä½" |
| | | disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="æ°é" |
| | | <up-form-item label="æ»æ°é" |
| | | prop="quantity" |
| | | required |
| | | border-bottom> |
| | | <up-input v-model="form.quantity" |
| | | type="number" |
| | | placeholder="请è¾å
¥æ°é" |
| | | placeholder="请è¾å
¥æ»æ°é" |
| | | :disabled="supplierQuantityDisabled" /> |
| | | </up-form-item> |
| | | <up-form-item label="åæ ¼æ°é" |
| | | prop="qualifiedQuantity" |
| | | required |
| | | border-bottom> |
| | | <up-input v-model="form.qualifiedQuantity" |
| | | type="number" |
| | | placeholder="请è¾å
¥åæ ¼æ°é" |
| | | clearable /> |
| | | </up-form-item> |
| | | <up-form-item label="ä¸åæ ¼æ°é" |
| | | prop="unqualifiedQuantity" |
| | | required |
| | | border-bottom> |
| | | <up-input v-model="form.unqualifiedQuantity" |
| | | type="number" |
| | | placeholder="请è¾å
¥ä¸åæ ¼æ°é" |
| | | clearable /> |
| | | </up-form-item> |
| | | <up-form-item label="æ£æµåä½" |
| | | prop="checkCompany" |
| | |
| | | <up-input v-model="form.checkCompany" |
| | | placeholder="请è¾å
¥æ£æµåä½" |
| | | clearable /> |
| | | </up-form-item> |
| | | <up-form-item label="æ£æµç»æ" |
| | | prop="checkResult" |
| | | required |
| | | border-bottom> |
| | | <up-input v-model="form.checkResult" |
| | | placeholder="è¯·éæ©æ£æµç»æ" |
| | | readonly |
| | | @click="showResultSheet" /> |
| | | <template #right> |
| | | <up-icon @click="showResultSheet = true" |
| | | name="arrow-right" /> |
| | | </template> |
| | | </up-form-item> |
| | | <up-form-item label="æ£éªå" |
| | | prop="checkName" |
| | |
| | | @select="selectModel" |
| | | @close="showModelSheet = false" |
| | | title="éæ©è§æ ¼åå·" /> |
| | | <!-- æ£æµç»æéæ© --> |
| | | <up-action-sheet :show="showResultSheet" |
| | | :actions="resultSheetOptions" |
| | | @select="selectResult" |
| | | @close="showResultSheet = false" |
| | | title="éæ©æ£æµç»æ" /> |
| | | <!-- æ£éªåéæ© --> |
| | | <up-action-sheet :show="showInspectorSheet" |
| | | :actions="userSheetOptions" |
| | |
| | | const showProductTree = ref(false); |
| | | // è§æ ¼åå·éæ© |
| | | const showModelSheet = ref(false); |
| | | // æ£æµç»æéæ© |
| | | const showResultSheet = ref(false); |
| | | // æ£éªåéæ© |
| | | const showInspectorSheet = ref(false); |
| | | // ææ éæ© |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | qualifiedQuantity: "", |
| | | unqualifiedQuantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | productMainId: null, |
| | | purchaseLedgerId: null, |
| | | }); |
| | |
| | | const modelOptions = ref([]); |
| | | // æ£éªåå表 |
| | | const userList = ref([]); |
| | | // æ£æµç»æé项 |
| | | const resultOptions = ref([ |
| | | { label: "åæ ¼", value: "åæ ¼" }, |
| | | { label: "ä¸åæ ¼", value: "ä¸åæ ¼" }, |
| | | ]); |
| | | // ææ é项 |
| | | const testStandardOptions = ref([]); |
| | | // å½å产åID |
| | |
| | | return modelOptions.value.map(item => ({ |
| | | name: item.model, |
| | | value: item.id, |
| | | })); |
| | | }); |
| | | |
| | | const resultSheetOptions = computed(() => { |
| | | return resultOptions.value.map(item => ({ |
| | | name: item.label, |
| | | value: item.value, |
| | | })); |
| | | }); |
| | | |
| | |
| | | ], |
| | | unit: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | checkCompany: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | checkResult: [ |
| | | { required: true, message: "è¯·éæ©æ£æµç»æ", trigger: "change" }, |
| | | qualifiedQuantity: [ |
| | | { required: true, message: "请è¾å
¥åæ ¼æ°é", trigger: "blur" }, |
| | | ], |
| | | unqualifiedQuantity: [ |
| | | { required: true, message: "请è¾å
¥ä¸åæ ¼æ°é", trigger: "blur" }, |
| | | ], |
| | | checkCompany: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | }; |
| | | |
| | | // æ¯å¦ä¸ºç¼è¾æ¨¡å¼ |
| | |
| | | modelOptions.value.find(item => item.id == value)?.model || ""; |
| | | form.value.unit = |
| | | modelOptions.value.find(item => item.id == value)?.unit || ""; |
| | | }; |
| | | |
| | | // éæ©æ£æµç»æ |
| | | const selectResult = e => { |
| | | form.value.checkResult = e.value; |
| | | showResultSheet.value = false; |
| | | }; |
| | | |
| | | // éæ©æ£éªå |
| | |
| | | showToast("è¯·éæ©ä¾åºå"); |
| | | return; |
| | | } |
| | | if (!form.value.quantity) { |
| | | showToast("请è¾å
¥æ°é"); |
| | | if (!form.value.quantity && form.value.quantity !== 0) { |
| | | showToast("请è¾å
¥æ»æ°é"); |
| | | return; |
| | | } |
| | | if ( |
| | | form.value.qualifiedQuantity === "" || |
| | | form.value.qualifiedQuantity === undefined |
| | | ) { |
| | | showToast("请è¾å
¥åæ ¼æ°é"); |
| | | return; |
| | | } |
| | | if ( |
| | | form.value.unqualifiedQuantity === "" || |
| | | form.value.unqualifiedQuantity === undefined |
| | | ) { |
| | | showToast("请è¾å
¥ä¸åæ ¼æ°é"); |
| | | return; |
| | | } |
| | | const qty = Number(form.value.quantity); |
| | | const qf = Number(form.value.qualifiedQuantity); |
| | | const uq = Number(form.value.unqualifiedQuantity); |
| | | if (Number.isNaN(qty) || qty < 0) { |
| | | showToast("æ»æ°éæ ¼å¼ä¸æ£ç¡®"); |
| | | return; |
| | | } |
| | | if (Number.isNaN(qf) || qf < 0 || Number.isNaN(uq) || uq < 0) { |
| | | showToast("åæ ¼/ä¸åæ ¼æ°éæ ¼å¼ä¸æ£ç¡®"); |
| | | return; |
| | | } |
| | | if (qf + uq !== qty) { |
| | | showToast("åæ ¼æ°éä¸ä¸åæ ¼æ°éä¹åé¡»çäºæ»æ°é"); |
| | | return; |
| | | } |
| | | if (!form.value.productId) { |
| | | showToast("è¯·éæ©äº§å"); |
| | | return; |
| | | } |
| | | if (!form.value.checkResult) { |
| | | showToast("è¯·éæ©æ£æµç»æ"); |
| | | return; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | const data = { ...form.value, qualityInspectParams: tableData.value }; |
| | | data.quantity = Number(data.quantity); |
| | | data.quantity = qty; |
| | | data.qualifiedQuantity = qf; |
| | | data.unqualifiedQuantity = uq; |
| | | if (isEdit.value) { |
| | | const res = await qualityInspectUpdate(data); |
| | | showToast("ä¿åæå"); |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | qualifiedQuantity: "", |
| | | unqualifiedQuantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | productMainId: null, |
| | | purchaseLedgerId: null, |
| | | }; |
| | |
| | | testStandardId: "1", |
| | | unit: "kg", |
| | | quantity: 1000, |
| | | qualifiedQuantity: 1000, |
| | | unqualifiedQuantity: 0, |
| | | checkCompany: "ç¬¬ä¸æ¹æ£æµæºæ", |
| | | checkResult: "åæ ¼", |
| | | productMainId: null, |
| | | purchaseLedgerId: null, |
| | | }; |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | qualifiedQuantity: "", |
| | | unqualifiedQuantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | productMainId: null, |
| | | purchaseLedgerId: null, |
| | | }; |
| | |
| | | </view> |
| | | <text class="header-title">{{ detailData.productName || '-' }}</text> |
| | | <view class="status-tags"> |
| | | <u-tag :type="getTagType(detailData.checkResult)" |
| | | <u-tag :type="getPassRateTagType(detailData.passRate)" |
| | | size="small" |
| | | class="status-tag"> |
| | | {{ detailData.checkResult || '-' }} |
| | | åæ ¼ç {{ formatPassRate(detailData.passRate) }} |
| | | </u-tag> |
| | | <u-tag :type="getStateTagType(detailData.inspectState)" |
| | | size="small" |
| | |
| | | <text class="detail-value">{{ detailData.unit || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ°é</text> |
| | | <text class="detail-value">{{ detailData.quantity || 0 }}</text> |
| | | <text class="detail-label">æ»æ°é</text> |
| | | <text class="detail-value">{{ detailData.quantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åæ ¼æ°é</text> |
| | | <text class="detail-value">{{ detailData.qualifiedQuantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¸åæ ¼æ°é</text> |
| | | <text class="detail-value">{{ detailData.unqualifiedQuantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åæ ¼ç</text> |
| | | <text class="detail-value">{{ formatPassRate(detailData.passRate) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ£æµåä½</text> |
| | |
| | | return dayjs(date).format("YYYY-MM-DD"); |
| | | }; |
| | | |
| | | // è·åæ ç¾ç±»å |
| | | const getTagType = result => { |
| | | switch (result) { |
| | | case "åæ ¼": |
| | | return "success"; |
| | | case "ä¸åæ ¼": |
| | | return "error"; |
| | | default: |
| | | return "info"; |
| | | } |
| | | // æ ¼å¼ååæ ¼çï¼æ¯æ 0â1 å°æ°æç¾åæ°ï¼ |
| | | const formatPassRate = val => { |
| | | if (val === null || val === undefined || val === "") return "-"; |
| | | const n = Number(val); |
| | | if (Number.isNaN(n)) return String(val); |
| | | if (n > 0 && n <= 1) return `${(n * 100).toFixed(1)}%`; |
| | | return `${Number.isInteger(n) ? n : Number(n.toFixed(1))}%`; |
| | | }; |
| | | |
| | | const getPassRateTagType = val => { |
| | | if (val === null || val === undefined || val === "") return "info"; |
| | | let n = Number(val); |
| | | if (Number.isNaN(n)) return "info"; |
| | | if (n > 0 && n <= 1) n *= 100; |
| | | if (n >= 100) return "success"; |
| | | if (n >= 60) return "warning"; |
| | | return "error"; |
| | | }; |
| | | |
| | | // è·åç¶ææ ç¾ç±»å |
| | |
| | | </view> |
| | | </view> |
| | | <view class="status-tags"> |
| | | <u-tag :type="getTagType(item.checkResult)" |
| | | v-if="item.checkResult!=null" |
| | | <u-tag :type="getPassRateTagType(item.passRate)" |
| | | v-if="item.passRate != null && item.passRate !== ''" |
| | | size="mini" |
| | | class="status-tag"> |
| | | {{ item.checkResult }} |
| | | {{ formatPassRate(item.passRate) }} |
| | | </u-tag> |
| | | <u-tag :type="getStateTagType(item.inspectState)" |
| | | size="mini" |
| | |
| | | <text class="detail-value">{{ item.checkName || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ°é</text> |
| | | <text class="detail-label">æ»æ°é</text> |
| | | <text class="detail-value">{{ item.quantity || 0 }} {{ item.unit || '' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åæ ¼æ°é</text> |
| | | <text class="detail-value">{{ item.qualifiedQuantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¸åæ ¼æ°é</text> |
| | | <text class="detail-value">{{ item.unqualifiedQuantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ£æµåä½</text> |
| | |
| | | return inspectState ? "checkmark-circle" : "time"; |
| | | }; |
| | | |
| | | // è·åæ ç¾ç±»å |
| | | const getTagType = checkResult => { |
| | | if (checkResult === "åæ ¼") return "success"; |
| | | if (checkResult === "ä¸åæ ¼") return "error"; |
| | | return "default"; |
| | | const formatPassRate = val => { |
| | | if (val === null || val === undefined || val === "") return "-"; |
| | | const n = Number(val); |
| | | if (Number.isNaN(n)) return String(val); |
| | | if (n > 0 && n <= 1) return `${(n * 100).toFixed(1)}%`; |
| | | return `${Number.isInteger(n) ? n : Number(n.toFixed(1))}%`; |
| | | }; |
| | | |
| | | const getPassRateTagType = val => { |
| | | if (val === null || val === undefined || val === "") return "default"; |
| | | let n = Number(val); |
| | | if (Number.isNaN(n)) return "default"; |
| | | if (n > 0 && n <= 1) n *= 100; |
| | | if (n >= 100) return "success"; |
| | | if (n >= 60) return "warning"; |
| | | return "error"; |
| | | }; |
| | | |
| | | const isFullPassByPassRate = item => { |
| | | const v = item.passRate; |
| | | if (v === null || v === undefined || v === "") return false; |
| | | const n = Number(v); |
| | | if (Number.isNaN(n)) return false; |
| | | if (n > 0 && n <= 1) return n >= 1; |
| | | return n >= 100; |
| | | }; |
| | | |
| | | // è·åç¶ææ ç¾ç±»å |
| | |
| | | item => !item.inspectState |
| | | ).length; |
| | | qualifiedCount.value = inspectionList.value.filter( |
| | | item => item.checkResult === "åæ ¼" |
| | | isFullPassByPassRate |
| | | ).length; |
| | | }) |
| | | .catch(err => { |
| | |
| | | placeholder="请è¾å
¥åä½" |
| | | disabled /> |
| | | </up-form-item> |
| | | <up-form-item label="æ°é" |
| | | <up-form-item label="æ»æ°é" |
| | | prop="quantity" |
| | | required |
| | | border-bottom> |
| | | <up-input v-model="form.quantity" |
| | | type="number" |
| | | placeholder="请è¾å
¥æ°é" |
| | | placeholder="请è¾å
¥æ»æ°é" |
| | | :disabled="processQuantityDisabled" /> |
| | | </up-form-item> |
| | | <up-form-item label="åæ ¼æ°é" |
| | | prop="qualifiedQuantity" |
| | | required |
| | | border-bottom> |
| | | <up-input v-model="form.qualifiedQuantity" |
| | | type="number" |
| | | placeholder="请è¾å
¥åæ ¼æ°é" |
| | | clearable /> |
| | | </up-form-item> |
| | | <up-form-item label="ä¸åæ ¼æ°é" |
| | | prop="unqualifiedQuantity" |
| | | required |
| | | border-bottom> |
| | | <up-input v-model="form.unqualifiedQuantity" |
| | | type="number" |
| | | placeholder="请è¾å
¥ä¸åæ ¼æ°é" |
| | | clearable /> |
| | | </up-form-item> |
| | | <up-form-item label="æ£æµåä½" |
| | | prop="checkCompany" |
| | |
| | | <up-input v-model="form.checkCompany" |
| | | placeholder="请è¾å
¥æ£æµåä½" |
| | | clearable /> |
| | | </up-form-item> |
| | | <up-form-item label="æ£æµç»æ" |
| | | prop="checkResult" |
| | | required |
| | | border-bottom> |
| | | <up-input v-model="form.checkResult" |
| | | placeholder="è¯·éæ©æ£æµç»æ" |
| | | readonly |
| | | @click="showResultSheet" /> |
| | | <template #right> |
| | | <up-icon @click="showResultSheet = true" |
| | | name="arrow-right" /> |
| | | </template> |
| | | </up-form-item> |
| | | <up-form-item label="æ£éªå" |
| | | prop="checkName" |
| | |
| | | @select="selectModel" |
| | | @close="showModelSheet = false" |
| | | title="éæ©è§æ ¼åå·" /> |
| | | <!-- æ£æµç»æéæ© --> |
| | | <up-action-sheet :show="showResultSheet" |
| | | :actions="resultSheetOptions" |
| | | @select="selectResult" |
| | | @close="showResultSheet = false" |
| | | title="éæ©æ£æµç»æ" /> |
| | | <!-- æ£éªåéæ© --> |
| | | <up-action-sheet :show="showInspectorSheet" |
| | | :actions="userSheetOptions" |
| | |
| | | const showProductTree = ref(false); |
| | | // è§æ ¼åå·éæ© |
| | | const showModelSheet = ref(false); |
| | | // æ£æµç»æéæ© |
| | | const showResultSheet = ref(false); |
| | | // æ£éªåéæ© |
| | | const showInspectorSheet = ref(false); |
| | | // ææ éæ© |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | qualifiedQuantity: "", |
| | | unqualifiedQuantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | productMainId: null, |
| | | purchaseLedgerId: null, |
| | | }); |
| | |
| | | const modelOptions = ref([]); |
| | | // æ£éªåå表 |
| | | const userList = ref([]); |
| | | // æ£æµç»æé项 |
| | | const resultOptions = ref([ |
| | | { label: "åæ ¼", value: "åæ ¼" }, |
| | | { label: "ä¸åæ ¼", value: "ä¸åæ ¼" }, |
| | | ]); |
| | | // ææ é项 |
| | | const testStandardOptions = ref([]); |
| | | // å½å产åID |
| | |
| | | return modelOptions.value.map(item => ({ |
| | | name: item.model, |
| | | value: item.id, |
| | | })); |
| | | }); |
| | | |
| | | const resultSheetOptions = computed(() => { |
| | | return resultOptions.value.map(item => ({ |
| | | name: item.label, |
| | | value: item.value, |
| | | })); |
| | | }); |
| | | |
| | |
| | | ], |
| | | unit: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | checkCompany: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | checkResult: [ |
| | | { required: true, message: "è¯·éæ©æ£æµç»æ", trigger: "change" }, |
| | | qualifiedQuantity: [ |
| | | { required: true, message: "请è¾å
¥åæ ¼æ°é", trigger: "blur" }, |
| | | ], |
| | | unqualifiedQuantity: [ |
| | | { required: true, message: "请è¾å
¥ä¸åæ ¼æ°é", trigger: "blur" }, |
| | | ], |
| | | checkCompany: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | }; |
| | | |
| | | // æ¯å¦ä¸ºç¼è¾æ¨¡å¼ |
| | |
| | | modelOptions.value.find(item => item.id == value)?.model || ""; |
| | | form.value.unit = |
| | | modelOptions.value.find(item => item.id == value)?.unit || ""; |
| | | }; |
| | | |
| | | // éæ©æ£æµç»æ |
| | | const selectResult = e => { |
| | | form.value.checkResult = e.value; |
| | | showResultSheet.value = false; |
| | | }; |
| | | |
| | | // éæ©æ£éªå |
| | |
| | | showToast("è¯·éæ©å·¥åº"); |
| | | return; |
| | | } |
| | | if (!form.value.quantity) { |
| | | showToast("请è¾å
¥æ°é"); |
| | | if (!form.value.quantity && form.value.quantity !== 0) { |
| | | showToast("请è¾å
¥æ»æ°é"); |
| | | return; |
| | | } |
| | | if ( |
| | | form.value.qualifiedQuantity === "" || |
| | | form.value.qualifiedQuantity === undefined |
| | | ) { |
| | | showToast("请è¾å
¥åæ ¼æ°é"); |
| | | return; |
| | | } |
| | | if ( |
| | | form.value.unqualifiedQuantity === "" || |
| | | form.value.unqualifiedQuantity === undefined |
| | | ) { |
| | | showToast("请è¾å
¥ä¸åæ ¼æ°é"); |
| | | return; |
| | | } |
| | | const qty = Number(form.value.quantity); |
| | | const qf = Number(form.value.qualifiedQuantity); |
| | | const uq = Number(form.value.unqualifiedQuantity); |
| | | if (Number.isNaN(qty) || qty < 0) { |
| | | showToast("æ»æ°éæ ¼å¼ä¸æ£ç¡®"); |
| | | return; |
| | | } |
| | | if (Number.isNaN(qf) || qf < 0 || Number.isNaN(uq) || uq < 0) { |
| | | showToast("åæ ¼/ä¸åæ ¼æ°éæ ¼å¼ä¸æ£ç¡®"); |
| | | return; |
| | | } |
| | | if (qf + uq !== qty) { |
| | | showToast("åæ ¼æ°éä¸ä¸åæ ¼æ°éä¹åé¡»çäºæ»æ°é"); |
| | | return; |
| | | } |
| | | if (!form.value.productId) { |
| | | showToast("è¯·éæ©äº§å"); |
| | | return; |
| | | } |
| | | if (!form.value.checkResult) { |
| | | showToast("è¯·éæ©æ£æµç»æ"); |
| | | return; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | const data = { ...form.value, qualityInspectParams: tableData.value }; |
| | | data.quantity = Number(data.quantity); |
| | | data.quantity = qty; |
| | | data.qualifiedQuantity = qf; |
| | | data.unqualifiedQuantity = uq; |
| | | if (isEdit.value) { |
| | | const res = await qualityInspectUpdate(data); |
| | | showToast("ä¿åæå"); |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | qualifiedQuantity: "", |
| | | unqualifiedQuantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | productMainId: null, |
| | | purchaseLedgerId: null, |
| | | }; |
| | |
| | | testStandardId: "1", |
| | | unit: "kg", |
| | | quantity: 1000, |
| | | qualifiedQuantity: 1000, |
| | | unqualifiedQuantity: 0, |
| | | checkCompany: "ç¬¬ä¸æ¹æ£æµæºæ", |
| | | checkResult: "åæ ¼", |
| | | productMainId: null, |
| | | purchaseLedgerId: null, |
| | | }; |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | qualifiedQuantity: "", |
| | | unqualifiedQuantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | productMainId: null, |
| | | purchaseLedgerId: null, |
| | | }; |
| | |
| | | </view> |
| | | <text class="header-title">{{ detailData.productName || '-' }}</text> |
| | | <view class="status-tags"> |
| | | <u-tag :type="getTagType(detailData.checkResult)" |
| | | <u-tag :type="getPassRateTagType(detailData.passRate)" |
| | | size="small" |
| | | class="status-tag"> |
| | | {{ detailData.checkResult || '-' }} |
| | | åæ ¼ç {{ formatPassRate(detailData.passRate) }} |
| | | </u-tag> |
| | | <u-tag :type="getStateTagType(detailData.inspectState)" |
| | | size="small" |
| | |
| | | <text class="detail-value">{{ detailData.unit || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ°é</text> |
| | | <text class="detail-value">{{ detailData.quantity || 0 }}</text> |
| | | <text class="detail-label">æ»æ°é</text> |
| | | <text class="detail-value">{{ detailData.quantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åæ ¼æ°é</text> |
| | | <text class="detail-value">{{ detailData.qualifiedQuantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¸åæ ¼æ°é</text> |
| | | <text class="detail-value">{{ detailData.unqualifiedQuantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åæ ¼ç</text> |
| | | <text class="detail-value">{{ formatPassRate(detailData.passRate) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ£æµåä½</text> |
| | |
| | | return dayjs(date).format("YYYY-MM-DD"); |
| | | }; |
| | | |
| | | // è·åæ ç¾ç±»å |
| | | const getTagType = result => { |
| | | switch (result) { |
| | | case "åæ ¼": |
| | | return "success"; |
| | | case "ä¸åæ ¼": |
| | | return "error"; |
| | | default: |
| | | return "info"; |
| | | } |
| | | const formatPassRate = val => { |
| | | if (val === null || val === undefined || val === "") return "-"; |
| | | const n = Number(val); |
| | | if (Number.isNaN(n)) return String(val); |
| | | if (n > 0 && n <= 1) return `${(n * 100).toFixed(1)}%`; |
| | | return `${Number.isInteger(n) ? n : Number(n.toFixed(1))}%`; |
| | | }; |
| | | |
| | | const getPassRateTagType = val => { |
| | | if (val === null || val === undefined || val === "") return "info"; |
| | | let n = Number(val); |
| | | if (Number.isNaN(n)) return "info"; |
| | | if (n > 0 && n <= 1) n *= 100; |
| | | if (n >= 100) return "success"; |
| | | if (n >= 60) return "warning"; |
| | | return "error"; |
| | | }; |
| | | |
| | | // è·åç¶ææ ç¾ç±»å |
| | |
| | | </view> |
| | | </view> |
| | | <view class="status-tags"> |
| | | <u-tag :type="getTagType(item.checkResult)" |
| | | v-if="item.checkResult!=null" |
| | | <u-tag :type="getPassRateTagType(item.passRate)" |
| | | v-if="item.passRate != null && item.passRate !== ''" |
| | | size="mini" |
| | | class="status-tag"> |
| | | {{ item.checkResult }} |
| | | {{ formatPassRate(item.passRate) }} |
| | | </u-tag> |
| | | <u-tag :type="getStateTagType(item.inspectState)" |
| | | size="mini" |
| | |
| | | <text class="detail-value">{{ item.checkName || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ°é</text> |
| | | <text class="detail-label">æ»æ°é</text> |
| | | <text class="detail-value">{{ item.quantity || 0 }} {{ item.unit || '' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åæ ¼æ°é</text> |
| | | <text class="detail-value">{{ item.qualifiedQuantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¸åæ ¼æ°é</text> |
| | | <text class="detail-value">{{ item.unqualifiedQuantity ?? '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ£æµåä½</text> |
| | |
| | | return inspectState ? "checkmark-circle" : "time"; |
| | | }; |
| | | |
| | | // è·åæ ç¾ç±»å |
| | | const getTagType = checkResult => { |
| | | if (checkResult === "åæ ¼") return "success"; |
| | | if (checkResult === "ä¸åæ ¼") return "error"; |
| | | return "default"; |
| | | const formatPassRate = val => { |
| | | if (val === null || val === undefined || val === "") return "-"; |
| | | const n = Number(val); |
| | | if (Number.isNaN(n)) return String(val); |
| | | if (n > 0 && n <= 1) return `${(n * 100).toFixed(1)}%`; |
| | | return `${Number.isInteger(n) ? n : Number(n.toFixed(1))}%`; |
| | | }; |
| | | |
| | | const getPassRateTagType = val => { |
| | | if (val === null || val === undefined || val === "") return "default"; |
| | | let n = Number(val); |
| | | if (Number.isNaN(n)) return "default"; |
| | | if (n > 0 && n <= 1) n *= 100; |
| | | if (n >= 100) return "success"; |
| | | if (n >= 60) return "warning"; |
| | | return "error"; |
| | | }; |
| | | |
| | | const isFullPassByPassRate = item => { |
| | | const v = item.passRate; |
| | | if (v === null || v === undefined || v === "") return false; |
| | | const n = Number(v); |
| | | if (Number.isNaN(n)) return false; |
| | | if (n > 0 && n <= 1) return n >= 1; |
| | | return n >= 100; |
| | | }; |
| | | |
| | | // è·åç¶ææ ç¾ç±»å |
| | |
| | | item => !item.inspectState |
| | | ).length; |
| | | qualifiedCount.value = inspectionList.value.filter( |
| | | item => item.checkResult === "åæ ¼" |
| | | isFullPassByPassRate |
| | | ).length; |
| | | }) |
| | | .catch(err => { |