| | |
| | | <template> |
| | | <u-popup |
| | | v-model="dialogVisitable" |
| | | :show="dialogVisitable" |
| | | mode="center" |
| | | :round="10" |
| | | :closeable="true" |
| | |
| | | <view class="upload-container"> |
| | | <view class="form-container"> |
| | | <view class="title">生产前</view> |
| | | <u-upload |
| | | :fileList="beforeModelValue" |
| | | @afterRead="afterRead" |
| | | @delete="deleteFile" |
| | | name="before" |
| | | multiple |
| | | :maxCount="10" |
| | | :maxSize="1024 * 1024" |
| | | accept="video/*" |
| | | :previewFullImage="true" |
| | | ></u-upload> |
| | | <view class="upload-buttons"> |
| | | <u-button type="primary" size="small" @click="chooseVideo('before')" :disabled="beforeModelValue.length >= 10"> |
| | | <u-icon name="video" size="16" color="#fff" style="margin-right: 5px;"></u-icon> |
| | | 选择视频 |
| | | </u-button> |
| | | <text class="file-count">{{ beforeModelValue.length }}/10</text> |
| | | </view> |
| | | <view class="file-list" v-if="beforeModelValue.length > 0"> |
| | | <view v-for="(file, index) in beforeModelValue" :key="index" class="file-item"> |
| | | <text class="file-name">视频{{ index + 1 }}</text> |
| | | <u-button |
| | | type="error" |
| | | size="mini" |
| | | :customStyle="{ minWidth: '120rpx', width: 'auto', padding: '0 20rpx', height: '60rpx' }" |
| | | @click="deleteFile(index, 'before')" |
| | | >删除</u-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-container"> |
| | | <view class="title">生产后</view> |
| | | <u-upload |
| | | :fileList="afterModelValue" |
| | | @afterRead="afterRead" |
| | | @delete="deleteFile" |
| | | name="after" |
| | | multiple |
| | | :maxCount="10" |
| | | :maxSize="1024 * 1024" |
| | | accept="video/*" |
| | | :previewFullImage="true" |
| | | ></u-upload> |
| | | <view class="upload-buttons"> |
| | | <u-button type="primary" size="small" @click="chooseVideo('after')" :disabled="afterModelValue.length >= 10"> |
| | | <u-icon name="video" size="16" color="#fff" style="margin-right: 5px;"></u-icon> |
| | | 选择视频 |
| | | </u-button> |
| | | <text class="file-count">{{ afterModelValue.length }}/10</text> |
| | | </view> |
| | | <view class="file-list" v-if="afterModelValue.length > 0"> |
| | | <view v-for="(file, index) in afterModelValue" :key="index" class="file-item"> |
| | | <text class="file-name">视频{{ index + 1 }}</text> |
| | | <u-button |
| | | type="error" |
| | | size="mini" |
| | | :customStyle="{ minWidth: '120rpx', width: 'auto', padding: '0 20rpx', height: '60rpx' }" |
| | | @click="deleteFile(index, 'after')" |
| | | >删除</u-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-container"> |
| | | <view class="title">生产问题</view> |
| | | <u-upload |
| | | :fileList="issueModelValue" |
| | | @afterRead="afterRead" |
| | | @delete="deleteFile" |
| | | name="issue" |
| | | multiple |
| | | :maxCount="10" |
| | | :maxSize="1024 * 1024" |
| | | accept="video/*" |
| | | :previewFullImage="true" |
| | | ></u-upload> |
| | | <view class="upload-buttons"> |
| | | <u-button type="primary" size="small" @click="chooseVideo('issue')" :disabled="issueModelValue.length >= 10"> |
| | | <u-icon name="video" size="16" color="#fff" style="margin-right: 5px;"></u-icon> |
| | | 选择视频 |
| | | </u-button> |
| | | <text class="file-count">{{ issueModelValue.length }}/10</text> |
| | | </view> |
| | | <view class="file-list" v-if="issueModelValue.length > 0"> |
| | | <view v-for="(file, index) in issueModelValue" :key="index" class="file-item"> |
| | | <text class="file-name">视频{{ index + 1 }}</text> |
| | | <u-button |
| | | type="error" |
| | | size="mini" |
| | | :customStyle="{ minWidth: '120rpx', width: 'auto', padding: '0 20rpx', height: '60rpx' }" |
| | | @click="deleteFile(index, 'issue')" |
| | | >删除</u-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue' |
| | | import { submitInspectionRecord } from '@/api/equipmentManagement/inspection.js' |
| | | import { ref, computed } from 'vue' |
| | | import {submitInspectionRecord, uploadInspectionTask} from '@/api/equipmentManagement/inspection.js' |
| | | import { getToken } from '@/utils/auth' |
| | | import config from '@/config.js' |
| | | |
| | | const emit = defineEmits(['closeDia']) |
| | | |
| | | // 上传接口URL |
| | | const uploadFileUrl = computed(() => { |
| | | return config.baseUrl + '/common/minioUploads' |
| | | }) |
| | | |
| | | // 上传请求头 |
| | | const uploadHeaders = computed(() => { |
| | | const token = getToken() |
| | | return token ? { Authorization: 'Bearer ' + token } : {} |
| | | }) |
| | | |
| | | const dialogVisitable = ref(false) |
| | | const beforeModelValue = ref([]) |
| | |
| | | const issueModelValue = ref([]) |
| | | const infoData = ref(null) |
| | | |
| | | // 文件上传处理 |
| | | const afterRead = (event) => { |
| | | const { name, file } = event |
| | | // 选择视频 |
| | | const chooseVideo = (type) => { |
| | | const currentList = type === 'before' ? beforeModelValue : type === 'after' ? afterModelValue : issueModelValue; |
| | | |
| | | // 上传文件到服务器 |
| | | uni.uploadFile({ |
| | | url: '/api/upload', // 替换为实际的上传接口 |
| | | filePath: file.url, |
| | | name: 'file', |
| | | if (currentList.value.length >= 10) { |
| | | uni.showToast({ |
| | | title: '最多只能选择10个视频', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | uni.chooseVideo({ |
| | | sourceType: ['camera', 'album'], |
| | | maxDuration: 60, |
| | | camera: 'back', |
| | | success: (res) => { |
| | | const data = JSON.parse(res.data) |
| | | if (data.code === 200) { |
| | | try { |
| | | if (!res.tempFilePath) { |
| | | throw new Error('未获取到视频文件'); |
| | | } |
| | | |
| | | // 从临时路径中提取文件名,做为初始展示 |
| | | const tempName = res.tempFilePath.split('/').pop() || `video_${Date.now()}.mp4` |
| | | const fileItem = { |
| | | url: data.data.url, |
| | | name: file.name, |
| | | status: 'success' |
| | | } |
| | | url: res.tempFilePath, |
| | | name: tempName, |
| | | originalFilename: tempName, |
| | | size: res.size || 0, |
| | | duration: res.duration || 0, |
| | | status: 'pending' // 待上传状态 |
| | | }; |
| | | |
| | | // 根据name添加到对应的数组 |
| | | if (name === 'before') { |
| | | beforeModelValue.value.push(fileItem) |
| | | } else if (name === 'after') { |
| | | afterModelValue.value.push(fileItem) |
| | | } else if (name === 'issue') { |
| | | issueModelValue.value.push(fileItem) |
| | | } |
| | | // 添加到对应的数组 |
| | | currentList.value.push(fileItem); |
| | | |
| | | // 自动上传 |
| | | uploadFile(fileItem, type, currentList.value.length - 1); |
| | | } catch (error) { |
| | | console.error('处理视频失败:', error); |
| | | uni.showToast({ |
| | | title: '上传成功', |
| | | icon: 'success' |
| | | }) |
| | | } else { |
| | | uni.showToast({ |
| | | title: '上传失败', |
| | | title: '处理视频失败', |
| | | icon: 'error' |
| | | }) |
| | | }); |
| | | } |
| | | }, |
| | | fail: () => { |
| | | fail: (err) => { |
| | | console.error('选择视频失败:', err); |
| | | uni.showToast({ |
| | | title: '上传失败', |
| | | title: '选择视频失败: ' + (err.errMsg || '未知错误'), |
| | | icon: 'error' |
| | | }) |
| | | }); |
| | | } |
| | | }) |
| | | }); |
| | | } |
| | | |
| | | // 上传文件到服务器 |
| | | const uploadFile = (fileItem, type, index) => { |
| | | fileItem.status = 'uploading'; |
| | | |
| | | // 确保token存在 |
| | | const token = getToken(); |
| | | if (!token) { |
| | | fileItem.status = 'failed'; |
| | | uni.showToast({ |
| | | title: '用户未登录', |
| | | icon: 'error' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | uni.uploadFile({ |
| | | url: uploadFileUrl.value, |
| | | filePath: fileItem.url, |
| | | name: 'files', // 注意:接口使用的是 'files' 而不是 'file' |
| | | header: { |
| | | 'Authorization': `Bearer ${token}` |
| | | }, |
| | | success: (res) => { |
| | | try { |
| | | if (res.statusCode === 200) { |
| | | const response = typeof res.data === 'string' ? JSON.parse(res.data) : res.data; |
| | | if (response.code === 200) { |
| | | // 响应数据是数组格式,取第一个元素 |
| | | const uploadedFile = Array.isArray(response.data) ? response.data[0] : response.data; |
| | | |
| | | console.log('上传成功,返回的文件信息:', uploadedFile); |
| | | console.log('原始文件名:', uploadedFile.originalFilename); |
| | | |
| | | // 更新文件信息 - 使用 Object.assign 确保响应式更新 |
| | | const displayName = uploadedFile.originalFilename |
| | | || uploadedFile.bucketFilename |
| | | || fileItem.name |
| | | || '未命名文件'; |
| | | Object.assign(fileItem, { |
| | | url: uploadedFile.url || uploadedFile.downloadUrl, |
| | | status: 'success', |
| | | id: uploadedFile.id, |
| | | name: displayName, |
| | | originalFilename: uploadedFile.originalFilename || displayName, // 保存原始文件名 |
| | | bucketFilename: uploadedFile.bucketFilename, |
| | | downloadUrl: uploadedFile.downloadUrl || uploadedFile.url, |
| | | size: uploadedFile.byteSize || fileItem.size, |
| | | createTime: uploadedFile.createTime || new Date().getTime() |
| | | }); |
| | | |
| | | console.log('更新后的文件项:', fileItem); |
| | | |
| | | uni.showToast({ |
| | | title: '上传成功', |
| | | icon: 'success' |
| | | }); |
| | | } else { |
| | | fileItem.status = 'failed'; |
| | | uni.showToast({ |
| | | title: response.msg || '上传失败', |
| | | icon: 'error' |
| | | }); |
| | | } |
| | | } else { |
| | | fileItem.status = 'failed'; |
| | | uni.showToast({ |
| | | title: `服务器错误,状态码: ${res.statusCode}`, |
| | | icon: 'error' |
| | | }); |
| | | } |
| | | } catch (e) { |
| | | fileItem.status = 'failed'; |
| | | console.error('解析响应失败:', e); |
| | | console.error('原始响应数据:', res.data); |
| | | uni.showToast({ |
| | | title: '解析响应失败', |
| | | icon: 'error' |
| | | }); |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | fileItem.status = 'failed'; |
| | | console.error('上传失败:', err); |
| | | let errorMessage = '上传失败'; |
| | | if (err.errMsg) { |
| | | if (err.errMsg.includes('statusCode: null')) { |
| | | errorMessage = '网络连接失败,请检查网络设置'; |
| | | } else if (err.errMsg.includes('timeout')) { |
| | | errorMessage = '上传超时,请重试'; |
| | | } else { |
| | | errorMessage = err.errMsg; |
| | | } |
| | | } |
| | | uni.showToast({ |
| | | title: errorMessage, |
| | | icon: 'error' |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | // 删除文件 |
| | | const deleteFile = (event) => { |
| | | const { name, index } = event |
| | | |
| | | if (name === 'before') { |
| | | beforeModelValue.value.splice(index, 1) |
| | | } else if (name === 'after') { |
| | | afterModelValue.value.splice(index, 1) |
| | | } else if (name === 'issue') { |
| | | issueModelValue.value.splice(index, 1) |
| | | const deleteFile = (index, type) => { |
| | | if (type === 'before') { |
| | | beforeModelValue.value.splice(index, 1); |
| | | } else if (type === 'after') { |
| | | afterModelValue.value.splice(index, 1); |
| | | } else if (type === 'issue') { |
| | | issueModelValue.value.splice(index, 1); |
| | | } |
| | | } |
| | | |
| | |
| | | try { |
| | | let arr = [] |
| | | if (beforeModelValue.value.length > 0) { |
| | | arr.push(...beforeModelValue.value.map(item => ({ ...item, statusType: 0 }))) |
| | | arr.push(...beforeModelValue.value.map(item => ({ ...item, type: 0 }))) |
| | | } |
| | | if (afterModelValue.value.length > 0) { |
| | | arr.push(...afterModelValue.value.map(item => ({ ...item, statusType: 1 }))) |
| | | arr.push(...afterModelValue.value.map(item => ({ ...item, type: 1 }))) |
| | | } |
| | | if (issueModelValue.value.length > 0) { |
| | | arr.push(...issueModelValue.value.map(item => ({ ...item, statusType: 2 }))) |
| | | arr.push(...issueModelValue.value.map(item => ({ ...item, type: 2 }))) |
| | | } |
| | | |
| | | // 提交数据 |
| | | infoData.value.storageBlobDTO = arr |
| | | await submitInspectionRecord({ ...infoData.value }) |
| | | await uploadInspectionTask({ ...infoData.value }) |
| | | |
| | | uni.showToast({ |
| | | title: '提交成功', |
| | |
| | | border-top: 1px solid #f0f0f0; |
| | | background-color: #fafafa; |
| | | } |
| | | |
| | | .upload-buttons { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .file-count { |
| | | font-size: 12px; |
| | | color: #999; |
| | | } |
| | | |
| | | .file-list { |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | .file-item { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 8px 0; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .file-item:last-child { |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .file-name { |
| | | font-size: 14px; |
| | | color: #333; |
| | | flex: 1; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | margin-right: 10px; |
| | | } |
| | | </style> |