<template>
  <div class="preview-container"> 
    <view class="backstyle_1"></view>
    <view class="backstyle_2"></view>
    <div class="header" @click="goBack">
      <span class="back-icon"><van-icon name="arrow-left" size="16px" /> {{ toValueWithout("效果预览") }}</span>
    </div>
    <div class="step-container">
      <div class="step-item">
        <div class="step-content">
          <div class="step-title">{{ toValueWithout("正面照片") }}</div>
          <div class="step-desc">{{ toValueWithout("清晰的正面照片") }}</div>
        </div>
      </div>
      <div class="step-item active">
        <div class="step-num">2</div>
        <div class="step-content">
          <div class="step-title">{{ toValueWithout("确认下单") }}</div>
          <div class="step-desc">{{ toValueWithout("选择一个你喜欢的效果图下单") }}</div>
        </div>
      </div>
    </div>
    <div v-if="!imageUrl" class="progress-section">
      <div class="progress-bar-bg">
        <div class="progress-bar-fg" :style="{ width: progress + '%' }"></div>
      </div>
      <div class="progress-text">{{progressText}} {{progress}}%</div>
      <div class="progress-desc">{{ toValueWithout(`总计大约需要${config.preview.progress.totalTime}秒，请耐心等待...`) }}</div>
    </div>
    <div v-else class="progress-section-picture" :style="`width: ${config.preview.imageSize.previewWidth}px;height: ${config.preview.imageSize.previewHeight}px;`">
      <div class="progress-section-img" :style="`width: ${config.preview.imageSize.previewWidth}px;height: ${config.preview.imageSize.previewHeight}px;`">
        <img v-if="shapeImage" class="box1-back-image" :src="getImageUrl(shapeImage)" :style="`width: ${config.preview.imageSize.previewWidth}px;height: ${config.preview.imageSize.previewHeight}px;`"  alt="">
        <div class="box1-front-box" :style="getStyle">
          <img class="box1-front-image" :src="imageUrl" alt="" :style="`max-height: ${config.preview.imageSize.previewHeight}px;`">
        </div>
        <div class="shape-text" :style="shapeTextStyle" v-if="shapeText">{{shapeText}}</div>
        <div class="shape-text" :style="topTextStyle" v-if="topText">{{topText}}</div>
        <div class="shape-text" :style="bottomTextStyle" v-if="bottomText">{{bottomText}}</div>
        <div v-if="badgeTypeId == 6 && axisz == 1 && roundTextConfigFront.width && roundTextConfigFront.charList" class="roundText font-chinese" :style="`left: ${roundTextConfigFront.x}px;top: ${roundTextConfigFront.y}px;width: ${roundTextConfigFront.width}px;height: ${roundTextConfigFront.height}px;position: absolute;pointer-events: none;z-index: 10;`">
          <div v-for="item in roundTextConfigFront.charList" :key="item.char" class="round-text-char" :style="`position: absolute;left: ${item.x}px;top: ${item.y}px;font-size: ${item.fontSize}px;font-weight: ${item.fontWeight};color: ${item.color};transform: translate(-50%, -50%) rotate(${item.rotateDeg}deg);transform-origin: center;white-space: nowrap;`">
            <span>{{item.char}}</span>
          </div>
        </div>
        <div v-if="badgeTypeId == 6 && axisz == -1 && roundTextConfigBack.width && roundTextConfigBack.charList" class="roundText font-chinese" :style="`left: ${roundTextConfigBack.x}px;top: ${roundTextConfigBack.y}px;width: ${roundTextConfigBack.width}px;height: ${roundTextConfigBack.height}px;position: absolute;pointer-events: none;z-index: 10;`">
          <div v-for="(item, index) in roundTextConfigBack.charList" :key="index" class="round-text-char" :style="`position: absolute;left: ${item.x}px;top: ${item.y}px;font-size: ${item.fontSize}px;font-weight: ${item.fontWeight};color: ${item.color};transform: translate(-50%, -50%) rotate(${item.rotateDeg}deg);transform-origin: center;white-space: nowrap;`">
            <span>{{item.char}}</span>
          </div>
        </div>
      </div>
    </div>
    <div class="image-list-box" v-if="imageList.length > 1">
      <div class="image-list-item" v-for="item in imageList" :key="item.key">
        <img v-if="item.status == 1" class="image-list-item-img" :class="{ imgActive: item.key == imgKey }" :src="item.origin_url" alt="" @click="changeImage(item)">
        <div v-else-if="item.status == 0" class="image-list-item-loading">
          {{ toValueWithout(config.preview.messages.designing) }}
        </div>
        <div v-else-if="item.status == 2" class="image-list-item-loading">
          {{ toValueWithout(config.preview.messages.designFailed) }}
        </div>
      </div>
    </div>
    <div class="info-section">
      <div class="info-item">
        <div class="info-title" v-if="productName">{{ toValueWithout(productName) }}</div>
        <div class="info-content">{{ toValueWithout(config.preview.messages.productType) }}</div>
      </div>
      <div class="info-item">
        <div class="info-title">{{ toValueWithout("3D全彩打印") }}</div>
        <div class="info-content">{{ toValueWithout(config.preview.messages.process) }}</div>
      </div>
      <div class="info-item">
        <div class="info-title">ID</div>
        <div class="info-content">{{ pid }}</div>
      </div>
    </div>
    <div class="shape-body">
      <div class="shape-type" v-if="imageUrl && typeId == 3">
        <div class="shape-type-item" :class="{ 'shape-active': item.id == shapeId }" v-for="item in shapeList" :key="item.id" @click="shapeChange(item)">{{item.name}}</div>
      </div>
      <div class="shape-box" v-if="imageUrl && typeId != 3 && typeId != 4">
        <block v-for="item in shapeList" :key="item.id">
          <div class="shape-item" @click="shapeChange(item)">
            <div class="shape-item-list">
              <img class="shape-item-image" :class="{ 'shape-item-image-round': config.preview.shapeIds.round.includes(item.id) }" :src="getImageUrl(item.cover_path) || imageUrl"/>
              <van-icon v-if="item.id == shapeId" class="shape-icon" :color="config.styles.colors.success" name="checked" size="18px" />
            </div>
            <div class="shape-item-text">{{ toValueWithout(item.name) }}</div>
          </div>
        </block>
      </div>
      <div class="shape-box-input" v-if="imageUrl && custom_switch == 1 && typeId == 2">
        <div v-if="config.preview.shapeIds.topBottomText.includes(shapeId)">
          <input class="shape-box-input-text" type="text" :placeholder="toValueWithout('请输入顶部文字')" v-model="topText" @change="changeTopText" @input="changeTopText" @onBlur="changeTopText" />
          <input class="shape-box-input-text" type="text" :placeholder="toValueWithout('请输入底部文字')" style="margin-top: 10px;" v-model="bottomText" @change="changeBottomText" @input="changeBottomText" @onBlur="changeBottomText" />
        </div>
        <div v-else style="width: 100%;">
          <input class="shape-box-input-text" type="text" :placeholder="toValueWithout('请输入文字')" v-model="shapeText" @change="changeShapeText" @input="changeShapeText" @onBlur="changeShapeText" />
        </div>
      </div>
      <div class="shape-box-input-box" v-if="imageUrl && custom_switch == 1 && typeId == 6">
        <input class="shape-box-input-text" v-if="axisz == 1" type="text" :placeholder="toValueWithout('请输入正面文字')" v-model="frontText" @change="changeFrontText" @input="changeFrontText" @onBlur="changeFrontText" />
        <input class="shape-box-input-text" v-if="axisz == -1" type="text" :placeholder="toValueWithout('请输入背面文字')" v-model="backText" @change="changeBackText" @input="changeBackText" @onBlur="changeBackText" />
      </div>
    </div>
    <div style="padding: 0 16px;">
      <van-divider />
    </div>
    <div class="order-section" v-if="imageUrl">
      <div class="order-title">{{ toValueWithout(config.preview.messages.orderQuantity) }}</div>
      <block v-for="item in sizeList" :key="item.id">
        <block>
          <div class="order-item">
            <span class="order-size">{{ item.size }}</span>
            <span class="order-free">({{ toValueWithout(config.preview.messages.remainingExchange) }}：{{ item.remaining }})</span>
            <div class="order-ctrl">
              <van-stepper v-model="item.count" :min="0" :max="item.remaining" @change="changeValue" />
            </div>
          </div>
        </block>
      </block>
    </div>
    <div class="address-box" v-if="orderStat.use_type == 2 && imageUrl">
      <div class="order-title" style="padding: 0 16px;">{{ toValueWithout(config.preview.messages.shippingAddress) }}</div>
      <div class="address-item">
        <van-address-edit
          :area-list="areaList"
          :tel-validator="true"
          tel-maxlength="11"
          show-delete
          show-search-result
          :search-result="searchResult"
          :area-columns-placeholder="[toValueWithout('请选择'), toValueWithout('请选择'), toValueWithout('请选择')]"
          @change="nameTelChange"
          @change-area="changeArea"
          @change-detail="onChangeDetail"
        />
      </div>
    </div>
    <div style="height: 130px;"></div>
    <div class="confirm-box">
      <div class="action-section">
        <!-- <button @click="sureReload" :disabled="flag < 1" class="action-btn"><img class="action-img" :src="reloadImage" alt=""> {{ toValueWithout(config.preview.messages.regenerate) }}</button> -->
        <button @click="compare" :disabled="flag < 1" class="action-btn"><img class="action-img" :src="compareImage" alt=""> {{ toValueWithout(config.preview.messages.compare) }}</button>
        <button @click="save" :disabled="flag < 1" class="action-btn"><img class="action-img" :src="downloadImage" alt=""> {{ toValueWithout(config.preview.messages.saveImage) }}</button>
      </div>
      <div class="btn-box">
        <button @click="confirm" :disabled="flag < 1" class="confirm-btn">{{ toValueWithout(config.preview.messages.confirmSelect) }}</button>
      </div>
    </div>
  </div>
  
  <van-action-sheet v-model:show="showCompare" :title="toValueWithout(config.preview.messages.compare)" :close-on-click-overlay="true" closeable>
    <div style="padding: 16px;">
      <div style="display: flex; align-items: center; justify-content: center; gap: 20px;">
        <div style="text-align: center;">
          <img :src="compareList.origin_path" :alt="toValueWithout(config.preview.messages.originalImage)" :style="`max-width: ${config.preview.imageSize.compareImageSize}px; max-height: ${config.preview.imageSize.compareImageSize}px; border-radius: 8px;`">
        </div>
        <div style="font-size: 24px; color: #333;">
          <van-icon name="arrow" size="20px" />
        </div>
        <div style="text-align: center;">
          <img :src="imageUrl" :alt="toValueWithout(config.preview.messages.previewImage)" :style="`width: ${config.preview.imageSize.compareImageSize}px; height: ${config.preview.imageSize.compareImageSize}px; border-radius: 8px;`">
        </div>
      </div>
      <div style="text-align: center; margin-top: 16px; color: #999; font-size: 12px;">
        {{ toValueWithout(config.preview.messages.compareTip) }}
      </div>
    </div>
  </van-action-sheet>

  <div v-if="showPreview">
    <div class="preview-mask" @click="showPreview = false">
      <img :src="imageWater" :alt="toValueWithout(config.preview.messages.badgePreview)" />
      <p>{{ toValueWithout(config.preview.messages.saveImageTip) }}</p>
    </div>
  </div>
