<template>
  <div
    class="inputs ht-picture"
    :class="[
      'inputs',
      formInputsDisplay == 'block'
        ? 'ht-form-inputs__block'
        : 'ht-form-inputs__inline',
      isMobile ? 'mobile-picture' : '',
    ]"
  >
    <file-upload
      v-if="uploadType === 'local' && inputWriteable && !userAgentMobile"
      ref="fileUpload"
      v-model="inputVal"
      class="ht-picture-upload"
      :action-url="actionUrlVal"
      :header="headerVal"
      :on-success="handleSuccess"
      :on-progress="onProgress"
      :before-upload="beforeImgUpload"
      :multiple="multiple"
      :limit="limit"
      :size="fileSize"
      :accept="accept"
      :show-file-list="false"
      :with-credentials="withCredentials"
      :on-exceed="handleExceed"
      :upload-button-name="t('ht.picture.uploadButtonText')"
      @clear="handleClear"
    />
    <div
      class="ht-picture_box"
      :class="{
        'ht-picture__web-box': uploadType == 'web',
        'has-img': imgList.length,
        'mobile-picture-box': isMobile,
      }"
    >
      <!-- 上传网络图片 -->
      <div v-if="uploadType == 'web' && inputWriteable" class="btn-wrap">
        <el-button size="mini" round icon="el-icon-plus" @click="openDialog">
          {{ t('ht.picture.uploadButtonText') }}
        </el-button>

        <el-popconfirm
          v-if="imgList.length"
          class="pop-confirm-btn"
          :title="t('ht.picture.deleteTip', { clear: t('ht.common.clear') })"
          @confirm="handleClear"
        >
          <el-button slot="reference" icon="el-icon-delete" round size="mini">
            {{ t('ht.common.clear') }}
          </el-button>
        </el-popconfirm>
      </div>
      <!-- 移动端本地图片 -->
      <div v-if="!!imgList.length" class="image-card-box">
        <el-card
          v-for="(item, index) of imgList"
          :key="item.uid"
          class="ht-picture__card"
          :alt="t('ht.picture.viewOriginalImage')"
          :body-style="bodyStyle"
        >
          <el-image
            :key="index"
            v-loading="loading"
            :src="item.url || getCurrentImgSrc(item)"
            :preview-src-list="srcList"
            class="ht-picture__item-img"
          />
          <div v-if="!isMobile" class="ht-picture__footer">
            <div
              class="ht-picture__name hover-follow-theme-color"
              :title="item.name || item.fileName"
            >
              <template v-if="openUrl">
                <a href="javascript:void(0);" @click="hrefClick()">
                  {{ item.name || item.fileName }}
                </a>
              </template>
              <template v-else>
                {{ item.name || item.fileName }}
              </template>
            </div>
            <div class="ht-picture__footer-btn">
              <i
                v-if="uploadType === 'local' && downloadable"
                class="el-icon-download ht-picture__download follow-theme-color hover-follow-theme-color"
                @click="downloadPicture(item)"
              />

              <el-popconfirm
                v-if="inputWriteable"
                :title="
                  t('ht.picture.deleteTip', { clear: t('ht.common.clear') })
                "
                @confirm="handleDelete(item)"
              >
                <i
                  slot="reference"
                  class="el-icon-error ht-picture_delete"
                  circle
                />
              </el-popconfirm>
            </div>
          </div>
          <!-- 移动端删除 -->
          <div
            v-if="inputWriteable && isMobile"
            class="mobile-delete"
            @click="handleDelete(item)"
          >
            <i class="el-icon-close mobile-cls-close"></i>
          </div>
        </el-card>
      </div>
      <div
        v-if="
          inputWriteable &&
          uploadType === 'local' &&
          userAgentMobile &&
          isMobile
        "
        class="ht-picture__mobile"
      >
        <input
          id="upload"
          ref="mobilePicRef"
          class="ht-picture__hide-input"
          type="file"
          accept="image/*"
          :capture="fieldSource === 'camera' ? 'camera' : undefined"
          :multiple="multiple"
          @change="handlePicChange($event)"
        />

        <!-- 移动端 -->
        <div>
          <div
            v-if="userAgentMobile && uploadType == 'local'"
            class="mobile-puls"
            @click="clickPicture"
          >
            <i
              class="van-icon van-icon-photograph van-uploader__upload-icon"
            ></i>
            <div v-if="uploadLoading" class="van-uploader__mask">
              <van-loading size="22" />
              <div class="van-uploader__mask-message">上传中...</div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <input
      v-model="value"
      v-validate="inputValidate"
      type="hidden"
      :name="inputName"
      :data-vv-as="name"
    />

    <ht-field-tail
      :writeable.sync="inputWriteable"
      :field-name="inputName"
      :input-value="value"
    />
    <el-dialog
      v-if="dialogFormVisible"
      :visible.sync="dialogFormVisible"
      :title="t('ht.picture.uploadWebImg')"
      :close-on-click-modal="false"
      :width="userAgentMobile ? '85%' : '50%'"
      :custom-class="isMobileClass"
      :append-to-body="appendToBody"
    >
      <el-form
        ref="webImgFormRef"
        :model="webImages"
        data-vv-scope="webImgFrom"
      >
        <ht-form-item
          :label="t('ht.picture.imgName')"
          label-width="100px"
          :class="{ 'mobile-picture__form-item': userAgentMobile }"
        >
          <ht-input
            v-model="webImages.fileName"
            style="width: 100%"
            :placeholder="t('ht.picture.imgNamePlaceHolder')"
            validate="required"
          />
        </ht-form-item>
        <ht-form-item
          :label="t('ht.picture.imgUrl')"
          label-width="100px"
          :class="{ 'mobile-picture__form-item': userAgentMobile }"
        >
          <ht-input
            v-model="webImages.url"
            style="width: 100%"
            :placeholder="t('ht.picture.imgUrlPlaceHolder')"
            validate="required"
          />
        </ht-form-item>
        <div
          class="ht-dialog-footer"
          :class="{ 'mobile-dialog-footer': userAgentMobile }"
        >
          <el-button
            type="primary"
            size="small"
            class="submit-button"
            :loading="btnLoading"
            @click="handleSubmit"
          >
            {{ t('ht.common.confirm') }}
          </el-button>
          <el-button size="small" @click="dialogFormVisible = false">
            {{ t('ht.common.close') }}
          </el-button>
        </div>
      </el-form>
    </el-dialog>
  </div>
