<template>
  <div class="page-zone-config">
    <!-- 顶部操作栏 -->
    <div class="toolbar">
      <div class="toolbar-left">
        <h2 class="toolbar-title">权益首页配置</h2>
        <el-tag v-if="pageStatus === 'published'" type="success" size="small" effect="plain">正式线上环境</el-tag>
        <el-tag v-else-if="pageStatus === 'modified'" type="warning" size="small" effect="plain">有未发布的修改</el-tag>
        <el-tag v-else size="info" effect="plain">草稿 (未发布)</el-tag>
      </div>
      <div class="toolbar-right">
        <el-button size="small" @click="showLinkDialog">
          <el-icon><Link /></el-icon>获取链接
        </el-button>
        <el-button size="small" type="primary" plain @click="handleSave('draft')">保存草稿</el-button>
        <el-button v-if="canPublish" size="small" type="primary" @click="handleSave('publish')">发布上线</el-button>
      </div>
    </div>

    <!-- 客户身份模块配置 -->
    <el-card class="section-card" shadow="hover">
      <template #header>
        <div class="section-header">
          <span><el-icon><Postcard /></el-icon> 客户身份模块配置</span>
        </div>
      </template>
      <el-alert
        type="info"
        :closable="false"
        show-icon
        title="前端将根据登录客户的实际客户MSC Group自动匹配展示以下对应的身份卡片内容。"
        style="margin-bottom:16px"
      />

      <div v-for="m in identityMscList" :key="m.key" class="identity-card">
        <div class="identity-title"><span class="title-bar"></span>{{ m.label }}</div>

        <!-- 客群背景图 -->
        <div class="identity-row">
          <div class="identity-field-label">客群背景图</div>
          <div class="bg-upload-area">
            <div class="bg-upload-box" @click="triggerIdentityUpload(m.key)">
              <img v-if="configData.identityModule[m.key].bgImage" :src="configData.identityModule[m.key].bgImage" class="preview-img" />
              <div v-else class="upload-placeholder">
                <el-icon><Picture /></el-icon>
                <span>未上传</span>
              </div>
              <div class="upload-overlay">
                <el-icon><Upload /></el-icon>
                <span>点击上传</span>
              </div>
            </div>
            <div class="upload-tip">建议图片尺寸：<b>750 × 185 px</b></div>
            <input :ref="'identityUpload_' + m.key" type="file" accept="image/*" style="display:none" @change="onIdentityImageUpload($event, m.key)" />
          </div>
        </div>

        <!-- 等级说明 -->
        <div v-if="hasGradeTipConfig(m.key)" class="identity-extra-block">
          <div class="config-field">
            <div class="config-field-label">等级说明</div>
            <quill-editor
              v-model:content="configData.identityModule[m.key].identityTipContent"
              content-type="html"
              :options="quillOptions"
              @change="markModified"
            />
            <div class="config-tip">
              <el-icon><InfoFilled /></el-icon>
              <span>移动端对应：用于配置【等级名称】旁边的“?”提示弹窗内容。</span>
            </div>
          </div>
        </div>

        <!-- 日均余额计算规则说明 -->
        <div
          v-if="m.key !== 'privateBank' && configData.identityModule[m.key].showAvgBalance"
          class="rule-block"
        >
          <div class="config-field">
            <div class="config-field-label">账户月内日均余额名称</div>
            <el-input
              v-model="configData.identityModule[m.key].avgBalanceName"
              maxlength="20"
              placeholder="请输入"
              class="balance-name-input"
              @input="markModified"
            />
          </div>
          <div class="config-field">
            <div class="config-field-label">余额说明</div>
            <quill-editor
              v-model:content="configData.identityModule[m.key].avgBalanceRule"
              content-type="html"
              :options="quillOptions"
              @change="markModified"
            />
            <div class="config-tip">
              <el-icon><InfoFilled /></el-icon>
              <span>移动端对应：用于配置【账户月内日均余额】旁边的“?”提示弹窗内容。</span>
            </div>
          </div>
        </div>
      </div>
    </el-card>

    <!-- 活动广告轮播图 -->
    <el-card class="section-card" shadow="hover">
      <template #header>
        <div class="section-header">
          <span><el-icon><DataBoard /></el-icon> 活动广告轮播图</span>
          <el-button type="text" @click="addCarousel" style="float:right">
            <el-icon><CirclePlus /></el-icon>添加轮播
          </el-button>
        </div>
      </template>
      <div v-if="configData.adCarousel.length === 0" class="empty-tip">暂无广告轮播图</div>
      <div v-for="(item, index) in configData.adCarousel" :key="'c' + index" class="carousel-item">
        <div class="item-index">NO. {{ index + 1 }}</div>
        <div class="item-actions">
          <el-popover placement="bottom" trigger="click" width="180">
            <div>
              <div style="margin-bottom:8px;font-size:13px;color:#666">移动到序号：</div>
              <div style="display:flex;gap:8px">
                <el-input-number v-model="sortTarget" :min="1" :max="configData.adCarousel.length" size="small" controls-position="right" style="width:100px" />
                <el-button size="small" type="primary" @click="moveItem('adCarousel', index, sortTarget - 1)">确定</el-button>
              </div>
            </div>
            <template #reference>
              <el-button size="small" circle @click="sortTarget = index + 1">
                <el-icon><Sort /></el-icon>
              </el-button>
            </template>
          </el-popover>
          <el-button size="small" type="danger" circle @click="removeCarousel(index)">
            <el-icon><Delete /></el-icon>
          </el-button>
        </div>

        <!-- 图片上传 -->
        <div class="carousel-body">
          <div class="image-upload-area">
            <div class="upload-box" @click="triggerUpload('carousel', index)">
              <img v-if="item.imageUrl" :src="item.imageUrl" class="preview-img" />
              <div v-else class="upload-placeholder">
                <el-icon><Picture /></el-icon>
                <span>未上传</span>
              </div>
              <div class="upload-overlay">
                <el-icon><Upload /></el-icon>
                <span>点击上传</span>
              </div>
            </div>
            <div class="upload-tip">建议图片尺寸：<b>686 × 296 px</b></div>
            <input :ref="'carouselUpload' + index" type="file" accept="image/*" style="display:none" @change="onImageUpload($event, 'carousel', index)" />
          </div>

          <!-- 标题 -->
          <el-form label-width="80px" style="margin-top:12px">
            <el-form-item label="主标题">
              <el-input v-model="item.title" @input="markModified" />
            </el-form-item>
            <el-form-item label="副标题">
              <el-input v-model="item.subtitle" @input="markModified" />
            </el-form-item>
          </el-form>

          <!-- 可见人群标签 -->
          <el-form label-width="110px" style="margin-top:4px">
            <el-form-item label="可见人群标签">
              <el-select v-model="item.tags" multiple placeholder="点击选择..." filterable @change="markModified" style="width:100%">
                <el-option v-for="tag in availableTags" :key="tag.id" :label="tag.name" :value="tag.id" />
              </el-select>
            </el-form-item>
          </el-form>

          <!-- 跳转链接配置 -->
          <div class="link-config-block">
            <div class="link-config-title"><el-icon><Link /></el-icon> 跳转链接配置</div>
            <el-form class="jump-config-form" label-position="top">
              <el-form-item class="jump-type-item" label-width="0">
                <el-radio-group v-model="item.jumpType" @change="handleZoneJumpTypeChange(item)">
                  <el-radio label="h5">H5链接跳转</el-radio>
                  <el-radio label="miniProgram">小程序跳转</el-radio>
                  <el-radio label="taikoo">太古地产</el-radio>
                  <el-radio label="dragon">龙腾</el-radio>
                </el-radio-group>
              </el-form-item>
              <el-form-item v-if="item.jumpType === 'h5'" label="配置链接">
                <el-input v-model="item.linkH5" placeholder="例如：https://hsbc.com" @input="markModified" />
              </el-form-item>
              <el-row v-if="item.jumpType === 'miniProgram'" :gutter="20">
                <el-col :span="12">
                  <el-form-item label="AppID">
                    <el-input v-model="item.wechatAppId" placeholder="例如：wx1234567890abcdef" @input="markModified" />
                  </el-form-item>
                </el-col>
                <el-col :span="12">
                  <el-form-item label="页面路径">
                    <el-input v-model="item.wechatPath" placeholder="例如：pages/index/index" @input="markModified" />
                  </el-form-item>
                </el-col>
              </el-row>
            </el-form>
          </div>
        </div>
      </div>
    </el-card>

    <!-- 常用兑换配置 -->
    <el-card class="section-card" shadow="hover">
      <template #header>
        <div class="section-header">
          <span><el-icon><Grid /></el-icon> 常用兑换配置</span>
          <el-button type="text" @click="addExchangeItem" style="float:right">
            <el-icon><CirclePlus /></el-icon>添加兑换项
          </el-button>
        </div>
      </template>
      <div v-if="configData.exchangeConfig.items.length === 0" class="empty-tip">暂无常用兑换项</div>
      <div v-for="(item, index) in configData.exchangeConfig.items" :key="'e' + index" class="exchange-item">
        <div class="item-index">NO. {{ index + 1 }}</div>
        <div class="item-actions">
          <el-popover placement="bottom" trigger="click" width="180">
            <div>
              <div style="margin-bottom:8px;font-size:13px;color:#666">移动到序号：</div>
              <div style="display:flex;gap:8px">
                <el-input-number v-model="sortTarget" :min="1" :max="configData.exchangeConfig.items.length" size="small" controls-position="right" style="width:100px" />
                <el-button size="small" type="primary" @click="moveItem('exchangeItems', index, sortTarget - 1)">确定</el-button>
              </div>
            </div>
            <template #reference>
              <el-button size="small" circle @click="sortTarget = index + 1">
                <el-icon><Sort /></el-icon>
              </el-button>
            </template>
          </el-popover>
          <el-button size="small" type="danger" circle @click="removeExchangeItem(index)">
            <el-icon><Delete /></el-icon>
          </el-button>
        </div>
        <div class="exchange-body">
          <div class="exchange-image" @click="triggerUpload('exchange', index)">
            <img v-if="item.imageUrl" :src="item.imageUrl" class="preview-img-sq" />
            <div v-else class="upload-placeholder-sm">
              <el-icon><Picture /></el-icon>
              <span>未上传</span>
            </div>
            <input :ref="'exchangeUpload' + index" type="file" accept="image/*" style="display:none" @change="onImageUpload($event, 'exchange', index)" />
          </div>
          <el-form label-width="80px" inline class="exchange-fields">
            <el-form-item label="展示文字">
              <el-input v-model="item.title" style="width:200px" @input="markModified" />
            </el-form-item>
            <el-form-item label="跳转链接">
              <el-input v-model="item.link" style="width:280px" placeholder="例如：https://test.hsbc.com" @input="markModified" />
            </el-form-item>
          </el-form>
        </div>
      </div>
    </el-card>

    <!-- 积分规则弹窗配置 -->
    <el-card class="section-card" shadow="hover">
      <template #header>
        <div class="section-header">
          <el-icon><Document /></el-icon> 积分规则弹窗配置
        </div>
      </template>
      <el-form label-width="120px">
        <el-form-item label="弹窗顶部名称">
          <el-input v-model="configData.ruleModal.title" style="width:50%" @input="markModified" />
        </el-form-item>
        <el-form-item label="规则内容">
          <quill-editor
            v-model:content="configData.ruleModal.content"
            content-type="html"
            :options="quillOptions"
            @change="markModified"
          />
        </el-form-item>
      </el-form>
    </el-card>

    <!-- 获取链接弹窗 -->
    <el-dialog title="获取页面链接" v-model="linkDialogVisible" width="680px">
      <el-form label-width="100px" inline>
        <el-form-item label="Campaign ID">
          <el-select v-model="linkForm.campaignId" clearable filterable placeholder="请选择 (无)" style="width:240px">
            <el-option v-for="opt in campaignOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
          </el-select>
        </el-form-item>
        <el-form-item label="Channel ID">
          <el-select v-model="linkForm.channelId" clearable filterable placeholder="请选择 (无)" style="width:240px">
            <el-option v-for="opt in channelOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
          </el-select>
        </el-form-item>
      </el-form>
      <div v-if="pageStatus === 'published'" class="link-section">
        <div class="link-label"><span class="dot dot-green"></span> 正式环境链接</div>
        <div class="link-row">
          <span class="link-type">H5链接</span>
          <el-input :value="prodH5Url" readonly size="small" />
          <el-button size="small" type="primary" plain @click="copyLink(prodH5Url)">复制</el-button>
        </div>
        <div class="link-row">
          <span class="link-type">小程序链接</span>
          <el-input :value="prodAppUrl" readonly size="small" />
          <el-button size="small" type="primary" plain @click="copyLink(prodAppUrl)">复制</el-button>
        </div>
      </div>
      <div class="link-section">
        <div class="link-label"><span class="dot dot-blue"></span> 草稿预览链接 (测试)</div>
        <div class="link-row">
          <el-input :value="testUrl" readonly size="small" />
          <el-button size="small" type="primary" plain @click="copyLink(testUrl)">复制</el-button>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { ElMessage } from 'element-plus'
