| | |
| | | <template> |
| | | <u-popup |
| | | v-model="dialogVisitable" |
| | | :show="dialogVisitable" |
| | | mode="center" |
| | | :round="10" |
| | | :closeable="true" |
| | |
| | | <u-input |
| | | v-model="form.location" |
| | | placeholder="请输入地点" |
| | | :maxlength="30" |
| | | :maxlength="100" |
| | | :disabled="true" |
| | | /> |
| | | > |
| | | <template #suffix> |
| | | <u-icon |
| | | name="map" |
| | | @click="getCurrentLocation" |
| | | class="location-icon" |
| | | :class="{ 'loading': locationLoading }" |
| | | /> |
| | | </template> |
| | | </u-input> |
| | | </u-form-item> |
| | | |
| | | <u-form-item label="附件" prop="storageBlobDTO" labelWidth="80"> |
| | | <u-upload |
| | | :fileList="form.storageBlobDTO" |
| | | @afterRead="afterRead" |
| | | @delete="deleteFile" |
| | | name="files" |
| | | multiple |
| | | :maxCount="10" |
| | | :maxSize="1024 * 1024" |
| | | accept="video/*" |
| | | :previewFullImage="true" |
| | | ></u-upload> |
| | | <view class="upload-container"> |
| | | <u-upload |
| | | :fileList="form.storageBlobDTO" |
| | | @afterRead="afterRead" |
| | | @delete="deleteFile" |
| | | name="files" |
| | | multiple |
| | | :maxCount="10" |
| | | :maxSize="50 * 1024 * 1024" |
| | | accept="image/*,video/*" |
| | | :previewFullImage="true" |
| | | :camera="true" |
| | | :gallery="true" |
| | | ></u-upload> |
| | | <view class="upload-actions"> |
| | | <u-button |
| | | type="primary" |
| | | size="small" |
| | | @click="chooseImage" |
| | | :customStyle="{ marginRight: '10px' }" |
| | | > |
| | | 拍照 |
| | | </u-button> |
| | | <u-button |
| | | type="success" |
| | | size="small" |
| | | @click="chooseVideo" |
| | | > |
| | | 录像 |
| | | </u-button> |
| | | </view> |
| | | </view> |
| | | </u-form-item> |
| | | |
| | | <u-form-item label="巡检人" prop="scannerName" labelWidth="80"> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { reactive, ref, onMounted } from 'vue' |
| | | import { reactive, ref, onMounted, nextTick } from 'vue' |
| | | import { addOrEditQrCodeRecord } from '@/api/inspectionUpload/index.js' |
| | | import useUserStore from '@/store/modules/user.ts' |
| | | |
| | |
| | | const formRef = ref(null) |
| | | const userStore = useUserStore() |
| | | const userInfo = ref({}) |
| | | const locationLoading = ref(false) |
| | | |
| | | // 获取当前时间 |
| | | function getCurrentDateTime() { |
| | |
| | | // 文件上传处理 |
| | | const afterRead = (event) => { |
| | | const { file } = event |
| | | console.log('文件选择:', file) |
| | | |
| | | // 上传文件到服务器 |
| | | uni.uploadFile({ |
| | | url: '/api/upload', // 替换为实际的上传接口 |
| | | filePath: file.url, |
| | | name: 'file', |
| | | // 直接添加到文件列表,不上传到服务器 |
| | | const fileItem = { |
| | | url: file.url, |
| | | name: file.name || `文件_${Date.now()}`, |
| | | status: 'success', |
| | | size: file.size || 0, |
| | | type: file.type || 'image/jpeg' |
| | | } |
| | | |
| | | form.storageBlobDTO.push(fileItem) |
| | | |
| | | uni.showToast({ |
| | | title: '文件添加成功', |
| | | icon: 'success' |
| | | }) |
| | | } |
| | | |
| | | // 拍照 |
| | | const chooseImage = () => { |
| | | uni.chooseImage({ |
| | | count: 1, |
| | | sizeType: ['original', 'compressed'], |
| | | sourceType: ['camera'], |
| | | success: (res) => { |
| | | const data = JSON.parse(res.data) |
| | | if (data.code === 200) { |
| | | const fileItem = { |
| | | url: data.data.url, |
| | | name: file.name, |
| | | status: 'success' |
| | | } |
| | | |
| | | form.storageBlobDTO.push(fileItem) |
| | | |
| | | uni.showToast({ |
| | | title: '上传成功', |
| | | icon: 'success' |
| | | }) |
| | | } else { |
| | | uni.showToast({ |
| | | title: '上传失败', |
| | | icon: 'error' |
| | | }) |
| | | console.log('拍照成功:', res) |
| | | const tempFilePath = res.tempFilePaths[0] |
| | | |
| | | const fileItem = { |
| | | url: tempFilePath, |
| | | name: `照片_${Date.now()}.jpg`, |
| | | status: 'success', |
| | | type: 'image/jpeg' |
| | | } |
| | | }, |
| | | fail: () => { |
| | | |
| | | form.storageBlobDTO.push(fileItem) |
| | | |
| | | uni.showToast({ |
| | | title: '上传失败', |
| | | title: '拍照成功', |
| | | icon: 'success' |
| | | }) |
| | | }, |
| | | fail: (err) => { |
| | | console.error('拍照失败:', err) |
| | | uni.showToast({ |
| | | title: '拍照失败', |
| | | icon: 'error' |
| | | }) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 录像 |
| | | const chooseVideo = () => { |
| | | uni.chooseVideo({ |
| | | sourceType: ['camera'], |
| | | maxDuration: 60, // 最大60秒 |
| | | camera: 'back', |
| | | success: (res) => { |
| | | console.log('录像成功:', res) |
| | | const tempFilePath = res.tempFilePath |
| | | |
| | | const fileItem = { |
| | | url: tempFilePath, |
| | | name: `视频_${Date.now()}.mp4`, |
| | | status: 'success', |
| | | type: 'video/mp4', |
| | | duration: res.duration, |
| | | size: res.size |
| | | } |
| | | |
| | | form.storageBlobDTO.push(fileItem) |
| | | |
| | | uni.showToast({ |
| | | title: '录像成功', |
| | | icon: 'success' |
| | | }) |
| | | }, |
| | | fail: (err) => { |
| | | console.error('录像失败:', err) |
| | | uni.showToast({ |
| | | title: '录像失败', |
| | | icon: 'error' |
| | | }) |
| | | } |
| | |
| | | form.storageBlobDTO.splice(index, 1) |
| | | } |
| | | |
| | | // 获取当前位置 |
| | | const getCurrentLocation = () => { |
| | | locationLoading.value = true |
| | | uni.showLoading({ title: '获取位置中...' }) |
| | | |
| | | uni.getLocation({ |
| | | type: 'gcj02', |
| | | success: (res) => { |
| | | // 使用逆地理编码获取地址信息 |
| | | uni.request({ |
| | | url: `https://restapi.amap.com/v3/geocode/regeo?key=c120a5dc69a9f61839f7763e6057005f&location=${res.longitude},${res.latitude}&radius=1000&extensions=all`, |
| | | success: (geoRes) => { |
| | | uni.hideLoading() |
| | | locationLoading.value = false |
| | | |
| | | if (geoRes.data.status === '1' && geoRes.data.regeocode) { |
| | | const regeocode = geoRes.data.regeocode |
| | | const address = regeocode.formatted_address |
| | | |
| | | // 优先显示详细地址 |
| | | if (address) { |
| | | form.location = address |
| | | uni.showToast({ |
| | | title: '位置获取成功', |
| | | icon: 'success' |
| | | }) |
| | | } else { |
| | | // 如果没有详细地址,尝试组合地址信息 |
| | | const addressComponent = regeocode.addressComponent |
| | | const combinedAddress = `${addressComponent.province}${addressComponent.city}${addressComponent.district}${addressComponent.township}` |
| | | form.location = combinedAddress |
| | | uni.showToast({ |
| | | title: '位置获取成功', |
| | | icon: 'success' |
| | | }) |
| | | } |
| | | } else { |
| | | // API调用成功但没有返回地址信息 |
| | | const fallbackAddress = `位置: ${res.latitude.toFixed(4)}, ${res.longitude.toFixed(4)}` |
| | | form.location = fallbackAddress |
| | | uni.showToast({ |
| | | title: '获取到位置,但地址解析失败', |
| | | icon: 'none' |
| | | }) |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | uni.hideLoading() |
| | | locationLoading.value = false |
| | | console.error('逆地理编码失败:', err) |
| | | |
| | | // 逆地理编码失败时,显示简化的位置信息 |
| | | const fallbackAddress = `位置: ${res.latitude.toFixed(4)}, ${res.longitude.toFixed(4)}` |
| | | form.location = fallbackAddress |
| | | uni.showToast({ |
| | | title: '位置获取成功,但地址解析失败', |
| | | icon: 'none' |
| | | }) |
| | | } |
| | | }) |
| | | }, |
| | | fail: (err) => { |
| | | uni.hideLoading() |
| | | locationLoading.value = false |
| | | uni.showToast({ |
| | | title: '获取位置失败,请检查定位权限', |
| | | icon: 'error' |
| | | }) |
| | | console.error('获取位置失败:', err) |
| | | |
| | | // 失败时显示错误信息 |
| | | form.location = '位置获取失败' |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 打开弹框 |
| | | const openDialog = async (row) => { |
| | | console.log('弹框接收到的数据:', row) |
| | | console.log('弹框打开前状态:', dialogVisitable.value) |
| | | |
| | | dialogVisitable.value = true |
| | | form.deviceName = row.deviceName || '' |
| | | form.location = row.location || '' |
| | | form.qrCodeId = row.qrCodeId || row.id || '' |
| | | form.storageBlobDTO = [] |
| | | |
| | | console.log('弹框打开后状态:', dialogVisitable.value) |
| | | console.log('弹框表单数据:', form) |
| | | |
| | | // 强制更新视图 |
| | | await nextTick() |
| | | console.log('nextTick后弹框状态:', dialogVisitable.value) |
| | | } |
| | | |
| | | // 提交表单 |
| | | const submitForm = async () => { |
| | | try { |
| | | console.log('开始提交表单,当前表单数据:', form) |
| | | |
| | | // 表单验证 |
| | | const valid = await formRef.value.validate() |
| | | if (!valid) return |
| | | if (formRef.value) { |
| | | const valid = await formRef.value.validate() |
| | | if (!valid) { |
| | | console.log('表单验证失败') |
| | | return |
| | | } |
| | | } |
| | | |
| | | form.qrCode.id = form.qrCodeId |
| | | // 检查必填字段 |
| | | if (!form.deviceName) { |
| | | uni.showToast({ |
| | | title: '请输入设备名称', |
| | | icon: 'error' |
| | | }) |
| | | return |
| | | } |
| | | |
| | | await addOrEditQrCodeRecord({ ...form }) |
| | | if (!form.location) { |
| | | uni.showToast({ |
| | | title: '请获取位置信息', |
| | | icon: 'error' |
| | | }) |
| | | return |
| | | } |
| | | |
| | | // 准备提交数据 |
| | | const submitData = { |
| | | deviceName: form.deviceName, |
| | | location: form.location, |
| | | scannerName: form.scannerName, |
| | | scannerId: form.scannerId, |
| | | scanTime: form.scanTime, |
| | | storageBlobDTO: form.storageBlobDTO, |
| | | qrCode: { |
| | | id: form.qrCodeId || form.qrCode.id |
| | | } |
| | | } |
| | | |
| | | console.log('准备提交的数据:', submitData) |
| | | |
| | | const response = await addOrEditQrCodeRecord(submitData) |
| | | console.log('提交响应:', response) |
| | | |
| | | uni.showToast({ |
| | | title: '提交成功', |
| | |
| | | cancel() |
| | | } catch (error) { |
| | | console.error('提交失败:', error) |
| | | |
| | | // 显示更详细的错误信息 |
| | | let errorMessage = '提交失败' |
| | | if (error.response) { |
| | | errorMessage = error.response.data?.message || `服务器错误: ${error.response.status}` |
| | | } else if (error.message) { |
| | | errorMessage = error.message |
| | | } |
| | | |
| | | uni.showToast({ |
| | | title: '提交失败', |
| | | icon: 'error' |
| | | title: errorMessage, |
| | | icon: 'error', |
| | | duration: 3000 |
| | | }) |
| | | } |
| | | } |
| | |
| | | border-top: 1px solid #f0f0f0; |
| | | background-color: #fafafa; |
| | | } |
| | | |
| | | .location-icon { |
| | | color: #1890ff; |
| | | cursor: pointer; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .location-icon:hover { |
| | | color: #40a9ff; |
| | | } |
| | | |
| | | .location-icon.loading { |
| | | color: #999; |
| | | animation: spin 1s linear infinite; |
| | | } |
| | | |
| | | @keyframes spin { |
| | | from { transform: rotate(0deg); } |
| | | to { transform: rotate(360deg); } |
| | | } |
| | | |
| | | .upload-container { |
| | | width: 100%; |
| | | } |
| | | |
| | | .upload-actions { |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | margin-top: 10px; |
| | | gap: 10px; |
| | | } |
| | | </style> |