gaoluyang
2025-09-20 4b39710e41760807527cba66c248c0939c3427b0
巡检上传页面
已修改2个文件
398 ■■■■ 文件已修改
src/pages/inspectionUpload/components/qrCodeFormDia.vue 344 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/inspectionUpload/index.vue 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/inspectionUpload/components/qrCodeFormDia.vue
@@ -1,6 +1,6 @@
<template>
  <u-popup 
    v-model="dialogVisitable"
    :show="dialogVisitable"
    mode="center" 
    :round="10"
    :closeable="true"
@@ -26,23 +26,53 @@
            <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">
@@ -72,7 +102,7 @@
</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'
@@ -82,6 +112,7 @@
const formRef = ref(null)
const userStore = useUserStore()
const userInfo = ref({})
const locationLoading = ref(false)
// 获取当前时间
function getCurrentDateTime() {
@@ -130,37 +161,89 @@
// 文件上传处理
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'
      })
    }
@@ -173,25 +256,149 @@
  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: '提交成功',
@@ -201,9 +408,19 @@
    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
    })
  }
}
@@ -251,4 +468,35 @@
  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>
src/pages/inspectionUpload/index.vue
@@ -317,9 +317,11 @@
const startScan = async () => {
  try {
    scanLoading.value = true
    // 使用uniapp的扫码API
    uni.scanCode({
      success: (res) => {
        console.log('扫码成功:', res)
        handleScanSuccess(res)
      },
      fail: (err) => {
@@ -328,10 +330,14 @@
          title: '扫码失败',
          icon: 'error'
        })
      },
      complete: () => {
        scanLoading.value = false
      }
    })
  } catch (e) {
    console.error('启动扫码失败:', e)
    scanLoading.value = false
    uni.showToast({
      title: '启动扫码失败',
      icon: 'error'
@@ -346,6 +352,8 @@
// 扫码成功处理
const handleScanSuccess = async (result) => {
  try {
    console.log('处理扫码结果:', result)
    uni.showToast({
      title: '识别成功',
      icon: 'success'
@@ -355,12 +363,28 @@
    let qrData
    try {
      qrData = JSON.parse(result.result)
      console.log('解析的二维码数据:', qrData)
    } catch (e) {
      qrData = { deviceName: result.result, location: '' }
      // 如果不是JSON格式,直接使用扫码结果作为设备名称
      qrData = {
        deviceName: result.result,
        location: '',
        qrCodeId: result.result // 添加二维码ID
      }
      console.log('使用默认数据格式:', qrData)
    }
    // 确保数据完整性
    if (!qrData.deviceName) {
      qrData.deviceName = result.result
    }
    if (!qrData.qrCodeId) {
      qrData.qrCodeId = result.result
    }
    
    callBackendAPI(qrData)
  } catch (error) {
    console.error('处理扫码结果失败:', error)
    uni.showToast({
      title: error.message || '数据解析失败',
      icon: 'error'
@@ -369,11 +393,33 @@
}
const callBackendAPI = (result) => {
  nextTick(() => {
    qrCodeFormDia.value?.openDialog(result)
  })
  console.log('准备打开弹框,数据:', result)
  console.log('弹框组件引用:', qrCodeFormDia.value)
  // 确保组件引用存在
  if (qrCodeFormDia.value) {
    console.log('直接调用弹框openDialog方法')
    qrCodeFormDia.value.openDialog(result)
  } else {
    // 如果组件引用不存在,等待下一个tick
    console.log('组件引用不存在,等待nextTick')
    nextTick(() => {
      console.log('nextTick后弹框组件引用:', qrCodeFormDia.value)
      if (qrCodeFormDia.value) {
        console.log('nextTick后调用弹框openDialog方法')
        qrCodeFormDia.value.openDialog(result)
      } else {
        console.error('弹框组件引用不存在')
        uni.showToast({
          title: '弹框组件未准备好',
          icon: 'error'
        })
      }
    })
  }
}
// 扫码处理
const handleScanCode = (result) => {
  console.log('扫码结果:', result)