import request from '@/utils/request'
import { fetchLinkOptions } from '@/utils/linkOptions'

export default {
  name: 'PageZoneConfig',
  data() {
    return {
      configData: {
        identityModule: this.defaultIdentityModule(),
        adCarousel: [],
        exchangeConfig: { items: [] },
        ruleModal: { title: '', content: '' }
      },
      identityMscList: [
        { key: 'advance', label: '运筹理财 (Advance)' },
        { key: 'premier', label: '卓越理财 (Premier)' },
        { key: 'premierElite', label: '卓越理财·尊尚 (Premier Elite)' },
        { key: 'privateBank', label: '环球私人银行 (Global Private Bank)' }
      ],
      availableTags: [],
      pageStatus: 'draft',
      isModified: false,
      dataLoaded: false,
      sortTarget: 1,
      linkDialogVisible: false,
      linkForm: { campaignId: '', channelId: '' },
      campaignOptions: [],
      channelOptions: [],
      quillOptions: {
        placeholder: '请输入富文本内容...',
        modules: {
          toolbar: [
            ['bold', 'italic', 'underline'],
            [{ list: 'ordered' }, { list: 'bullet' }],
            [{ header: [1, 2, 3, false] }],
            ['link', 'image'],
            ['clean']
          ]
        }
      }
    }
  },
  computed: {
    linkQueryStr() {
      const params = []
      if (this.linkForm.campaignId) params.push(`CampaignId=${this.linkForm.campaignId}`)
      if (this.linkForm.channelId) params.push(`Channelid=${this.linkForm.channelId}`)
      return params.length ? '?' + params.join('&') : ''
    },
    prodH5Url() {
      return `https://hsbc.com/zone${this.linkQueryStr}`
    },
    prodAppUrl() {
      return `hsbc-app://zone${this.linkQueryStr}`
    },
    testUrl() {
      const q = this.linkQueryStr
      return `https://test.hsbc.com/zone${q ? q + '&' : '?'}draft=1`
    },
    canPublish() {
      return !this.isModified && ['draft', 'modified'].includes(this.pageStatus)
    }
  },
  created() {
    this.fetchData()
  },
  methods: {
    defaultIdentityModule() {
      const base = {
        bgImage: '',
        showAvgBalance: true,
        avgBalanceName: '账户月内日均余额',
        avgBalanceRule: '<p></p>'
      }
      const gradeTipBase = { identityTipContent: '<p>展示客户当前身份等级说明。</p>' }
      return {
        advance: { ...base },
        premier: { ...base, ...gradeTipBase },
        premierElite: { ...base, ...gradeTipBase },
        privateBank: {
          bgImage: '',
          identityTipContent: '<p>环球私人银行客户身份由客户 MSC Group 自动匹配展示。</p>'
        }
      }
    },
    hasGradeTipConfig(key) {
      return ['premier', 'premierElite', 'privateBank'].includes(key)
    },
    normalizeIdentityModule(source = {}) {
      const defaults = this.defaultIdentityModule()
      Object.keys(defaults).forEach((key) => {
        const current = source[key] || {}
        source[key] = { ...defaults[key], ...current }
        delete source[key].showQualifyStatus
        delete source[key].showPbLevel
        delete source[key].identityText
        delete source[key].qualifyStatusText
        if (source[key].avgBalanceRule && !String(source[key].avgBalanceRule).trim().startsWith('<')) {
          source[key].avgBalanceRule = `<p>${source[key].avgBalanceRule}</p>`
        }
      })
      return source
    },
    createDefaultJumpConfig(overrides = {}) {
      return {
        jumpType: 'h5',
        fixedLink: '',
        linkH5: '',
        linkApp: '',
        wechatAppId: '',
        wechatPath: '',
        ...overrides
      }
    },
    getPartnerFixedLink(type) {
      if (type === 'taikoo') return '太古地产'
      if (type === 'dragon') return '龙腾'
      return ''
    },
    normalizePartnerJumpType(type, fixedLink = '') {
      if (type === 'taikoo' || type === 'dragon') return type
      if (type === 'fixed') return fixedLink === '龙腾' ? 'dragon' : 'taikoo'
      return type
    },
    inferJumpType(item = {}) {
      if (item.jumpType) return this.normalizePartnerJumpType(item.jumpType, item.fixedLink)
      if (item.wechatAppId || item.wechatPath) return 'miniProgram'
      if (item.linkH5) return 'h5'
      if (item.fixedLink === '太古地产') return 'taikoo'
      if (item.fixedLink === '龙腾') return 'dragon'
      return 'h5'
    },
    normalizeJumpConfig(item) {
      const normalized = this.createDefaultJumpConfig({
        ...item,
        jumpType: this.inferJumpType(item)
      })
      Object.keys(normalized).forEach(key => {
        item[key] = normalized[key]
      })
      this.clearInactiveJumpFields(item)
    },
    normalizeCarouselItems(items = []) {
      items.forEach(item => this.normalizeJumpConfig(item))
      return items
    },
    clearInactiveJumpFields(item) {
      item.fixedLink = this.getPartnerFixedLink(item.jumpType)
      if (item.jumpType !== 'h5') item.linkH5 = ''
      if (item.jumpType !== 'miniProgram') {
        item.wechatAppId = ''
        item.wechatPath = ''
      }
      item.linkApp = ''
    },
    handleZoneJumpTypeChange(item) {
      this.clearInactiveJumpFields(item)
      this.markModified()
    },
    validateJumpConfig(item) {
      if (this.getPartnerFixedLink(item.jumpType)) return true
      if (item.jumpType === 'h5') return !!(item.linkH5 || '').trim()
      if (item.jumpType === 'miniProgram') {
        return !!(item.wechatAppId || '').trim() && !!(item.wechatPath || '').trim()
      }
      return false
    },
    async fetchData() {
      const res = await request.get('/api/page-config/zone')
      const cfg = res.data.config || {}
      if (!cfg.identityModule) cfg.identityModule = this.defaultIdentityModule()
      cfg.identityModule = this.normalizeIdentityModule(cfg.identityModule)
      cfg.adCarousel = this.normalizeCarouselItems(cfg.adCarousel || [])
      this.configData = cfg
      this.availableTags = res.data.availableTags
      this.pageStatus = res.data.status
      this.isModified = false
      this.$nextTick(() => { this.dataLoaded = true })
    },
    triggerIdentityUpload(key) {
      const ref = this.$refs['identityUpload_' + key]
      if (ref) (Array.isArray(ref) ? ref[0] : ref).click()
    },
    onIdentityImageUpload(event, key) {
      const file = event.target.files[0]
      if (!file) return
      const reader = new FileReader()
      reader.onload = (e) => {
        this.configData.identityModule[key].bgImage = e.target.result
        this.markModified()
      }
      reader.readAsDataURL(file)
      event.target.value = ''
    },
    async loadLinkOptions() {
      const { campaignOptions, channelOptions } = await fetchLinkOptions()
      this.campaignOptions = campaignOptions
      this.channelOptions = channelOptions
    },
    markModified() {
      if (!this.dataLoaded) return
      if (this.pageStatus === 'published') {
        this.pageStatus = 'modified'
      }
      this.isModified = true
    },
    triggerUpload(type, index) {
      const ref = this.$refs[type + 'Upload' + index]
      if (ref) (Array.isArray(ref) ? ref[0] : ref).click()
    },
    onImageUpload(event, type, index) {
      const file = event.target.files[0]
      if (!file) return
      const reader = new FileReader()
      reader.onload = (e) => {
        if (type === 'carousel') {
          this.configData.adCarousel[index].imageUrl = e.target.result
        } else {
          this.configData.exchangeConfig.items[index].imageUrl = e.target.result
        }
        this.markModified()
      }
      reader.readAsDataURL(file)
      event.target.value = ''
    },
    addCarousel() {
      this.configData.adCarousel.push({
        imageUrl: '', ...this.createDefaultJumpConfig(),
        title: '新广告', subtitle: '', tags: []
      })
      this.markModified()
    },
    removeCarousel(index) {
      this.configData.adCarousel.splice(index, 1)
      this.markModified()
    },
    addExchangeItem() {
      this.configData.exchangeConfig.items.push({ imageUrl: '', title: '新兑换项', link: '' })
      this.markModified()
    },
    removeExchangeItem(index) {
      this.configData.exchangeConfig.items.splice(index, 1)
      this.markModified()
    },
    moveItem(type, from, to) {
      const arr = type === 'adCarousel' ? this.configData.adCarousel : this.configData.exchangeConfig.items
      if (to < 0 || to >= arr.length || from === to) return
      const item = arr.splice(from, 1)[0]
      arr.splice(to, 0, item)
      this.markModified()
    },
    async handleSave(type) {
      this.normalizeCarouselItems(this.configData.adCarousel || [])
      const invalidCarouselIndex = (this.configData.adCarousel || []).findIndex(item => !this.validateJumpConfig(item))
      if (invalidCarouselIndex > -1) {
        ElMessage.error(`保存失败：第 ${invalidCarouselIndex + 1} 个活动广告轮播图跳转链接配置未填写完整！`)
        return
      }
      if (type === 'publish' && this.isModified) {
        ElMessage.warning('请先保存草稿后再发布上线')
        return
      }
      const status = type === 'publish' ? 'published' : (this.pageStatus === 'published' || this.pageStatus === 'modified' ? 'modified' : 'draft')
      await request.put('/api/page-config/zone', { config: this.configData, status })
      this.pageStatus = status
      this.isModified = false
      ElMessage.success(type === 'publish' ? '已发布权益首页配置！' : '已保存权益首页配置草稿！')
    },
    async showLinkDialog() {
      await this.loadLinkOptions()
      this.linkForm = { campaignId: '', channelId: '' }
      this.linkDialogVisible = true
    },
    copyLink(text) {
      navigator.clipboard.writeText(text).then(() => {
        ElMessage.success('链接已复制到剪贴板')
      })
    }
  }
}
</script>

