Преглед изворни кода

feat: ROV 排序 + URL 自动召回等字典 + 默认视频ID

- RecallResultTable ROV 列加 sorter (默认点击倒排, null 沉末)
- TextRecallTab URL queryText 自动召回前等真实字典加载完, 避免 fallback 只跑 2 维度
- 新增 useConfigCodesReady() hook 暴露字典就绪状态
- DEFAULT_VIDEO_ID: 64632804 → 60308273 (有 AI 字段的样本)
刘立冬 пре 2 дана
родитељ
комит
97f9fe5a41
3 измењених фајлова са 40 додато и 3 уклоњено
  1. 20 0
      src/api/configCodes.ts
  2. 10 0
      src/components/RecallResultTable.tsx
  3. 10 3
      src/pages/RecallTestPage.tsx

+ 20 - 0
src/api/configCodes.ts

@@ -51,6 +51,26 @@ export function useConfigCodes(): Record<string, string> {
   return data
 }
 
+/**
+ * 真实字典是否已经从后端拉到 (而非 SAFE_FALLBACK).
+ * 用于"URL 自动召回"等场景需要等真实全量字典再触发, 避免只跑 fallback 的 2 个维度.
+ */
+export function useConfigCodesReady(): boolean {
+  const [ready, setReady] = useState<boolean>(cache != null)
+  useEffect(() => {
+    if (cache != null) {
+      setReady(true)
+      return
+    }
+    fetchOnce()
+      .then(() => setReady(true))
+      .catch(() => {
+        // 失败保持 false, 由调用方决定是否兜底
+      })
+  }, [])
+  return ready
+}
+
 /** "全部" 维度的特殊 value, 提交时拆开成所有 configCode 并发调用 */
 export const ALL_CONFIG_CODE = '__ALL__'
 

+ 10 - 0
src/components/RecallResultTable.tsx

@@ -306,6 +306,16 @@ export default function RecallResultTable({ items }: Props) {
       align: 'right',
       onHeaderCell: () => ({ style: METRIC_HEADER_STYLE }),
       onCell: () => ({ style: METRIC_CELL_STYLE }),
+      sorter: (a, b) => {
+        const av = parseNum(a.videoDetail?.rov)
+        const bv = parseNum(b.videoDetail?.rov)
+        // 缺失值统一沉到最末: 不论升降序都被排到尾巴
+        if (av == null && bv == null) return 0
+        if (av == null) return 1
+        if (bv == null) return -1
+        return av - bv
+      },
+      sortDirections: ['descend', 'ascend'],
       filterIcon: () => (
         <FilterFilled
           style={{ color: filters.rov != null ? ACTIVE_ICON_COLOR : IDLE_ICON_COLOR }}

+ 10 - 3
src/pages/RecallTestPage.tsx

@@ -46,6 +46,7 @@ import {
   getConfigDisplayLabel,
   listAllConfigCodes,
   useConfigCodes,
+  useConfigCodesReady,
 } from '../api/configCodes'
 import type {
   AIUnderstandingVO,
@@ -188,7 +189,7 @@ export default function RecallTestPage() {
 // Tab1: 票圈视频ID — 三栏并列布局(视频详情 / AI理解 / 解构层级 都是召回维度)
 // ============================================================================
 /** 进入页面默认查询的视频ID, 避免空白态 */
-const DEFAULT_VIDEO_ID = 64632804
+const DEFAULT_VIDEO_ID = 60308273
 
 function VideoIdTab() {
   /** URL 上 ?videoId=xxx 优先于默认 ID;有则首次查询后自动按选题召回 */
@@ -637,6 +638,7 @@ function TextRecallTab() {
   const [result, setResult] = useState<RecallResultVO | null>(null)
   const [loading, setLoading] = useState(false)
   const configCodes = useConfigCodes()
+  const configCodesReady = useConfigCodesReady()
   const groupedOptions = buildGroupedConfigOptions(configCodes)
   /** 召回结果标题展示的维度 meta — 锁定提交瞬间的值, 避免提交后改下拉影响展示 */
   const [resultMeta, setResultMeta] = useState<{
@@ -733,14 +735,19 @@ function TextRecallTab() {
     }
   }, [queryText, configCode, topN, configCodes])
 
-  /** URL 上有 queryText 时, 挂载后自动触发一次召回 (Grafana 跳转 0 点击) */
+  /**
+   * URL 上有 queryText 时, 挂载后自动触发一次召回 (Grafana 跳转 0 点击)
+   * 必须等 configCodes 真实字典加载完, 否则 ALL 模式只会跑 SAFE_FALLBACK 的 2 个维度
+   * (URL 显式带 configCode 时无此约束, 单维度跑就行)
+   */
   const autoSearchedRef = useRef(false)
   useEffect(() => {
     if (autoSearchedRef.current) return
     if (!urlQueryText) return
+    if (!urlConfigCode && !configCodesReady) return
     autoSearchedRef.current = true
     onSubmit()
-  }, [urlQueryText, onSubmit])
+  }, [urlQueryText, urlConfigCode, configCodesReady, onSubmit])
 
   return (
     <Space direction="vertical" size={16} style={{ width: '100%' }}>