gongchunyi
2 天以前 0a251e40e30e7c8a96d71b3b9b6c459d4dfa4b22
src/views/salesManagement/indicatorStats/index.vue
@@ -2,7 +2,7 @@
  <div class="app-container indicator-stats">
    <!-- KPI 汇总 -->
    <el-row :gutter="20" class="stats-row">
      <el-col :xs="24" :sm="12" :md="8">
      <el-col :xs="24" :sm="12" :md="6">
        <div class="stat-card stat-card-blue">
          <div class="stat-icon-wrapper">
            <div class="stat-icon">
@@ -16,7 +16,7 @@
          <div class="stat-bg-decoration"></div>
        </div>
      </el-col>
      <el-col :xs="24" :sm="12" :md="8">
      <el-col :xs="24" :sm="12" :md="6">
        <div class="stat-card stat-card-green">
          <div class="stat-icon-wrapper">
            <div class="stat-icon">
@@ -30,7 +30,21 @@
          <div class="stat-bg-decoration"></div>
        </div>
      </el-col>
      <el-col :xs="24" :sm="12" :md="8">
      <el-col :xs="24" :sm="12" :md="6">
        <div class="stat-card stat-card-purple">
          <div class="stat-icon-wrapper">
            <div class="stat-icon">
              <el-icon :size="32"><Goods /></el-icon>
            </div>
          </div>
          <div class="stat-content">
            <div class="stat-value">{{ formatQuantity(indicatorKpis.productSalesQuantity) }}</div>
            <div class="stat-label">产品销售数量</div>
          </div>
          <div class="stat-bg-decoration"></div>
        </div>
      </el-col>
      <el-col :xs="24" :sm="12" :md="6">
        <div class="stat-card stat-card-orange">
          <div class="stat-icon-wrapper">
            <div class="stat-icon">
@@ -38,7 +52,7 @@
            </div>
          </div>
          <div class="stat-content">
            <div class="stat-value">{{ indicatorKpis.shipRate }}%</div>
            <div class="stat-value">{{ indicatorKpis.shipRate }}</div>
            <div class="stat-label">发货率</div>
          </div>
          <div class="stat-bg-decoration"></div>
@@ -98,11 +112,11 @@
              <label class="filter-label">日期范围</label>
              <el-date-picker 
                v-model="indicatorFilter.dateRange" 
                type="daterange"
                type="monthrange"
                range-separator="至"
                start-placeholder="开始日期" 
                end-placeholder="结束日期" 
                value-format="YYYY-MM-DD"
                value-format="YYYY-MM"
                style="width: 100%" 
              />
            </div>
@@ -127,47 +141,12 @@
        <div ref="indicatorChartRef" class="chart-wrapper"></div>
      </div>
    </el-card>
    <!-- 业绩统计(团队维度,无个人姓名) -->
    <el-card v-if="showTeamPerformance" class="table-card" shadow="hover">
      <template #header>
        <div class="card-header">
          <span class="card-title">团队业绩统计</span>
        </div>
      </template>
      <el-table
        :data="teamPerformanceList"
        border
        stripe
        style="width: 100%"
        :header-cell-style="{ background: '#f5f7fa', color: '#606266', fontWeight: 'bold' }"
      >
        <el-table-column prop="team" label="销售团队" min-width="120"/>
        <el-table-column prop="orderCount" label="订单数" align="right" min-width="100"/>
        <el-table-column prop="salesAmount" label="销售额" align="right" min-width="140">
          <template #default="scope">¥{{ scope.row.salesAmount.toLocaleString() }}</template>
        </el-table-column>
        <el-table-column prop="shipRate" label="发货率" align="right" min-width="100">
          <template #default="scope">{{ scope.row.shipRate }}%</template>
        </el-table-column>
        <el-table-column prop="attainment" label="目标达成率" align="center" min-width="120">
          <template #default="scope">
            <el-tag
              :type="scope.row.attainment >= 100 ? 'success' : scope.row.attainment >= 80 ? 'warning' : 'danger'"
              effect="dark"
            >
              {{ scope.row.attainment }}%
            </el-tag>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
