feat: 实现前端组件库和API服务基础架构

refactor: 移除废弃的AGI策略演进服务

fix: 修正磁盘I/O指标字段命名

chore: 更新项目依赖版本

test: 添加前后端集成测试用例

docs: 更新AI模块接口文档

style: 统一审计日志字段命名规范

perf: 优化Redis订阅连接错误处理

build: 配置多项目工作区结构

ci: 添加Vite开发服务器CORS支持
This commit is contained in:
2026-03-18 15:22:55 +08:00
parent b31591e04c
commit c932a67be2
96 changed files with 37748 additions and 16326 deletions

View File

@@ -0,0 +1,566 @@
import { Injectable, Logger } from '@nestjs/common';
import { Order, Return, Product } from '@prisma/client';
import { PrismaService } from '../../config/database';
interface ReturnData {
id: string;
orderId: string;
productId: string;
skuId: string;
reason: string;
description: string;
status: 'PENDING' | 'APPROVED' | 'REJECTED';
createdAt: Date;
updatedAt: Date;
}
interface ProductData {
id: string;
name: string;
sku: string;
category: string;
price: number;
createdAt: Date;
updatedAt: Date;
}
interface ReturnAnalysisResult {
skuId: string;
productName: string;
returnRate: number;
totalReturns: number;
totalOrders: number;
primaryReasons: {
reason: string;
count: number;
percentage: number;
}[];
temporalAnalysis: {
period: string;
returnRate: number;
orderCount: number;
returnCount: number;
}[];
recommendations: string[];
riskLevel: 'low' | 'medium' | 'high';
}
@Injectable()
export class ReturnAnalysisService {
private readonly logger = new Logger(ReturnAnalysisService.name);
constructor(private readonly prisma: PrismaService) {}
/**
* 分析SKU退货原因
* @param skuId SKU ID
* @param traceId 链路追踪ID
* @returns 退货分析结果
*/
async analyzeReturnReasons(skuId: string, traceId: string): Promise<ReturnAnalysisResult> {
this.logger.log(`开始分析SKU退货原因: ${skuId}`, { traceId, skuId });
try {
// 获取SKU相关的退货数据
const returns = await this.prisma.return.findMany({
where: { skuId },
include: {
order: {
include: {
product: true,
},
},
},
});
// 获取SKU相关的订单数据
const orders = await this.prisma.order.findMany({
where: {
items: {
some: {
skuId,
},
},
},
});
// 获取商品信息
const product = await this.prisma.product.findFirst({
where: {
skus: {
some: {
id: skuId,
},
},
},
});
if (!product) {
throw new Error(`SKU对应的商品不存在: ${skuId}`);
}
// 计算退货率
const totalOrders = orders.length;
const totalReturns = returns.length;
const returnRate = totalOrders > 0 ? (totalReturns / totalOrders) * 100 : 0;
// 分析主要退货原因
const primaryReasons = this.analyzePrimaryReasons(returns);
// 时间趋势分析
const temporalAnalysis = this.analyzeTemporalTrends(returns, orders);
// 生成建议
const recommendations = this.generateRecommendations({
returnRate,
primaryReasons,
temporalAnalysis,
product,
});
// 评估风险等级
const riskLevel = this.assessRiskLevel(returnRate);
const result: ReturnAnalysisResult = {
skuId,
productName: product.name,
returnRate: Math.round(returnRate * 100) / 100,
totalReturns,
totalOrders,
primaryReasons,
temporalAnalysis,
recommendations,
riskLevel,
};
this.logger.log(`SKU退货原因分析完成: ${skuId}, 退货率: ${returnRate}%`, { traceId, result });
return result;
} catch (error) {
this.logger.error(`SKU退货原因分析失败: ${error.message}`, { traceId, skuId, error });
throw error;
}
}
/**
* 批量分析SKU退货原因
* @param skuIds SKU ID列表
* @param traceId 链路追踪ID
* @returns 退货分析结果列表
*/
async batchAnalyzeReturnReasons(skuIds: string[], traceId: string): Promise<ReturnAnalysisResult[]> {
this.logger.log(`开始批量分析SKU退货原因, 数量: ${skuIds.length}`, { traceId });
const results: ReturnAnalysisResult[] = [];
for (const skuId of skuIds) {
try {
const result = await this.analyzeReturnReasons(skuId, traceId);
results.push(result);
} catch (error) {
this.logger.error(`批量分析SKU退货原因失败: ${skuId}, 错误: ${error.message}`, { traceId, skuId });
}
}
this.logger.log(`批量分析SKU退货原因完成, 成功: ${results.length}/${skuIds.length}`, { traceId });
return results;
}
/**
* 获取高退货率SKU列表
* @param threshold 退货率阈值
* @param limit 返回数量
* @param traceId 链路追踪ID
* @returns 高退货率SKU列表
*/
async getHighReturnRateSkus(threshold: number = 10, limit: number = 10, traceId: string): Promise<Array<{
skuId: string;
productName: string;
returnRate: number;
totalReturns: number;
totalOrders: number;
primaryReason: string;
}>> {
this.logger.log(`获取高退货率SKU列表, 阈值: ${threshold}%, 限制: ${limit}`, { traceId });
try {
// 获取所有SKU的退货数据
const returns = await this.prisma.return.findMany({
include: {
order: {
include: {
product: true,
},
},
},
});
// 获取所有SKU的订单数据
const orders = await this.prisma.order.findMany({
include: {
items: true,
},
});
// 按SKU分组计算退货率
const skuReturnStats = new Map<string, { returns: ReturnData[]; orders: Order[] }>();
// 统计退货
returns.forEach(ret => {
if (!skuReturnStats.has(ret.skuId)) {
skuReturnStats.set(ret.skuId, { returns: [], orders: [] });
}
skuReturnStats.get(ret.skuId)?.returns.push(ret);
});
// 统计订单
orders.forEach(order => {
order.items.forEach(item => {
if (!skuReturnStats.has(item.skuId)) {
skuReturnStats.set(item.skuId, { returns: [], orders: [] });
}
skuReturnStats.get(item.skuId)?.orders.push(order);
});
});
// 计算退货率并筛选高退货率SKU
const highReturnRateSkus = [];
for (const [skuId, stats] of skuReturnStats.entries()) {
const totalOrders = stats.orders.length;
const totalReturns = stats.returns.length;
const returnRate = totalOrders > 0 ? (totalReturns / totalOrders) * 100 : 0;
if (returnRate >= threshold) {
// 获取商品名称
const product = await this.prisma.product.findFirst({
where: {
skus: {
some: {
id: skuId,
},
},
},
});
// 获取主要退货原因
const primaryReasons = this.analyzePrimaryReasons(stats.returns);
const primaryReason = primaryReasons.length > 0 ? primaryReasons[0].reason : '未知';
highReturnRateSkus.push({
skuId,
productName: product?.name || '未知商品',
returnRate: Math.round(returnRate * 100) / 100,
totalReturns,
totalOrders,
primaryReason,
});
}
}
// 按退货率排序并限制数量
highReturnRateSkus.sort((a, b) => b.returnRate - a.returnRate);
this.logger.log(`获取高退货率SKU列表完成, 数量: ${highReturnRateSkus.length}`, { traceId });
return highReturnRateSkus.slice(0, limit);
} catch (error) {
this.logger.error(`获取高退货率SKU列表失败: ${error.message}`, { traceId, error });
throw error;
}
}
/**
* 分析主要退货原因
*/
private analyzePrimaryReasons(returns: any[]): ReturnAnalysisResult['primaryReasons'] {
// 统计各退货原因的数量
const reasonCounts = new Map<string, number>();
returns.forEach(ret => {
const reason = ret.reason || '其他';
reasonCounts.set(reason, (reasonCounts.get(reason) || 0) + 1);
});
// 转换为数组并计算百分比
const totalReturns = returns.length;
const reasons = Array.from(reasonCounts.entries())
.map(([reason, count]) => ({
reason,
count,
percentage: totalReturns > 0 ? (count / totalReturns) * 100 : 0,
}))
.sort((a, b) => b.count - a.count)
.slice(0, 5); // 只返回前5个主要原因
return reasons;
}
/**
* 分析时间趋势
*/
private analyzeTemporalTrends(returns: any[], orders: Order[]): ReturnAnalysisResult['temporalAnalysis'] {
// 按周分组分析
const weeklyData = new Map<string, { orders: number; returns: number }>();
// 统计订单
orders.forEach(order => {
const weekKey = this.getWeekKey(order.createdAt);
if (!weeklyData.has(weekKey)) {
weeklyData.set(weekKey, { orders: 0, returns: 0 });
}
weeklyData.get(weekKey)!.orders++;
});
// 统计退货
returns.forEach(ret => {
const weekKey = this.getWeekKey(ret.createdAt);
if (!weeklyData.has(weekKey)) {
weeklyData.set(weekKey, { orders: 0, returns: 0 });
}
weeklyData.get(weekKey)!.returns++;
});
// 转换为数组并计算退货率
const temporalData = Array.from(weeklyData.entries())
.map(([period, data]) => ({
period,
returnRate: data.orders > 0 ? (data.returns / data.orders) * 100 : 0,
orderCount: data.orders,
returnCount: data.returns,
}))
.sort((a, b) => a.period.localeCompare(b.period));
return temporalData;
}
/**
* 获取周key
*/
private getWeekKey(date: Date): string {
const d = new Date(date);
const year = d.getFullYear();
const weekNumber = this.getWeekNumber(d);
return `${year}-W${weekNumber}`;
}
/**
* 获取周数
*/
private getWeekNumber(date: Date): number {
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
const dayNum = d.getUTCDay() || 7;
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
return Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
}
/**
* 生成建议
*/
private generateRecommendations(data: {
returnRate: number;
primaryReasons: ReturnAnalysisResult['primaryReasons'];
temporalAnalysis: ReturnAnalysisResult['temporalAnalysis'];
product: Product;
}): string[] {
const recommendations: string[] = [];
// 基于退货率的建议
if (data.returnRate > 20) {
recommendations.push('建议考虑暂时下架该SKU进行全面质量检查');
} else if (data.returnRate > 10) {
recommendations.push('建议优化产品描述和图片,确保与实际产品一致');
}
// 基于主要退货原因的建议
const topReason = data.primaryReasons[0];
if (topReason) {
switch (topReason.reason) {
case '质量问题':
recommendations.push('建议加强质量控制,对供应商进行审核');
break;
case '尺寸不符':
recommendations.push('建议提供更详细的尺寸表和测量指南');
break;
case '描述不符':
recommendations.push('建议更新产品描述,确保与实际产品一致');
break;
case '物流损坏':
recommendations.push('建议优化包装,选择更可靠的物流服务商');
break;
case '其他':
recommendations.push('建议收集更详细的退货原因,以便针对性改进');
break;
}
}
// 基于时间趋势的建议
if (data.temporalAnalysis.length > 1) {
const recentTrend = this.analyzeTrend(data.temporalAnalysis);
if (recentTrend === 'increasing') {
recommendations.push('退货率呈上升趋势,建议立即采取措施');
} else if (recentTrend === 'decreasing') {
recommendations.push('退货率呈下降趋势,建议继续保持当前改进措施');
}
}
// 通用建议
recommendations.push('建议定期监控该SKU的退货情况及时调整策略');
return recommendations;
}
/**
* 分析趋势
*/
private analyzeTrend(data: ReturnAnalysisResult['temporalAnalysis']): 'increasing' | 'decreasing' | 'stable' {
if (data.length < 2) return 'stable';
const recentData = data.slice(-3); // 取最近3个周期的数据
const firstRate = recentData[0].returnRate;
const lastRate = recentData[recentData.length - 1].returnRate;
const changeRate = ((lastRate - firstRate) / firstRate) * 100;
if (changeRate > 10) {
return 'increasing';
} else if (changeRate < -10) {
return 'decreasing';
} else {
return 'stable';
}
}
/**
* 评估风险等级
*/
private assessRiskLevel(returnRate: number): 'low' | 'medium' | 'high' {
if (returnRate > 20) {
return 'high';
} else if (returnRate > 10) {
return 'medium';
} else {
return 'low';
}
}
/**
* 生成退货分析报告
* @param period 时间周期(如:'week', 'month', 'quarter'
* @param traceId 链路追踪ID
* @returns 退货分析报告
*/
async generateReturnAnalysisReport(period: string, traceId: string) {
this.logger.log(`生成退货分析报告, 周期: ${period}`, { traceId, period });
try {
// 计算时间范围
const endDate = new Date();
let startDate = new Date();
switch (period) {
case 'week':
startDate.setDate(startDate.getDate() - 7);
break;
case 'month':
startDate.setMonth(startDate.getMonth() - 1);
break;
case 'quarter':
startDate.setMonth(startDate.getMonth() - 3);
break;
default:
startDate.setMonth(startDate.getMonth() - 1);
}
// 获取时间范围内的退货数据
const returns = await this.prisma.return.findMany({
where: {
createdAt: {
gte: startDate,
lte: endDate,
},
},
include: {
order: {
include: {
product: true,
},
},
},
});
// 按SKU分组
const skuGroups = new Map<string, typeof returns>();
returns.forEach(ret => {
if (!skuGroups.has(ret.skuId)) {
skuGroups.set(ret.skuId, []);
}
skuGroups.get(ret.skuId)?.push(ret);
});
// 分析每个SKU
const skuAnalyses = [];
for (const [skuId, skuReturns] of skuGroups.entries()) {
try {
const analysis = await this.analyzeReturnReasons(skuId, traceId);
skuAnalyses.push(analysis);
} catch (error) {
this.logger.error(`分析SKU ${skuId} 失败: ${error.message}`, { traceId, skuId });
}
}
// 计算整体退货率
const totalReturns = returns.length;
const totalOrders = await this.prisma.order.count({
where: {
createdAt: {
gte: startDate,
lte: endDate,
},
},
});
const overallReturnRate = totalOrders > 0 ? (totalReturns / totalOrders) * 100 : 0;
// 分析主要退货原因
const overallReasons = this.analyzePrimaryReasons(returns);
// 按风险等级分组
const highRiskSkus = skuAnalyses.filter(analysis => analysis.riskLevel === 'high');
const mediumRiskSkus = skuAnalyses.filter(analysis => analysis.riskLevel === 'medium');
const lowRiskSkus = skuAnalyses.filter(analysis => analysis.riskLevel === 'low');
const report = {
period,
timeRange: {
start: startDate,
end: endDate,
},
overallReturnRate: Math.round(overallReturnRate * 100) / 100,
totalReturns,
totalOrders,
overallReasons,
skuAnalyses,
riskDistribution: {
high: highRiskSkus.length,
medium: mediumRiskSkus.length,
low: lowRiskSkus.length,
},
highRiskSkus: highRiskSkus.map(sku => ({
skuId: sku.skuId,
productName: sku.productName,
returnRate: sku.returnRate,
primaryReason: sku.primaryReasons[0]?.reason || '未知',
})),
};
this.logger.log(`生成退货分析报告完成`, { traceId, report });
return report;
} catch (error) {
this.logger.error(`生成退货分析报告失败: ${error.message}`, { traceId, period, error });
throw error;
}
}
}

