Skip to content

Commit b4518f3

Browse files
committed
fix(ai): 前后端字段契约对齐 camelCase——修复 AI 精修成本确认白屏 (est.est_cost_yuan undefined toFixed)
1 parent c103fcd commit b4518f3

4 files changed

Lines changed: 48 additions & 48 deletions

File tree

‎app/src/components/AiRefineCard.tsx‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ export default function AiRefineCard({ sessionId, onApplied }: { sessionId: numb
145145
}
146146
setEstimate(est);
147147
setBalance(bal);
148-
setRemember(est.remember_cost_choice);
148+
setRemember(est.rememberCostChoice);
149149
// 已"记住此选择"且同意过 → 跳过确认直接开始
150-
if (est.remember_cost_choice) {
150+
if (est.rememberCostChoice) {
151151
void start(est);
152152
} else {
153153
setPhase("confirm");
@@ -220,7 +220,7 @@ export default function AiRefineCard({ sessionId, onApplied }: { sessionId: numb
220220
)}
221221
{phase === "done" && (
222222
<span style={{ fontSize: 11, color: "#0d9488" }}>
223-
新增 {result?.added_lines} 行 · 删除 {result?.removed_lines} 行 · 切片 {result?.slices}
223+
新增 {result?.addedLines} 行 · 删除 {result?.removedLines} 行 · 切片 {result?.slices}
224224
</span>
225225
)}
226226
</div>
@@ -246,9 +246,9 @@ export default function AiRefineCard({ sessionId, onApplied }: { sessionId: numb
246246
<div style={{ border: "1px solid #e5e7eb", background: "#fff", borderRadius: 6, padding: 8, marginBottom: 6, fontSize: 12 }}>
247247
<div style={{ fontWeight: 600, marginBottom: 4 }}>成本确认</div>
248248
<div>
249-
预估 token:<strong>{est.est_tokens}</strong> · 预估费用:<strong>¥{est.est_cost_yuan.toFixed(4)}</strong>
250-
{est.price_per_1m > 0 && <span style={{ color: "#6b7280" }}>(单价 ¥{est.price_per_1m}/1M token)</span>}
251-
{est.price_per_1m === 0 && <span style={{ color: "#0d9488" }}>(当前模型免费档 ¥0)</span>}
249+
预估 token:<strong>{est.estTokens}</strong> · 预估费用:<strong>¥{est.estCostYuan.toFixed(4)}</strong>
250+
{est.pricePer1m > 0 && <span style={{ color: "#6b7280" }}>(单价 ¥{est.pricePer1m}/1M token)</span>}
251+
{est.pricePer1m === 0 && <span style={{ color: "#0d9488" }}>(当前模型免费档 ¥0)</span>}
252252
</div>
253253
{balance && (
254254
<div style={{ color: balance.lowBalanceWarning ? "#dc2626" : "#374151" }}>

‎app/src/components/EnrichPanel.tsx‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export default function EnrichPanel({ noteId, onUpdated }: { noteId: number; onU
208208
if (!result) return;
209209
await invoke<{ id: number }>("ai_enrich_revert", {
210210
noteId,
211-
baseMarkdown: result.base_markdown,
211+
baseMarkdown: result.baseMarkdown,
212212
}).catch((e) => setMsg(`撤销失败:${e}`));
213213
setMsg("已撤销补充(内容还原补充前——删除无残留)");
214214
onUpdated?.();
@@ -237,7 +237,7 @@ export default function EnrichPanel({ noteId, onUpdated }: { noteId: number; onU
237237
)}
238238
{phase === "done" && result && (
239239
<span style={{ fontSize: 11, color: "#7c3aed" }}>
240-
深度 {result.depth_blocks} · 广度 {result.breadth_blocks} · 切片 {result.blocks}
240+
深度 {result.depthBlocks} · 广度 {result.breadthBlocks} · 切片 {result.blocks}
241241
</span>
242242
)}
243243
</div>
@@ -281,8 +281,8 @@ export default function EnrichPanel({ noteId, onUpdated }: { noteId: number; onU
281281
<div style={{ border: "1px solid #e5e7eb", background: "#fff", borderRadius: 6, padding: 8, marginBottom: 6, fontSize: 12 }}>
282282
<div style={{ fontWeight: 600, marginBottom: 4 }}>成本确认</div>
283283
<div>
284-
预估 token:<strong>{est.est_tokens}</strong> · 预估费用:<strong>¥{est.est_cost_yuan.toFixed(4)}</strong>
285-
{est.est_cost_yuan === 0 && <span style={{ color: "#0d9488" }}>(当前模型免费档 ¥0)</span>}
284+
预估 token:<strong>{est.estTokens}</strong> · 预估费用:<strong>¥{est.estCostYuan.toFixed(4)}</strong>
285+
{est.estCostYuan === 0 && <span style={{ color: "#0d9488" }}>(当前模型免费档 ¥0)</span>}
286286
</div>
287287
{balance && (
288288
<div style={{ color: balance.lowBalanceWarning ? "#dc2626" : "#374151" }}>
@@ -318,7 +318,7 @@ export default function EnrichPanel({ noteId, onUpdated }: { noteId: number; onU
318318
{phase === "done" && result && (
319319
<div>
320320
<div style={{ maxHeight: 200, overflowY: "auto", border: "1px solid #e5e7eb", borderRadius: 6, background: "#fff", padding: 8, fontSize: 11, fontFamily: "monospace", marginBottom: 6, whiteSpace: "pre-wrap" }}>
321-
{result.enriched_markdown.slice(-800)}
321+
{result.enrichedMarkdown.slice(-800)}
322322
</div>
323323
<div style={{ display: "flex", gap: 6 }}>
324324
<button style={{ ...btn, background: "#7c3aed", color: "#fff", border: "none" }} onClick={() => void apply()}>

‎app/src/components/VersionPanel.tsx‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export default function VersionPanel({ noteId, onChanged }: { noteId: number; on
7676
const rollback = async (versionId: number) => {
7777
const v = versions.find((x) => x.id === versionId);
7878
if (!v) return;
79-
if (!window.confirm(`回滚到「${SOURCE_BADGE[v.source].label}」版本(${fmtTime(v.created_at)})?将创建新版本,历史链保留。`)) return;
79+
if (!window.confirm(`回滚到「${SOURCE_BADGE[v.source].label}」版本(${fmtTime(v.createdAt)})?将创建新版本,历史链保留。`)) return;
8080
try {
8181
await invoke<{ id: number }>("note_versions_rollback", { noteId, targetVersionId: versionId });
8282
setMsg("已回滚(新版本 user-edit,历史链未破坏)");
@@ -87,7 +87,7 @@ export default function VersionPanel({ noteId, onChanged }: { noteId: number; on
8787
}
8888
};
8989

90-
const totalCost = usage.reduce((s, u) => s + u.cost_yuan, 0);
90+
const totalCost = usage.reduce((s, u) => s + u.costYuan, 0);
9191

9292
return (
9393
<div style={{ border: "1px solid #e5e7eb", borderRadius: 8, padding: 10, marginBottom: 10, background: "#fcfcfd" }}>
@@ -108,11 +108,11 @@ export default function VersionPanel({ noteId, onChanged }: { noteId: number; on
108108
const badge = SOURCE_BADGE[v.source] ?? SOURCE_BADGE.rule;
109109
return (
110110
<div key={v.id} style={{ display: "flex", gap: 8, alignItems: "center", padding: "4px 8px", borderBottom: "1px solid #f3f4f6", fontSize: 11 }}>
111-
<span style={{ color: "#6b7280", width: 110, flexShrink: 0 }}>{fmtTime(v.created_at)}</span>
111+
<span style={{ color: "#6b7280", width: 110, flexShrink: 0 }}>{fmtTime(v.createdAt)}</span>
112112
<span style={{ color: badge.color, background: badge.bg, borderRadius: 8, padding: "1px 8px", fontWeight: 600 }}>{badge.label}</span>
113-
{v.meta.cost_yuan != null && <span style={{ color: "#b45309" }}>¥{v.meta.cost_yuan.toFixed(4)}</span>}
113+
{v.meta.costYuan != null && <span style={{ color: "#b45309" }}>¥{v.meta.costYuan.toFixed(4)}</span>}
114114
{v.meta.model && <span style={{ color: "#9ca3af", maxWidth: 120, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{v.meta.model}</span>}
115-
{v.meta.merged_from && <span style={{ color: "#9ca3af" }} title={v.meta.merged_from}>· 已合并</span>}
115+
{v.meta.mergedFrom && <span style={{ color: "#9ca3af" }} title={v.meta.mergedFrom}>· 已合并</span>}
116116
<span style={{ flex: 1 }} />
117117
{i !== versions.length - 1 && (
118118
<button style={{ ...btn, color: "#b45309" }} onClick={() => void rollback(v.id)}>
@@ -150,7 +150,7 @@ export default function VersionPanel({ noteId, onChanged }: { noteId: number; on
150150
<div style={{ fontSize: 11, fontWeight: 600, color: "#374151", marginBottom: 4 }}>AI 成本记录</div>
151151
{usage.map((u) => (
152152
<div key={u.id} style={{ fontSize: 11, color: "#6b7280", padding: "2px 0" }}>
153-
{fmtTime(u.created_at)} · {u.op_type === "refine" ? "精修" : "补充"} · in {u.tokens_in} / out {u.tokens_out} token · ¥{u.cost_yuan.toFixed(4)} · {u.model} · {u.slices} 片
153+
{fmtTime(u.createdAt)} · {u.opType === "refine" ? "精修" : "补充"} · in {u.tokensIn} / out {u.tokensOut} token · ¥{u.costYuan.toFixed(4)} · {u.model} · {u.slices} 片
154154
</div>
155155
))}
156156
</div>

‎app/src/types.ts‎

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -705,30 +705,30 @@ export interface AiTaskHandle {
705705
/** 段级 diff 操作(Rust DiffOp:三态外部标签) */
706706
export type DiffOp = { unchanged: string } | { added: string } | { removed: string };
707707

708-
/** 精修结果(Rust AiRefineResult——diff 预览 + 采纳落库数据源) */
708+
/** 精修结果(Rust AiRefineResult——diff 预览 + 采纳落库数据源;camelCase 契约) */
709709
export interface AiRefineResult {
710710
title: string;
711711
/** 规则基线(采纳落库时作为首快照——版本链 [rule, ai-refine]) */
712-
base_markdown: string;
713-
refined_markdown: string;
712+
baseMarkdown: string;
713+
refinedMarkdown: string;
714714
diff: DiffOp[];
715-
added_lines: number;
716-
removed_lines: number;
715+
addedLines: number;
716+
removedLines: number;
717717
slices: number;
718718
model: string;
719719
}
720720

721-
/** 成本预估(Rust CostEstimate) */
721+
/** 成本预估(Rust CostEstimate;camelCase 契约) */
722722
export interface CostEstimate {
723-
est_tokens: number;
724-
est_cost_yuan: number;
725-
price_per_1m: number;
723+
estTokens: number;
724+
estCostYuan: number;
725+
pricePer1m: number;
726726
}
727727

728-
/** 精修成本预估视图(Rust RefineEstimateView) */
728+
/** 精修成本预估视图(Rust RefineEstimateView;camelCase 契约) */
729729
export interface RefineEstimateView {
730730
estimate: CostEstimate;
731-
remember_cost_choice: boolean;
731+
rememberCostChoice: boolean;
732732
}
733733

734734
// ────────────────────────────────────────────────────────────
@@ -738,14 +738,14 @@ export interface RefineEstimateView {
738738
/** 补充子项(Rust AiEnrichKind;kebab-case——d1~d3 深度/b1~b6 广度) */
739739
export type EnrichKind = "d1" | "d2" | "d3" | "b1" | "b2" | "b3" | "b4" | "b5" | "b6";
740740

741-
/** 补充结果(Rust AiEnrichResult——混合落位 markdown + base 供撤销) */
741+
/** 补充结果(Rust AiEnrichResult——混合落位 markdown + base 供撤销;camelCase) */
742742
export interface AiEnrichResult {
743-
note_id: number;
744-
base_markdown: string;
745-
enriched_markdown: string;
743+
noteId: number;
744+
baseMarkdown: string;
745+
enrichedMarkdown: string;
746746
blocks: number;
747-
depth_blocks: number;
748-
breadth_blocks: number;
747+
depthBlocks: number;
748+
breadthBlocks: number;
749749
slices: number;
750750
kinds: string[];
751751
model: string;
@@ -758,35 +758,35 @@ export interface AiEnrichResult {
758758
/** 版本来源(Rust NoteVersionSource;kebab-case) */
759759
export type NoteVersionSource = "rule" | "ai-refine" | "ai-enrich" | "user-edit";
760760

761-
/** 版本元数据(Rust VersionMeta) */
761+
/** 版本元数据(Rust VersionMeta;camelCase 契约) */
762762
export interface VersionMeta {
763-
cost_yuan: number | null;
763+
costYuan: number | null;
764764
model: string | null;
765765
slices: number | null;
766-
merged_from: string | null;
766+
mergedFrom: string | null;
767767
}
768768

769-
/** 版本快照(Rust NoteVersion) */
769+
/** 版本快照(Rust NoteVersion;camelCase 契约) */
770770
export interface NoteVersion {
771771
id: number;
772-
note_id: number;
772+
noteId: number;
773773
content: string;
774774
source: NoteVersionSource;
775-
parent_id: number | null;
776-
created_at: number;
775+
parentId: number | null;
776+
createdAt: number;
777777
meta: VersionMeta;
778778
}
779779

780-
/** AI 成本记录(Rust AiUsageRecord) */
780+
/** AI 成本记录(Rust AiUsageRecord;camelCase 契约) */
781781
export interface AiUsageRecord {
782782
id: number;
783-
note_id: number;
784-
op_type: string;
785-
tokens_in: number;
786-
tokens_out: number;
787-
cost_yuan: number;
783+
noteId: number;
784+
opType: string;
785+
tokensIn: number;
786+
tokensOut: number;
787+
costYuan: number;
788788
model: string;
789789
slices: number;
790-
created_at: number;
790+
createdAt: number;
791791
}
792792

0 commit comments

Comments
 (0)