<template>
  <div class="leadership-cockpit">
    <!-- 顶部状态栏 & 筛选器 -->
    <div class="cockpit-header">
      <div class="header-left">
        <h1 class="page-title">集团驾驶舱 <span class="subtitle">本月经营动态监测</span></h1>
      </div>
      <div class="header-right">
        <el-form :inline="true" class="search-form-compact">
          <el-form-item label="时间范围">
            <el-date-picker v-model="query.month" type="month" value-format="yyyy-MM" placeholder="选择年月" size="mini"
              style="width: 150px;" @change="handleMonthChange" />
          </el-form-item>
          <el-form-item label="门店">
            <el-select v-model="query.storeIds" multiple collapse-tags placeholder="全部门店" filterable clearable
              size="mini" style="width: 180px;">
              <el-option v-for="store in storeOptions" :key="store.id" :label="store.fullName || store.dm"
                :value="store.id">
              </el-option>
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" size="mini" icon="el-icon-refresh" @click="search()">更新看板</el-button>
          </el-form-item>
          <el-form-item>
            <el-button type="success" size="mini" icon="el-icon-magic-stick" @click="openTechModal">
              测试弹窗
            </el-button>
          </el-form-item>
        </el-form>
      </div>
    </div>

    <!-- 第一层：核心 KPI 指标 (6个) -->
    <el-row :gutter="16" class="kpi-row">
      <el-col :span="4" v-for="(kpi, index) in kpiList" :key="index">
        <div class="kpi-card" :class="kpi.type">
          <div class="kpi-icon"><i :class="kpi.icon"></i></div>
          <div class="kpi-info">
            <div class="kpi-label">{{ kpi.label }}</div>
            <div class="kpi-value">
              <span class="unit" v-if="kpi.isMoney">￥</span>
              {{ kpi.value }}
              <span class="unit" v-if="kpi.isPercent">%</span>
            </div>
            <div class="kpi-trend" v-if="kpi.target">
              目标: {{ kpi.target }} <i class="el-icon-top" v-if="kpi.status === 'up'"></i>
            </div>
          </div>
        </div>
      </el-col>
    </el-row>

    <!-- 会员统计区域 - 统一一行展示 -->
    <el-row :gutter="16" class="member-statistics-section">
      <!-- 会员核心指标 -->
      <el-col :span="8">
        <el-card class="dashboard-card member-overview-card" shadow="hover">
          <div slot="header" class="card-title">
            <span><i class="el-icon-user-solid"></i> 会员核心指标</span>
          </div>
          <div class="member-overview-grid">
            <div class="member-stat-item stat-item-1">
              <div class="stat-main">
                <div class="stat-icon">
                  <i class="el-icon-user-solid"></i>
                </div>
                <div class="stat-content">
                  <div class="stat-label">总会员数</div>
                  <div class="stat-value">{{ formatNumber(memberStatistics.totalMembers) }}</div>
                </div>
              </div>
              <div class="stat-tags">
                <span class="stat-tag">
                  <span class="stat-tag-inner">
                    <i class="el-icon-arrow-up"></i>
                    <span class="stat-tag-text">
                      本月新增: {{ formatNumber(memberStatistics.newMembers) }}人
                    </span>
                  </span>
                </span>
                <span class="stat-tag" v-if="memberStatistics.newMembersLastMonth > 0">
                  <span class="stat-tag-inner">
                    <i class="el-icon-arrow-down"></i>
                    <span class="stat-tag-text">
                      上月新增: {{ formatNumber(memberStatistics.newMembersLastMonth) }}人
                    </span>
                  </span>
                </span>
              </div>
            </div>
            <div class="member-stat-item stat-item-2">
              <div class="stat-main">
                <div class="stat-icon">
                  <i class="el-icon-success"></i>
                </div>
                <div class="stat-content">
                  <div class="stat-label">活跃会员数</div>
                  <div class="stat-value">{{ formatNumber(memberStatistics.activeMembers) }}</div>
                </div>
              </div>
              <div class="stat-tags">
                <span class="stat-tag">
                  <span class="stat-tag-inner">
                    <i class="el-icon-success"></i>
                    <span class="stat-tag-text">
                      活跃(≤3天): {{ formatNumber(memberStatistics.active_0_3) }}
                    </span>
                  </span>
                </span>
                <span class="stat-tag">
                  <span class="stat-tag-inner">
                    <i class="el-icon-date"></i>
                    <span class="stat-tag-text">
                      常到店(4-59天): {{ formatNumber(memberStatistics.active_4_59) }}
                    </span>
                  </span>
                </span>
                <span class="stat-tag">
                  <span class="stat-tag-inner">
                    <i class="el-icon-data-line"></i>
                    <span class="stat-tag-text">
                      60天活跃率: {{ memberStatistics.activeRate }}%
                    </span>
                  </span>
                </span>
                <span class="stat-tag">
                  <span class="stat-tag-inner">
                    <i class="el-icon-aim"></i>
                    <span class="stat-tag-text">
                      30天活跃率: {{ memberStatistics.activeRate30 }}%
                    </span>
                  </span>
                </span>
              </div>
            </div>
            <div class="member-stat-item stat-item-3">
              <div class="stat-main">
                <div class="stat-icon">
                  <i class="el-icon-wallet"></i>
                </div>
                <div class="stat-content">
                  <div class="stat-label">剩余权益总金额</div>
                  <div class="stat-value">￥{{ formatMoney(memberStatistics.totalRemainingAmount) }}</div>
                </div>
              </div>
              <div class="stat-tags">
                <span class="stat-tag">
                  <span class="stat-tag-inner">
                    <i class="el-icon-user"></i>
                    <span class="stat-tag-text">
                      人均: {{ formatMoney(memberStatistics.avgRemainingAmount) }}元
                    </span>
                  </span>
                </span>
                <span class="stat-tag" v-if="memberStatistics.topRemainingAmount > 0">
                  <span class="stat-tag-inner">
                    <i class="el-icon-user-solid"></i>
                    <span class="stat-tag-text">
                      最高剩余权益金额: {{ memberStatistics.topRemainingMemberName || '无' }} ￥{{
                        formatMoney(memberStatistics.topRemainingAmount) }}
                    </span>
                  </span>
                </span>
                <span class="stat-tag" v-if="memberStatistics.topBillingAmount > 0">
                  <span class="stat-tag-inner">
                    <i class="el-icon-wallet"></i>
                    <span class="stat-tag-text">
                      本月开单最高: {{ memberStatistics.topBillingMemberName || '无' }} ￥{{
                        formatMoney(memberStatistics.topBillingAmount) }}
                    </span>
                  </span>
                </span>
                <span class="stat-tag" v-if="memberStatistics.topConsumeAmount > 0">
                  <span class="stat-tag-inner">
                    <i class="el-icon-medal"></i>
                    <span class="stat-tag-text">
                      本月消耗最高: {{ memberStatistics.topConsumeMemberName || '无' }} ￥{{
                        formatMoney(memberStatistics.topConsumeAmount) }}
                    </span>
                  </span>
                </span>
              </div>
            </div>
            <div class="member-stat-item stat-item-4">
              <div class="stat-main">
                <div class="stat-icon">
                  <i class="el-icon-warning"></i>
                </div>
                <div class="stat-content">
                  <div class="stat-label">沉睡会员数</div>
                  <div class="stat-value">{{ formatNumber(memberStatistics.totalSleepMembers) }}</div>
                </div>
              </div>
              <div class="stat-tags">
                <span class="stat-tag">
                  <span class="stat-tag-inner">
                    <i class="el-icon-time"></i>
                    <span class="stat-tag-text">
                      60-89天: {{ formatNumber(memberStatistics.sleep_60_89) }}
                    </span>
                  </span>
                </span>
                <span class="stat-tag">
                  <span class="stat-tag-inner">
                    <i class="el-icon-warning-outline"></i>
                    <span class="stat-tag-text">
                      90-179天: {{ formatNumber(memberStatistics.sleep_90_179) }}
                    </span>
                  </span>
                </span>
                <span class="stat-tag">
                  <span class="stat-tag-inner">
                    <i class="el-icon-warning-outline"></i>
                    <span class="stat-tag-text">
                      180-359天: {{ formatNumber(memberStatistics.sleep_180_359) }}
                    </span>
                  </span>
                </span>
                <span class="stat-tag">
                  <span class="stat-tag-inner">
                    <i class="el-icon-warning-outline"></i>
                    <span class="stat-tag-text">
                      360天+: {{ formatNumber(memberStatistics.sleep_360_plus) }}
                    </span>
                  </span>
                </span>
              </div>
            </div>
          </div>
        </el-card>
      </el-col>

      <!-- 会员类型分布 -->
      <el-col :span="8">
        <el-card class="dashboard-card member-type-card" shadow="hover">
          <div slot="header" class="card-title">
            <span><i class="el-icon-pie-chart"></i> 会员类型分布</span>
          </div>
          <div ref="memberTypeChart" class="member-type-chart"></div>
        </el-card>
      </el-col>

      <!-- 会员分类统计 -->
      <el-col :span="8">
        <el-card class="dashboard-card member-category-card" shadow="hover">
          <div slot="header" class="card-title">
            <span><i class="el-icon-data-analysis"></i> 会员分类统计</span>
          </div>
          <div class="member-category-content">
            <div ref="memberCategoryChart" class="member-category-chart"></div>
            <div class="member-category-legend">
              <div class="legend-item">
                <div class="legend-color" style="background: #409EFF;"></div>
                <div class="legend-text">
                  <div class="legend-name">生美会员</div>
                  <div class="legend-value">{{ formatNumber(memberStatistics.beautyMembers) }}人</div>
                </div>
              </div>
              <div class="legend-item">
                <div class="legend-color" style="background: #F56C6C;"></div>
                <div class="legend-text">
                  <div class="legend-name">医美会员</div>
                  <div class="legend-value">{{ formatNumber(memberStatistics.medicalMembers) }}人</div>
                </div>
              </div>
              <div class="legend-item">
                <div class="legend-color" style="background: #67C23A;"></div>
                <div class="legend-text">
                  <div class="legend-name">科技部会员</div>
                  <div class="legend-value">{{ formatNumber(memberStatistics.techMembers) }}人</div>
                </div>
              </div>
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 第二层：深度分析区 (趋势 + 流量) -->
    <el-row :gutter="16" class="analysis-row">
      <!-- 营收/消耗趋势 -->
      <el-col :span="16">
        <el-card class="dashboard-card" shadow="hover">
          <div slot="header" class="card-title">
            <span><i class="el-icon-data-line"></i> 营收与服务产出趋势分析</span>
            <el-radio-group v-model="trendType" size="mini" style="float: right" @change="handleTrendTypeChange">
              <el-radio-button label="month">按月</el-radio-button>
              <el-radio-button label="day">按天</el-radio-button>
              <el-radio-button label="week">按周</el-radio-button>
            </el-radio-group>
          </div>
          <div id="revenueTrendChart" class="chart-box"></div>
        </el-card>
      </el-col>
      <!-- 转化漏斗 -->
      <el-col :span="8">
        <el-card class="dashboard-card funnel-card" shadow="hover">
          <div slot="header" class="card-title">
            <span><i class="el-icon-filter"></i> 拓客全链路转化漏斗</span>
          </div>
          <div id="tkFunnelChart" class="chart-box"></div>
          <div class="funnel-stats">
            <div class="stat-mini">邀约率: <span>{{ formatPercent(getTkInviteRate()) }}%</span></div>
            <div class="stat-mini">到店率: <span>{{ formatPercent(getInviteStoreRate()) }}%</span></div>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 第三层：竞技排行区 (4个维度) -->
    <el-row :gutter="16" class="ranking-row">
      <!-- 门店排行榜 -->
      <el-col :span="6">
        <el-card class="dashboard-card" shadow="hover">
          <div slot="header" class="card-title"><span><i class="el-icon-office-building"></i> 门店业绩琅琊榜</span></div>
          <div class="rank-list">
            <div class="rank-item" v-for="(item, idx) in storeRanking" :key="idx">
              <span class="rank-no" :class="'top' + (idx + 1)">{{ idx + 1 }}</span>
              <span class="rank-name">{{ item.StoreName }}</span>
              <span class="rank-val">￥{{ formatMoney(item.TotalPerformance) }}</span>
            </div>
          </div>
        </el-card>
      </el-col>
      <!-- 健康师排行 (开单/消耗) -->
      <el-col :span="12">
        <el-card class="dashboard-card" shadow="hover">
          <div slot="header" class="card-title">
            <span><i class="el-icon-user"></i> 核心员效贡献矩阵</span>
            <el-button-group style="float: right">
              <el-button size="mini" :type="coachRankType === 'billing' ? 'primary' : ''"
                @click="coachRankType = 'billing'">开单榜</el-button>
              <el-button size="mini" :type="coachRankType === 'consume' ? 'primary' : ''"
                @click="coachRankType = 'consume'">消耗榜</el-button>
              <el-button size="mini" :type="coachRankType === 'refund' ? 'primary' : ''"
                @click="coachRankType = 'refund'">客情警告</el-button>
            </el-button-group>
          </div>
          <el-table :data="coachRanking" size="mini" style="width: 100%">
            <el-table-column type="index" label="排名" width="50"></el-table-column>
            <el-table-column prop="HealthCoachName" label="健康师"></el-table-column>
            <el-table-column prop="Amount" label="业绩" align="right">
              <template slot-scope="scope">￥{{ formatMoney(scope.row.Amount) }}</template>
            </el-table-column>
            <el-table-column label="占比" width="100">
              <template slot-scope="scope">
                <el-progress :percentage="scope.row.Percent" :show-text="false" :stroke-width="6"
                  :color="idx === 0 ? '#f56c6c' : '#409eff'"></el-progress>
              </template>
            </el-table-column>
          </el-table>
        </el-card>
      </el-col>
      <!-- 金三角排名 -->
      <el-col :span="6">
        <el-card class="dashboard-card" shadow="hover">
          <div slot="header" class="card-title"><span><i class="el-icon-medal"></i> 金三角战队协同榜</span></div>
          <div class="rank-list">
            <div class="rank-item" v-for="(item, idx) in goldTriangleRankingTop10" :key="idx">
              <span class="rank-no" :class="'top' + (idx + 1)">{{ idx + 1 }}</span>
              <span class="rank-name">{{ item.GoldTriangleName }}</span>
              <span class="rank-val">￥{{ formatMoney(item.TotalPerformance) }}</span>
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 第四层：细节洞察 (客情、项目、结构) -->
    <el-row :gutter="16" class="insight-row">
      <!-- 到店频次 -->
      <el-col :span="8">
        <el-card class="dashboard-card" shadow="hover">
          <div slot="header" class="card-title"><span><i class="el-icon-view"></i> 会员到店频次分布</span></div>
          <div id="visitFreqChart" class="chart-box"></div>
        </el-card>
      </el-col>
      <!-- 消耗品项TOP10 -->
      <el-col :span="8">
        <el-card class="dashboard-card" shadow="hover">
          <div slot="header" class="card-title"><span><i class="el-icon-present"></i> 消耗品项 TOP 10</span></div>
          <div class="item-rank">
            <div class="item-rank-row" v-for="(item, idx) in consumeItemTop10" :key="idx">
              <span class="item-index">{{ idx + 1 }}</span>
              <span class="item-name">{{ item.ItemName }}</span>
              <el-progress :percentage="item.Percent" :stroke-width="12" color="#67C23A"
                :show-text="false"></el-progress>
              <span class="item-count">{{ item.Count }}</span>
            </div>
          </div>
        </el-card>
      </el-col>
      <!-- 开单品项TOP10 -->
      <el-col :span="8">
        <el-card class="dashboard-card" shadow="hover">
          <div slot="header" class="card-title"><span><i class="el-icon-pie-chart"></i> 开单品项 TOP 10</span></div>
          <div class="item-rank">
            <div class="item-rank-row" v-for="(item, idx) in billingItemTop10" :key="idx">
              <span class="item-index">{{ idx + 1 }}</span>
              <span class="item-name">{{ item.ItemName }}</span>
              <el-progress :percentage="item.Percent" :stroke-width="12" color="#409EFF"
                :show-text="false"></el-progress>
              <span class="item-count">{{ item.Count }}</span>
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 配置对话框 (保留原有功能) -->
    <el-dialog title="看板字段配置" :visible.sync="showFieldConfigDialog" width="600px" append-to-body>
      <el-checkbox-group v-model="selectedFields">
        <el-checkbox v-for="field in availableFields" :key="field.prop" :label="field.prop">
          {{ field.label }}
        </el-checkbox>
      </el-checkbox-group>
      <div slot="footer">
        <el-button size="mini" @click="selectAllFields">全选</el-button>
        <el-button size="mini" @click="unselectAllFields">反选</el-button>
        <el-button type="primary" size="mini" @click="confirmFieldConfig">确 定</el-button>
      </div>
    </el-dialog>

    <!-- 科技感弹窗预览 -->
    <el-dialog :visible.sync="showTechModal" :title="techModalTitle" :width="techModalWidth" custom-class="tech-dialog"
      append-to-body :close-on-click-modal="false">
      <div class="tech-dialog-controls">
        <el-input v-model="techModalTitle" size="mini" placeholder="弹窗标题" class="control-item" />
        <el-input v-model="techModalWidth" size="mini" placeholder="宽度 如 960px / 80%" class="control-item" />
        <el-input v-model="techModalHeight" size="mini" placeholder="高度 如 70vh" class="control-item" />
        <el-button size="mini" icon="el-icon-refresh" @click="resetTechModal">重置</el-button>
      </div>
      <div class="tech-dialog-body" :style="{ maxHeight: techModalHeight }">
        <div class="tech-grid">
          <div class="tech-card neon-blue">
            <div class="tech-card-title">核心权益</div>
            <div class="tech-card-value">￥{{ formatMoney(memberStatistics.totalRemainingAmount) }}</div>
            <div class="tech-card-desc">剩余权益总额</div>
          </div>
          <div class="tech-card neon-green">
            <div class="tech-card-title">活跃度</div>
            <div class="tech-card-value">{{ memberStatistics.activeRate }}%</div>
            <div class="tech-card-desc">60天活跃率</div>
          </div>
          <div class="tech-card neon-orange">
            <div class="tech-card-title">睡眠会员</div>
            <div class="tech-card-value">{{ formatNumber(memberStatistics.totalSleepMembers) }}</div>
            <div class="tech-card-desc">需唤醒用户</div>
          </div>
        </div>
        <div class="tech-section">
          <div class="tech-section-title">
            <span>组件内容区域</span>
            <span class="subtitle">超出高度自动出现滚动条</span>
          </div>
          <div class="tech-timeline">
            <div class="tech-timeline-item" v-for="i in 6" :key="i">
              <div class="dot"></div>
              <div class="content">
                <div class="title">事件 {{ i }}</div>
                <div class="desc">这里放任意组件或文本，模拟实际穿透内容。</div>
              </div>
              <div class="time">T-{{ i }}</div>
            </div>
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import request from '@/utils/request'
import * as echarts from 'echarts'
import dayjs from 'dayjs'

