|
|
@@ -60,7 +60,7 @@ export function QueryWalkPage({ runId, queryId }: { runId: string; queryId: stri
|
|
|
<span className="tag-mini">{groups.length ? `${groups.length} 个起点` : "没有继续扩展"}</span>
|
|
|
</summary>
|
|
|
<div className="decl-body">
|
|
|
- <Summary label="怎么看" value="先看左侧起点视频,再沿着右侧路线看:从哪里触发、生成了什么、带回哪些视频。" />
|
|
|
+ <Summary label="怎么看" value="每个白色块是一条起点视频;视频下面缩进的路线,就是它向外游走的标签、作者或翻页。" />
|
|
|
<Summary label="本轮概况" value={`已执行 ${Number(data.summary.success_count || 0)} 条路线 · 未执行 ${Number(data.summary.skipped_count || 0)} 条路线 · 新增搜索词 ${Number(data.summary.extension_query_count || 0)} 个`} />
|
|
|
</div>
|
|
|
</details>
|
|
|
@@ -98,26 +98,29 @@ function WalkGroupCard({ group, index, runId }: { group: WalkGroup; index: numbe
|
|
|
const score = group.video ? scoreSummary(asRecord(group.video.decision).score_items) : "";
|
|
|
|
|
|
return (
|
|
|
- <article className="walk-ledger-group" id={`source-${encodeURIComponent(group.id)}`}>
|
|
|
- <div className="walk-ledger-spine" />
|
|
|
- <section className="walk-source-card">
|
|
|
- <div className="walk-source-kicker">起点视频 {index + 1}</div>
|
|
|
- <h2>{titleParts.title}</h2>
|
|
|
- {titleParts.tags.length ? (
|
|
|
- <div className="walk-source-tags">
|
|
|
- {titleParts.tags.map((tag) => <span key={tag}>{tag}</span>)}
|
|
|
- </div>
|
|
|
- ) : null}
|
|
|
- <div className="walk-source-facts">
|
|
|
- <Fact label="作者" value={group.author} />
|
|
|
- <Fact label="判断" value={group.decisionLabel} tone={decisionTone(group.decisionLabel)} />
|
|
|
- {score ? <Fact label="评分" value={score} /> : null}
|
|
|
- {group.terminalLabel ? <Fact label="处理" value={group.terminalLabel} /> : null}
|
|
|
+ <article className="walk-story-block" id={`source-${encodeURIComponent(group.id)}`}>
|
|
|
+ <header className="walk-story-head">
|
|
|
+ <span className="walk-source-kicker">起点视频 {index + 1}</span>
|
|
|
+ <div className="walk-story-title">
|
|
|
+ <h2>{titleParts.title}</h2>
|
|
|
+ {titleParts.tags.length ? (
|
|
|
+ <div className="walk-source-tags">
|
|
|
+ {titleParts.tags.map((tag) => <span key={tag}>{tag}</span>)}
|
|
|
+ </div>
|
|
|
+ ) : null}
|
|
|
</div>
|
|
|
<VideoLinks video={group.video} runId={runId} />
|
|
|
- </section>
|
|
|
+ </header>
|
|
|
+
|
|
|
+ <div className="walk-source-facts">
|
|
|
+ <Fact label="作者" value={group.author} />
|
|
|
+ <Fact label="判断" value={group.decisionLabel} tone={decisionTone(group.decisionLabel)} />
|
|
|
+ {score ? <Fact label="评分" value={score} /> : null}
|
|
|
+ {group.terminalLabel ? <Fact label="处理" value={group.terminalLabel} /> : null}
|
|
|
+ </div>
|
|
|
|
|
|
- <section className="walk-route-stack" aria-label={`${group.title} 的游走路线`}>
|
|
|
+ <section className="walk-story-routes" aria-label={`${group.title} 的游走路线`}>
|
|
|
+ <div className="walk-story-routes-label">从这条视频继续往外找</div>
|
|
|
{routeActions.length ? routeActions.map((action, actionIndex) => (
|
|
|
<WalkRouteCard action={action} runId={runId} sourceId={group.id} key={`${text(action.id, "walk")}-${actionIndex}`} />
|
|
|
)) : <div className="walk-no-route">这条视频没有继续产生标签、作者或翻页路线。</div>}
|
|
|
@@ -147,51 +150,54 @@ function WalkRouteCard({ action, runId, sourceId }: { action: RawRecord; runId:
|
|
|
const secondNode = routeResultNode(action, targetQuery, targetVideos, isSuccess);
|
|
|
|
|
|
return (
|
|
|
- <article className={`walk-route-card ${edgeTone(edgeId)} ${isSuccess ? "success" : "stopped"}`} id={`route-${encodeURIComponent(text(action.id, routeName))}`}>
|
|
|
- <div className="walk-route-head">
|
|
|
- <span className="walk-edge-icon">{edgeIcon(edgeId)}</span>
|
|
|
- <div>
|
|
|
- <strong>{routeName}</strong>
|
|
|
- <p>{isSuccess ? successSentence(action, targetQuery, targetVideos) : stoppedSentence(action)}</p>
|
|
|
+ <article className={`walk-tree-route ${edgeTone(edgeId)} ${isSuccess ? "success" : "stopped"}`} id={`route-${encodeURIComponent(text(action.id, routeName))}`}>
|
|
|
+ <div className="walk-tree-route-dot" />
|
|
|
+ <div className="walk-tree-route-body">
|
|
|
+ <div className="walk-route-head">
|
|
|
+ <span className="walk-edge-icon">{edgeIcon(edgeId)}</span>
|
|
|
+ <div>
|
|
|
+ <strong>{routeName}</strong>
|
|
|
+ <p>{isSuccess ? successSentence(action, targetQuery, targetVideos) : stoppedSentence(action)}</p>
|
|
|
+ </div>
|
|
|
+ <span className={`chip ${isSuccess ? "green" : "yellow"}`}>{isSuccess ? "已执行" : "未执行"}</span>
|
|
|
</div>
|
|
|
- <span className={`chip ${isSuccess ? "green" : "yellow"}`}>{isSuccess ? "已执行" : "未执行"}</span>
|
|
|
- </div>
|
|
|
|
|
|
- <div className="walk-flow" aria-label={`${routeName} 的链路`}>
|
|
|
- <FlowNode label="起点" value="这条视频" href={`#source-${encodeURIComponent(sourceId)}`} />
|
|
|
- <FlowArrow />
|
|
|
- <FlowNode label={firstNode.label} value={firstNode.value} />
|
|
|
- <FlowArrow />
|
|
|
- <FlowNode label={secondNode.label} value={secondNode.value} href={secondNode.href} tone={isSuccess ? "strong" : "muted"} />
|
|
|
- </div>
|
|
|
+ <div className="walk-flow" aria-label={`${routeName} 的链路`}>
|
|
|
+ <FlowNode label="从" value="这条视频" href={`#source-${encodeURIComponent(sourceId)}`} />
|
|
|
+ <FlowArrow />
|
|
|
+ <FlowNode label={firstNode.label} value={firstNode.value} />
|
|
|
+ <FlowArrow />
|
|
|
+ <FlowNode label={secondNode.label} value={secondNode.value} href={secondNode.href} tone={isSuccess ? "strong" : "muted"} />
|
|
|
+ </div>
|
|
|
|
|
|
- <div className="walk-route-bottom">
|
|
|
- <span className={`walk-gate ${isSuccess ? "pass" : "stop"}`}>{gate}</span>
|
|
|
- {targetQuery.id ? (
|
|
|
- <Link className="walk-jump-button" href={`/runs/${encodeURIComponent(runId)}/queries/${encodeURIComponent(text(targetQuery.id, ""))}/videos`}>
|
|
|
- 查看带回视频
|
|
|
- </Link>
|
|
|
- ) : null}
|
|
|
- <a className="walk-jump-button" href={`#source-${encodeURIComponent(sourceId)}`}>回到起点</a>
|
|
|
- </div>
|
|
|
+ <div className="walk-route-bottom">
|
|
|
+ <span className={`walk-gate ${isSuccess ? "pass" : "stop"}`}>{gate}</span>
|
|
|
+ {targetQuery.id ? (
|
|
|
+ <Link className="walk-jump-button" href={`/runs/${encodeURIComponent(runId)}/queries/${encodeURIComponent(text(targetQuery.id, ""))}/videos`}>
|
|
|
+ 查看带回视频
|
|
|
+ </Link>
|
|
|
+ ) : null}
|
|
|
+ <a className="walk-jump-button" href={`#source-${encodeURIComponent(sourceId)}`}>回到起点</a>
|
|
|
+ </div>
|
|
|
|
|
|
- {targetVideos.length ? (
|
|
|
- <div className="walk-result-videos">
|
|
|
- <div className="walk-result-title">
|
|
|
- <ListVideo size={15} />
|
|
|
- <span>带回视频 {targetVideos.length} 条</span>
|
|
|
- </div>
|
|
|
- {targetVideos.slice(0, 4).map((video) => (
|
|
|
- <div className="walk-result-video" key={text(video.id, text(video.title, "video"))}>
|
|
|
- <Link className="walk-result-video-main" href={`/runs/${encodeURIComponent(runId)}/videos/${encodeURIComponent(text(video.id, ""))}`}>
|
|
|
- <b>{text(video.title, "无标题视频")}</b>
|
|
|
- <small>{text(video.author, "未知作者")} · {text(asRecord(video.decision).label, "未判断")}</small>
|
|
|
- </Link>
|
|
|
- <VideoLinks video={video} runId={runId} compact />
|
|
|
+ {targetVideos.length ? (
|
|
|
+ <div className="walk-result-videos">
|
|
|
+ <div className="walk-result-title">
|
|
|
+ <ListVideo size={15} />
|
|
|
+ <span>带回视频 {targetVideos.length} 条</span>
|
|
|
</div>
|
|
|
- ))}
|
|
|
- </div>
|
|
|
- ) : null}
|
|
|
+ {targetVideos.slice(0, 4).map((video) => (
|
|
|
+ <div className="walk-result-video" key={text(video.id, text(video.title, "video"))}>
|
|
|
+ <Link className="walk-result-video-main" href={`/runs/${encodeURIComponent(runId)}/videos/${encodeURIComponent(text(video.id, ""))}`}>
|
|
|
+ <b>{text(video.title, "无标题视频")}</b>
|
|
|
+ <small>{text(video.author, "未知作者")} · {text(asRecord(video.decision).label, "未判断")}</small>
|
|
|
+ </Link>
|
|
|
+ <VideoLinks video={video} runId={runId} compact />
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ ) : null}
|
|
|
+ </div>
|
|
|
</article>
|
|
|
);
|
|
|
}
|