Commit e1f34014c8d0fee776b55bd7a8f9efe390614fae

Authored by “wangming”
1 parent fd5f9045

chore: update development environment configuration

- Swapped the VUE_APP_BASE_API value to point to localhost for local development.
- Commented out the previous test API URL for clarity.
antis-ncc-admin/.env.development
... ... @@ -2,8 +2,8 @@
2 2  
3 3 VUE_CLI_BABEL_TRANSPILE_MODULES = true
4 4 # VUE_APP_BASE_API = 'https://erp.lvqianmeiye.com'
5   -VUE_APP_BASE_API = 'http://erp_test.lvqianmeiye.com'
6   -# VUE_APP_BASE_API = 'http://localhost:2011'
  5 +# VUE_APP_BASE_API = 'http://erp_test.lvqianmeiye.com'
  6 +VUE_APP_BASE_API = 'http://localhost:2011'
7 7 # VUE_APP_BASE_API = 'http://localhost:2011'
8 8 VUE_APP_IMG_API = ''
9 9 VUE_APP_BASE_WSS = 'ws://192.168.110.45:2011/websocket'
... ...
antis-ncc-admin/src/views/extend/storeDashboard/index.vue 0 → 100644
  1 +<template>
  2 + <div class="store-dashboard">
  3 + <!-- 顶部:门店信息 + 核心指标 -->
  4 + <div class="dashboard-header">
  5 + <div class="header-left">
  6 + <div class="store-info">
  7 + <div class="store-avatar">
  8 + <i class="el-icon-office-building"></i>
  9 + </div>
  10 + <div class="store-details">
  11 + <div class="store-name-row">
  12 + <h2 class="store-name">示例门店名称</h2>
  13 + <el-tag type="success" size="small">正常营业</el-tag>
  14 + </div>
  15 + <div class="store-meta">
  16 + <span class="meta-item"><i class="el-icon-tickets"></i> MD2024001</span>
  17 + <span class="meta-item"><i class="el-icon-location"></i> 北京市朝阳区</span>
  18 + <span class="meta-item"><i class="el-icon-calendar"></i> 2024-01-15</span>
  19 + </div>
  20 + </div>
  21 + </div>
  22 + </div>
  23 + <div class="header-right">
  24 + <div class="core-stats">
  25 + <div class="core-stat-item primary">
  26 + <div class="stat-label">开单业绩</div>
  27 + <div class="stat-value">¥1,258,680</div>
  28 + <div class="stat-trend up">+12.5%</div>
  29 + </div>
  30 + <div class="core-stat-item success">
  31 + <div class="stat-label">消耗业绩</div>
  32 + <div class="stat-value">¥986,420</div>
  33 + <div class="stat-trend up">+8.3%</div>
  34 + </div>
  35 + <div class="core-stat-item info">
  36 + <div class="stat-label">完成率</div>
  37 + <div class="stat-value">85.6%</div>
  38 + <div class="stat-trend up">+2.1%</div>
  39 + </div>
  40 + <div class="core-stat-item warning">
  41 + <div class="stat-label">净业绩</div>
  42 + <div class="stat-value">¥272,260</div>
  43 + <div class="stat-trend up">+15.8%</div>
  44 + </div>
  45 + </div>
  46 + </div>
  47 + </div>
  48 +
  49 + <!-- 核心KPI指标 -->
  50 + <div class="kpi-section">
  51 + <div class="kpi-card" v-for="(kpi, index) in kpiList" :key="index" :class="kpi.type">
  52 + <div class="kpi-icon">
  53 + <i :class="kpi.icon"></i>
  54 + </div>
  55 + <div class="kpi-content">
  56 + <div class="kpi-label">{{ kpi.label }}</div>
  57 + <div class="kpi-value">
  58 + <span class="unit" v-if="kpi.isMoney">¥</span>{{ kpi.value }}
  59 + <span class="unit" v-if="kpi.isPercent">%</span>
  60 + </div>
  61 + </div>
  62 + <div class="kpi-trend" v-if="kpi.trend">
  63 + <i :class="kpi.trendIcon"></i>
  64 + <span>{{ kpi.trend }}</span>
  65 + </div>
  66 + </div>
  67 + </div>
  68 +
  69 + <!-- 主要内容区域:左右分栏 -->
  70 + <div class="main-content">
  71 + <!-- 左侧:图表区域 -->
  72 + <div class="content-left">
  73 + <!-- 第一行:业绩趋势图 + 品项分类占比 -->
  74 + <el-row :gutter="16" class="chart-row">
  75 + <el-col :span="16">
  76 + <el-card class="chart-card" shadow="hover">
  77 + <div slot="header" class="card-header">
  78 + <i class="el-icon-data-line"></i>
  79 + <span>近12个月业绩趋势</span>
  80 + </div>
  81 + <div ref="trendChart" class="chart-container"></div>
  82 + </el-card>
  83 + </el-col>
  84 + <el-col :span="8">
  85 + <el-card class="chart-card" shadow="hover">
  86 + <div slot="header" class="card-header">
  87 + <i class="el-icon-pie-chart"></i>
  88 + <span>品项分类占比</span>
  89 + </div>
  90 + <div ref="categoryChart" class="chart-container"></div>
  91 + </el-card>
  92 + </el-col>
  93 + </el-row>
  94 +
  95 + <!-- 第二行:每日运营数据趋势 + 门店综合能力雷达图 -->
  96 + <el-row :gutter="16" class="chart-row">
  97 + <el-col :span="16">
  98 + <el-card class="chart-card" shadow="hover">
  99 + <div slot="header" class="card-header">
  100 + <i class="el-icon-date"></i>
  101 + <span>每日运营数据趋势</span>
  102 + </div>
  103 + <div ref="dailyChart" class="chart-container"></div>
  104 + </el-card>
  105 + </el-col>
  106 + <el-col :span="8">
  107 + <el-card class="chart-card" shadow="hover">
  108 + <div slot="header" class="card-header">
  109 + <i class="el-icon-aim"></i>
  110 + <span>门店综合能力分析</span>
  111 + </div>
  112 + <div ref="radarChart" class="chart-container"></div>
  113 + </el-card>
  114 + </el-col>
  115 + </el-row>
  116 +
  117 + <!-- 第三行:业绩对比分析 + 各分类业绩堆叠对比 -->
  118 + <el-row :gutter="16" class="chart-row">
  119 + <el-col :span="12">
  120 + <el-card class="chart-card" shadow="hover">
  121 + <div slot="header" class="card-header">
  122 + <i class="el-icon-s-marketing"></i>
  123 + <span>业绩对比分析</span>
  124 + </div>
  125 + <div ref="compareChart" class="chart-container"></div>
  126 + </el-card>
  127 + </el-col>
  128 + <el-col :span="12">
  129 + <el-card class="chart-card" shadow="hover">
  130 + <div slot="header" class="card-header">
  131 + <i class="el-icon-s-data"></i>
  132 + <span>各分类业绩堆叠对比</span>
  133 + </div>
  134 + <div ref="stackedChart" class="chart-container"></div>
  135 + </el-card>
  136 + </el-col>
  137 + </el-row>
  138 +
  139 + <!-- 第四行:会员转化漏斗 + 客单价与项目数关系 -->
  140 + <el-row :gutter="16" class="chart-row">
  141 + <el-col :span="12">
  142 + <el-card class="chart-card" shadow="hover">
  143 + <div slot="header" class="card-header">
  144 + <i class="el-icon-sort"></i>
  145 + <span>会员转化漏斗</span>
  146 + </div>
  147 + <div ref="funnelChart" class="chart-container"></div>
  148 + </el-card>
  149 + </el-col>
  150 + <el-col :span="12">
  151 + <el-card class="chart-card" shadow="hover">
  152 + <div slot="header" class="card-header">
  153 + <i class="el-icon-s-marketing"></i>
  154 + <span>客单价与项目数关系分析</span>
  155 + </div>
  156 + <div ref="scatterChart" class="chart-container"></div>
  157 + </el-card>
  158 + </el-col>
  159 + </el-row>
  160 +
  161 + <!-- 第五行:一周运营热力图 -->
  162 + <el-row :gutter="16" class="chart-row">
  163 + <el-col :span="24">
  164 + <el-card class="chart-card" shadow="hover">
  165 + <div slot="header" class="card-header">
  166 + <i class="el-icon-s-grid"></i>
  167 + <span>一周运营热力图</span>
  168 + </div>
  169 + <div ref="heatmapChart" class="chart-container"></div>
  170 + </el-card>
  171 + </el-col>
  172 + </el-row>
  173 +
  174 + <!-- 第六行:品项开单排行 -->
  175 + <el-row :gutter="16" class="chart-row">
  176 + <el-col :span="24">
  177 + <el-card class="table-card" shadow="hover">
  178 + <div slot="header" class="card-header">
  179 + <i class="el-icon-shopping-bag-1"></i>
  180 + <span>品项开单排行(Top 10)</span>
  181 + </div>
  182 + <el-table :data="topBillingItems" size="small" border stripe>
  183 + <el-table-column type="index" label="排名" width="60" align="center">
  184 + <template slot-scope="scope">
  185 + <el-tag v-if="scope.$index < 3" :type="['danger', 'warning', 'success'][scope.$index]" size="mini">
  186 + {{ scope.$index + 1 }}
  187 + </el-tag>
  188 + <span v-else>{{ scope.$index + 1 }}</span>
  189 + </template>
  190 + </el-table-column>
  191 + <el-table-column prop="itemName" label="品项名称" min-width="180" />
  192 + <el-table-column prop="billingAmount" label="开单金额" width="140" align="right">
  193 + <template slot-scope="scope">
  194 + <span style="font-weight: 600; color: #67C23A;">¥{{ formatMoney(scope.row.billingAmount) }}</span>
  195 + </template>
  196 + </el-table-column>
  197 + <el-table-column prop="billingCount" label="开单次数" width="100" align="center" />
  198 + <el-table-column prop="category" label="分类" width="80" align="center">
  199 + <template slot-scope="scope">
  200 + <el-tag size="mini" :type="getCategoryType(scope.row.category)">{{ scope.row.category }}</el-tag>
  201 + </template>
  202 + </el-table-column>
  203 + </el-table>
  204 + </el-card>
  205 + </el-col>
  206 + </el-row>
  207 +
  208 + <!-- 第七行:健康师业绩排行 + 消耗品项排行 -->
  209 + <el-row :gutter="16" class="chart-row">
  210 + <el-col :span="12">
  211 + <el-card class="table-card" shadow="hover">
  212 + <div slot="header" class="card-header">
  213 + <i class="el-icon-user-solid"></i>
  214 + <span>健康师业绩排行(Top 10)</span>
  215 + </div>
  216 + <el-table :data="healthCoachRanking" size="small" border stripe>
  217 + <el-table-column type="index" label="排名" width="60" align="center" />
  218 + <el-table-column prop="name" label="健康师姓名" min-width="120" />
  219 + <el-table-column prop="billingPerformance" label="开单业绩" width="120" align="right">
  220 + <template slot-scope="scope">¥{{ formatMoney(scope.row.billingPerformance) }}</template>
  221 + </el-table-column>
  222 + <el-table-column prop="consumePerformance" label="消耗业绩" width="120" align="right">
  223 + <template slot-scope="scope">¥{{ formatMoney(scope.row.consumePerformance) }}</template>
  224 + </el-table-column>
  225 + <el-table-column prop="totalPerformance" label="总业绩" width="120" align="right">
  226 + <template slot-scope="scope">¥{{ formatMoney(scope.row.totalPerformance) }}</template>
  227 + </el-table-column>
  228 + </el-table>
  229 + </el-card>
  230 + </el-col>
  231 + <el-col :span="12">
  232 + <el-card class="table-card" shadow="hover">
  233 + <div slot="header" class="card-header">
  234 + <i class="el-icon-goods"></i>
  235 + <span>消耗品项排行(Top 10)</span>
  236 + </div>
  237 + <el-table :data="topConsumeItems" size="small" border stripe>
  238 + <el-table-column type="index" label="排名" width="60" align="center" />
  239 + <el-table-column prop="itemName" label="品项名称" min-width="150" />
  240 + <el-table-column prop="consumeAmount" label="消耗金额" width="120" align="right">
  241 + <template slot-scope="scope">
  242 + <span style="font-weight: 600; color: #409EFF;">¥{{ formatMoney(scope.row.consumeAmount) }}</span>
  243 + </template>
  244 + </el-table-column>
  245 + <el-table-column prop="category" label="分类" width="80" />
  246 + </el-table>
  247 + </el-card>
  248 + </el-col>
  249 + </el-row>
  250 + </div>
  251 +
  252 + <!-- 右侧:指标卡片区域 -->
  253 + <div class="content-right">
  254 + <!-- 业绩概览 -->
  255 + <el-card class="metrics-card" shadow="hover">
  256 + <div slot="header" class="card-header">
  257 + <i class="el-icon-data-line"></i>
  258 + <span>业绩概览</span>
  259 + </div>
  260 + <div class="metrics-grid">
  261 + <div class="metric-item" v-for="(item, index) in performanceList" :key="index">
  262 + <div class="metric-icon" :style="{ background: item.iconBg }">
  263 + <i :class="item.icon"></i>
  264 + </div>
  265 + <div class="metric-info">
  266 + <div class="metric-label">{{ item.label }}</div>
  267 + <div class="metric-value">{{ item.value }}</div>
  268 + </div>
  269 + </div>
  270 + </div>
  271 + </el-card>
  272 +
  273 + <!-- 运营指标 -->
  274 + <el-card class="metrics-card" shadow="hover">
  275 + <div slot="header" class="card-header">
  276 + <i class="el-icon-s-data"></i>
  277 + <span>运营指标</span>
  278 + </div>
  279 + <div class="metrics-grid">
  280 + <div class="metric-item" v-for="(item, index) in operationList" :key="index">
  281 + <div class="metric-icon" :style="{ background: item.iconBg }">
  282 + <i :class="item.icon"></i>
  283 + </div>
  284 + <div class="metric-info">
  285 + <div class="metric-label">{{ item.label }}</div>
  286 + <div class="metric-value">{{ item.value }}</div>
  287 + </div>
  288 + </div>
  289 + </div>
  290 + </el-card>
  291 +
  292 + <!-- 会员分析 -->
  293 + <el-card class="metrics-card" shadow="hover">
  294 + <div slot="header" class="card-header">
  295 + <i class="el-icon-user"></i>
  296 + <span>会员分析</span>
  297 + </div>
  298 + <div class="metrics-grid">
  299 + <div class="metric-item" v-for="(item, index) in memberList" :key="index">
  300 + <div class="metric-icon" :style="{ background: item.iconBg }">
  301 + <i :class="item.icon"></i>
  302 + </div>
  303 + <div class="metric-info">
  304 + <div class="metric-label">{{ item.label }}</div>
  305 + <div class="metric-value">{{ item.value }}</div>
  306 + <div class="metric-rate" v-if="item.rate">{{ item.rate }}</div>
  307 + </div>
  308 + </div>
  309 + </div>
  310 + </el-card>
  311 +
  312 + <!-- 目标完成度仪表盘 -->
  313 + <el-card class="chart-card-small" shadow="hover">
  314 + <div slot="header" class="card-header">
  315 + <i class="el-icon-odometer"></i>
  316 + <span>目标完成度</span>
  317 + </div>
  318 + <div ref="gaugeChart" class="chart-container-small"></div>
  319 + </el-card>
  320 +
  321 + <!-- 各分类业绩占比趋势 -->
  322 + <el-card class="chart-card-small" shadow="hover">
  323 + <div slot="header" class="card-header">
  324 + <i class="el-icon-data-line"></i>
  325 + <span>各分类占比趋势</span>
  326 + </div>
  327 + <div ref="stackedAreaChart" class="chart-container-small"></div>
  328 + </el-card>
  329 +
  330 + <!-- 门店排名对比 -->
  331 + <el-card class="metrics-card" shadow="hover">
  332 + <div slot="header" class="card-header">
  333 + <i class="el-icon-trophy"></i>
  334 + <span>门店排名对比</span>
  335 + </div>
  336 + <div class="ranking-content">
  337 + <div class="ranking-item">
  338 + <div class="ranking-label">业绩排名</div>
  339 + <div class="ranking-value">
  340 + <span class="rank-number">{{ comparison.performanceRanking }}</span>
  341 + <span class="rank-total">/ {{ comparison.totalStoreCount }}</span>
  342 + </div>
  343 + <div class="ranking-badge" :class="getRankingClass(comparison.performanceRanking, comparison.totalStoreCount)">
  344 + {{ getRankingText(comparison.performanceRanking, comparison.totalStoreCount) }}
  345 + </div>
  346 + </div>
  347 + <el-divider></el-divider>
  348 + <div class="comparison-stats">
  349 + <div class="stat-row">
  350 + <span class="stat-label">同类型门店平均业绩</span>
  351 + <span class="stat-value">¥{{ formatMoney(comparison.avgPerformanceSameType) }}</span>
  352 + </div>
  353 + <div class="stat-row">
  354 + <span class="stat-label">同类型门店数</span>
  355 + <span class="stat-value">{{ comparison.sameTypeStoreCount }}家</span>
  356 + </div>
  357 + <div class="stat-row">
  358 + <span class="stat-label">同组织门店平均业绩</span>
  359 + <span class="stat-value">¥{{ formatMoney(comparison.avgPerformanceSameOrg) }}</span>
  360 + </div>
  361 + <div class="stat-row">
  362 + <span class="stat-label">同组织门店数</span>
  363 + <span class="stat-value">{{ comparison.sameOrgStoreCount }}家</span>
  364 + </div>
  365 + </div>
  366 + </div>
  367 + </el-card>
  368 +
  369 + <!-- 本月经营提示 -->
  370 + <el-card class="tips-card" shadow="hover">
  371 + <div slot="header" class="card-header">
  372 + <i class="el-icon-warning"></i>
  373 + <span>本月经营提示</span>
  374 + </div>
  375 + <div class="tips-content">
  376 + <div class="tip-item" v-for="(tip, index) in operationTips" :key="index" :class="tip.type">
  377 + <i :class="tip.icon"></i>
  378 + <span>{{ tip.text }}</span>
  379 + </div>
  380 + </div>
  381 + </el-card>
  382 +
  383 + <!-- 快速数据洞察 -->
  384 + <el-card class="insight-card" shadow="hover">
  385 + <div slot="header" class="card-header">
  386 + <i class="el-icon-data-analysis"></i>
  387 + <span>快速数据洞察</span>
  388 + </div>
  389 + <div class="insight-content">
  390 + <div class="insight-item" v-for="(insight, index) in dataInsights" :key="index">
  391 + <div class="insight-header">
  392 + <span class="insight-title">{{ insight.title }}</span>
  393 + <el-tag :type="insight.tagType" size="mini">{{ insight.tag }}</el-tag>
  394 + </div>
  395 + <div class="insight-value">{{ insight.value }}</div>
  396 + <div class="insight-desc">{{ insight.desc }}</div>
  397 + </div>
  398 + </div>
  399 + </el-card>
  400 +
  401 + <!-- 本月关键指标 -->
  402 + <el-card class="key-metrics-card" shadow="hover">
  403 + <div slot="header" class="card-header">
  404 + <i class="el-icon-s-flag"></i>
  405 + <span>本月关键指标</span>
  406 + </div>
  407 + <div class="key-metrics-content">
  408 + <div class="progress-item" v-for="(metric, index) in keyMetrics" :key="index">
  409 + <div class="progress-header">
  410 + <span class="progress-label">{{ metric.label }}</span>
  411 + <span class="progress-value">{{ metric.value }}%</span>
  412 + </div>
  413 + <el-progress :percentage="metric.value" :color="metric.color" :stroke-width="8"></el-progress>
  414 + </div>
  415 + </div>
  416 + </el-card>
  417 + </div>
  418 + </div>
  419 +
  420 + <!-- 表格区域 -->
  421 + <div class="table-section">
  422 +
  423 + </div>
  424 + </div>
  425 +</template>
  426 +
  427 +<script>
  428 +import * as echarts from 'echarts'
  429 +
  430 +export default {
  431 + name: 'StoreDashboard',
  432 + data() {
  433 + return {
  434 + kpiList: [
  435 + { label: '开单次数', value: '1,256', icon: 'el-icon-s-order', type: 'primary', trend: '+5.2%', trendIcon: 'el-icon-top' },
  436 + { label: '消耗次数', value: '2,458', icon: 'el-icon-s-marketing', type: 'success', trend: '+3.7%', trendIcon: 'el-icon-top' },
  437 + { label: '人头数', value: '1,258', icon: 'el-icon-user', type: 'info', trend: '+4.1%', trendIcon: 'el-icon-top' },
  438 + { label: '人次', value: '3,456', icon: 'el-icon-user-solid', type: 'warning', trend: '+6.2%', trendIcon: 'el-icon-top' },
  439 + { label: '项目数', value: '5,678', icon: 'el-icon-menu', type: 'primary', trend: '+3.5%', trendIcon: 'el-icon-top' },
  440 + { label: '客单价', value: '¥285', icon: 'el-icon-coin', type: 'success', isMoney: true, trend: '+2.8%', trendIcon: 'el-icon-top' }
  441 + ],
  442 + performanceList: [
  443 + { label: '开单次数', value: '1,256', icon: 'el-icon-document', iconBg: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
  444 + { label: '消耗次数', value: '2,458', icon: 'el-icon-goods', iconBg: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)' },
  445 + { label: '退卡次数', value: '23', icon: 'el-icon-refresh-left', iconBg: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)' },
  446 + { label: '平均开单金额', value: '¥1,002', icon: 'el-icon-coin', iconBg: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)' },
  447 + { label: '平均消耗金额', value: '¥401', icon: 'el-icon-coin', iconBg: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)' },
  448 + { label: '剩余权益', value: '¥325.69万', icon: 'el-icon-wallet', iconBg: 'linear-gradient(135deg, #30cfd0 0%, #330867 100%)' },
  449 + { label: '目标业绩', value: '¥120万', icon: 'el-icon-aim', iconBg: 'linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)' },
  450 + { label: '退卡金额', value: '¥4.57万', icon: 'el-icon-money', iconBg: 'linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%)' }
  451 + ],
  452 + operationList: [
  453 + { label: '人头数', value: '1,258', icon: 'el-icon-user', iconBg: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
  454 + { label: '人次', value: '3,456', icon: 'el-icon-user-solid', iconBg: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)' },
  455 + { label: '项目数', value: '5,678', icon: 'el-icon-menu', iconBg: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)' },
  456 + { label: '客单价', value: '¥285', icon: 'el-icon-coin', iconBg: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)' },
  457 + { label: '项目单价', value: '¥174', icon: 'el-icon-coin', iconBg: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)' },
  458 + { label: '人均项目数', value: '4.51', icon: 'el-icon-s-grid', iconBg: 'linear-gradient(135deg, #30cfd0 0%, #330867 100%)' }
  459 + ],
  460 + memberList: [
  461 + { label: '总会员数', value: '3,256', icon: 'el-icon-user', iconBg: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
  462 + { label: '本月新增', value: '156', icon: 'el-icon-user-solid', iconBg: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)' },
  463 + { label: '活跃会员', value: '1,856', icon: 'el-icon-success', iconBg: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)', rate: '57.0%' },
  464 + { label: '沉睡会员', value: '856', icon: 'el-icon-warning', iconBg: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)', rate: '26.3%' },
  465 + { label: '生美会员', value: '2,156', icon: 'el-icon-star-on', iconBg: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)' },
  466 + { label: '医美会员', value: '856', icon: 'el-icon-star-on', iconBg: 'linear-gradient(135deg, #30cfd0 0%, #330867 100%)' },
  467 + { label: '科美会员', value: '456', icon: 'el-icon-star-on', iconBg: 'linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)' },
  468 + { label: '教育会员', value: '256', icon: 'el-icon-star-on', iconBg: 'linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%)' }
  469 + ],
  470 + healthCoachRanking: [
  471 + { name: '张健康', billingPerformance: 256800, consumePerformance: 198600, totalPerformance: 455400 },
  472 + { name: '李美丽', billingPerformance: 198600, consumePerformance: 156800, totalPerformance: 355400 },
  473 + { name: '王优雅', billingPerformance: 186500, consumePerformance: 145600, totalPerformance: 332100 },
  474 + { name: '刘青春', billingPerformance: 165800, consumePerformance: 128900, totalPerformance: 294700 },
  475 + { name: '陈优雅', billingPerformance: 145600, consumePerformance: 112500, totalPerformance: 258100 },
  476 + { name: '杨美丽', billingPerformance: 128900, consumePerformance: 98600, totalPerformance: 227500 },
  477 + { name: '赵健康', billingPerformance: 112500, consumePerformance: 85600, totalPerformance: 198100 },
  478 + { name: '钱优雅', billingPerformance: 98600, consumePerformance: 75600, totalPerformance: 174200 },
  479 + { name: '孙美丽', billingPerformance: 85600, consumePerformance: 65800, totalPerformance: 151400 },
  480 + { name: '周健康', billingPerformance: 75600, consumePerformance: 56800, totalPerformance: 132400 }
  481 + ],
  482 + topBillingItems: [
  483 + { itemName: '高端护理套餐', billingAmount: 156800, billingCount: 45, category: '生美' },
  484 + { itemName: '医美美容项目', billingAmount: 128600, billingCount: 38, category: '医美' },
  485 + { itemName: 'SPA身体护理', billingAmount: 98500, billingCount: 52, category: '生美' },
  486 + { itemName: '激光美容疗程', billingAmount: 89600, billingCount: 28, category: '医美' },
  487 + { itemName: '皮肤管理项目', billingAmount: 75800, billingCount: 42, category: '科美' },
  488 + { itemName: '面部深度护理', billingAmount: 68900, billingCount: 56, category: '生美' },
  489 + { itemName: '抗衰美容项目', billingAmount: 58600, billingCount: 22, category: '医美' },
  490 + { itemName: '美白亮肤疗程', billingAmount: 48900, billingCount: 35, category: '科美' },
  491 + { itemName: '眼部精华护理', billingAmount: 42800, billingCount: 48, category: '生美' },
  492 + { itemName: '补水保湿项目', billingAmount: 38600, billingCount: 62, category: '生美' }
  493 + ],
  494 + topConsumeItems: [
  495 + { itemName: '面部护理套餐', consumeAmount: 125680, category: '生美' },
  496 + { itemName: '身体SPA护理', consumeAmount: 98600, category: '生美' },
  497 + { itemName: '激光美容项目', consumeAmount: 85600, category: '医美' },
  498 + { itemName: '抗衰老治疗', consumeAmount: 75600, category: '医美' },
  499 + { itemName: '皮肤管理项目', consumeAmount: 65800, category: '科美' },
  500 + { itemName: '眼部护理', consumeAmount: 56800, category: '生美' },
  501 + { itemName: '紧致提升项目', consumeAmount: 45600, category: '医美' },
  502 + { itemName: '美白亮肤项目', consumeAmount: 38900, category: '科美' },
  503 + { itemName: '深层清洁护理', consumeAmount: 32800, category: '生美' },
  504 + { itemName: '补水保湿项目', consumeAmount: 28900, category: '生美' }
  505 + ],
  506 + dailyData: [
  507 + { date: '2024-12-01', headCount: 45, personCount: 128, projectCount: 256, billingPerformance: 45680, consumePerformance: 32890 },
  508 + { date: '2024-12-02', headCount: 52, personCount: 145, projectCount: 289, billingPerformance: 52890, consumePerformance: 38960 },
  509 + { date: '2024-12-03', headCount: 48, personCount: 132, projectCount: 268, billingPerformance: 48960, consumePerformance: 35280 },
  510 + { date: '2024-12-04', headCount: 56, personCount: 156, projectCount: 312, billingPerformance: 56890, consumePerformance: 41250 },
  511 + { date: '2024-12-05', headCount: 49, personCount: 138, projectCount: 278, billingPerformance: 49860, consumePerformance: 36580 },
  512 + { date: '2024-12-06', headCount: 58, personCount: 162, projectCount: 325, billingPerformance: 59860, consumePerformance: 43280 },
  513 + { date: '2024-12-07', headCount: 62, personCount: 178, projectCount: 356, billingPerformance: 62890, consumePerformance: 45680 },
  514 + { date: '2024-12-08', headCount: 55, personCount: 152, projectCount: 304, billingPerformance: 55860, consumePerformance: 40250 },
  515 + { date: '2024-12-09', headCount: 51, personCount: 142, projectCount: 284, billingPerformance: 51860, consumePerformance: 37580 },
  516 + { date: '2024-12-10', headCount: 59, personCount: 165, projectCount: 330, billingPerformance: 59860, consumePerformance: 43280 }
  517 + ],
  518 + trendChart: null,
  519 + categoryChart: null,
  520 + dailyChart: null,
  521 + compareChart: null,
  522 + stackedChart: null,
  523 + funnelChart: null,
  524 + scatterChart: null,
  525 + heatmapChart: null,
  526 + radarChart: null,
  527 + gaugeChart: null,
  528 + stackedAreaChart: null,
  529 + comparison: {
  530 + performanceRanking: 5,
  531 + totalStoreCount: 28,
  532 + avgPerformanceSameType: 1156800,
  533 + sameTypeStoreCount: 12,
  534 + avgPerformanceSameOrg: 1089600,
  535 + sameOrgStoreCount: 8
  536 + },
  537 + operationTips: [
  538 + { type: 'success', icon: 'el-icon-success', text: '本月业绩完成度良好,保持当前节奏' },
  539 + { type: 'warning', icon: 'el-icon-warning', text: '沉睡会员占比26.3%,建议加强会员唤醒' },
  540 + { type: 'info', icon: 'el-icon-info', text: '客单价¥285,可通过项目组合提升' },
  541 + { type: 'warning', icon: 'el-icon-warning', text: '退卡金额较上月增长,需关注服务质量' }
  542 + ],
  543 + dataInsights: [
  544 + { title: '最佳营业时段', tag: '热门', tagType: 'danger', value: '14:00-17:00', desc: '此时段客流量最高,建议配置更多人手' },
  545 + { title: '高价值会员', tag: '重点', tagType: 'warning', value: '156人', desc: '单次消费超过¥1000,需重点维护' },
  546 + { title: '项目转化率', tag: '优秀', tagType: 'success', value: '68.5%', desc: '体验项目转化为正式开卡的比例' },
  547 + { title: '复购周期', tag: '正常', tagType: 'info', value: '28天', desc: '会员平均复购间隔,保持稳定' }
  548 + ],
  549 + keyMetrics: [
  550 + { label: '目标完成度', value: 85.6, color: '#67C23A' },
  551 + { label: '会员活跃度', value: 57.0, color: '#409EFF' },
  552 + { label: '项目满意度', value: 92.3, color: '#E6A23C' },
  553 + { label: '员工效率', value: 78.5, color: '#F56C6C' }
  554 + ]
  555 + }
  556 + },
  557 + mounted() {
  558 + this.initCharts()
  559 + window.addEventListener('resize', this.handleResize)
  560 + },
  561 + beforeDestroy() {
  562 + if (this.trendChart) this.trendChart.dispose()
  563 + if (this.categoryChart) this.categoryChart.dispose()
  564 + if (this.dailyChart) this.dailyChart.dispose()
  565 + if (this.compareChart) this.compareChart.dispose()
  566 + if (this.stackedChart) this.stackedChart.dispose()
  567 + if (this.funnelChart) this.funnelChart.dispose()
  568 + if (this.scatterChart) this.scatterChart.dispose()
  569 + if (this.heatmapChart) this.heatmapChart.dispose()
  570 + if (this.radarChart) this.radarChart.dispose()
  571 + if (this.gaugeChart) this.gaugeChart.dispose()
  572 + if (this.stackedAreaChart) this.stackedAreaChart.dispose()
  573 + window.removeEventListener('resize', this.handleResize)
  574 + },
  575 + methods: {
  576 + initCharts() {
  577 + this.$nextTick(() => {
  578 + this.renderTrendChart()
  579 + this.renderCategoryChart()
  580 + this.renderDailyChart()
  581 + this.renderCompareChart()
  582 + this.renderStackedChart()
  583 + this.renderFunnelChart()
  584 + this.renderScatterChart()
  585 + this.renderHeatmapChart()
  586 + this.renderRadarChart()
  587 + this.renderGaugeChart()
  588 + this.renderStackedAreaChart()
  589 + })
  590 + },
  591 + renderTrendChart() {
  592 + if (!this.$refs.trendChart) return
  593 + this.trendChart = echarts.init(this.$refs.trendChart)
  594 + const option = {
  595 + tooltip: { trigger: 'axis', axisPointer: { type: 'cross' } },
  596 + legend: { data: ['开单业绩', '消耗业绩', '净业绩'], top: 10 },
  597 + grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true },
  598 + xAxis: { type: 'category', data: ['2024-01', '2024-02', '2024-03', '2024-04', '2024-05', '2024-06', '2024-07', '2024-08', '2024-09', '2024-10', '2024-11', '2024-12'] },
  599 + yAxis: { type: 'value', axisLabel: { formatter: '¥{value}' } },
  600 + series: [
  601 + { name: '开单业绩', type: 'line', smooth: true, data: [856000, 928000, 1025000, 1156000, 1089000, 1125000, 1186000, 1258000, 1156000, 1289000, 1356000, 1258680], itemStyle: { color: '#409EFF' }, areaStyle: { color: 'rgba(64, 158, 255, 0.1)' } },
  602 + { name: '消耗业绩', type: 'line', smooth: true, data: [658000, 712000, 786000, 856000, 798000, 825000, 868000, 912000, 856000, 936000, 986000, 986420], itemStyle: { color: '#67C23A' }, areaStyle: { color: 'rgba(103, 194, 58, 0.1)' } },
  603 + { name: '净业绩', type: 'line', smooth: true, data: [198000, 216000, 239000, 300000, 291000, 300000, 318000, 346000, 300000, 353000, 370000, 272260], itemStyle: { color: '#E6A23C' }, areaStyle: { color: 'rgba(230, 162, 60, 0.1)' } }
  604 + ]
  605 + }
  606 + this.trendChart.setOption(option)
  607 + },
  608 + renderCategoryChart() {
  609 + if (!this.$refs.categoryChart) return
  610 + this.categoryChart = echarts.init(this.$refs.categoryChart)
  611 + const option = {
  612 + tooltip: { trigger: 'item' },
  613 + legend: { show: false },
  614 + series: [{
  615 + name: '品项分类',
  616 + type: 'pie',
  617 + radius: ['40%', '70%'],
  618 + center: ['50%', '50%'],
  619 + avoidLabelOverlap: true,
  620 + itemStyle: { borderRadius: 6, borderColor: '#fff', borderWidth: 2 },
  621 + label: { show: true, position: 'outside', formatter: '{b}\n{c}', fontSize: 12 },
  622 + labelLine: { show: true, length: 15, length2: 10 },
  623 + data: [
  624 + { value: 456800, name: '生美', itemStyle: { color: '#A8D5E2' } },
  625 + { value: 256800, name: '医美', itemStyle: { color: '#B8E6B8' } },
  626 + { value: 198600, name: '科美', itemStyle: { color: '#FFD4A3' } },
  627 + { value: 74220, name: '产品', itemStyle: { color: '#E6C1E6' } }
  628 + ]
  629 + }]
  630 + }
  631 + this.categoryChart.setOption(option)
  632 + },
  633 + renderDailyChart() {
  634 + if (!this.$refs.dailyChart) return
  635 + this.dailyChart = echarts.init(this.$refs.dailyChart)
  636 + const option = {
  637 + tooltip: { trigger: 'axis', axisPointer: { type: 'cross' } },
  638 + legend: { data: ['开单业绩', '消耗业绩', '人头数', '人次', '项目数'], top: 10 },
  639 + grid: { left: '60px', right: '80px', top: '50px', bottom: '60px', containLabel: false },
  640 + xAxis: { type: 'category', data: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30'], axisLabel: { rotate: 45, interval: 2, fontSize: 11 } },
  641 + yAxis: [
  642 + { type: 'value', name: '业绩', position: 'left', axisLabel: { formatter: value => value >= 10000 ? '¥' + (value / 10000).toFixed(1) + '万' : '¥' + value }, splitLine: { lineStyle: { type: 'dashed', color: '#E4E7ED' } } },
  643 + { type: 'value', name: '数量', position: 'right', splitLine: { show: false } }
  644 + ],
  645 + series: [
  646 + { name: '开单业绩', type: 'bar', yAxisIndex: 0, data: [45680, 52890, 48960, 56890, 49860, 59860, 62890, 55860, 51860, 59860, 52890, 48960, 56890, 49860, 59860, 62890, 55860, 51860, 59860, 52890, 48960, 56890, 49860, 59860, 62890, 55860, 51860, 59860, 52890, 48960], itemStyle: { color: '#409EFF' }, barWidth: '30%' },
  647 + { name: '消耗业绩', type: 'bar', yAxisIndex: 0, data: [32890, 38960, 35280, 41250, 36580, 43280, 45680, 40250, 37580, 43280, 38960, 35280, 41250, 36580, 43280, 45680, 40250, 37580, 43280, 38960, 35280, 41250, 36580, 43280, 45680, 40250, 37580, 43280, 38960, 35280], itemStyle: { color: '#67C23A' }, barWidth: '30%' },
  648 + { name: '人头数', type: 'line', yAxisIndex: 1, data: [45, 52, 48, 56, 49, 58, 62, 55, 51, 59, 52, 48, 56, 49, 58, 62, 55, 51, 59, 52, 48, 56, 49, 58, 62, 55, 51, 59, 52, 48], itemStyle: { color: '#F56C6C' }, lineStyle: { width: 2 }, symbol: 'circle', symbolSize: 6 },
  649 + { name: '人次', type: 'line', yAxisIndex: 1, data: [128, 145, 132, 156, 138, 162, 178, 152, 142, 165, 145, 132, 156, 138, 162, 178, 152, 142, 165, 145, 132, 156, 138, 162, 178, 152, 142, 165, 145, 132], itemStyle: { color: '#E6A23C' }, lineStyle: { width: 2 }, symbol: 'circle', symbolSize: 6 },
  650 + { name: '项目数', type: 'line', yAxisIndex: 1, data: [256, 289, 268, 312, 278, 325, 356, 304, 284, 330, 289, 268, 312, 278, 325, 356, 304, 284, 330, 289, 268, 312, 278, 325, 356, 304, 284, 330, 289, 268], itemStyle: { color: '#909399' }, lineStyle: { width: 2 }, symbol: 'circle', symbolSize: 6 }
  651 + ]
  652 + }
  653 + this.dailyChart.setOption(option)
  654 + },
  655 + renderCompareChart() {
  656 + if (!this.$refs.compareChart) return
  657 + this.compareChart = echarts.init(this.$refs.compareChart)
  658 + const option = {
  659 + tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
  660 + legend: { data: ['开单业绩', '消耗业绩'], top: 10 },
  661 + grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true },
  662 + xAxis: { type: 'category', data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'] },
  663 + yAxis: { type: 'value', axisLabel: { formatter: value => value >= 10000 ? (value / 10000).toFixed(1) + '万' : value } },
  664 + series: [
  665 + { name: '开单业绩', type: 'bar', data: [856, 928, 1025, 1156, 1089, 1125, 1186, 1258, 1156, 1289, 1356, 1258], itemStyle: { color: '#409EFF' } },
  666 + { name: '消耗业绩', type: 'bar', data: [658, 712, 786, 856, 798, 825, 868, 912, 856, 936, 986, 986], itemStyle: { color: '#67C23A' } }
  667 + ]
  668 + }
  669 + this.compareChart.setOption(option)
  670 + },
  671 + renderStackedChart() {
  672 + if (!this.$refs.stackedChart) return
  673 + this.stackedChart = echarts.init(this.$refs.stackedChart)
  674 + const option = {
  675 + tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
  676 + legend: { data: ['生美', '医美', '科美', '产品'], top: 10 },
  677 + grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true },
  678 + xAxis: { type: 'category', data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'] },
  679 + yAxis: { type: 'value', axisLabel: { formatter: value => value >= 10000 ? (value / 10000).toFixed(1) + '万' : value } },
  680 + series: [
  681 + { name: '生美', type: 'bar', stack: 'total', data: [320, 350, 380, 420, 390, 410, 450, 480, 420, 460, 500, 480], itemStyle: { color: '#A8D5E2' } },
  682 + { name: '医美', type: 'bar', stack: 'total', data: [180, 200, 220, 250, 230, 240, 260, 280, 250, 270, 290, 280], itemStyle: { color: '#B8E6B8' } },
  683 + { name: '科美', type: 'bar', stack: 'total', data: [140, 150, 160, 180, 170, 175, 190, 200, 180, 195, 210, 200], itemStyle: { color: '#FFD4A3' } },
  684 + { name: '产品', type: 'bar', stack: 'total', data: [50, 55, 60, 70, 65, 68, 75, 80, 70, 78, 85, 80], itemStyle: { color: '#E6C1E6' } }
  685 + ]
  686 + }
  687 + this.stackedChart.setOption(option)
  688 + },
  689 + renderFunnelChart() {
  690 + if (!this.$refs.funnelChart) return
  691 + this.funnelChart = echarts.init(this.$refs.funnelChart)
  692 + const option = {
  693 + tooltip: { trigger: 'item', formatter: '{a} <br/>{b}: {c} ({d}%)' },
  694 + legend: { data: ['访问', '咨询', '到店', '体验', '开单', '复购'], top: 10 },
  695 + series: [{
  696 + name: '会员转化',
  697 + type: 'funnel',
  698 + left: '10%',
  699 + top: 60,
  700 + bottom: 60,
  701 + width: '80%',
  702 + min: 0,
  703 + max: 10000,
  704 + minSize: '0%',
  705 + maxSize: '100%',
  706 + sort: 'descending',
  707 + gap: 2,
  708 + label: { show: true, position: 'inside', formatter: '{b}: {c}' },
  709 + labelLine: { length: 10, lineStyle: { width: 1, type: 'solid' } },
  710 + itemStyle: { borderColor: '#fff', borderWidth: 1 },
  711 + emphasis: { label: { fontSize: 20 } },
  712 + data: [
  713 + { value: 10000, name: '访问', itemStyle: { color: '#409EFF' } },
  714 + { value: 8000, name: '咨询', itemStyle: { color: '#67C23A' } },
  715 + { value: 6000, name: '到店', itemStyle: { color: '#E6A23C' } },
  716 + { value: 4000, name: '体验', itemStyle: { color: '#F56C6C' } },
  717 + { value: 2000, name: '开单', itemStyle: { color: '#909399' } },
  718 + { value: 1500, name: '复购', itemStyle: { color: '#606266' } }
  719 + ]
  720 + }]
  721 + }
  722 + this.funnelChart.setOption(option)
  723 + },
  724 + renderScatterChart() {
  725 + if (!this.$refs.scatterChart) return
  726 + this.scatterChart = echarts.init(this.$refs.scatterChart)
  727 + const option = {
  728 + tooltip: { trigger: 'item', formatter: '客单价: {c[0]}<br/>项目数: {c[1]}<br/>会员数: {c[2]}' },
  729 + legend: { data: ['会员分布'], top: 10 },
  730 + grid: { left: '3%', right: '7%', bottom: '3%', top: '15%', containLabel: true },
  731 + xAxis: { type: 'value', name: '客单价(元)', nameLocation: 'middle', nameGap: 30 },
  732 + yAxis: { type: 'value', name: '项目数', nameLocation: 'middle', nameGap: 50 },
  733 + series: [{
  734 + name: '会员分布',
  735 + type: 'scatter',
  736 + symbolSize: data => Math.sqrt(data[2]) * 2,
  737 + data: [
  738 + [285, 4.5, 320], [320, 5.2, 280], [250, 3.8, 350], [380, 6.5, 180], [290, 4.8, 300],
  739 + [350, 5.8, 220], [280, 4.2, 310], [420, 7.2, 150], [310, 5.0, 260], [360, 6.0, 200],
  740 + [270, 4.0, 330], [390, 6.8, 170], [300, 4.9, 290], [370, 6.2, 210], [260, 3.9, 340]
  741 + ],
  742 + itemStyle: { color: '#409EFF', opacity: 0.6 }
  743 + }]
  744 + }
  745 + this.scatterChart.setOption(option)
  746 + },
  747 + renderHeatmapChart() {
  748 + if (!this.$refs.heatmapChart) return
  749 + this.heatmapChart = echarts.init(this.$refs.heatmapChart)
  750 + const hours = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
  751 + const times = ['09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00', '21:00']
  752 + const data = []
  753 + for (let i = 0; i < hours.length; i++) {
  754 + for (let j = 0; j < times.length; j++) {
  755 + const value = Math.floor(Math.random() * 100)
  756 + data.push([j, i, value])
  757 + }
  758 + }
  759 + const option = {
  760 + tooltip: { position: 'top', formatter: params => `${hours[params.value[1]]} ${times[params.value[0]]}<br/>客流量: ${params.value[2]}` },
  761 + grid: { height: '50%', top: '10%' },
  762 + xAxis: { type: 'category', data: times, splitArea: { show: true }, position: 'top' },
  763 + yAxis: { type: 'category', data: hours, splitArea: { show: true } },
  764 + visualMap: {
  765 + min: 0,
  766 + max: 100,
  767 + calculable: true,
  768 + orient: 'horizontal',
  769 + left: 'center',
  770 + bottom: '5%',
  771 + inRange: { color: ['#e0f3ff', '#409EFF', '#1d4ed8'] }
  772 + },
  773 + series: [{
  774 + name: '客流量',
  775 + type: 'heatmap',
  776 + data: data,
  777 + label: { show: true },
  778 + emphasis: { itemStyle: { shadowBlur: 10, shadowColor: 'rgba(0, 0, 0, 0.5)' } }
  779 + }]
  780 + }
  781 + this.heatmapChart.setOption(option)
  782 + },
  783 + renderRadarChart() {
  784 + if (!this.$refs.radarChart) return
  785 + this.radarChart = echarts.init(this.$refs.radarChart)
  786 + const option = {
  787 + tooltip: {},
  788 + radar: {
  789 + indicator: [
  790 + { name: '业绩能力', max: 100 },
  791 + { name: '服务能力', max: 100 },
  792 + { name: '会员管理', max: 100 },
  793 + { name: '运营效率', max: 100 },
  794 + { name: '团队协作', max: 100 },
  795 + { name: '客户满意度', max: 100 }
  796 + ],
  797 + center: ['50%', '55%'],
  798 + radius: '70%'
  799 + },
  800 + series: [{
  801 + name: '门店综合能力',
  802 + type: 'radar',
  803 + data: [{
  804 + value: [85, 78, 82, 75, 80, 88],
  805 + name: '当前门店',
  806 + areaStyle: { color: 'rgba(64, 158, 255, 0.3)' },
  807 + itemStyle: { color: '#409EFF' },
  808 + lineStyle: { color: '#409EFF', width: 2 }
  809 + }, {
  810 + value: [75, 72, 70, 68, 75, 80],
  811 + name: '行业平均',
  812 + areaStyle: { color: 'rgba(103, 194, 58, 0.2)' },
  813 + itemStyle: { color: '#67C23A' },
  814 + lineStyle: { color: '#67C23A', width: 2, type: 'dashed' }
  815 + }]
  816 + }]
  817 + }
  818 + this.radarChart.setOption(option)
  819 + },
  820 + renderGaugeChart() {
  821 + if (!this.$refs.gaugeChart) return
  822 + this.gaugeChart = echarts.init(this.$refs.gaugeChart)
  823 + const option = {
  824 + tooltip: { formatter: '{a} <br/>{b}: {c}%' },
  825 + series: [{
  826 + name: '目标完成度',
  827 + type: 'gauge',
  828 + progress: { show: true },
  829 + detail: { valueAnimation: true, formatter: '{value}%', fontSize: 20, offsetCenter: [0, '70%'] },
  830 + data: [{ value: 85.6, name: '完成率' }],
  831 + axisLine: {
  832 + lineStyle: {
  833 + width: 20,
  834 + color: [[0.3, '#67C23A'], [0.7, '#E6A23C'], [1, '#F56C6C']]
  835 + }
  836 + },
  837 + axisTick: { show: false },
  838 + splitLine: { show: false },
  839 + axisLabel: { show: false },
  840 + pointer: { show: false },
  841 + title: { show: false }
  842 + }]
  843 + }
  844 + this.gaugeChart.setOption(option)
  845 + },
  846 + renderStackedAreaChart() {
  847 + if (!this.$refs.stackedAreaChart) return
  848 + this.stackedAreaChart = echarts.init(this.$refs.stackedAreaChart)
  849 + const option = {
  850 + tooltip: { trigger: 'axis', axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } } },
  851 + legend: { data: ['生美', '医美', '科美', '产品'], top: 10 },
  852 + grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true },
  853 + xAxis: [{ type: 'category', boundaryGap: false, data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'] }],
  854 + yAxis: [{ type: 'value', axisLabel: { formatter: '{value}%' } }],
  855 + series: [
  856 + { name: '生美', type: 'line', stack: 'Total', areaStyle: {}, emphasis: { focus: 'series' }, data: [45, 48, 50, 52, 49, 51, 53, 55, 52, 54, 56, 54], itemStyle: { color: '#A8D5E2' } },
  857 + { name: '医美', type: 'line', stack: 'Total', areaStyle: {}, emphasis: { focus: 'series' }, data: [25, 26, 27, 28, 27, 28, 29, 30, 28, 29, 30, 29], itemStyle: { color: '#B8E6B8' } },
  858 + { name: '科美', type: 'line', stack: 'Total', areaStyle: {}, emphasis: { focus: 'series' }, data: [20, 21, 22, 23, 22, 22, 23, 24, 23, 23, 24, 23], itemStyle: { color: '#FFD4A3' } },
  859 + { name: '产品', type: 'line', stack: 'Total', areaStyle: {}, emphasis: { focus: 'series' }, data: [10, 5, 1, -3, 2, -1, -5, -9, -3, -6, -10, -6], itemStyle: { color: '#E6C1E6' } }
  860 + ]
  861 + }
  862 + this.stackedAreaChart.setOption(option)
  863 + },
  864 + handleResize() {
  865 + if (this.trendChart) this.trendChart.resize()
  866 + if (this.categoryChart) this.categoryChart.resize()
  867 + if (this.dailyChart) this.dailyChart.resize()
  868 + if (this.compareChart) this.compareChart.resize()
  869 + if (this.stackedChart) this.stackedChart.resize()
  870 + if (this.funnelChart) this.funnelChart.resize()
  871 + if (this.scatterChart) this.scatterChart.resize()
  872 + if (this.heatmapChart) this.heatmapChart.resize()
  873 + if (this.radarChart) this.radarChart.resize()
  874 + if (this.gaugeChart) this.gaugeChart.resize()
  875 + if (this.stackedAreaChart) this.stackedAreaChart.resize()
  876 + },
  877 + formatMoney(value) {
  878 + if (value === null || value === undefined) return '0.00'
  879 + return Number(value).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
  880 + },
  881 + getRankingClass(rank, total) {
  882 + const percentage = rank / total
  883 + if (percentage <= 0.2) return 'excellent'
  884 + if (percentage <= 0.5) return 'good'
  885 + return 'normal'
  886 + },
  887 + getRankingText(rank, total) {
  888 + const percentage = rank / total
  889 + if (percentage <= 0.2) return '优秀'
  890 + if (percentage <= 0.5) return '良好'
  891 + return '一般'
  892 + },
  893 + getCategoryType(category) {
  894 + const typeMap = {
  895 + '生美': 'primary',
  896 + '医美': 'success',
  897 + '科美': 'warning',
  898 + '产品': 'info'
  899 + }
  900 + return typeMap[category] || ''
  901 + }
  902 + }
  903 +}
  904 +</script>
  905 +
  906 +<style lang="scss" scoped>
  907 +.store-dashboard {
  908 + padding: 20px;
  909 + background: #f5f7fa;
  910 + min-height: calc(100vh - 84px);
  911 +
  912 + // 顶部Header
  913 + .dashboard-header {
  914 + display: flex;
  915 + justify-content: space-between;
  916 + align-items: center;
  917 + padding: 20px 24px;
  918 + background: #fff;
  919 + border-radius: 12px;
  920 + margin-bottom: 20px;
  921 + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  922 +
  923 + .header-left {
  924 + .store-info {
  925 + display: flex;
  926 + align-items: center;
  927 + gap: 16px;
  928 +
  929 + .store-avatar {
  930 + width: 64px;
  931 + height: 64px;
  932 + border-radius: 12px;
  933 + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  934 + display: flex;
  935 + align-items: center;
  936 + justify-content: center;
  937 + color: #fff;
  938 + font-size: 28px;
  939 + }
  940 +
  941 + .store-details {
  942 + .store-name-row {
  943 + display: flex;
  944 + align-items: center;
  945 + gap: 12px;
  946 + margin-bottom: 8px;
  947 +
  948 + .store-name {
  949 + margin: 0;
  950 + font-size: 24px;
  951 + font-weight: 600;
  952 + color: #303133;
  953 + }
  954 + }
  955 +
  956 + .store-meta {
  957 + display: flex;
  958 + gap: 20px;
  959 + font-size: 14px;
  960 + color: #606266;
  961 +
  962 + .meta-item {
  963 + display: flex;
  964 + align-items: center;
  965 + gap: 6px;
  966 +
  967 + i {
  968 + color: #909399;
  969 + }
  970 + }
  971 + }
  972 + }
  973 + }
  974 + }
  975 +
  976 + .header-right {
  977 + .core-stats {
  978 + display: flex;
  979 + gap: 16px;
  980 +
  981 + .core-stat-item {
  982 + padding: 16px 20px;
  983 + border-radius: 10px;
  984 + min-width: 140px;
  985 + text-align: center;
  986 + transition: all 0.3s;
  987 +
  988 + &.primary {
  989 + background: linear-gradient(135deg, #ecf5ff 0%, #d9ecff 100%);
  990 + border-left: 4px solid #409EFF;
  991 + }
  992 +
  993 + &.success {
  994 + background: linear-gradient(135deg, #f0f9ff 0%, #e1f3ff 100%);
  995 + border-left: 4px solid #67C23A;
  996 + }
  997 +
  998 + &.info {
  999 + background: linear-gradient(135deg, #f4f4f5 0%, #e9e9eb 100%);
  1000 + border-left: 4px solid #909399;
  1001 + }
  1002 +
  1003 + &.warning {
  1004 + background: linear-gradient(135deg, #fdf6ec 0%, #fae6d3 100%);
  1005 + border-left: 4px solid #E6A23C;
  1006 + }
  1007 +
  1008 + .stat-label {
  1009 + font-size: 13px;
  1010 + color: #606266;
  1011 + margin-bottom: 8px;
  1012 + }
  1013 +
  1014 + .stat-value {
  1015 + font-size: 22px;
  1016 + font-weight: 700;
  1017 + color: #303133;
  1018 + margin-bottom: 6px;
  1019 + }
  1020 +
  1021 + .stat-trend {
  1022 + font-size: 12px;
  1023 + font-weight: 500;
  1024 +
  1025 + &.up {
  1026 + color: #67C23A;
  1027 + }
  1028 +
  1029 + i {
  1030 + font-size: 10px;
  1031 + }
  1032 + }
  1033 + }
  1034 + }
  1035 + }
  1036 + }
  1037 +
  1038 + // KPI指标卡片
  1039 + .kpi-section {
  1040 + display: grid;
  1041 + grid-template-columns: repeat(6, 1fr);
  1042 + gap: 12px;
  1043 + margin-bottom: 20px;
  1044 +
  1045 + .kpi-card {
  1046 + display: flex;
  1047 + align-items: center;
  1048 + padding: 16px;
  1049 + background: #fff;
  1050 + border-radius: 10px;
  1051 + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  1052 + transition: all 0.3s;
  1053 + position: relative;
  1054 + overflow: hidden;
  1055 +
  1056 + &::before {
  1057 + content: '';
  1058 + position: absolute;
  1059 + top: 0;
  1060 + left: 0;
  1061 + width: 4px;
  1062 + height: 100%;
  1063 + }
  1064 +
  1065 + &.primary::before {
  1066 + background: #409EFF;
  1067 + }
  1068 +
  1069 + &.success::before {
  1070 + background: #67C23A;
  1071 + }
  1072 +
  1073 + &.info::before {
  1074 + background: #909399;
  1075 + }
  1076 +
  1077 + &.warning::before {
  1078 + background: #E6A23C;
  1079 + }
  1080 +
  1081 + &:hover {
  1082 + transform: translateY(-2px);
  1083 + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  1084 + }
  1085 +
  1086 + .kpi-icon {
  1087 + width: 48px;
  1088 + height: 48px;
  1089 + border-radius: 10px;
  1090 + display: flex;
  1091 + align-items: center;
  1092 + justify-content: center;
  1093 + font-size: 22px;
  1094 + color: #fff;
  1095 + margin-right: 12px;
  1096 + flex-shrink: 0;
  1097 + }
  1098 +
  1099 + &.primary .kpi-icon {
  1100 + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  1101 + }
  1102 +
  1103 + &.success .kpi-icon {
  1104 + background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
  1105 + }
  1106 +
  1107 + &.info .kpi-icon {
  1108 + background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  1109 + }
  1110 +
  1111 + &.warning .kpi-icon {
  1112 + background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
  1113 + }
  1114 +
  1115 + .kpi-content {
  1116 + flex: 1;
  1117 + min-width: 0;
  1118 +
  1119 + .kpi-label {
  1120 + font-size: 13px;
  1121 + color: #909399;
  1122 + margin-bottom: 6px;
  1123 + }
  1124 +
  1125 + .kpi-value {
  1126 + font-size: 20px;
  1127 + font-weight: 600;
  1128 + color: #303133;
  1129 +
  1130 + .unit {
  1131 + font-size: 14px;
  1132 + font-weight: 500;
  1133 + }
  1134 + }
  1135 + }
  1136 +
  1137 + .kpi-trend {
  1138 + font-size: 12px;
  1139 + color: #67C23A;
  1140 + font-weight: 500;
  1141 + margin-left: 8px;
  1142 + white-space: nowrap;
  1143 + }
  1144 + }
  1145 + }
  1146 +
  1147 + // 主要内容区域:左右分栏
  1148 + .main-content {
  1149 + display: grid;
  1150 + grid-template-columns: 1fr 400px;
  1151 + gap: 20px;
  1152 + margin-bottom: 20px;
  1153 +
  1154 + .content-left {
  1155 + display: flex;
  1156 + flex-direction: column;
  1157 + gap: 16px;
  1158 + }
  1159 +
  1160 + .content-right {
  1161 + display: flex;
  1162 + flex-direction: column;
  1163 + gap: 16px;
  1164 + }
  1165 +
  1166 + .chart-row {
  1167 + margin-bottom: 0;
  1168 + }
  1169 + }
  1170 +
  1171 + // 图表卡片
  1172 + .chart-card {
  1173 + border-radius: 12px;
  1174 + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  1175 +
  1176 + ::v-deep .el-card__header {
  1177 + padding: 16px 20px;
  1178 + border-bottom: 1px solid #ebeef5;
  1179 + }
  1180 +
  1181 + ::v-deep .el-card__body {
  1182 + padding: 20px;
  1183 + }
  1184 +
  1185 + .chart-container {
  1186 + width: 100%;
  1187 + height: 360px;
  1188 + min-height: 360px;
  1189 + }
  1190 + }
  1191 +
  1192 + .chart-card-small {
  1193 + border-radius: 12px;
  1194 + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  1195 +
  1196 + ::v-deep .el-card__header {
  1197 + padding: 14px 18px;
  1198 + border-bottom: 1px solid #ebeef5;
  1199 + }
  1200 +
  1201 + ::v-deep .el-card__body {
  1202 + padding: 16px;
  1203 + }
  1204 +
  1205 + .chart-container-small {
  1206 + width: 100%;
  1207 + height: 260px;
  1208 + min-height: 260px;
  1209 + }
  1210 + }
  1211 +
  1212 + // 指标卡片
  1213 + .metrics-card {
  1214 + border-radius: 12px;
  1215 + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  1216 +
  1217 + ::v-deep .el-card__header {
  1218 + padding: 14px 18px;
  1219 + border-bottom: 1px solid #ebeef5;
  1220 + }
  1221 +
  1222 + ::v-deep .el-card__body {
  1223 + padding: 16px;
  1224 + }
  1225 +
  1226 + .metrics-grid {
  1227 + display: grid;
  1228 + grid-template-columns: repeat(2, 1fr);
  1229 + gap: 10px;
  1230 +
  1231 + .metric-item {
  1232 + display: flex;
  1233 + align-items: center;
  1234 + padding: 12px;
  1235 + background: #f8f9fa;
  1236 + border-radius: 8px;
  1237 + transition: all 0.3s;
  1238 +
  1239 + &:hover {
  1240 + background: #f0f2f5;
  1241 + transform: translateY(-1px);
  1242 + }
  1243 +
  1244 + .metric-icon {
  1245 + width: 40px;
  1246 + height: 40px;
  1247 + border-radius: 8px;
  1248 + color: #fff;
  1249 + display: flex;
  1250 + align-items: center;
  1251 + justify-content: center;
  1252 + font-size: 18px;
  1253 + margin-right: 10px;
  1254 + flex-shrink: 0;
  1255 + }
  1256 +
  1257 + .metric-info {
  1258 + flex: 1;
  1259 + min-width: 0;
  1260 +
  1261 + .metric-label {
  1262 + font-size: 12px;
  1263 + color: #909399;
  1264 + margin-bottom: 4px;
  1265 + white-space: nowrap;
  1266 + overflow: hidden;
  1267 + text-overflow: ellipsis;
  1268 + }
  1269 +
  1270 + .metric-value {
  1271 + font-size: 16px;
  1272 + font-weight: 600;
  1273 + color: #303133;
  1274 + white-space: nowrap;
  1275 + overflow: hidden;
  1276 + text-overflow: ellipsis;
  1277 + }
  1278 +
  1279 + .metric-rate {
  1280 + font-size: 11px;
  1281 + color: #909399;
  1282 + margin-top: 2px;
  1283 + }
  1284 + }
  1285 + }
  1286 + }
  1287 + }
  1288 +
  1289 + // 卡片标题
  1290 + .card-header {
  1291 + display: flex;
  1292 + align-items: center;
  1293 + font-size: 15px;
  1294 + font-weight: 600;
  1295 + color: #303133;
  1296 +
  1297 + i {
  1298 + margin-right: 8px;
  1299 + color: #409EFF;
  1300 + font-size: 16px;
  1301 + }
  1302 + }
  1303 +
  1304 + // 排名对比卡片
  1305 + .ranking-content {
  1306 + padding: 8px 0;
  1307 +
  1308 + .ranking-item {
  1309 + text-align: center;
  1310 + padding: 16px 0;
  1311 +
  1312 + .ranking-label {
  1313 + font-size: 13px;
  1314 + color: #909399;
  1315 + margin-bottom: 12px;
  1316 + }
  1317 +
  1318 + .ranking-value {
  1319 + margin-bottom: 12px;
  1320 +
  1321 + .rank-number {
  1322 + font-size: 36px;
  1323 + font-weight: 700;
  1324 + color: #409EFF;
  1325 + }
  1326 +
  1327 + .rank-total {
  1328 + font-size: 18px;
  1329 + color: #909399;
  1330 + margin-left: 4px;
  1331 + }
  1332 + }
  1333 +
  1334 + .ranking-badge {
  1335 + display: inline-block;
  1336 + padding: 4px 16px;
  1337 + border-radius: 12px;
  1338 + font-size: 13px;
  1339 + font-weight: 600;
  1340 +
  1341 + &.excellent {
  1342 + background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
  1343 + color: #fff;
  1344 + }
  1345 +
  1346 + &.good {
  1347 + background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  1348 + color: #fff;
  1349 + }
  1350 +
  1351 + &.normal {
  1352 + background: #f4f4f5;
  1353 + color: #909399;
  1354 + }
  1355 + }
  1356 + }
  1357 +
  1358 + .comparison-stats {
  1359 + .stat-row {
  1360 + display: flex;
  1361 + justify-content: space-between;
  1362 + align-items: center;
  1363 + padding: 10px 0;
  1364 + font-size: 13px;
  1365 +
  1366 + &:not(:last-child) {
  1367 + border-bottom: 1px dashed #ebeef5;
  1368 + }
  1369 +
  1370 + .stat-label {
  1371 + color: #606266;
  1372 + }
  1373 +
  1374 + .stat-value {
  1375 + font-weight: 600;
  1376 + color: #303133;
  1377 + }
  1378 + }
  1379 + }
  1380 + }
  1381 +
  1382 + // 经营提示卡片
  1383 + .tips-card {
  1384 + border-radius: 12px;
  1385 + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  1386 +
  1387 + ::v-deep .el-card__header {
  1388 + padding: 14px 18px;
  1389 + border-bottom: 1px solid #ebeef5;
  1390 + }
  1391 +
  1392 + ::v-deep .el-card__body {
  1393 + padding: 16px;
  1394 + }
  1395 +
  1396 + .tips-content {
  1397 + .tip-item {
  1398 + display: flex;
  1399 + align-items: flex-start;
  1400 + padding: 12px;
  1401 + margin-bottom: 8px;
  1402 + border-radius: 8px;
  1403 + font-size: 13px;
  1404 + line-height: 1.6;
  1405 + transition: all 0.3s;
  1406 +
  1407 + &:last-child {
  1408 + margin-bottom: 0;
  1409 + }
  1410 +
  1411 + i {
  1412 + margin-right: 8px;
  1413 + margin-top: 2px;
  1414 + font-size: 14px;
  1415 + flex-shrink: 0;
  1416 + }
  1417 +
  1418 + span {
  1419 + flex: 1;
  1420 + }
  1421 +
  1422 + &.success {
  1423 + background: #f0f9ff;
  1424 + color: #67C23A;
  1425 +
  1426 + i {
  1427 + color: #67C23A;
  1428 + }
  1429 + }
  1430 +
  1431 + &.warning {
  1432 + background: #fdf6ec;
  1433 + color: #E6A23C;
  1434 +
  1435 + i {
  1436 + color: #E6A23C;
  1437 + }
  1438 + }
  1439 +
  1440 + &.info {
  1441 + background: #f4f4f5;
  1442 + color: #909399;
  1443 +
  1444 + i {
  1445 + color: #909399;
  1446 + }
  1447 + }
  1448 +
  1449 + &:hover {
  1450 + transform: translateX(4px);
  1451 + }
  1452 + }
  1453 + }
  1454 + }
  1455 +
  1456 + // 快速数据洞察卡片
  1457 + .insight-card {
  1458 + border-radius: 12px;
  1459 + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  1460 +
  1461 + ::v-deep .el-card__header {
  1462 + padding: 14px 18px;
  1463 + border-bottom: 1px solid #ebeef5;
  1464 + }
  1465 +
  1466 + ::v-deep .el-card__body {
  1467 + padding: 16px;
  1468 + }
  1469 +
  1470 + .insight-content {
  1471 + .insight-item {
  1472 + padding: 14px;
  1473 + margin-bottom: 12px;
  1474 + background: #f8f9fa;
  1475 + border-radius: 8px;
  1476 + border-left: 3px solid #409EFF;
  1477 + transition: all 0.3s;
  1478 +
  1479 + &:last-child {
  1480 + margin-bottom: 0;
  1481 + }
  1482 +
  1483 + &:hover {
  1484 + background: #f0f2f5;
  1485 + transform: translateX(4px);
  1486 + }
  1487 +
  1488 + .insight-header {
  1489 + display: flex;
  1490 + justify-content: space-between;
  1491 + align-items: center;
  1492 + margin-bottom: 8px;
  1493 +
  1494 + .insight-title {
  1495 + font-size: 13px;
  1496 + font-weight: 600;
  1497 + color: #303133;
  1498 + }
  1499 + }
  1500 +
  1501 + .insight-value {
  1502 + font-size: 20px;
  1503 + font-weight: 700;
  1504 + color: #409EFF;
  1505 + margin-bottom: 6px;
  1506 + }
  1507 +
  1508 + .insight-desc {
  1509 + font-size: 12px;
  1510 + color: #909399;
  1511 + line-height: 1.5;
  1512 + }
  1513 + }
  1514 + }
  1515 + }
  1516 +
  1517 + // 关键指标卡片
  1518 + .key-metrics-card {
  1519 + border-radius: 12px;
  1520 + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  1521 +
  1522 + ::v-deep .el-card__header {
  1523 + padding: 14px 18px;
  1524 + border-bottom: 1px solid #ebeef5;
  1525 + }
  1526 +
  1527 + ::v-deep .el-card__body {
  1528 + padding: 16px;
  1529 + }
  1530 +
  1531 + .key-metrics-content {
  1532 + .progress-item {
  1533 + margin-bottom: 20px;
  1534 +
  1535 + &:last-child {
  1536 + margin-bottom: 0;
  1537 + }
  1538 +
  1539 + .progress-header {
  1540 + display: flex;
  1541 + justify-content: space-between;
  1542 + align-items: center;
  1543 + margin-bottom: 8px;
  1544 +
  1545 + .progress-label {
  1546 + font-size: 13px;
  1547 + color: #606266;
  1548 + font-weight: 500;
  1549 + }
  1550 +
  1551 + .progress-value {
  1552 + font-size: 16px;
  1553 + font-weight: 700;
  1554 + color: #303133;
  1555 + }
  1556 + }
  1557 + }
  1558 + }
  1559 + }
  1560 +
  1561 + // 表格区域
  1562 + .table-section {
  1563 + .table-card {
  1564 + border-radius: 12px;
  1565 + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  1566 +
  1567 + ::v-deep .el-card__header {
  1568 + padding: 16px 20px;
  1569 + border-bottom: 1px solid #ebeef5;
  1570 + }
  1571 +
  1572 + ::v-deep .el-card__body {
  1573 + padding: 20px;
  1574 + }
  1575 + }
  1576 + }
  1577 +}
  1578 +</style>
... ...
sql/门店驾驶舱菜单配置.sql 0 → 100644
  1 +-- 门店驾驶舱菜单配置脚本
  2 +
  3 +SET @AdminRoleId = '94e3a9bb0fce4547886972998fddba1c'; -- 系统管理员角色ID
  4 +
  5 +-- 1. 清理旧数据 (防止重复执行报错)
  6 +DELETE FROM BASE_MODULE WHERE F_Id = 'store-dashboard';
  7 +DELETE FROM BASE_AUTHORIZE WHERE F_ItemId = 'store-dashboard';
  8 +
  9 +-- 2. 创建菜单: 门店驾驶舱 (父级: 报表中心 725873504657868037)
  10 +INSERT INTO BASE_MODULE (F_Id, F_ParentId, F_Type, F_FullName, F_EnCode, F_UrlAddress, F_Icon, F_SortCode, F_EnabledMark, F_Category, F_DeleteMark, F_LinkTarget, F_PropertyJson, F_IsButtonAuthorize, F_IsColumnAuthorize, F_IsDataAuthorize, F_IsFormAuthorize, F_CreatorTime)
  11 +VALUES
  12 +('store-dashboard', '725873504657868037', 2, '门店驾驶舱', 'storeDashboard', 'extend/storeDashboard', 'icon-ym icon-ym-office-building', 11, 1, 'Web', NULL, '_self', '{"moduleId":"","iconBackgroundColor":"","isTree":0}', 1, 1, 1, 1, NOW());
  13 +
  14 +-- 3. 授权给 系统管理员 角色
  15 +INSERT INTO BASE_AUTHORIZE (F_Id, F_ItemType, F_ItemId, F_ObjectType, F_ObjectId, F_SortCode, F_CreatorTime, F_CreatorUserId)
  16 +VALUES
  17 +(REPLACE(UUID(), '-', ''), 'module', 'store-dashboard', 'Role', @AdminRoleId, 1, NOW(), 'admin');
  18 +
... ...