|
|
@@ -1,8 +1,10 @@
|
|
|
"use client";
|
|
|
|
|
|
+import { useState } from "react";
|
|
|
import Link from "next/link";
|
|
|
-import { GitBranch, ListVideo } from "lucide-react";
|
|
|
+import { GitBranch, Info, ListVideo } from "lucide-react";
|
|
|
import { AppShell } from "@/components/AppShell";
|
|
|
+import { BusinessDrawer, type BusinessDrawerState } from "@/components/BusinessDrawer";
|
|
|
import { EmptyState, ErrorState, LoadingState } from "@/components/StateBlocks";
|
|
|
import {
|
|
|
assetDetailText,
|
|
|
@@ -19,6 +21,7 @@ import { useFlowLedger } from "./useFlowLedger";
|
|
|
|
|
|
export function LedgerPage({ runId }: { runId: string }) {
|
|
|
const { ledger, loading, error, reload } = useFlowLedger(runId);
|
|
|
+ const [drawer, setDrawer] = useState<BusinessDrawerState>(null);
|
|
|
|
|
|
const rows = ledger?.rows || [];
|
|
|
|
|
|
@@ -51,7 +54,7 @@ export function LedgerPage({ runId }: { runId: string }) {
|
|
|
<DemandCell demand={ledger.demandSummary} isFirst={row.id === rows[0]?.id} />
|
|
|
<SourceCell row={row} />
|
|
|
<VideoCell runId={runId} row={row} />
|
|
|
- <RuleSummaryCell row={row} />
|
|
|
+ <RuleSummaryCell row={row} onOpenScore={setDrawer} />
|
|
|
<WalkCell runId={runId} row={row} />
|
|
|
<AssetCell row={row} />
|
|
|
</tr>
|
|
|
@@ -59,6 +62,7 @@ export function LedgerPage({ runId }: { runId: string }) {
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</section>
|
|
|
+ <BusinessDrawer drawer={drawer} onClose={() => setDrawer(null)} />
|
|
|
</>
|
|
|
) : null}
|
|
|
</AppShell>
|
|
|
@@ -203,7 +207,7 @@ function VideoMini({ runId, video }: { runId: string; video: VideoRef }) {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
-function RuleSummaryCell({ row }: { row: FlowLedgerRow }) {
|
|
|
+function RuleSummaryCell({ row, onOpenScore }: { row: FlowLedgerRow; onOpenScore: (drawer: BusinessDrawerState) => void }) {
|
|
|
return (
|
|
|
<td className="rules-cell">
|
|
|
<div className="cell-stack">
|
|
|
@@ -213,11 +217,55 @@ function RuleSummaryCell({ row }: { row: FlowLedgerRow }) {
|
|
|
<span className="chip yellow">待复看 {row.ruleSummary.reviewCount}</span>
|
|
|
<span className="chip">淘汰 {row.ruleSummary.rejectCount}</span>
|
|
|
</div>
|
|
|
+ <button className="mini-button score-rule-button" type="button" onClick={() => onOpenScore(scoreRuleDrawer(row))}>
|
|
|
+ <Info size={13} />
|
|
|
+ 打分规则
|
|
|
+ </button>
|
|
|
</div>
|
|
|
</td>
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+function scoreRuleDrawer(row: FlowLedgerRow): BusinessDrawerState {
|
|
|
+ return {
|
|
|
+ title: "渠道判断打分规则",
|
|
|
+ sections: [
|
|
|
+ {
|
|
|
+ label: "本格结果",
|
|
|
+ value: `${ruleHeadline(row)}。入池 ${row.ruleSummary.passCount} 条,待复看 ${row.ruleSummary.reviewCount} 条,淘汰 ${row.ruleSummary.rejectCount} 条。`,
|
|
|
+ tone: row.ruleSummary.passCount ? "good" : row.ruleSummary.reviewCount ? "warn" : "neutral"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "总分怎么来",
|
|
|
+ value: "总分 = 是否契合需求 50% + 平台表现 50%。",
|
|
|
+ tone: "info"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "两个评分项",
|
|
|
+ items: [
|
|
|
+ "是否契合需求(50%):看视频内容是否贴合本次需求和当前 query。",
|
|
|
+ "平台表现(50%):看点赞、评论、转发等平台反馈综合表现。"
|
|
|
+ ],
|
|
|
+ tone: "neutral"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "怎么判定",
|
|
|
+ items: [
|
|
|
+ "入池:通常总分达到 70 分以上,内容可以进入后续使用。",
|
|
|
+ "待复看:通常 55-69 分,或系统认为还需要人工确认。",
|
|
|
+ "淘汰:通常低于 55 分,或内容明显不契合本次需求。"
|
|
|
+ ],
|
|
|
+ tone: "neutral"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "和继续游走的关系",
|
|
|
+ value: "入池不等于一定继续游走。继续游走还要同时看总分、是否契合需求、平台表现三项门槛。",
|
|
|
+ tone: "warn"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
function WalkCell({ runId, row }: { runId: string; row: FlowLedgerRow }) {
|
|
|
return (
|
|
|
<td className="walk-cell">
|