</template>
<script>
  import permission from '@/mixins/permission.js'
  import mobileMode from '@/mixins/mobileMode.js'
  import locale from '@/mixins/locale.js'
  import form from '@/mixins/form.js'

  import fileUpload from '../../FileUpload'
  import inputName from '@/mixins/inputName.js'

  const { saveAs } = require('file-saver')
  import { createObjectURL } from '@/util/brower.js'
  import utils from '@/utils.js'
  import _ from 'lodash'
  import { compress } from 'image-conversion'
  import { lazyAMapApiLoaderInstance } from 'vue-amap'
  export default {
    name: 'HtPicture',
    components: {
      fileUpload,
    },
    mixins: [permission, mobileMode, locale, inputName, form],
    props: {
      compress: {
        type: Boolean,
        default: false,
      },
      value: {
        type: String,
      },
      withCredentials: {
        type: Boolean,
        default: false,
      },
      uploadType: {
        type: String,
        default: '',
        validator: (val) => (val ? ['web', 'local'].includes(val) : true),
      },
      actionUrl: {
        type: String,
        default: '',
      },
      headers: Object,
      imgHeight: [String, Number],
      imgWidth: [String, Number],
      limit: Number,
      multiple: {
        type: Boolean,
        default: true,
      },
      allowPreview: {
        type: Boolean,
        default: false,
      },
      allowDownload: {
        type: Boolean,
        default: false,
      },
      fileSize: {
        type: Number,
        default: 6,
      },
      bodyStyle: {
        type: Object,
        default: () => {
          return {
            // padding: '10px',
            // cursor: 'pointer',
          }
        },
      },
      onProgress: Function,
      openUrl: {
        type: String,
        default: '',
      },
      flowData: {
        type: Object,
        default: () => {
          return {}
        },
      },
      appendToBody: {
        type: Boolean,
        default: true,
      },
      pushKm: {
        type: Number,
        default: 0,
      },
      kmFolderId: {
        type: String,
        default: '',
      },
      fieldSource: {
        //图片来源 camera unlimited
        type: String,
        default: 'unlimited',
      },
      fieldSourceOptions: {
        //和图片来源的takePicture绑定  信息追加 date address
        type: String,
        default: '',
      },
    },
    data() {
      return {
        imgList: [], //上传成功展示图片列表
        dialogFormVisible: false,
        srcList: [], //图片预览url列表
        webImages: {
          fileName: '',
          url: '',
        },
        accept: 'jpg,png,gif,ico,jpeg,GPG,PNG,GIF,JPEG',
        refreshFileUploadDebounce: _.debounce(this.refreshFileUpload, 200),
        loading: false,
        btnLoading: false,
        compressConfig: 0.3,
        uploadLoading: false,
        address: '', //图片地址
      }
    },
    computed: {
      inputVal: {
        get() {
          let imgValue = []
          if (utils.isEmpty(this.value)) {
            imgValue = []
          } else if (
            this.value.constructor == String &&
            utils.isJSON(this.value)
          ) {
            imgValue = [...JSON.parse(this.value)]
          }
          return imgValue
        },
        set() {},
      },
      downloadable() {
        return this.inputWriteable || this.allowDownload
      },
      preview() {
        return this.inputWriteable || this.allowPreview
      },
      style() {
        return {
          width: `${this.imgWidth || ''}px`,
          height: `${this.imgHeight || ''}px`,
        }
      },
      isUpload() {
        return !['r', 'n'].includes(this.permission)
      },
      isMobileClass() {
        return this.userAgentMobile ? 'is-mobile' : 'form-dialog'
      },
      actionUrlVal: function () {
        return this.actionUrl
          ? this.actionUrl
          : this.pushKm
          ? this.$requestConfig.kmUploadUrl + `?folderId=${this.kmFolderId}`
          : this.$requestConfig.uploadUrl
          ? this.handlerUploadUrl
          : 'https://jsonplaceholder.typicode.com/posts/'
      },
      handlerUploadUrl() {
        const baseUrl = this.$requestConfig.uploadUrl
        if (!this.flowData.defId) {
          return baseUrl
        }
        const indexOfMark = baseUrl.indexOf('?')
        if (indexOfMark == -1) {
          return `${baseUrl}?defId=${this.flowData.defId}`
        }
        if (indexOfMark > -1 && indexOfMark == baseUrl.length - 1) {
          return `${baseUrl}defId=${this.flowData.defId}`
        }
        if (indexOfMark > -1 && indexOfMark < baseUrl.length - 1) {
          return `${baseUrl}&defId=${this.flowData.defId}`
        }
        return baseUrl
      },
      headerVal: function () {
        return this.headers
          ? this.headers
          : this.$requestConfig.header
          ? this.$requestConfig.header()
          : null
      },
      fieldSourceOptionsObj() {
        if (this.fieldSourceOptions) {
          const parsed = utils.parseToJson(this.fieldSourceOptions)
          return {
            address: Boolean(
              parsed.address === 'true' || parsed.address === true
            ),
            date: Boolean(parsed.date === 'true' || parsed.date === true),
          }
        }
        return {
          address: false,
          date: false,
        }
      },
    },
    watch: {
      imgList: {
        handler() {
          this.syncSrcList()
        },
        deep: true,
        immediate: true,
      },
      value(val) {
        if (val) {
          this.initData()
        } else {
          this.imgList = []
        }
      },
    },
    mounted() {
      if (this.isMobile) {
        this.addMobileTopLabelClass()
      }
      if (this.value) {
        this.initData()
      }
      this.$nextTick(async () => {
        if (this.fieldSource == 'camera') {
          this.$initAMapApiLoader()
          await lazyAMapApiLoaderInstance.load().then(() => {
            this.autoLocate() // 页面加载后自动定位
          })
        }
      })
    },
    methods: {
      initData() {
        const currentImgList =
          this.value.constructor == String ? JSON.parse(this.value) : this.value
        if (currentImgList.constructor == Array && currentImgList.length > -1) {
          this.updateImgListWithCurrentImgList(currentImgList)
        }
      },
      // 比对原来的图片数组和现在的图片数组，如果元素相同时把原图片中url属性复制过来，避免图片反复加载。
      updateImgListWithCurrentImgList(currentImgList) {
        if (
          !this.imgList ||
          this.imgList.length == 0 ||
          !currentImgList ||
          currentImgList.length == 0
        ) {
          this.imgList = currentImgList
        } else {
          currentImgList.forEach((m) => {
            const oldItem = this.imgList.find(
              (n) =>
                m.uid === n.uid ||
                (m.response &&
                  n.response &&
                  m.response.fileId == n.response.fileId)
            )
            if (oldItem && oldItem.url) {
              m.url = oldItem.url
            }
          })
          this.imgList = currentImgList
        }
      },

      getCurrentImgSrc(item) {
        if (item && item.url) {
          return item.url
        }
        const this_ = this
        if (item && item.response && item.response.fileId) {
          item.urlLoading = true
          item.url = this.$requestConfig.getImgSrc(item.response.fileId)
          this_.syncSrcList()
          return item.url
          /*  if (this_.imgList && this_.imgList.length > 0) {
            const firstItem = this_.imgList[0]
            this_.$set(this_.imgList, 0, firstItem)
            this_.syncSrcList()
          } */
        }
      },
      syncSrcList() {
        const urlList = this.imgList.map((file) => file.url)
        this.srcList = this.preview ? urlList : []
      },
      downloadPicture(file) {
        if (file && file.response && file.response.uploadType === 'km') {
          this.switchDownloadPicture(file, 'downloadFromKm')
        } else {
          this.switchDownloadPicture(file, 'download')
        }
      },
      switchDownloadPicture(file, functionName) {
        // 组件单独绑定了download事件
        if (this.$options._parentListeners.download) {
          this.$emit('download', file)
        }
        // 未绑定时触发全局download事件处理函数
        else if (this.$requestConfig[functionName]) {
          this.$requestConfig[functionName](
            file.fileId || file.response ? file.response.fileId : ''
          )
            .then(({ data, headers }) => {
              // 附件下载
              const fileName = decodeURIComponent(
                headers['content-disposition']
                  .split(';')[1]
                  .split('filename=')[1]
              )
              const blob = new Blob([data])
              saveAs(blob, fileName)
            })
            .catch((err) => {
              this.showMessage(`附件下载失败：${err}`, 'danger')
            })
        }
      },
      handleDelete(item) {
        let currentFileList = utils.isEmpty(this.value)
          ? []
          : this.value.constructor == String
          ? JSON.parse(this.value)
          : this.value
        const index = currentFileList.findIndex((file) => file.uid == item.uid)
        currentFileList.splice(index, 1)
        const imgListIndex = this.imgList.findIndex(
          (file) => file.uid == item.uid
        )
        this.$refs.fileUpload &&
          this.$refs.fileUpload.$refs.elUploadEl.uploadFiles.splice(
            imgListIndex,
            1
          )
        this.imgList.splice(imgListIndex, 1)
        this.$emit(
          'input',
          currentFileList.length > 0 ? JSON.stringify(currentFileList) : ''
        )
        if (this.uploadType === 'local') {
          this.refreshFileUploadDebounce()
        }
        if (this.userAgentMobile) {
          this.$refs.mobilePicRef.value = ''
        }
      },
      handlePicChange(e) {
        const imgData = [...e.target.files]
        // 如果有个数限制
        if (this.limit) {
          let totalLength = imgData.length + this.imgList.length
          if (this.limit < totalLength) {
            this.showMessage(
              this.t('ht.picture.limitCountTip', {
                limit: this.limit,
              }),
              'warning'
            )
            return
          }
        }
        // 图片格式校验
        let wrongFlag = false
        imgData.forEach((item) => {
          if (this.isPictureType(item.name)) {
            wrongFlag = true
          }
        })
        if (wrongFlag) {
          this.toast()
          return
        }
        imgData.forEach((item) => {
          this.mobileUploadFile(item)
        })
      },
      clickPicture() {
        this.$refs.mobilePicRef.click()
      },
      async handleSubmit() {
        let result = await this.$validator.validateAll('webImgFrom')
        if (!result) {
          return
        }
        this.btnLoading = true
        if (
          this.inputVal.length + 1 > this.limit ||
          this.srcList.length + 1 > this.limit
        ) {
          this.btnLoading = false
          return this.showMessage(
            this.t('ht.picture.limitCountTip', { limit: this.limit }),
            'warning'
          )
        }
        this.setImgList(this.webImages)
        this.$emit('input', JSON.stringify(this.imgList))
        this.dialogFormVisible = false
      },
      openDialog() {
        this.dialogFormVisible = true
        this.btnLoading = false
        this.$nextTick(() => {
          this.$refs.webImgFormRef.resetFields()
          this.webImages = {
            fileName: '',
            url: '',
          }
        })
      },
      setImgList(files) {
        this.imgList.push({
          ...files,
          uid: `${new Date().getTime()}_${Math.ceil(Math.random() * 10)}`,
        })
      },
      handleSuccess(response, file, fileList) {
        const fileListCopy = fileList.map((item) => {
          return {
            ...item,
            fileName: item.fileName || item.response.fileName,
          }
        })
        let url = ''
        if (
          (file.raw && file.raw.type && file.raw.type.indexOf('image/') > -1) ||
          (!file.raw && file.type && file.type.indexOf('image/') > -1)
        ) {
          url = createObjectURL(file.raw ? file.raw : file)
        }
        this.imgList.push({
          ...file,
          url,
          fileName: file.name || file.response.fileName,
        })
        this.$emit('input', JSON.stringify(fileListCopy))
        this.$emit('on-success', response, file, fileListCopy)
        this.refreshFileUploadDebounce()
      },
      beforeImgUpload(file) {
        if (this.isPictureType(file.name)) {
          this.toast()
          return false
        }
        if (this.compress) {
          return new Promise((resolve) => {
            compress(
              file,
              this.$imageCompressConfig
                ? this.$imageCompressConfig
                : this.compressConfig
            ).then((res) => {
              resolve(res)
            })
          })
        }
      },
      clearForm() {
        this.webImages.fileName = ''
        this.webImages.url = ''
      },
      isPictureType(name) {
        const fileType = name.replace(/.+\./, '')
        const allowedTypeArr = this.accept.split(',')
        return allowedTypeArr.indexOf(fileType.toLowerCase()) === -1
      },
      toast() {
        this.showMessage(this.t('ht.picture.limitTypeTip'), 'warning')
      },
      handleClear() {
        this.imgList = []
        this.srcList = []
        this.$emit('input', '')
      },
      // 同步附件数据到上传组件
      refreshFileUpload() {
        this.$nextTick(() => {
          this.$refs.fileUpload && this.$refs.fileUpload.reload(this.inputVal)
        })
      },
      hrefClick() {
        let url = this.openUrl
          .replaceAll('${mvue}', this.$requestConfig.manageUrl)
          .replaceAll('${fvue}', this.$requestConfig.frontUrl)
          .replaceAll('${front}', this.$requestConfig.frontUrl)

        window.open(url, '_blank')
      },
      // 1. 先定义绘制圆角矩形的工具函数（独立于ctx）
      drawRoundedRect(ctx, x, y, width, height, radius = 4) {
        ctx.beginPath()
        // 左上角圆角：从左上角右边的点开始，绘制到左上角上边的点
        ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 1.5)
        // 右上角圆角：从右上角左边的点开始，绘制到右上角上边的点
        ctx.arc(
          x + width - radius,
          y + radius,
          radius,
          Math.PI * 1.5,
          Math.PI * 2
        )
        // 右下角圆角：从右下角左边的点开始，绘制到右下角下边的点
        ctx.arc(
          x + width - radius,
          y + height - radius,
          radius,
          0,
          Math.PI * 0.5
        ) // 补全5个参数
        // 左下角圆角：从左下角右边的点开始，绘制到左下角下边的点
        ctx.arc(x + radius, y + height - radius, radius, Math.PI * 0.5, Math.PI)
        ctx.closePath() // 闭合路径
      },
      combineImageAndInfo(file) {
        if (
          this.fieldSource === 'camera' &&
          (this.fieldSourceOptionsObj.address ||
            this.fieldSourceOptionsObj.date)
        ) {
          return new Promise((resolve, reject) => {
            const img = new Image()
            // 将文件转为dataURL，避免Canvas跨域问题
            const reader = new FileReader()
            reader.onload = (e) => {
              img.src = e.target.result
              img.onload = () => {
                // 创建Canvas
                const canvas = document.createElement('canvas')
                const ctx = canvas.getContext('2d')

                // 设置Canvas尺寸（与原图一致）
                canvas.width = Math.max(img.width, 100)
                canvas.height = Math.max(img.height, 300)

                // 绘制原图
                ctx.drawImage(img, 0, 0)

                // 绘制文字背景（半透明黑色矩形）
                // ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'
                ctx.fillRect(0, canvas.height, canvas.width, 100)
                if (this.fieldSourceOptionsObj.address) {
                  // 绘制地址文字
                  ctx.fillStyle = '#ffffff'
                  ctx.font = '24px sans-serif'
                  ctx.textAlign = 'start'
                  ctx.fillText(`${this.address}`, 30, canvas.height - 60)
                }

                // -------- 绘制竖线装饰（示例中的黄色竖线） --------
                ctx.strokeStyle = '#FFCC00'
                ctx.lineWidth = 4
                ctx.beginPath()
                ctx.moveTo(20, img.height - 80)
                ctx.lineTo(20, img.height - 20)
                ctx.stroke()
                if (this.fieldSourceOptionsObj.date) {
                  // -------- 绘制“打卡+时间”标签 --------
                  //白色时间背景
                  ctx.fillStyle = '#e9eff9'
                  ctx.fillRect(20, canvas.height - 145, 185, 50)
                  // this.drawRoundedRect(ctx, 20, canvas.height - 145, 165, 50)

                  // 黄色“打卡”背景
                  ctx.fillStyle = '#FFCC00'
                  ctx.fillRect(30, canvas.height - 140, 80, 40)
                  // this.drawRoundedRect(ctx, 30, canvas.height - 140, 70, 40)
                  // 黑色“打卡”文字
                  ctx.fillStyle = 'black'
                  ctx.font = 'bold 32px sans-serif'
                  ctx.fillText('打卡', 40, canvas.height - 108)

                  // 白色时间文字
                  ctx.fillStyle = '#064297'
                  ctx.font = 'bold 32px sans-serif'
                  ctx.fillText(
                    this.formatTime(undefined, 2),
                    110,
                    canvas.height - 108
                  )
                  // 绘制时间文字
                  ctx.fillStyle = 'white'
                  ctx.font = '24px sans-serif'
                  ctx.fillText(`${this.formatTime()}`, 30, canvas.height - 30)
                }

                // 将Canvas转为图片URL
                const combinedImgUrl = canvas.toDataURL('image/jpeg')
                // 转换为File对象（文件名可自定义，如"photo_with_info.jpg"）
                const combinedFile = this.dataUrlToFile(
                  combinedImgUrl,
                  `photo_${Date.now()}.jpg` // 用时间戳避免重名
                )

                //  resolve File对象（而非DataURL）
                resolve(combinedFile)
              }
            }
            reader.readAsDataURL(file)
          })
        } else {
          return Promise.resolve(file)
        }
      },
      // 将DataURL转换为File对象
      dataUrlToFile(dataUrl, filename) {
        // 1. 解析DataURL格式（分离MIME类型和base64数据）
        const arr = dataUrl.split(',')
        // arr[0] 格式为 "data:image/jpeg;base64"，提取MIME类型
        const mime = arr[0].match(/:(.*?);/)[1]
        // arr[1] 是base64编码的字符串，解码为二进制数据
        const bstr = atob(arr[1])
        let n = bstr.length
        // 将二进制字符串转换为Uint8Array（二进制数组）
        const u8arr = new Uint8Array(n)
        while (n--) {
          u8arr[n] = bstr.charCodeAt(n)
        }

        // 2. 先创建Blob对象（二进制数据容器）
        const blob = new Blob([u8arr], { type: mime })
        // 3. 将Blob转换为File对象（指定文件名和类型）
        return new File([blob], filename, { type: mime })
      },
      // 移动端发送上传图片请求
      mobileUploadFile(files) {
        this.combineImageAndInfo(files).then((file) => {
          this.uploadLoading = true
          let formData = new FormData()
          formData.append('file', file, file.name)
          this.$requestConfig
            .request({
              url: this.actionUrlVal,
              method: 'post',
              data: formData,
              headers: {
                ...this.headerVal,
                'Content-Type': 'multipart/form-data',
              },
            })
            .then((res) => {
              if (res.success) {
                this.uploadLoading = false
                // 成功之后组装数据 组装成跟pc一样格式，预览时可以服用预览
                let uid = `${new Date().getTime()}_${Math.ceil(
                  Math.random() * 10
                )}`
                res.uid = uid
                let fileObj = {
                  uid: uid,
                  name: file.name,
                  response: res,
                  url: createObjectURL(file),
                }
                this.imgList.push(fileObj)
                let newCopy = JSON.parse(JSON.stringify(this.imgList))
                // 传给后端需把url删除
                newCopy.forEach((item) => {
                  delete item.url
                })
                this.$emit('input', JSON.stringify(newCopy))
              }
            })
            .catch(() => {
              this.uploadLoading = false
            })
        })
      },
      autoLocate() {
        // 加载定位插件
        window.AMap.plugin('AMap.Geolocation', () => {
          const geolocation = new window.AMap.Geolocation({
            enableHighAccuracy: true, // 高精度定位
            timeout: 10000, // 超时时间（10秒）
            maximumAge: 0, // 不缓存定位结果
            // 关闭所有UI显示（因为不需要地图）
            showButton: false, // 不显示定位按钮
            showMarker: false, // 不显示定位标记
            showCircle: false, // 不显示精度圆
            panToLocation: false, // 无需移动地图（无地图）
          })

          // 调用定位
          geolocation.getCurrentPosition((status, result) => {
            this.loading = false
            if (status === 'complete') {
              // 定位成功：获取经纬度
              // this.position.lng = result.position.lng
              // this.position.lat = result.position.lat
              this.address = result.formattedAddress
            } else {
              // 定位失败（如用户拒绝权限、网络问题等）
              this.errorMsg = `定位失败：${result.message || '未知错误'}`
            }
          })
        })
      },

      // 步骤3：格式化时间
      formatTime(date = new Date(), type = 1) {
        const year = date.getFullYear()
        const month = String(date.getMonth() + 1).padStart(2, '0')
        const day = String(date.getDate()).padStart(2, '0')
        const hours = String(date.getHours()).padStart(2, '0')
        const minutes = String(date.getMinutes()).padStart(2, '0')
        const seconds = String(date.getSeconds()).padStart(2, '0')
        const weekAbbr = ['日', '一', '二', '三', '四', '五', '六']
        const shortWeek = `星期${weekAbbr[new Date().getDay()]}`
        if (type === 1) {
          return `${year}-${month}-${day} ${shortWeek}`
        } else {
          return `${hours}:${minutes}`
        }
      },
      handleExceed() {
        this.showMessage(
          this.t('ht.picture.limitCountTip', { limit: this.limit }),
          'warning'
        )
      },
      showMessage(msg, type) {
        if (this.isMobile) {
          this.$notify({
            type: type,
            message: msg,
            duration: 2000,
          })
        } else {
          if (type == 'danger') {
            type = 'error'
          }
          this.$message({
            type: type,
            message: msg,
          })
        }
      },
    },
  }
