gaoluyang
2025-09-24 752b14d2caa47ccceac328f79389fbf5e2e62ce4
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,32 @@
            <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">
              <ImageUpload
                v-model="form.storageBlobDTO"
                :limit="10"
                :fileSize="50"
                :fileType="['jpg', 'jpeg', 'png', 'mp4', 'mov']"
                :maxVideoDuration="60"
                :statusType="0"
                @update:modelValue="handleStorageBlobUpdate"
              />
            </view>
          </u-form-item>
          
          <u-form-item label="巡检人" prop="scannerName" labelWidth="80">
@@ -72,9 +81,10 @@
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue'
import { reactive, ref, onMounted, onUnmounted, nextTick } from 'vue'
import { addOrEditQrCodeRecord } from '@/api/inspectionUpload/index.js'
import useUserStore from '@/store/modules/user.ts'
import ImageUpload from '@/components/imageUpload/index.vue'
const emit = defineEmits(['closeDia'])
@@ -82,6 +92,10 @@
const formRef = ref(null)
const userStore = useUserStore()
const userInfo = ref({})
const locationLoading = ref(false)
// 请求取消标志
let isRequestCancelled = false
// 获取当前时间
function getCurrentDateTime() {
@@ -118,80 +132,204 @@
onMounted(async () => {
  try {
    const res = await userStore.getInfo()
    userInfo.value = res.user
    form.scannerName = userInfo.value.nickName
    form.scannerId = userInfo.value.userId
    form.scanTime = getCurrentDateTime()
    // 检查组件是否还存在
    if (!isRequestCancelled && userInfo.value !== undefined) {
      userInfo.value = res.user
      form.scannerName = userInfo.value.nickName
      form.scannerId = userInfo.value.userId
      form.scanTime = getCurrentDateTime()
    }
  } catch (error) {
    console.error('获取用户信息失败:', error)
  }
})
// 文件上传处理
const afterRead = (event) => {
  const { file } = event
// 处理storageBlobDTO数据更新
const handleStorageBlobUpdate = (value) => {
  form.storageBlobDTO = value || []
}
// 获取当前位置
const getCurrentLocation = () => {
  // 检查组件是否还存在
  if (isRequestCancelled) return
  
  // 上传文件到服务器
  uni.uploadFile({
    url: '/api/upload', // 替换为实际的上传接口
    filePath: file.url,
    name: 'file',
  locationLoading.value = true
  uni.showLoading({ title: '获取位置中...' })
  uni.getLocation({
    type: 'gcj02',
    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'
        })
      // 检查组件是否还存在
      if (isRequestCancelled) {
        uni.hideLoading()
        return
      }
      // 使用逆地理编码获取地址信息
      uni.request({
        url: `https://restapi.amap.com/v3/geocode/regeo?key=c120a5dc69a9f61839f7763e6057005f&location=${res.longitude},${res.latitude}&radius=1000&extensions=all`,
        success: (geoRes) => {
          // 检查组件是否还存在
          if (isRequestCancelled) {
            uni.hideLoading()
            return
          }
          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) => {
          // 检查组件是否还存在
          if (isRequestCancelled) {
            uni.hideLoading()
            return
          }
          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: () => {
    fail: (err) => {
      // 检查组件是否还存在
      if (isRequestCancelled) {
        uni.hideLoading()
        return
      }
      uni.hideLoading()
      locationLoading.value = false
      uni.showToast({
        title: '上传失败',
        title: '获取位置失败,请检查定位权限',
        icon: 'error'
      })
      console.error('获取位置失败:', err)
      // 失败时显示错误信息
      form.location = '位置获取失败'
    }
  })
}
// 删除文件
const deleteFile = (event) => {
  const { index } = event
  form.storageBlobDTO.splice(index, 1)
}
// 打开弹框
const openDialog = async (row) => {
  console.log('弹框接收到的数据:', row)
  dialogVisitable.value = true
  form.deviceName = row.deviceName || ''
  form.location = row.location || ''
  form.qrCodeId = row.qrCodeId || row.id || ''
  form.qrCodeId = row.qrCodeId
  form.storageBlobDTO = []
  console.log('弹框表单数据:', form)
  // 强制更新视图
  await nextTick()
  console.log('nextTick后弹框状态:', dialogVisitable.value)
}
// 提交表单
const submitForm = async () => {
  try {
    // 检查组件是否还存在
    if (isRequestCancelled) return
    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.map(file => ({
        id: file.id, // 添加id字段
        url: file.url,
        bucketFilename: file.bucketFilename || file.name,
        downloadUrl: file.downloadUrl || file.url,
        type: 0,
        size: file.size,
        createTime: file.createTime || new Date().getTime()
      })),
      qrCode: {
        id: form.qrCodeId
      }
    }
    console.log('准备提交的数据:', submitData)
    const response = await addOrEditQrCodeRecord(submitData)
    // 检查组件是否还存在
    if (isRequestCancelled) return
    console.log('提交响应:', response)
    
    uni.showToast({
      title: '提交成功',
@@ -200,10 +338,23 @@
    
    cancel()
  } catch (error) {
    // 检查组件是否还存在
    if (isRequestCancelled) return
    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
    })
  }
}
@@ -213,6 +364,25 @@
  dialogVisitable.value = false
  emit('closeDia')
}
// 组件销毁时的清理
onUnmounted(() => {
  // 设置取消标志,阻止后续的异步操作
  isRequestCancelled = true
  // 清理状态
  if (locationLoading.value) {
    locationLoading.value = false
  }
  // 关闭弹窗
  if (dialogVisitable.value) {
    dialogVisitable.value = false
  }
  // 隐藏可能显示的加载提示
  uni.hideLoading()
})
defineExpose({ openDialog })
</script>
@@ -251,4 +421,28 @@
  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%;
}
</style>