View File

@@ -0,0 +1,510 @@
import { Injectable, Logger } from '@nestjs/common';
import { Product, Sku, Return, Order } from '@prisma/client';
import { PrismaService } from '../../config/database';
interface SkuData {
id: string;
productId: string;
sku: string;
price: number;
stock: number;
attributes: Record<string, string>;
createdAt: Date;
updatedAt: Date;
}
interface ProductData {
id: string;
name: string;
description: string;
category: string;
brand: string;
createdAt: Date;
updatedAt: Date;
}
interface OptimizationResult {
skuId: string;
productName: string;
currentReturnRate: number;
targetReturnRate: number;
optimizationStrategies: {
type: string;
description: string;
expectedImpact: number; // 预期降低退货率的百分比
priority: 'high' | 'medium' | 'low';
implementationSteps: string[];
}[];
estimatedSavings: {
returnReduction: number; // 预计减少的退货数量
revenueImpact: number; // 预计增加的收入
costSavings: number; // 预计节省的成本
};
confidence: number; // 优化方案的置信度
}
@Injectable()
export class ReturnOptimizationService {
private readonly logger = new Logger(ReturnOptimizationService.name);
constructor(private readonly prisma: PrismaService) {}
/**
* 为SKU生成智能优化建议
* @param skuId SKU ID
* @param traceId 链路追踪ID
* @returns 优化建议结果
*/
async generateOptimizationSuggestions(skuId: string, traceId: string): Promise<OptimizationResult> {
this.logger.log(`开始为SKU生成优化建议: ${skuId}`, { traceId, skuId });
try {
// 获取SKU信息
const sku = await this.prisma.sku.findUnique({
where: { id: skuId },
include: {
product: true,
},
});
if (!sku) {
throw new Error(`SKU不存在: ${skuId}`);
}
// 获取SKU的退货数据
const returns = await this.prisma.return.findMany({
where: { skuId },
});
// 获取SKU的订单数据
const orders = await this.prisma.order.findMany({
where: {
items: {
some: {
skuId,
},
},
},
});
// 计算当前退货率
const totalOrders = orders.length;
const totalReturns = returns.length;
const currentReturnRate = totalOrders > 0 ? (totalReturns / totalOrders) * 100 : 0;
// 分析退货原因
const returnReasons = this.analyzeReturnReasons(returns);
// 生成优化策略
const optimizationStrategies = this.generateOptimizationStrategies({
sku,
product: sku.product,
returnReasons,
currentReturnRate,
});
// 计算预计节省
const estimatedSavings = this.calculateEstimatedSavings({
sku,
currentReturnRate,
optimizationStrategies,
orders,
});
// 计算置信度
const confidence = this.calculateConfidence(optimizationStrategies, returnReasons);
// 设置目标退货率
const targetReturnRate = Math.max(0, currentReturnRate - 5); // 目标降低5个百分点
const result: OptimizationResult = {
skuId,
productName: sku.product.name,
currentReturnRate: Math.round(currentReturnRate * 100) / 100,
targetReturnRate: Math.round(targetReturnRate * 100) / 100,
optimizationStrategies,
estimatedSavings,
confidence,
};
this.logger.log(`SKU优化建议生成完成: ${skuId}`, { traceId, result });
return result;
} catch (error) {
this.logger.error(`SKU优化建议生成失败: ${error.message}`, { traceId, skuId, error });
throw error;
}
}
/**
* 批量为SKU生成优化建议
* @param skuIds SKU ID列表
* @param traceId 链路追踪ID
* @returns 优化建议结果列表
*/
async batchGenerateOptimizationSuggestions(skuIds: string[], traceId: string): Promise<OptimizationResult[]> {
this.logger.log(`开始批量为SKU生成优化建议, 数量: ${skuIds.length}`, { traceId });
const results: OptimizationResult[] = [];
for (const skuId of skuIds) {
try {
const result = await this.generateOptimizationSuggestions(skuId, traceId);
results.push(result);
} catch (error) {
this.logger.error(`批量生成SKU优化建议失败: ${skuId}, 错误: ${error.message}`, { traceId, skuId });
}
}
this.logger.log(`批量生成SKU优化建议完成, 成功: ${results.length}/${skuIds.length}`, { traceId });
return results;
}
/**
* 分析退货原因
*/
private analyzeReturnReasons(returns: Return[]): Record<string, number> {
const reasonCounts = new Map<string, number>();
returns.forEach(ret => {
const reason = ret.reason || '其他';
reasonCounts.set(reason, (reasonCounts.get(reason) || 0) + 1);
});
return Object.fromEntries(reasonCounts);
}
/**
* 生成优化策略
*/
private generateOptimizationStrategies(data: {
sku: Sku & { product: Product };
product: Product;
returnReasons: Record<string, number>;
currentReturnRate: number;
}): OptimizationResult['optimizationStrategies'] {
const strategies: OptimizationResult['optimizationStrategies'] = [];
// 基于退货原因的策略
const topReasons = Object.entries(data.returnReasons)
.sort(([,a], [,b]) => b - a)
.slice(0, 3); // 取前3个主要原因
topReasons.forEach(([reason, count]) => {
switch (reason) {
case '质量问题':
strategies.push({
type: 'quality_improvement',
description: '改进产品质量,加强质量控制',
expectedImpact: 15,
priority: 'high',
implementationSteps: [
'对供应商进行审核和评估',
'建立质量检测流程',
'对不合格产品进行召回',
'定期抽样检查',
],
});
break;
case '尺寸不符':
strategies.push({
type: 'size_accuracy',
description: '提供更准确的尺寸信息和测量指南',
expectedImpact: 10,
priority: 'medium',
implementationSteps: [
'更新产品页面的尺寸表',
'提供详细的测量方法',
'添加尺寸对比图表',
'收集客户反馈优化尺寸描述',
],
});
break;
case '描述不符':
strategies.push({
type: 'description_accuracy',
description: '优化产品描述和图片,确保与实际产品一致',
expectedImpact: 12,
priority: 'high',
implementationSteps: [
'更新产品描述,确保准确性',
'添加更多真实产品图片',
'拍摄产品使用视频',
'明确标注产品的材质和特性',
],
});
break;
case '物流损坏':
strategies.push({
type: 'packaging_improvement',
description: '优化包装,减少物流损坏',
expectedImpact: 8,
priority: 'medium',
implementationSteps: [
'使用更坚固的包装材料',
'添加缓冲材料',
'选择更可靠的物流服务商',
'在包装上标注易碎标志',
],
});
break;
case '其他':
strategies.push({
type: 'customer_feedback',
description: '收集更详细的客户反馈,了解具体问题',
expectedImpact: 5,
priority: 'low',
implementationSteps: [
'添加详细的退货原因调查',
'主动联系退货客户了解原因',
'建立客户反馈收集系统',
'定期分析反馈数据',
],
});
break;
}
});
// 通用优化策略
if (data.currentReturnRate > 15) {
strategies.push({
type: 'pricing_strategy',
description: '调整定价策略,提高产品价值感知',
expectedImpact: 7,
priority: 'medium',
implementationSteps: [
'分析竞争对手定价',
'调整产品定价',
'提供捆绑销售选项',
'推出限时优惠活动',
],
});
}
// 产品信息优化
strategies.push({
type: 'product_information',
description: '优化产品页面信息,提高透明度',
expectedImpact: 6,
priority: 'low',
implementationSteps: [
'添加详细的产品规格',
'提供真实的客户评价',
'更新产品使用说明',
'添加常见问题解答',
],
});
// 客户服务优化
strategies.push({
type: 'customer_service',
description: '提升客户服务质量,减少沟通误解',
expectedImpact: 4,
priority: 'low',
implementationSteps: [
'提供更及时的客户支持',
'培训客服人员产品知识',
'建立快速响应机制',
'主动解决客户问题',
],
});
// 按优先级排序
strategies.sort((a, b) => {
const priorityOrder = { high: 3, medium: 2, low: 1 };
return priorityOrder[b.priority] - priorityOrder[a.priority];
});
return strategies;
}
/**
* 计算预计节省
*/
private calculateEstimatedSavings(data: {
sku: Sku;
currentReturnRate: number;
optimizationStrategies: OptimizationResult['optimizationStrategies'];
orders: Order[];
}): OptimizationResult['estimatedSavings'] {
// 计算总预期影响
const totalExpectedImpact = data.optimizationStrategies
.reduce((sum, strategy) => sum + strategy.expectedImpact, 0);
// 计算预计减少的退货率
const expectedReturnRateReduction = Math.min(totalExpectedImpact, data.currentReturnRate);
// 计算预计减少的退货数量
const averageMonthlyOrders = orders.length / 3; // 假设数据覆盖3个月
const returnReduction = (averageMonthlyOrders * expectedReturnRateReduction) / 100;
// 计算预计增加的收入(假设退货商品无法再次销售)
const revenueImpact = returnReduction * data.sku.price;
// 计算预计节省的成本(退货处理成本)
const averageReturnProcessingCost = 20; // 假设每笔退货处理成本为20元
const costSavings = returnReduction * averageReturnProcessingCost;
return {
returnReduction: Math.round(returnReduction),
revenueImpact: Math.round(revenueImpact * 100) / 100,
costSavings: Math.round(costSavings * 100) / 100,
};
}
/**
* 计算置信度
*/
private calculateConfidence(
strategies: OptimizationResult['optimizationStrategies'],
returnReasons: Record<string, number>
): number {
// 基于策略数量和退货原因分析的完整性计算置信度
const strategyCount = strategies.length;
const reasonCount = Object.keys(returnReasons).length;
// 基础置信度
let baseConfidence = 70;
// 根据策略数量调整
if (strategyCount >= 5) {
baseConfidence += 10;
} else if (strategyCount >= 3) {
baseConfidence += 5;
}
// 根据退货原因分析调整
if (reasonCount >= 3) {
baseConfidence += 10;
} else if (reasonCount >= 2) {
baseConfidence += 5;
}
// 最高置信度为95%
return Math.min(95, baseConfidence);
}
/**
* 获取优化建议报告
* @param skuIds SKU ID列表
* @param traceId 链路追踪ID
* @returns 优化建议报告
*/
async getOptimizationReport(skuIds: string[], traceId: string) {
this.logger.log(`生成优化建议报告, SKU数量: ${skuIds.length}`, { traceId });
try {
// 批量生成优化建议
const optimizationResults = await this.batchGenerateOptimizationSuggestions(skuIds, traceId);
// 计算整体统计数据
const totalCurrentReturnRate = optimizationResults.reduce((sum, result) => sum + result.currentReturnRate, 0) / optimizationResults.length;
const totalTargetReturnRate = optimizationResults.reduce((sum, result) => sum + result.targetReturnRate, 0) / optimizationResults.length;
const totalReturnReduction = optimizationResults.reduce((sum, result) => sum + result.estimatedSavings.returnReduction, 0);
const totalRevenueImpact = optimizationResults.reduce((sum, result) => sum + result.estimatedSavings.revenueImpact, 0);
const totalCostSavings = optimizationResults.reduce((sum, result) => sum + result.estimatedSavings.costSavings, 0);
// 分析策略分布
const strategyDistribution = new Map<string, number>();
optimizationResults.forEach(result => {
result.optimizationStrategies.forEach(strategy => {
strategyDistribution.set(strategy.type, (strategyDistribution.get(strategy.type) || 0) + 1);
});
});
// 按优先级统计策略
const priorityDistribution = new Map<string, number>();
optimizationResults.forEach(result => {
result.optimizationStrategies.forEach(strategy => {
priorityDistribution.set(strategy.priority, (priorityDistribution.get(strategy.priority) || 0) + 1);
});
});
const report = {
skuCount: optimizationResults.length,
averageCurrentReturnRate: Math.round(totalCurrentReturnRate * 100) / 100,
averageTargetReturnRate: Math.round(totalTargetReturnRate * 100) / 100,
totalReturnReduction: Math.round(totalReturnReduction),
totalRevenueImpact: Math.round(totalRevenueImpact * 100) / 100,
totalCostSavings: Math.round(totalCostSavings * 100) / 100,
strategyDistribution: Object.fromEntries(strategyDistribution),
priorityDistribution: Object.fromEntries(priorityDistribution),
optimizationResults,
topRecommendations: this.getTopRecommendations(optimizationResults),
};
this.logger.log(`生成优化建议报告完成`, { traceId, report });
return report;
} catch (error) {
this.logger.error(`生成优化建议报告失败: ${error.message}`, { traceId, error });
throw error;
}
}
/**
* 获取顶级建议
*/
private getTopRecommendations(optimizationResults: OptimizationResult[]): Array<{
strategyType: string;
description: string;
frequency: number;
averageImpact: number;
}> {
const strategyStats = new Map<string, { count: number; totalImpact: number; description: string }>();
optimizationResults.forEach(result => {
result.optimizationStrategies.forEach(strategy => {
if (!strategyStats.has(strategy.type)) {
strategyStats.set(strategy.type, { count: 0, totalImpact: 0, description: strategy.description });
}
const stats = strategyStats.get(strategy.type)!;
stats.count++;
stats.totalImpact += strategy.expectedImpact;
});
});
return Array.from(strategyStats.entries())
.map(([type, stats]) => ({
strategyType: type,
description: stats.description,
frequency: stats.count,
averageImpact: Math.round((stats.totalImpact / stats.count) * 100) / 100,
}))
.sort((a, b) => b.frequency - a.frequency)
.slice(0, 5);
}
/**
* 应用优化策略
* @param skuId SKU ID
* @param strategyType 策略类型
* @param traceId 链路追踪ID
* @returns 应用结果
*/
async applyOptimizationStrategy(skuId: string, strategyType: string, traceId: string) {
this.logger.log(`应用优化策略: ${strategyType} 到 SKU: ${skuId}`, { traceId, skuId, strategyType });
try {
// 这里可以实现具体的策略应用逻辑
// 例如:更新产品信息、调整定价、优化包装等
// 模拟应用结果
const result = {
skuId,
strategyType,
applied: true,
message: `成功应用 ${strategyType} 策略到 SKU ${skuId}`,
timestamp: new Date(),
};
this.logger.log(`优化策略应用完成`, { traceId, result });
return result;
} catch (error) {
this.logger.error(`应用优化策略失败: ${error.message}`, { traceId, skuId, strategyType, error });
throw error;
}
}
}

