| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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> |