import { useEffect, useMemo, useRef, useState } from 'react' import ErrorState from '../../components/ErrorState.jsx' import LoadingState from '../../components/LoadingState.jsx' import DecodeKnowledgeModal from '../decode/DecodeKnowledgeModal.jsx' import AxisColumn from './AxisColumn.jsx' import ManualQueryModal from './ManualQueryModal.jsx' import QueryColumn from './QueryColumn.jsx' import SearchResultColumn from './SearchResultColumn.jsx' import TopicTableQueryPanel from './TopicTableQueryPanel.jsx' import { useLatestQueryDetail, useQueryBoard } from './useQueryBoard.js' import { isQuerySearched } from './model.js' function selectedQueryPayload(queryText, latest) { if (!latest?.query_id) return null return { query: queryText, query_id: latest.query_id, detail_version: [ latest.candidate_count || 0, latest.creation_hit_count || 0, latest.decoded_count || 0, latest.payload_count || 0, ].join(':'), } } function manualFamilyFromBoard(board) { const rows = (board?.queries || []).filter((row) => row.family_key === 'manual') return { key: 'manual', label: '手动 Query', axes: [], items: rows.map((row, index) => ({ query: row.query_text, parts: {}, keep: true, reason: row.filter_reason || '', sort_order: row.sort_order ?? index, })), } } function topicTableFamily() { return { key: 'topic_table', label: '选题表生成', axes: [], items: [], } } export default function QueryBoardPage() { const { preview, board, latestByQuery, loading, error, lastUpdatedAt, refreshBoard, } = useQueryBoard() const [activeKey, setActiveKey] = useState('f1') const [selectedQuery, setSelectedQuery] = useState(null) const [decodeItemId, setDecodeItemId] = useState('') const [manualMode, setManualMode] = useState('') const didSetDefaultTab = useRef(false) const families = useMemo(() => { const base = preview?.families || [] const manual = manualFamilyFromBoard(board) return [...base, manual, topicTableFamily()] }, [board, preview]) const family = families.find((row) => row.key === activeKey) || families[0] || { axes: [], items: [] } const familyItems = family.items || [] const familyRunCount = familyItems.filter((item) => isQuerySearched(latestByQuery.get(item.query))).length const totalRunCount = families.reduce((count, row) => { return count + (row.items || []).filter((item) => isQuerySearched(latestByQuery.get(item.query))).length }, 0) const totalItemCount = families.reduce((sum, row) => sum + (row.items || []).length, 0) const detailState = useLatestQueryDetail(selectedQuery) const lastUpdatedText = useMemo(() => { return lastUpdatedAt ? lastUpdatedAt.toLocaleTimeString('zh-CN', { hour12: false }) : '' }, [lastUpdatedAt]) useEffect(() => { if (!didSetDefaultTab.current && (window.location.hash || '#/') === '#/' && families.some((row) => row.key === 'f1')) { didSetDefaultTab.current = true setActiveKey('f1') } }, [families]) useEffect(() => { const firstKey = families[0]?.key if (firstKey && !families.some((row) => row.key === activeKey) && preview) { setActiveKey(firstKey) } }, [families, activeKey, preview]) useEffect(() => { if (!familyItems.length) { if (selectedQuery) setSelectedQuery(null) return } if (selectedQuery && familyItems.some((item) => item.query === selectedQuery.query)) { const latest = latestByQuery.get(selectedQuery.query) const next = selectedQueryPayload(selectedQuery.query, latest) if (next && (next.query_id !== selectedQuery.query_id || next.detail_version !== selectedQuery.detail_version)) { setSelectedQuery(next) } return } const first = familyItems.find((item) => isQuerySearched(latestByQuery.get(item.query))) if (first) { const latest = latestByQuery.get(first.query) setSelectedQuery(selectedQueryPayload(first.query, latest)) } else { setSelectedQuery(null) } }, [activeKey, board, familyItems, latestByQuery, selectedQuery]) if (error) return {error} if (loading || !preview) return return (
{families.map((row) => ( ))}
{family.key === 'topic_table' ? ( 选题字段 + LLM · 只生成 Query ) : ( <> {lastUpdatedText ? `上次刷新 ${lastUpdatedText}` : '等待后台写入数据'}
)}
{family.key === 'topic_table' ? :
{(family.axes || []).map((axis) => ( ))} { setSelectedQuery(selectedQueryPayload(queryItem.query, queryLatest)) }} familyRunCount={familyRunCount} totalRunCount={totalRunCount} totalItemCount={totalItemCount} emptyMessage={ family.key === 'manual' ? '暂无手动 Query,点击右上角手动输入或上传 JSON 创建。' : undefined } />
} {decodeItemId && (
setDecodeItemId('')}>
event.stopPropagation()}> setDecodeItemId('')} />
)} {manualMode && ( setManualMode('')} onSubmitted={async () => { setManualMode('') await refreshBoard() setActiveKey('manual') }} /> )}
) }