</template>
<script setup lang="ts">
import { onMounted, ref, onUnmounted, nextTick, computed } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { showSuccessToast, showToast, showConfirmDialog } from 'vant';
import { localStorage } from '@/utils/local-storage'
import * as badgeApi from '@/api/badge'
import { areaList } from '@/utils/area'
import { toValueWithout } from '@/lang/utils'
import { createTextPosition } from '@/utils/textHelper'
import { cartoonConfig as config } from '@/config/cartoon'

// 导入图片资源
import reloadImageSrc from '@/assets/badge/reload.png'
import compareImageSrc from '@/assets/badge/duibi.png'
import downloadImageSrc from '@/assets/badge/down.png'

const reloadImage = reloadImageSrc
const compareImage = compareImageSrc
const downloadImage = downloadImageSrc

const router = useRouter();
const showCompare = ref(false)
const imageList = ref([])
const imageWater = ref('')

const frontText = ref('')
const backText = ref('')
const frontKey = ref(1)

// 圆形文字配置
const roundTextConfigFront = ref({})
const roundTextConfigBack = ref({})
const cachedImageInfo = ref(null)
const imageInfo = ref(null)
const badgeTypeId = ref(0)
const axisz = ref(1)

// 创建适配 Vue 的 textHelper 实例
const textHelper = createTextPosition({
  setData: (data: any) => {
    Object.keys(data).forEach(key => {
      if (key === 'roundTextConfigFront') {
        roundTextConfigFront.value = data[key]
      } else if (key === 'roundTextConfigBack') {
        roundTextConfigBack.value = data[key]
      } else if (key === 'cachedImageInfo') {
        cachedImageInfo.value = data[key]
      } else if (key === 'imageInfo') {
        imageInfo.value = data[key]
      }
    })
  }
})

