| | |
| | | count |
| | | maxlength="200" /> |
| | | </u-form-item> |
| | | <u-form-item label="故障图片" |
| | | border-bottom> |
| | | <view class="repair-image-upload"> |
| | | <u-button type="primary" |
| | | @click="chooseRepairImage" |
| | | :loading="uploading" |
| | | :disabled="uploading"> |
| | | {{ uploading ? "上传中..." : "上传故障图片" }} |
| | | </u-button> |
| | | <view v-if="repairImageList.length" |
| | | class="repair-image-list"> |
| | | <view v-for="(file, index) in repairImageList" |
| | | :key="file.id || index" |
| | | class="repair-image-item"> |
| | | <image :src="normalizeFileUrl(file.url || file.tempFilePath)" |
| | | mode="aspectFill" |
| | | class="repair-image-preview" |
| | | @click="previewRepairImage(index)" /> |
| | | <view class="repair-image-delete" |
| | | @click="removeRepairImage(file, index)"> |
| | | <u-icon name="close" |
| | | size="12" |
| | | color="#fff" /> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </u-form-item> |
| | | </u-cell-group> |
| | | <!-- 提交按钮 --> |
| | | <view class="footer-btns"> |
| | |
| | | |
| | | <script setup> |
| | | import { ref, computed, onMounted, onUnmounted } from "vue"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import { onLoad, onShow } from "@dcloudio/uni-app"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import config from "@/config"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; |
| | | import { |
| | | addRepair, |
| | | delRepairFile, |
| | | editRepair, |
| | | getRepairFileList, |
| | | getRepairById, |
| | | } from "@/api/equipmentManagement/repair"; |
| | | import dayjs from "dayjs"; |
| | |
| | | const showDevice = ref(false); |
| | | const showDate = ref(false); |
| | | const pickerDateValue = ref(Date.now()); |
| | | const uploading = ref(false); |
| | | const repairImageList = ref([]); |
| | | const currentRepairId = ref(undefined); |
| | | const pageInited = ref(false); |
| | | |
| | | // 设备选项 |
| | | const deviceOptions = ref([]); |
| | |
| | | repairName: undefined, // 报修人 |
| | | remark: undefined, // 故障现象 |
| | | }); |
| | | |
| | | 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 normalizeId = raw => { |
| | | if (raw === null || raw === undefined) return undefined; |
| | | const val = String(raw).trim(); |
| | | if (!val || val === "undefined" || val === "null") return undefined; |
| | | return val; |
| | | }; |
| | | |
| | | const resolveRepairId = () => { |
| | | const pages = getCurrentPages(); |
| | | const currentPage = pages[pages.length - 1] || {}; |
| | | const routeId = normalizeId(currentPage?.options?.id); |
| | | const memoryId = normalizeId(currentRepairId.value); |
| | | const storageId = normalizeId(uni.getStorageSync("repairId")); |
| | | return memoryId || routeId || storageId; |
| | | }; |
| | | |
| | | const getPageId = () => { |
| | | const id = resolveRepairId(); |
| | | currentRepairId.value = id; |
| | | return id; |
| | | }; |
| | | |
| | | const fetchRepairFileList = async id => { |
| | | if (!id) { |
| | | repairImageList.value = []; |
| | | return; |
| | | } |
| | | try { |
| | | const { code, data } = await getRepairFileList(id); |
| | | if (code === 200) { |
| | | repairImageList.value = Array.isArray(data) ? data : []; |
| | | } else { |
| | | repairImageList.value = []; |
| | | } |
| | | } catch (e) { |
| | | repairImageList.value = []; |
| | | } |
| | | }; |
| | | |
| | | const chooseRepairImage = () => { |
| | | uni.chooseImage({ |
| | | count: 9, |
| | | sizeType: ["original", "compressed"], |
| | | sourceType: ["album", "camera"], |
| | | success: res => { |
| | | const id = getPageId(); |
| | | const files = res.tempFiles || []; |
| | | if (!files.length) return; |
| | | if (id) { |
| | | uploadRepairImages(files, id); |
| | | return; |
| | | } |
| | | if (operationType.value === "edit") { |
| | | showToast("未获取到报修ID,请返回列表后重试"); |
| | | return; |
| | | } |
| | | // 新增模式临时上传:先本地暂存,保存报修后再自动上传绑定 |
| | | const tempItems = files.map((file, idx) => { |
| | | const filePath = file.path || file.tempFilePath; |
| | | return { |
| | | id: `temp_${Date.now()}_${idx}`, |
| | | url: filePath, |
| | | tempFilePath: filePath, |
| | | name: file.name || `temp_${Date.now()}_${idx}.jpg`, |
| | | isTemp: true, |
| | | }; |
| | | }); |
| | | repairImageList.value = [...repairImageList.value, ...tempItems]; |
| | | showToast("已临时添加,保存报修后自动上传"); |
| | | }, |
| | | fail: () => { |
| | | showToast("选择图片失败"); |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | const uploadRepairImages = async (files, repairId) => { |
| | | const commonId = normalizeId(repairId); |
| | | if (!commonId) { |
| | | showToast("未获取到报修ID,上传失败"); |
| | | return; |
| | | } |
| | | const token = getToken(); |
| | | if (!token) { |
| | | showToast("登录已失效,请重新登录"); |
| | | return; |
| | | } |
| | | uploading.value = true; |
| | | try { |
| | | for (const file of files) { |
| | | const filePath = file.path || file.tempFilePath; |
| | | if (!filePath) continue; |
| | | await new Promise((resolve, reject) => { |
| | | uni.uploadFile({ |
| | | url: `${config.baseUrl}/device/repair/uploadFile`, |
| | | filePath, |
| | | name: "file", |
| | | formData: { |
| | | deviceRepairId: commonId, |
| | | type: 13, |
| | | }, |
| | | header: { |
| | | Authorization: `Bearer ${token}`, |
| | | }, |
| | | success: uploadRes => { |
| | | try { |
| | | const parsed = JSON.parse(uploadRes.data || "{}"); |
| | | if (uploadRes.statusCode === 200 && parsed.code === 200) { |
| | | resolve(parsed); |
| | | } else { |
| | | reject(new Error(parsed.msg || "上传失败")); |
| | | } |
| | | } catch (err) { |
| | | reject(new Error("上传响应解析失败")); |
| | | } |
| | | }, |
| | | fail: () => reject(new Error("上传失败")), |
| | | }); |
| | | }); |
| | | } |
| | | showToast("上传成功"); |
| | | await fetchRepairFileList(commonId); |
| | | } catch (e) { |
| | | showToast(e?.message || "上传失败"); |
| | | } finally { |
| | | uploading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const previewRepairImage = index => { |
| | | const urls = repairImageList.value |
| | | .map(item => normalizeFileUrl(item.url || item.tempFilePath)) |
| | | .filter(Boolean); |
| | | if (!urls.length) return; |
| | | uni.previewImage({ |
| | | urls, |
| | | current: urls[index] || urls[0], |
| | | }); |
| | | }; |
| | | |
| | | const removeRepairImage = (file, index) => { |
| | | if (!file?.id || file?.isTemp) { |
| | | repairImageList.value.splice(index, 1); |
| | | return; |
| | | } |
| | | uni.showModal({ |
| | | title: "提示", |
| | | content: "确认删除该图片吗?", |
| | | success: async res => { |
| | | if (!res.confirm) return; |
| | | try { |
| | | const { code } = await delRepairFile(file.id); |
| | | if (code === 200) { |
| | | repairImageList.value.splice(index, 1); |
| | | showToast("删除成功"); |
| | | } else { |
| | | showToast("删除失败"); |
| | | } |
| | | } catch (e) { |
| | | showToast("删除失败"); |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | // 报修状态选项 |
| | | const repairStatusOptions = ref([ |
| | |
| | | form.value.repairTime = dayjs(data.repairTime).format("YYYY-MM-DD"); |
| | | form.value.repairName = data.repairName; |
| | | form.value.remark = data.remark; |
| | | await fetchRepairFileList(id); |
| | | repairStatusText.value = |
| | | repairStatusOptions.value.find(item => item.value == data.status) |
| | | ?.name || ""; |
| | |
| | | showDate.value = false; |
| | | }; |
| | | |
| | | onLoad(options => { |
| | | const routeId = normalizeId(options?.id); |
| | | const storageId = normalizeId(uni.getStorageSync("repairId")); |
| | | const id = routeId || storageId; |
| | | currentRepairId.value = id || undefined; |
| | | pageInited.value = true; |
| | | }); |
| | | |
| | | onShow(() => { |
| | | // 页面显示时获取参数 |
| | | // onLoad 已拿到 id 后,再按当前 id 初始化页面 |
| | | if (!pageInited.value) return; |
| | | getPageParams(); |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | // 页面加载时获取设备列表和参数 |
| | | // 页面加载时先获取设备列表 |
| | | loadDeviceName(); |
| | | getPageParams(); |
| | | }); |
| | | |
| | | // 组件卸载时清理定时器 |
| | |
| | | // 准备提交数据 |
| | | const submitData = { ...form.value }; |
| | | |
| | | const { code } = id |
| | | const result = id |
| | | ? await editRepair({ id: id, ...submitData }) |
| | | : await addRepair(submitData); |
| | | const { code, data } = result || {}; |
| | | |
| | | if (code == 200) { |
| | | // 新增场景:临时图片在保存成功后自动上传并绑定新报修单 |
| | | if (!id) { |
| | | const newId = data?.id || data?.repairId || data; |
| | | if (newId) { |
| | | currentRepairId.value = newId; |
| | | const tempFiles = repairImageList.value |
| | | .filter(item => item?.isTemp && (item.tempFilePath || item.url)) |
| | | .map(item => ({ |
| | | path: item.tempFilePath || item.url, |
| | | tempFilePath: item.tempFilePath || item.url, |
| | | })); |
| | | if (tempFiles.length) { |
| | | await uploadRepairImages(tempFiles, newId); |
| | | } |
| | | } |
| | | } |
| | | showToast(`${id ? "编辑" : "新增"}报修成功`); |
| | | setTimeout(() => { |
| | | uni.navigateBack(); |
| | |
| | | |
| | | // 获取页面参数 |
| | | const getPageParams = () => { |
| | | // 使用uni.getStorageSync获取id |
| | | const id = uni.getStorageSync("repairId"); |
| | | const id = resolveRepairId(); |
| | | currentRepairId.value = id || undefined; |
| | | |
| | | // 根据是否有id参数来判断是新增还是编辑 |
| | | if (id) { |
| | | // 编辑模式,获取详情 |
| | | loadForm(id); |
| | | // 可选:获取后清除存储的id,避免影响后续操作 |
| | | uni.removeStorageSync("repairId"); |
| | | } else { |
| | | // 新增模式 |
| | | currentRepairId.value = undefined; |
| | | repairImageList.value = []; |
| | | loadForm(); |
| | | } |
| | | }; |
| | | |
| | | // 获取页面ID |
| | | const getPageId = () => { |
| | | // 使用uni.getStorageSync获取id |
| | | const id = uni.getStorageSync("repairId"); |
| | | return id; |
| | | }; |
| | | </script> |
| | | |
| | |
| | | margin-left: 8px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .repair-image-upload { |
| | | width: 100%; |
| | | } |
| | | |
| | | .repair-image-list { |
| | | margin-top: 12px; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .repair-image-item { |
| | | position: relative; |
| | | width: 80px; |
| | | height: 80px; |
| | | } |
| | | |
| | | .repair-image-preview { |
| | | width: 80px; |
| | | height: 80px; |
| | | border-radius: 6px; |
| | | background: #f5f5f5; |
| | | } |
| | | |
| | | .repair-image-delete { |
| | | position: absolute; |
| | | top: -6px; |
| | | right: -6px; |
| | | width: 18px; |
| | | height: 18px; |
| | | border-radius: 50%; |
| | | background: rgba(0, 0, 0, 0.65); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | </style> |