feat(comparison-records): 比价记录展示 LLM 实际成本(列表列 + 详情 + 价格快照)
- 列表「成本」列优先显示后端冻结的实际成本(当时价/绿色),无则回退前端估算(灰色) - 详情抽屉「LLM 成本」:有 llm_cost_yuan 显示实际值 +「实际·当时价」标,无则回退估算; 另展示所用单价快照 JSON - types.ts:ComparisonRecordListItem 加 llm_cost_yuan(详情继承) - 顺带:InputNumber addonAfter → suffix(消 antd 弃用警告);详情 llm_calls 遍历对 input_messages 加空值防御(残缺数据不再整页白屏) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -215,7 +215,16 @@ export default function ComparisonRecordsPage() {
|
||||
title: '成本',
|
||||
key: 'cost',
|
||||
width: 90,
|
||||
render: (_, r) => fmtCost(calcCost(r.input_tokens, r.output_tokens, pricePerMTok)),
|
||||
// 有后端冻结的实际成本(当时价)就用它;否则回退老的前端估算(需顶部填 LLM 单价)。
|
||||
render: (_, r) => {
|
||||
if (r.llm_cost_yuan != null) {
|
||||
return <span title="实际成本(按调用时单价冻结)" style={{ color: '#389e0d' }}>{fmtCost(r.llm_cost_yuan)}</span>;
|
||||
}
|
||||
const est = calcCost(r.input_tokens, r.output_tokens, pricePerMTok);
|
||||
return est == null
|
||||
? '-'
|
||||
: <span title="估算(顶部 LLM 单价 × token)" style={{ color: '#999' }}>{fmtCost(est)}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '机型/ROM',
|
||||
@@ -292,7 +301,7 @@ export default function ComparisonRecordsPage() {
|
||||
min={0}
|
||||
step={0.1}
|
||||
style={{ width: 210 }}
|
||||
addonAfter="元/百万token"
|
||||
suffix="元/百万token"
|
||||
/>
|
||||
</Space>
|
||||
|
||||
@@ -331,12 +340,27 @@ export default function ComparisonRecordsPage() {
|
||||
? '-'
|
||||
: `${detail.input_tokens ?? 0} / ${detail.output_tokens ?? 0} / ${(detail.input_tokens ?? 0) + (detail.output_tokens ?? 0)}`}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="估算成本">
|
||||
{fmtCost(calcCost(detail.input_tokens, detail.output_tokens, pricePerMTok))}
|
||||
{pricePerMTok == null && (detail.input_tokens != null || detail.output_tokens != null)
|
||||
? <span style={{ color: '#999', fontSize: 12 }}>(顶部填 LLM 单价后显示)</span>
|
||||
: null}
|
||||
<Descriptions.Item label="LLM 成本">
|
||||
{detail.llm_cost_yuan != null ? (
|
||||
<>
|
||||
{fmtCost(detail.llm_cost_yuan)}
|
||||
<Tag color="green" style={{ marginLeft: 6 }}>实际·当时价</Tag>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{fmtCost(calcCost(detail.input_tokens, detail.output_tokens, pricePerMTok))}
|
||||
<span style={{ color: '#999', fontSize: 12, marginLeft: 6 }}>估算</span>
|
||||
{pricePerMTok == null && (detail.input_tokens != null || detail.output_tokens != null)
|
||||
? <span style={{ color: '#999', fontSize: 12 }}>(顶部填 LLM 单价后显示)</span>
|
||||
: null}
|
||||
</>
|
||||
)}
|
||||
</Descriptions.Item>
|
||||
{detail.llm_price_snapshot ? (
|
||||
<Descriptions.Item label="价格快照" span={2}>
|
||||
<pre style={preStyle}>{JSON.stringify(detail.llm_price_snapshot, null, 2)}</pre>
|
||||
</Descriptions.Item>
|
||||
) : null}
|
||||
<Descriptions.Item label="源平台">{detail.source_platform_name || '-'}({cents(detail.source_price_cents)})</Descriptions.Item>
|
||||
<Descriptions.Item label="最优">{detail.best_platform_name || '-'}({cents(detail.best_price_cents)})</Descriptions.Item>
|
||||
<Descriptions.Item label="省" span={2}>{cents(detail.saved_amount_cents)}{detail.is_source_best ? '(源平台最便宜)' : ''}</Descriptions.Item>
|
||||
@@ -432,7 +456,7 @@ export default function ComparisonRecordsPage() {
|
||||
),
|
||||
children: (
|
||||
<div>
|
||||
{c.input_messages.map((m, j) => (
|
||||
{(c.input_messages ?? []).map((m, j) => (
|
||||
<div key={j} style={{ marginBottom: 8 }}>
|
||||
<Tag>{m.role}</Tag>
|
||||
<pre style={preStyle}>{pretty(m.content)}</pre>
|
||||
|
||||
@@ -354,6 +354,7 @@ export interface ComparisonRecordListItem {
|
||||
retry_count: number | null;
|
||||
input_tokens: number | null;
|
||||
output_tokens: number | null;
|
||||
llm_cost_yuan: number | null; // 后端按「当时价」冻结的实际成本(元);旧记录 null → 「成本」列回退估算
|
||||
device_model: string | null;
|
||||
rom_vendor: string | null;
|
||||
rom_name: string | null;
|
||||
@@ -396,6 +397,8 @@ export interface ComparisonRecordDetail extends ComparisonRecordListItem {
|
||||
latitude: number | null;
|
||||
llm_calls: LlmCall[] | null;
|
||||
raw_payload: Record<string, unknown> | null;
|
||||
// 算成本所用单价快照 {mode, prices:{model:{...}}}(llm_cost_yuan 继承自列表项)。
|
||||
llm_price_snapshot: Record<string, unknown> | null;
|
||||
}
|
||||
|
||||
export interface AdRevenueImpression {
|
||||
|
||||
Reference in New Issue
Block a user