| | |
| | | <template> |
| | | <view class="inspection-upload-page"> |
| | | <!-- 页面头部 --> |
| | | <PageHeader title="巡检管理" |
| | | <PageHeader title="设备巡检" |
| | | @back="goBack" /> |
| | | <!-- 数据列表 --> |
| | | <view class="table-section"> |
| | |
| | | <text class="task-location">{{ item.inspectionLocation }}</text> |
| | | </view> |
| | | <view class="task-actions"> |
| | | <u-button type="primary" |
| | | <!-- <u-button type="primary" |
| | | size="small" |
| | | @click.stop="startScanForTask(item)" |
| | | :customStyle="{ |
| | |
| | | marginRight: '8px' |
| | | }"> |
| | | 扫码上传 |
| | | </u-button> --> |
| | | <u-button type="primary" |
| | | size="small" |
| | | @click.stop="startUploadForTask(item)" |
| | | :customStyle="{ |
| | | borderRadius: '15px', |
| | | height: '30px', |
| | | fontSize: '12px', |
| | | marginRight: '8px' |
| | | }"> |
| | | 图片上传 |
| | | </u-button> |
| | | <u-button type="success" |
| | | size="small" |
| | |
| | | :key="index" |
| | | class="file-item"> |
| | | <view class="file-preview-container"> |
| | | <image v-if="file.type === 'image' || (file.type !== 'video' && !file.type)" |
| | | :src="file.url || file.tempFilePath || file.path || file.downloadUrl" |
| | | <image v-if="isImageFile(file)" |
| | | :src="getFileAccessUrl(file)" |
| | | class="file-preview" |
| | | mode="aspectFill" /> |
| | | <view v-else-if="file.type === 'video'" |
| | | <view v-else-if="isVideoFile(file)" |
| | | class="video-preview"> |
| | | <uni-icons type="videocam" |
| | | name="videocam" |
| | |
| | | </view> |
| | | </view> |
| | | <view class="file-info"> |
| | | <text class="file-name">{{ file.bucketFilename || file.name || (file.type === 'image' ? '图片' : '视频') |
| | | <text class="file-name">{{ file.bucketFilename || file.name || (isImageFile(file) ? '图片' : '视频') |
| | | }}</text> |
| | | <text class="file-size">{{ formatFileSize(file.size) }}</text> |
| | | </view> |
| | |
| | | @click="previewAttachment(file)"> |
| | | <view class="attachment-preview-container"> |
| | | <image v-if="file.type === 'image' || isImageFile(file)" |
| | | :src="file.url || file.downloadUrl" |
| | | :src="getFileAccessUrl(file)" |
| | | class="attachment-preview" |
| | | mode="aspectFill" /> |
| | | <view v-else |
| | |
| | | </view> |
| | | <view class="video-modal-body"> |
| | | <video v-if="currentVideoFile" |
| | | :src="currentVideoFile.url || currentVideoFile.downloadUrl" |
| | | :src="getFileAccessUrl(currentVideoFile)" |
| | | class="video-player" |
| | | controls |
| | | autoplay |
| | |
| | | |
| | | // 计算上传URL |
| | | const uploadFileUrl = computed(() => { |
| | | const baseUrl = "http://114.132.189.42:9030"; |
| | | const baseUrl = config.baseUrl; |
| | | |
| | | return baseUrl + uploadConfig.action; |
| | | }); |
| | |
| | | } |
| | | }; |
| | | |
| | | // 图片上传(可选择图片上传或者是相机拍照) |
| | | const startUploadForTask = async (task, type) => { |
| | | // 直接打开上传弹窗 |
| | | openUploadDialog(task); |
| | | }; |
| | | |
| | | // 查看附件 |
| | | const viewAttachments = async task => { |
| | | try { |
| | |
| | | : allList.filter(f => f?.type === 12); |
| | | |
| | | const mapToViewFile = (file, viewType) => { |
| | | const u = normalizeFileUrl(file?.url || file?.downloadUrl || ""); |
| | | const u = getFileAccessUrl(file); |
| | | return { |
| | | ...file, |
| | | // 用于三标签页分组:0=生产前 1=生产中 2=生产后 |
| | |
| | | return true; |
| | | } |
| | | |
| | | // 检查原有的type字段 |
| | | if (file.type === "image") return true; |
| | | // 检查原有的type字段(或保留的媒体类型) |
| | | if (file.type === "image" || file.mediaType === "image") return true; |
| | | |
| | | // 检查文件扩展名 |
| | | const name = file.bucketFilename || file.originalFilename || file.name || ""; |
| | |
| | | return ["jpg", "jpeg", "png", "gif", "webp"].includes(ext); |
| | | }; |
| | | |
| | | // 判断是否为视频文件 |
| | | const isVideoFile = file => { |
| | | if (!file) return false; |
| | | if (file.type === "video" || file.mediaType === "video") return true; |
| | | const name = file.bucketFilename || file.originalFilename || file.name || ""; |
| | | const ext = name.split(".").pop()?.toLowerCase(); |
| | | return ["mp4", "mov", "avi", "wmv", "mkv", "webm"].includes(ext); |
| | | }; |
| | | |
| | | // 文件访问基础域(后端要求前缀) |
| | | const filePreviewBase = "http://114.132.189.42:9098"; |
| | | const filePreviewBase = config.fileUrl; |
| | | |
| | | // 将后端返回的文件地址规范成可访问URL |
| | | // 兼容场景: |
| | | // - 已经是 http/https:直接返回 |
| | | // - 以 / 开头:拼接 filePreviewBase |
| | | // - Windows 本地路径(如 D:\ruoyi\prod\uploads...\xx.jpg):尝试截取 prod 之后的相对路径并拼接 filePreviewBase |
| | | const normalizeFileUrl = rawUrl => { |
| | | try { |
| | | if (!rawUrl || typeof rawUrl !== "string") return ""; |
| | | const url = rawUrl.trim(); |
| | | if (!url) return ""; |
| | | if (/^https?:\/\//i.test(url)) return url; |
| | | if (url.startsWith("/")) return `${filePreviewBase}${url}`; |
| | | const normalizeFileUrl = (rawUrl = "") => { |
| | | let fileUrl = rawUrl || ""; |
| | | const javaApi = filePreviewBase; |
| | | const localPrefixes = ["wxfile://", "file://", "content://", "blob:", "data:"]; |
| | | |
| | | // Windows path -> web path |
| | | if (/^[a-zA-Z]:\\/.test(url)) { |
| | | const normalized = url.replace(/\\/g, "/"); |
| | | const idx = normalized.indexOf("/prod/"); |
| | | if (idx >= 0) { |
| | | const relative = normalized.slice(idx + "/prod/".length); |
| | | return `${filePreviewBase}/${relative}`; |
| | | } |
| | | // 兜底:无法推断映射规则时,至少把反斜杠变成正斜杠 |
| | | return normalized; |
| | | } |
| | | |
| | | // 其他相对路径:直接用 baseUrl 拼一下 |
| | | return `${filePreviewBase}/${url.replace(/^\//, "")}`; |
| | | } catch (e) { |
| | | return rawUrl || ""; |
| | | 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 || file?.downloadUrl || ""); |
| | | }; |
| | | |
| | | // 预览附件 |
| | |
| | | // 预览图片 |
| | | const imageUrls = getCurrentViewAttachments() |
| | | .filter(f => isImageFile(f)) |
| | | .map(f => f.url || f.downloadUrl); |
| | | .map(f => getFileAccessUrl(f)); |
| | | |
| | | uni.previewImage({ |
| | | urls: imageUrls, |
| | | current: file.url || file.downloadUrl, |
| | | current: getFileAccessUrl(file), |
| | | }); |
| | | } else { |
| | | // 预览视频 - 显示视频播放弹窗 |
| | |
| | | downloadUrl: uploadedFile.downloadUrl || uploadedFile.url, |
| | | size: uploadedFile.size || uploadedFile.byteSize || file.size, |
| | | createTime: uploadedFile.createTime || new Date().getTime(), |
| | | mediaType: file.type || uploadedFile.mediaType, |
| | | type: typeValue, // 添加类型字段:0=生产前, 1=生产中, 2=生产后 |
| | | }; |
| | | |