feat: 实现多商户管理模块与前端服务
refactor: 优化服务层代码并修复类型问题 docs: 更新开发进度文档 feat(merchant): 新增商户监控与数据统计服务 feat(dashboard): 添加商户管理前端页面与服务 fix: 修复类型转换与可选参数处理 feat: 实现商户订单、店铺与结算管理功能 refactor: 重构审计日志格式与服务调用 feat: 新增商户入驻与身份注册功能 fix(controller): 修复路由参数类型问题 feat: 添加商户排名与统计报告功能 chore: 更新模拟数据与服务配置
This commit is contained in:
204
server/src/services/MerchantDataStatisticsService.ts
Normal file
204
server/src/services/MerchantDataStatisticsService.ts
Normal file
@@ -0,0 +1,204 @@
|
||||
import { Knex } from 'knex';
|
||||
import { db } from '../database';
|
||||
|
||||
export class MerchantDataStatisticsService {
|
||||
/**
|
||||
* 统计多商户数据
|
||||
* @param params 统计参数
|
||||
* @param traceInfo 追踪信息
|
||||
* @returns 统计数据
|
||||
*/
|
||||
public static async statisticsMerchantData(
|
||||
params: {
|
||||
merchantId?: string;
|
||||
timeRange?: { start: string; end: string };
|
||||
metrics?: string[];
|
||||
},
|
||||
traceInfo: {
|
||||
tenantId: string;
|
||||
shopId: string;
|
||||
taskId: string;
|
||||
traceId: string;
|
||||
businessType: 'TOC' | 'TOB';
|
||||
}
|
||||
): Promise<{
|
||||
merchantId: string;
|
||||
timestamp: string;
|
||||
metrics: Record<string, any>;
|
||||
details: Array<{
|
||||
metric: string;
|
||||
value: number;
|
||||
unit: string;
|
||||
trend: 'up' | 'down' | 'stable';
|
||||
}>;
|
||||
}> {
|
||||
try {
|
||||
// 模拟数据库查询
|
||||
const merchantId = params.merchantId || 'all';
|
||||
const timestamp = new Date().toISOString();
|
||||
|
||||
// 构建统计指标
|
||||
const metrics = {
|
||||
totalOrders: Math.floor(Math.random() * 1000) + 100,
|
||||
totalSales: (Math.random() * 100000 + 10000).toFixed(2),
|
||||
averageOrderValue: (Math.random() * 500 + 100).toFixed(2),
|
||||
orderCompletionRate: (Math.random() * 30 + 70).toFixed(2),
|
||||
activeCustomers: Math.floor(Math.random() * 500) + 100,
|
||||
newCustomers: Math.floor(Math.random() * 100) + 20,
|
||||
};
|
||||
|
||||
const details = Object.entries(metrics).map(([metric, value]) => ({
|
||||
metric,
|
||||
value: typeof value === 'string' ? parseFloat(value) : value,
|
||||
unit: metric.includes('Rate') ? '%' : metric.includes('Sales') || metric.includes('Value') ? '¥' : '',
|
||||
trend: ['up', 'down', 'stable'][Math.floor(Math.random() * 3)] as 'up' | 'down' | 'stable',
|
||||
}));
|
||||
|
||||
return {
|
||||
merchantId,
|
||||
timestamp,
|
||||
metrics,
|
||||
details,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error statistics merchant data:', error);
|
||||
throw new Error('Failed to statistics merchant data');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成商户数据统计报告
|
||||
* @param params 报告参数
|
||||
* @param traceInfo 追踪信息
|
||||
* @returns 报告数据
|
||||
*/
|
||||
public static async generateStatisticsReport(
|
||||
params: {
|
||||
merchantId?: string;
|
||||
timeRange: { start: string; end: string };
|
||||
reportType: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly';
|
||||
},
|
||||
traceInfo: {
|
||||
tenantId: string;
|
||||
shopId: string;
|
||||
taskId: string;
|
||||
traceId: string;
|
||||
businessType: 'TOC' | 'TOB';
|
||||
}
|
||||
): Promise<{
|
||||
reportId: string;
|
||||
merchantId: string;
|
||||
reportType: string;
|
||||
timeRange: { start: string; end: string };
|
||||
timestamp: string;
|
||||
summary: string;
|
||||
metrics: Record<string, any>;
|
||||
recommendations: string[];
|
||||
}> {
|
||||
try {
|
||||
const reportId = `REPORT-${Date.now()}`;
|
||||
const merchantId = params.merchantId || 'all';
|
||||
const timestamp = new Date().toISOString();
|
||||
|
||||
// 生成统计数据
|
||||
const statistics = await this.statisticsMerchantData(params, traceInfo);
|
||||
|
||||
// 生成摘要
|
||||
const summary = `商户 ${merchantId} 在 ${params.timeRange.start} 至 ${params.timeRange.end} 期间的${this.getReportTypeName(params.reportType)}统计报告`;
|
||||
|
||||
// 生成建议
|
||||
const recommendations = [
|
||||
'建议优化产品定价策略,提高平均订单价值',
|
||||
'建议增加促销活动,吸引更多新客户',
|
||||
'建议改进客户服务,提高订单完成率',
|
||||
'建议分析销售数据,优化产品结构',
|
||||
];
|
||||
|
||||
return {
|
||||
reportId,
|
||||
merchantId,
|
||||
reportType: params.reportType,
|
||||
timeRange: params.timeRange,
|
||||
timestamp,
|
||||
summary,
|
||||
metrics: statistics.metrics,
|
||||
recommendations,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error generating statistics report:', error);
|
||||
throw new Error('Failed to generate statistics report');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商户排名
|
||||
* @param params 排名参数
|
||||
* @param traceInfo 追踪信息
|
||||
* @returns 排名数据
|
||||
*/
|
||||
public static async getMerchantRanking(
|
||||
params: {
|
||||
metric: 'sales' | 'orders' | 'customers' | 'completionRate';
|
||||
limit?: number;
|
||||
timeRange: { start: string; end: string };
|
||||
},
|
||||
traceInfo: {
|
||||
tenantId: string;
|
||||
shopId: string;
|
||||
taskId: string;
|
||||
traceId: string;
|
||||
businessType: 'TOC' | 'TOB';
|
||||
}
|
||||
): Promise<{
|
||||
metric: string;
|
||||
timeRange: { start: string; end: string };
|
||||
timestamp: string;
|
||||
rankings: Array<{
|
||||
rank: number;
|
||||
merchantId: string;
|
||||
merchantName: string;
|
||||
value: number;
|
||||
unit: string;
|
||||
}>;
|
||||
}> {
|
||||
try {
|
||||
const limit = params.limit || 10;
|
||||
const timestamp = new Date().toISOString();
|
||||
|
||||
// 模拟排名数据
|
||||
const rankings = Array.from({ length: limit }, (_, index) => ({
|
||||
rank: index + 1,
|
||||
merchantId: `MERCHANT-${index + 1}`,
|
||||
merchantName: `商户${index + 1}`,
|
||||
value: Math.floor(Math.random() * 100000) + 1000,
|
||||
unit: params.metric === 'completionRate' ? '%' : params.metric === 'customers' || params.metric === 'orders' ? '' : '¥',
|
||||
})).sort((a, b) => b.value - a.value);
|
||||
|
||||
return {
|
||||
metric: params.metric,
|
||||
timeRange: params.timeRange,
|
||||
timestamp,
|
||||
rankings,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error getting merchant ranking:', error);
|
||||
throw new Error('Failed to get merchant ranking');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取报告类型名称
|
||||
* @param reportType 报告类型
|
||||
* @returns 报告类型名称
|
||||
*/
|
||||
private static getReportTypeName(reportType: string): string {
|
||||
const typeNames = {
|
||||
daily: '每日',
|
||||
weekly: '每周',
|
||||
monthly: '每月',
|
||||
quarterly: '季度',
|
||||
yearly: '年度',
|
||||
};
|
||||
return typeNames[reportType as keyof typeof typeNames] || '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user