Files
makemd/server/src/services/CarbonCostGameService.ts

94 lines
3.2 KiB
TypeScript
Raw Normal View History

import db from '../config/database';
import { AuditService } from './AuditService';
import { PathSimulatorService } from './PathSimulatorService';
/**
* [BIZ_TRADE_19]
* (ESG)
*/
export class CarbonCostGameService {
/**
*
*/
static async runPathGame(
tenantId: string,
orderId: string,
traceId: string
): Promise<{ selectedMode: string; carbon: number; cost: number }> {
// 1. 获取订单基础信息
const order = await db('cf_orders').where({ id: orderId }).first();
if (!order) throw new Error('Order not found');
// 2. 调用 PathSimulatorService 获取不同路径选项 (模拟多维度路径计算)
const options = [
{ mode: 'AIR', cost: 45.0, carbon: 15.2, reliability: 0.99, tsl: 3 },
{ mode: 'SEA', cost: 12.0, carbon: 0.8, reliability: 0.85, tsl: 25 },
{ mode: 'RAIL', cost: 22.0, carbon: 2.5, reliability: 0.92, tsl: 15 },
{ mode: 'TRUCK', cost: 28.0, carbon: 5.4, reliability: 0.90, tsl: 10 }
];
// 3. 博弈评分逻辑 (Game Score Calculation)
// 目标min(Cost) + min(Carbon) + max(Reliability)
// 权重可根据租户偏好动态调整 (这里假设 4:4:2)
const weights = { cost: 0.4, carbon: 0.4, reliability: 0.2 };
// 归一化计算
const gameResults = options.map(opt => {
// 评分越高越好 (对 Cost 和 Carbon 取倒数)
const score = (1 / opt.cost) * weights.cost +
(1 / opt.carbon) * weights.carbon +
opt.reliability * weights.reliability;
return { ...opt, score };
});
// 4. 选择得分最高的路径
const bestOption = gameResults.reduce((prev, curr) => curr.score > prev.score ? curr : prev);
await db.transaction(async (trx) => {
// 5. 持久化博弈结果
await trx('cf_carbon_cost_game').insert({
tenant_id: tenantId,
order_id: orderId,
carbon_footprint: bestOption.carbon,
shipping_cost: bestOption.cost,
game_score: bestOption.score,
selected_mode: bestOption.mode,
logic_description: JSON.stringify({
alternatives: gameResults,
weights
})
});
// 6. 审计记录
await AuditService.log({
tenant_id: tenantId,
action: 'CARBON_COST_GAME_COMPLETED',
target_type: 'LOGISTICS_ROUTE',
target_id: orderId,
trace_id: traceId,
new_data: JSON.stringify({ selectedMode: bestOption.mode, score: bestOption.score }),
metadata: JSON.stringify({ carbon: bestOption.carbon, cost: bestOption.cost })
});
});
return {
selectedMode: bestOption.mode,
carbon: bestOption.carbon,
cost: bestOption.cost
};
}
/**
*
*/
static async getCarbonSummary(tenantId: string) {
const summary = await db('cf_carbon_cost_game')
.where({ tenant_id: tenantId })
.select('selected_mode')
.sum('carbon_footprint as total_carbon')
.count('* as count')
.groupBy('selected_mode');
return summary;
}
}