spring
8 天以前 ea6ad9ddc3d5b33897e93276282245f7023836ff
大数据市场分析
已添加1个文件
1082 ■■■■■ 文件已修改
src/views/marketAnalysis/index.vue 1082 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/marketAnalysis/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1082 @@
<template>
  <div class="market-analysis-container">
    <!-- æ•°æ®æ¦‚览卡片 -->
    <el-row :gutter="20" class="data-overview">
      <el-col :span="6">
        <el-card class="overview-card" shadow="hover">
          <div class="card-content">
            <div class="card-icon price-icon">
              <el-icon><TrendCharts /></el-icon>
            </div>
            <div class="card-info">
              <div class="card-title">平均煤价</div>
              <div class="card-value">Â¥{{ marketData.avgPrice.toFixed(2) }}</div>
              <div class="card-change" :class="marketData.priceChange >= 0 ? 'positive' : 'negative'">
                {{ marketData.priceChange >= 0 ? '+' : '' }}{{ marketData.priceChange.toFixed(2) }}%
              </div>
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="overview-card" shadow="hover">
          <div class="card-content">
            <div class="card-icon volume-icon">
              <el-icon><DataLine /></el-icon>
            </div>
            <div class="card-info">
              <div class="card-title">交易量</div>
              <div class="card-value">{{ marketData.totalVolume }}万吨</div>
              <div class="card-change" :class="marketData.volumeChange >= 0 ? 'positive' : 'negative'">
                {{ marketData.volumeChange >= 0 ? '+' : '' }}{{ marketData.volumeChange.toFixed(2) }}%
              </div>
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="overview-card" shadow="hover">
          <div class="card-content">
            <div class="card-icon customer-icon">
              <el-icon><User /></el-icon>
            </div>
            <div class="card-info">
              <div class="card-title">活跃客户</div>
              <div class="card-value">{{ marketData.activeCustomers }}å®¶</div>
              <div class="card-change" :class="marketData.customerChange >= 0 ? 'positive' : 'negative'">
                {{ marketData.customerChange >= 0 ? '+' : '' }}{{ marketData.customerChange.toFixed(2) }}%
              </div>
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="overview-card" shadow="hover">
          <div class="card-content">
            <div class="card-icon trend-icon">
              <el-icon><TrendCharts /></el-icon>
            </div>
            <div class="card-info">
              <div class="card-title">市场趋势</div>
              <div class="card-value">{{ marketData.marketTrend }}</div>
              <div class="card-change" :class="marketData.trendScore >= 0 ? 'positive' : 'negative'">
                ä¿¡å¿ƒæŒ‡æ•°: {{ marketData.trendScore }}
              </div>
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>
    <!-- ä¸»è¦åˆ†æžåŒºåŸŸ -->
    <el-row :gutter="20" class="main-analysis">
      <!-- ä»·æ ¼è¶‹åŠ¿åˆ†æž -->
      <el-col :span="16">
        <el-card class="analysis-card" shadow="hover">
          <template #header>
            <div class="card-header">
              <span>煤种价格趋势分析</span>
              <div class="header-controls">
                <el-select v-model="selectedCoalType" placeholder="选择煤种" size="small" style="width: 120px">
                  <el-option label="混煤" value="mixed" />
                  <el-option label="精煤" value="refined" />
                  <el-option label="动力煤" value="power" />
                  <el-option label="焦煤" value="coking" />
                </el-select>
                <el-select v-model="selectedRegion" placeholder="选择产地" size="small" style="width: 120px">
                  <el-option label="山西" value="shanxi" />
                  <el-option label="内蒙古" value="neimenggu" />
                  <el-option label="陕西" value="shaanxi" />
                  <el-option label="新疆" value="xinjiang" />
                </el-select>
                <el-select v-model="selectedPeriod" placeholder="时间周期" size="small" style="width: 100px">
                  <el-option label="日" value="day" />
                  <el-option label="周" value="week" />
                  <el-option label="月" value="month" />
                  <el-option label="å­£" value="quarter" />
                </el-select>
              </div>
            </div>
          </template>
          <div class="chart-container">
            <div ref="priceChartRef" class="chart" style="height: 400px;"></div>
          </div>
        </el-card>
      </el-col>
      <!-- å®¢æˆ·è¡Œä¸ºåˆ†æž -->
      <el-col :span="8">
        <el-card class="analysis-card" shadow="hover">
          <template #header>
            <div class="card-header">
              <span>客户行为画像</span>
            </div>
          </template>
          <div class="customer-analysis">
            <div class="customer-type-distribution">
              <h4>客户类型分布</h4>
              <div ref="customerChartRef" class="chart" style="height: 200px;"></div>
            </div>
            <div class="purchase-preference">
              <h4>采购偏好分析</h4>
              <div class="preference-item" v-for="item in customerPreferences" :key="item.type">
                <div class="preference-label">{{ item.type }}</div>
                <div class="preference-bar">
                  <div class="bar-fill" :style="{ width: item.percentage + '%' }"></div>
                </div>
                <div class="preference-value">{{ item.percentage }}%</div>
              </div>
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>
    <!-- è¯¦ç»†åˆ†æžåŒºåŸŸ -->
    <el-row :gutter="20" class="detail-analysis">
      <!-- åŒºåŸŸä»·æ ¼å¯¹æ¯” -->
      <el-col :span="12">
        <el-card class="analysis-card" shadow="hover">
          <template #header>
            <div class="card-header">
              <span>区域价格对比</span>
            </div>
          </template>
          <div class="region-comparison">
            <div ref="regionChartRef" class="chart" style="height: 300px;"></div>
          </div>
        </el-card>
      </el-col>
      <!-- å®¢æˆ·é‡‡è´­å‘¨æœŸåˆ†æž -->
      <el-col :span="12">
        <el-card class="analysis-card" shadow="hover">
          <template #header>
            <div class="card-header">
              <span>客户采购周期分析</span>
            </div>
          </template>
          <div class="purchase-cycle">
            <div ref="cycleChartRef" class="chart" style="height: 300px;"></div>
          </div>
        </el-card>
      </el-col>
    </el-row>
    <!-- æ™ºèƒ½æŽ¨èåŒºåŸŸ -->
    <el-row :gutter="20" class="smart-recommendations">
      <el-col :span="24">
        <el-card class="analysis-card" shadow="hover">
          <template #header>
            <div class="card-header">
              <span>智能营销推荐</span>
              <el-tag type="warning" size="small">AI算法驱动</el-tag>
            </div>
          </template>
          <div class="recommendations-content">
            <el-row :gutter="20">
              <el-col :span="8">
                <div class="recommendation-section">
                  <h4>个性化定价建议</h4>
                  <div class="pricing-suggestions">
                    <div class="suggestion-item" v-for="suggestion in pricingSuggestions" :key="suggestion.id">
                      <div class="suggestion-header">
                        <span class="customer-name">{{ suggestion.customerName }}</span>
                        <el-tag :type="suggestion.priority" size="small">{{ suggestion.priorityText }}</el-tag>
                      </div>
                      <div class="suggestion-content">
                        <p>建议价格:¥{{ suggestion.suggestedPrice }}/吨</p>
                        <p>议价空间:{{ suggestion.negotiationSpace }}%</p>
                        <p>推单时机:{{ suggestion.timing }}</p>
                      </div>
                    </div>
                  </div>
                </div>
              </el-col>
              <el-col :span="8">
                <div class="recommendation-section">
                  <h4>热销煤型推荐</h4>
                  <div class="hot-coal-types">
                    <div class="coal-type-item" v-for="coal in hotCoalTypes" :key="coal.id">
                      <div class="coal-info">
                        <div class="coal-name">{{ coal.name }}</div>
                        <div class="coal-spec">{{ coal.specification }}</div>
                      </div>
                      <div class="coal-metrics">
                        <div class="metric">
                          <span class="label">热度指数:</span>
                          <span class="value">{{ coal.heatIndex }}</span>
                        </div>
                        <div class="metric">
                          <span class="label">库存状态:</span>
                          <el-tag :type="coal.stockStatus === '充足' ? 'success' : 'warning'" size="small">
                            {{ coal.stockStatus }}
                          </el-tag>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </el-col>
              <el-col :span="8">
                <div class="recommendation-section">
                  <h4>客户粘性提升</h4>
                  <div class="loyalty-improvements">
                    <div class="improvement-item" v-for="improvement in loyaltyImprovements" :key="improvement.id">
                      <div class="improvement-header">
                        <span class="strategy-name">{{ improvement.strategyName }}</span>
                        <span class="success-rate">成功率: {{ improvement.successRate }}%</span>
                      </div>
                      <div class="improvement-content">
                        <p>{{ improvement.description }}</p>
                        <div class="action-buttons">
                          <el-button type="primary" size="small">执行策略</el-button>
                          <el-button size="small">查看详情</el-button>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </el-col>
            </el-row>
          </div>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import { Refresh, TrendCharts, DataLine, User } from '@element-plus/icons-vue'
