<template>
  <div class="photo-upload-page">
    <div class="badge-size">
      <div class="order-type">
        <div class="order-type-item" v-if="orderStat.order_no">
          <div class="order-type-item-title">
            {{ toValueWithout("订单编号") }}
          </div>
          <div class="order-type-item-title">
            {{ orderStat.order_no }}
          </div>
        </div>
        <div class="order-type-item" v-if="prodId">
          <div class="order-type-item-title">
            {{ toValueWithout("产品类型") }}
          </div>
          <div class="order-type-item-title" v-if="typeName">
            {{ toValueWithout(typeName) }}
          </div>
        </div>
        <div class="order-type-item" v-if="prodId">
          <div class="order-type-item-title">
            {{ toValueWithout("主体类型") }}
          </div>
          <div class="order-type-item-title" v-if="subjectName">
            {{ toValueWithout(subjectName) }}
          </div>
        </div>
      </div>
      <div class="size-title">
        {{ toValueWithout("剩余兑换数量") }}
      </div>
      <div class="size-options">
        <div class="size-item" v-for="item in sizeList" :key="item.id">
          <div class="size-text">
            {{ item.size }}
          </div>
          <div class="size-count">
            （{{ toValueWithout("剩余兑换") }}：{{ item.remaining }}）
          </div>
        </div>
      </div>
    </div>
    <div class="badge-info">
      <div class="badge-item" @click="goToRecord">
        <div class="badge-title">
          {{ toValueWithout("设计图集") }}
        </div>
        <div class="badge-count">
          {{ orderStat.create_count || 0 }}{{ toValueWithout("张") }}
        </div>
      </div>
      <div class="badge-item" @click="goToMyOrder">
        <div class="badge-title">
          {{ toValueWithout("我的订单") }}
        </div>
        <div class="badge-count">
          {{ orderStat.order_count || 0 }}{{ toValueWithout("笔") }}
        </div>
      </div>
    </div>
    <div :style="`height: ${config.styles.spacing.itemGap};background: ${config.styles.colors.backgroundSecondary};`"></div>
    <div class="step-container">
      <div class="step-item active">
        <div class="step-num">
          1
        </div>
        <div class="step-content">
          <div class="step-title">
            {{ toValueWithout("上传正面照片") }}
          </div>
          <div class="step-desc">
            {{ toValueWithout("1张五官清晰的正面照片") }}
          </div>
        </div>
      </div>
      <div class="step-item">
        <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="shouldShowKindList">
      <div :style="`font-size: 16px; color: ${config.styles.colors.textPrimary}; font-weight: bold; margin-top: ${config.styles.spacing.sectionMargin};padding: 0 ${config.styles.spacing.pagePadding};`">
        {{ toValueWithout("风格类型") }}
      </div>
      <div class="kind-box">
        <div class="kind-box-item" v-for="item in kindList" :key="item.id" :class="{ styleActive: kindId == item.id }">
          <div class="kind-item-title" @click="kindChange(item)">
            {{ toValueWithout(item.name) }}
          </div>
        </div>
      </div>
    </div>
    <div v-if="typeId == 11 && count_prop > 0">
      <div :style="`font-size: 16px; color: ${config.styles.colors.textPrimary}; font-weight: bold; margin-top: ${config.styles.spacing.sectionMargin};padding: 0 ${config.styles.spacing.pagePadding};`">
        {{ toValueWithout("相框标题") }}
      </div>
      <div :style="`padding: 10px ${config.styles.spacing.pagePadding};`">
        <el-input type="text" v-model="scene_prop" :placeholder="toValueWithout('请输入相框标题')" @input="scenePropInputText" />
        <div class="photo-upload-tip" style="color: red;">
          *{{ toValueWithout("相框标题将用于生成图片，请输入简洁明了的相框标题") }}
        </div>
      </div>
    </div>
    <div v-if="isViews == 1">
      <div :style="`font-size: 16px; color: ${config.styles.colors.textPrimary}; font-weight: bold; margin-top: ${config.styles.spacing.sectionMargin};padding: 0 ${config.styles.spacing.pagePadding};`">
        {{ toValueWithout("多视角参考图") }}
      </div>
      <div :style="`font-size: 12px; color: ${config.styles.colors.textTertiary}; margin-top: ${config.styles.spacing.itemGap};padding: 0 ${config.styles.spacing.pagePadding};`">
        {{ toValueWithout("AI建模具有随机性，上传参考图有助于更好的还原主体特征") }}
      </div>
      <div class="photo-upload-box-refer">
        <van-uploader 
          v-model="referPicture" 
          multiple 
          :max-count="config.upload.maxReferCount" 
          :max-size="config.upload.maxSize" 
          @oversize="onOversize" 
          :deletable="true" 
          :show-preview="true" 
          :before-read="beforeRead" 
          upload-icon="plus" />
      </div>
    </div>
    <div v-if="typeId == 8 && mountsList.length > 0">
      <div :style="`font-size: 16px; color: ${config.styles.colors.textPrimary}; font-weight: bold; margin-top: ${config.styles.spacing.sectionMargin};padding: 0 ${config.styles.spacing.pagePadding};`">
        {{ toValueWithout("坐骑类型") }}
      </div>
      <div class="mounts-list-container" :style="`padding: 0 ${config.styles.spacing.pagePadding};`">
        <div v-for="item in mountsList" :key="item.id" class="mounts-item" @click="rideChange(item)">
          <div class="mounts-item-list">
            <img 
              class="mounts-item-image" 
              :src="item.image" 
              :alt="toValueWithout(item.name)"
            />
            <van-icon 
              v-if="item.id == mountsId" 
              class="mounts-icon" 
              :color="config.styles.colors.success" 
              name="checked" 
              size="18px" 
            />
          </div>
          <div class="mounts-item-text">{{ toValueWithout(item.name) }}</div>
        </div>
      </div>
    </div>
    <div v-if="typeId == 9 && count_prop > 0">
      <div :style="`font-size: 16px; color: ${config.styles.colors.textPrimary}; font-weight: bold; margin-top: ${config.styles.spacing.sectionMargin};padding: 0 ${config.styles.spacing.pagePadding};`">
        {{ toValueWithout("场景道具") }}
      </div>
      <div :style="`padding: 10px ${config.styles.spacing.pagePadding};`">
        <div :style="`margin-top: 16px;`">
          <div
            v-for="(_, index) in 4"
            :key="index"
            :style="`display: flex; align-items: center; margin-bottom: 12px;`"
          >
            <el-input
              v-model="scenePropsInputs[index]"
              :placeholder="toValueWithout('请输入场景道具')"
              :style="`flex: 1; margin-right: 8px;`"
              @input="updateScenePropFromInputs"
              clearable
            />
          </div>
        </div>
      </div>
    </div>
    <div class="photo-upload-body">
      <div v-if="!picture" class="photo-upload-box">
        <div class="photo-upload-area">
          <div class="photo-upload-plus">
            +
          </div>
          <div class="photo-upload-text">
            {{ toValueWithout("点击上传照片") }}
          </div>
          <div class="photo-upload-tip">
            *{{ toValueWithout("上传照片时建议勾选[原图]") }}
          </div>
        </div>
        <div class="photo-upload-footer">
          {{ toValueWithout("请确定您对上传的照片拥有合法使用权利或已取得他人合法授权，且同意本平台分析图片信息以提供生成服务") }}
        </div>
      </div>
      <img class="photo-upload-img" v-if="picture" :src="picture" alt="" srcset="">
      <div class="photo-upload-box-1">
        <h5-cropper :option="option" @getbase64Data="getbase64Data" @imgorigoinf="imgorigoinf"></h5-cropper>
      </div>
    </div>
    <div :style="`height: 120px;`"></div>
    <div class="design-action-bar">
      <div class="design-left">
        <img class="design-leaf-icon" width="18" height="18" :src="leafIcon" alt="">
        <span class="design-remaining">{{ toValueWithout("剩余") }}{{ orderStat.remain_count || 0 }}{{ toValueWithout("次") }}</span>
      </div>
      <button class="design-btn" @click="goToPreview">
        <span>{{ toValueWithout("开始设计") }}</span>
        <img class="design-arrow" :src="arrowIcon" alt="">
      </button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { useRouter } from 'vue-router'
