|
|
@@ -7,6 +7,7 @@ export interface TimeFilterParams {
|
|
|
endDate?: string;
|
|
|
timeRange?: 'today' | 'yesterday' | 'last7days' | 'last30days' | 'thisYear' | 'lastYear' | 'custom';
|
|
|
year?: number; // 特定年份,例如2024, 2025
|
|
|
+ forceRefresh?: boolean; // 强制刷新,跳过缓存直接读取数据库
|
|
|
}
|
|
|
|
|
|
export interface SummaryStatistics {
|
|
|
@@ -16,8 +17,6 @@ export interface SummaryStatistics {
|
|
|
wechatOrders: number;
|
|
|
creditSales: number;
|
|
|
creditOrders: number;
|
|
|
- todaySales: number;
|
|
|
- todayOrders: number;
|
|
|
}
|
|
|
|
|
|
export interface UserConsumptionItem {
|
|
|
@@ -45,6 +44,7 @@ export interface PaginationParams {
|
|
|
limit?: number;
|
|
|
sortBy?: 'totalSpent' | 'orderCount' | 'avgOrderAmount' | 'lastOrderDate';
|
|
|
sortOrder?: 'asc' | 'desc';
|
|
|
+ forceRefresh?: boolean; // 强制刷新,跳过缓存直接读取数据库
|
|
|
}
|
|
|
|
|
|
export class DataOverviewServiceMt {
|
|
|
@@ -113,16 +113,18 @@ export class DataOverviewServiceMt {
|
|
|
// 生成缓存键
|
|
|
const cacheKey = `data_overview:summary:${tenantId}:${params.timeRange || 'today'}:${params.startDate || ''}:${params.endDate || ''}`;
|
|
|
|
|
|
- // 尝试从缓存获取
|
|
|
- const cached = await this.redisUtil.get(cacheKey);
|
|
|
- if (cached) {
|
|
|
- return JSON.parse(cached);
|
|
|
+ // 尝试从缓存获取(除非强制刷新)
|
|
|
+ if (!params.forceRefresh) {
|
|
|
+ const cached = await this.redisUtil.get(cacheKey);
|
|
|
+ if (cached) {
|
|
|
+ return JSON.parse(cached);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
const { startDate, endDate } = this.getDateRange(params);
|
|
|
|
|
|
// 执行统计查询
|
|
|
- const statistics = await this.calculateStatistics(tenantId, startDate, endDate);
|
|
|
+ const statistics = await this.calculateStatistics(tenantId, startDate, endDate, params.forceRefresh);
|
|
|
|
|
|
// 设置缓存:今日数据5分钟,历史数据30分钟
|
|
|
const isToday = params.timeRange === 'today' || (!params.timeRange && !params.startDate && !params.endDate);
|
|
|
@@ -135,15 +137,15 @@ export class DataOverviewServiceMt {
|
|
|
/**
|
|
|
* 计算统计数据
|
|
|
*/
|
|
|
- private async calculateStatistics(tenantId: number, startDate: Date, endDate: Date): Promise<SummaryStatistics> {
|
|
|
+ private async calculateStatistics(tenantId: number, startDate: Date, endDate: Date, forceRefresh: boolean = false): Promise<SummaryStatistics> {
|
|
|
// 使用TypeORM查询构建器进行统计
|
|
|
const queryBuilder = this.orderRepository.createQueryBuilder('order')
|
|
|
.select([
|
|
|
'COUNT(*) as total_orders',
|
|
|
- 'SUM(order.amount) as total_sales',
|
|
|
- 'SUM(CASE WHEN order.payType = :wechatPayType THEN order.amount ELSE 0 END) as wechat_sales',
|
|
|
- 'SUM(CASE WHEN order.payType = :creditPayType THEN order.amount ELSE 0 END) as credit_sales',
|
|
|
- 'COUNT(CASE WHEN order.payType = :wechatPayType THEN 1 END) as wechat_orders',
|
|
|
+ 'SUM(order.payAmount) as total_sales',
|
|
|
+ 'SUM(CASE WHEN order.payType != :creditPayType THEN order.payAmount ELSE 0 END) as wechat_sales',
|
|
|
+ 'SUM(CASE WHEN order.payType = :creditPayType THEN order.payAmount ELSE 0 END) as credit_sales',
|
|
|
+ 'COUNT(CASE WHEN order.payType != :creditPayType THEN 1 END) as wechat_orders',
|
|
|
'COUNT(CASE WHEN order.payType = :creditPayType THEN 1 END) as credit_orders'
|
|
|
])
|
|
|
.where('order.tenantId = :tenantId', { tenantId })
|
|
|
@@ -151,36 +153,33 @@ export class DataOverviewServiceMt {
|
|
|
.andWhere('order.cancelTime IS NULL') // 排除已取消的订单
|
|
|
.andWhere('order.createdAt BETWEEN :startDate AND :endDate', { startDate, endDate })
|
|
|
.setParameters({
|
|
|
- wechatPayType: 1, // 1=积分支付(假设为微信支付)
|
|
|
- creditPayType: 3 // 3=额度支付(假设为信用支付)
|
|
|
+ creditPayType: 3 // 3=额度支付
|
|
|
});
|
|
|
|
|
|
const result = await queryBuilder.getRawOne();
|
|
|
|
|
|
- // 计算今日数据(单独查询以提高性能)
|
|
|
- const todayStats = await this.getTodayStatistics(tenantId);
|
|
|
-
|
|
|
return {
|
|
|
totalSales: Number(result?.total_sales || 0),
|
|
|
totalOrders: Number(result?.total_orders || 0),
|
|
|
wechatSales: Number(result?.wechat_sales || 0),
|
|
|
wechatOrders: Number(result?.wechat_orders || 0),
|
|
|
creditSales: Number(result?.credit_sales || 0),
|
|
|
- creditOrders: Number(result?.credit_orders || 0),
|
|
|
- todaySales: todayStats.todaySales,
|
|
|
- todayOrders: todayStats.todayOrders
|
|
|
+ creditOrders: Number(result?.credit_orders || 0)
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取今日实时统计数据
|
|
|
*/
|
|
|
- async getTodayStatistics(tenantId: number): Promise<{ todaySales: number; todayOrders: number }> {
|
|
|
+ async getTodayStatistics(tenantId: number, forceRefresh: boolean = false): Promise<{ todaySales: number; todayOrders: number }> {
|
|
|
const cacheKey = `data_overview:today:${tenantId}:${new Date().toISOString().split('T')[0]}`;
|
|
|
|
|
|
- const cached = await this.redisUtil.get(cacheKey);
|
|
|
- if (cached) {
|
|
|
- return JSON.parse(cached);
|
|
|
+ // 尝试从缓存获取(除非强制刷新)
|
|
|
+ if (!forceRefresh) {
|
|
|
+ const cached = await this.redisUtil.get(cacheKey);
|
|
|
+ if (cached) {
|
|
|
+ return JSON.parse(cached);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
const todayStart = new Date();
|
|
|
@@ -190,7 +189,7 @@ export class DataOverviewServiceMt {
|
|
|
const queryBuilder = this.orderRepository.createQueryBuilder('order')
|
|
|
.select([
|
|
|
'COUNT(*) as today_orders',
|
|
|
- 'SUM(order.amount) as today_sales'
|
|
|
+ 'SUM(order.payAmount) as today_sales'
|
|
|
])
|
|
|
.where('order.tenantId = :tenantId', { tenantId })
|
|
|
.andWhere('order.payState = :payState', { payState: 2 }) // 2=支付成功
|
|
|
@@ -231,10 +230,12 @@ export class DataOverviewServiceMt {
|
|
|
// 生成缓存键
|
|
|
const cacheKey = `data_overview:user_consumption:${tenantId}:${params.timeRange || 'all'}:${params.startDate || ''}:${params.endDate || ''}:${paginationParams.page || 1}:${paginationParams.limit || 10}:${paginationParams.sortBy || 'totalSpent'}:${paginationParams.sortOrder || 'desc'}`;
|
|
|
|
|
|
- // 尝试从缓存获取
|
|
|
- const cached = await this.redisUtil.get(cacheKey);
|
|
|
- if (cached) {
|
|
|
- return JSON.parse(cached);
|
|
|
+ // 尝试从缓存获取(除非强制刷新)
|
|
|
+ if (!paginationParams.forceRefresh) {
|
|
|
+ const cached = await this.redisUtil.get(cacheKey);
|
|
|
+ if (cached) {
|
|
|
+ return JSON.parse(cached);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
const { startDate, endDate } = this.getDateRange(params);
|
|
|
@@ -296,9 +297,9 @@ export class DataOverviewServiceMt {
|
|
|
'order.userId as userId',
|
|
|
'MAX(user.name) as userName', // 关联用户表获取用户名
|
|
|
'MAX(user.phone) as userPhone', // 关联用户表获取手机号
|
|
|
- 'SUM(order.amount) as totalSpent',
|
|
|
+ 'SUM(order.payAmount) as totalSpent',
|
|
|
'COUNT(order.id) as orderCount',
|
|
|
- 'AVG(order.amount) as avgOrderAmount',
|
|
|
+ 'AVG(order.payAmount) as avgOrderAmount',
|
|
|
'MAX(order.createdAt) as lastOrderDate'
|
|
|
])
|
|
|
.leftJoin('order.user', 'user') // 关联用户表
|
|
|
@@ -331,11 +332,11 @@ export class DataOverviewServiceMt {
|
|
|
*/
|
|
|
private getSortField(sortBy: string): string {
|
|
|
const sortMap: Record<string, string> = {
|
|
|
- 'totalSpent': 'SUM(order.amount)',
|
|
|
+ 'totalSpent': 'SUM(order.payAmount)',
|
|
|
'orderCount': 'COUNT(order.id)',
|
|
|
- 'avgOrderAmount': 'AVG(order.amount)',
|
|
|
+ 'avgOrderAmount': 'AVG(order.payAmount)',
|
|
|
'lastOrderDate': 'MAX(order.createdAt)'
|
|
|
};
|
|
|
- return sortMap[sortBy] || 'SUM(order.amount)';
|
|
|
+ return sortMap[sortBy] || 'SUM(order.payAmount)';
|
|
|
}
|
|
|
}
|