export default {
  name: 'LeadershipCockpit',
  data() {
    return {
      query: {
        month: dayjs().format('YYYY-MM'), // 默认当前年月
        storeIds: []
      },
      storeOptions: [],
      // 核心 KPI 数据
      kpiData: {},
      trendType: 'day',
      coachRankType: 'billing',
      // 看板核心数据
      trendData: [],
      storeRanking: [],
      coachRankings: {
        billing: [],
        consume: [],
        refund: []
      },
      goldTriangleRankings: [],
      consumeItemTop10: [], // 消耗品项TOP10
      billingItemTop10: [], // 开单品项TOP10
      tkStatisticsData: null,
      customerVisitFrequencyData: [],
      // 会员统计数据
      memberStatistics: {
        totalMembers: 0,
        newMembers: 0,
        newMembersLastMonth: 0,
        active_0_3: 0,
        active_4_59: 0,
        activeMembers: 0,
        activeRate: 0,
        activeRate30: 0,
        totalRemainingAmount: 0,
        avgRemainingAmount: 0,
        topRemainingMemberName: '',
        topRemainingAmount: 0,
        topBillingMemberName: '',
        topBillingAmount: 0,
        topConsumeMemberName: '',
        topConsumeAmount: 0,
        totalSleepMembers: 0,
        sleep_60_89: 0,
        sleep_90_179: 0,
        sleep_180_359: 0,
        sleep_360_plus: 0,
        beautyMembers: 0,
        medicalMembers: 0,
        techMembers: 0,
        educationMembers: 0
      },
      memberTypeDistribution: [], // 会员类型分布
      // 内部状态
      loading: false,
      showFieldConfigDialog: false,
      // 科技感弹窗
      showTechModal: false,
      techModalTitle: '会员画像穿透预览',
      techModalWidth: '960px',
      techModalHeight: '70vh',
      availableFields: [
        { prop: 'StoreName', label: '门店名称' },
        { prop: 'BillingAmount', label: '开单金额' },
        { prop: 'ConsumeAmount', label: '消耗金额' }
      ],
      selectedFields: ['StoreName', 'BillingAmount', 'ConsumeAmount'],
      charts: {}
    }
  },
  computed: {
    // 6大核心 KPI 装饰器
    kpiList() {
      const d = this.kpiData || {}
      return [
        { label: '本月成交总额', value: this.formatMoney(d.TotalBillingAmount), icon: 'el-icon-wallet', type: 'primary', isMoney: true },
        { label: '本月消耗金额', value: this.formatMoney(d.TotalConsumeAmount), icon: 'el-icon-medal', type: 'success', isMoney: true },
        { label: '完成业绩(净额)', value: this.formatMoney(d.CompletedBillingAmount), icon: 'el-icon-trophy', type: 'warning', isMoney: true },
        { label: '开单目标达成', value: d.BillingCompletionRate || 0, icon: 'el-icon-pie-chart', type: 'info', isPercent: true, target: this.formatMoney(d.TargetBillingAmount), status: (d.BillingCompletionRate >= 100) ? 'up' : 'down' },
        { label: '本月拓客人数', value: (this.tkStatisticsData && this.tkStatisticsData.TkCount) ? this.tkStatisticsData.TkCount : 0, icon: 'el-icon-user-solid', type: 'danger', isPercent: false, target: null, status: null },
        { label: '退卡总计', value: this.formatMoney(d.TotalRefundAmount), icon: 'el-icon-warning-outline', type: 'error', isMoney: true }
      ]
    },
    // 健康师排行榜数据切换
    coachRanking() {
      const list = this.coachRankings[this.coachRankType] || []
      const max = list.length > 0 ? Math.max(...list.map(i => i.Amount || 1)) : 100
      return list.map(item => ({
        ...item,
        Percent: Math.min(100, Math.round((item.Amount / max) * 100))
      })).slice(0, 10)
    },
    // 金三角排行榜Top10
    goldTriangleRankingTop10() {
      if (!this.goldTriangleRankings || this.goldTriangleRankings.length === 0) {
        return []
      }
      return [...this.goldTriangleRankings]
        .sort((a, b) => (b.F_TotalPerformance || b.TotalPerformance || 0) - (a.F_TotalPerformance || a.TotalPerformance || 0))
        .slice(0, 10)
        .map(item => ({
          GoldTriangleName: item.F_GoldTriangleName || item.GoldTriangleName || '未知',
          TotalPerformance: item.F_TotalPerformance || item.TotalPerformance || 0
        }))
    }
  },
  watch: {
    coachRankType() {
      // 切换排行榜类型时不需要重载 API，已经预加载
    },
    trendType() {
      // 趋势类型改变时重新加载数据
      this.search()
    },
    query: {
      deep: true,
      handler() {
        // 条件变化不自动触发，手动点更新
      }
    }
  },
  async mounted() {
    this.setDefaultTimeRange()
    await this.initStoreOptions()
    this.search()
    window.addEventListener('resize', this.handleResize)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.handleResize)
    Object.values(this.charts).forEach(c => c && c.dispose())
    if (this.charts.memberTypeChart) {
      this.charts.memberTypeChart.dispose()
    }
    if (this.charts.memberCategoryChart) {
      this.charts.memberCategoryChart.dispose()
    }
  },
  methods: {
    // 设置默认查询范围：本月
    setDefaultTimeRange() {
      this.query.month = dayjs().format('YYYY-MM')
    },
    // 打开科技感弹窗
    openTechModal() {
      this.showTechModal = true
    },
    // 重置弹窗大小与标题
    resetTechModal() {
      this.techModalTitle = '会员画像穿透预览'
      this.techModalWidth = '960px'
      this.techModalHeight = '70vh'
    },
    // 年月选择器变化处理
    handleMonthChange() {
      // 自动触发查询
      this.search()
    },

    // 将日期转换为月份格式 (YYYYMM)
    formatDateToMonth(dateStr) {
      if (!dateStr) return null
      const date = dayjs(dateStr)
      return date.format('YYYYMM')
    },
    // 将日期字符串转换为DateTime对象格式
    formatDateToDateTime(dateStr, isEnd = false) {
      if (!dateStr) return null
      const date = dayjs(dateStr)
      if (isEnd) {
        return date.endOf('day').format('YYYY-MM-DD HH:mm:ss')
      }
      return date.startOf('day').format('YYYY-MM-DD HH:mm:ss')
    },
    // 搜索逻辑
    async search() {
      this.loading = true

      // 从年月选择器获取月份，转换为开始和结束时间
      const selectedMonth = this.query.month || dayjs().format('YYYY-MM')
      // 确保开始时间是选择月份的第一天 00:00:00，结束时间是最后一天 23:59:59
      const monthStart = dayjs(selectedMonth + '-01').startOf('day')
      const monthEnd = dayjs(selectedMonth + '-01').endOf('month').endOf('day')

      // 获取当前月份（YYYYMM格式，用于需要月份格式的接口）
      const currentMonth = monthStart.format('YYYYMM')

      // 构建不同接口需要的参数格式
      // 确保开始时间是选择月份的第一天 00:00:00，结束时间是最后一天 23:59:59
      const dateParams = {
        startTime: monthStart.startOf('day').format('YYYY-MM-DD HH:mm:ss'),
        endTime: monthEnd.endOf('day').format('YYYY-MM-DD HH:mm:ss'),
        storeIds: this.query.storeIds || []
      }

      // 根据趋势类型构建不同的查询参数
      let trendParams = {}
      if (this.trendType === 'month') {
        // 按月：查询最近12个月
        const trendStartMonth = monthStart.subtract(11, 'month').format('YYYYMM')
        const trendEndMonth = currentMonth
        trendParams = {
          startMonth: trendStartMonth,
          endMonth: trendEndMonth,
          periodType: 'month',
          storeIds: this.query.storeIds || []
        }
      } else if (this.trendType === 'day') {
        // 按天：查询本月
        const monthStartDate = monthStart.format('YYYY-MM-DD')
        const monthEndDate = monthEnd.format('YYYY-MM-DD')
        trendParams = {
          startMonth: monthStartDate,
          endMonth: monthEndDate,
          periodType: 'day',
          storeIds: this.query.storeIds || []
        }
      } else if (this.trendType === 'week') {
        // 按周：查询最近4周
        const weekStartDate = monthStart.subtract(27, 'day').format('YYYY-MM-DD')
        const weekEndDate = monthEnd.format('YYYY-MM-DD')
        trendParams = {
          startMonth: weekStartDate,
          endMonth: weekEndDate,
          periodType: 'week',
          storeIds: this.query.storeIds || []
        }
      }

      const monthParams = {
        startMonth: currentMonth,
        endMonth: currentMonth,
        statisticsMonth: currentMonth,
        storeIds: this.query.storeIds || []
      }

      try {
        await Promise.all([
          this.loadKPIs(dateParams),
          this.loadTrends(trendParams),
          this.loadTkFunnel(dateParams),
          this.loadRankings({ ...monthParams, ...dateParams }),
          this.loadInsights(dateParams),
          this.loadMemberStatistics({ statisticsMonth: currentMonth })
        ])
        // 确保数据加载完成后再渲染图表
        await this.$nextTick()
        this.initAllCharts()
      } catch (e) {
        console.error('LeadershipCockpit Load Error:', e)
        const errorMsg = (e.response && e.response.data && e.response.data.msg) || e.message || '未知错误'
        this.$message.error('数据加载异常，请检查网络或重试: ' + errorMsg)
      } finally {
        this.loading = false
      }
    },

    // --- 数据加载器 ---
    async loadKPIs(p) {
      try {
        // 将时间字符串转换为 Date 对象，确保使用北京时间
        const startTimeDate = p.startTime ? dayjs(p.startTime).startOf('day').toDate() : null
        const endTimeDate = p.endTime ? dayjs(p.endTime).endOf('day').toDate() : null

        const res = await request({
          url: '/api/Extend/LqReport/get-business-statistics',
          method: 'POST',
          data: {
            startTime: p.startTime,
            endTime: p.endTime,
            storeIds: p.storeIds || []
          }
        })
        // 接口返回的数据格式
        const data = res.data || {}
        this.kpiData = {
          TotalBillingAmount: data.TotalBillingAmount || data.billing_amount || 0,
          TotalConsumeAmount: data.TotalConsumeAmount || data.consume_amount || 0,
          CompletedBillingAmount: (data.TotalBillingAmount || data.billing_amount || 0) - (data.TotalRefundAmount || data.refund_amount || 0),
          BillingCompletionRate: data.BillingCompletionRate || 0,
          ConsumeCompletionRate: data.ConsumeCompletionRate || 0,
          TargetBillingAmount: data.TargetBillingAmount || data.target_billing_amount || 0,
          TargetConsumeAmount: data.TargetConsumeAmount || data.target_consume_amount || 0,
          TotalRefundAmount: data.TotalRefundAmount || data.refund_amount || 0
        }
      } catch (error) {
        console.error('加载KPI数据失败:', error)
        this.kpiData = {}
      }
    },
    async loadTrends(p) {
      try {
        const res = await request({
          url: '/api/Extend/LqReport/get-store-performance-trend',
          method: 'POST',
          data: {
            startMonth: p.startMonth,
            endMonth: p.endMonth,
            periodType: p.periodType || 'month',
            storeIds: p.storeIds || []
          }
        })
        // 接口返回格式: { Success: true, Data: [...], Message: "..." }
        console.log('趋势接口返回数据:', res.data)
        if (res.data && res.data.Success && res.data.Data && Array.isArray(res.data.Data)) {
          // 将数据转换为图表需要的格式（按日期汇总）
          const allData = []
          res.data.Data.forEach(store => {
            if (store && store.Data && Array.isArray(store.Data)) {
              store.Data.forEach(item => {
                if (item && item.Month) {
                  allData.push({
                    Date: item.Month,
                    BillingAmount: parseFloat(item.TotalPerformance || 0),
                    ConsumeAmount: parseFloat(item.ConsumeAmount || 0)
                  })
                }
              })
            }
          })
          // 按日期分组汇总
          const grouped = {}
          allData.forEach(item => {
            if (!grouped[item.Date]) {
              grouped[item.Date] = { Date: item.Date, BillingAmount: 0, ConsumeAmount: 0 }
            }
            grouped[item.Date].BillingAmount += item.BillingAmount
            grouped[item.Date].ConsumeAmount += item.ConsumeAmount
          })
          this.trendData = Object.values(grouped).sort((a, b) => a.Date.localeCompare(b.Date))

          console.log('处理后的趋势数据:', this.trendData)

          // 调试日志
          if (this.trendData.length === 0) {
            console.warn('趋势数据为空，接口返回:', res.data)
          }
        } else {
          console.warn('趋势数据格式不正确，接口返回:', res.data)
          this.trendData = []
        }
      } catch (error) {
        console.error('加载趋势数据失败:', error)
        this.trendData = []
      }
    },
    async loadTkFunnel(p) {
      try {
        const res = await request({
          url: '/api/Extend/LqTkjlb/get-tk-statistics',
          method: 'POST',
          data: {
            startTime: p.startTime ? dayjs(p.startTime).toDate() : null,
            endTime: p.endTime ? dayjs(p.endTime).toDate() : null,
            storeId: p.storeIds || []
          }
        })
        this.tkStatisticsData = res.data || null
      } catch (error) {
        console.error('加载拓客漏斗数据失败:', error)
        this.tkStatisticsData = null
      }
    },
    async loadRankings(p) {
      try {
        const [store, bill, cons, refu, gold] = await Promise.all([
          request({
            url: '/api/Extend/LqReport/get-store-performance-ranking',
            method: 'POST',
            data: {
              statisticsMonth: p.statisticsMonth,
              topCount: 10
            }
          }),
          request({
            url: '/api/Extend/LqReport/get-health-coach-billing-ranking',
            method: 'POST',
            data: {
              startTime: p.startTime,
              endTime: p.endTime,
              storeIds: p.storeIds
            }
          }),
          request({
            url: '/api/Extend/LqReport/get-health-coach-consume-ranking',
            method: 'POST',
            data: {
              startTime: p.startTime,
              endTime: p.endTime,
              storeIds: p.storeIds
            }
          }),
          request({
            url: '/api/Extend/LqReport/get-health-coach-refund-ranking',
            method: 'POST',
            data: {
              startTime: p.startTime,
              endTime: p.endTime,
              storeIds: p.storeIds
            }
          }),
          request({
            url: '/api/Extend/LqReport/get-gold-triangle-performance-ranking',
            method: 'POST',
            data: {
              statisticsMonth: p.statisticsMonth,
              topCount: 10
            }
          })
        ])

        // 解析门店排行榜数据
        if (store.data && store.data.Success && store.data.Data) {
          this.storeRanking = store.data.Data.map(item => ({
            StoreName: item.StoreName,
            TotalPerformance: item.TotalPerformance || 0
          }))
        } else {
          this.storeRanking = []
        }

        // 解析健康师排行榜数据
        const billData = (bill.data && bill.data.Success && bill.data.Data) ? bill.data.Data : (bill.data || [])
        const consData = (cons.data && cons.data.Success && cons.data.Data) ? cons.data.Data : (cons.data || [])
        const refuData = (refu.data && refu.data.Success && refu.data.Data) ? refu.data.Data : (refu.data || [])

        this.coachRankings.billing = billData.map(i => ({
          HealthCoachName: i.HealthCoachName || i.Name || '未知',
          Amount: i.BillingPerformance || i.Performance || 0
        }))
        this.coachRankings.consume = consData.map(i => ({
          HealthCoachName: i.HealthCoachName || i.Name || '未知',
          Amount: i.ConsumePerformance || i.Performance || 0
        }))
        this.coachRankings.refund = refuData.map(i => ({
          HealthCoachName: i.HealthCoachName || i.Name || '未知',
          Amount: i.RefundPerformance || i.Performance || 0
        }))

        // 解析金三角排行榜数据
        if (gold.data && gold.data.Success && gold.data.Data) {
          this.goldTriangleRankings = gold.data.Data.map(item => ({
            F_GoldTriangleName: item.GoldTriangleName,
            F_TotalPerformance: item.TotalPerformance || 0
          }))
        } else {
          this.goldTriangleRankings = []
        }
      } catch (error) {
        console.error('加载排行榜数据失败:', error)
        this.storeRanking = []
        this.coachRankings = { billing: [], consume: [], refund: [] }
        this.goldTriangleRankings = []
      }
    },
    async loadMemberStatistics(p) {
      try {
        const res = await request({
          url: '/api/Extend/LqReport/get-dashboard-data',
          method: 'POST',
          data: {
            StatisticsMonth: p.statisticsMonth
          }
        })
        if (res.data && res.data.Success && res.data.Data && res.data.Data.MemberStatistics) {
          const ms = res.data.Data.MemberStatistics
          const active_0_3 = ms.ActiveMembers0_3 || 0
          const active_4_59 = ms.ActiveMembers4_59 || 0
          const totalMembers = ms.TotalMembers || 0
          const active30 = ms.ActiveMembers || 0
          const active60 = active_0_3 + active_4_59
          const activeRate60 = totalMembers > 0 ? Math.round((active60 / totalMembers) * 10000) / 100 : 0
          const activeRate30 = totalMembers > 0 ? Math.round((active30 / totalMembers) * 10000) / 100 : 0
          this.memberStatistics = {
            totalMembers,
            newMembers: ms.NewMembersThisMonth || 0,
            newMembersLastMonth: ms.NewMembersLastMonth || 0,
            active_0_3,
            active_4_59,
            // 活跃会员数：沉睡天数 ≤ 59 天（即活跃 + 常到店）
            activeMembers: active60,
            // 60天活跃率
            activeRate: activeRate60,
            // 30天活跃率（后端ActiveMembers本身为30天口径）
            activeRate30,
            totalRemainingAmount: ms.TotalRemainingAmount || 0,
            avgRemainingAmount: ms.AvgRemainingAmount || 0,
            topRemainingMemberName: ms.TopRemainingMemberName || '',
            topRemainingAmount: ms.TopRemainingAmount || 0,
            topBillingMemberName: ms.TopBillingMemberName || '',
            topBillingAmount: ms.TopBillingAmount || 0,
            topConsumeMemberName: ms.TopConsumeMemberName || '',
            topConsumeAmount: ms.TopConsumeAmount || 0,
            totalSleepMembers: ms.TotalSleepMembers || 0,
            sleep_60_89: ms.SleepMembers60_89 || 0,
            sleep_90_179: ms.SleepMembers90_179 || 0,
            sleep_180_359: ms.SleepMembers180_359 || 0,
            sleep_360_plus: ms.SleepMembers360Plus || 0,
            beautyMembers: ms.BeautyMembers || 0,
            medicalMembers: ms.MedicalMembers || 0,
            techMembers: ms.TechMembers || 0,
            educationMembers: ms.EducationMembers || 0
          }
          this.memberTypeDistribution = ms.MemberTypeDistribution || []
          // 等待DOM更新后渲染会员类型分布饼图和分类雷达图，并更新tag滚动
          this.$nextTick(() => {
            this.initMemberTypeChart()
            this.initMemberCategoryChart()
            this.updateStatTagMarquee()
          })
        }
      } catch (error) {
        console.error('加载会员统计数据失败:', error)
        this.memberStatistics = {}
        this.memberTypeDistribution = []
      }
    },
    updateStatTagMarquee() {
      if (!this.$el) return
      const tags = this.$el.querySelectorAll('.member-stat-item .stat-tag')
      tags.forEach(tag => {
        const inner = tag.querySelector('.stat-tag-inner')
        if (!inner) return
        // 以整个tag的可视宽度作为判断标准，内容超过tag宽度才滚动
        if (inner.scrollWidth > tag.clientWidth + 1) {
          inner.classList.add('is-marquee')
        } else {
          inner.classList.remove('is-marquee')
        }
      })
    },
    async loadInsights(p) {
      try {
        const [freq, item] = await Promise.all([
          request({
            url: '/api/Extend/LqReport/get-customer-visit-frequency',
            method: 'POST',
            data: {
              startTime: p.startTime ? dayjs(p.startTime).toDate() : null,
              endTime: p.endTime ? dayjs(p.endTime).toDate() : null,
              storeIds: p.storeIds || []
            }
          }),
          request({
            url: '/api/Extend/LqReport/get-item-statistics',
            method: 'POST',
            data: {
              startTime: p.startTime ? dayjs(p.startTime).toDate() : null,
              endTime: p.endTime ? dayjs(p.endTime).toDate() : null,
              storeIds: p.storeIds || []
            }
          })
        ])

        // 解析客户到店频次数据
        this.customerVisitFrequencyData = (freq.data || []).map(item => ({
          VisitCount: item.VisitCount || 0,
          CustomerCount: item.CustomerCount || 0
        }))

        // 解析品项统计数据
        const raw = item.data || []

        // 消耗品项TOP10（按消耗数量排序）
        const consumeMax = raw.length ? Math.max(...raw.map(i => (i.ConsumeCount || 0)), 1) : 100
        this.consumeItemTop10 = raw
          .filter(i => (i.ConsumeCount || 0) > 0)
          .sort((a, b) => (b.ConsumeCount || 0) - (a.ConsumeCount || 0))
          .slice(0, 10)
          .map(i => ({
            ItemName: i.ItemName || '未知品项',
            Count: i.ConsumeCount || 0,
            Percent: Math.round(((i.ConsumeCount || 0) / consumeMax) * 100)
          }))

        // 开单品项TOP10（按开单数量排序）
        const billingMax = raw.length ? Math.max(...raw.map(i => (i.BillingCount || 0)), 1) : 100
        this.billingItemTop10 = raw
          .filter(i => (i.BillingCount || 0) > 0)
          .sort((a, b) => (b.BillingCount || 0) - (a.BillingCount || 0))
          .slice(0, 10)
          .map(i => ({
            ItemName: i.ItemName || '未知品项',
            Count: i.BillingCount || 0,
            Percent: Math.round(((i.BillingCount || 0) / billingMax) * 100)
          }))
      } catch (error) {
        console.error('加载洞察数据失败:', error)
        this.customerVisitFrequencyData = []
        this.consumeItemTop10 = []
        this.billingItemTop10 = []
      }
    },

    // --- 图表引擎 ---
    initAllCharts() {
      this.renderTrendChart()
      this.renderFunnelChart()
      // renderGoldChart 已移除，改为列表显示
      this.renderVisitChart()
      // renderCategoryChart 已移除，改为列表显示
      this.initMemberTypeChart()
      this.initMemberCategoryChart()
    },
    // 初始化会员类型分布饼图
    initMemberTypeChart() {
      if (!this.$refs.memberTypeChart || !this.memberTypeDistribution || this.memberTypeDistribution.length === 0) {
        return
      }
      if (this.charts.memberTypeChart) {
        this.charts.memberTypeChart.dispose()
      }
      const chartDom = this.$refs.memberTypeChart
      if (!chartDom) return
      this.charts.memberTypeChart = echarts.init(chartDom)
      const option = {
        tooltip: {
          trigger: 'item',
          formatter: '{a} <br/>{b}: {c}人 ({d}%)'
        },
        legend: {
          orient: 'vertical',
          left: '5%',
          top: 'middle',
          itemWidth: 14,
          itemHeight: 14,
          textStyle: {
            fontSize: 13,
            color: '#606266',
            fontWeight: 'normal'
          },
          itemGap: 12
        },
        series: [
          {
            name: '会员类型',
            type: 'pie',
            radius: ['50%', '85%'],
            center: ['65%', '50%'],
            avoidLabelOverlap: false,
            itemStyle: {
              borderRadius: 8,
              borderColor: '#fff',
              borderWidth: 3
            },
            label: {
              show: true,
              formatter: '{b}\n{c}人\n({d}%)',
              fontSize: 12,
              fontWeight: 'normal',
              color: '#303133',
              lineHeight: 16
            },
            labelLine: {
              show: true,
              length: 15,
              length2: 8,
              lineStyle: {
                width: 1
              }
            },
            emphasis: {
              label: {
                show: true,
                fontSize: 13,
                fontWeight: 'bold'
              },
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: 'rgba(0, 0, 0, 0.3)'
              }
            },
            data: this.memberTypeDistribution.map((item, index) => {
              const colors = ['#F56C6C', '#67C23A', '#409EFF', '#E6A23C']
              return {
                value: item.Count || 0,
                name: item.MemberType || '未知',
                itemStyle: {
                  color: colors[index % colors.length]
                }
              }
            })
          }
        ]
      }
      this.charts.memberTypeChart.setOption(option)

      // 响应式调整
      window.addEventListener('resize', () => {
        if (this.charts.memberTypeChart) {
          this.charts.memberTypeChart.resize()
        }
      })
    },
    // 初始化会员分类雷达图（移除教育部会员）
    initMemberCategoryChart() {
      if (!this.$refs.memberCategoryChart) {
        return
      }
      if (this.charts.memberCategoryChart) {
        this.charts.memberCategoryChart.dispose()
      }
      const chartDom = this.$refs.memberCategoryChart
      if (!chartDom) return
      this.charts.memberCategoryChart = echarts.init(chartDom)

      // 计算最大值用于归一化（只计算三个分类）
      const maxValue = Math.max(
        this.memberStatistics.beautyMembers || 0,
        this.memberStatistics.medicalMembers || 0,
        this.memberStatistics.techMembers || 0
      ) || 100

      const option = {
        tooltip: {
          trigger: 'item',
          formatter: (params) => {
            const name = params.name
            let actualValue = 0
            switch (name) {
              case '生美会员': actualValue = this.memberStatistics.beautyMembers || 0; break
              case '医美会员': actualValue = this.memberStatistics.medicalMembers || 0; break
              case '科技部会员': actualValue = this.memberStatistics.techMembers || 0; break
            }
            return `${name}<br/>${actualValue}人`
          }
        },
        radar: {
          indicator: [
            { name: '生美会员', max: maxValue },
            { name: '医美会员', max: maxValue },
            { name: '科技部会员', max: maxValue }
          ],
          center: ['50%', '55%'],
          radius: '90%',
          nameGap: 10,
          splitNumber: 4,
          axisName: {
            color: '#303133',
            fontSize: 13,
            fontWeight: 'bold'
          },
          splitArea: {
            areaStyle: {
              color: ['rgba(64, 158, 255, 0.1)', 'rgba(64, 158, 255, 0.05)']
            }
          },
          splitLine: {
            lineStyle: {
              color: 'rgba(64, 158, 255, 0.2)'
            }
          },
          axisLine: {
            lineStyle: {
              color: 'rgba(64, 158, 255, 0.3)'
            }
          }
        },
        series: [
          {
            name: '会员分类统计',
            type: 'radar',
            data: [
              {
                value: [
                  this.memberStatistics.beautyMembers || 0,
                  this.memberStatistics.medicalMembers || 0,
                  this.memberStatistics.techMembers || 0
                ],
                name: '会员分布',
                areaStyle: {
                  color: 'rgba(64, 158, 255, 0.2)'
                },
                lineStyle: {
                  color: '#409EFF',
                  width: 2
                },
                itemStyle: {
                  color: '#409EFF'
                },
                symbol: 'circle',
                symbolSize: 6
              }
            ]
          }
        ]
      }
      this.charts.memberCategoryChart.setOption(option)

      // 响应式调整
      window.addEventListener('resize', () => {
        if (this.charts.memberCategoryChart) {
          this.charts.memberCategoryChart.resize()
        }
      })
    },
    renderTrendChart() {
      const chart = this.getChart('revenueTrendChart')
      console.log('渲染趋势图表，数据:', this.trendData)

      if (!this.trendData || this.trendData.length === 0) {
        chart.setOption({
          title: { text: '暂无数据', left: 'center', top: 'middle', textStyle: { color: '#909399' } }
        })
        return
      }

      // 格式化日期显示
      const dates = this.trendData.map(i => {
        const date = i.Date
        if (!date) return ''

        if (this.trendType === 'month') {
          // 按月：YYYYMM格式，转换为 YYYY-MM
          if (date.length === 6) {
            return date.substring(0, 4) + '-' + date.substring(4, 6)
          }
        } else if (this.trendType === 'day') {
          // 按天：YYYY-MM-DD格式，只显示日期部分
          if (date.length >= 10) {
            return date.substring(5, 10) // MM-DD
          }
        } else if (this.trendType === 'week') {
          // 按周：YYYY-WXX格式，转换为更友好的显示
          if (date.includes('-W')) {
            return date.replace('-W', ' 第') + '周'
          }
        }

        return date
      })

      const billingData = this.trendData.map(i => parseFloat(i.BillingAmount || 0))
      const consumeData = this.trendData.map(i => parseFloat(i.ConsumeAmount || 0))

      console.log('图表数据 - 日期:', dates, '成交额:', billingData, '服务产出:', consumeData)

      chart.setOption({
        tooltip: {
          trigger: 'axis',
          backgroundColor: 'rgba(255,255,255,0.95)',
          borderWidth: 1,
          borderColor: '#E4E7ED',
          textStyle: { color: '#303133' },
          shadowBlur: 10,
          formatter: function (params) {
            let result = '<div style="color: #303133; font-weight: bold;">' + params[0].name + '</div>'
            params.forEach(param => {
              const value = param.value >= 10000 ? (param.value / 10000).toFixed(2) + '万' : '￥' + param.value.toLocaleString()
              result += '<div style="margin-top: 4px;">' + param.marker + '<span style="color: #606266;">' + param.seriesName + '</span>: <span style="color: #303133; font-weight: bold;">' + value + '</span></div>'
            })
            return result
          }
        },
        legend: { top: 0, textStyle: { color: '#303133', fontSize: 12 }, itemGap: 20 },
        grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
        xAxis: {
          type: 'category',
          boundaryGap: false,
          data: dates,
          axisLine: { lineStyle: { color: '#E4E7ED' } },
          axisLabel: { color: '#303133', fontSize: 12 }
        },
        yAxis: {
          type: 'value',
          splitLine: { lineStyle: { type: 'dashed', color: '#E4E7ED' } },
          axisLine: { lineStyle: { color: '#E4E7ED' } },
          axisLabel: {
            color: '#303133',
            fontSize: 12,
            formatter: function (value) {
              if (value >= 10000) {
                return (value / 10000).toFixed(1) + '万'
              }
              return value
            }
          }
        },
        series: [
          {
            name: '成交额',
            type: 'line',
            smooth: true,
            showSymbol: dates.length === 1 ? true : dates.length <= 7 ? true : false,
            symbol: 'circle',
            symbolSize: 6,
            areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(64,158,255,0.3)' }, { offset: 1, color: 'rgba(64,158,255,0)' }]) },
            data: billingData,
            color: '#409EFF',
            lineStyle: { width: 2 }
          },
          {
            name: '服务产出',
            type: 'line',
            smooth: true,
            showSymbol: dates.length === 1 ? true : dates.length <= 7 ? true : false,
            symbol: 'circle',
            symbolSize: 6,
            areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(103,194,58,0.3)' }, { offset: 1, color: 'rgba(103,194,58,0)' }]) },
            data: consumeData,
            color: '#67C23A',
            lineStyle: { width: 2 }
          }
        ]
      })
    },
    renderFunnelChart() {
      if (!this.tkStatisticsData) return
      const chart = this.getChart('tkFunnelChart')
      const d = this.tkStatisticsData
      chart.setOption({
        tooltip: { trigger: 'item' },
        series: [{
          type: 'funnel', left: '10%', top: 20, bottom: 20, width: '80%',
          label: { show: true, position: 'inside', formatter: '{b}\n{c}人', color: '#fff' },
          itemStyle: { borderWidth: 0, shadowBlur: 10, shadowColor: 'rgba(0,0,0,0.1)' },
          data: [
            { value: d.TkCount, name: '获客' },
            { value: d.YaoyCount, name: '邀约' },
            { value: d.DdCount, name: '到店' },
            { value: d.XfCount, name: '成交' }
          ],
          color: ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C']
        }]
      })
    },
    renderGoldChart() {
      const chart = this.getChart('goldTriangleChart')
      if (!this.goldTriangleRankings || this.goldTriangleRankings.length === 0) {
        chart.setOption({
          title: { text: '暂无数据', left: 'center', top: 'middle', textStyle: { color: '#909399' } }
        })
        return
      }

      const sorted = [...this.goldTriangleRankings]
        .sort((a, b) => (b.F_TotalPerformance || b.TotalPerformance || 0) - (a.F_TotalPerformance || a.TotalPerformance || 0))
        .slice(0, 5)

      chart.setOption({
        tooltip: { trigger: 'axis' },
        grid: { left: '25%', right: '10%', top: 10, bottom: 20 },
        xAxis: { type: 'value', show: false },
        yAxis: {
          type: 'category',
          data: sorted.map(i => i.F_GoldTriangleName || i.GoldTriangleName || '未知'),
          axisLine: { show: false },
          axisTick: { show: false },
          axisLabel: { fontSize: 11, color: '#909399' }
        },
        series: [{
          type: 'bar',
          data: sorted.map(i => i.F_TotalPerformance || i.TotalPerformance || 0),
          barWidth: 10,
          itemStyle: { borderRadius: 5, color: '#E6A23C' },
          showBackground: true,
          backgroundStyle: { color: '#F2F6FC', borderRadius: 5 }
        }]
      })
    },
    renderVisitChart() {
      const chart = this.getChart('visitFreqChart')
      if (!this.customerVisitFrequencyData || this.customerVisitFrequencyData.length === 0) {
        chart.setOption({
          title: { text: '暂无数据', left: 'center', top: 'middle', textStyle: { color: '#909399' } }
        })
        return
      }

      const data = this.customerVisitFrequencyData
        .sort((a, b) => (a.VisitCount || 0) - (b.VisitCount || 0))
        .slice(0, 8)

      chart.setOption({
        tooltip: {
          trigger: 'axis',
          formatter: function (params) {
            const param = params[0]
            return param.name + '<br/>' + param.seriesName + ': ' + param.value + '人'
          }
        },
        grid: { left: '15%', right: '10%', top: '10%', bottom: '15%' },
        xAxis: {
          type: 'category',
          data: data.map(i => (i.VisitCount || 0) + '次'),
          axisLine: { show: true, lineStyle: { color: '#E4E7ED' } },
          axisTick: { show: false },
          axisLabel: { color: '#606266', fontSize: 12 }
        },
        yAxis: {
          type: 'value',
          show: true,
          axisLine: { show: false },
          axisTick: { show: false },
          splitLine: { lineStyle: { type: 'dashed', color: '#E4E7ED' } },
          axisLabel: { color: '#909399', fontSize: 12 }
        },
        series: [{
          type: 'bar',
          name: '客户数',
          data: data.map(i => i.CustomerCount || 0),
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: '#409EFF' },
            { offset: 1, color: '#67C23A' }
          ]),
          barWidth: '50%',
          itemStyle: { borderRadius: [4, 4, 0, 0] },
          label: {
            show: true,
            position: 'top',
            color: '#303133',
            fontSize: 12
          }
        }]
      })
    },
    renderCategoryChart() {
      // 这个图表已经改为开单品项TOP10列表，不再需要渲染图表
      // 保留方法避免报错
    },
    getChart(id) {
      const dom = document.getElementById(id)
      if (!dom) return { setOption: () => { } }
      if (this.charts[id]) this.charts[id].dispose()
      this.charts[id] = echarts.init(dom)
      return this.charts[id]
    },
    handleResize() { Object.values(this.charts).forEach(c => c && c.resize()) },
    async initStoreOptions() {
      try {
        const res = await request({ url: '/api/Extend/LqMdxx/Selector', method: 'GET' })
        // 接口返回格式: { list: [...] }
        this.storeOptions = (res.data && res.data.list) ? res.data.list : []
      } catch (error) {
        console.error('加载门店列表失败:', error)
        this.storeOptions = []
      }
    },
    formatMoney(v) { return Number(v || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) },
    formatNumber(v) {
      const num = Number(v || 0)
      return num.toLocaleString()
    },
    formatPercent(v) { return Number(v || 0).toFixed(1) },
    getTkInviteRate() {
      if (!this.tkStatisticsData || !this.tkStatisticsData.TkCount) return 0
      return (this.tkStatisticsData.YaoyCount / this.tkStatisticsData.TkCount * 100)
    },
    getInviteStoreRate() {
      if (!this.tkStatisticsData || !this.tkStatisticsData.YaoyCount) return 0
      return (this.tkStatisticsData.DdCount / this.tkStatisticsData.YaoyCount * 100)
    },
    confirmFieldConfig() { this.showFieldConfigDialog = false },
    selectAllFields() { this.selectedFields = this.availableFields.map(f => f.prop) },
    unselectAllFields() { this.selectedFields = [] }
  }
}
</script>