View File

@@ -0,0 +1,463 @@
import { PrismaClient } from '@prisma/client';
import { Logger } from 'winston';
import { ReturnEffectAnalysisResult, ReturnEffectMetrics, SKUImpactAnalysis } from '../../shared/types/return';
/**
* 退货效果分析服务
* 分析高退货率SKU对销售、利润的影响生成分析报告
*/
export class ReturnEffectAnalysisService {
private prisma: PrismaClient;
private logger: Logger;
constructor(prisma: PrismaClient, logger: Logger) {
this.prisma = prisma;
this.logger = logger;
}
/**
* 分析退货对SKU的影响
* @param skuId SKU ID
* @param timeRange 时间范围
* @param traceId 链路追踪ID
* @returns 退货效果分析结果
*/
async analyzeSKUReturnEffect(
skuId: string,
timeRange: {
start: Date;
end: Date;
},
traceId: string
): Promise<ReturnEffectAnalysisResult> {
this.logger.info(`开始分析SKU ${skuId} 的退货效果`, { traceId });
try {
// 获取SKU信息
const sku = await this.prisma.sku.findUnique({
where: { id: skuId },
include: {
product: true
}
});
if (!sku) {
throw new Error(`SKU ${skuId} 不存在`);
}
// 获取退货数据
const returns = await this.prisma.return.findMany({
where: {
skuId,
createdAt: {
gte: timeRange.start,
lte: timeRange.end
}
},
include: {
order: true
}
});
// 获取销售数据
const orders = await this.prisma.order.findMany({
where: {
items: {
some: {
skuId
}
},
createdAt: {
gte: timeRange.start,
lte: timeRange.end
}
},
include: {
items: {
where: {
skuId
}
}
}
});
// 计算基本指标
const totalOrders = orders.length;
const totalReturns = returns.length;
const returnRate = totalOrders > 0 ? (totalReturns / totalOrders) * 100 : 0;
// 计算销售影响
const totalSales = orders.reduce((sum, order) => {
const skuItem = order.items.find(item => item.skuId === skuId);
return sum + (skuItem ? skuItem.price * skuItem.quantity : 0);
}, 0);
const returnedSales = returns.reduce((sum, returnItem) => {
return sum + returnItem.refundAmount;
}, 0);
const salesImpact = (returnedSales / totalSales) * 100;
// 计算利润影响
const totalProfit = orders.reduce((sum, order) => {
const skuItem = order.items.find(item => item.skuId === skuId);
if (!skuItem) return sum;
const cost = sku.costPrice || 0;
return sum + (skuItem.price - cost) * skuItem.quantity;
}, 0);
const lostProfit = returns.reduce((sum, returnItem) => {
const cost = sku.costPrice || 0;
const order = orders.find(o => o.id === returnItem.orderId);
if (!order) return sum;
const skuItem = order.items.find(item => item.skuId === skuId);
if (!skuItem) return sum;
return sum + (skuItem.price - cost) * skuItem.quantity;
}, 0);
const profitImpact = (lostProfit / totalProfit) * 100;
// 分析退货原因分布
const reasonDistribution = this.analyzeReasonDistribution(returns);
// 生成改进建议
const recommendations = this.generateRecommendations({
returnRate,
salesImpact,
profitImpact,
reasonDistribution,
sku
});
// 生成分析报告
const analysisReport = this.generateAnalysisReport({
sku,
timeRange,
returnRate,
salesImpact,
profitImpact,
reasonDistribution,
recommendations
});
const result: ReturnEffectAnalysisResult = {
skuId,
productName: sku.product.name,
timeRange,
metrics: {
returnRate,
totalOrders,
totalReturns,
totalSales,
returnedSales,
salesImpact,
totalProfit,
lostProfit,
profitImpact
},
reasonDistribution,
recommendations,
analysisReport
};
this.logger.info(`SKU ${skuId} 退货效果分析完成`, { traceId, returnRate, salesImpact, profitImpact });
return result;
} catch (error) {
this.logger.error(`分析SKU ${skuId} 退货效果失败`, { traceId, error: (error as Error).message });
throw error;
}
}
/**
* 批量分析多个SKU的退货效果
* @param skuIds SKU ID列表
* @param timeRange 时间范围
* @param traceId 链路追踪ID
* @returns 多个SKU的退货效果分析结果
*/
async batchAnalyzeSKUReturnEffect(
skuIds: string[],
timeRange: {
start: Date;
end: Date;
},
traceId: string
): Promise<ReturnEffectAnalysisResult[]> {
this.logger.info(`开始批量分析 ${skuIds.length} 个SKU的退货效果`, { traceId });
try {
const results = await Promise.all(
skuIds.map(skuId => this.analyzeSKUReturnEffect(skuId, timeRange, traceId))
);
this.logger.info(`批量分析完成,成功分析 ${results.length} 个SKU`, { traceId });
return results;
} catch (error) {
this.logger.error(`批量分析SKU退货效果失败`, { traceId, error: (error as Error).message });
throw error;
}
}
/**
* 分析退货原因分布
* @param returns 退货数据
* @returns 退货原因分布
*/
private analyzeReasonDistribution(returns: any[]): Record<string, number> {
const distribution: Record<string, number> = {};
returns.forEach(returnItem => {
const reason = returnItem.reason || '其他';
distribution[reason] = (distribution[reason] || 0) + 1;
});
return distribution;
}
/**
* 生成改进建议
* @param analysisData 分析数据
* @returns 改进建议
*/
private generateRecommendations(analysisData: {
returnRate: number;
salesImpact: number;
profitImpact: number;
reasonDistribution: Record<string, number>;
sku: any;
}): string[] {
const { returnRate, salesImpact, profitImpact, reasonDistribution, sku } = analysisData;
const recommendations: string[] = [];
// 根据退货率生成建议
if (returnRate > 30) {
recommendations.push('考虑暂时下架该SKU进行全面质量检查');
recommendations.push('重新评估供应商,考虑更换供应商');
} else if (returnRate > 20) {
recommendations.push('加强质量控制,提高产品质量');
recommendations.push('优化产品描述,确保与实际产品一致');
} else if (returnRate > 10) {
recommendations.push('定期检查库存,确保产品存储条件良好');
recommendations.push('提供更详细的产品使用说明');
}
// 根据销售影响生成建议
if (salesImpact > 20) {
recommendations.push('调整定价策略,考虑降价以减少退货率');
recommendations.push('加强售前咨询,确保客户了解产品特性');
}
// 根据利润影响生成建议
if (profitImpact > 25) {
recommendations.push('重新评估成本结构,寻找降低成本的方法');
recommendations.push('考虑提高产品价格以抵消退货损失');
}
// 根据退货原因生成建议
const topReason = Object.entries(reasonDistribution)
.sort(([,a], [,b]) => b - a)[0];
if (topReason) {
const [reason, count] = topReason;
switch (reason) {
case '质量问题':
recommendations.push('加强产品质量检测,确保符合标准');
recommendations.push('与供应商沟通,要求提高产品质量');
break;
case '尺寸不合适':
recommendations.push('提供更详细的尺寸图表');
recommendations.push('考虑提供尺寸测量指南');
break;
case '描述不符':
recommendations.push('更新产品描述,确保与实际产品一致');
recommendations.push('增加产品实拍图片和视频');
break;
case '物流损坏':
recommendations.push('优化包装方式,减少运输损坏');
recommendations.push('与物流公司合作,改善运输条件');
break;
default:
recommendations.push(`针对"${reason}"原因,制定相应的改进措施`);
}
}
return recommendations;
}
/**
* 生成分析报告
* @param data 分析数据
* @returns 分析报告
*/
private generateAnalysisReport(data: {
sku: any;
timeRange: {
start: Date;
end: Date;
};
returnRate: number;
salesImpact: number;
profitImpact: number;
reasonDistribution: Record<string, number>;
recommendations: string[];
}): string {
const { sku, timeRange, returnRate, salesImpact, profitImpact, reasonDistribution, recommendations } = data;
let report = `# SKU 退货效果分析报告\n\n`;
report += `## 基本信息\n`;
report += `- SKU ID: ${sku.id}\n`;
report += `- 产品名称: ${sku.product.name}\n`;
report += `- 分析时间范围: ${timeRange.start.toISOString()}${timeRange.end.toISOString()}\n\n`;
report += `## 核心指标\n`;
report += `- 退货率: ${returnRate.toFixed(2)}%\n`;
report += `- 销售影响: ${salesImpact.toFixed(2)}%\n`;
report += `- 利润影响: ${profitImpact.toFixed(2)}%\n\n`;
report += `## 退货原因分布\n`;
Object.entries(reasonDistribution).forEach(([reason, count]) => {
report += `- ${reason}: ${count}\n`;
});
report += `\n`;
report += `## 改进建议\n`;
recommendations.forEach((recommendation, index) => {
report += `${index + 1}. ${recommendation}\n`;
});
return report;
}
/**
* 分析高退货率SKU的整体影响
* @param threshold 退货率阈值
* @param timeRange 时间范围
* @param traceId 链路追踪ID
* @returns 高退货率SKU的整体影响分析
*/
async analyzeHighReturnSKUsImpact(
threshold: number,
timeRange: {
start: Date;
end: Date;
},
traceId: string
): Promise<SKUImpactAnalysis> {
this.logger.info(`开始分析退货率超过 ${threshold}% 的SKU整体影响`, { traceId });
try {
// 获取所有SKU的退货数据
const skus = await this.prisma.sku.findMany({
include: {
product: true
}
});
// 分析每个SKU的退货率
const highReturnSKUs = [];
let totalImpact = 0;
for (const sku of skus) {
const returns = await this.prisma.return.count({
where: {
skuId: sku.id,
createdAt: {
gte: timeRange.start,
lte: timeRange.end
}
}
});
const orders = await this.prisma.order.count({
where: {
items: {
some: {
skuId: sku.id
}
},
createdAt: {
gte: timeRange.start,
lte: timeRange.end
}
}
});
const returnRate = orders > 0 ? (returns / orders) * 100 : 0;
if (returnRate > threshold) {
// 计算该SKU的销售和利润影响
const skuOrders = await this.prisma.order.findMany({
where: {
items: {
some: {
skuId: sku.id
}
},
createdAt: {
gte: timeRange.start,
lte: timeRange.end
}
},
include: {
items: {
where: {
skuId: sku.id
}
}
}
});
const totalSales = skuOrders.reduce((sum, order) => {
const skuItem = order.items.find(item => item.skuId === sku.id);
return sum + (skuItem ? skuItem.price * skuItem.quantity : 0);
}, 0);
const skuReturns = await this.prisma.return.findMany({
where: {
skuId: sku.id,
createdAt: {
gte: timeRange.start,
lte: timeRange.end
}
}
});
const returnedSales = skuReturns.reduce((sum, returnItem) => {
return sum + returnItem.refundAmount;
}, 0);
const salesImpact = (returnedSales / totalSales) * 100;
highReturnSKUs.push({
skuId: sku.id,
productName: sku.product.name,
returnRate,
salesImpact,
totalSales,
returnedSales
});
totalImpact += salesImpact;
}
}
// 按退货率排序
highReturnSKUs.sort((a, b) => b.returnRate - a.returnRate);
const analysis: SKUImpactAnalysis = {
threshold,
timeRange,
totalHighReturnSKUs: highReturnSKUs.length,
averageImpact: highReturnSKUs.length > 0 ? totalImpact / highReturnSKUs.length : 0,
highReturnSKUs,
top5SKUs: highReturnSKUs.slice(0, 5)
};
this.logger.info(`高退货率SKU整体影响分析完成共发现 ${highReturnSKUs.length} 个高退货率SKU`, { traceId });
return analysis;
} catch (error) {
this.logger.error(`分析高退货率SKU整体影响失败`, { traceId, error: (error as Error).message });
throw error;
}
}
}