import H5Cropper from 'vue-cropper-h5'
import "vue-cropper-h5/dist/style.css"
import { showLoadingToast, showToast, closeToast, showFailToast, showSuccessToast } from 'vant';
import type { UploaderFileListItem } from 'vant'
import * as badgeApi from '@/api/badge'
import { useTranslation } from "i18next-vue";
import * as i18n from '@/lang/utils'
import { toValueWithout } from '@/lang/utils'
import { cartoonConfig } from '@/config/cartoon'
import leafIcon from '@/assets/badge/leaf.png'
import arrowIcon from '@/assets/badge/arrow.png'

// 初始化翻译功能
const { t } = useTranslation();
i18n.set(t);

// 使用配置
const config = cartoonConfig

const referPicture = ref<UploaderFileListItem[]>([])
const router = useRouter()

// 初始化裁剪器配置
const option = ref({
  ...config.upload.cropOptions
})

// 判断是否是APP
const openApp = () => {
  const ua = navigator.userAgent;
  const isIOS = /iPhone|iPad|iPod/i.test(ua);
  const isAndroid = /Android/i.test(ua);

  if (isIOS) {
    option.value.ceilbutton = true
  } else if (isAndroid) {
    option.value.ceilbutton = false
  } else {
    option.value.ceilbutton = true
  }
}

