Просмотр исходного кода

Inline demand details and score weights

Sam Lee 3 недель назад
Родитель
Сommit
7805ca7642
3 измененных файлов с 79 добавлено и 58 удалено
  1. 24 0
      web2/app/globals.css
  2. 28 54
      web2/features/LedgerPage.tsx
  3. 27 4
      web2/features/VideoDetailPage.tsx

+ 24 - 0
web2/app/globals.css

@@ -419,6 +419,30 @@ a:focus-visible {
   font-weight: 750;
 }
 
+.demand-inline-section {
+  display: grid;
+  gap: 5px;
+  padding-top: 6px;
+  border-top: 1px solid #e2e8f0;
+}
+
+.demand-inline-section > b {
+  color: #111827;
+  font-size: 11.5px;
+}
+
+.demand-inline-section > div {
+  display: grid;
+  gap: 4px;
+}
+
+.demand-inline-section span {
+  color: #334155;
+  font-size: 11px;
+  line-height: 1.45;
+  overflow-wrap: anywhere;
+}
+
 .ledger-table {
   width: max-content;
   min-width: 100%;

+ 28 - 54
web2/features/LedgerPage.tsx

@@ -2,7 +2,7 @@
 
 import { useState } from "react";
 import Link from "next/link";
-import { ChevronLeft, ChevronRight, FileText, GitBranch, Info } from "lucide-react";
+import { ChevronLeft, ChevronRight, GitBranch, Info } from "lucide-react";
 import { AppShell } from "@/components/AppShell";
 import { BusinessDrawer, type BusinessDrawerState } from "@/components/BusinessDrawer";
 import { EmptyState, ErrorState, LoadingState } from "@/components/StateBlocks";
@@ -42,7 +42,6 @@ export function LedgerPage({ runId }: { runId: string }) {
               demand={ledger.demandSummary}
               collapsed={demandCollapsed}
               onToggle={() => setDemandCollapsed((value) => !value)}
-              onOpenDemand={setDrawer}
             />
             <section className="table-wrap">
               <table className="ledger-table">
@@ -73,14 +72,13 @@ export function LedgerPage({ runId }: { runId: string }) {
 function DemandPanel({
   demand,
   collapsed,
-  onToggle,
-  onOpenDemand
+  onToggle
 }: {
   demand?: DemandSummary;
   collapsed: boolean;
   onToggle: () => void;
-  onOpenDemand: (drawer: BusinessDrawerState) => void;
 }) {
+  const meta = demandMetaItems(demand);
   return (
     <aside className={`demand-side-panel ${collapsed ? "collapsed" : ""}`}>
       <div className="demand-panel-head">
@@ -115,67 +113,43 @@ function DemandPanel({
               <span>{demand.seedTerms.join("、")}</span>
             </p>
           ) : null}
-          {demand?.sourcePostId ? <span className="demand-panel-meta">来源帖子 {demand.sourcePostId}</span> : null}
-          <button className="mini-button demand-detail-button" type="button" onClick={() => onOpenDemand(demandDrawer(demand))}>
-            <FileText size={13} />
-            看原始需求
-          </button>
+          {demand?.reason ? (
+            <p className="demand-line">
+              <b>形成原因:</b>
+              <span>{demand.reason}</span>
+            </p>
+          ) : null}
+          {meta.length ? (
+            <div className="demand-inline-section">
+              <b>来源信息:</b>
+              <div>
+                {meta.map((item) => <span key={item}>{item}</span>)}
+              </div>
+            </div>
+          ) : null}
+          {demand?.categoryPaths.length ? (
+            <div className="demand-inline-section">
+              <b>分类树路径:</b>
+              <div>
+                {demand.categoryPaths.map((item) => <span key={item}>{item}</span>)}
+              </div>
+            </div>
+          ) : null}
         </div>
       ) : null}
     </aside>
   );
 }
 
-function demandDrawer(demand?: DemandSummary): BusinessDrawerState {
-  if (!demand) {
-    return {
-      title: "原始需求",
-      sections: [
-        {
-          label: "需求待确认",
-          value: "当前运行没有写入原始需求单摘要。",
-          tone: "warn"
-        }
-      ]
-    };
-  }
-  const meta = [
+function demandMetaItems(demand?: DemandSummary): string[] {
+  if (!demand) return [];
+  return [
     demand.id ? `需求单:${demand.id}` : "",
     demand.source ? `来源:${demand.source}` : "",
     demand.sourcePostId ? `来源帖子:${demand.sourcePostId}` : "",
     demand.itemsetIds.length ? `itemset:${demand.itemsetIds.join(" / ")}` : "",
     demand.support ? `支持度:${demand.support}` : ""
   ].filter(Boolean);
-  return {
-    title: `原始需求:${demand.name || demand.id || "待确认"}`,
-    sections: [
-      {
-        label: "需求说明",
-        value: demand.description || "暂无需求说明",
-        tone: "info"
-      },
-      {
-        label: "形成原因",
-        value: demand.reason || "暂无形成原因",
-        tone: "neutral"
-      },
-      {
-        label: "来源信息",
-        items: meta,
-        tone: "neutral"
-      },
-      {
-        label: "Pattern 词",
-        value: demand.seedTerms.length ? demand.seedTerms.join("、") : "暂无 Pattern 词",
-        tone: "good"
-      },
-      {
-        label: "分类树路径",
-        items: demand.categoryPaths.length ? demand.categoryPaths : ["暂无分类树路径"],
-        tone: "neutral"
-      }
-    ]
-  };
 }
 
 function HeaderSummaryChips({ rows, dataOriginLabel }: { rows: FlowLedgerRow[]; dataOriginLabel: string }) {

+ 27 - 4
web2/features/VideoDetailPage.tsx

@@ -87,7 +87,7 @@ export function VideoDetailPage({ runId, contentId }: { runId: string; contentId
                 {mainScores.map((item) => (
                   <div className={`score-module ${scoreModuleTone(item.label)}`} key={item.label}>
                     <span>{displayScoreLabel(item.label)}</span>
-                    <b>{item.scoreLabel}</b>
+                    <b>{mainScoreDisplay(item.label, item.scoreLabel)}</b>
                     <em>{scoreRuleText(item.label)}</em>
                     {item.detail ? <small>{item.detail}</small> : null}
                   </div>
@@ -101,7 +101,7 @@ export function VideoDetailPage({ runId, contentId }: { runId: string; contentId
                   {platformBreakdown.length ? platformBreakdown.map((item) => (
                     <div className="score-breakdown-row" key={item.label}>
                       <span>{displayScoreLabel(item.label)}</span>
-                      <b>{item.scoreLabel}</b>
+                      <b>{platformScoreDisplay(item.label, item.scoreLabel, item.detail)}</b>
                       <small>{item.detail || platformBreakdownRule(item.label)}</small>
                     </div>
                   )) : (
@@ -133,8 +133,31 @@ function scoreModuleTone(label: string): string {
 function scoreRuleText(label: string): string {
   const displayLabel = displayScoreLabel(label);
   if (displayLabel === "总分") return "用于决定入池、待复看或淘汰";
-  if (displayLabel === "是否契合需求") return "占总分 50%";
-  if (displayLabel === "平台表现") return "占总分 50%";
+  if (displayLabel === "是否契合需求") return "折算进总分";
+  if (displayLabel === "平台表现") return "折算进总分";
+  return "";
+}
+
+function mainScoreDisplay(label: string, scoreLabel: string): string {
+  const displayLabel = displayScoreLabel(label);
+  if (displayLabel === "是否契合需求" || displayLabel === "平台表现") return `${compactScore(scoreLabel)} × 50%`;
+  return compactScore(scoreLabel);
+}
+
+function platformScoreDisplay(label: string, scoreLabel: string, detail?: string): string {
+  const weight = detail?.match(/权重\s*([0-9.]+%)/)?.[1] || platformWeight(displayScoreLabel(label));
+  return weight ? `${compactScore(scoreLabel)} × ${weight}` : compactScore(scoreLabel);
+}
+
+function compactScore(scoreLabel: string): string {
+  return scoreLabel.replace(/\s+/g, "");
+}
+
+function platformWeight(label: string): string {
+  if (label === "点赞表现") return "40%";
+  if (label === "评论表现") return "20%";
+  if (label === "转发表现") return "20%";
+  if (label === "收藏表现") return "20%";
   return "";
 }