<template>
  <div class="page-assembly">
    <!-- ==================== 列表视图 ==================== -->
    <template v-if="viewState === 'list'">
      <el-card>
        <div slot="header" class="search-section">
          <div class="search-row">
            <el-form :model="searchForm" label-width="80px" inline>
              <el-form-item label="页面ID:">
                <el-input v-model="searchForm.id" placeholder="请输入" clearable style="width:160px" />
              </el-form-item>
              <el-form-item label="页面名称:">
                <el-input v-model="searchForm.name" placeholder="请输入" clearable style="width:160px" />
              </el-form-item>
              <div class="button-group">
                <el-button type="primary" @click="handleSearch">查询</el-button>
                <el-button @click="handleReset">重置</el-button>
              </div>
            </el-form>
          </div>
          <div class="action-row">
            <el-button type="primary" icon="el-icon-plus" @click="handleCreate">新建组装页</el-button>
          </div>
        </div>

        <el-table :data="tableData" stripe border style="width:100%">
          <el-table-column label="操作" width="200" fixed="left">
            <template slot-scope="scope">
              <el-button type="text" size="small" @click="handleEdit(scope.row)">编辑</el-button>
              <el-button type="text" size="small" @click="showLinkDialog(scope.row.id)">链接</el-button>
              <el-button type="text" size="small" style="color:#F56C6C" @click="handleDelete(scope.row)">删除</el-button>
            </template>
          </el-table-column>
          <el-table-column prop="id" label="页面ID" width="120" align="center" />
          <el-table-column prop="name" label="组装页名称" min-width="200" show-overflow-tooltip />
          <el-table-column label="发布状态" width="100" align="center">
            <template slot-scope="scope">
              <el-tag :type="scope.row.status === 'published' ? 'success' : 'info'" size="small">
                {{ scope.row.status === 'published' ? '已上架' : '草稿' }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="createTime" label="创建时间" width="180" align="center" />
          <el-table-column prop="updateTime" label="更新时间" width="180" align="center" />
        </el-table>
      </el-card>
    </template>

    <!-- ==================== 编辑视图 ==================== -->
    <template v-else>
      <!-- 操作栏 -->
      <div class="toolbar">
        <div class="toolbar-left">
          <el-button size="small" icon="el-icon-arrow-left" @click="backToList">返回</el-button>
          <h2 class="toolbar-title">{{ isNew ? '新建组装页' : '编辑组装页' }}</h2>
          <el-tag v-if="editData.status === 'published' && !isModified" type="success" size="small" effect="plain">正式线上环境</el-tag>
          <el-tag v-else-if="isModified" 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" icon="el-icon-link" @click="showLinkDialog(editData.id)">获取链接</el-button>
          <el-button size="small" type="primary" plain @click="handleSaveAssembly('draft')">保存草稿</el-button>
          <el-button size="small" type="primary" @click="handleSaveAssembly('publish')">发布上线</el-button>
        </div>
      </div>

      <!-- 基本信息 -->
      <el-card class="section-card" shadow="hover">
        <div class="basic-info">
          <div class="info-item">
            <span class="info-label">页面 ID：</span>
            <el-tag size="small" effect="plain">{{ editData.id || '保存后生成' }}</el-tag>
          </div>
          <div class="info-item" style="flex:1">
            <span class="info-label">组装页名称 <span style="color:#F56C6C">*</span></span>
            <el-input v-model="editData.name" placeholder="请为该页面设置一个名称 (必填)" size="small" @input="isModified = true" />
          </div>
        </div>
      </el-card>

      <!-- 模块列表 -->
      <div v-for="(block, bIdx) in editData.blocks" :key="block.id" class="block-card">
        <!-- 模块操作栏 -->
        <div class="block-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="editData.blocks.length" size="mini" controls-position="right" style="width:100px" />
                <el-button size="mini" type="primary" @click="moveBlock(bIdx, sortTarget - 1)">确定</el-button>
              </div>
            </div>
            <el-button slot="reference" size="mini" icon="el-icon-sort" @click="sortTarget = bIdx + 1">排序</el-button>
          </el-popover>
          <el-button v-if="block.type !== 'privilege'" size="mini" icon="el-icon-copy-document" @click="duplicateBlock(bIdx)">复制</el-button>
          <el-button size="mini" type="danger" icon="el-icon-delete" @click="removeBlock(bIdx)">删除</el-button>
        </div>

        <!-- 图片模块 -->
        <template v-if="block.type === 'image'">
          <div class="block-header"><i class="el-icon-picture-outline"></i> 图片模块</div>
          <div class="block-body">
            <div class="image-upload-area">
              <div class="upload-box upload-box-wide" @click="triggerBlockUpload(bIdx)">
                <img v-if="block.data.imageUrl" :src="block.data.imageUrl" class="preview-img" />
                <div v-else class="upload-placeholder">
                  <i class="el-icon-picture"></i><span>未上传图片</span>
                </div>
                <div class="upload-overlay"><i class="el-icon-upload2"></i><span>点击上传图片</span></div>
              </div>
              <div class="upload-tip">建议宽度：<b>750px</b><br/>高度不限，系统将按比例自适应展示</div>
              <input :ref="'blockUpload' + bIdx" type="file" accept="image/*" style="display:none" @change="onBlockImageUpload($event, bIdx)" />
            </div>
          </div>
        </template>

        <!-- 权益商品模块 -->
        <template v-else-if="block.type === 'privilege'">
          <div class="block-header"><i class="el-icon-s-grid"></i> 权益商品模块 <span class="block-hint">(当前页面仅限添加一个)</span></div>
          <div class="block-body">
            <el-form label-width="100px" style="margin-bottom:16px;border-bottom:1px solid #ebeef5;padding-bottom:16px">
              <el-form-item label="可配置大标题">
                <el-input v-model="block.data.title" style="width:50%" @input="isModified = true" />
              </el-form-item>
            </el-form>
            <div v-for="(pItem, pIdx) in block.data.items" :key="pIdx" class="privilege-row">
              <el-tag size="mini" effect="plain" class="privilege-no">NO. {{ pIdx + 1 }}</el-tag>
              <div class="privilege-icon"><i class="el-icon-document"></i></div>
              <div class="privilege-info">
                <div class="privilege-title">{{ pItem.title }}</div>
                <div class="privilege-desc">{{ pItem.desc }}</div>
              </div>
              <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="block.data.items.length" size="mini" controls-position="right" style="width:100px" />
                    <el-button size="mini" type="primary" @click="movePrivilegeItem(bIdx, pIdx, sortTarget - 1)">确定</el-button>
                  </div>
                </div>
                <el-button slot="reference" size="mini" icon="el-icon-sort" circle @click="sortTarget = pIdx + 1" />
              </el-popover>
            </div>
          </div>
        </template>

        <!-- 图文模块 (富文本) -->
        <template v-else-if="block.type === 'richtext'">
          <div class="block-header"><i class="el-icon-notebook-2"></i> 图文模块</div>
          <div class="block-body">
            <quill-editor
              v-model="block.data.content"
              :options="quillOptions"
              @change="onQuillChange"
            />
          </div>
        </template>

        <!-- 按钮模块 -->
        <template v-else-if="block.type === 'buttonGroup'">
          <div class="block-header">
            <span><i class="el-icon-thumb"></i> 按钮模块</span>
            <el-button type="text" icon="el-icon-circle-plus-outline" size="small" @click="addButton(bIdx)" style="float:right">添加按钮</el-button>
          </div>
          <div class="block-body">
            <div v-if="block.data.buttons.length === 0" class="empty-tip">暂无按钮</div>
            <div v-for="(btn, btnIdx) in block.data.buttons" :key="btnIdx" class="button-config-item">
              <div class="btn-index">BTN {{ btnIdx + 1 }}</div>
              <div class="btn-config-body">
                <el-form label-width="80px">
                  <el-row :gutter="16">
                    <el-col :span="8">
                      <el-form-item label="按钮文案">
                        <el-input v-model="btn.text" size="small" @input="isModified = true" />
                      </el-form-item>
                    </el-col>
                    <el-col :span="8">
                      <el-form-item label="点击动作">
                        <el-select v-model="btn.actionType" size="small" @change="isModified = true">
                          <el-option label="跳转链接" value="link" />
                          <el-option label="弹窗提示" value="dialog" />
                        </el-select>
                      </el-form-item>
                    </el-col>
                    <el-col :span="8">
                      <el-form-item label="按钮样式">
                        <el-select v-model="btn.style" size="small" @change="isModified = true">
                          <el-option label="突出显示 (红色)" value="primary" />
                          <el-option label="次要操作 (白色)" value="secondary" />
                        </el-select>
                      </el-form-item>
                    </el-col>
                  </el-row>
                  <!-- 跳转链接 -->
                  <el-form-item v-if="btn.actionType === 'link'" label="跳转链接">
                    <el-input v-model="btn.link" size="small" placeholder="必填，输入跳转URL" @input="isModified = true">
                      <template slot="append"><span style="color:#F56C6C">*</span></template>
                    </el-input>
                  </el-form-item>
                  <!-- 弹窗配置 -->
                  <div v-if="btn.actionType === 'dialog'" class="dialog-config">
                    <div class="dialog-config-title"><i class="el-icon-monitor"></i> 弹窗内容配置 (包含取消、确认按钮)</div>
                    <el-form-item label="弹窗标题">
                      <el-input v-model="btn.dialog.title" size="small" placeholder="弹窗标题" @input="isModified = true" />
                    </el-form-item>
                    <el-form-item label="弹窗描述">
                      <el-input v-model="btn.dialog.desc" type="textarea" :rows="2" size="small" placeholder="弹窗正文提示..." @input="isModified = true" />
                    </el-form-item>
                    <el-row :gutter="16">
                      <el-col :span="12">
                        <el-form-item label="确认文案">
                          <el-input v-model="btn.dialog.confirmText" size="small" placeholder="例如：继续前往" @input="isModified = true" />
                        </el-form-item>
                      </el-col>
                      <el-col :span="12">
                        <el-form-item label="确认链接">
                          <el-input v-model="btn.dialog.confirmLink" size="small" placeholder="选填，无链接则仅关闭弹窗" @input="isModified = true" />
                        </el-form-item>
                      </el-col>
                    </el-row>
                  </div>
                </el-form>
              </div>
              <div class="btn-config-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="block.data.buttons.length" size="mini" controls-position="right" style="width:100px" />
                      <el-button size="mini" type="primary" @click="moveButton(bIdx, btnIdx, sortTarget - 1)">确定</el-button>
                    </div>
                  </div>
                  <el-button slot="reference" size="mini" icon="el-icon-sort" circle @click="sortTarget = btnIdx + 1" />
                </el-popover>
                <el-button size="mini" type="danger" icon="el-icon-delete" circle @click="removeButton(bIdx, btnIdx)" />
              </div>
            </div>
          </div>
        </template>
      </div>

      <!-- 添加模块按钮 -->
      <div class="add-block-bar">
        <el-button type="text" icon="el-icon-picture-outline" @click="addBlock('image')">图片模块</el-button>
        <el-button v-if="!hasPrivilegeBlock" type="text" icon="el-icon-s-grid" @click="addBlock('privilege')">权益商品模块</el-button>
        <el-button type="text" icon="el-icon-notebook-2" @click="addBlock('richtext')">图文模块</el-button>
        <el-button type="text" icon="el-icon-thumb" @click="addBlock('buttonGroup')">按钮模块</el-button>
      </div>
    </template>

    <!-- 获取链接弹窗 -->
    <el-dialog title="获取页面链接" :visible.sync="linkDialogVisible" width="680px">
      <el-form label-width="100px" inline>
        <el-form-item label="Campaign ID">
          <el-select v-model="linkForm.campaignId" clearable placeholder="请选择 (无)">
            <el-option label="CAMP202511" value="CAMP202511" />
            <el-option label="CAMP_WINTER" value="CAMP_WINTER" />
          </el-select>
        </el-form-item>
        <el-form-item label="Channel ID">
          <el-select v-model="linkForm.channelId" clearable placeholder="请选择 (无)">
            <el-option label="APP推送" value="CH_APP" />
            <el-option label="微信公众号" value="CH_WECHAT" />
          </el-select>
        </el-form-item>
      </el-form>
      <div v-if="linkTargetPublished" 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="assemblyProdH5" readonly size="small" />
          <el-button size="small" type="primary" plain @click="copyLink(assemblyProdH5)">复制</el-button>
        </div>
        <div class="link-row">
          <span class="link-type">小程序/APP</span>
          <el-input :value="assemblyProdApp" readonly size="small" />
          <el-button size="small" type="primary" plain @click="copyLink(assemblyProdApp)">复制</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="assemblyTestUrl" readonly size="small" />
          <el-button size="small" type="primary" plain @click="copyLink(assemblyTestUrl)">复制</el-button>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import request from '@/utils/request'

let blockIdCounter = 0
function genBlockId() {
  return 'b_' + (++blockIdCounter) + '_' + Math.random().toString(36).substr(2, 6)
}

export default {
  name: 'PageAssembly',
  data() {
    return {
      viewState: 'list',
      tableData: [],
      searchForm: { id: '', name: '' },
      editData: this.createEmptyAssembly(),
      isNew: true,
      isModified: false,
      quillReady: false,
      sortTarget: 1,
      linkDialogVisible: false,
      linkForm: { campaignId: '', channelId: '' },
      linkTargetId: '',
      linkTargetPublished: false,
      quillOptions: {
        placeholder: '请输入图文内容...',
        modules: {
          toolbar: [
            ['bold', 'italic', 'underline'],
            [{ list: 'ordered' }, { list: 'bullet' }],
            [{ header: [1, 2, 3, false] }],
            ['link', 'image'],
            ['clean']
          ]
        }
      }
    }
  },
  computed: {
    hasPrivilegeBlock() {
      return this.editData.blocks.some(b => b.type === 'privilege')
    },
    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('&') : ''
    },
    assemblyProdH5() {
      return `https://hsbc.com/assembly?id=${this.linkTargetId}${this.linkQueryStr}`
    },
    assemblyProdApp() {
      return `hsbc-app://assembly?id=${this.linkTargetId}${this.linkQueryStr}`
    },
    assemblyTestUrl() {
      return `https://test.hsbc.com/assembly?id=${this.linkTargetId}&draft=1${this.linkQueryStr}`
    }
  },
  created() {
    this.fetchList()
  },
  methods: {
    createEmptyAssembly() {
      return {
        id: '', name: '', status: 'draft',
        blocks: [
          { type: 'image', id: genBlockId(), data: { imageUrl: '' } },
          { type: 'privilege', id: genBlockId(), data: { title: '权益标题', items: [{ id: '1', title: '权益名称', desc: '权益简介' }] } },
          { type: 'richtext', id: genBlockId(), data: { content: '<p>组装页富文本区块内容...</p>' } },
          { type: 'buttonGroup', id: genBlockId(), data: { buttons: [{ text: '点击配置', link: '', style: 'primary', actionType: 'link', dialog: { title: '', desc: '', confirmText: '确认', confirmLink: '' } }] } }
        ]
      }
    },
    async fetchList() {
      const res = await request.get('/api/assembly/list', { params: this.searchForm })
      this.tableData = res.data
    },
    handleSearch() {
      this.fetchList()
    },
    handleReset() {
      this.searchForm = { id: '', name: '' }
      this.fetchList()
    },
    handleCreate() {
      this.editData = this.createEmptyAssembly()
      this.isNew = true
      this.isModified = true
      this.quillReady = false
      this.viewState = 'edit'
      this.$nextTick(() => { this.quillReady = true })
    },
    handleEdit(row) {
      this.editData = JSON.parse(JSON.stringify(row))
      this.isNew = false
      this.isModified = false
      this.quillReady = false
      this.viewState = 'edit'
      this.$nextTick(() => { this.quillReady = true })
    },
    async handleDelete(row) {
      await this.$confirm('确认要删除该组装页吗？此操作不可恢复。', '提示', { type: 'warning' })
      await request.post('/api/assembly/delete', { id: row.id })
      this.$message.success('删除成功')
      this.fetchList()
    },
    backToList() {
      this.viewState = 'list'
      this.fetchList()
    },
    async handleSaveAssembly(type) {
      const data = this.editData
      let hasError = false
      data.blocks.forEach(block => {
        if (block.type === 'buttonGroup') {
          block.data.buttons.forEach(btn => {
            if (btn.actionType === 'link' && !btn.link.trim()) hasError = true
          })
        }
      })
      if (hasError) {
        this.$message.error('保存失败：按钮模块中存在未填写的跳转链接！')
        return
      }
      if (!data.name.trim()) data.name = '未命名组装页'
      data.status = type === 'publish' ? 'published' : 'draft'

      const res = await request.post('/api/assembly/save', data)
      if (!data.id) data.id = res.data.id
      this.isModified = false
      this.$message.success(type === 'publish' ? '已发布组装页配置！' : '已保存组装页配置草稿！')
      if (type === 'publish') this.backToList()
    },

    onQuillChange() {
      if (this.quillReady) this.isModified = true
    },

    // 模块操作
    addBlock(type) {
      const block = { type, id: genBlockId(), data: {} }
      if (type === 'image') block.data = { imageUrl: '' }
      if (type === 'privilege') block.data = { title: '新权益标题', items: [{ id: '1', title: '模拟权益', desc: '描述' }] }
      if (type === 'richtext') block.data = { content: '<p>输入富文本内容...</p>' }
      if (type === 'buttonGroup') block.data = { buttons: [{ text: '点击跳转', link: '', style: 'primary', actionType: 'link', dialog: { title: '', desc: '', confirmText: '确认', confirmLink: '' } }] }
      this.editData.blocks.push(block)
      this.isModified = true
    },
    duplicateBlock(index) {
      const block = this.editData.blocks[index]
      if (block.type === 'privilege') {
        this.$message.warning('权益商品模块每页仅限配置一个，无法复制！')
        return
      }
      const copy = JSON.parse(JSON.stringify(block))
      copy.id = genBlockId()
      this.editData.blocks.splice(index + 1, 0, copy)
      this.isModified = true
    },
    removeBlock(index) {
      this.$confirm('确定删除该模块吗？', '提示', { type: 'warning' }).then(() => {
        this.editData.blocks.splice(index, 1)
        this.isModified = true
      }).catch(() => {})
    },
    moveBlock(from, to) {
      if (to < 0 || to >= this.editData.blocks.length || from === to) return
      const item = this.editData.blocks.splice(from, 1)[0]
      this.editData.blocks.splice(to, 0, item)
      this.isModified = true
    },
    movePrivilegeItem(bIdx, from, to) {
      const items = this.editData.blocks[bIdx].data.items
      if (to < 0 || to >= items.length || from === to) return
      const item = items.splice(from, 1)[0]
      items.splice(to, 0, item)
      this.isModified = true
    },

    // 按钮操作
    addButton(bIdx) {
      this.editData.blocks[bIdx].data.buttons.push({
        text: '新按钮', link: '', style: 'secondary', actionType: 'link',
        dialog: { title: '', desc: '', confirmText: '确认', confirmLink: '' }
      })
      this.isModified = true
    },
    removeButton(bIdx, btnIdx) {
      this.editData.blocks[bIdx].data.buttons.splice(btnIdx, 1)
      this.isModified = true
    },
    moveButton(bIdx, from, to) {
      const buttons = this.editData.blocks[bIdx].data.buttons
      if (to < 0 || to >= buttons.length || from === to) return
      const item = buttons.splice(from, 1)[0]
      buttons.splice(to, 0, item)
      this.isModified = true
    },

    // 图片上传
    triggerBlockUpload(bIdx) {
      const ref = this.$refs['blockUpload' + bIdx]
      if (ref) (Array.isArray(ref) ? ref[0] : ref).click()
    },
    onBlockImageUpload(event, bIdx) {
      const file = event.target.files[0]
      if (!file) return
      const reader = new FileReader()
      reader.onload = (e) => {
        this.$set(this.editData.blocks[bIdx].data, 'imageUrl', e.target.result)
        this.isModified = true
      }
      reader.readAsDataURL(file)
      event.target.value = ''
    },

    // 链接弹窗
    showLinkDialog(id) {
      if (!id) {
        this.$message.warning('请先保存组装页再获取链接！')
        return
      }
      this.linkTargetId = id
      const item = this.tableData.find(a => a.id === id) || this.editData
      this.linkTargetPublished = item && item.status === 'published'
      this.linkForm = { campaignId: '', channelId: '' }
      this.linkDialogVisible = true
    },
    copyLink(text) {
      navigator.clipboard.writeText(text).then(() => {
        this.$message.success('链接已复制到剪贴板')
      })
    }
  }
}
</script>