const imgurl = ref('')

// 跳转设计图集
function goToRecord() {
  router.push(config.routes.record)
}

// 跳转我的订单
function goToMyOrder() {
  router.push(config.routes.myOrder)
}

// 获取兑换数量
const sizeList = ref([])
const getSizeList = () => {
  badgeApi.getOrderPrice({}).then((res: any) => {
    sizeList.value = res
  })
}

// 获取首页显示的数量和类型
const orderStat = ref({})
const prodId = ref(0)
const prop = ref('')
const typeId = ref(0)
const subjectId = ref(0)
const typeName = ref('')
const subjectName = ref('')
const isViews = ref(0)
const getOrderStat = () => {
  badgeApi.getOrderStat({}).then((res: any) => {
    orderStat.value = res
    prodId.value = res.prod_id
    prop.value = res.prop
    typeId.value = res.type_id
    typeName.value = res.type_name
    subjectId.value = res.subject_id
    subjectName.value = res.subject_name
    isViews.value = res.is_views
    getKindList()
    if (res.type_id === 8) {
      mountsId.value = 0
      getmountsList()
    } else if (res.type_id === 9) {
      scenePropsInputs.value = ['', '', '', '']
      scene_prop.value = ''
    }
  })
}

// 计算属性：是否显示照片示例
const shouldShowPhotoExample = computed(() => {
  return config.productLimits.photoExampleTypes.includes(prop.value)
})

// 计算属性：是否显示风格类型
const shouldShowKindList = computed(() => {
  return kindList.value.length > 0
})

const kindList = ref([])
const getKindList = () => {
  badgeApi.getKindList({
    prod_id: prodId.value
  }).then((res: any) => {
    kindList.value = res.list
    kindId.value = res.list && res.list[0]?.id
    count_prop.value = res.list && res.list[0]?.count_prop
  })
}



const kindId = ref(0)
const count_prop = ref(0)
const kindChange = (item: any) => {
  kindId.value = item.id
  count_prop.value = item.count_prop
}

// 计算字符单位：中文占2个，英文/数字/空格/符号占1个
const getCharUnits = (str: string) => {
  let units = 0
  for (const char of str) {
    units += /[\u4e00-\u9fff\u3400-\u4dbf]/.test(char) ? 2 : 1
  }
  return units
}

