fix and add
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
This commit is contained in:
@@ -134,14 +134,14 @@ export namespace AgentApi {
|
|||||||
agent_id?: number;
|
agent_id?: number;
|
||||||
status?: number;
|
status?: number;
|
||||||
withdraw_no?: string;
|
withdraw_no?: string;
|
||||||
status?: number;
|
|
||||||
withdraw_no?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提现统计数据
|
// 提现统计数据
|
||||||
export interface WithdrawalStatistics {
|
export interface WithdrawalStatistics {
|
||||||
total_withdrawal_amount: number;
|
total_withdrawal_amount: number;
|
||||||
today_withdrawal_amount: number;
|
today_withdrawal_amount: number;
|
||||||
|
total_actual_amount: number;
|
||||||
|
total_tax_amount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 代理订单统计数据
|
// 代理订单统计数据
|
||||||
@@ -156,6 +156,20 @@ export interface AgentStatistics {
|
|||||||
today_agent_count: number; // 今日新增代理数
|
today_agent_count: number; // 今日新增代理数
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 代理链接产品统计项
|
||||||
|
export interface AgentLinkProductStatisticsItem {
|
||||||
|
product_name: string;
|
||||||
|
link_count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 代理链接产品统计响应
|
||||||
|
export interface AgentLinkProductStatisticsResp {
|
||||||
|
items: AgentLinkProductStatisticsItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 代理链接产品统计请求参数
|
||||||
|
export interface GetAgentLinkProductStatisticsParams {}
|
||||||
|
|
||||||
// 代理上级抽佣相关接口
|
// 代理上级抽佣相关接口
|
||||||
export interface AgentCommissionDeductionListItem {
|
export interface AgentCommissionDeductionListItem {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -517,10 +531,20 @@ async function getAgentStatistics() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取代理链接产品统计数据
|
||||||
|
*/
|
||||||
|
async function getAgentLinkProductStatistics() {
|
||||||
|
return requestClient.get<AgentApi.AgentLinkProductStatisticsResp>(
|
||||||
|
'/agent/agent-link/product-statistics',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getAgentCommissionDeductionList,
|
getAgentCommissionDeductionList,
|
||||||
getAgentCommissionList,
|
getAgentCommissionList,
|
||||||
getAgentLinkList,
|
getAgentLinkList,
|
||||||
|
getAgentLinkProductStatistics,
|
||||||
getAgentList,
|
getAgentList,
|
||||||
getAgentMembershipConfigList,
|
getAgentMembershipConfigList,
|
||||||
getAgentOrderStatistics,
|
getAgentOrderStatistics,
|
||||||
|
|||||||
28
apps/web-antd/src/api/order/order-statistics.ts
Normal file
28
apps/web-antd/src/api/order/order-statistics.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { requestClient } from '#/api/request';
|
||||||
|
|
||||||
|
export namespace OrderStatisticsApi {
|
||||||
|
// 订单统计数据项
|
||||||
|
export interface OrderStatisticsItem {
|
||||||
|
date: string; // 日期
|
||||||
|
count: number; // 订单数量
|
||||||
|
amount: number; // 订单金额
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单统计响应
|
||||||
|
export interface OrderStatisticsResponse {
|
||||||
|
items: OrderStatisticsItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时间维度类型
|
||||||
|
export type TimeDimension = 'day' | 'month' | 'year' | 'all';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取订单统计数据
|
||||||
|
* @param dimension 时间维度:day-日(当月1号到今天),month-月(今年1月到当月),year-年(过去5年),all-全部(按日统计)
|
||||||
|
*/
|
||||||
|
export function getOrderStatistics(dimension: OrderStatisticsApi.TimeDimension) {
|
||||||
|
return requestClient.get<OrderStatisticsApi.OrderStatisticsResponse>('/order/statistics', {
|
||||||
|
params: { dimension }
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -49,6 +49,12 @@ export namespace OrderApi {
|
|||||||
total_profit_amount: number;
|
total_profit_amount: number;
|
||||||
today_profit_amount: number;
|
today_profit_amount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 订单来源统计数据
|
||||||
|
export interface OrderSourceStatistics {
|
||||||
|
product_name: string;
|
||||||
|
order_count: number;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,4 +92,11 @@ async function getIncomeStatistics() {
|
|||||||
return requestClient.get<OrderApi.IncomeStatistics>('/order/revenue-statistics');
|
return requestClient.get<OrderApi.IncomeStatistics>('/order/revenue-statistics');
|
||||||
}
|
}
|
||||||
|
|
||||||
export { getOrderList, refundOrder, getRefundStatistics, getIncomeStatistics };
|
/**
|
||||||
|
* 获取订单来源统计数据
|
||||||
|
*/
|
||||||
|
async function getOrderSourceStatistics() {
|
||||||
|
return requestClient.get<{ items: OrderApi.OrderSourceStatistics[] }>('/order/source-statistics');
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getOrderList, refundOrder, getRefundStatistics, getIncomeStatistics, getOrderSourceStatistics };
|
||||||
|
|||||||
@@ -4,63 +4,91 @@ import type { EchartsUIType } from '@vben/plugins/echarts';
|
|||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
|
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
|
||||||
|
import { getOrderSourceStatistics } from '#/api/order/order';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
// 获取订单来源统计数据
|
||||||
|
async function fetchOrderSourceStatistics() {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const response = await getOrderSourceStatistics();
|
||||||
|
|
||||||
|
// 提取产品名称和订单数量
|
||||||
|
const data = response.items.map(item => ({
|
||||||
|
name: item.product_name,
|
||||||
|
value: item.order_count,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 如果有数据,则渲染图表
|
||||||
|
if (data && data.length > 0) {
|
||||||
|
renderEcharts({
|
||||||
|
legend: {
|
||||||
|
bottom: '2%',
|
||||||
|
left: 'center',
|
||||||
|
data: data.map(item => item.name),
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
animationDelay() {
|
||||||
|
return Math.random() * 100;
|
||||||
|
},
|
||||||
|
animationEasing: 'exponentialInOut',
|
||||||
|
animationType: 'scale',
|
||||||
|
avoidLabelOverlap: false,
|
||||||
|
color: [
|
||||||
|
'#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9',
|
||||||
|
'#ffb980', '#d87a80', '#8d98b3', '#e5cf0d',
|
||||||
|
'#97b552', '#95706d', '#dc69aa', '#07a2a4',
|
||||||
|
'#9a7fd1', '#588dd5', '#f5994e', '#c05050'
|
||||||
|
],
|
||||||
|
data: data,
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
fontSize: '12',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: 10,
|
||||||
|
borderWidth: 2,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
position: 'center',
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
name: '订单来源',
|
||||||
|
radius: ['40%', '65%'],
|
||||||
|
type: 'pie',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: '{b}: {c} ({d}%)',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取订单来源统计数据失败:', error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
renderEcharts({
|
fetchOrderSourceStatistics();
|
||||||
legend: {
|
|
||||||
bottom: '2%',
|
|
||||||
left: 'center',
|
|
||||||
data: ['产品A', '产品B', '产品C', '产品D'],
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
animationDelay() {
|
|
||||||
return Math.random() * 100;
|
|
||||||
},
|
|
||||||
animationEasing: 'exponentialInOut',
|
|
||||||
animationType: 'scale',
|
|
||||||
avoidLabelOverlap: false,
|
|
||||||
color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
|
|
||||||
data: [
|
|
||||||
{ name: '产品A', value: 1048 },
|
|
||||||
{ name: '产品B', value: 735 },
|
|
||||||
{ name: '产品C', value: 580 },
|
|
||||||
{ name: '产品D', value: 484 },
|
|
||||||
],
|
|
||||||
emphasis: {
|
|
||||||
label: {
|
|
||||||
fontSize: '12',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
show: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
itemStyle: {
|
|
||||||
// borderColor: '#fff',
|
|
||||||
borderRadius: 10,
|
|
||||||
borderWidth: 2,
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
position: 'center',
|
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
labelLine: {
|
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
name: '订单来源',
|
|
||||||
radius: ['40%', '65%'],
|
|
||||||
type: 'pie',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'item',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<EchartsUI ref="chartRef" />
|
<div v-if="loading" class="flex justify-center items-center h-64">
|
||||||
|
加载中...
|
||||||
|
</div>
|
||||||
|
<EchartsUI v-else ref="chartRef" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,59 +1,59 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { EchartsUIType } from '@vben/plugins/echarts';
|
import type { EchartsUIType } from '@vben/plugins/echarts';
|
||||||
|
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
|
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
|
||||||
|
import { Button } from 'ant-design-vue';
|
||||||
import { getOrderList } from '#/api/order/order';
|
import { getOrderStatistics } from '#/api/order/order-statistics';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
|
||||||
|
// 时间维度状态
|
||||||
|
const timeDimension = ref<'day' | 'month' | 'year' | 'all'>('day');
|
||||||
|
|
||||||
onMounted(async () => {
|
// 获取订单统计数据
|
||||||
|
async function fetchOrderStatistics() {
|
||||||
try {
|
try {
|
||||||
// 准备图表数据
|
console.log('Fetching order statistics with dimension:', timeDimension.value);
|
||||||
const dates = Array.from({ length: 30 }).map((_, index) => {
|
|
||||||
const date = new Date();
|
|
||||||
date.setDate(date.getDate() - 29 + index);
|
|
||||||
return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' });
|
|
||||||
});
|
|
||||||
|
|
||||||
// 准备日期数组,用于查询订单数据
|
// 使用后端API获取数据
|
||||||
const queryDates = Array.from({ length: 30 }).map((_, index) => {
|
const response = await getOrderStatistics(timeDimension.value);
|
||||||
const date = new Date();
|
console.log('Order statistics response:', response);
|
||||||
date.setDate(date.getDate() - 29 + index);
|
|
||||||
return date.toISOString().split('T')[0]; // YYYY-MM-DD格式
|
|
||||||
});
|
|
||||||
|
|
||||||
// 获取每日订单数据
|
let items = response.items || [];
|
||||||
const orderDataPromises = queryDates.map(async (date) => {
|
|
||||||
try {
|
// 如果后端返回空数据,显示空状态
|
||||||
// 获取当天的开始和结束时间
|
if (items.length === 0) {
|
||||||
const startTime = `${date} 00:00:00`;
|
console.log('No data from backend, showing empty chart');
|
||||||
const endTime = `${date} 23:59:59`;
|
items = [];
|
||||||
|
}
|
||||||
// 获取当天的订单数据
|
|
||||||
const response = await getOrderList({
|
console.log('Items for chart:', items);
|
||||||
page: 1,
|
|
||||||
pageSize: 1,
|
// 按日期排序
|
||||||
create_time_start: startTime,
|
items.sort((a: any, b: any) => a.date.localeCompare(b.date));
|
||||||
create_time_end: endTime
|
|
||||||
});
|
// 提取日期和数量
|
||||||
|
const dates = items.map((item: any) => {
|
||||||
return response.total || 0;
|
// 根据时间维度格式化日期显示
|
||||||
} catch (error) {
|
const date = new Date(item.date);
|
||||||
console.error(`获取${date}的订单数据失败:`, error);
|
if (timeDimension.value === 'year') {
|
||||||
return 0;
|
return `${date.getFullYear()}`;
|
||||||
|
} else if (timeDimension.value === 'month') {
|
||||||
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
|
||||||
|
} else {
|
||||||
|
return `${date.getMonth() + 1}-${String(date.getDate()).padStart(2, '0')}`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 等待所有请求完成
|
const orderData = items.map((item: any) => item.count);
|
||||||
const orderData = await Promise.all(orderDataPromises);
|
const amountData = items.map((item: any) => item.amount);
|
||||||
|
|
||||||
// 计算Y轴最大值
|
// 计算Y轴最大值
|
||||||
const maxValue = Math.max(...orderData) || 10;
|
const maxOrderValue = Math.max(...orderData) || 10;
|
||||||
|
const maxAmountValue = Math.max(...amountData) || 10;
|
||||||
|
|
||||||
renderEcharts({
|
renderEcharts({
|
||||||
grid: {
|
grid: {
|
||||||
@@ -61,7 +61,11 @@ onMounted(async () => {
|
|||||||
containLabel: true,
|
containLabel: true,
|
||||||
left: '1%',
|
left: '1%',
|
||||||
right: '1%',
|
right: '1%',
|
||||||
top: '2%',
|
top: '10%',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['订单数', '订单金额'],
|
||||||
|
top: 0,
|
||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
@@ -77,6 +81,19 @@ onMounted(async () => {
|
|||||||
color: '#4f9cff',
|
color: '#4f9cff',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
data: amountData,
|
||||||
|
type: 'line',
|
||||||
|
name: '订单金额',
|
||||||
|
smooth: true,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#52c41a',
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
opacity: 0.3,
|
||||||
|
color: '#52c41a',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
tooltip: {
|
tooltip: {
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
@@ -86,8 +103,15 @@ onMounted(async () => {
|
|||||||
},
|
},
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
formatter: (params: any) => {
|
formatter: (params: any) => {
|
||||||
const param = params[0];
|
let result = `${params[0].axisValue}<br/>`;
|
||||||
return `${param.axisValue}<br/>${param.seriesName}: ${param.value}`;
|
params.forEach((param: any) => {
|
||||||
|
if (param.seriesName === '订单金额') {
|
||||||
|
result += `${param.seriesName}: ¥${param.value.toFixed(2)}<br/>`;
|
||||||
|
} else {
|
||||||
|
result += `${param.seriesName}: ${param.value}<br/>`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
@@ -95,11 +119,22 @@ onMounted(async () => {
|
|||||||
type: 'category',
|
type: 'category',
|
||||||
boundaryGap: false,
|
boundaryGap: false,
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: [
|
||||||
max: Math.ceil(maxValue * 1.2), // 比最大值大20%作为Y轴上限
|
{
|
||||||
splitNumber: 4,
|
type: 'value',
|
||||||
type: 'value',
|
name: '订单数',
|
||||||
},
|
position: 'left',
|
||||||
|
max: Math.ceil(maxOrderValue * 1.2),
|
||||||
|
splitNumber: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: '金额(¥)',
|
||||||
|
position: 'right',
|
||||||
|
max: Math.ceil(maxAmountValue * 1.2),
|
||||||
|
splitNumber: 4,
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取订单趋势数据失败:', error);
|
console.error('获取订单趋势数据失败:', error);
|
||||||
@@ -111,7 +146,11 @@ onMounted(async () => {
|
|||||||
containLabel: true,
|
containLabel: true,
|
||||||
left: '1%',
|
left: '1%',
|
||||||
right: '1%',
|
right: '1%',
|
||||||
top: '2%',
|
top: '10%',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['订单数', '订单金额'],
|
||||||
|
top: 0,
|
||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
@@ -127,6 +166,19 @@ onMounted(async () => {
|
|||||||
color: '#4f9cff',
|
color: '#4f9cff',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
data: Array(30).fill(0),
|
||||||
|
type: 'line',
|
||||||
|
name: '订单金额',
|
||||||
|
smooth: true,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#52c41a',
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
opacity: 0.3,
|
||||||
|
color: '#52c41a',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
tooltip: {
|
tooltip: {
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
@@ -145,16 +197,66 @@ onMounted(async () => {
|
|||||||
type: 'category',
|
type: 'category',
|
||||||
boundaryGap: false,
|
boundaryGap: false,
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: [
|
||||||
max: 10,
|
{
|
||||||
splitNumber: 4,
|
type: 'value',
|
||||||
type: 'value',
|
name: '订单数',
|
||||||
},
|
position: 'left',
|
||||||
|
max: 10,
|
||||||
|
splitNumber: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: '金额(¥)',
|
||||||
|
position: 'right',
|
||||||
|
max: 10,
|
||||||
|
splitNumber: 4,
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 组件挂载时获取数据
|
||||||
|
onMounted(() => {
|
||||||
|
fetchOrderStatistics();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听时间维度变化
|
||||||
|
watch(timeDimension, () => {
|
||||||
|
fetchOrderStatistics();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<EchartsUI ref="chartRef" />
|
<div>
|
||||||
</template>
|
<div class="mb-4 flex justify-end space-x-2">
|
||||||
|
<Button
|
||||||
|
:type="timeDimension === 'day' ? 'primary' : 'default'"
|
||||||
|
@click="timeDimension = 'day'"
|
||||||
|
>
|
||||||
|
日
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
:type="timeDimension === 'month' ? 'primary' : 'default'"
|
||||||
|
@click="timeDimension = 'month'"
|
||||||
|
>
|
||||||
|
月
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
:type="timeDimension === 'year' ? 'primary' : 'default'"
|
||||||
|
@click="timeDimension = 'year'"
|
||||||
|
>
|
||||||
|
年
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
:type="timeDimension === 'all' ? 'primary' : 'default'"
|
||||||
|
@click="timeDimension = 'all'"
|
||||||
|
>
|
||||||
|
全部
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<EchartsUI ref="chartRef" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -22,7 +22,7 @@ import AnalyticsVisitsSales from './analytics-visits-sales.vue';
|
|||||||
import AnalyticsVisitsSource from './analytics-visits-source.vue';
|
import AnalyticsVisitsSource from './analytics-visits-source.vue';
|
||||||
import AnalyticsVisits from './analytics-visits.vue';
|
import AnalyticsVisits from './analytics-visits.vue';
|
||||||
|
|
||||||
import { getAgentList, getAgentStatistics, getWithdrawalStatistics, getAgentOrderStatistics } from '#/api/agent';
|
import { getAgentStatistics, getWithdrawalStatistics, getAgentOrderStatistics } from '#/api/agent';
|
||||||
import { getOrderList, getRefundStatistics, getIncomeStatistics } from '#/api/order/order';
|
import { getOrderList, getRefundStatistics, getIncomeStatistics } from '#/api/order/order';
|
||||||
import { getPlatformUserList } from '#/api/platform-user';
|
import { getPlatformUserList } from '#/api/platform-user';
|
||||||
|
|
||||||
@@ -63,26 +63,30 @@ const overviewItems = ref<AnalysisOverviewItem[]>([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: SvgBellIcon,
|
icon: SvgBellIcon,
|
||||||
title: '总提现金额',
|
title: '总提现金额',
|
||||||
value: 0,
|
value: 0,
|
||||||
todaytitle: '今日新增提现金额',
|
SubValue: 0,
|
||||||
todayValue: 0,
|
todaySubtitle: '总实际到账金额',
|
||||||
Subtitle: '总退款金额',
|
todaySubValue: 0,
|
||||||
SubValue: 0,
|
extraTitle: '总扣税金额',
|
||||||
todaySubtitle: '今日新增退款金额',
|
extraValue: 0,
|
||||||
todaySubValue: 0,
|
todaytitle: '今日新增提现金额',
|
||||||
|
todayValue: 0,
|
||||||
|
Subtitle: '总退款金额',
|
||||||
|
extra2Title: '今日新增退款金额',
|
||||||
|
extra2Value: 0,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const chartTabs: TabOption[] = [
|
const chartTabs: TabOption[] = [
|
||||||
{
|
|
||||||
label: '推广访问趋势',
|
|
||||||
value: 'trends',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '订单趋势',
|
label: '订单趋势',
|
||||||
value: 'visits',
|
value: 'visits',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '推广访问趋势',
|
||||||
|
value: 'trends',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// 获取统计数据
|
// 获取统计数据
|
||||||
@@ -138,6 +142,8 @@ async function fetchStatistics() {
|
|||||||
const withdrawalStatsResponse = await getWithdrawalStatistics();
|
const withdrawalStatsResponse = await getWithdrawalStatistics();
|
||||||
const totalWithdrawalAmount = withdrawalStatsResponse.total_withdrawal_amount || 0;
|
const totalWithdrawalAmount = withdrawalStatsResponse.total_withdrawal_amount || 0;
|
||||||
const todayWithdrawalAmount = withdrawalStatsResponse.today_withdrawal_amount || 0;
|
const todayWithdrawalAmount = withdrawalStatsResponse.today_withdrawal_amount || 0;
|
||||||
|
const totalActualAmount = withdrawalStatsResponse.total_actual_amount || 0;
|
||||||
|
const totalTaxAmount = withdrawalStatsResponse.total_tax_amount || 0;
|
||||||
|
|
||||||
// 获取退款统计数据
|
// 获取退款统计数据
|
||||||
const refundStatsResponse = await getRefundStatistics();
|
const refundStatsResponse = await getRefundStatistics();
|
||||||
@@ -192,10 +198,14 @@ async function fetchStatistics() {
|
|||||||
value: totalWithdrawalAmount,
|
value: totalWithdrawalAmount,
|
||||||
todaytitle: '今日新增提现金额',
|
todaytitle: '今日新增提现金额',
|
||||||
todayValue: todayWithdrawalAmount,
|
todayValue: todayWithdrawalAmount,
|
||||||
|
extra2Title: '今日新增退款金额',
|
||||||
|
extra2Value: todayRefundAmount,
|
||||||
Subtitle: '总退款金额',
|
Subtitle: '总退款金额',
|
||||||
SubValue: totalRefundAmount,
|
SubValue: totalRefundAmount,
|
||||||
todaySubtitle: '今日新增退款金额',
|
todaySubtitle: '总实际到账金额',
|
||||||
todaySubValue: todayRefundAmount,
|
todaySubValue: totalActualAmount,
|
||||||
|
extraTitle: '总扣税金额',
|
||||||
|
extraValue: totalTaxAmount,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -213,12 +223,12 @@ onMounted(() => {
|
|||||||
<div class="p-5">
|
<div class="p-5">
|
||||||
<AnalysisOverview :items="overviewItems" />
|
<AnalysisOverview :items="overviewItems" />
|
||||||
<AnalysisChartsTabs :tabs="chartTabs" class="mt-5">
|
<AnalysisChartsTabs :tabs="chartTabs" class="mt-5">
|
||||||
<template #trends>
|
|
||||||
<AnalyticsTrends />
|
|
||||||
</template>
|
|
||||||
<template #visits>
|
<template #visits>
|
||||||
<AnalyticsVisits />
|
<AnalyticsVisits />
|
||||||
</template>
|
</template>
|
||||||
|
<template #trends>
|
||||||
|
<AnalyticsTrends />
|
||||||
|
</template>
|
||||||
</AnalysisChartsTabs>
|
</AnalysisChartsTabs>
|
||||||
|
|
||||||
<div class="mt-5 w-full md:flex">
|
<div class="mt-5 w-full md:flex">
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ withDefaults(defineProps<Props>(), {
|
|||||||
<Card v-for="(item, index) in items" :key="index" class="relative overflow-hidden">
|
<Card v-for="(item, index) in items" :key="index" class="relative overflow-hidden">
|
||||||
<CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
|
<CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<CardTitle class="text-sm font-medium">
|
<CardTitle class="text-sm font-medium">
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<VbenIcon :icon="item.icon" class="h-4 w-4 text-muted-foreground" />
|
<VbenIcon :icon="item.icon" class="h-4 w-4 text-muted-foreground" />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div class="text-2xl font-bold">
|
<div class="text-2xl font-bold">
|
||||||
<VbenCountToAnimator :end-val="item.value" />
|
<VbenCountToAnimator :end-val="item.value" />
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs text-muted-foreground">
|
<p class="text-xs text-muted-foreground">
|
||||||
{{ item.todaytitle }}
|
{{ item.todaytitle }}
|
||||||
@@ -50,11 +50,23 @@ withDefaults(defineProps<Props>(), {
|
|||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="text-xs text-muted-foreground flex justify-between mt-1">
|
<p class="text-xs text-muted-foreground flex justify-between mt-1">
|
||||||
<span>{{ item.todaySubtitle }}</span>
|
<span>{{ item.todaySubtitle }}</span>
|
||||||
<span class="font-medium text-foreground">
|
<span class="font-medium text-foreground">
|
||||||
+<VbenCountToAnimator :end-val="item.todaySubValue" />
|
+<VbenCountToAnimator :end-val="item.todaySubValue" />
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
|
<p v-if="item.extraTitle" class="text-xs text-muted-foreground flex justify-between mt-1">
|
||||||
|
<span>{{ item.extraTitle }}</span>
|
||||||
|
<span class="font-medium text-foreground">
|
||||||
|
<VbenCountToAnimator :end-val="item.extraValue || 0" />
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p v-if="item.extra2Title" class="text-xs text-muted-foreground flex justify-between mt-1">
|
||||||
|
<span>{{ item.extra2Title }}</span>
|
||||||
|
<span class="font-medium text-foreground">
|
||||||
|
+<VbenCountToAnimator :end-val="item.extra2Value || 0" />
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ interface AnalysisOverviewItem {
|
|||||||
SubValue: number;
|
SubValue: number;
|
||||||
todaySubtitle: string;
|
todaySubtitle: string;
|
||||||
todaySubValue: number;
|
todaySubValue: number;
|
||||||
|
extraTitle?: string;
|
||||||
|
extraValue?: number;
|
||||||
|
extra2Title?: string;
|
||||||
|
extra2Value?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WorkbenchProjectItem {
|
interface WorkbenchProjectItem {
|
||||||
|
|||||||
Reference in New Issue
Block a user