View File

@@ -1,96 +0,0 @@
import { logger } from '../../utils/logger';
import { FeatureGovernanceService } from '../governance/FeatureGovernanceService';
import db from '../../config/database';
export interface ComputeJob {
jobId: string;
tenantId: string;
complexity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
allocatedNodes: number;
cpuLimit: number; // mCore
memoryLimit: number; // MiB
status: 'QUEUED' | 'RUNNING' | 'COMPLETED' | 'FAILED';
}
/**
* [CORE_DEV_35] AGI 弹性算力动态编排 V2 (Elastic Compute V2)
* @description 核心逻辑:针对多 Agent 协作产生的海量、异构算力需求,实现亚秒级的资源调度。
* 系统根据 AGI 任务的认知复杂度(如:简单的 SKU 翻译 vs 复杂的全球供应链 RCA
* 动态调整算力配额,支持在 K8s/Edge 节点间执行“计算热迁移”,确保关键决策链路的零延迟响应。
*/
export class ElasticComputeServiceV2 {
private static readonly JOBS_TABLE = 'cf_agi_compute_jobs';
/**
* 初始化表结构
*/
static async initTable() {
const hasTable = await db.schema.hasTable(this.JOBS_TABLE);
if (!hasTable) {
console.log(`📦 Creating ${this.JOBS_TABLE} table...`);
await db.schema.createTable(this.JOBS_TABLE, (table) => {
table.increments('id').primary();
table.string('job_id', 64).notNullable().unique();
table.string('tenant_id', 64).notNullable();
table.string('complexity', 16);
table.integer('allocated_nodes');
table.integer('cpu_limit');
table.integer('memory_limit');
table.string('status', 16).defaultTo('QUEUED');
table.timestamp('created_at').defaultTo(db.fn.now());
table.index(['tenant_id', 'status']);
});
console.log(`✅ Table ${this.JOBS_TABLE} created`);
}
}
/**
* 申请算力资源并启动任务
*/
static async scheduleAGIJob(params: {
tenantId: string;
complexity: ComputeJob['complexity'];
}): Promise<string> {
const jobId = `AGI-JOB-${Date.now()}`;
// 1. 动态资源估算逻辑
const config = this.estimateResourceNeeds(params.complexity);
await db(this.JOBS_TABLE).insert({
job_id: jobId,
tenant_id: params.tenantId,
complexity: params.complexity,
allocated_nodes: config.nodes,
cpu_limit: config.cpu,
memory_limit: config.memory,
status: 'RUNNING'
});
logger.info(`[ElasticCompute] Scheduled ${params.complexity} job ${jobId} with ${config.nodes} nodes for Tenant ${params.tenantId}`);
// 2. 联动边缘 WASM 或 TEE 集群进行容器启动 (模拟)
// await InfinityComputeService.provisionNodes(jobId, config);
return jobId;
}
/**
* 资源需求估算模型
*/
private static estimateResourceNeeds(complexity: ComputeJob['complexity']) {
switch (complexity) {
case 'CRITICAL': return { nodes: 16, cpu: 8000, memory: 32768 };
case 'HIGH': return { nodes: 4, cpu: 2000, memory: 8192 };
case 'MEDIUM': return { nodes: 2, cpu: 1000, memory: 4096 };
default: return { nodes: 1, cpu: 500, memory: 1024 };
}
}
/**
* 释放算力资源
*/
static async completeJob(jobId: string) {
await db(this.JOBS_TABLE).where({ job_id: jobId }).update({ status: 'COMPLETED' });
logger.info(`[ElasticCompute] Resources released for job ${jobId}`);
}
}

