|
|
@@ -26,16 +26,6 @@ function fmtTime(iso?: string | null): string {
|
|
|
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
|
|
|
}
|
|
|
|
|
|
-function firstCategoryPath(seed: AnyRec): string {
|
|
|
- const bindings = Array.isArray(seed.category_bindings) ? seed.category_bindings : [];
|
|
|
- const first = rec(bindings[0]);
|
|
|
- const path = first.category_path || first.category_full_path;
|
|
|
- if (path) return String(path);
|
|
|
- const itemsets = Array.isArray(seed.itemsets) ? seed.itemsets : [];
|
|
|
- const fi = rec(itemsets[0]);
|
|
|
- return fi.category_path ? String(fi.category_path) : "—";
|
|
|
-}
|
|
|
-
|
|
|
export function DemandDetail({ item }: { item: RunListItem }) {
|
|
|
const runId = item.run_id;
|
|
|
const [dash, setDash] = useState<DashboardResponse | null>(null);
|
|
|
@@ -61,8 +51,13 @@ export function DemandDetail({ item }: { item: RunListItem }) {
|
|
|
}, [runId]);
|
|
|
|
|
|
const biz = rec(dash?.business_summary);
|
|
|
- const seedTerms = seed && Array.isArray(seed.seed_terms) ? seed.seed_terms : [];
|
|
|
+ const seedTerms: string[] = seed && Array.isArray(seed.seed_terms) ? seed.seed_terms.map(String) : [];
|
|
|
const matched = seed && Array.isArray(seed.matched_post_ids) ? seed.matched_post_ids.length : null;
|
|
|
+ // 命中分类 = 这个 Pattern(itemset)锚定的分类树节点(可能多个)
|
|
|
+ const bindings = seed && Array.isArray(seed.category_bindings) ? seed.category_bindings.map(rec) : [];
|
|
|
+ const source = compactValue(seed?.pattern_source_system) || "—";
|
|
|
+ // Pattern 标识 = itemset_id(频繁项集);从分类绑定里取唯一值
|
|
|
+ const patternIds = [...new Set(bindings.map((b) => b.itemset_id).filter((x) => x != null).map(String))];
|
|
|
|
|
|
return (
|
|
|
<div className="demand-detail">
|
|
|
@@ -89,26 +84,48 @@ export function DemandDetail({ item }: { item: RunListItem }) {
|
|
|
{loading ? (
|
|
|
<div className="loading-state">加载中…</div>
|
|
|
) : seed ? (
|
|
|
- <div className="demand-facts">
|
|
|
- <div className="demand-fact">
|
|
|
- <span>种子词</span>
|
|
|
- <strong>{seedTerms.length ? seedTerms.map(String).join("、") : "—"}</strong>
|
|
|
- </div>
|
|
|
- <div className="demand-fact">
|
|
|
- <span>命中分类</span>
|
|
|
- <strong>{firstCategoryPath(seed)}</strong>
|
|
|
+ <div className="demand-evidence">
|
|
|
+ {/* 种子词 = 这个 Pattern 命中的分类名,直接用作搜索词 */}
|
|
|
+ <div className="demand-ev-block">
|
|
|
+ <div className="demand-ev-head">
|
|
|
+ <span className="demand-tag pattern">种子词 · 来自 Pattern</span>
|
|
|
+ {patternIds.length ? <span className="demand-pid">Pattern #{patternIds.join(" + ")}(频繁项集)</span> : null}
|
|
|
+ </div>
|
|
|
+ <div className="demand-seed-terms">
|
|
|
+ {seedTerms.length ? seedTerms.map((t) => <span className="demand-seed-term" key={t}>{t}</span>) : <span className="muted">—</span>}
|
|
|
+ </div>
|
|
|
+ <p className="demand-tip">
|
|
|
+ 上游 Pattern 挖掘({source})得出的频繁项集,种子词就是这个 Pattern 命中的分类名,直接作为搜索词去找内容。
|
|
|
+ </p>
|
|
|
</div>
|
|
|
- <div className="demand-fact">
|
|
|
- <span>证据样本</span>
|
|
|
- <strong>{matched != null ? `${matched} 条匹配` : "—"}</strong>
|
|
|
- </div>
|
|
|
- <div className="demand-fact">
|
|
|
- <span>验证状态</span>
|
|
|
- <strong>{compactValue(seed.validation_status) || "—"}</strong>
|
|
|
+
|
|
|
+ {/* 命中分类 = 分类树节点 */}
|
|
|
+ <div className="demand-ev-block">
|
|
|
+ <div className="demand-ev-head">
|
|
|
+ <span className="demand-tag tree">命中分类 · 内容分类树节点</span>
|
|
|
+ </div>
|
|
|
+ {bindings.length ? (
|
|
|
+ <div className="demand-cat-list">
|
|
|
+ {bindings.map((b, i) => (
|
|
|
+ <div className="demand-cat-row" key={i}>
|
|
|
+ <strong className="demand-cat-name">{compactValue(b.category_name)}</strong>
|
|
|
+ <code className="demand-cat-path">{compactValue(b.category_path)}</code>
|
|
|
+ <span className="demand-cat-meta">
|
|
|
+ 分类树 {compactValue(b.category_level)} 级 · {compactValue(b.category_source_type)}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ ) : (
|
|
|
+ <span className="muted">—</span>
|
|
|
+ )}
|
|
|
</div>
|
|
|
- <div className="demand-fact">
|
|
|
- <span>挖掘来源</span>
|
|
|
- <strong>{compactValue(seed.pattern_source_system) || "—"}</strong>
|
|
|
+
|
|
|
+ {/* 证据规模 / 验证 */}
|
|
|
+ <div className="demand-meta-row">
|
|
|
+ <span>证据样本 <b>{matched != null ? matched : "—"}</b> 条匹配</span>
|
|
|
+ <span>验证状态 <b>{compactValue(seed.validation_status) || "—"}</b></span>
|
|
|
+ <span>挖掘来源 <b>{source}</b></span>
|
|
|
</div>
|
|
|
</div>
|
|
|
) : (
|