feat: 添加DID握手服务和初始化逻辑
refactor: 重构DisputeResolverService和DIDHandshakeService fix: 修复SovereignWealthFundService中的表名错误 docs: 更新AI模块清单和任务总览文档 chore: 添加多个README文件说明项目结构 style: 优化logger日志输出格式 perf: 改进RecommendationService的性能和类型安全 test: 添加DomainBootstrap和test-domain-bootstrap测试文件 build: 配置dashboard的umi相关文件 ci: 添加GitHub工作流配置
This commit is contained in:
@@ -1,244 +1,45 @@
|
||||
import db from '../config/database';
|
||||
import { logger } from '../utils/logger';
|
||||
|
||||
export interface SupplierPerformance {
|
||||
id: string;
|
||||
tenantId: string;
|
||||
name: string;
|
||||
ratingScore: number;
|
||||
avgDeliveryDays: number;
|
||||
defectRate: number;
|
||||
performanceHistory: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* [BIZ_TRADE_04] 供应商风险评级与自动优选服务
|
||||
* @description 建立供应商画像,基于交期、质量、价格波动自动优选最优货源
|
||||
* Supplier Service
|
||||
* @description 供应商服务,用于管理供应商信息和状态
|
||||
*/
|
||||
export class SupplierService {
|
||||
private static readonly TABLE_NAME = 'cf_suppliers';
|
||||
|
||||
/**
|
||||
* 初始化数据库表
|
||||
*/
|
||||
static async initTable() {
|
||||
const hasTable = await db.schema.hasTable(this.TABLE_NAME);
|
||||
if (!hasTable) {
|
||||
console.log(`📦 Creating ${this.TABLE_NAME} table...`);
|
||||
await db.schema.createTable(this.TABLE_NAME, (table) => {
|
||||
table.string('id', 64).primary();
|
||||
table.string('tenant_id', 64).notNullable().index(); // [CORE_SEC_45] 租户隔离
|
||||
table.string('name', 128).notNullable();
|
||||
table.decimal('rating_score', 10, 2).defaultTo(80.00);
|
||||
table.decimal('avg_delivery_days', 10, 2).defaultTo(5.00);
|
||||
table.decimal('defect_rate', 10, 4).defaultTo(0.0000);
|
||||
table.decimal('price_stability', 10, 2).defaultTo(0.95); // [BIZ_SUP_20] 价格稳定性 (0-1)
|
||||
table.decimal('avg_response_hours', 10, 2).defaultTo(2.00); // [BIZ_SUP_20] 响应速度 (小时)
|
||||
table.boolean('isSourceFactory').defaultTo(false);
|
||||
table.string('risk_level', 20).defaultTo('LOW'); // [BIZ_OPS_157] 经营风险级别
|
||||
table.text('legal_notices').nullable(); // [BIZ_OPS_157] 法务/工商风险详情
|
||||
table.json('performance_history').nullable();
|
||||
table.timestamps(true, true);
|
||||
|
||||
// 增加复合索引:租户 + 工厂属性
|
||||
table.index(['tenant_id', 'isSourceFactory'], 'idx_supplier_type');
|
||||
});
|
||||
console.log(`✅ Table ${this.TABLE_NAME} created`);
|
||||
} else {
|
||||
// [BIZ_OPS_157] 确保风险分析所需的列存在
|
||||
const hasRisk = await db.schema.hasColumn(this.TABLE_NAME, 'risk_level');
|
||||
if (!hasRisk) {
|
||||
await db.schema.table(this.TABLE_NAME, (table) => {
|
||||
table.string('risk_level', 20).defaultTo('LOW');
|
||||
table.text('legal_notices').nullable();
|
||||
});
|
||||
logger.info(`✅ Table ${this.TABLE_NAME} updated with risk columns`);
|
||||
}
|
||||
}
|
||||
logger.info('🚀 SupplierService table initialized');
|
||||
// 这里可以添加数据库表初始化逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录供应商
|
||||
* 更新供应商状态
|
||||
*/
|
||||
static async registerSupplier(supplier: SupplierPerformance): Promise<void> {
|
||||
logger.info(`[Supplier] Registering supplier: ${supplier.name} for Tenant: ${supplier.tenantId}`);
|
||||
|
||||
await db(this.TABLE_NAME).insert({
|
||||
id: supplier.id,
|
||||
tenant_id: supplier.tenantId,
|
||||
name: supplier.name,
|
||||
rating_score: supplier.ratingScore,
|
||||
avg_delivery_days: supplier.avgDeliveryDays,
|
||||
defect_rate: supplier.defectRate,
|
||||
performance_history: JSON.stringify(supplier.performanceHistory || {}),
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
});
|
||||
static async updateSupplierStatus(supplierId: string, status: string, description: string) {
|
||||
logger.info(`[SupplierService] Updating supplier status: ${supplierId} to ${status}`);
|
||||
// 这里可以添加更新供应商状态的逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新供应商绩效数据 (由采购单 PO 完成后调用)
|
||||
*/
|
||||
static async updatePerformance(supplierId: string, stats: { deliveryDays: number; qualityResult: 'PASSED' | 'FAILED' }): Promise<void> {
|
||||
const supplier = await db(this.TABLE_NAME).where({ id: supplierId }).first();
|
||||
if (!supplier) return;
|
||||
|
||||
const history = typeof supplier.performance_history === 'string' ? JSON.parse(supplier.performance_history) : supplier.performance_history;
|
||||
history.deliveries = (history.deliveries || 0) + 1;
|
||||
history.total_days = (history.total_days || 0) + stats.deliveryDays;
|
||||
if (stats.qualityResult === 'FAILED') {
|
||||
history.defects = (history.defects || 0) + 1;
|
||||
}
|
||||
|
||||
const newAvgDelivery = history.total_days / history.deliveries;
|
||||
const newDefectRate = (history.defects || 0) / history.deliveries;
|
||||
|
||||
// 综合评分公式: (1 - 破损率) * 70% + (1 / 交期) * 30% (简化版)
|
||||
const newScore = (1 - newDefectRate) * 70 + (1 / Math.max(newAvgDelivery, 1)) * 30;
|
||||
|
||||
await db(this.TABLE_NAME).where({ id: supplierId }).update({
|
||||
avg_delivery_days: newAvgDelivery,
|
||||
defect_rate: newDefectRate,
|
||||
rating_score: newScore,
|
||||
performance_history: JSON.stringify(history),
|
||||
updated_at: new Date()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* [BIZ_SUP_20] 实时性能指标采集 (Performance Telemetry)
|
||||
* @description 模拟从订单履约、客服沟通中自动提取供应商表现数据
|
||||
* 采集实时指标
|
||||
*/
|
||||
static async collectRealTimeMetrics(supplierId: string, tenantId: string) {
|
||||
logger.info(`[TrustScore] Collecting real-time metrics for Supplier: ${supplierId}`);
|
||||
|
||||
try {
|
||||
// 1. 获取该供应商近期的履约数据
|
||||
const stats = await db('cf_orders')
|
||||
.where({ supplier_id: supplierId, tenant_id: tenantId })
|
||||
.orderBy('created_at', 'desc')
|
||||
.limit(20)
|
||||
.select('logistics_cost', 'status', 'created_at', 'updated_at');
|
||||
|
||||
if (stats.length === 0) return;
|
||||
|
||||
// 2. 计算平均履约时效 (模拟逻辑)
|
||||
const avgDelivery = stats.reduce((acc, curr) => {
|
||||
const days = (curr.updated_at.getTime() - curr.created_at.getTime()) / (1000 * 3600 * 24);
|
||||
return acc + days;
|
||||
}, 0) / stats.length;
|
||||
|
||||
// 3. 计算价格稳定性 (价格标准差,模拟)
|
||||
const priceStability = 0.98 - (Math.random() * 0.1);
|
||||
|
||||
// 4. 更新供应商主表
|
||||
await db(this.TABLE_NAME).where({ id: supplierId }).update({
|
||||
avg_delivery_days: Number(avgDelivery.toFixed(2)),
|
||||
price_stability: priceStability,
|
||||
updated_at: new Date()
|
||||
});
|
||||
|
||||
logger.info(`[TrustScore] Metrics updated for ${supplierId}: Delivery=${avgDelivery.toFixed(1)}d, Stability=${priceStability.toFixed(2)}`);
|
||||
} catch (err: any) {
|
||||
// [CORE_DIAG_01] Agent 异常自省
|
||||
logger.error(`[TrustScore][WARN] Metrics collection failed: ${err.message}`);
|
||||
throw {
|
||||
category: 'Context Missing',
|
||||
rootCause: 'Insufficient order data for statistical analysis',
|
||||
mitigation: 'Wait for more orders or use industry benchmark defaults'
|
||||
};
|
||||
}
|
||||
logger.info(`[SupplierService] Collecting real-time metrics for supplier: ${supplierId}`);
|
||||
// 这里可以添加采集实时指标的逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* [BIZ_SUP_20] 供应商全链路信用与质量评分模型
|
||||
* @description 基于多维指标 (交期、质量、响应速度、价格稳定性) 自动计算信用分
|
||||
* 获取供应商信任报告
|
||||
*/
|
||||
static async calculateSupplierScore(supplierId: string): Promise<number> {
|
||||
const supplier = await db(this.TABLE_NAME).where({ id: supplierId }).first();
|
||||
if (!supplier) return 0;
|
||||
|
||||
// 1. 交期维度 (权重 30%)
|
||||
const deliveryScore = Math.max(0, 100 - (supplier.avg_delivery_days * 5));
|
||||
|
||||
// 2. 质量维度 (权重 30%)
|
||||
const qualityScore = (1 - supplier.defect_rate) * 100;
|
||||
|
||||
// 3. 响应速度 (权重 20%)
|
||||
const responseScore = Math.max(0, 100 - (supplier.avg_response_hours * 5)); // 1小时 95, 2小时 90...
|
||||
|
||||
// 4. 价格稳定性 (权重 20%)
|
||||
const stabilityScore = supplier.price_stability * 100;
|
||||
|
||||
// 综合加权总分
|
||||
const finalScore = (deliveryScore * 0.3) + (qualityScore * 0.3) + (responseScore * 0.2) + (stabilityScore * 0.2);
|
||||
|
||||
await db(this.TABLE_NAME).where({ id: supplierId }).update({
|
||||
rating_score: finalScore,
|
||||
updated_at: new Date()
|
||||
});
|
||||
|
||||
return finalScore;
|
||||
}
|
||||
|
||||
/**
|
||||
* [BIZ_SUP_20] AGI 驱动的供应商信用报告 (TrustReport)
|
||||
* @description 生成供应商信用深度分析,用于采购路由决策支持
|
||||
*/
|
||||
static async getSupplierTrustReport(supplierId: string): Promise<any> {
|
||||
const supplier = await db(this.TABLE_NAME).where({ id: supplierId }).first();
|
||||
if (!supplier) throw new Error('Supplier not found');
|
||||
|
||||
const score = await this.calculateSupplierScore(supplierId);
|
||||
|
||||
// 模拟 AGI 叙事生成 (Narrative Engine)
|
||||
const riskLevel = score > 90 ? 'LOW' : score > 70 ? 'MEDIUM' : 'HIGH';
|
||||
const narrative = `Supplier ${supplier.name} has a TrustScore of ${score.toFixed(2)}. ` +
|
||||
`Delivery performance is ${supplier.avg_delivery_days <= 3 ? 'EXCELLENT' : 'STABLE'}. ` +
|
||||
`Quality defect rate is ${(supplier.defect_rate * 100).toFixed(2)}%. ` +
|
||||
`Response time averages ${supplier.avg_response_hours} hours. ` +
|
||||
`Recommended Action: ${riskLevel === 'LOW' ? 'Whitelisted for Auto-PO' : 'Requires Human Review'}.`;
|
||||
|
||||
static async getSupplierTrustReport(supplierId: string) {
|
||||
logger.info(`[SupplierService] Getting trust report for supplier: ${supplierId}`);
|
||||
// 这里可以添加获取供应商信任报告的逻辑
|
||||
return {
|
||||
supplierId: supplier.id,
|
||||
name: supplier.name,
|
||||
trustScore: score,
|
||||
riskLevel,
|
||||
narrative,
|
||||
metrics: {
|
||||
deliveryDays: supplier.avg_delivery_days,
|
||||
defectRate: supplier.defect_rate,
|
||||
responseHours: supplier.avg_response_hours,
|
||||
priceStability: supplier.price_stability
|
||||
},
|
||||
isFactory: supplier.isSourceFactory
|
||||
supplierId,
|
||||
trustScore: 0.85,
|
||||
riskLevel: 'LOW',
|
||||
lastUpdated: new Date()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* [BIZ_SUP_15] 推荐最优供应商
|
||||
*/
|
||||
static async recommendBestSupplier(productId: string, tenantId: string): Promise<string | null> {
|
||||
logger.info(`[Supplier] Recommending best supplier for Product: ${productId}, Tenant: ${tenantId}`);
|
||||
|
||||
const suppliers = await db(this.TABLE_NAME)
|
||||
.where({ tenant_id: tenantId })
|
||||
.orderBy('rating_score', 'desc')
|
||||
.limit(1);
|
||||
|
||||
return suppliers.length > 0 ? suppliers[0].id : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* [BIZ_AI_16-EXT] 更新供应商状态或执行切换建议
|
||||
*/
|
||||
static async updateSupplierStatus(supplierId: string, status: string, notes?: string): Promise<void> {
|
||||
logger.info(`[Supplier] Updating status for ${supplierId} to ${status}. Notes: ${notes}`);
|
||||
|
||||
await db(this.TABLE_NAME).where({ id: supplierId }).update({
|
||||
risk_level: status === 'BLOCK' ? 'HIGH' : 'LOW',
|
||||
legal_notices: notes,
|
||||
updated_at: new Date()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user