// 计算产品名称
const productName = computed(() => {
  if (!typeId.value || !prodId.value) return ''
  const typeConfig = config.preview.productNames[typeId.value]
  if (typeConfig && typeConfig[prodId.value]) {
    return typeConfig[prodId.value]
  }
  return ''
})

function compare() {
  showCompare.value = true
}

function sureReload() {
  console.log('orderStat', orderStat.value)
  if (orderStat.value.remain_count <= 0) {
    showToast(toValueWithout(config.preview.messages.noRemainingCount))
    return
  }
  isPreview.value = false
  showConfirmDialog({
    title: toValueWithout(config.preview.messages.regenerate),
    message: toValueWithout(config.preview.messages.confirmRegenerate),
  })
  .then(() => {
    group.value = newGroup.value
    const params = {
      pid: pid.value,
      group: config.preview.defaults.group,
      prod_id: prodId.value,
      type_id: typeId.value,
      kind_id: kindId.value
    }
    badgeApi.putModeling(params).then((res: any) => {
      console.log('putModeling', res)
      imageUrl.value = '';
      imageList.value = []
      imgKey.value = '';
      createLog()
    }).catch((err) => {
      console.log('putModeling', err)
      showToast({
        message: err.message,
        duration: 2000,
      })
    })
  })
  .catch(() => {
    // on cancel
  });
}

const imgKey = ref(config.preview.defaults.imgKey)
const frameUrl = ref('')
const changeImage = (item: any) => {
  console.log('changeImage', item)
  imgKey.value = item.key
  imageUrl.value = config.preview.shapeIds.specialFrame.includes(shapeId.value) ? item.frame_url : item.origin_url
  frameUrl.value = item.frame_url
  imageWater.value = item.image_url
}

const createLog = () => {
  badgeApi.createLog({
    pid: pid.value,
    group: config.preview.defaults.group,
    prod_id: prodId.value,
    type_id: typeId.value,
    kind_id: kindId.value
  }).then((res: any) => {
    console.log('createLog', res)
    progressTimer.value = null
    getImageList()
    progressList()
    getCompareImage()
    timer.value = setInterval(() => {
      getImageList()
    }, config.preview.polling.interval)
  }).catch((err) => {
    console.log('createLog', err)
    showToast({
      message: err.message,
      duration: 2000,
    })
  })
}

const showPreview = ref(false)
function save() {
  showPreview.value = true;
}
const compareList = ref({})
const style_name = ref('')
function getCompareImage() {
  badgeApi.getCompareImage({
    pid: pid.value,
    group: config.preview.defaults.group,
    prod_id: prodId.value,
    type_id: typeId.value
  }).then((res: any) => {
    console.log('getCompareImage', res)
    compareList.value = res
    style_name.value = res.list[0].kind_name || res.kind_name
  }).catch((err) => {
    console.log('getCompareImage', err)
    showToast({
      message: err.message,
      duration: 2000,
    })
  })
}
function goBack() {
  router.back()
}

const sizeList = ref([])
const getSizeList = () => {
  badgeApi.getOrderPrice({}).then((res: any) => {
    console.log('getSizeList', res);
    sizeList.value = res
    if (typeId.value != 4) {
      getShapeList()
    }
  })
}

const contact_name = ref('')
const contact_mobile = ref('')
const province_id = ref(0)
const city_id = ref(0)
const county_id = ref(0)
const province_name = ref('')
const city_name = ref('')
const county_name = ref('')
const address = ref('')
const nameTelChange = (res: any) => {
  console.log('nameTelChange', res)
  if (res.key == 'name') {
    contact_name.value = res.value
  } else {
    contact_mobile.value = res.value
  }
}

const changeArea = (value: any) => {
  console.log('changeArea', value)
  province_id.value = value[0].value
  city_id.value = value[1].value
  county_id.value = value[2].value
  province_name.value = value[0].text
  city_name.value = value[1].text
  county_name.value = value[2].text
}

const onChangeDetail = (value: any) => {
  console.log('onChangeDetail', value)
  address.value = value
}

const payAmount = ref(0)
const changeValue = (value: number) => {
  console.log(value) 
  payAmount.value = value
}

const loading = ref(false)
const confirm = () => {
  if (loading.value) return
  console.log('confirm')
  if (payAmount.value <= 0) {
    showToast(toValueWithout(config.preview.messages.selectQuantity))
    return
  }
  if (orderStat.value.use_type == 2 && !contact_name.value) {
    showToast(toValueWithout(config.preview.messages.fillContactName))
    return
  }
  if (orderStat.value.use_type == 2 && !contact_mobile.value) {
    showToast(toValueWithout(config.preview.messages.fillContactMobile))
    return
  }
  if (orderStat.value.use_type == 2 && !province_id.value) {
    showToast(toValueWithout(config.preview.messages.selectArea))
    return
  }
  if (orderStat.value.use_type == 2 && !address.value) {
    showToast(toValueWithout(config.preview.messages.fillAddress))
    return
  }
  getPosition()
  loading.value = true
  showConfirmDialog({
    title: toValueWithout(config.preview.messages.confirmSelect),
    message: toValueWithout(config.preview.messages.confirmOrder),
  })
  .then(() => {
    const parms = {
      pid: pid.value,
      key: imgKey.value,
      pay_amount: payAmount.value,
      products: sizeList.value,
      prod_id: prodId.value,
      shape_id: shapeId.value,
      custom_text: shapeText.value ? shapeText.value : frontText.value,
      back_text: backText.value ? backText.value : '',
      shape_ids: shapeIds.value,
      type_id: typeId.value,
      up_text: topText.value ? topText.value : '',
      down_text: bottomText.value ? bottomText.value : '',
      subject_id: subjectId.value,
    }
    if (orderStat.value.use_type == 2) {
      parms.province_id = province_id.value
      parms.city_id = city_id.value
      parms.county_id = county_id.value
      parms.province_name = province_name.value
      parms.city_name = city_name.value
      parms.county_name = county_name.value
      parms.address = address.value
      parms.contact_name = contact_name.value
      parms.contact_mobile = contact_mobile.value
      parms.addr_id = config.preview.defaults.addrId
      parms.country_id = config.preview.defaults.countryId
    }
    console.log('parms', parms)
    badgeApi.creatOrder(parms).then((res: any) => {
      console.log('creatOrder', res)
      showSuccessToast({
        message: toValueWithout(config.preview.messages.orderSuccess),
        duration: 2000,
      })
      router.push({
        path: config.routes.myOrder
      })
      loading.value = false
    }).catch((err) => {
      console.log('creatOrder', err)
      loading.value = false
      showToast({
        message: err.message,
        duration: 2000,
      })
    }).finally(() => {
      loading.value = false
    })
  })
  .catch(() => {
    loading.value = false
  });
}

