Skip to content

Commit f716e0f

Browse files
committed
feat(settlement): 组面板结算仪式交互
1 parent 497de33 commit f716e0f

2 files changed

Lines changed: 71 additions & 1 deletion

File tree

‎app/src/components/NoteGroupPanel.tsx‎

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ function kindBadge(kind: string): { label: string; color: string } {
2727
return { label: "📄 独立", color: "#6b7280" };
2828
}
2929

30+
/** 结算计划(v0.11.3;仪式第一步——呈现沼泽全貌) */
31+
interface SettlementPlan {
32+
itemCount: number;
33+
due: boolean;
34+
lastSettledAt: number | null;
35+
mergePairs: { keepId: number; dropId: number; keepText: string; dropText: string }[];
36+
archiveCandidates: { id: number; text: string }[];
37+
}
38+
3039
/** 解析路由理由 JSON(损坏防御性回退空对象)。 */
3140
export function parseRouteReason(raw: string | null): GroupRouteReason {
3241
if (!raw) return {};
@@ -62,6 +71,8 @@ export default function NoteGroupPanel({ groupFilter, onGroupFilterChange, selec
6271
// 改判表单态(展开区消费)
6372
const [overrideKind, setOverrideKind] = useState("standalone");
6473
const [overrideDomain, setOverrideDomain] = useState("");
74+
// v0.11.3:结算计划态(展开区仪式)
75+
const [settlePlan, setSettlePlan] = useState<SettlementPlan | null>(null);
6576

6677
const load = useCallback(async () => {
6778
try {
@@ -155,6 +166,32 @@ export default function NoteGroupPanel({ groupFilter, onGroupFilterChange, selec
155166
}
156167
};
157168

169+
// ── v0.11.3:组结算仪式(先呈现计划,用户确认后执行)──
170+
const runSettlementPlan = async (g: NoteGroup) => {
171+
try {
172+
const plan = await invoke<SettlementPlan>("settlement_plan", { groupId: g.id });
173+
setSettlePlan(plan);
174+
setStatus("");
175+
} catch (e) {
176+
setStatus(`结算计划失败: ${e}`);
177+
}
178+
};
179+
180+
const runExecuteSettlement = async (g: NoteGroup) => {
181+
try {
182+
const r = await invoke<{ merged: number; archived: number; coreNoteId: number | null }>(
183+
"execute_settlement",
184+
{ groupId: g.id, applyMerges: true, applyArchives: true },
185+
);
186+
setSettlePlan(null);
187+
setStatus(`结算完成:合并 ${r.merged} 条重复、归档 ${r.archived} 条低价值,已生成核心提炼笔记`);
188+
await load();
189+
onChanged();
190+
} catch (e) {
191+
setStatus(`结算执行失败: ${e}`);
192+
}
193+
};
194+
158195
return (
159196
<div style={{ width: 230, flexShrink: 0, borderRight: "1px solid #e5e7eb", display: "flex", flexDirection: "column" }}>
160197
<div style={{ padding: "10px 12px", borderBottom: "1px solid #e5e7eb", fontWeight: 600, display: "flex", alignItems: "center", gap: 8 }}>
@@ -231,7 +268,7 @@ export default function NoteGroupPanel({ groupFilter, onGroupFilterChange, selec
231268
</span>
232269
<span style={{ fontSize: 11, color: "#9ca3af" }}>{g.noteCount}</span>
233270
<span
234-
onClick={(e) => { e.stopPropagation(); setExpandedId(expanded ? null : g.id); setOverrideKind(g.kind); setOverrideDomain(g.domainTag ?? ""); }}
271+
onClick={(e) => { e.stopPropagation(); setExpandedId(expanded ? null : g.id); setOverrideKind(g.kind); setOverrideDomain(g.domainTag ?? ""); setSettlePlan(null); }}
235272
style={{ fontSize: 11, color: "#6b7280", cursor: "pointer", padding: "0 3px" }}
236273
title="路由详情/改判"
237274
>
@@ -292,6 +329,12 @@ export default function NoteGroupPanel({ groupFilter, onGroupFilterChange, selec
292329
style={{ fontSize: 11, cursor: "pointer", padding: "2px 8px", borderRadius: 4, border: "1px solid #d1d5db", background: "#fff" }}>
293330
🎴 复习本组
294331
</button>
332+
{/* v0.11.3:组结算入口(防沼泽仪式) */}
333+
<button onClick={() => void runSettlementPlan(g)}
334+
style={{ fontSize: 11, cursor: "pointer", padding: "2px 8px", borderRadius: 4, border: "1px solid #d1d5db", background: "#fff" }}
335+
title="对账本组:提炼核心/合并重复/归档低价值">
336+
🧹 结算
337+
</button>
295338
{selectedNoteId != null && (
296339
<>
297340
<button onClick={() => void runMove(g.id)}
@@ -305,6 +348,32 @@ export default function NoteGroupPanel({ groupFilter, onGroupFilterChange, selec
305348
</>
306349
)}
307350
</div>
351+
{/* v0.11.3:结算计划呈现(仪式第一步:看见沼泽全貌再动手) */}
352+
{settlePlan && (
353+
<div style={{ marginTop: 8, padding: 8, background: "#fff", borderRadius: 6, border: "1px solid #e5e7eb" }}>
354+
<div style={{ fontWeight: 600, color: "#374151", marginBottom: 4 }}>
355+
结算计划 · 共 {settlePlan.itemCount} 条目
356+
{settlePlan.due && <span style={{ color: "#b45309", marginLeft: 6 }}>⚠ 建议结算</span>}
357+
</div>
358+
<div style={{ color: "#6b7280" }}>重复合并:{settlePlan.mergePairs.length} 对(保留长文本,归档短重复)</div>
359+
{settlePlan.mergePairs.slice(0, 3).map((p) => (
360+
<div key={p.dropId} style={{ color: "#9ca3af", paddingLeft: 6, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
361+
「{p.keepText.slice(0, 18)}…」⇐「{p.dropText.slice(0, 18)}…」
362+
</div>
363+
))}
364+
<div style={{ color: "#6b7280", marginTop: 2 }}>低价值归档:{settlePlan.archiveCandidates.length} 条(老化且无卡绑定,可恢复)</div>
365+
<div style={{ display: "flex", gap: 4, marginTop: 6 }}>
366+
<button onClick={() => void runExecuteSettlement(g)}
367+
style={{ fontSize: 11, cursor: "pointer", padding: "2px 10px", borderRadius: 4, border: "1px solid #0f766e", background: "#f0fdfa", color: "#0f766e" }}>
368+
✓ 执行结算(含核心提炼)
369+
</button>
370+
<button onClick={() => setSettlePlan(null)}
371+
style={{ fontSize: 11, cursor: "pointer", padding: "2px 8px", borderRadius: 4, border: "1px solid #d1d5db", background: "#fff" }}>
372+
取消
373+
</button>
374+
</div>
375+
</div>
376+
)}
308377
</div>
309378
)}
310379
</div>

‎docs/standards/line-limit-exemptions.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
| app/src/components/SessionDetailPanel.tsx | 371 | 会话详情面板:质量报告/段列表/OCR 概览/操作区单一面板完整交互流内聚(前端审查登记) | 若再增长:质量报告区拆至 SessionQualityReport.tsx |
6666
| app/src/components/ProfileDetector.tsx | 346 | 档案检测组件:投票/确认流/记忆偏好 UI 内聚(前端审查登记) | 若再增长:确认流拆至 ProfileConfirmFlow.tsx |
6767
| app/src/components/NoteEditView.tsx | 315 | 笔记编辑视图:编辑态/标签/结构面板内聚(前端审查登记) | 若再增长:结构面板拆至 NoteStructurePane.tsx |
68+
| app/src/components/NoteGroupPanel.tsx | 371 | v0.11.0~3 笔记组侧栏:组列表/路由可见可改/碎片捕获/闪卡生成与复习入口/结算仪式——组域交互单一面板内聚 | 若再增长:结算仪式区拆至 GroupSettlementPane.tsx |
6869

6970
> 前端 **拆分中**(Task #9 笔记域修复进行中,暂不登记行数):`app/src/types.ts`、`app/src/pages/NotesPage.tsx`——待前端拆分完成后以实测行数重新评估。
7071
> 前端 SessionsPage.tsx 审查快照 304 行(登记值),v0.7.1 硬拆后长期 ≤300,本轮审查期间轻微越线;随 NotesPage/types.ts 拆分任务一并复核,若仍越线按上表模式登记。

0 commit comments

Comments
 (0)