<style lang="scss" scoped>
.leadership-cockpit {
  padding: 16px;
  background-color: #f5f7fa;
  min-height: 100vh;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  .cockpit-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
    background: #fff;
    padding: 12px 20px;
    border-radius: 8px;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);

    .page-title {
      margin: 0;
      font-size: 20px;
      color: #303133;
      font-weight: 600;

      .subtitle {
        font-size: 13px;
        color: #909399;
        font-weight: normal;
        margin-left: 12px;
      }
    }

    .search-form-compact {
      .el-form-item {
        margin-bottom: 0;
        margin-right: 15px;
      }

      .range-separator {
        margin: 0 8px;
        color: #DCDFE6;
      }
    }
  }

  /* KPI Cards */
  .kpi-row {
    margin-bottom: 16px;
  }

  .kpi-card {
    background: #fff;
    padding: 20px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    position: relative;
    overflow: hidden;
    height: 100px;
    box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.04);
    transition: transform 0.3s;

    &:hover {
      transform: translateY(-4px);
    }

    &.primary {
      border-left: 4px solid #409EFF;

      .kpi-icon {
        color: #409EFF;
        background: rgba(64, 158, 255, 0.1);
      }
    }

    &.success {
      border-left: 4px solid #67C23A;

      .kpi-icon {
        color: #67C23A;
        background: rgba(103, 194, 58, 0.1);
      }
    }

    &.warning {
      border-left: 4px solid #E6A23C;

      .kpi-icon {
        color: #E6A23C;
        background: rgba(230, 162, 60, 0.1);
      }
    }

    &.info {
      border-left: 4px solid #909399;

      .kpi-icon {
        color: #909399;
        background: rgba(144, 147, 153, 0.1);
      }
    }

    &.danger {
      border-left: 4px solid #F56C6C;

      .kpi-icon {
        color: #F56C6C;
        background: rgba(245, 108, 108, 0.1);
      }
    }

    &.error {
      border-left: 4px solid #f5222d;

      .kpi-icon {
        color: #f5222d;
        background: rgba(245, 34, 45, 0.1);
      }
    }

    .kpi-icon {
      width: 48px;
      height: 48px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 24px;
      margin-right: 15px;
    }

    .kpi-label {
      font-size: 13px;
      color: #909399;
      margin-bottom: 6px;
    }

    .kpi-value {
      font-size: 20px;
      font-weight: bold;
      color: #303133;

      .unit {
        font-size: 13px;
        margin: 0 2px;
      }
    }

    .kpi-trend {
      font-size: 11px;
      color: #c0c4cc;
      margin-top: 4px;

      i {
        color: #67C23A;
      }
    }
  }

  /* Dashboard Cards */
  .dashboard-card {
    border: none;
    border-radius: 8px;
    margin-bottom: 16px;

    &::v-deep .el-card__header {
      padding: 12px 20px;
      border-bottom: 1px solid #f0f2f5;
    }

    .card-title {
      font-size: 15px;
      font-weight: 600;
      color: #303133;

      i {
        color: #409EFF;
        margin-right: 8px;
      }
    }
  }

  .chart-box {
    height: 320px;
    width: 100%;
  }

  .chart-box-mini {
    height: 180px;
    width: 100%;
  }

  /* 会员统计区域样式 */
  .member-statistics-section {
    width: 100%;
    margin-right: 0px !important;
    margin-left: 0px !important;
  }

  /* 统一三个卡片的高度 */
  .member-overview-card,
  .member-type-card,
  .member-category-card {
    &::v-deep .el-card__body {
      height: 360px;
      padding: 16px;
      display: flex;
      flex-direction: column;
    }
  }

  .member-overview-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    flex: 1;
    width: 100%;
  }

  .member-stat-item {
    background: #f5f7fa;
    border-radius: 8px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    transition: all 0.3s ease;
    border: none;
    box-shadow: none;
    height: 160px;

    &:hover {
      box-shadow: 0 8px 20px rgba(31, 45, 61, 0.12);
      transform: translateY(-2px);
    }

    .stat-main {
      display: flex;
      align-items: flex-start;
      margin-bottom: 12px;
    }

    .stat-icon {
      width: 56px;
      height: 56px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 28px;
      margin-right: 14px;
      flex-shrink: 0;
    }

    &.stat-item-1 .stat-icon {
      background: rgba(64, 158, 255, 0.1);
      color: #409EFF;
    }

    &.stat-item-2 .stat-icon {
      background: rgba(103, 194, 58, 0.1);
      color: #67C23A;
    }

    &.stat-item-3 .stat-icon {
      background: rgba(230, 162, 60, 0.1);
      color: #E6A23C;
    }

    &.stat-item-4 .stat-icon {
      background: rgba(245, 108, 108, 0.1);
      color: #F56C6C;
    }

    .stat-content {
      flex: 1;
      min-width: 0;
      display: flex;
      flex-direction: column;
      justify-content: center;
    }

    .stat-label {
      font-size: 13px;
      color: #909399;
      font-weight: normal;
      margin-bottom: 6px;
    }

    .stat-value {
      font-size: 26px;
      font-weight: bold;
      color: #303133;
      line-height: 1.2;
    }

    .stat-tags {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 6px 8px;
      margin-top: 8px;
    }

    .stat-tag {
      display: block;
      background: #fff;
      border-radius: 12px;
      padding: 6px 10px;
      font-size: 12px;
      font-weight: 500;
      color: #303133;
      overflow: hidden;
    }

    .stat-tag-inner {
      display: inline-flex;
      align-items: center;
    }

    .stat-tag-text {
      display: inline-block;
      white-space: nowrap;
    }

    .stat-tag-inner.is-marquee {
      animation: stat-tag-marquee 8s linear infinite;
    }

    &.stat-item-1 .stat-tag-inner i {
      color: #409EFF;
    }

    &.stat-item-2 .stat-tag-inner i {
      color: #67C23A;
    }

    &.stat-item-3 .stat-tag-inner i {
      color: #E6A23C;
    }

    &.stat-item-4 .stat-tag-inner i {
      color: #f56c6c;
    }
  }

  @keyframes stat-tag-marquee {
    0% {
      transform: translateX(0);
    }

    100% {
      transform: translateX(-100%);
    }
  }

  /* 会员类型分布图表 */
  .member-type-chart {
    height: 100%;
    width: 100%;
    flex: 1;
    min-height: 0;
  }

  /* 会员分类统计 */
  .member-category-content {
    display: flex;
    align-items: center;
    gap: 12px;
    height: 100%;
    flex: 1;
    min-height: 0;
  }

  .member-category-chart {
    flex: 2;
    height: 100%;
    min-width: 0;
  }

  .member-category-legend {
    width: 140px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 12px;
    background: #f5f7fa;
    border-radius: 6px;
  }

  .legend-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px;
    background: white;
    border-radius: 4px;
    transition: all 0.3s ease;

    &:hover {
      background: #f0f2f5;
    }
  }

  .legend-color {
    width: 24px;
    height: 24px;
    border-radius: 4px;
    flex-shrink: 0;
  }

  .legend-text {
    flex: 1;

    .legend-name {
      font-size: 12px;
      font-weight: normal;
      color: #606266;
      margin-bottom: 2px;
    }

    .legend-value {
      font-size: 14px;
      font-weight: bold;
      color: #303133;
    }
  }

  /* 统一卡片高度 */
  .analysis-row {
    .dashboard-card {
      height: 400px;
      display: flex;
      flex-direction: column;

      &::v-deep .el-card__body {
        flex: 1;
        display: flex;
        flex-direction: column;
        overflow: hidden;
      }

      .chart-box {
        flex: 1;
        min-height: 0;
      }
    }

    .funnel-card {
      &::v-deep .el-card__body {
        padding-bottom: 50px;
      }
    }
  }

  .ranking-row {
    .dashboard-card {
      height: 540px;
      display: flex;
      flex-direction: column;

      &::v-deep .el-card__body {
        flex: 1;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        padding: 20px;
      }

      .rank-list {
        flex: 1;
        overflow-y: auto;
        max-height: 100%;
      }

      &::v-deep .el-table {
        flex: 1;
        overflow: hidden;
      }

      &::v-deep .el-table__body-wrapper {
        max-height: calc(100% - 40px);
        overflow-y: auto;
      }
    }
  }

  /* Rankings */
  .rank-list {
    .rank-item {
      display: flex;
      align-items: center;
      padding: 12px 0;
      border-bottom: 1px dotted #EBEEF5;

      &:last-child {
        border-bottom: none;
      }

      .rank-no {
        width: 20px;
        height: 20px;
        border-radius: 4px;
        background: #909399;
        color: #fff;
        font-size: 12px;
        display: flex;
        align-items: center;
        justify-content: center;
        margin-right: 12px;

        &.top1 {
          background: #F56C6C;
        }

        &.top2 {
          background: #E6A23C;
        }

        &.top3 {
          background: #409EFF;
        }
      }

      .rank-name {
        flex: 1;
        color: #606266;
        font-size: 14px;
      }

      .rank-val {
        font-weight: 600;
        color: #303133;
        font-size: 14px;
      }
    }
  }

  /* Funnel Stats */
  .funnel-stats {
    display: flex;
    justify-content: space-around;
    padding: 10px 0;

    .stat-mini {
      font-size: 12px;
      color: #909399;

      span {
        color: #303133;
        font-weight: 600;
        margin-left: 6px;
      }
    }
  }

  /* Item Rank */
  .item-rank {
    .item-rank-row {
      display: flex;
      align-items: center;
      margin-bottom: 12px;

      .item-index {
        font-weight: bold;
        color: #C0C4CC;
        margin-right: 10px;
        font-style: italic;
        flex-shrink: 0;
        width: 20px;
      }

      .item-name {
        display: inline-block;
        font-size: 13px;
        color: #606266;
        margin-right: 10px;
        flex-shrink: 0;
        min-width: 80px;
        max-width: 120px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      &::v-deep .el-progress {
        flex: 1;
        margin-right: 10px;
      }

      &::v-deep .el-progress-bar__outer {
        background-color: #F2F6FC;
      }

      .item-count {
        flex-shrink: 0;
        font-size: 13px;
        color: #606266;
        font-weight: 600;
        white-space: nowrap;
        min-width: 60px;
        text-align: right;
      }
    }
  }

  /* 科技感弹窗 */
  ::v-deep .tech-dialog {
    .el-dialog__header {
      background: linear-gradient(90deg, rgba(64, 158, 255, 0.18), rgba(103, 194, 58, 0.12));
      border-bottom: 1px solid rgba(64, 158, 255, 0.15);
    }

    .el-dialog__body {
      background: radial-gradient(circle at 20% 20%, rgba(64, 158, 255, 0.08), transparent 35%),
        radial-gradient(circle at 80% 20%, rgba(103, 194, 58, 0.08), transparent 35%),
        #0f172a;
      color: #e5eaf3;
      padding: 16px;
    }

    .el-dialog {
      box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
      border: 1px solid rgba(64, 158, 255, 0.25);
    }
  }

  .tech-dialog-controls {
    display: flex;
    gap: 8px;
    margin-bottom: 12px;

    .control-item {
      width: 180px;
    }
  }

  .tech-dialog-body {
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    padding: 12px;
    background: rgba(255, 255, 255, 0.03);
    overflow: auto;
  }

  .tech-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 12px;
  }

  .tech-card {
    border-radius: 12px;
    padding: 14px;
    color: #fff;
    position: relative;
    overflow: hidden;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
  }

  .neon-blue {
    background: linear-gradient(135deg, #1d4ed8, #0ea5e9);
  }

  .neon-green {
    background: linear-gradient(135deg, #15803d, #22c55e);
  }

  .neon-orange {
    background: linear-gradient(135deg, #c2410c, #f97316);
  }

  .tech-card-title {
    font-size: 13px;
    opacity: 0.9;
  }

  .tech-card-value {
    margin-top: 6px;
    font-size: 24px;
    font-weight: 700;
  }

  .tech-card-desc {
    margin-top: 4px;
    font-size: 12px;
    opacity: 0.8;
  }

  .tech-section {
    margin-top: 14px;
    border-radius: 12px;
    padding: 12px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.06);
  }

  .tech-section-title {
    display: flex;
    justify-content: space-between;
    color: #9ca3af;
    margin-bottom: 10px;

    .subtitle {
      font-size: 12px;
      opacity: 0.8;
    }
  }

  .tech-timeline {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .tech-timeline-item {
    display: grid;
    grid-template-columns: 16px 1fr 80px;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.05);
  }

  .tech-timeline-item .dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: #22c55e;
    box-shadow: 0 0 8px #22c55e;
    margin-left: 3px;
  }

  .tech-timeline-item .content .title {
    color: #e5e7eb;
    font-size: 13px;
    font-weight: 600;
  }

  .tech-timeline-item .content .desc {
    color: #9ca3af;
    font-size: 12px;
    margin-top: 2px;
  }

  .tech-timeline-item .time {
    text-align: right;
    color: #60a5fa;
    font-size: 12px;
  }
}
</style>