// 限制最多 12 个字符单位：中文占2个，英文/数字/空格/符号占1个
const scenePropInputText = (val: string) => {
  if (getCharUnits(val) > 18) {
    let units = 0
    let i = 0
    for (; i < val.length; i++) {
      const add = /[\u4e00-\u9fff\u3400-\u4dbf]/.test(val[i]) ? 2 : 1
      if (units + add > 18) break
      units += add
    }
    val = val.slice(0, i)
  }
  scene_prop.value = val
}

// 形状列表相关
const mountsList = ref<any[]>([])
const mountsId = ref(0)

// 获取图片URL
const getImageUrl = (path: string) => {
  if (!path) return ''
  return 'https://suwa3d-3dview.oss-cn-shanghai.aliyuncs.com/' + path
}

// 获取形状列表
const getmountsList = () => {
  if (!prodId.value || !typeId.value) {
    return
  }
  badgeApi.getMountsList({
    prod_id: prodId.value,
    type_id: typeId.value,
    status: 1,
    page: 1,
    size: 1000
  }).then((res: any) => {
    if (res && res.list && res.list.length > 0) {
      mountsList.value = res.list
      // 默认选中第一个
      if (!mountsId.value) {
        mountsId.value = res.list[0].id
      }
    }
  }).catch((err: any) => {
    console.error('getShapeList', err)
  })
}

// 切换形状
const rideChange = (item: any) => {
  mountsId.value = item.id
}

const scene_prop = ref('') // 四个输入框的值用;拼接后提交接口

// 场景道具四个输入框
const scenePropsInputs = ref<string[]>(['', '', '', ''])

// 四个输入框有值时，用;拼接更新到 scene_prop
const updateScenePropFromInputs = () => {
  scene_prop.value = scenePropsInputs.value
    .map(v => (v || '').trim())
    .filter(v => v)
    .join(';')
}

const isLoading = ref(false)

// 生成图片
function goToPreview() {
  if (isLoading.value) {
    return
  }
  if (!imgurl.value) {
    showToast(toValueWithout('请先上传照片'))
    return
  }
  if (orderStat.value.remain_count <= 0) {
    showToast(toValueWithout('剩余次数不足'))
    return
  }
  isLoading.value = true
  getPid()
}

const picture = ref(null)

const imageWidth = ref(0);
const imageHeight = ref(0);

function getbase64Data(data: string) {
  picture.value = data;

  const img = new Image();
  img.src = data;
  img.onload = () => {
    imageWidth.value = img.naturalWidth;
    imageHeight.value = img.naturalHeight;
    if (imageWidth.value < config.upload.minWidth || imageHeight.value < config.upload.minHeight) {
      showToast(toValueWithout(`请上传尺寸大于${config.upload.minWidth}*${config.upload.minHeight}像素的照片`))
      imgurl.value = null
      picture.value = null
      return false;
    }
    const blob = base64ToBlob(data);
    if (blob.size > config.upload.maxSize) {
      showToast(toValueWithout(`照片大小不能超过${config.upload.maxSize / 1024 / 1024}M`))
      imgurl.value = null
      picture.value = null
      return false;
    }
    imgurl.value = blob;
  }
}

function base64ToBlob(base64: string) {
  const arr = base64.split(',');
  const mime = arr[0].match(/:(.*?);/)?.[1] || 'image/jpeg';
  const bstr = atob(arr[1]);
  const n = bstr.length;
  const u8arr = new Uint8Array(n);
  for (let i = 0; i < n; i++) {
    u8arr[i] = bstr.charCodeAt(i);
  }
  return new Blob([u8arr], {
    type: mime
  });
}

