diff --git a/src/api/statistics/trade.ts b/src/api/statistics/trade.ts new file mode 100644 index 00000000..f7829ccb --- /dev/null +++ b/src/api/statistics/trade.ts @@ -0,0 +1,70 @@ +import request from '@/config/axios' +import dayjs from 'dayjs' +import { formatDate } from '@/utils/formatTime' + +/** 交易统计对照 Response VO */ +export interface TradeStatisticsComparisonRespVO<T> { + value: T + reference: T +} + +/** 交易统计 Response VO */ +export interface TradeSummaryRespVO { + yesterdayOrderCount: number + monthOrderCount: number + yesterdayPayPrice: number + monthPayPrice: number +} + +/** 交易状况 Request VO */ +export interface TradeTrendReqVO { + times: [dayjs.ConfigType, dayjs.ConfigType] +} + +/** 交易状况统计 Response VO */ +export interface TradeTrendSummaryRespVO { + time: string + turnover: number + orderPayPrice: number + rechargePrice: number + expensePrice: number + balancePrice: number + brokerageSettlementPrice: number + orderRefundPrice: number +} + +// 查询交易统计 +export const getTradeStatisticsSummary = () => { + return request.get<TradeStatisticsComparisonRespVO<TradeSummaryRespVO>>({ + url: '/statistics/trade/summary' + }) +} + +// 获得交易状况统计 +export const getTradeTrendSummary = (params: TradeTrendReqVO) => { + return request.get<TradeStatisticsComparisonRespVO<TradeTrendSummaryRespVO>>({ + url: '/statistics/trade/trend/summary', + params: formatDateParam(params) + }) +} + +// 获得交易状况明细 +export const getTradeTrendList = (params: TradeTrendReqVO) => { + return request.get<TradeTrendSummaryRespVO[]>({ + url: '/statistics/trade/trend/list', + params: formatDateParam(params) + }) +} + +// 导出交易状况明细 +export const exportTradeTrend = (params: TradeTrendReqVO) => { + return request.download({ + url: '/statistics/trade/trend/export-excel', + params: formatDateParam(params) + }) +} + +/** 时间参数需要格式化, 确保接口能识别 */ +const formatDateParam = (params: TradeTrendReqVO) => { + return { times: [formatDate(params.times[0]), formatDate(params.times[1])] } as TradeTrendReqVO +} diff --git a/src/components/CountTo/src/CountTo.vue b/src/components/CountTo/src/CountTo.vue index 1b1131a0..7a19bec7 100644 --- a/src/components/CountTo/src/CountTo.vue +++ b/src/components/CountTo/src/CountTo.vue @@ -11,21 +11,21 @@ const { getPrefixCls } = useDesign() const prefixCls = getPrefixCls('count-to') const props = defineProps({ - startVal: propTypes.number.def(0), - endVal: propTypes.number.def(2021), - duration: propTypes.number.def(3000), - autoplay: propTypes.bool.def(true), - decimals: propTypes.number.validate((value: number) => value >= 0).def(0), - decimal: propTypes.string.def('.'), - separator: propTypes.string.def(','), - prefix: propTypes.string.def(''), - suffix: propTypes.string.def(''), - useEasing: propTypes.bool.def(true), + startVal: propTypes.number.def(0), // 开始播放值 + endVal: propTypes.number.def(2021), // 最终值 + duration: propTypes.number.def(3000), // 动画时长 + autoplay: propTypes.bool.def(true), // 是否自动播放动画, 默认播放 + decimals: propTypes.number.validate((value: number) => value >= 0).def(0), // 显示的小数位数, 默认不显示小数 + decimal: propTypes.string.def('.'), // 小数分隔符号, 默认为点 + separator: propTypes.string.def(','), // 数字每三位的分隔符, 默认为逗号 + prefix: propTypes.string.def(''), // 前缀, 数值前面显示的内容 + suffix: propTypes.string.def(''), // 后缀, 数值后面显示的内容 + useEasing: propTypes.bool.def(true), // 是否使用缓动效果, 默认启用 easingFn: { type: Function as PropType<(t: number, b: number, c: number, d: number) => number>, default(t: number, b: number, c: number, d: number) { return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b - } + } // 缓动函数 } }) diff --git a/src/layout/components/useRenderLayout.tsx b/src/layout/components/useRenderLayout.tsx index 46a1e60e..1110cd86 100644 --- a/src/layout/components/useRenderLayout.tsx +++ b/src/layout/components/useRenderLayout.tsx @@ -107,7 +107,7 @@ export const useRenderLayout = () => { ></ToolHeader> {tagsView.value ? ( - <TagsView class="layout-border__bottom layout-border__top"></TagsView> + <TagsView class="layout-border__top layout-border__bottom"></TagsView> ) : undefined} </div> @@ -121,13 +121,13 @@ export const useRenderLayout = () => { const renderTopLeft = () => { return ( <> - <div class="flex items-center bg-[var(--top-header-bg-color)] relative layout-border__bottom dark:bg-[var(--el-bg-color)]"> + <div class="relative flex items-center bg-[var(--top-header-bg-color)] layout-border__bottom dark:bg-[var(--el-bg-color)]"> {logo.value ? <Logo class="custom-hover"></Logo> : undefined} <ToolHeader class="flex-1"></ToolHeader> </div> - <div class="absolute top-[var(--logo-height)+1px] left-0 w-full h-[calc(100%-1px-var(--logo-height))] flex"> - <Menu class="!h-full relative layout-border__right"></Menu> + <div class="absolute left-0 top-[var(--logo-height)+1px] h-[calc(100%-1px-var(--logo-height))] w-full flex"> + <Menu class="relative layout-border__right !h-full"></Menu> <div class={[ `${prefixCls}-content`, @@ -187,7 +187,7 @@ export const useRenderLayout = () => { ]} > {logo.value ? <Logo class="custom-hover"></Logo> : undefined} - <Menu class="flex-1 px-10px h-[var(--top-tool-height)]"></Menu> + <Menu class="h-[var(--top-tool-height)] flex-1 px-10px"></Menu> <ToolHeader></ToolHeader> </div> <div @@ -233,12 +233,12 @@ export const useRenderLayout = () => { const renderCutMenu = () => { return ( <> - <div class="flex items-center bg-[var(--top-header-bg-color)] relative layout-border__bottom"> + <div class="relative flex items-center bg-[var(--top-header-bg-color)] layout-border__bottom"> {logo.value ? <Logo class="custom-hover !pr-15px"></Logo> : undefined} <ToolHeader class="flex-1"></ToolHeader> </div> - <div class="absolute top-[var(--logo-height)] left-0 w-[calc(100%-2px)] h-[calc(100%-var(--logo-height))] flex"> + <div class="absolute left-0 top-[var(--logo-height)] h-[calc(100%-var(--logo-height))] w-[calc(100%-2px)] flex"> <TabMenu></TabMenu> <div class={[ diff --git a/src/utils/formatTime.ts b/src/utils/formatTime.ts index 87409260..b30151eb 100644 --- a/src/utils/formatTime.ts +++ b/src/utils/formatTime.ts @@ -11,7 +11,7 @@ import dayjs from 'dayjs' * @description format 季度 + 星期 + 几周:"YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ" * @returns 返回拼接后的时间字符串 */ -export function formatDate(date: Date | number, format?: string): string { +export function formatDate(date: dayjs.ConfigType, format?: string): string { // 日期不存在,则返回空 if (!date) { return '' @@ -221,3 +221,68 @@ export function convertDate(param: Date | string) { } return param } + +/** + * 指定的两个日期, 是否为同一天 + * @param a 日期 A + * @param b 日期 B + */ +export function isSameDay(a: dayjs.ConfigType, b: dayjs.ConfigType): boolean { + if (!a || !b) return false + + const aa = dayjs(a) + const bb = dayjs(b) + return aa.year() == bb.year() && aa.month() == bb.month() && aa.day() == bb.day() +} + +/** + * 获取一天的开始时间、截止时间 + * @param date 日期 + * @param days 天数 + */ +export function getDayRange( + date: dayjs.ConfigType, + days: number +): [dayjs.ConfigType, dayjs.ConfigType] { + const day = dayjs(date).add(days, 'd') + return getDateRange(day, day) +} + +/** + * 获取最近7天的开始时间、截止时间 + */ +export function getLast7Days(): [dayjs.ConfigType, dayjs.ConfigType] { + const lastWeekDay = dayjs().subtract(7, 'd') + const yesterday = dayjs().subtract(1, 'd') + return getDateRange(lastWeekDay, yesterday) +} + +/** + * 获取最近30天的开始时间、截止时间 + */ +export function getLast30Days(): [dayjs.ConfigType, dayjs.ConfigType] { + const lastMonthDay = dayjs().subtract(30, 'd') + const yesterday = dayjs().subtract(1, 'd') + return getDateRange(lastMonthDay, yesterday) +} + +/** + * 获取最近1年的开始时间、截止时间 + */ +export function getLast1Year(): [dayjs.ConfigType, dayjs.ConfigType] { + const lastYearDay = dayjs().subtract(1, 'y') + const yesterday = dayjs().subtract(1, 'd') + return getDateRange(lastYearDay, yesterday) +} + +/** + * 获取指定日期的开始时间、截止时间 + * @param beginDate 开始日期 + * @param endDate 截止日期 + */ +export function getDateRange( + beginDate: dayjs.ConfigType, + endDate: dayjs.ConfigType +): [dayjs.ConfigType, dayjs.ConfigType] { + return [dayjs(beginDate).startOf('d'), dayjs(endDate).endOf('d')] +} diff --git a/src/views/statistics/trade/components/TradeStatisticValue.vue b/src/views/statistics/trade/components/TradeStatisticValue.vue new file mode 100644 index 00000000..475810ee --- /dev/null +++ b/src/views/statistics/trade/components/TradeStatisticValue.vue @@ -0,0 +1,41 @@ +<template> + <div class="bg flex flex-col gap-2 p-6"> + <div class="flex items-center justify-between text-gray-500"> + <span>{{ title }}</span> + <el-tooltip :content="tooltip" placement="top-start" v-if="tooltip"> + <Icon icon="ep:warning" /> + </el-tooltip> + </div> + <div class="mb-4 text-3xl"> + <CountTo :prefix="prefix" :end-val="value" :decimals="decimals" /> + </div> + <div class="flex flex-row gap-1 text-sm"> + <span class="text-gray-500">环比</span> + <span :class="toNumber(percent) > 0 ? 'text-red-500' : 'text-green-500'"> + {{ Math.abs(toNumber(percent)) }}% + <Icon :icon="toNumber(percent) > 0 ? 'ep:caret-top' : 'ep:caret-bottom'" class="!text-sm" /> + </span> + </div> + </div> +</template> +<script lang="ts" setup> +import { propTypes } from '@/utils/propTypes' +import { toNumber } from 'lodash-es' + +/** 交易统计值组件 */ +defineOptions({ name: 'TradeStatisticValue' }) + +defineProps({ + tooltip: propTypes.string.def(''), + title: propTypes.string.def(''), + prefix: propTypes.string.def(''), + value: propTypes.number.def(0), + decimals: propTypes.number.def(0), + percent: propTypes.oneOfType([Number, String]).def(0) +}) +</script> +<style scoped> +.bg { + background-color: var(--el-bg-color-overlay); +} +</style> diff --git a/src/views/statistics/trade/components/TradeTrendValue.vue b/src/views/statistics/trade/components/TradeTrendValue.vue new file mode 100644 index 00000000..e1e2e4fe --- /dev/null +++ b/src/views/statistics/trade/components/TradeTrendValue.vue @@ -0,0 +1,54 @@ +<template> + <div class="mb-8 flex flex-row items-center gap-3"> + <div + class="h-12 w-12 flex flex-shrink-0 items-center justify-center rounded-1" + :class="`${iconColor} ${iconBgColor}`" + > + <Icon :icon="icon" class="!text-6" /> + </div> + <div class="bg flex flex-col gap-1"> + <div class="flex items-center gap-1 text-gray-500"> + <span class="text-3.5">{{ title }}</span> + <el-tooltip :content="tooltip" placement="top-start" v-if="tooltip"> + <Icon icon="ep:warning" class="item-center flex !text-3" /> + </el-tooltip> + </div> + <div class="flex flex-row items-baseline gap-2"> + <div class="text-7"> + <CountTo :prefix="prefix" :end-val="value" :decimals="decimals" /> + </div> + <span :class="toNumber(percent) > 0 ? 'text-red-500' : 'text-green-500'"> + <span class="text-sm">{{ Math.abs(toNumber(percent)) }}%</span> + <Icon + :icon="toNumber(percent) > 0 ? 'ep:caret-top' : 'ep:caret-bottom'" + class="ml-0.5 !text-3" + /> + </span> + </div> + </div> + </div> +</template> +<script lang="ts" setup> +import { propTypes } from '@/utils/propTypes' +import { toNumber } from 'lodash-es' + +/** 交易状况统计值组件 */ +defineOptions({ name: 'TradeTrendValue' }) + +defineProps({ + title: propTypes.string.def(''), + tooltip: propTypes.string.def(''), + icon: propTypes.string.def(''), + iconColor: propTypes.string.def(''), + iconBgColor: propTypes.string.def(''), + prefix: propTypes.string.def(''), + value: propTypes.number.def(0), + decimals: propTypes.number.def(0), + percent: propTypes.oneOfType([Number, String]).def(0) +}) +</script> +<style scoped> +.bg { + background-color: var(--el-bg-color-overlay); +} +</style> diff --git a/src/views/statistics/trade/index.vue b/src/views/statistics/trade/index.vue new file mode 100644 index 00000000..c6af0f5f --- /dev/null +++ b/src/views/statistics/trade/index.vue @@ -0,0 +1,428 @@ +<template> + <div class="flex flex-col"> + <el-row :gutter="16" class="summary"> + <el-col :sm="6" :xs="12"> + <TradeStatisticValue + tooltip="昨日订单数量" + title="昨日订单数量" + :value="summary?.value?.yesterdayOrderCount || 0" + :percent=" + calculateRelativeRate( + summary?.value?.yesterdayOrderCount, + summary?.reference?.yesterdayOrderCount + ) + " + /> + </el-col> + <el-col :sm="6" :xs="12"> + <TradeStatisticValue + tooltip="本月订单数量" + title="本月订单数量" + :value="summary?.value?.monthOrderCount || 0" + :percent=" + calculateRelativeRate( + summary?.value?.monthOrderCount, + summary?.reference?.monthOrderCount + ) + " + /> + </el-col> + <el-col :sm="6" :xs="12"> + <TradeStatisticValue + tooltip="昨日支付金额" + title="昨日支付金额" + prefix="¥" + :decimals="2" + :value="fenToYuan(summary?.value?.yesterdayPayPrice || 0)" + :percent=" + calculateRelativeRate( + summary?.value?.yesterdayPayPrice, + summary?.reference?.yesterdayPayPrice + ) + " + /> + </el-col> + <el-col :sm="6" :xs="12"> + <TradeStatisticValue + tooltip="本月支付金额" + title="本月支付金额" + prefix="¥" + ::decimals="2" + :value="fenToYuan(summary?.value?.monthPayPrice || 0)" + :percent=" + calculateRelativeRate(summary?.value?.monthPayPrice, summary?.reference?.monthPayPrice) + " + /> + </el-col> + </el-row> + <el-card shadow="never"> + <template #header> + <!-- 标题 --> + <div class="flex flex-row items-center justify-between"> + <span>交易状况</span> + <!-- 查询条件 --> + <div class="flex flex-row items-center gap-2"> + <el-radio-group v-model="shortcutDays" @change="handleDateTypeChange"> + <el-radio-button :label="1">昨天</el-radio-button> + <el-radio-button :label="7">最近7天</el-radio-button> + <el-radio-button :label="30">最近30天</el-radio-button> + </el-radio-group> + <el-date-picker + v-model="queryParams.times" + value-format="YYYY-MM-DD HH:mm:ss" + type="daterange" + start-placeholder="开始日期" + end-placeholder="结束日期" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + :shortcuts="shortcuts" + class="!w-240px" + @change="getTradeTrendData" + /> + <el-button + class="ml-4" + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['statistics:trade:export']" + > + <Icon icon="ep:download" class="mr-1" />导出 + </el-button> + </div> + </div> + </template> + <!-- 统计值 --> + <el-row :gutter="16"> + <el-col :md="6" :sm="12" :xs="24"> + <TradeTrendValue + title="营业额" + tooltip="商品支付金额、充值金额" + icon="fa-solid:yen-sign" + icon-color="bg-blue-100" + icon-bg-color="text-blue-500" + prefix="¥" + :decimals="2" + :value="fenToYuan(trendSummary?.value?.turnover || 0)" + :percent=" + calculateRelativeRate( + trendSummary?.value?.turnover, + trendSummary?.reference?.turnover + ) + " + /> + </el-col> + <el-col :md="6" :sm="12" :xs="24"> + <TradeTrendValue + title="商品支付金额" + tooltip="用户购买商品的实际支付金额,包括微信支付、余额支付、支付宝支付、线下支付金额(拼团商品在成团之后计入,线下支付订单在后台确认支付后计入)" + icon="fa-solid:shopping-cart" + icon-color="bg-purple-100" + icon-bg-color="text-purple-500" + prefix="¥" + :decimals="2" + :value="fenToYuan(trendSummary?.value?.orderPayPrice || 0)" + :percent=" + calculateRelativeRate( + trendSummary?.value?.orderPayPrice, + trendSummary?.reference?.orderPayPrice + ) + " + /> + </el-col> + <el-col :md="6" :sm="12" :xs="24"> + <TradeTrendValue + title="充值金额" + tooltip="用户成功充值的金额" + icon="fa-solid:money-check-alt" + icon-color="bg-yellow-100" + icon-bg-color="text-yellow-500" + prefix="¥" + :decimals="2" + :value="fenToYuan(trendSummary?.value?.rechargePrice || 0)" + :percent=" + calculateRelativeRate( + trendSummary?.value?.rechargePrice, + trendSummary?.reference?.rechargePrice + ) + " + /> + </el-col> + <el-col :md="6" :sm="12" :xs="24"> + <TradeTrendValue + title="支出金额" + tooltip="余额支付金额、支付佣金金额、商品退款金额" + icon="ep:warning-filled" + icon-color="bg-green-100" + icon-bg-color="text-green-500" + prefix="¥" + :decimals="2" + :value="fenToYuan(trendSummary?.value?.expensePrice || 0)" + :percent=" + calculateRelativeRate( + trendSummary?.value?.expensePrice, + trendSummary?.reference?.expensePrice + ) + " + /> + </el-col> + <el-col :md="6" :sm="12" :xs="24"> + <TradeTrendValue + title="余额支付金额" + tooltip="用户下单时使用余额实际支付的金额" + icon="fa-solid:wallet" + icon-color="bg-cyan-100" + icon-bg-color="text-cyan-500" + prefix="¥" + :decimals="2" + :value="fenToYuan(trendSummary?.value?.balancePrice || 0)" + :percent=" + calculateRelativeRate( + trendSummary?.value?.balancePrice, + trendSummary?.reference?.balancePrice + ) + " + /> + </el-col> + <el-col :md="6" :sm="12" :xs="24"> + <TradeTrendValue + title="支付佣金金额" + tooltip="后台给推广员支付的推广佣金,以实际支付为准" + icon="fa-solid:award" + icon-color="bg-yellow-100" + icon-bg-color="text-yellow-500" + prefix="¥" + :decimals="2" + :value="fenToYuan(trendSummary?.value?.brokerageSettlementPrice || 0)" + :percent=" + calculateRelativeRate( + trendSummary?.value?.brokerageSettlementPrice, + trendSummary?.reference?.brokerageSettlementPrice + ) + " + /> + </el-col> + <el-col :md="6" :sm="12" :xs="24"> + <TradeTrendValue + title="商品退款金额" + tooltip="用户成功退款的商品金额" + icon="fa-solid:times-circle" + icon-color="bg-blue-100" + icon-bg-color="text-blue-500" + prefix="¥" + :decimals="2" + :value="fenToYuan(trendSummary?.value?.orderRefundPrice || 0)" + :percent=" + calculateRelativeRate( + trendSummary?.value?.orderRefundPrice, + trendSummary?.reference?.orderRefundPrice + ) + " + /> + </el-col> + </el-row> + <!-- 拆线图 --> + <el-skeleton :loading="trendLoading" animated> + <Echart :height="500" :options="lineChartOptions" /> + </el-skeleton> + </el-card> + </div> +</template> +<script lang="ts" setup> +import * as TradeStatisticsApi from '@/api/statistics/trade' +import TradeStatisticValue from './components/TradeStatisticValue.vue' +import TradeTrendValue from './components/TradeTrendValue.vue' +import { EChartsOption } from 'echarts' +import { + TradeStatisticsComparisonRespVO, + TradeSummaryRespVO, + TradeTrendReqVO, + TradeTrendSummaryRespVO +} from '@/api/statistics/trade' +import dayjs from 'dayjs' +import { fenToYuan } from '@/utils' +import * as DateUtil from '@/utils/formatTime' +import download from '@/utils/download' + +/** 交易统计 */ +defineOptions({ name: 'TradeStatistics' }) + +const message = useMessage() // 消息弹窗 + +const loading = ref(true) // 加载中 +const trendLoading = ref(true) // 交易状态加载中 +const exportLoading = ref(false) // 导出的加载中 +const queryParams = reactive<TradeTrendReqVO>({ times: ['', ''] }) // 交易状况查询参数 +const shortcutDays = ref(7) // 日期快捷天数(单选按钮组), 默认7天 +const summary = ref<TradeStatisticsComparisonRespVO<TradeSummaryRespVO>>() // 交易统计数据 +const trendSummary = ref<TradeStatisticsComparisonRespVO<TradeTrendSummaryRespVO>>() // 交易状况统计数据 + +/** 日期快捷选择 */ +const shortcuts = [ + { + text: '昨天', + value: () => DateUtil.getDayRange(new Date(), -1) + }, + { + text: '最近7天', + value: () => DateUtil.getLast7Days() + }, + { + text: '本月', + value: () => [dayjs().startOf('M'), dayjs().subtract(1, 'd')] + }, + { + text: '最近30天', + value: () => DateUtil.getLast30Days() + }, + { + text: '最近1年', + value: () => DateUtil.getLast1Year() + } +] + +/** 折线图配置 */ +const lineChartOptions = reactive<EChartsOption>({ + dataset: { + dimensions: ['date', 'turnover', 'orderPayPrice', 'rechargePrice', 'expensePrice'], + source: [] + }, + grid: { + left: 20, + right: 20, + bottom: 20, + top: 80, + containLabel: true + }, + legend: { + top: 50 + }, + series: [ + { name: '营业额', type: 'line', smooth: true }, + { name: '商品支付金额', type: 'line', smooth: true }, + { name: '充值金额', type: 'line', smooth: true }, + { name: '支出金额', type: 'line', smooth: true } + ], + 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', + boundaryGap: false, + axisTick: { + show: false + } + }, + yAxis: { + axisTick: { + show: false + } + } +}) as EChartsOption + +/** 计算环比 */ +const calculateRelativeRate = (value?: number, reference?: number) => { + // 防止除0 + if (!reference) return 0 + + return ((100 * ((value || 0) - reference)) / reference).toFixed(0) +} + +/** 设置时间范围 */ +function setTimes() { + const beginDate = dayjs().subtract(shortcutDays.value, 'd') + const yesterday = dayjs().subtract(1, 'd') + queryParams.times = DateUtil.getDateRange(beginDate, yesterday) +} + +/** 处理交易状况查询(日期单选按钮组选择后) */ +const handleDateTypeChange = async () => { + // 设置时间范围 + setTimes() + // 查询数据 + await getTradeTrendData() +} + +/** 处理交易状况查询 */ +const getTradeTrendData = async () => { + trendLoading.value = true + await Promise.all([getTradeTrendSummary(), getTradeTrendList()]) + trendLoading.value = false +} + +/** 查询交易统计 */ +const getTradeStatisticsSummary = async () => { + summary.value = await TradeStatisticsApi.getTradeStatisticsSummary() +} + +/** 查询交易状况数据统计 */ +const getTradeTrendSummary = async () => { + loading.value = true + trendSummary.value = await TradeStatisticsApi.getTradeTrendSummary(queryParams) + loading.value = false +} + +/** 查询交易状况数据列表 */ +const getTradeTrendList = async () => { + const times = queryParams.times + // 开始与截止在同一天的, 折线图出不来, 需要延长一天 + if (DateUtil.isSameDay(times[0], times[1])) { + // 前天 + times[0] = DateUtil.formatDate(dayjs(times[0]).subtract(1, 'd')) + } + // 查询数据 + const list = await TradeStatisticsApi.getTradeTrendList({ times }) + // 处理数据 + for (let item of list) { + item.turnover = fenToYuan(item.turnover) + item.orderPayPrice = fenToYuan(item.orderPayPrice) + item.rechargePrice = fenToYuan(item.rechargePrice) + item.expensePrice = fenToYuan(item.expensePrice) + } + // 更新 Echarts 数据 + if (lineChartOptions.dataset && lineChartOptions.dataset['source']) { + lineChartOptions.dataset['source'] = list + } +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await TradeStatisticsApi.exportTradeTrend(queryParams) + download.excel(data, '交易状况.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 初始化 **/ +onMounted(async () => { + await getTradeStatisticsSummary() + await handleDateTypeChange() +}) +</script> +<style lang="scss" scoped> +.summary { + .el-col { + margin-bottom: 1rem; + } +} +</style>