</script>
<style lang="scss" scoped>
  .ht-picture {
    &__images {
      display: flex;
      flex-wrap: wrap;
      margin: 10px;
    }
    &__card {
      margin-right: 8px;
      margin-bottom: 8px;
    }
    // &__item-img {
    //   height: 240px;
    //   width: 260px;
    //   border-radius: 4px;
    // }
    &__footer {
      min-height: 32px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      overflow: hidden;
      flex: 1;
    }
    &__name {
      flex: 1;
      line-height: 32px;
      font-size: 14px;
      margin-left: 8px;
      margin-right: 8px;
      color: #595959;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    &__hide-input {
      display: none;
    }

    .ht-picture__download {
      margin-right: 8px;
      color: #00c2ce;
      font-size: 16px;
      cursor: pointer;
    }
    .ht-picture_delete {
      font-size: 16px;
      color: #bfbfbf;
      cursor: pointer;
    }
    .pop-confirm-btn {
      margin-left: 10px;
    }
    .ht-picture_box {
      .image-card-box {
        display: flex;
        flex-wrap: wrap;
      }
      .ht-picture__card {
        border-color: #ebebeb;
        background: #fff;
        padding: 16px;
        width: 356px;
        height: 96px;
        box-sizing: border-box;
        box-shadow: none;
        ::v-deep .el-card__body {
          display: flex;
          align-items: center;
          justify-content: space-between;
          padding: 0;
          .ht-picture__item-img {
            width: 64px;
            height: 64px;
            border-radius: 4px;
          }
        }
      }
    }
    .ht-picture__web-box {
      .image-card-box {
        padding-top: 12px;
      }
    }
    .mobile-picture-box {
      display: flex;
      flex-wrap: wrap;
    }
  }
  .form-dialog {
    .ht-dialog-footer {
      text-align: center;
      .submit-button {
        width: unset;
        margin-right: 10px;
      }
    }
  }
  .ht-dialog-footer {
    text-align: center;
  }
  ::v-deep {
    input[type='hidden'][aria-invalid='true'] + .ht-picture-upload {
      max-width: 220px;
      outline: 1px solid #f56c6c;
    }
  }
  // 移动端样式

  .mobile-picture {
    .ht-picture_box {
      .ht-picture__card {
        position: relative;
        margin: 0 20px 10px 0;
        width: 64px;
        height: 64px;
        overflow: visible;
        padding: 0;
        .mobile-delete {
          position: absolute;
          top: 0;
          right: 0;
          width: 14px;
          height: 14px;
          background-color: rgba(0, 0, 0, 0.7);
          border-radius: 0 4px 0 12px;
          color: #fff;
          .mobile-cls-close {
            position: absolute;
            font-size: 12px;
            top: 0;
            right: 0;
          }
        }
        ::v-deep .el-card__body {
          width: 100%;
          height: 100%;
          padding: 0;
        }
      }
    }

    ::v-deep .mobile-puls {
      position: relative;
      border: 1px solid #e6e6e6;
      width: 64px;
      height: 64px;
      border-radius: 4px;
      display: flex;
      align-items: center;
      justify-content: center;
      margin-right: 20px;
      i {
        font-size: 30px;
        color: #e6e6e6;
      }
      .van-loading {
        height: 22px;
        line-height: 22px;
      }
    }
  }
</style>
