510 lines
13 KiB
Markdown
510 lines
13 KiB
Markdown
# 代码审查报告
|
||
|
||
> **审查日期**: 2026-03-19
|
||
> **审查范围**: 全代码库深度检查
|
||
> **审查目标**: 逻辑统一性、冗余代码、潜在冲突
|
||
|
||
---
|
||
|
||
## 📊 审查概览
|
||
|
||
| 类别 | 问题数量 | 严重程度 | 状态 |
|
||
|------|----------|----------|------|
|
||
| 🔴 严重问题 | 3 | 高 | 需立即修复 |
|
||
| 🟡 中等问题 | 5 | 中 | 需计划修复 |
|
||
| 🟢 轻微问题 | 4 | 低 | 建议优化 |
|
||
|
||
---
|
||
|
||
## 🔴 严重问题
|
||
|
||
### 1. 服务层逻辑重复与不一致
|
||
|
||
**问题描述**:
|
||
`ArbitrageService` 和 `PriceComparisonService` 存在高度重复的逻辑,但实现细节不一致。
|
||
|
||
**涉及文件**:
|
||
- `server/src/services/ArbitrageService.ts`
|
||
- `server/src/services/PriceComparisonService.ts`
|
||
|
||
**具体问题**:
|
||
|
||
#### 1.1 汇率数据不一致
|
||
```typescript
|
||
// ArbitrageService.ts (第62行)
|
||
private static readonly EXCHANGE_RATE = 7.2; // 硬编码单一汇率
|
||
|
||
// PriceComparisonService.ts (第65-71行)
|
||
private static readonly EXCHANGE_RATES: Record<string, number> = {
|
||
'CNY-USD': 0.14,
|
||
'USD-CNY': 7.2,
|
||
'CNY-EUR': 0.13,
|
||
'EUR-CNY': 7.7,
|
||
'USD-EUR': 0.92,
|
||
'EUR-USD': 1.09
|
||
};
|
||
```
|
||
|
||
**影响**: 两个服务对相同货币对可能计算出不同的汇率结果。
|
||
|
||
#### 1.2 机会评分算法不一致
|
||
```typescript
|
||
// ArbitrageService.ts (第465-470行)
|
||
private calculateOpportunityScore(profitSnapshot: ProfitSnapshot): number {
|
||
const profitRateScore = Math.min(profitSnapshot.profitRate * 200, 40);
|
||
const roiScore = Math.min(profitSnapshot.roi * 50, 30);
|
||
const netProfitScore = Math.min(profitSnapshot.netProfit / 10, 30);
|
||
return Math.round(profitRateScore + roiScore + netProfitScore);
|
||
}
|
||
|
||
// PriceComparisonService.ts (第381-386行)
|
||
private calculateOpportunityScore(profitSnapshot: ProfitSnapshot, priceDiffPercent: number): number {
|
||
const profitRateScore = Math.min(profitSnapshot.profitRate * 200, 40);
|
||
const roiScore = Math.min(profitSnapshot.roi * 50, 30);
|
||
const priceDiffScore = Math.min(priceDiffPercent, 30); // 不同!
|
||
return Math.round(profitRateScore + roiScore + priceDiffScore);
|
||
}
|
||
```
|
||
|
||
**影响**: 相同的利润数据可能产生不同的机会评分。
|
||
|
||
---
|
||
|
||
### 2. 利润红线检查未统一调用
|
||
|
||
**问题描述**:
|
||
`PricingService.checkRisk()` 已实现完整的利润红线检查逻辑,但其他服务未调用此方法。
|
||
|
||
**涉及文件**:
|
||
- `server/src/services/PricingService.ts` (定义了 checkRisk)
|
||
- `server/src/services/ArbitrageService.ts` (未调用)
|
||
- `server/src/services/PriceComparisonService.ts` (未调用)
|
||
- `server/src/services/DynamicPricingService.ts` (有自己的检查逻辑)
|
||
|
||
**现有实现**:
|
||
```typescript
|
||
// PricingService.ts (第116-135行) - 正确实现
|
||
static checkRisk(snapshot: ProfitSnapshot, isB2B: boolean): {
|
||
isRisk: boolean;
|
||
message?: string;
|
||
level: 'BLOCK' | 'WARN' | 'PASS'
|
||
} {
|
||
const profitRate = snapshot.profitRate;
|
||
|
||
if (isB2B) {
|
||
if (profitRate < 0.15) { // B2B < 15% 阻止
|
||
return { isRisk: true, message: `...`, level: 'BLOCK' };
|
||
}
|
||
} else {
|
||
if (profitRate < 0.20) { // B2C < 20% 预警
|
||
return { isRisk: true, message: `...`, level: 'WARN' };
|
||
}
|
||
}
|
||
return { isRisk: false, level: 'PASS' };
|
||
}
|
||
```
|
||
|
||
**问题代码**:
|
||
```typescript
|
||
// ArbitrageService.ts (第107-111行) - 自己实现的检查
|
||
if (profitSnapshot.profitRate < 0.05) {
|
||
riskLevel = 'BLOCK';
|
||
} else if (profitSnapshot.profitRate < 0.15 || profitSnapshot.roi < 0.2) {
|
||
riskLevel = 'HIGH';
|
||
} else if (profitSnapshot.profitRate < 0.25) {
|
||
riskLevel = 'MEDIUM';
|
||
}
|
||
```
|
||
|
||
**影响**:
|
||
- 违反项目规则中的利润红线约束
|
||
- 不同服务的风险判断标准不一致
|
||
|
||
---
|
||
|
||
### 3. 数据库表定义分散
|
||
|
||
**问题描述**:
|
||
数据库表定义分散在两个地方,违反单一职责原则。
|
||
|
||
**涉及文件**:
|
||
- `server/src/database/DatabaseSchema.ts` - 主数据库架构
|
||
- `server/src/services/DynamicPricingService.ts` - 内部定义 initTables()
|
||
|
||
**问题代码**:
|
||
```typescript
|
||
// DynamicPricingService.ts (第216-299行)
|
||
static async initTables() {
|
||
// 在服务内部创建表定义
|
||
const hasConfigTable = await db.schema.hasTable(this.CONFIG_TABLE);
|
||
if (!hasConfigTable) {
|
||
await db.schema.createTable(this.CONFIG_TABLE, (table) => { ... });
|
||
}
|
||
// ...
|
||
}
|
||
```
|
||
|
||
**影响**:
|
||
- 表定义难以统一管理
|
||
- 初始化顺序可能出问题
|
||
- 违反项目架构规范
|
||
|
||
---
|
||
|
||
## 🟡 中等问题
|
||
|
||
### 4. 文档与代码不一致
|
||
|
||
**问题描述**:
|
||
`Business_ClosedLoops.md` 中提到的表名与实际代码不匹配。
|
||
|
||
**涉及文件**:
|
||
- `docs/00_Business/Business_ClosedLoops.md`
|
||
|
||
**不一致内容**:
|
||
| 文档中的表名 | 实际代码中的表名 | 状态 |
|
||
|-------------|-----------------|------|
|
||
| cf_arbitrage_products | ❌ 不存在 | 需补充或删除文档 |
|
||
| cf_arbitrage_orders | ❌ 不存在 | 需补充或删除文档 |
|
||
| cf_arbitrage_profits | ❌ 不存在 | 需补充或删除文档 |
|
||
| cf_pricing_metrics | ❌ 不存在 | 需补充或删除文档 |
|
||
|
||
---
|
||
|
||
### 5. 前端 DataSource 模式重复
|
||
|
||
**问题描述**:
|
||
多个 DataSource 文件实现了相同的 Mock/API 切换模式。
|
||
|
||
**涉及文件**:
|
||
- `dashboard/src/services/dynamicPricingDataSource.ts`
|
||
- `dashboard/src/services/arbitrageDataSource.ts`
|
||
- `dashboard/src/services/shopReportDataSource.ts`
|
||
|
||
**重复模式**:
|
||
```typescript
|
||
// 每个文件都有相同的结构
|
||
interface IXxxDataSource { ... }
|
||
|
||
class MockXxxDataSource implements IXxxDataSource { ... }
|
||
|
||
class ApiXxxDataSource implements IXxxDataSource { ... }
|
||
|
||
export const xxxDataSource: IXxxDataSource = USE_MOCK
|
||
? new MockXxxDataSource()
|
||
: new ApiXxxDataSource();
|
||
```
|
||
|
||
**建议**: 抽取为通用的 DataSource 工厂模式。
|
||
|
||
---
|
||
|
||
### 6. 状态枚举定义分散
|
||
|
||
**问题描述**:
|
||
相同业务概念的状态枚举在多处重复定义。
|
||
|
||
**涉及文件**:
|
||
- `server/src/services/ArbitrageService.ts`
|
||
- `server/src/services/DynamicPricingService.ts`
|
||
- `server/src/database/DatabaseSchema.ts`
|
||
|
||
**示例**:
|
||
```typescript
|
||
// ArbitrageService.ts
|
||
status: 'PENDING' | 'APPROVED' | 'REJECTED' | 'EXECUTING' | 'EXECUTED' | 'FAILED';
|
||
|
||
// DynamicPricingService.ts
|
||
status: 'PENDING' | 'EXECUTED' | 'REJECTED' | 'EXPIRED';
|
||
|
||
// DatabaseSchema.ts (cf_arbitrage_opportunities)
|
||
table.enum('status', ['PENDING', 'APPROVED', 'REJECTED', 'EXECUTING', 'EXECUTED', 'FAILED']);
|
||
```
|
||
|
||
**建议**: 统一定义在 `shared/types/` 目录下。
|
||
|
||
---
|
||
|
||
### 7. 服务实例化模式不一致
|
||
|
||
**问题描述**:
|
||
部分服务使用单例模式,部分不使用。
|
||
|
||
**涉及文件**:
|
||
- `server/src/services/ArbitrageService.ts` - 使用单例
|
||
- `server/src/services/PriceComparisonService.ts` - 使用单例
|
||
- `server/src/services/DynamicPricingService.ts` - 不使用单例
|
||
- `server/src/services/PricingService.ts` - 静态方法,无实例
|
||
|
||
**影响**: 服务调用方式不统一,增加理解成本。
|
||
|
||
---
|
||
|
||
### 8. 缓存策略分散
|
||
|
||
**问题描述**:
|
||
各服务独立定义缓存策略,未统一管理。
|
||
|
||
**涉及文件**:
|
||
- `server/src/services/DynamicPricingService.ts` - CACHE_PREFIX, CACHE_TTL
|
||
- `server/src/services/CompetitorPriceService.ts` - CACHE_PREFIX, CACHE_TTL
|
||
|
||
**建议**: 统一缓存配置管理。
|
||
|
||
---
|
||
|
||
## 🟢 轻微问题
|
||
|
||
### 9. 日志格式不统一
|
||
|
||
**问题描述**:
|
||
不同服务的日志前缀格式不一致。
|
||
|
||
```typescript
|
||
// ArbitrageService.ts
|
||
logger.info(`[ArbitrageService] ...`);
|
||
|
||
// PriceComparisonService.ts
|
||
logger.info(`[PriceComparisonService] ...`);
|
||
|
||
// DynamicPricingService.ts
|
||
logger.info(`[DynamicPricing] ...`); // 缩写
|
||
```
|
||
|
||
---
|
||
|
||
### 10. 类型导出方式不一致
|
||
|
||
**问题描述**:
|
||
类型导出方式混用。
|
||
|
||
```typescript
|
||
// 方式1: 先定义后导出
|
||
export interface ArbitrageOpportunity { ... }
|
||
|
||
// 方式2: 定义时导出
|
||
interface PriceComparison { ... }
|
||
export interface PriceComparison { ... } // 重复声明
|
||
```
|
||
|
||
---
|
||
|
||
### 11. 错误处理不一致
|
||
|
||
**问题描述**:
|
||
部分服务有详细的错误处理,部分直接抛出异常。
|
||
|
||
---
|
||
|
||
### 12. 注释语言混用
|
||
|
||
**问题描述**:
|
||
代码注释中中英文混用,不统一。
|
||
|
||
---
|
||
|
||
## 📋 修复方案
|
||
|
||
### 方案一:统一汇率服务
|
||
|
||
**优先级**: P0
|
||
**预计工时**: 4h
|
||
|
||
**实施步骤**:
|
||
1. 创建 `ExchangeRateService.ts` 统一管理汇率
|
||
2. 从外部 API 或配置获取实时汇率
|
||
3. 修改 `ArbitrageService` 和 `PriceComparisonService` 调用统一服务
|
||
|
||
```typescript
|
||
// 新建 server/src/services/ExchangeRateService.ts
|
||
export class ExchangeRateService {
|
||
private static rates: Record<string, number> = { ... };
|
||
private static lastUpdate: Date;
|
||
|
||
static async getRate(from: string, to: string): Promise<number> {
|
||
await this.ensureFresh();
|
||
return this.rates[`${from}-${to}`] || 1;
|
||
}
|
||
|
||
private static async ensureFresh(): Promise<void> {
|
||
// 每小时更新一次
|
||
if (!this.lastUpdate || Date.now() - this.lastUpdate.getTime() > 3600000) {
|
||
await this.fetchLatestRates();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 方案二:统一机会评分算法
|
||
|
||
**优先级**: P0
|
||
**预计工时**: 2h
|
||
|
||
**实施步骤**:
|
||
1. 在 `PricingService` 中添加 `calculateOpportunityScore` 方法
|
||
2. 修改 `ArbitrageService` 和 `PriceComparisonService` 调用统一方法
|
||
|
||
```typescript
|
||
// 在 PricingService.ts 中添加
|
||
static calculateOpportunityScore(
|
||
profitSnapshot: ProfitSnapshot,
|
||
options?: { priceDiffPercent?: number; netProfit?: number }
|
||
): number {
|
||
const profitRateScore = Math.min(profitSnapshot.profitRate * 200, 40);
|
||
const roiScore = Math.min(profitSnapshot.roi * 50, 30);
|
||
|
||
// 优先使用价格差异,其次使用净利润
|
||
const thirdScore = options?.priceDiffPercent
|
||
? Math.min(options.priceDiffPercent, 30)
|
||
: Math.min((options?.netProfit || profitSnapshot.netProfit) / 10, 30);
|
||
|
||
return Math.round(profitRateScore + roiScore + thirdScore);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 方案三:统一利润红线检查
|
||
|
||
**优先级**: P0
|
||
**预计工时**: 3h
|
||
|
||
**实施步骤**:
|
||
1. 修改 `ArbitrageService` 调用 `PricingService.checkRisk()`
|
||
2. 修改 `PriceComparisonService` 调用 `PricingService.checkRisk()`
|
||
3. 修改 `DynamicPricingService` 使用统一检查
|
||
|
||
```typescript
|
||
// 修改 ArbitrageService.ts
|
||
import { PricingService } from './PricingService';
|
||
|
||
async createOpportunity(...): Promise<ArbitrageOpportunity> {
|
||
// ... 计算利润
|
||
|
||
// 使用统一的利润红线检查
|
||
const riskCheck = PricingService.checkRisk(profitSnapshot, options?.isB2B || false);
|
||
|
||
let riskLevel: 'LOW' | 'MEDIUM' | 'HIGH' | 'BLOCK';
|
||
switch (riskCheck.level) {
|
||
case 'BLOCK':
|
||
riskLevel = 'BLOCK';
|
||
break;
|
||
case 'WARN':
|
||
riskLevel = 'HIGH';
|
||
break;
|
||
default:
|
||
riskLevel = profitSnapshot.profitRate >= 0.25 ? 'LOW' : 'MEDIUM';
|
||
}
|
||
|
||
// ...
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 方案四:集中数据库表定义
|
||
|
||
**优先级**: P1
|
||
**预计工时**: 4h
|
||
|
||
**实施步骤**:
|
||
1. 将 `DynamicPricingService.initTables()` 中的表定义移至 `DatabaseSchema.ts`
|
||
2. 在 `DatabaseSchema.initializeAll()` 中统一调用
|
||
3. 删除服务中的表创建代码
|
||
|
||
---
|
||
|
||
### 方案五:统一状态枚举定义
|
||
|
||
**优先级**: P1
|
||
**预计工时**: 2h
|
||
|
||
**实施步骤**:
|
||
1. 创建 `server/src/shared/types/status.ts`
|
||
2. 定义所有业务状态枚举
|
||
3. 修改各服务引用统一枚举
|
||
|
||
```typescript
|
||
// 新建 server/src/shared/types/status.ts
|
||
export enum ArbitrageStatus {
|
||
PENDING = 'PENDING',
|
||
APPROVED = 'APPROVED',
|
||
REJECTED = 'REJECTED',
|
||
EXECUTING = 'EXECUTING',
|
||
EXECUTED = 'EXECUTED',
|
||
FAILED = 'FAILED'
|
||
}
|
||
|
||
export enum PricingDecisionStatus {
|
||
PENDING = 'PENDING',
|
||
EXECUTED = 'EXECUTED',
|
||
REJECTED = 'REJECTED',
|
||
EXPIRED = 'EXPIRED'
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 方案六:统一 DataSource 工厂
|
||
|
||
**优先级**: P2
|
||
**预计工时**: 3h
|
||
|
||
**实施步骤**:
|
||
1. 创建 `dashboard/src/services/DataSourceFactory.ts`
|
||
2. 抽取公共 Mock/API 切换逻辑
|
||
3. 重构现有 DataSource 文件
|
||
|
||
---
|
||
|
||
## 📊 修复优先级矩阵
|
||
|
||
| 方案 | 优先级 | 影响范围 | 风险 | 预计工时 |
|
||
|------|--------|----------|------|----------|
|
||
| 方案一:统一汇率服务 | P0 | 高 | 低 | 4h |
|
||
| 方案二:统一机会评分 | P0 | 中 | 低 | 2h |
|
||
| 方案三:统一利润红线 | P0 | 高 | 中 | 3h |
|
||
| 方案四:集中表定义 | P1 | 中 | 中 | 4h |
|
||
| 方案五:统一状态枚举 | P1 | 低 | 低 | 2h |
|
||
| 方案六:DataSource工厂 | P2 | 低 | 低 | 3h |
|
||
|
||
**总预计工时**: 18h
|
||
|
||
---
|
||
|
||
## ✅ 验收标准
|
||
|
||
### 修复后需满足:
|
||
|
||
1. **汇率统一**: 所有服务使用同一汇率源
|
||
2. **评分一致**: 相同输入产生相同的机会评分
|
||
3. **红线统一**: 所有利润检查调用 `PricingService.checkRisk()`
|
||
4. **表定义集中**: 所有表定义在 `DatabaseSchema.ts`
|
||
5. **类型统一**: 状态枚举在 `shared/types/` 统一定义
|
||
6. **文档同步**: 文档与代码一致
|
||
|
||
---
|
||
|
||
## 📝 执行建议
|
||
|
||
### 阶段一:紧急修复 (P0)
|
||
- 先修复汇率、评分、利润红线三个核心问题
|
||
- 预计工时:9h
|
||
- 风险:低
|
||
|
||
### 阶段二:架构优化 (P1)
|
||
- 集中表定义、统一状态枚举
|
||
- 预计工时:6h
|
||
- 风险:中
|
||
|
||
### 阶段三:代码规范 (P2)
|
||
- DataSource 工厂、日志格式、注释语言
|
||
- 预计工时:3h
|
||
- 风险:低
|
||
|
||
---
|
||
|
||
*本报告由代码审查工具生成,建议按优先级逐步修复。*
|