function imgorigoinf(data: File) {
  const img = new Image();
  const objectUrl = URL.createObjectURL(data);
  img.src = objectUrl;
  img.onload = () => {
    imageWidth.value = img.naturalWidth;
    imageHeight.value = img.naturalHeight;
    if (imageWidth.value < config.upload.minWidth || imageHeight.value < config.upload.minHeight) {
      showToast(toValueWithout(`请上传尺寸大于${config.upload.minWidth}*${config.upload.minHeight}像素的照片`))
      setTimeout(() => {
        const btn = document.querySelector('.btn')
        if (btn) {
          (btn as HTMLElement).click()
        }
      }, 1500);
      imgurl.value = null
      picture.value = null
      return
    }
    URL.revokeObjectURL(objectUrl)
  }
  img.onerror = () => {
    URL.revokeObjectURL(objectUrl)
  }
}

const onOversize = (file: any) => {
  if (file.size > config.upload.maxSize) {
    showToast(toValueWithout(`照片大小不能超过${config.upload.maxSize / 1024 / 1024}M`))
    return false
  }
  return true
}

const beforeRead = (file: any) => {
  const toPreviewAndCheck = (input: any): Promise<UploaderFileListItem> => {
    return new Promise((resolve, reject) => {
      const raw: File = input.file || input
      if (raw.size > config.upload.maxSize) {
        showToast(toValueWithout(`照片大小不能超过${config.upload.maxSize / 1024 / 1024}M`))
        reject(false)
        return
      }
      const objectUrl = URL.createObjectURL(raw)
      const img = new Image()
      img.src = objectUrl
      img.onload = () => {
        const width = img.naturalWidth
        const height = img.naturalHeight
        imageWidth.value = width
        imageHeight.value = height
        URL.revokeObjectURL(objectUrl)
        if (width < config.upload.minWidth || height < config.upload.minHeight) {
          showToast(toValueWithout(`请上传尺寸大于${config.upload.minWidth}×${config.upload.minHeight}像素的照片`))
          reject(false)
          return
        }
        const reader = new FileReader()
        reader.onload = (e) => {
          const url = e.target?.result as string
          const out: any = input
          out.url = url
          resolve(out)
        }
        reader.onerror = () => {
          showToast(toValueWithout('图片读取失败'))
          reject(false)
        }
        reader.readAsDataURL(raw)
      }
      img.onerror = () => {
        showToast(toValueWithout('图片加载失败'))
        URL.revokeObjectURL(objectUrl)
        reject(false)
      }
    })
  }

  if (Array.isArray(file)) {
    return Promise.allSettled(file.map(toPreviewAndCheck)).then((results) => {
      const passed = results
        .filter(r => r.status === 'fulfilled')
        .map((r: any) => r.value)
      if (passed.length === 0) return Promise.reject(false)
      return passed
    })
  }
  return toPreviewAndCheck(file)
}

// 获取Pid
const pid = ref('')
const getPid = async () => {
  showLoadingToast({
    message: toValueWithout('上传中...'),
    forbidClick: true,
    loadingType: 'spinner',
    duration: 0,
  })
  const params = {
    prod_id: prodId.value,
    type_id: typeId.value,
    subject_id: subjectId.value
  }
  try {
    const res = await badgeApi.getPid(params) as any
    isLoading.value = false
    pid.value = res.pid
    try {
      const uploadTasks = [
        sendToOss(imgurl.value, res.url),
      ]
      await Promise.all(uploadTasks)
      if (isViews.value == 1 && referPicture.value.length > 0) {
        const multiUrlTasks = referPicture.value.map((item) => {
          return badgeApi.getMultiUrl({
            pid: pid.value,
          }).then((res: any) => {
            return sendToOss(item.file, res.multi_url)
          })
        })
        await Promise.all(multiUrlTasks)
      }
    } catch (err) {
      closeToast()
      console.error('上传失败:', err)
      showFailToast({
        message: toValueWithout('上传失败'),
        duration: 2000,
      })
      isLoading.value = false
      return
    }
  } catch (err: any) {
    isLoading.value = false
    closeToast()
    showToast({
      message: err.message,
      duration: 2000,
    })
  } finally {
    isLoading.value = false
  }
}