<style scoped>
.toolbar {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 16px; padding: 12px 16px;
  background: #fff; border-radius: 4px; box-shadow: 0 1px 4px rgba(0,0,0,.06);
}
.toolbar-left { display: flex; align-items: center; gap: 12px; }
.toolbar-title { margin: 0; font-size: 18px; font-weight: 600; }
.toolbar-right { display: flex; gap: 8px; }

.section-card { margin-bottom: 16px; }
.section-header { font-weight: 600; }
.section-header i { margin-right: 6px; color: #909399; }

.carousel-item, .exchange-item {
  position: relative; border: 1px solid #ebeef5; border-radius: 8px;
  padding: 24px 16px 16px; margin-bottom: 16px; background: #fff;
}
.item-index {
  position: absolute; left: 0; top: 0;
  background: #409EFF; color: #fff; font-size: 11px; font-weight: 700;
  padding: 2px 10px; border-radius: 8px 0 8px 0;
}
.item-actions {
  position: absolute; right: 12px; top: 12px;
  display: flex; gap: 6px;
}

.image-upload-area { display: flex; align-items: center; gap: 16px; }
.upload-box {
  width: 256px; height: 144px;
  background: #eef6fc; border: 1px solid #dcdfe6; border-radius: 4px;
  position: relative; overflow: hidden; cursor: pointer;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.upload-box:hover .upload-overlay { display: flex; }
.preview-img { width: 100%; height: 100%; object-fit: cover; }
.upload-placeholder {
  display: flex; flex-direction: column; align-items: center;
  color: #c0c4cc; font-size: 12px;
}
.upload-placeholder i { font-size: 28px; margin-bottom: 4px; }
.upload-overlay {
  display: none; position: absolute; inset: 0;
  background: rgba(0,0,0,.5); color: #fff;
  flex-direction: column; align-items: center; justify-content: center; font-size: 14px;
}
.upload-overlay i { font-size: 24px; margin-bottom: 4px; }
.upload-tip {
  font-size: 12px; color: #909399;
  background: #f5f7fa; padding: 8px 12px; border-radius: 4px; border: 1px solid #ebeef5;
}

.link-config-block {
  background: #f5f7fa; padding: 18px 20px 20px; border-radius: 6px;
  border: 1px solid #ebeef5; margin-top: 8px;
}
.link-config-title {
  font-size: 13px; font-weight: 600; color: #303133;
  border-bottom: 1px solid #dcdfe6; padding-bottom: 12px; margin-bottom: 14px;
}
.jump-config-form :deep(.el-form-item) {
  margin-bottom: 14px;
}
.jump-config-form :deep(.el-form-item:last-child) {
  margin-bottom: 0;
}
.jump-config-form :deep(.el-form-item__label) {
  line-height: 20px;
  padding: 0 0 6px;
  color: #303133;
}
.jump-config-form :deep(.el-form-item__content) {
  width: 100%;
}
.jump-type-item {
  margin-bottom: 18px;
}
.link-config-block :deep(.el-radio) {
  margin-right: 22px;
}

.exchange-body { display: flex; align-items: flex-start; gap: 16px; margin-top: 8px; }
.exchange-image {
  width: 80px; height: 80px; flex-shrink: 0;
  background: #eef6fc; border: 1px solid #dcdfe6; border-radius: 4px;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; overflow: hidden;
}
.preview-img-sq { width: 100%; height: 100%; object-fit: cover; }
.upload-placeholder-sm {
  display: flex; flex-direction: column; align-items: center;
  color: #c0c4cc; font-size: 10px;
}
.upload-placeholder-sm i { font-size: 18px; }
.exchange-fields { flex: 1; margin-top: 8px; }

.empty-tip {
  text-align: center; color: #c0c4cc; padding: 24px;
  border: 1px dashed #dcdfe6; border-radius: 4px;
}

.link-section { margin-top: 16px; padding: 12px; background: #fafafa; border-radius: 6px; border: 1px solid #ebeef5; }
.link-section + .link-section { margin-top: 12px; }
.link-label { font-weight: 600; margin-bottom: 8px; display: flex; align-items: center; gap: 6px; }
.link-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.link-type { font-size: 12px; color: #909399; width: 70px; flex-shrink: 0; }
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.dot-green { background: #67C23A; }
.dot-blue { background: #409EFF; }

/* 客户身份模块配置 */
.identity-card {
  border: 1px solid #ebeef5;
  border-radius: 8px;
  padding: 16px 20px;
  margin-bottom: 16px;
  background: #fff;
}
.identity-title {
  display: flex; align-items: center;
  font-size: 14px; font-weight: 600; color: #303133;
  margin-bottom: 14px;
}
.title-bar {
  display: inline-block; width: 4px; height: 14px;
  background: #409EFF; border-radius: 2px; margin-right: 8px;
}
.identity-row { margin-bottom: 14px; }
.identity-field-label {
  font-size: 13px; color: #606266; margin-bottom: 6px;
}
.muted { color: #909399; font-weight: normal; font-size: 12px; }
.bg-upload-area {
  display: flex; align-items: center; gap: 16px;
}
.bg-upload-box {
  width: 300px; height: 75px;
  background: #eef6fc; border: 1px solid #dcdfe6; border-radius: 4px;
  position: relative; overflow: hidden; cursor: pointer;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.bg-upload-box:hover .upload-overlay { display: flex; }
.identity-extra-block {
  padding: 0;
  margin: 8px 0 22px;
}
.rule-block {
  padding: 22px 0 0;
  border-top: 1px solid #ebeef5;
}
.config-field {
  margin-bottom: 22px;
}
.config-field:last-child {
  margin-bottom: 0;
}
.config-field-label {
  font-size: 14px;
  font-weight: 600;
  color: #1f2d3d;
  margin-bottom: 10px;
  line-height: 20px;
}
.balance-name-input {
  width: 420px;
  max-width: 100%;
}
.config-tip {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 8px;
  color: #606266;
  font-size: 12px;
  line-height: 18px;
}
.config-tip i {
  color: #409EFF;
  font-size: 14px;
}
:deep(.identity-card .ql-container.ql-snow) {
  height: 120px;
}
:deep(.identity-card .ql-toolbar.ql-snow) {
  border-radius: 4px 4px 0 0;
}
:deep(.identity-card .ql-container.ql-snow) {
  border-radius: 0 0 4px 4px;
}
</style>
