eight
2024-08-13 b10adc8a3fd000901836e2219fa83462694e9866
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
<template>
  <el-card shadow="never">
    <template #header>
      <div class="flex flex-row items-center justify-between">
        <CardTitle title="交易量趋势" />
        <!-- 查询条件 -->
        <div class="flex flex-row items-center gap-2">
          <el-radio-group v-model="timeRangeType" @change="handleTimeRangeTypeChange">
            <el-radio-button v-for="[key, value] in timeRange.entries()" :key="key" :label="key">
              {{ value.name }}
            </el-radio-button>
          </el-radio-group>
        </div>
      </div>
    </template>
    <!-- 折线图 -->
    <Echart :height="300" :options="eChartOptions" />
  </el-card>
</template>
<script lang="ts" setup>
import dayjs, { Dayjs } from 'dayjs'
import { EChartsOption } from 'echarts'
import * as TradeStatisticsApi from '@/api/mall/statistics/trade'
import { fenToYuan } from '@/utils'
import { formatDate } from '@/utils/formatTime'
import { CardTitle } from '@/components/Card'
 
/** 交易量趋势 */
defineOptions({ name: 'TradeTrendCard' })
 
enum TimeRangeTypeEnum {
  DAY30 = 1,
  WEEK = 7,
  MONTH = 30,
  YEAR = 365
} // 日期类型
const timeRangeType = ref(TimeRangeTypeEnum.DAY30) // 日期快捷选择按钮, 默认30天
const loading = ref(true) // 加载中
// 时间范围 Map
const timeRange = new Map()
  .set(TimeRangeTypeEnum.DAY30, {
    name: '30天',
    series: [
      { name: '订单金额', type: 'bar', smooth: true, data: [] },
      { name: '订单数量', type: 'line', smooth: true, data: [] }
    ]
  })
  .set(TimeRangeTypeEnum.WEEK, {
    name: '周',
    series: [
      { name: '上周金额', type: 'bar', smooth: true, data: [] },
      { name: '本周金额', type: 'bar', smooth: true, data: [] },
      { name: '上周数量', type: 'line', smooth: true, data: [] },
      { name: '本周数量', type: 'line', smooth: true, data: [] }
    ]
  })
  .set(TimeRangeTypeEnum.MONTH, {
    name: '月',
    series: [
      { name: '上月金额', type: 'bar', smooth: true, data: [] },
      { name: '本月金额', type: 'bar', smooth: true, data: [] },
      { name: '上月数量', type: 'line', smooth: true, data: [] },
      { name: '本月数量', type: 'line', smooth: true, data: [] }
    ]
  })
  .set(TimeRangeTypeEnum.YEAR, {
    name: '年',
    series: [
      { name: '去年金额', type: 'bar', smooth: true, data: [] },
      { name: '今年金额', type: 'bar', smooth: true, data: [] },
      { name: '去年数量', type: 'line', smooth: true, data: [] },
      { name: '今年数量', type: 'line', smooth: true, data: [] }
    ]
  })
/** 图表配置 */
const eChartOptions = reactive<EChartsOption>({
  grid: {
    left: 20,
    right: 20,
    bottom: 20,
    top: 80,
    containLabel: true
  },
  legend: {
    top: 50,
    data: []
  },
  series: [],
  toolbox: {
    feature: {
      // 数据区域缩放
      dataZoom: {
        yAxisIndex: false // Y轴不缩放
      },
      brush: {
        type: ['lineX', 'clear'] // 区域缩放按钮、还原按钮
      },
      saveAsImage: { show: true, name: '订单量趋势' } // 保存为图片
    }
  },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'cross'
    },
    padding: [5, 10]
  },
  xAxis: {
    type: 'category',
    inverse: true,
    boundaryGap: false,
    axisTick: {
      show: false
    },
    data: [],
    axisLabel: {
      formatter: (date: string) => {
        switch (timeRangeType.value) {
          case TimeRangeTypeEnum.DAY30:
            return formatDate(date, 'MM-DD')
          case TimeRangeTypeEnum.WEEK:
            let weekDay = formatDate(date, 'ddd')
            if (weekDay == '0') weekDay = '日'
            return '周' + weekDay
          case TimeRangeTypeEnum.MONTH:
            return formatDate(date, 'D')
          case TimeRangeTypeEnum.YEAR:
            return formatDate(date, 'M') + '月'
          default:
            return date
        }
      }
    }
  },
  yAxis: {
    axisTick: {
      show: false
    }
  }
}) as EChartsOption
 
/** 时间范围类型单选按钮选中 */
const handleTimeRangeTypeChange = async () => {
  // 设置时间范围
  let beginTime: Dayjs
  let endTime: Dayjs
  switch (timeRangeType.value) {
    case TimeRangeTypeEnum.WEEK:
      beginTime = dayjs().startOf('week')
      endTime = dayjs().endOf('week')
      break
    case TimeRangeTypeEnum.MONTH:
      beginTime = dayjs().startOf('month')
      endTime = dayjs().endOf('month')
      break
    case TimeRangeTypeEnum.YEAR:
      beginTime = dayjs().startOf('year')
      endTime = dayjs().endOf('year')
      break
    case TimeRangeTypeEnum.DAY30:
    default:
      beginTime = dayjs().subtract(30, 'day').startOf('d')
      endTime = dayjs().endOf('d')
      break
  }
  // 发送时间范围选中事件
  await getOrderCountTrendComparison(beginTime, endTime)
}
 
/** 查询订单数量趋势对照数据 */
const getOrderCountTrendComparison = async (
  beginTime: dayjs.ConfigType,
  endTime: dayjs.ConfigType
) => {
  loading.value = true
  // 查询数据
  const list = await TradeStatisticsApi.getOrderCountTrendComparison(
    timeRangeType.value,
    beginTime,
    endTime
  )
  // 处理数据
  const dates: string[] = []
  const series = [...timeRange.get(timeRangeType.value).series]
  for (let item of list) {
    dates.push(item.value.date)
    if (series.length === 2) {
      series[0].data.push(fenToYuan(item?.value?.orderPayPrice || 0)) // 当前金额
      series[1].data.push(item?.value?.orderPayCount || 0) // 当前数量
    } else {
      series[0].data.push(fenToYuan(item?.reference?.orderPayPrice || 0)) // 对照金额
      series[1].data.push(fenToYuan(item?.value?.orderPayPrice || 0)) // 当前金额
      series[2].data.push(item?.reference?.orderPayCount || 0) // 对照数量
      series[3].data.push(item?.value?.orderPayCount || 0) // 当前数量
    }
  }
  eChartOptions.xAxis!['data'] = dates
  eChartOptions.series = series
  // legend在4个切换到2个的时候,还是显示成4个,需要手动配置一下
  eChartOptions.legend['data'] = series.map((item) => item.name)
  loading.value = false
}
 
/** 初始化 **/
onMounted(() => {
  handleTimeRangeTypeChange()
})
</script>