| | |
| | | > |
| | | <view class="popup-content"> |
| | | <view class="popup-header"> |
| | | <text class="popup-title">上传</text> |
| | | <text class="popup-title">巡检记录上传</text> |
| | | </view> |
| | | |
| | | <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="title">巡检状态</view> |
| | | <view class="exception-section"> |
| | | <view class="exception-options"> |
| | | <view |
| | | class="exception-option" |
| | | :class="{ active: hasException === false }" |
| | | @click="setExceptionStatus(false)" |
| | | > |
| | | <u-icon name="checkmark-circle" size="20" color="#52c41a"></u-icon> |
| | | <text class="option-text">正常</text> |
| | | </view> |
| | | <view |
| | | class="exception-option" |
| | | :class="{ active: hasException === true }" |
| | | @click="setExceptionStatus(true)" |
| | | > |
| | | <u-icon name="close-circle" size="20" color="#ff4d4f"></u-icon> |
| | | <text class="option-text">存在异常</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 异常描述(仅在异常时显示) --> |
| | | <view class="form-container" v-if="hasException === true"> |
| | | <view class="title">异常描述</view> |
| | | <u-input |
| | | v-model="exceptionDescription" |
| | | type="textarea" |
| | | :maxlength="500" |
| | | placeholder="请描述异常情况..." |
| | | :customStyle="{ padding: '10px', backgroundColor: '#f5f5f5' }" |
| | | /> |
| | | </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> |
| | | |
| | | <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> |
| | | <!-- 上传区域(仅在异常时显示) --> |
| | | <template v-if="hasException === true"> |
| | | <view class="form-container"> |
| | | <view class="title">生产前</view> |
| | | <u-upload |
| | | :fileList="beforeModelValue" |
| | | @afterRead="afterRead" |
| | | @delete="deleteFile" |
| | | name="before" |
| | | multiple |
| | | :maxCount="10" |
| | | :maxSize="5 * 1024 * 1024" |
| | | accept="image/*" |
| | | :previewFullImage="true" |
| | | ></u-upload> |
| | | </view> |
| | | |
| | | <view class="form-container"> |
| | | <view class="title">生产后</view> |
| | | <u-upload |
| | | :fileList="afterModelValue" |
| | | @afterRead="afterRead" |
| | | @delete="deleteFile" |
| | | name="after" |
| | | multiple |
| | | :maxCount="10" |
| | | :maxSize="5 * 1024 * 1024" |
| | | accept="image/*" |
| | | :previewFullImage="true" |
| | | ></u-upload> |
| | | </view> |
| | | |
| | | <view class="form-container"> |
| | | <view class="title">生产问题</view> |
| | | <u-upload |
| | | :fileList="issueModelValue" |
| | | @afterRead="afterRead" |
| | | @delete="deleteFile" |
| | | name="issue" |
| | | multiple |
| | | :maxCount="10" |
| | | :maxSize="5 * 1024 * 1024" |
| | | accept="image/*" |
| | | :previewFullImage="true" |
| | | ></u-upload> |
| | | </view> |
| | | </template> |
| | | |
| | | <!-- 正常状态提示 --> |
| | | <view class="form-container normal-tip" v-if="hasException === false"> |
| | | <u-icon name="info-circle" size="40" color="#52c41a"></u-icon> |
| | | <text class="tip-text">设备运行正常,无需上传照片</text> |
| | | </view> |
| | | </view> |
| | | |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue' |
| | | import { ref, computed } from 'vue' |
| | | import { submitInspectionRecord } from '@/api/equipmentManagement/inspection.js' |
| | | import { getToken } from '@/utils/auth' |
| | | import config from '@/config' |
| | | |
| | | const emit = defineEmits(['closeDia']) |
| | | |
| | |
| | | const issueModelValue = ref([]) |
| | | const infoData = ref(null) |
| | | |
| | | // 异常状态:null=未选择, false=正常, true=异常 |
| | | const hasException = ref(null) |
| | | // 异常描述 |
| | | const exceptionDescription = ref('') |
| | | |
| | | // 计算上传URL |
| | | const uploadFileUrl = computed(() => { |
| | | let baseUrl = ''; |
| | | |
| | | if (process.env.VUE_APP_BASE_API) { |
| | | baseUrl = process.env.VUE_APP_BASE_API; |
| | | } else { |
| | | baseUrl = config.baseUrl; |
| | | } |
| | | |
| | | return baseUrl + '/file/upload'; |
| | | }) |
| | | |
| | | const uploadSingleFile = async (fileItem, typeValue) => { |
| | | const token = getToken() |
| | | if (!token) throw new Error('用户未登录') |
| | | |
| | | // H5: u-upload 可能给原生 File(fileItem.file) |
| | | const rawFile = fileItem?.file |
| | | if (rawFile) { |
| | | const formData = new FormData() |
| | | formData.append('file', rawFile, rawFile.name || 'image.jpg') |
| | | formData.append('type', String(typeValue)) |
| | | const res = await fetch(uploadFileUrl.value, { |
| | | method: 'POST', |
| | | headers: { Authorization: 'Bearer ' + token }, |
| | | body: formData |
| | | }) |
| | | const data = await res.json() |
| | | if (data?.code !== 200) throw new Error(data?.msg || '上传失败') |
| | | return { |
| | | url: data?.data?.url, |
| | | name: rawFile.name || 'image.jpg', |
| | | status: 'success' |
| | | } |
| | | } |
| | | |
| | | // 非 H5 / 兼容:走 uni.uploadFile |
| | | return await new Promise((resolve, reject) => { |
| | | uni.uploadFile({ |
| | | url: uploadFileUrl.value, |
| | | filePath: fileItem.url, |
| | | name: 'file', |
| | | header: { |
| | | 'Authorization': `Bearer ${token}` |
| | | }, |
| | | formData: { |
| | | type: typeValue |
| | | }, |
| | | success: (res) => { |
| | | try { |
| | | const data = JSON.parse(res.data) |
| | | if (data.code === 200) { |
| | | resolve({ |
| | | url: data.data.url, |
| | | name: fileItem.name, |
| | | status: 'success' |
| | | }) |
| | | } else { |
| | | reject(new Error(data.msg || '上传失败')) |
| | | } |
| | | } catch (e) { |
| | | reject(e) |
| | | } |
| | | }, |
| | | fail: (err) => reject(err) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 文件上传处理 |
| | | const afterRead = (event) => { |
| | | const { name, file } = event |
| | | |
| | | // 上传文件到服务器 |
| | | uni.uploadFile({ |
| | | url: '/api/upload', // 替换为实际的上传接口 |
| | | filePath: file.url, |
| | | name: 'file', |
| | | success: (res) => { |
| | | const data = JSON.parse(res.data) |
| | | if (data.code === 200) { |
| | | const fileItem = { |
| | | url: data.data.url, |
| | | name: file.name, |
| | | status: 'success' |
| | | } |
| | | |
| | | // 根据name添加到对应的数组 |
| | | if (name === 'before') { |
| | | beforeModelValue.value.push(fileItem) |
| | | } else if (name === 'after') { |
| | | afterModelValue.value.push(fileItem) |
| | | } else if (name === 'issue') { |
| | | issueModelValue.value.push(fileItem) |
| | | } |
| | | |
| | | uni.showToast({ |
| | | title: '上传成功', |
| | | icon: 'success' |
| | | }) |
| | | } else { |
| | | uni.showToast({ |
| | | title: '上传失败', |
| | | icon: 'error' |
| | | }) |
| | | // 根据上传类型设置不同的type值 |
| | | let typeValue = 10 // 默认值 |
| | | if (name === 'before') { |
| | | typeValue = 10 // 生产前 |
| | | } else if (name === 'after') { |
| | | typeValue = 11 // 生产中 |
| | | } else if (name === 'issue') { |
| | | typeValue = 12 // 生产后 |
| | | } |
| | | |
| | | const files = Array.isArray(file) ? file : [file] |
| | | Promise.resolve().then(async () => { |
| | | for (const f of files) { |
| | | const uploaded = await uploadSingleFile(f, typeValue) |
| | | if (name === 'before') { |
| | | beforeModelValue.value.push(uploaded) |
| | | } else if (name === 'after') { |
| | | afterModelValue.value.push(uploaded) |
| | | } else if (name === 'issue') { |
| | | issueModelValue.value.push(uploaded) |
| | | } |
| | | }, |
| | | fail: () => { |
| | | uni.showToast({ |
| | | title: '上传失败', |
| | | icon: 'error' |
| | | }) |
| | | } |
| | | uni.showToast({ title: '上传成功', icon: 'success' }) |
| | | }).catch((err) => { |
| | | console.error('上传失败:', err) |
| | | uni.showToast({ title: '上传失败', icon: 'error' }) |
| | | }) |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | // 设置异常状态 |
| | | const setExceptionStatus = (status) => { |
| | | hasException.value = status |
| | | } |
| | | |
| | | // 提交表单 |
| | | const submitForm = async () => { |
| | | try { |
| | | // 检查是否选择了巡检状态 |
| | | if (hasException.value === null) { |
| | | uni.showToast({ |
| | | title: '请选择巡检状态', |
| | | icon: 'none' |
| | | }) |
| | | return |
| | | } |
| | | |
| | | // 如果是异常状态,检查是否有上传文件 |
| | | if (hasException.value === true) { |
| | | const totalFiles = beforeModelValue.value.length + afterModelValue.value.length + issueModelValue.value.length |
| | | if (totalFiles === 0) { |
| | | uni.showToast({ |
| | | title: '请上传异常照片', |
| | | icon: 'none' |
| | | }) |
| | | return |
| | | } |
| | | // 检查是否填写了异常描述 |
| | | if (!exceptionDescription.value.trim()) { |
| | | uni.showToast({ |
| | | title: '请填写异常描述', |
| | | icon: 'none' |
| | | }) |
| | | return |
| | | } |
| | | } |
| | | |
| | | let arr = [] |
| | | if (beforeModelValue.value.length > 0) { |
| | | arr.push(...beforeModelValue.value.map(item => ({ ...item, statusType: 0 }))) |
| | |
| | | |
| | | // 提交数据 |
| | | infoData.value.storageBlobDTO = arr |
| | | infoData.value.hasException = hasException.value |
| | | infoData.value.exceptionDescription = exceptionDescription.value |
| | | await submitInspectionRecord({ ...infoData.value }) |
| | | |
| | | uni.showToast({ |
| | |
| | | beforeModelValue.value = [] |
| | | afterModelValue.value = [] |
| | | issueModelValue.value = [] |
| | | hasException.value = null |
| | | exceptionDescription.value = '' |
| | | } |
| | | |
| | | // 关闭弹框 |
| | |
| | | border-top: 1px solid #f0f0f0; |
| | | background-color: #fafafa; |
| | | } |
| | | |
| | | // 异常状态选择样式 |
| | | .exception-section { |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | .exception-options { |
| | | display: flex; |
| | | gap: 15px; |
| | | } |
| | | |
| | | .exception-option { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 8px; |
| | | padding: 15px 20px; |
| | | border: 2px solid #e0e0e0; |
| | | border-radius: 8px; |
| | | cursor: pointer; |
| | | transition: all 0.3s; |
| | | background-color: #fff; |
| | | |
| | | &.active { |
| | | border-color: #1890ff; |
| | | background-color: #e6f7ff; |
| | | } |
| | | |
| | | &:active { |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | |
| | | .option-text { |
| | | font-size: 14px; |
| | | color: #333; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | // 正常状态提示样式 |
| | | .normal-tip { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 40px 20px; |
| | | background-color: #f6ffed; |
| | | border: 1px dashed #b7eb8f; |
| | | border-radius: 8px; |
| | | |
| | | .tip-text { |
| | | margin-top: 15px; |
| | | font-size: 14px; |
| | | color: #52c41a; |
| | | } |
| | | } |
| | | </style> |