const getPosition = () => {
  badgeApi.composite({
    pid: pid.value,
    num: imgKey.value,
    custom_text: shapeText.value ? shapeText.value : frontSaveText.value,
    back_text: backSaveText.value ? backSaveText.value : '',
    shape_id: shapeId.value,
    type_id: typeId.value,
    shape_ids: shapeIds.value,
    up_text: topText.value ? topText.value : '',
    down_text: bottomText.value ? bottomText.value : '',
  }).then((res: any) => {
    console.log('getPosition', res)
  }).catch((err) => {
    console.log('getPosition', err)
  })
}

const imageUrl = ref('')
const originUrl = ref('')
const group = ref(config.preview.defaults.group);
// 轮询获取图片
const flag = ref(1)
const timer = ref()
const progress = ref(0)
const progressTimer = ref()
const progressText = ref('')
const progressList = () => {
  progress.value = 0
  if (!progressTimer.value) {
    progressTimer.value = setInterval(() => {
      if (progress.value < config.preview.progress.maxProgress) {
        progress.value += 1
        const thresholds = config.preview.progress.thresholds
        if (progress.value < thresholds.stage1) {
          progressText.value = toValueWithout(config.preview.progress.stages.stage1)
        } else if (progress.value < thresholds.stage2) {
          progressText.value = toValueWithout(config.preview.progress.stages.stage2)
        } else if (progress.value < thresholds.stage3) {
          progressText.value = toValueWithout(config.preview.progress.stages.stage3)
        } else {
          progressText.value = toValueWithout(config.preview.progress.stages.stage4)
        }
      }
    }, config.preview.progress.interval)
  }
}

const newGroup = ref(0)
const isPreview = ref(false)
const getImageList = () => {
  badgeApi.getImageList({
    pid: pid.value, 
    group: config.preview.defaults.group,
    prod_id: prodId.value
  }).then((res: any) => {
    console.log('getImageList', res)
    const data = res || []
    flag.value = data.flag
    if (data.flag === 1) {
      newGroup.value = data.next_group
      
      nextTick(() => {
        const newList = data.list.map(item => ({
          ...item,
          isNew: true
        }))

        const firstGeneratedImage = newList.find(item => item.status === 1)

        if (firstGeneratedImage && !isPreview.value) {
          originUrl.value = firstGeneratedImage.origin_url
          imageUrl.value = firstGeneratedImage.origin_url
          frameUrl.value = firstGeneratedImage.frame_url
          imageWater.value = firstGeneratedImage.image_url
          imgKey.value = firstGeneratedImage.key
          isPreview.value = true
        }

        const mergedList = imageList.value.map(item => {
          const newItem = newList.find(n => n.key === item.key)
          return newItem || item
        })

        newList.forEach(newItem => {
          if (!mergedList.find(item => item.key === newItem.key)) {
            mergedList.push(newItem)
          }
        })

        imageList.value = mergedList

        console.log('imgKey.value', imgKey.value)
        if (imgKey.value) {
          const currentImage = mergedList.filter((item: any) => item.key === imgKey.value)[0]
          console.log('currentImage', currentImage)
          if (currentImage && currentImage.status === 1) {
            originUrl.value = currentImage.origin_url
            imageUrl.value = currentImage.origin_url
            frameUrl.value = currentImage.frame_url
            imageWater.value = currentImage.image_url
            isPreview.value = true
          } else {
            originUrl.value = currentImage.origin_url
            imageUrl.value = currentImage.origin_url
            frameUrl.value = currentImage.frame_url
            imageWater.value = currentImage.image_url
            isPreview.value = true
          }
        }
      })
    }
    if (data.flag === 2) {
      newGroup.value = data.next_group
      clearInterval(timer.value)
      clearInterval(progressTimer.value)
      
      progress.value = 100
      
      imageList.value = data.list
      if (imgKey.value) {
        originUrl.value = data.list.filter((item: any) => item.key == imgKey.value)[0].origin_url
        imageUrl.value = data.list.filter((item: any) => item.key == imgKey.value)[0].origin_url
        frameUrl.value = data.list.filter((item: any) => item.key == imgKey.value)[0].frame_url
        imageWater.value = data.list.filter((item: any) => item.key == imgKey.value)[0].image_url
      } else {
        originUrl.value = data.list[0].origin_url
        imageUrl.value = data.list[0].origin_url
        frameUrl.value = data.list[0].frame_url
        imageWater.value = data.list[0].image_url
        imgKey.value = data.list[0].key
      }
      localStorage.remove('userId')
    }
  }).catch((err) => {
    showToast({
      message: err.message,
      duration: 2000,
    })
  })
}

const shapeId = ref(0)
const shapeIds = ref([])
const shapeImage = ref('')

