index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. <template>
  2. <div class="flex flex-col">
  3. <el-row :gutter="16" class="summary">
  4. <el-col :sm="6" :xs="12">
  5. <TradeStatisticValue
  6. tooltip="昨日订单数量"
  7. title="昨日订单数量"
  8. :value="summary?.value?.yesterdayOrderCount || 0"
  9. :percent="
  10. calculateRelativeRate(
  11. summary?.value?.yesterdayOrderCount,
  12. summary?.reference?.yesterdayOrderCount
  13. )
  14. "
  15. />
  16. </el-col>
  17. <el-col :sm="6" :xs="12">
  18. <TradeStatisticValue
  19. tooltip="本月订单数量"
  20. title="本月订单数量"
  21. :value="summary?.value?.monthOrderCount || 0"
  22. :percent="
  23. calculateRelativeRate(
  24. summary?.value?.monthOrderCount,
  25. summary?.reference?.monthOrderCount
  26. )
  27. "
  28. />
  29. </el-col>
  30. <el-col :sm="6" :xs="12">
  31. <TradeStatisticValue
  32. tooltip="昨日支付金额"
  33. title="昨日支付金额"
  34. prefix="¥"
  35. :decimals="2"
  36. :value="fenToYuan(summary?.value?.yesterdayPayPrice || 0)"
  37. :percent="
  38. calculateRelativeRate(
  39. summary?.value?.yesterdayPayPrice,
  40. summary?.reference?.yesterdayPayPrice
  41. )
  42. "
  43. />
  44. </el-col>
  45. <el-col :sm="6" :xs="12">
  46. <TradeStatisticValue
  47. tooltip="本月支付金额"
  48. title="本月支付金额"
  49. prefix="¥"
  50. ::decimals="2"
  51. :value="fenToYuan(summary?.value?.monthPayPrice || 0)"
  52. :percent="
  53. calculateRelativeRate(summary?.value?.monthPayPrice, summary?.reference?.monthPayPrice)
  54. "
  55. />
  56. </el-col>
  57. </el-row>
  58. <el-card shadow="never">
  59. <template #header>
  60. <!-- 标题 -->
  61. <div class="flex flex-row items-center justify-between">
  62. <CardTitle title="交易状况" />
  63. <!-- 查询条件 -->
  64. <ShortcutDateRangePicker ref="shortcutDateRangePicker" @change="getTradeTrendData">
  65. <el-button
  66. class="ml-4"
  67. @click="handleExport"
  68. :loading="exportLoading"
  69. v-hasPermi="['statistics:trade:export']"
  70. >
  71. <Icon icon="ep:download" class="mr-1" />导出
  72. </el-button>
  73. </ShortcutDateRangePicker>
  74. </div>
  75. </template>
  76. <!-- 统计值 -->
  77. <el-row :gutter="16">
  78. <el-col :md="6" :sm="12" :xs="24">
  79. <SummaryCard
  80. title="营业额"
  81. tooltip="商品支付金额、充值金额"
  82. icon="fa-solid:yen-sign"
  83. icon-color="bg-blue-100"
  84. icon-bg-color="text-blue-500"
  85. prefix="¥"
  86. :decimals="2"
  87. :value="fenToYuan(trendSummary?.value?.turnoverPrice || 0)"
  88. :percent="
  89. calculateRelativeRate(
  90. trendSummary?.value?.turnoverPrice,
  91. trendSummary?.reference?.turnoverPrice
  92. )
  93. "
  94. />
  95. </el-col>
  96. <el-col :md="6" :sm="12" :xs="24">
  97. <SummaryCard
  98. title="商品支付金额"
  99. tooltip="用户购买商品的实际支付金额,包括微信支付、余额支付、支付宝支付、线下支付金额(拼团商品在成团之后计入,线下支付订单在后台确认支付后计入)"
  100. icon="fa-solid:shopping-cart"
  101. icon-color="bg-purple-100"
  102. icon-bg-color="text-purple-500"
  103. prefix="¥"
  104. :decimals="2"
  105. :value="fenToYuan(trendSummary?.value?.orderPayPrice || 0)"
  106. :percent="
  107. calculateRelativeRate(
  108. trendSummary?.value?.orderPayPrice,
  109. trendSummary?.reference?.orderPayPrice
  110. )
  111. "
  112. />
  113. </el-col>
  114. <el-col :md="6" :sm="12" :xs="24">
  115. <SummaryCard
  116. title="充值金额"
  117. tooltip="用户成功充值的金额"
  118. icon="fa-solid:money-check-alt"
  119. icon-color="bg-yellow-100"
  120. icon-bg-color="text-yellow-500"
  121. prefix="¥"
  122. :decimals="2"
  123. :value="fenToYuan(trendSummary?.value?.rechargePrice || 0)"
  124. :percent="
  125. calculateRelativeRate(
  126. trendSummary?.value?.rechargePrice,
  127. trendSummary?.reference?.rechargePrice
  128. )
  129. "
  130. />
  131. </el-col>
  132. <el-col :md="6" :sm="12" :xs="24">
  133. <SummaryCard
  134. title="支出金额"
  135. tooltip="余额支付金额、支付佣金金额、商品退款金额"
  136. icon="ep:warning-filled"
  137. icon-color="bg-green-100"
  138. icon-bg-color="text-green-500"
  139. prefix="¥"
  140. :decimals="2"
  141. :value="fenToYuan(trendSummary?.value?.expensePrice || 0)"
  142. :percent="
  143. calculateRelativeRate(
  144. trendSummary?.value?.expensePrice,
  145. trendSummary?.reference?.expensePrice
  146. )
  147. "
  148. />
  149. </el-col>
  150. <el-col :md="6" :sm="12" :xs="24">
  151. <SummaryCard
  152. title="余额支付金额"
  153. tooltip="用户下单时使用余额实际支付的金额"
  154. icon="fa-solid:wallet"
  155. icon-color="bg-cyan-100"
  156. icon-bg-color="text-cyan-500"
  157. prefix="¥"
  158. :decimals="2"
  159. :value="fenToYuan(trendSummary?.value?.walletPayPrice || 0)"
  160. :percent="
  161. calculateRelativeRate(
  162. trendSummary?.value?.walletPayPrice,
  163. trendSummary?.reference?.walletPayPrice
  164. )
  165. "
  166. />
  167. </el-col>
  168. <el-col :md="6" :sm="12" :xs="24">
  169. <SummaryCard
  170. title="支付佣金金额"
  171. tooltip="后台给推广员支付的推广佣金,以实际支付为准"
  172. icon="fa-solid:award"
  173. icon-color="bg-yellow-100"
  174. icon-bg-color="text-yellow-500"
  175. prefix="¥"
  176. :decimals="2"
  177. :value="fenToYuan(trendSummary?.value?.brokerageSettlementPrice || 0)"
  178. :percent="
  179. calculateRelativeRate(
  180. trendSummary?.value?.brokerageSettlementPrice,
  181. trendSummary?.reference?.brokerageSettlementPrice
  182. )
  183. "
  184. />
  185. </el-col>
  186. <el-col :md="6" :sm="12" :xs="24">
  187. <SummaryCard
  188. title="商品退款金额"
  189. tooltip="用户成功退款的商品金额"
  190. icon="fa-solid:times-circle"
  191. icon-color="bg-blue-100"
  192. icon-bg-color="text-blue-500"
  193. prefix="¥"
  194. :decimals="2"
  195. :value="fenToYuan(trendSummary?.value?.afterSaleRefundPrice || 0)"
  196. :percent="
  197. calculateRelativeRate(
  198. trendSummary?.value?.afterSaleRefundPrice,
  199. trendSummary?.reference?.afterSaleRefundPrice
  200. )
  201. "
  202. />
  203. </el-col>
  204. </el-row>
  205. <!-- 折线图 -->
  206. <el-skeleton :loading="trendLoading" animated>
  207. <Echart :height="500" :options="lineChartOptions" />
  208. </el-skeleton>
  209. </el-card>
  210. </div>
  211. </template>
  212. <script lang="ts" setup>
  213. import * as TradeStatisticsApi from '@/api/mall/statistics/trade'
  214. import TradeStatisticValue from './components/TradeStatisticValue.vue'
  215. import SummaryCard from '@/components/SummaryCard/index.vue'
  216. import { EChartsOption } from 'echarts'
  217. import { DataComparisonRespVO } from '@/api/mall/statistics/common'
  218. import { TradeSummaryRespVO, TradeTrendSummaryRespVO } from '@/api/mall/statistics/trade'
  219. import { calculateRelativeRate, fenToYuan } from '@/utils'
  220. import download from '@/utils/download'
  221. import { CardTitle } from '@/components/Card'
  222. import * as DateUtil from '@/utils/formatTime'
  223. import dayjs from 'dayjs'
  224. /** 交易统计 */
  225. defineOptions({ name: 'TradeStatistics' })
  226. const message = useMessage() // 消息弹窗
  227. const trendLoading = ref(true) // 交易状态加载中
  228. const exportLoading = ref(false) // 导出的加载中
  229. const summary = ref<DataComparisonRespVO<TradeSummaryRespVO>>() // 交易统计数据
  230. const trendSummary = ref<DataComparisonRespVO<TradeTrendSummaryRespVO>>() // 交易状况统计数据
  231. const shortcutDateRangePicker = ref()
  232. /** 折线图配置 */
  233. const lineChartOptions = reactive<EChartsOption>({
  234. dataset: {
  235. dimensions: ['date', 'turnoverPrice', 'orderPayPrice', 'rechargePrice', 'expensePrice'],
  236. source: []
  237. },
  238. grid: {
  239. left: 20,
  240. right: 20,
  241. bottom: 20,
  242. top: 80,
  243. containLabel: true
  244. },
  245. legend: {
  246. top: 50
  247. },
  248. series: [
  249. { name: '营业额', type: 'line', smooth: true },
  250. { name: '商品支付金额', type: 'line', smooth: true },
  251. { name: '充值金额', type: 'line', smooth: true },
  252. { name: '支出金额', type: 'line', smooth: true }
  253. ],
  254. toolbox: {
  255. feature: {
  256. // 数据区域缩放
  257. dataZoom: {
  258. yAxisIndex: false // Y轴不缩放
  259. },
  260. brush: {
  261. type: ['lineX', 'clear'] // 区域缩放按钮、还原按钮
  262. },
  263. saveAsImage: { show: true, name: '交易状况' } // 保存为图片
  264. }
  265. },
  266. tooltip: {
  267. trigger: 'axis',
  268. axisPointer: {
  269. type: 'cross'
  270. },
  271. padding: [5, 10]
  272. },
  273. xAxis: {
  274. type: 'category',
  275. boundaryGap: false,
  276. axisTick: {
  277. show: false
  278. }
  279. },
  280. yAxis: {
  281. axisTick: {
  282. show: false
  283. }
  284. }
  285. }) as EChartsOption
  286. /** 处理交易状况查询 */
  287. const getTradeTrendData = async () => {
  288. trendLoading.value = true
  289. // 1. 处理时间: 开始与截止在同一天的, 折线图出不来, 需要延长一天
  290. const times = shortcutDateRangePicker.value.times
  291. if (DateUtil.isSameDay(times[0], times[1])) {
  292. // 前天
  293. times[0] = DateUtil.formatDate(dayjs(times[0]).subtract(1, 'd'))
  294. }
  295. // 查询数据
  296. await Promise.all([getTradeTrendSummary(), getTradeStatisticsList()])
  297. trendLoading.value = false
  298. }
  299. /** 查询交易统计 */
  300. const getTradeStatisticsSummary = async () => {
  301. summary.value = await TradeStatisticsApi.getTradeStatisticsSummary()
  302. }
  303. /** 查询交易状况数据统计 */
  304. const getTradeTrendSummary = async () => {
  305. const times = shortcutDateRangePicker.value.times
  306. trendSummary.value = await TradeStatisticsApi.getTradeTrendSummary({ times })
  307. }
  308. /** 查询交易状况数据列表 */
  309. const getTradeStatisticsList = async () => {
  310. // 查询数据
  311. const times = shortcutDateRangePicker.value.times
  312. const list = await TradeStatisticsApi.getTradeStatisticsList({ times })
  313. // 处理数据
  314. for (let item of list) {
  315. item.turnoverPrice = fenToYuan(item.turnoverPrice)
  316. item.orderPayPrice = fenToYuan(item.orderPayPrice)
  317. item.rechargePrice = fenToYuan(item.rechargePrice)
  318. item.expensePrice = fenToYuan(item.expensePrice)
  319. }
  320. // 更新 Echarts 数据
  321. if (lineChartOptions.dataset && lineChartOptions.dataset['source']) {
  322. lineChartOptions.dataset['source'] = list
  323. }
  324. }
  325. /** 导出按钮操作 */
  326. const handleExport = async () => {
  327. try {
  328. // 导出的二次确认
  329. await message.exportConfirm()
  330. // 发起导出
  331. exportLoading.value = true
  332. const times = shortcutDateRangePicker.value.times
  333. const data = await TradeStatisticsApi.exportTradeStatisticsExcel({ times })
  334. download.excel(data, '交易状况.xls')
  335. } catch {
  336. } finally {
  337. exportLoading.value = false
  338. }
  339. }
  340. /** 初始化 **/
  341. onMounted(async () => {
  342. await getTradeStatisticsSummary()
  343. })
  344. </script>
  345. <style lang="scss" scoped>
  346. .summary {
  347. .el-col {
  348. margin-bottom: 1rem;
  349. }
  350. }
  351. </style>