<style scoped>
.search-section .search-row { margin-bottom: 0; }
.search-section .action-row { margin-top: 15px; }
.button-group { display: inline-block; margin-left: 20px; }

.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; }
.basic-info { display: flex; align-items: center; gap: 24px; }
.info-item { display: flex; align-items: center; gap: 8px; }
.info-label { font-size: 13px; color: #909399; white-space: nowrap; }

.block-card {
  background: #fff; border-radius: 8px; border: 1px solid #ebeef5;
  margin-bottom: 16px; overflow: hidden; position: relative;
  box-shadow: 0 1px 4px rgba(0,0,0,.04);
}
.block-header {
  background: #f5f7fa; padding: 10px 16px;
  border-bottom: 1px solid #ebeef5; font-weight: 600; font-size: 14px;
}
.block-header i { margin-right: 6px; color: #909399; }
.block-hint { font-size: 12px; color: #c0c4cc; font-weight: normal; margin-left: 8px; }
.block-body { padding: 16px; }
.block-actions {
  position: absolute; right: 0; top: 0; z-index: 10;
  display: flex; gap: 4px; background: #f5f7fa;
  border-bottom: 1px solid #ebeef5; border-left: 1px solid #ebeef5;
  padding: 6px 8px; border-radius: 0 0 0 8px;
}

.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-wide { width: 360px; height: 160px; }
.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; line-height: 1.6;
  background: #f5f7fa; padding: 8px 12px; border-radius: 4px; border: 1px solid #ebeef5;
}

.privilege-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border: 1px solid #ebeef5; border-radius: 6px;
  background: #fafafa; margin-bottom: 8px;
}
.privilege-no { flex-shrink: 0; }
.privilege-icon {
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid #dcdfe6; background: #fff;
  display: flex; align-items: center; justify-content: center;
  color: #909399; font-size: 18px; flex-shrink: 0;
}
.privilege-info { flex: 1; opacity: .8; }
.privilege-title { font-size: 13px; font-weight: 600; }
.privilege-desc { font-size: 12px; color: #909399; margin-top: 2px; }

.button-config-item {
  position: relative; border: 1px solid #ebeef5; border-radius: 6px;
  padding: 20px 12px 12px; margin-bottom: 12px; background: #fafafa;
}
.btn-index {
  position: absolute; left: 0; top: 0;
  background: #606266; color: #fff; font-size: 10px; font-weight: 700;
  padding: 2px 8px; border-radius: 6px 0 6px 0;
}
.btn-config-body { flex: 1; }
.btn-config-actions {
  position: absolute; right: 12px; top: 12px;
  display: flex; gap: 6px;
}
.dialog-config {
  background: #fff; padding: 12px; border: 1px solid #ebeef5; border-radius: 6px;
  margin-top: 4px;
}
.dialog-config-title {
  font-size: 13px; font-weight: 600; color: #606266;
  border-bottom: 1px solid #ebeef5; padding-bottom: 8px; margin-bottom: 12px;
}

.add-block-bar {
  display: flex; gap: 16px; justify-content: center;
  padding: 20px; border: 2px dashed #dcdfe6; border-radius: 8px;
  background: #fff; margin-bottom: 16px;
}

.empty-tip {
  text-align: center; color: #c0c4cc; padding: 16px;
  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; }
</style>