import { Document, Van, Tickets, Search, Refresh } from '@element-plus/icons-vue'
import { Document, Van, Tickets, Search, Refresh, Goods } from '@element-plus/icons-vue'
import * as echarts from 'echarts'
import { getTotalStatistics, getStatisticsTable } from '@/api/salesManagement/indicatorStats'
import { productTreeList } from '@/api/basicData/product.js'
@@ -177,6 +156,7 @@
const indicatorKpis = reactive({
  orderCount: 0,
  salesAmount: 0,
  productSalesQuantity: 0,
  shipRate: 0
})
@@ -196,13 +176,11 @@
const productOptions = ref([])
const customerOption = ref([])
const teamPerformanceList = ref([
  { team: '华东大区', orderCount: 320, salesAmount: 2850000, shipRate: 90, attainment: 105 },
  { team: '华北大区', orderCount: 280, salesAmount: 2150000, shipRate: 86, attainment: 92 },
  { team: '华南大区', orderCount: 210, salesAmount: 1850000, shipRate: 88, attainment: 78 },
  { team: '西南大区', orderCount: 180, salesAmount: 1500000, shipRate: 83, attainment: 74 }
])
const formatQuantity = (value) => {
  const num = Number(value)
  if (Number.isNaN(num)) return '0'
  return num.toLocaleString(undefined, { maximumFractionDigits: 2 })
}
// 转换产品树数据,将 id 改为 value
function convertIdToValue(data) {
  return data.map((item) => {
@@ -276,8 +254,8 @@
    if (res && res.data) {
      indicatorKpis.orderCount = res.data.total || 0
      indicatorKpis.salesAmount = res.data.contractAmountTotal || 0
      // 发货率如果接口没有返回,保持原值或设为0
      // indicatorKpis.shipRate = res.data.shipRate || 0
      indicatorKpis.productSalesQuantity = res.data.productQuantityTotal || 0
      indicatorKpis.shipRate = res.data.shipRate || 0
    }
  } catch (error) {
    console.error('获取头部统计失败:', error)
@@ -324,12 +302,19 @@
  if (indicatorChart) indicatorChart.dispose()
  indicatorChart = echarts.init(indicatorChartRef.value)
  
  // 根据接口返回的数据结构更新图表
  // 接口返回: dateList, orderCountList, salesAmountList
  // 接口返回: dateList, orderCountList, salesAmountList, productQuantityList
  const option = {
    title: { text: '多维度销售指标趋势', left: 'center' },
    tooltip: { trigger: 'axis' },
    legend: { data: ['订单数', '销售额'], top: 30 },
    legend: {
      data: ['订单数', '销售额', '产品销售数量'],
      top: 30,
      selected: {
        '订单数': false,
        '销售额': true,
        '产品销售数量': true
      }
    },
    grid: { left: '3%', right: '8%', bottom: '3%', containLabel: true },
    xAxis: { 
      type: 'category', 
@@ -364,6 +349,13 @@
        yAxisIndex: 0,
        data: chartData.salesAmountList || [], 
        itemStyle: { color: '#67c23a' } 
      },
      {
        name: '产品销售数量',
        type: 'line',
        yAxisIndex: 1,
        data: chartData.productQuantityList || [],
        itemStyle: { color: '#f56c6c' }
      }
    ]
  }
@@ -377,7 +369,15 @@
  const option = {
    title: { text: '多维度销售指标趋势', left: 'center' },
    tooltip: { trigger: 'axis' },
    legend: { data: ['订单数', '销售额'], top: 30 },
    legend: {
      data: ['订单数', '销售额', '产品销售数量'],
      top: 30,
      selected: {
        '订单数': false,
        '销售额': true,
        '产品销售数量': true
      }
    },
    grid: { left: '3%', right: '8%', bottom: '3%', containLabel: true },
    xAxis: { type: 'category', data: [] },
    yAxis: [
@@ -397,7 +397,8 @@
    ],
    series: [
      { name: '订单数', type: 'line', yAxisIndex: 1, data: [], itemStyle: { color: '#409eff' } },
      { name: '销售额', type: 'bar', yAxisIndex: 0, data: [], itemStyle: { color: '#67c23a' } }
      { name: '销售额', type: 'bar', yAxisIndex: 0, data: [], itemStyle: { color: '#67c23a' } },
      { name: '产品销售数量', type: 'line', yAxisIndex: 1, data: [], itemStyle: { color: '#f56c6c' } }
    ]
  }
  indicatorChart.setOption(option)
@@ -448,7 +449,6 @@
<style scoped lang="scss">
.indicator-stats {
  padding: 20px;
  background: #f5f7fa;
  min-height: calc(100vh - 84px);
}
@@ -566,6 +566,17 @@
      background: #e6a23c;
    }
  }
  &.stat-card-purple {
    .stat-icon {
      background: linear-gradient(135deg, #9b59b6 0%, #b37fcc 100%);
      color: #fff;
    }
    .stat-bg-decoration {
      background: #9b59b6;
    }
  }
}
.chart-card,