const shapeList = ref([])
const custom_switch = ref(0)
const limitCount = ref(0)
const getShapeList = () => {
  badgeApi.getShapeList({
    prod_id: prodId.value,
    type_id: typeId.value
  }).then((res: any) => {
    console.log('getShapeList', res)
    shapeList.value = res.list
    shapeId.value = res.list[0].id
    shapeImage.value = res.list[0]?.frame_path
    custom_switch.value = res.list[0]?.custom_switch
    limitCount.value = res.list[0]?.text_limit_max
    ImageShow(res.list[0])
    if (custom_switch.value == 1 && typeId.value == 2) {
      shapeText.value = ''
      topText.value = ''
      bottomText.value = ''
      topTextStyle.value = ''
      bottomTextStyle.value = ''
      shapeTextStyle.value = ''
      textShow(res.list[0])
    }
    if (custom_switch.value == 1 && typeId.value == 6) {
      shapeIds.value = res.list.map((item: any) => item.id)
      if (res.list[0].axisz == 1) {
        axisz.value = 1
        frontKey.value = 1
        frontTextShow(res.list[0], true)
      } else if (res.list[0].axisz == -1) {
        axisz.value = -1
        frontKey.value = 2
        frontTextShow(res.list[0], false)
      } else {
        axisz.value = 1
        frontKey.value = 1
        frontTextShow(res.list[0], true)
      }
    }
  }).catch((err) => {
    console.log('getShapeList', err)
  })
}

const getImageUrl = (path: string) => {
  return 'https://suwa3d-3dview.oss-cn-shanghai.aliyuncs.com/' + path
}

const getStyle = ref('')
const ImageShow = (item: any) => {
  const scale = config.preview.imageScale;
  const img = new Image()
  img.src = getImageUrl(item.frame_path)
  img.onload = () => {
    console.log('img', img)
    const ratioWidth = config.preview.imageSize.previewWidth / img.width;
    const ratioHeight = config.preview.imageSize.previewHeight / img.height;
    const x = item.axisx * ratioWidth * scale;
    const y = item.axisy * ratioHeight * scale;
    const path_width = item.width * ratioWidth * scale;
    const path_height = item.height * ratioHeight * scale;
    getStyle.value = `left: ${x}px;top: ${y}px;width: ${path_width}px;height: ${path_height}px;`
  }
}

const shapeTextStyle = ref('')
const topTextStyle = ref('')
const bottomTextStyle = ref('')
const textShow = (item: any, type: string = 'shape') => {
  const scale = config.preview.imageScale;
  const img = new Image()
  img.src = getImageUrl(item.frame_path)
  img.onload = () => {
    console.log('img', img)
    const ratioWidth = config.preview.imageSize.previewWidth / img.width;
    const ratioHeight = config.preview.imageSize.previewHeight / img.height;
    const x = item.text_axisx * ratioWidth * scale;
    const y = item.text_axisy * ratioHeight * scale;
    const path_width = item.text_width * ratioWidth * scale;
    const path_height = item.text_height * ratioHeight * scale;
    const text_size = item.font_size * Math.min(ratioWidth * scale, ratioHeight * scale);
    if (type == 'shape') {
      shapeTextStyle.value = `left: ${x}px;top: ${y}px;width: ${path_width}px;height: ${path_height}px;text-align: center;line-height: ${path_height}px;font-size: ${text_size}px;color: ${item.font_color};font-weight: ${item.font_weight};`
    } else if (type == 'top') {
      topTextStyle.value = `left: ${x}px;top: ${y}px;width: ${path_width}px;height: ${path_height}px;text-align: center;line-height: ${path_height}px;font-size: ${text_size}px;color: ${item.font_color};font-weight: ${item.font_weight};`
    } else if (type == 'bottom') {
      bottomTextStyle.value = `left: ${x}px;top: ${y}px;width: ${path_width}px;height: ${path_height}px;text-align: center;line-height: ${path_height}px;font-size: ${text_size}px;color: ${item.font_color};font-weight: ${item.font_weight};`
    }
  }
}

const frontTextShow = (event: any, isFront: boolean | null = null) => {
  if (isFront === null) {
    isFront = frontKey.value == 1;
  }
  isFront = Boolean(isFront);
  
  let config_text: any = {};
  if (isFront) {
    config_text = {
      x: event.front_text_axisx || config.preview.textConfig.front.x,
      y: event.front_text_axisy || config.preview.textConfig.front.y,
      width: event.front_text_width || config.preview.textConfig.front.width,
      height: event.front_text_height || config.preview.textConfig.front.height,
      radius: event.front_text_radius || config.preview.textConfig.front.radius,
      fontSize: event.front_font_size || config.preview.textConfig.front.fontSize,
      maxLength: config.preview.textConfig.front.maxLength
    };
  } else {
    config_text = {
      x: event.back_text_axisx !== undefined ? event.back_text_axisx : config.preview.textConfig.back.x,
      y: event.back_text_axisy !== undefined ? event.back_text_axisy : config.preview.textConfig.back.y,
      width: event.back_text_width !== undefined ? event.back_text_width : config.preview.textConfig.back.width,
      height: event.back_text_height !== undefined ? event.back_text_height : config.preview.textConfig.back.height,
      radius: event.back_text_radius !== undefined ? event.back_text_radius : config.preview.textConfig.back.radius,
      fontSize: event.back_font_size !== undefined ? event.back_font_size : config.preview.textConfig.back.fontSize,
      maxLength: config.preview.textConfig.back.maxLength
    };
  }
  
  const text = isFront ? frontText.value : backText.value;
  const bindKey = isFront ? 'roundTextConfigFront' : 'roundTextConfigBack';
  const shapeImagePath = event.frame_path || shapeImage.value;
  const cachedInfo = cachedImageInfo.value;
  const needFetchImage = !cachedInfo || cachedInfo.src !== shapeImagePath;
  
  if (!needFetchImage && cachedInfo) {
    textHelper.roundText({
      shapeImage: shapeImagePath,
      x: config_text.x,
      y: config_text.y,
      width: config_text.width,
      height: config_text.height,
      radius: config_text.radius,
      text: text,
      isFront: isFront,
      style: {
        fontSize: config_text.fontSize,
        color: event.font_color || config.preview.textConfig.defaultColor,
        fontWeight: event.font_weight || config.preview.textConfig.defaultWeight,
        textAlign: 'center',
      },
      bindKey: bindKey,
      cachedImageInfo: cachedInfo
    });
    
    nextTick(() => {
      const currentConfig = isFront ? roundTextConfigFront.value : roundTextConfigBack.value;
      if (frontKey.value == (isFront ? 1 : 2) && currentConfig && currentConfig.charList) {
        // Vue 会自动响应式更新
      }
    });
  } else {
    textHelper.roundText({
      shapeImage: shapeImagePath,
      x: config_text.x,
      y: config_text.y,
      width: config_text.width,
      height: config_text.height,
      radius: config_text.radius,
      text: text,
      isFront: isFront,
      style: {
        fontSize: config_text.fontSize,
        color: event.font_color || config.preview.textConfig.defaultColor,
        fontWeight: event.font_weight || config.preview.textConfig.defaultWeight,
        textAlign: 'center',
      },
      bindKey: bindKey,
      onImageInfoCached: (imageInfo: any) => {
        cachedImageInfo.value = imageInfo;
      }
    });
    
    const checkAndUpdate = (attempts = 0) => {
      if (attempts > 10) return;
      
      const currentConfig = isFront ? roundTextConfigFront.value : roundTextConfigBack.value;
      if (frontKey.value == (isFront ? 1 : 2)) {
        if (currentConfig && currentConfig.charList && currentConfig.charList.length > 0) {
          // Vue 会自动响应式更新
        } else if (attempts < 10) {
          setTimeout(() => {
            checkAndUpdate(attempts + 1);
          }, 50);
        }
      }
    };
    
    setTimeout(() => {
      checkAndUpdate(0);
    }, 50);
  }
}

