| | |
| | | maxlength="500" |
| | | placeholder="请描述异常情况..." /> |
| | | </view> |
| | | <!-- 分类标签页(仅在异常时显示) --> |
| | | <!-- 上传区域(仅在异常时显示) --> |
| | | <view class="section-card" |
| | | v-if="hasException === true"> |
| | | <view class="upload-tabs"> |
| | | <view class="tab-item" |
| | | :class="{ active: currentUploadType === 'before' }" |
| | | @click="switchUploadType('before')"> |
| | | 生产前 |
| | | </view> |
| | | <view class="tab-item" |
| | | :class="{ active: currentUploadType === 'after' }" |
| | | @click="switchUploadType('after')"> |
| | | 生产中 |
| | | </view> |
| | | <view class="tab-item" |
| | | :class="{ active: currentUploadType === 'issue' }" |
| | | @click="switchUploadType('issue')"> |
| | | 生产后 |
| | | </view> |
| | | </view> |
| | | <!-- 当前分类的上传区域 --> |
| | | <view class="section-title">上传附件</view> |
| | | <view class="upload-area"> |
| | | <view class="upload-buttons"> |
| | | <u-button type="primary" |
| | | @click="chooseMedia('image')" |
| | | :loading="uploading" |
| | | :disabled="getCurrentFiles().length >= uploadConfig.limit" |
| | | :disabled="fileList.length >= uploadConfig.limit" |
| | | :customStyle="{ marginRight: '10px', flex: 1 }"> |
| | | <u-icon name="camera" |
| | | size="18" |
| | |
| | | <u-button type="success" |
| | | @click="chooseMedia('video')" |
| | | :loading="uploading" |
| | | :disabled="getCurrentFiles().length >= uploadConfig.limit" |
| | | :disabled="fileList.length >= uploadConfig.limit" |
| | | :customStyle="{ flex: 1 }"> |
| | | <uni-icons type="videocam" |
| | | size="18" |
| | |
| | | :showText="true" |
| | | activeColor="#409eff"></u-line-progress> |
| | | </view> |
| | | <!-- 当前分类的文件列表 --> |
| | | <view v-if="getCurrentFiles().length > 0" |
| | | <!-- 文件列表 --> |
| | | <view v-if="fileList.length > 0" |
| | | class="file-list"> |
| | | <view v-for="(file, index) in getCurrentFiles()" |
| | | <view v-for="(file, index) in fileList" |
| | | :key="index" |
| | | class="file-item"> |
| | | <view class="file-preview-container"> |
| | |
| | | style="margin-right: 5px"></uni-icons> |
| | | <text class="video-text">视频</text> |
| | | </view> |
| | | <!-- 删除按钮 --> |
| | | <view class="delete-btn" |
| | | @click="removeFile(index)"> |
| | | <u-icon name="close" |
| | |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-if="getCurrentFiles().length === 0" |
| | | <view v-if="fileList.length === 0" |
| | | class="empty-state"> |
| | | <text>请选择要上传的{{ getUploadTypeText() }}图片或视频</text> |
| | | <text>请选择要上传的图片或视频</text> |
| | | </view> |
| | | </view> |
| | | <!-- 统计信息 --> |
| | | <view class="upload-summary"> |
| | | <text class="summary-text"> |
| | | 生产前: {{ beforeModelValue.length }}个文件 | |
| | | 生产中: {{ afterModelValue.length }}个文件 | |
| | | 生产后: {{ issueModelValue.length }}个文件 |
| | | </text> |
| | | <text class="summary-text">已上传: {{ fileList.length }}个文件</text> |
| | | </view> |
| | | </view> |
| | | <!-- 正常状态提示 --> |
| | |
| | | const uploading = ref(false); |
| | | const uploadProgress = ref(0); |
| | | |
| | | // 三个分类的上传状态 |
| | | const beforeModelValue = ref([]); // 生产前 |
| | | const afterModelValue = ref([]); // 生产中 |
| | | const issueModelValue = ref([]); // 生产后 |
| | | |
| | | // 当前激活的上传类型 |
| | | const currentUploadType = ref("before"); // 'before', 'after', 'issue' |
| | | // 统一的文件列表 |
| | | const fileList = ref([]); |
| | | |
| | | // 异常状态 |
| | | const hasException = ref(null); // null: 未选择, true: 存在异常, false: 正常 |
| | |
| | | const info = JSON.parse(decodeURIComponent(options.taskInfo)); |
| | | taskInfo.value = info; |
| | | |
| | | // 回显逻辑:从 taskInfo 中恢复已上传的文件 |
| | | const mapFiles = list => { |
| | | if (!list || !Array.isArray(list)) return []; |
| | | return list.map(item => { |
| | | // 处理 URL,去除可能的空格 |
| | | const finalUrl = (item.url || item.previewURL || "").trim(); |
| | | // 自动推断文件类型 |
| | | let fileType = item.type; |
| | | if (!fileType && item.contentType) { |
| | | fileType = item.contentType.startsWith("video") ? "video" : "image"; |
| | | } else if (!fileType) { |
| | | fileType = "image"; // 默认图片 |
| | | } |
| | | // 回显逻辑:从 commonFileListVO 恢复已上传的文件 |
| | | const fileVOList = Array.isArray(info.commonFileListVO) ? info.commonFileListVO : []; |
| | | fileList.value = fileVOList.map(item => { |
| | | const finalUrl = (item.url || item.previewURL || "").trim(); |
| | | let fileType = item.type; |
| | | if (!fileType && item.contentType) { |
| | | fileType = item.contentType.startsWith("video") ? "video" : "image"; |
| | | } else if (!fileType) { |
| | | fileType = "image"; |
| | | } |
| | | return { |
| | | ...item, |
| | | url: finalUrl, |
| | | name: item.name || item.originalFilename, |
| | | tempId: item.tempId || item.id || item.tempFileId, |
| | | size: item.size || item.byteSize || 0, |
| | | type: fileType, |
| | | status: "success", |
| | | }; |
| | | }); |
| | | |
| | | return { |
| | | ...item, |
| | | url: finalUrl, |
| | | name: item.name || item.originalFilename, |
| | | tempId: item.tempId || item.id || item.tempFileId, |
| | | size: item.size || item.byteSize || 0, // 映射大小字段 |
| | | type: fileType, |
| | | status: "success", |
| | | }; |
| | | }); |
| | | }; |
| | | |
| | | // 修正字段映射:BeforeVO(生产前), VO(生产中), AfterVO(生产后) |
| | | if ( |
| | | info.commonFileListBeforeVO && |
| | | Array.isArray(info.commonFileListBeforeVO) |
| | | ) { |
| | | beforeModelValue.value = mapFiles(info.commonFileListBeforeVO); |
| | | } |
| | | console.log(beforeModelValue.value, "beforeModelValue"); |
| | | |
| | | if (info.commonFileListVO && Array.isArray(info.commonFileListVO)) { |
| | | afterModelValue.value = mapFiles(info.commonFileListVO); |
| | | } |
| | | if ( |
| | | info.commonFileListAfterVO && |
| | | Array.isArray(info.commonFileListAfterVO) |
| | | ) { |
| | | issueModelValue.value = mapFiles(info.commonFileListAfterVO); |
| | | } |
| | | |
| | | // 如果有异常描述,也恢复 |
| | | if (info.abnormalDescription) { |
| | | abnormalDescription.value = info.abnormalDescription; |
| | | } |
| | | // 如果有异常状态,也恢复 |
| | | if (info.hasException !== undefined && info.hasException !== null) { |
| | | hasException.value = info.hasException; |
| | | } else if ( |
| | | info.inspectionResult !== undefined && |
| | | info.inspectionResult !== null |
| | | ) { |
| | | // 0-异常,1-正常 |
| | | } else if (info.inspectionResult !== undefined && info.inspectionResult !== null) { |
| | | hasException.value = String(info.inspectionResult) === "0"; |
| | | } |
| | | |
| | | // 自动兜底:如果存在已上传文件,则必然是异常状态,确保 UI 正常显示 |
| | | if ( |
| | | !hasException.value && |
| | | (beforeModelValue.value.length > 0 || |
| | | afterModelValue.value.length > 0 || |
| | | issueModelValue.value.length > 0) |
| | | ) { |
| | | if (!hasException.value && fileList.value.length > 0) { |
| | | hasException.value = true; |
| | | } |
| | | } catch (e) { |
| | |
| | | // 返回上一页 |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // 切换上传类型 |
| | | const switchUploadType = type => { |
| | | currentUploadType.value = type; |
| | | }; |
| | | |
| | | // 获取当前分类的文件列表 |
| | | const getCurrentFiles = () => { |
| | | switch (currentUploadType.value) { |
| | | case "before": |
| | | return beforeModelValue.value || []; |
| | | case "after": |
| | | return afterModelValue.value || []; |
| | | case "issue": |
| | | return issueModelValue.value || []; |
| | | default: |
| | | return []; |
| | | } |
| | | }; |
| | | |
| | | // 获取上传类型文本 |
| | | const getUploadTypeText = () => { |
| | | switch (currentUploadType.value) { |
| | | case "before": |
| | | return "生产前"; |
| | | case "after": |
| | | return "生产中"; |
| | | case "issue": |
| | | return "生产后"; |
| | | default: |
| | | return ""; |
| | | } |
| | | }; |
| | | |
| | | // 设置异常状态 |
| | |
| | | inspector: taskInfo.value?.inspector, |
| | | hasException: hasException.value, |
| | | inspectionResult: hasException.value ? 0 : 1, // 0-异常,1-正常 |
| | | commonFileListBeforeDTO: beforeModelValue.value, |
| | | commonFileListDTO: afterModelValue.value, |
| | | commonFileListAfterDTO: issueModelValue.value, |
| | | uploadedFiles: { |
| | | before: beforeModelValue.value, |
| | | after: afterModelValue.value, |
| | | issue: issueModelValue.value, |
| | | }, |
| | | commonFileListDTO: fileList.value, |
| | | uploadedFiles: fileList.value, |
| | | }; |
| | | |
| | | uni.setStorageSync("repairTaskInfo", JSON.stringify(taskData)); |
| | |
| | | |
| | | // 如果是异常状态,检查是否有上传文件和描述 |
| | | if (hasException.value === true) { |
| | | const totalFiles = |
| | | beforeModelValue.value.length + |
| | | afterModelValue.value.length + |
| | | issueModelValue.value.length; |
| | | if (totalFiles === 0) { |
| | | if (fileList.value.length === 0) { |
| | | uni.showToast({ |
| | | title: "请上传异常照片", |
| | | icon: "none", |
| | |
| | | mask: true, |
| | | }); |
| | | |
| | | // 按照逻辑合并所有分类的文件用于提取ID |
| | | const allFiles = [ |
| | | ...beforeModelValue.value, |
| | | ...afterModelValue.value, |
| | | ...issueModelValue.value, |
| | | ]; |
| | | |
| | | // 传给后端的临时文件ID列表 |
| | | let tempFileIds = []; |
| | | if (allFiles.length > 0) { |
| | | tempFileIds = allFiles |
| | | if (fileList.value.length > 0) { |
| | | tempFileIds = fileList.value |
| | | .map(item => item?.tempId ?? item?.tempFileId ?? item?.id) |
| | | .filter(v => v !== undefined && v !== null && v !== ""); |
| | | } |
| | |
| | | // 提交数据 |
| | | const submitData = { |
| | | ...taskInfo.value, |
| | | commonFileListBeforeDTO: beforeModelValue.value, // 生产前 |
| | | commonFileListDTO: afterModelValue.value, // 生产中 |
| | | commonFileListAfterDTO: issueModelValue.value, // 生产后 |
| | | commonFileListDTO: fileList.value, |
| | | hasException: hasException.value, |
| | | inspectionResult: hasException.value ? 0 : 1, // 0-异常,1-正常 |
| | | abnormalDescription: abnormalDescription.value, |
| | |
| | | |
| | | // 拍照/拍视频 |
| | | const chooseMedia = type => { |
| | | if (getCurrentFiles().length >= uploadConfig.limit) { |
| | | if (fileList.value.length >= uploadConfig.limit) { |
| | | uni.showToast({ |
| | | title: `最多只能选择${uploadConfig.limit}个文件`, |
| | | icon: "none", |
| | |
| | | return; |
| | | } |
| | | |
| | | const remaining = uploadConfig.limit - getCurrentFiles().length; |
| | | const remaining = uploadConfig.limit - fileList.value.length; |
| | | |
| | | // 优先使用 chooseMedia |
| | | if (typeof uni.chooseMedia === "function") { |
| | |
| | | Authorization: `Bearer ${token}`, |
| | | }, |
| | | formData: { |
| | | type: getTabType(), |
| | | type: 10, |
| | | }, |
| | | success: res => { |
| | | try { |
| | |
| | | status: "success", |
| | | }; |
| | | |
| | | // 根据当前类型添加到对应数组 |
| | | if (currentUploadType.value === "before") { |
| | | beforeModelValue.value.push(uploadedFile); |
| | | } else if (currentUploadType.value === "after") { |
| | | afterModelValue.value.push(uploadedFile); |
| | | } else if (currentUploadType.value === "issue") { |
| | | issueModelValue.value.push(uploadedFile); |
| | | } |
| | | fileList.value.push(uploadedFile); |
| | | |
| | | uni.showToast({ title: "上传成功", icon: "success" }); |
| | | } else { |
| | |
| | | }); |
| | | }; |
| | | |
| | | // 获取type值 |
| | | const getTabType = () => { |
| | | switch (currentUploadType.value) { |
| | | case "before": |
| | | return 10; |
| | | case "after": |
| | | return 11; |
| | | case "issue": |
| | | return 12; |
| | | default: |
| | | return 10; |
| | | } |
| | | }; |
| | | |
| | | // 删除文件 |
| | | const removeFile = index => { |
| | | const files = getCurrentFiles(); |
| | | const files = fileList.value; |
| | | files.splice(index, 1); |
| | | }; |
| | | </script> |
| | |
| | | outline: none; |
| | | border-color: #409eff; |
| | | background: #fff; |
| | | } |
| | | |
| | | /* 分类标签页 */ |
| | | .upload-tabs { |
| | | display: flex; |
| | | gap: 10px; |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .tab-item { |
| | | flex: 1; |
| | | padding: 10px; |
| | | text-align: center; |
| | | background: #f5f5f5; |
| | | border-radius: 6px; |
| | | font-size: 13px; |
| | | color: #666; |
| | | cursor: pointer; |
| | | transition: all 0.3s; |
| | | } |
| | | |
| | | .tab-item.active { |
| | | background: #409eff; |
| | | color: #fff; |
| | | } |
| | | |
| | | /* 上传区域 */ |