View File

@@ -21,7 +21,6 @@ import { FeatureToggleService } from '../governance/FeatureToggleService';
import { S3QuotaManager } from '../governance/S3QuotaManager';
// Business Services
import { AGIStrategyEvolutionService } from '../../services/AGIStrategyEvolutionService';
import { ActionAuditService } from '../../services/ActionAuditService';
import { AgentSwarmService } from '../../services/AgentSwarmService';
import { AutoCircuitBreakerService } from '../../services/AutoCircuitBreakerService';
@@ -539,11 +538,6 @@ export class DomainBootstrap {
priority: DomainRegistry.Priority.CORE_INFRA,
init: () => ExperimentService.initTable()
});
DomainRegistry.register({
name: 'AGIStrategyEvolution',
priority: DomainRegistry.Priority.CORE_INFRA,
init: () => AGIStrategyEvolutionService.initTable()
});
// 2. 运行时与安全 (SECURITY / RUNTIME)
DomainRegistry.register({

View File

@@ -86,7 +86,6 @@ import { TaxReportService } from '../../services/TaxReportService';
import { UnifiedTaskService } from '../../services/UnifiedTaskService';
import { AgentSelfAwarenessService } from '../ai/AgentSelfAwarenessService';
import { AGILegalComplianceService } from '../ai/AGILegalComplianceService';
import { AGIStrategyEvolutionService } from '../ai/AGIStrategyEvolutionService';
import { AutoCircuitBreakerService } from '../ai/AutoCircuitBreakerService';
import { FederatedNodeService } from '../ai/FederatedNodeService';
import { InfinityComputeService } from '../ai/InfinityComputeService';
@@ -204,7 +203,6 @@ export class LegacyTableInitializer {
await SKUMappingService.initTable();
await UnifiedTaskService.initTable();
await SummaryAggregationService.initTable();
await AGIStrategyEvolutionService.initTable();
await FederatedNodeService.initTable();
await AutonomousSandboxService.initTable();
await SandboxROIAdvisor.initTable();