TradeTrendCard.vue 6.3 KB

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