// 上传到OSS
const pendingUploads = ref(0)
const isAnotherAPICalled = ref(false)
const sendToOss = async (src: string | Blob | File, url: string) => {
  try {
    pendingUploads.value++
    const response = await fetch(url, {
      method: 'PUT',
      headers: {
        'Content-Type': 'image/jpeg'
      },
      body: src
    })

    if (!response.ok) {
      throw new Error('Upload failed')
    }
    
    if (--pendingUploads.value === 0 && !isAnotherAPICalled.value) {
      isAnotherAPICalled.value = true
      createLog()
    }

  } catch (err: any) {
    closeToast()
    pendingUploads.value--
    showFailToast({
      message: err.message,
      duration: 2000,
    })
  }
}

// 创建日志
const createLog = () => {
  const params = {
    pid: pid.value,
    group: 1,
    prod_id: prodId.value,
    type_id: typeId.value,
    kind_id: kindId.value,
    subject_id: subjectId.value,
    scene_prop: scene_prop.value ? scene_prop.value : undefined,
    mounts_id: mountsId.value || undefined,
  }
  badgeApi.createLog(params).then(() => {
    closeToast()
    showSuccessToast({
      message: toValueWithout('照片上传成功'),
      duration: 2000,
    })
    setTimeout(() => {
      closeToast()
      router.push({
        path: config.routes.preview,
        query: {
          pid: pid.value,
          group: 1,
          prod_id: prodId.value,
          type_id: typeId.value,
          kind_id: kindId.value,
          subject_id: subjectId.value
        },
      })
    }, 1000);
  }).catch((err: any) => {
    showFailToast({
      message: err.message,
      duration: 2000,
    })
  }).finally(() => {
    closeToast()
  })
}

onMounted(() => {
  openApp()
  getOrderStat()
  getSizeList()
})
</script>

<style lang="scss" scoped>
.photo-upload-page {
  height: auto;
  overflow-y: scroll!important;
}
.badge-size {
  padding: 16px;
  .size-title {
    font-size: 14px;
    color: #000;
  }
  .size-options {
    .size-item {
      margin-top: 8px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      .size-text {
        font-size: 14px;
        color: #333;
        text-align: center;
        padding: 4px 10px;
        background: #F0F2F5;
        border-radius: 4px;
        margin-right: 5px;
        display: inline-block;
      }
      .size-count {
        font-size: 12px;
        color: #999;
        display: inline-block;
      }
    }
  }
}
.badge-info {
  display: flex;
  justify-content: space-between;
  padding: 0 16px 16px 16px;
  .badge-item:first-child {
    background-image: url('@/assets/badge/sheji.png');
    background-size: cover;
    background-position: center;
    margin-right: 5px;
  }
  .badge-item:last-child {
    background-image: url('@/assets/badge/order.png');
    background-size: cover;
    background-position: center;
    margin-left: 5px;
  }
  .badge-item {
    padding: 18px 12px;
    flex: 1;
    text-align: left;
    cursor: pointer;
    height: 88px;
    .badge-title {
      font-size: 16px;
      color: #000;
      font-weight: bold;
    }
    .badge-count {
      font-size: 15px;
      color: #333;
      font-weight: bold;
      margin-top: 8px;
    }
  }
}
.step-container {
  display: flex;
  align-items: flex-start;
  padding: 16px 0 16px 16px;
}
.step-item {
  display: flex;
  align-items: center;
  flex: 1;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.step-item.active {
  flex: 2;
  margin-left: 50px;
}
.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;
}
.step-title {
  font-size: 16px;
  color: #808080;
}
.step-desc {
  font-size: 12px;
  color: #808080;
  margin-top: 2px;
}