import * as echarts from 'echarts'
// å“åº”式数据
const refreshing = ref(false)
const lastUpdateTime = ref('')
const selectedCoalType = ref('mixed')
const selectedRegion = ref('shanxi')
const selectedPeriod = ref('month')
// å›¾è¡¨å¼•用
const priceChartRef = ref(null)
const customerChartRef = ref(null)
const regionChartRef = ref(null)
const cycleChartRef = ref(null)
// å›¾è¡¨å®žä¾‹
let priceChart = null
let customerChart = null
let regionChart = null
let cycleChart = null
// å¸‚场数据
const marketData = reactive({
  avgPrice: 1250.50,
  priceChange: 2.35,
  totalVolume: 1250.8,
  volumeChange: -1.25,
  activeCustomers: 156,
  customerChange: 3.45,
  marketTrend: '稳中有升',
  trendScore: 8.5
})
// å®¢æˆ·åå¥½æ•°æ®
const customerPreferences = ref([
  { type: '焦化厂', percentage: 35 },
  { type: '电厂', percentage: 28 },
  { type: '钢厂', percentage: 22 },
  { type: '化工厂', percentage: 15 }
])
// å®šä»·å»ºè®®
const pricingSuggestions = ref([
  {
    id: 1,
    customerName: '山西焦化集团',
    priority: 'high',
    priorityText: '高优先级',
    suggestedPrice: 1280,
    negotiationSpace: 5.2,
    timing: '本周内'
  },
  {
    id: 2,
    customerName: '华能电力',
    priority: 'medium',
    priorityText: '中优先级',
    suggestedPrice: 1250,
    negotiationSpace: 3.8,
    timing: '下周初'
  },
  {
    id: 3,
    customerName: '宝钢集团',
    priority: 'low',
    priorityText: '低优先级',
    suggestedPrice: 1220,
    negotiationSpace: 2.5,
    timing: '本月内'
  }
])
// çƒ­é”€ç…¤åž‹
const hotCoalTypes = ref([
  {
    id: 1,
    name: '优质混煤',
    specification: '发热量5500大卡',
    heatIndex: 9.2,
    stockStatus: '充足'
  },
  {
    id: 2,
    name: '精洗焦煤',
    specification: '灰分≤8%',
    heatIndex: 8.8,
    stockStatus: '充足'
  },
  {
    id: 3,
    name: '动力煤',
    specification: '发热量6000大卡',
    heatIndex: 8.5,
    stockStatus: 'ç´§å¼ '
  }
])
// å®¢æˆ·ç²˜æ€§æå‡ç­–ç•¥
const loyaltyImprovements = ref([
  {
    id: 1,
    strategyName: '差异化定价策略',
    successRate: 85,
    description: '根据客户采购频次和议价能力,制定个性化价格方案'
  },
  {
    id: 2,
    strategyName: '精准推单节奏',
    successRate: 78,
    description: '基于客户采购周期分析,在最佳时机推送相关产品'
  },
  {
    id: 3,
    strategyName: '增值服务包',
    successRate: 92,
    description: '提供物流配送、质量检测等增值服务,提升客户满意度'
  }
])
// æ¨¡æ‹Ÿæ•°æ®ç”Ÿæˆ
const generateMockData = () => {
  // ç”Ÿæˆä»·æ ¼è¶‹åŠ¿æ•°æ®
  const dates = []
  const prices = []
  const volumes = []
  for (let i = 30; i >= 0; i--) {
    const date = new Date()
    date.setDate(date.getDate() - i)
    dates.push(date.toLocaleDateString())
    const basePrice = 1200 + Math.random() * 200
    prices.push(basePrice)
    const baseVolume = 30 + Math.random() * 20
    volumes.push(baseVolume)
  }
  return { dates, prices, volumes }
}
// åˆå§‹åŒ–价格趋势图表
const initPriceChart = () => {
  if (!priceChartRef.value) return
  priceChart = echarts.init(priceChartRef.value)
  const { dates, prices, volumes } = generateMockData()
  const option = {
    title: {
      text: '混煤月度价格变化趋势',
      left: 'center',
      textStyle: {
        fontSize: 16,
        fontWeight: 'bold'
      }
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'cross'
      }
    },
    legend: {
      data: ['ä»·æ ¼(元/吨)', '交易量(万吨)'],
      top: 30
    },
    grid: {
      left: '3%',
      right: '4%',
      bottom: '3%',
      containLabel: true
    },
    xAxis: {
      type: 'category',
      data: dates,
      axisLabel: {
        rotate: 45
      }
    },
    yAxis: [
      {
        type: 'value',
        name: 'ä»·æ ¼(元/吨)',
        position: 'left'
      },
      {
        type: 'value',
        name: '交易量(万吨)',
        position: 'right'
      }
    ],
    series: [
      {
        name: 'ä»·æ ¼(元/吨)',
        type: 'line',
        data: prices,
        smooth: true,
        lineStyle: {
          color: '#409EFF',
          width: 3
        },
        itemStyle: {
          color: '#409EFF'
        }
      },
      {
        name: '交易量(万吨)',
        type: 'bar',
        yAxisIndex: 1,
        data: volumes,
        itemStyle: {
          color: '#67C23A'
        }
      }
    ]
  }
  priceChart.setOption(option)
}
// åˆå§‹åŒ–客户分布图表
const initCustomerChart = () => {
  if (!customerChartRef.value) return
  customerChart = echarts.init(customerChartRef.value)
  const option = {
    tooltip: {
      trigger: 'item',
      formatter: '{a} <br/>{b}: {c} ({d}%)'
    },
    series: [
      {
        name: '客户类型',
        type: 'pie',
        radius: ['40%', '70%'],
        avoidLabelOverlap: false,
        label: {
          show: false,
          position: 'center'
        },
        emphasis: {
          label: {
            show: true,
            fontSize: '18',
            fontWeight: 'bold'
          }
        },
        labelLine: {
          show: false
        },
        data: [
          { value: 35, name: '焦化厂' },
          { value: 28, name: '电厂' },
          { value: 22, name: '钢厂' },
          { value: 15, name: '化工厂' }
        ]
      }
    ]
  }
  customerChart.setOption(option)
}
// åˆå§‹åŒ–区域对比图表
const initRegionChart = () => {
  if (!regionChartRef.value) return
  regionChart = echarts.init(regionChartRef.value)
  const option = {
    title: {
      text: '各产地煤价对比',
      left: 'center'
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'shadow'
      }
    },
    legend: {
      data: ['混煤', '精煤', '动力煤', '焦煤'],
      top: 30
    },
    grid: {
      left: '3%',
      right: '4%',
      bottom: '3%',
      containLabel: true
    },
    xAxis: {
      type: 'category',
      data: ['山西', '内蒙古', '陕西', '新疆']
    },
    yAxis: {
      type: 'value',
      name: 'ä»·æ ¼(元/吨)'
    },
    series: [
      {
        name: '混煤',
        type: 'bar',
        data: [1250, 1180, 1220, 1150]
      },
      {
        name: '精煤',
        type: 'bar',
        data: [1350, 1280, 1320, 1250]
      },
      {
        name: '动力煤',
        type: 'bar',
        data: [1150, 1080, 1120, 1050]
      },
      {
        name: '焦煤',
        type: 'bar',
        data: [1450, 1380, 1420, 1350]
      }
    ]
  }
  regionChart.setOption(option)
}
// åˆå§‹åŒ–采购周期图表
const initCycleChart = () => {
  if (!cycleChartRef.value) return
  cycleChart = echarts.init(cycleChartRef.value)
  const option = {
    title: {
      text: '客户采购周期分布',
      left: 'center'
    },
    tooltip: {
      trigger: 'item'
    },
    series: [
      {
        name: '采购周期',
        type: 'funnel',
        left: '10%',
        top: 60,
        bottom: 60,
        width: '80%',
        height: '80%',
        min: 0,
        max: 100,
        minSize: '0%',
        maxSize: '100%',
        sort: 'descending',
        gap: 2,
        label: {
          show: true,
          position: 'inside'
        },
        labelLine: {
          length: 10,
          lineStyle: {
            width: 1,
            type: 'solid'
          }
        },
        itemStyle: {
          borderColor: '#fff',
          borderWidth: 1
        },
        emphasis: {
          label: {
            fontSize: 20
          }
        },
        data: [
          { value: 100, name: '高频客户(周采购)' },
          { value: 80, name: '中频客户(月采购)' },
          { value: 60, name: '低频客户(季采购)' },
          { value: 40, name: '偶发客户(年采购)' }
        ]
      }
    ]
  }
  cycleChart.setOption(option)
}
// åˆ·æ–°æ•°æ®
const refreshData = async () => {
  refreshing.value = true
  try {
    // æ¨¡æ‹Ÿæ•°æ®åˆ·æ–°
    await new Promise(resolve => setTimeout(resolve, 2000))
    // æ›´æ–°å¸‚场数据
    marketData.avgPrice = 1200 + Math.random() * 200
    marketData.priceChange = (Math.random() - 0.5) * 10
    marketData.totalVolume = 1000 + Math.random() * 500
    marketData.volumeChange = (Math.random() - 0.5) * 8
    marketData.activeCustomers = 140 + Math.floor(Math.random() * 40)
    marketData.customerChange = (Math.random() - 0.5) * 6
    marketData.trendScore = 7 + Math.random() * 3
    // æ›´æ–°æ—¶é—´
    lastUpdateTime.value = new Date().toLocaleString()
    // é‡æ–°åˆå§‹åŒ–图表
    await nextTick()
    initPriceChart()
    initCustomerChart()
    initRegionChart()
    initCycleChart()
    ElMessage.success('数据刷新成功')
  } catch (error) {
    ElMessage.error('数据刷新失败')
  } finally {
    refreshing.value = false
  }
}
// è‡ªåŠ¨åˆ·æ–°å®šæ—¶å™¨
let refreshTimer = null
// å¯åŠ¨è‡ªåŠ¨åˆ·æ–°
const startAutoRefresh = () => {
  refreshTimer = setInterval(() => {
    refreshData()
  }, 10 * 60 * 1000) // 10分钟
}
// åœæ­¢è‡ªåŠ¨åˆ·æ–°
const stopAutoRefresh = () => {
  if (refreshTimer) {
    clearInterval(refreshTimer)
    refreshTimer = null
  }
}
// ç›‘听窗口大小变化
const handleResize = () => {
  if (priceChart) priceChart.resize()
  if (customerChart) customerChart.resize()
  if (regionChart) regionChart.resize()
  if (cycleChart) cycleChart.resize()
}
// ç”Ÿå‘½å‘¨æœŸ
onMounted(async () => {
  // åˆå§‹åŒ–æ—¶é—´
  lastUpdateTime.value = new Date().toLocaleString()
  // ç­‰å¾…DOM渲染完成
  await nextTick()
  // åˆå§‹åŒ–图表
  initPriceChart()
  initCustomerChart()
  initRegionChart()
  initCycleChart()
  // å¯åŠ¨è‡ªåŠ¨åˆ·æ–°
  startAutoRefresh()
  // ç›‘听窗口大小变化
  window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
  // åœæ­¢è‡ªåŠ¨åˆ·æ–°
  stopAutoRefresh()
  // é”€æ¯å›¾è¡¨
  if (priceChart) priceChart.dispose()
  if (customerChart) customerChart.dispose()
  if (regionChart) regionChart.dispose()
  if (cycleChart) cycleChart.dispose()
  // ç§»é™¤äº‹ä»¶ç›‘听
  window.removeEventListener('resize', handleResize)
})
</script>
<style scoped>
.market-analysis-container {
  padding: 20px;
  background-color: #f5f7fa;
  min-height: 100vh;
}
.page-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding: 20px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.page-header h1 {
  margin: 0;
  color: #303133;
  font-size: 24px;
  font-weight: 600;
}
.header-info {
  display: flex;
  align-items: center;
  gap: 15px;
}
.update-time {
  color: #909399;
  font-size: 14px;
}
.data-overview {
  margin-bottom: 20px;
}
.overview-card {
  height: 120px;
}
.card-content {
  display: flex;
  align-items: center;
  height: 100%;
}
.card-icon {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 15px;
  font-size: 24px;
  color: white;
}
.price-icon {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.volume-icon {
  background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
.customer-icon {
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
.trend-icon {
  background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
.card-info {
  flex: 1;
}
.card-title {
  font-size: 14px;
  color: #909399;
  margin-bottom: 8px;
}
.card-value {
  font-size: 24px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 8px;
}
.card-change {
  font-size: 12px;
  font-weight: 500;
}
.card-change.positive {
  color: #67c23a;
}
.card-change.negative {
  color: #f56c6c;
}
.main-analysis {
  margin-bottom: 20px;
}
.analysis-card {
  margin-bottom: 20px;
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: 600;
  font-size: 16px;
}
.header-controls {
  display: flex;
  gap: 10px;
}
.chart-container {
  padding: 10px 0;
}
.chart {
  width: 100%;
}
.customer-analysis h4 {
  margin: 0 0 15px 0;
  color: #303133;
  font-size: 14px;
}
.customer-type-distribution {
  margin-bottom: 20px;
}
.preference-item {
  display: flex;
  align-items: center;
  margin-bottom: 12px;
}
.preference-label {
  width: 80px;
  font-size: 12px;
  color: #606266;
}
.preference-bar {
  flex: 1;
  height: 8px;
  background-color: #f0f0f0;
  border-radius: 4px;
  margin: 0 10px;
  overflow: hidden;
}
.bar-fill {
  height: 100%;
  background: linear-gradient(90deg, #409eff 0%, #67c23a 100%);
  border-radius: 4px;
  transition: width 0.3s ease;
}
.preference-value {
  width: 40px;
  font-size: 12px;
  color: #409eff;
  font-weight: 500;
}
.detail-analysis {
  margin-bottom: 20px;
}
.smart-recommendations {
  margin-bottom: 20px;
}
.recommendations-content {
  padding: 10px 0;
}
.recommendation-section h4 {
  margin: 0 0 15px 0;
  color: #303133;
  font-size: 14px;
  border-bottom: 2px solid #409eff;
  padding-bottom: 5px;
}
.suggestion-item {
  background: #f8f9fa;
  border-radius: 6px;
  padding: 12px;
  margin-bottom: 12px;
  border-left: 4px solid #409eff;
}
.suggestion-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}
.customer-name {
  font-weight: 500;
  color: #303133;
}
.suggestion-content p {
  margin: 5px 0;
  font-size: 12px;
  color: #606266;
}
.coal-type-item {
  background: #f8f9fa;
  border-radius: 6px;
  padding: 12px;
  margin-bottom: 12px;
  border-left: 4px solid #67c23a;
}
.coal-info {
  margin-bottom: 8px;
}
.coal-name {
  font-weight: 500;
  color: #303133;
  font-size: 14px;
}
.coal-spec {
  font-size: 12px;
  color: #909399;
}
.coal-metrics {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.metric {
  font-size: 12px;
}
.metric .label {
  color: #909399;
}
.metric .value {
  color: #409eff;
  font-weight: 500;
}
.improvement-item {
  background: #f8f9fa;
  border-radius: 6px;
  padding: 12px;
  margin-bottom: 12px;
  border-left: 4px solid #e6a23c;
}
.improvement-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}
.strategy-name {
  font-weight: 500;
  color: #303133;
}
.success-rate {
  font-size: 12px;
  color: #67c23a;
  font-weight: 500;
}
.improvement-content p {
  margin: 5px 0 10px 0;
  font-size: 12px;
  color: #606266;
}
.action-buttons {
  display: flex;
  gap: 8px;
}
/* å“åº”式设计 */
@media (max-width: 1200px) {
  .header-controls {
    flex-direction: column;
    gap: 5px;
  }
  .header-controls .el-select {
    width: 100px !important;
  }
}
@media (max-width: 768px) {
  .page-header {
    flex-direction: column;
    gap: 15px;
    text-align: center;
  }
  .header-info {
    flex-direction: column;
    gap: 10px;
  }
}
</style>