const shapeText = ref('')
const changeShapeText = (e: any) => {
  console.log('changeShapeText', e.target.value)
  if (!validateInput(e.target.value)) {
    showToast(config.preview.messages.invalidInput)
    shapeText.value = e.target.value.replace(/[^a-zA-Z0-9\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7a3\u00c0-\u017f\s~！@#￥%……&*（）——+_)(*&^%$#@!~?><:"}{|、】【'；、。，'.]/g, '');
    return;
  } 
  handleInput(e.target.value)
}

const topText = ref('')
const changeTopText = (e: any) => {
  console.log('changeTopText', e.target.value)
  if (!validateInput(e.target.value)) {
    showToast(config.preview.messages.invalidInput)
    topText.value = e.target.value.replace(/[^a-zA-Z0-9\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7a3\u00c0-\u017f\s~！@#￥%……&*（）——+_)(*&^%$#@!~?><:"}{|、】【'；、。，'.]/g, '');
    return;
  } 
  handleInput(e.target.value, 'top')
  const textPos = shapeList.value.find((item: any) => item.id === shapeId.value)?.text_pos?.find((d: any) => d.position_place == 'top')
  if (textPos) {
    textPos.frame_path = shapeImage.value;
    textShow(textPos, 'top')
  }
}

const bottomText = ref('')
const changeBottomText = (e: any) => {
  console.log('changeBottomText', e.target.value)
  if (!validateInput(e.target.value)) {
    showToast(config.preview.messages.invalidInput)
    bottomText.value = e.target.value.replace(/[^a-zA-Z0-9\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7a3\u00c0-\u017f\s~！@#￥%……&*（）——+_)(*&^%$#@!~?><:"}{|、】【'；、。，'.]/g, '');
    return;
  } 
  handleInput(e.target.value, 'bottom')
  const textPos = shapeList.value.find((item: any) => item.id === shapeId.value)?.text_pos?.find((d: any) => d.position_place == 'bottom')
  if (textPos) {
    textPos.frame_path = shapeImage.value;
    textShow(textPos, 'bottom')
  }
}

const frontSaveText = ref('')
const changeFrontText = (e: any) => {
  const inputValue = e?.target?.value ?? frontText.value
  console.log('changeFrontText', inputValue)
  frontText.value = inputValue
  frontSaveText.value = inputValue
  handleInput(inputValue)
  if (typeId.value == 6 && shapeList.value.length > 0) {
    const currentShape = shapeList.value.find((item: any) => item.id === shapeId.value)
    if (currentShape && currentShape.axisz == 1) {
      frontTextShow(currentShape, true)
    }
  }
}

const backSaveText = ref('')
const changeBackText = (e: any) => {
  const inputValue = e?.target?.value ?? backText.value
  console.log('changeBackText', inputValue)
  backText.value = inputValue
  backSaveText.value = inputValue
  handleInput(inputValue)
  if (typeId.value == 6 && shapeList.value.length > 0) {
    const currentShape = shapeList.value.find((item: any) => item.id === shapeId.value)
    if (currentShape && currentShape.axisz == -1) {
      frontTextShow(currentShape, false)
    }
  }
}

const validateInput = (input: string) => {
  const regex = /^[a-zA-Z0-9\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7a3\u00c0-\u017f\s~！@#￥%……&*（）——+_)(*&^%$#@!~?><:"}{|、】【'；、。，'.]+$/;
  return regex.test(input);
}

const handleInput = (value: string, type: string = 'shape') => {
  let byteLength = calculateByteLength(value);
  console.log('byteLength', byteLength, limitCount.value)
  if (byteLength > limitCount.value) {
    let validValue = '';
    let currentBytes = 0;
    for (let i = 0; i < value.length; i++) {
      const char = value.charAt(i);
      const code = char.charCodeAt(0);
      let charBytes = 0;
      if (code === 32) {
        charBytes = 1;
      } else {
        charBytes = code > 255 ? 2 : 1;
      }
      if (currentBytes + charBytes <= limitCount.value) {
        validValue += char;
        currentBytes += charBytes;
      } else {
        break;
      }
    }
    if (typeId.value == 2) {
      if (config.preview.shapeIds.topBottomText.includes(shapeId.value)) {
        type == 'top' ? topText.value = validValue : bottomText.value = validValue;
      } else {
        shapeText.value = validValue;
      }
    } else {
      if (axisz.value == 1) {
        frontText.value = validValue;
        frontSaveText.value = validValue;
      } else {
        backText.value = validValue;
        backSaveText.value = validValue;
      }
    }
    if (typeId.value == 6 && shapeList.value.length > 0) {
      const currentShape = shapeList.value.find((item: any) => item.id === shapeId.value)
      if (currentShape) {
        if (currentShape.axisz == 1) {
          frontTextShow(currentShape, true)
        } else if (currentShape.axisz == -1) {
          frontTextShow(currentShape, false)
        }
      }
    }
    return;
  }
  if (typeId.value == 2) {
    if (config.preview.shapeIds.topBottomText.includes(shapeId.value)) {
      type == 'top' ? topText.value = value : bottomText.value = value;
    } else {
      shapeText.value = value;
    }
  } else {
    if (axisz.value == 1) {
      frontText.value = value;
      frontSaveText.value = value;
    } else {
      backText.value = value;
      backSaveText.value = value;
    }
  }
  if (typeId.value == 6 && shapeList.value.length > 0) {
    const currentShape = shapeList.value.find((item: any) => item.id === shapeId.value)
    if (currentShape) {
      if (currentShape.axisz == 1) {
        frontTextShow(currentShape, true)
      } else if (currentShape.axisz == -1) {
        frontTextShow(currentShape, false)
      }
    }
  }
}

const calculateByteLength = (str: string) => {
  let len = 0;
  for (let i = 0; i < str.length; i++) {
    const code = str.charCodeAt(i);
    if (code === 32) {
      len += 1;
    } else {
      len += code > 255 ? 2 : 1;
    }
  }
  return len;
}

const shapeChange = (item: any) => {
  console.log('shapeChange', item)
  sizeList.value.map((item: any) => {
    if (item.shape_id !== item.id) {
      item.count = 0
    }
  })
  shapeText.value = '';
  shapeId.value = item.id
  shapeImage.value = item.frame_path
  custom_switch.value = item.custom_switch
  limitCount.value = item.text_limit_max
  if (typeId.value == 3) {
    imageUrl.value = config.preview.shapeIds.frame.includes(item.id) ? originUrl.value : frameUrl.value
  } else {
    imageUrl.value = originUrl.value
  }
  ImageShow(item)
  if (custom_switch.value == 1 && typeId.value == 2) {
    shapeText.value = ''
    topText.value = ''
    bottomText.value = ''
    topTextStyle.value = ''
    bottomTextStyle.value = ''
    shapeTextStyle.value = ''
    textShow(item)
  }
  if (custom_switch.value == 1 && typeId.value == 6) {
    if (item.axisz == 1) {
      axisz.value = 1
      frontKey.value = 1
      frontText.value = frontSaveText.value ? frontSaveText.value : ''
      backText.value = backSaveText.value ? backSaveText.value : ''
      frontTextShow(item, true)
    } else if (item.axisz == -1) {
      axisz.value = -1
      frontKey.value = 2
      backText.value = backSaveText.value ? backSaveText.value : ''
      frontText.value = frontSaveText.value ? frontSaveText.value : ''
      frontTextShow(item, false)
    }
  }
}

const orderStat = ref({})
const typeId = ref(0)
const subjectId = ref(0)
const getOrderStat = () => {
  badgeApi.getOrderStat({}).then((res: any) => {
    console.log('getOrderStat', res)
    orderStat.value = res
    typeId.value = res.type_id
    subjectId.value = res.subject_id
    badgeTypeId.value = res.type_id
    getSizeList()
  })
}

function handleBeforeUnload(_event: BeforeUnloadEvent) {
  // code 的清除已在 main.ts 中统一处理，这里只处理页面特定的清理逻辑
  // 清除轮询和进度条计时器
  clearInterval(timer.value)
  clearInterval(progressTimer.value)
  // userId 的清除由 main.ts 统一处理
}

const pid = ref(0)
const route = useRoute()
const prodId = ref(0)
const kindId = ref(0)
onMounted(() => {
  pid.value = route.query.pid
  group.value = route.query.group
  if (route.query.key) {
    imgKey.value = route.query.key
  }
  if (route.query.prod_id) {
    prodId.value = route.query.prod_id
  }
  if (route.query.kind_id) {
    kindId.value = Number(route.query.kind_id)
  }
  getOrderStat()

  getImageList()
  progressList()
  setTimeout(() => {
    getCompareImage()
  }, config.preview.polling.compareImageDelay)
  timer.value = setInterval(() => {
    getImageList()
  }, config.preview.polling.interval)
  window.addEventListener('beforeunload', handleBeforeUnload);
})

onUnmounted(() => {
  clearInterval(timer.value)
  clearInterval(progressTimer.value)
})

const searchResult = ref([])
</script>
<style scoped>
.preview-container {
  min-height: 100vh;
  font-family: 'PingFang SC', Arial, sans-serif;
  color: #222;
}
.backstyle_1 {
  position: fixed;
  left: -110px;
  top: -40px;
  width: 328px;
  height: 216px;
  opacity: 0.2;
  transform: rotate(-13.72deg);
  border-radius: 50%;
  background-image: radial-gradient( rgba(250, 182, 55, 0.726), #ebd5a09c, #d4cab100);
  z-index: -10;
}
.backstyle_2 {
  position: fixed;
  left: 97px;
  top: -95px;
  width: 370px;
  height: 374px;
  opacity: 0.1;
  border-radius: 50%;
  background-image: radial-gradient( rgb(69, 255, 63), #90f2729a, #90f27200);
  z-index: -10;
}
.header {
  display: flex;
  align-items: center;
  height: 40px;
  font-size: 14px;
  color: #999;
  padding: 16px 16px 0 16px;
}
.back-icon {
  margin-right: 8px;
  color: #222;
  font-size: 16px;
  cursor: pointer;
}

.step-container {
  display: flex;
  align-items: flex-start;
  padding: 16px 16px 16px 0;
}
.step-item {
  display: flex;
  align-items: center;
  flex: 1;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.step-item.active {
  flex: 2.5;
}
.step-num {
  font-size: 48px;
  line-height: 1;
  position: relative;
  margin-right: 8px;
  text-shadow: 0 2px 8px #e6f7e6;
  color: #CCCCCC;
}
.step-item.active .step-num {
  color: #fff;
  text-shadow:
    1px 1px 0 #000,
    -1px -1px 0 #000,
    -1px 1px 0 #000,
    1px -1px 0 #000,
    0 1px 0 #000,
    1px 0 0 #000,
    0 -1px 0 #000,
    -1px 0 0 #000;
}
.step-item.active .step-num::after {
  content: '';
  position: absolute;
  top: 20px;
  right: 0;
  width: 15px;
  height: 15px;
  background-color: #50cf54;
  opacity: 0.5;
  border-radius: 50%;
}
.step-content {
  display: flex;
  flex-direction: column;
  height: 48px;
}
.step-item.active .step-title {
  color: #000;
  font-weight: bold;
  font-size: 16px;
}
.step-item.active .step-desc {
  color: #808080;
  font-size: 13px;
}
.step-title {
  font-size: 16px;
  color: #808080;;
}
.step-desc {
  font-size: 12px;
  color: #808080;
  margin-top: 2px;
}
.progress-section {
  margin: 0 auto;
  text-align: center;
  width: 100vw;
  height: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}
.progress-section-picture {
  width: 320px;
  height: 320px;
  position: relative;
  margin: 0 auto;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}
.progress-section-img {
  position: relative;
  display: flex;
  justify-content: center;
}
.box1-back-image {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  object-fit: cover;
  border-radius: 10px;
} 
.box1-front-box {
  position: absolute;
  z-index: 1;
}
.box1-front-image {
  width: 100%;
  height: auto;
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.3);
}
.progress-bar-bg {
  width: 70%;
  height: 10px;
  background: #eee;
  border-radius: 5px;
  margin: 0 auto 8px auto;
  position: relative;
  overflow: hidden;
}
.progress-bar-fg {
  height: 100%;
  background: #6fdc8c;
  border-radius: 5px;
  transition: width 0.3s;
}
.progress-text {
  font-size: 15px;
  color: #222;
  margin-bottom: 2px;
}
.progress-desc {
  font-size: 12px;
  color: #999;
}
.info-section {
  display: flex;
  justify-content: flex-start;
  padding: 16px;
}
.info-item {
  flex: 1;
}
.info-title {
  font-size: 13px;
  color: #222;
  font-weight: 600;
  margin-bottom: 2px;
}
.info-content {
  font-size: 12px;
  color: #999;
}
.order-section {
  border-radius: 10px;
  padding: 0 16px;
  margin-bottom: 18px;
}
.order-title {
  font-size: 14px;
  color: #222;
  font-weight: 600;
  margin-bottom: 10px;
}
.order-item {
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}
.order-size {
  font-size: 15px;
  color: #222;
  margin-right: 8px;
}
.order-free {
  font-size: 12px;
  color: #999;
  margin-right: 16px;
}
.order-ctrl {
  display: flex;
  align-items: center;
  margin-left: auto;
}
.confirm-box {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  background: #fff;
  z-index: 10;
  padding: 0 16px 16px 16px;
  border-top: 1px solid #e6e6e6;
}
.action-section {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  padding: 0 16px;
}
.action-btn {
  flex: 1;
  margin: 0 4px;
  border: none;
  border-radius: 8px;
  color: #222;
  font-size: 13px;
  padding: 8px 0;
  cursor: pointer;
  transition: background 0.2s;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #fff;
}
.action-img {
  width: 20px;
  height: 20px;
  margin-right: 5px;
}
.btn-box {
  display: flex;
  justify-content: center;
  align-items: center;
}
.confirm-btn {
  width: 80vw;
  background: linear-gradient(90deg, #D1ED8E 0%, #55E668 100%);
  color: #000;
  font-size: 17px;
  font-weight: 600;
  border: none;
  border-radius: 24px;
  padding: 12px 0;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(111,220,140,0.08);
  letter-spacing: 2px;
}
.confirm-btn:active {
  background: linear-gradient(90deg, #5ccf7a 0%, #8fdca0 100%);
}
.preview-mask {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
.preview-mask img {
  max-width: 80%;
  max-height: 80%;
  border-radius: 10px;
  box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
}
.preview-mask p {
  margin-top: 16px;
  color: #fff;
  font-size: 16px;
  text-align: center;
} 
.progress-image-item-shadow {
  position: absolute;
  top: 0;
  left: 0;
  width: 80vw;
  height: 80vw;
  object-fit: cover;
  box-shadow: inset 2px 2px 4px  rgba(255, 255, 255, 0.5),inset -2px -2px 4px  rgba(0, 0, 0, 0.2);
  border-radius: 50%;
}
.image-list-box {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 16px 16px 0 16px;
}
.image-list-item {
  width: 20vw;
  height: 20vw;
}
.image-list-item-img {
  width: 20vw;
  height: 20vw;
  border-radius: 12px;
  border: 3px solid #fff;
  background: rgba(0, 0, 0, 0.3);
}
.image-list-item-img.imgActive {
  border: 3px solid #50cf54;
}
.image-list-item-loading {
  width: 20vw;
  height: 20vw;
  border-radius: 12px;
  background: #f0f0f0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  color: #999;
}
.shape-body {
  background: #fff;
  border-radius: 8px;
  padding: 0 20px;
}
.shape-box {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  justify-content: flex-start;
}
.shape-title {
  padding-bottom: 12px;
  font-size: 14px;
  font-weight: bold;
}
.shape-item {
  position: relative;
  flex: 0 0 24%;
  /* margin-right: calc(4% / 3); */
  margin-bottom: calc(4% / 2);
  margin-right: 8px!important;
}
.shape-item:nth-child(4n){ 
  margin-right: 0; 
} 
.shape-item:last-child{ 
  margin-right: auto; 
}
.shape-item-image {
  width: 20vw;
  height: 20vw;
  border-radius: 8px;
}
.shape-icon {
  position: absolute;
  right: 6px;
  top: 14vw;
}
.shape-item-text {
  font-size: 12px;
  text-align: center;
  max-width: 20vw;
}
.shape-type {
  display: -webkit-box;
  overflow-x: scroll;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding-bottom: 16px;
}
.shape-type-item {
  background: #F0F2F5;
  font-size: 12px;
  height: 7vw;
  padding: 0px 16px;
  border-radius: 4px;
  margin-right: 8px;
  display: flex;
  justify-content: center;
  align-items: center;
}
.shape-active {
  background: #15CF5F;
  color: #fff;
}
.shape-box-input {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 10px;
}
.shape-box-input-box {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 10px;
  gap: 10px;
  flex-direction: column;
}
.shape-box-input-text {
  width: 100%;
  height: 40px;
  border: 1px solid #ccc;
  border-radius: 4px;
  padding: 0 10px;
}
.shape-text {
  position: absolute;
  z-index: 2;
  font-family: chinese;
  overflow: hidden;
  text-shadow: 1px 0px 1px #000000a1;
  white-space: pre-wrap;
}
.font-chinese {
  font-family: chinese;
}
.shape-item-image-round {
  border-radius: 50%;
}
.van-address-edit {
  padding: 0!important;
}
</style>