.photo-upload-body {
  position: relative;
  width: 80vw;
  height: 80vw;
  margin: 16px auto 0 auto;
  text-align: center;
}
.photo-upload-box {
  margin: 16px auto 0 auto;
  width: 80vw;
  height: 80vw;
  border-radius: 12px;
  background: #F0F2F5;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  box-sizing: border-box;
}
.photo-upload-box-1 {
  width: 80vw;
  height: 70vw;
  border-radius: 12px;
  background: rgba(0, 0, 0, 0);
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
}
.photo-upload-img {
  max-width: 80vw;
  max-height: 80vw;
  border-radius: 12px;
}
.photo-upload-header {
  width: 100%;
  display: flex;
  align-items: center;
  padding: 12px 16px 0 12px;
  font-size: 14px;
  color: #888;
  justify-content: flex-end;
}
.photo-upload-guide-icon {
  font-size: 16px;
  margin-right: 4px;
}
.photo-upload-guide-text {
  font-size: 13px;
}
.photo-upload-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  user-select: none;
}
.photo-upload-plus {
  font-size: 48px;
  color: #c2c2c2;
  margin-bottom: 0;
}
.photo-upload-text {
  font-size: 16px;
  color: #888;
  margin-bottom: 4px;
}
.photo-upload-tip {
  font-size: 12px;
  color: #b0b0b0;
}
.photo-upload-footer {
  position: absolute;
  bottom: 0px;
  left: 0;
  width: 100%;
  text-align: center;
  font-size: 12px;
  color: #b0b0b0;
  padding: 0 12px;
  line-height: 1.5;
}

.step-line-item-desc {
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding: 16px 16px 0 16px;
}

.design-action-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px;
  background: #fff;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
}
.design-left {
  display: flex;
  align-items: center;
}
.design-leaf-icon {
  margin-right: 4px;
  vertical-align: middle;
}
.design-remaining {
  color: #222;
  font-size: 16px;
  font-weight: 500;
}
.design-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  outline: none;
  cursor: pointer;
  width: 50vw;
  height: 56px;
  border-radius: 28px;
  font-size: 20px;
  font-weight: bold;
  background: linear-gradient(90deg, #D1ED8E 0%, #55E668 100%);
  color: #222;
  box-shadow: 0 2px 8px rgba(80, 207, 84, 0.10);
  transition: background 0.2s;
  position: relative;
}
.design-btn .design-arrow {
  margin-left: 20px;
  vertical-align: middle;
  position: absolute;
  right: 30px;
  transition: transform 0.2s;
  width: 18px;
  height: 12px;
}
.order-type-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: #fff;
  border-radius: 12px;
  margin-bottom: 12px;
  font-size: 14px;
}
.kind-box {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-wrap: wrap;
  padding: 16px;
}
.kind-box-item {
  margin-right: 10px;
  margin-bottom: 10px;
  padding: 6px 10px;
  background: #f5f5f5;
  border-radius: 8px;
  color: #333;
}
.kind-item-title {
  font-size: 14px;
}
.kind-box-item.styleActive {
  background: #50CF54;
  color: #fff;
}
.photo-upload-box-refer {
  margin: 16px;
}
.mounts-list-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  margin-top: 12px;
}
.mounts-item {
  position: relative;
  flex: 0 0 calc(25% - 6px);
  margin-right: 8px;
  margin-bottom: 16px;
  cursor: pointer;
}
.mounts-item:nth-child(4n) {
  margin-right: 0;
}
.mounts-item-list {
  position: relative;
  width: 100%;
  padding-bottom: 100%;
  border-radius: 8px;
  overflow: hidden;
  background: #f5f5f5;
}
.mounts-item-image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 8px;
  transition: transform 0.2s;
}
.mounts-item-image-round {
  border-radius: 50%;
}
.mounts-item:hover .mounts-item-image {
  transform: scale(1.05);
}
.mounts-icon {
  position: absolute;
  right: 6px;
  bottom: 6px;
  z-index: 2;
  background: rgba(255, 255, 255, 0.9);
  border-radius: 50%;
  padding: 2px;
}
.mounts-item-text {
  font-size: 12px;
  text-align: center;
  margin-top: 8px;
  color: v-bind('config.styles.colors.textSecondary');
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
</style>

