refactor(selection): 统一信号与股票处理逻辑,重构相关数据结构与接口,更新前端展示以支持股票信息
This commit is contained in:
@@ -12,12 +12,15 @@ import {
|
||||
SelectValue,
|
||||
} from "@/shared/ui/select"
|
||||
|
||||
import type { SelectionResults, SelectionSignal } from "../api/selection.types"
|
||||
import type {
|
||||
SelectionResults,
|
||||
SelectionStockResult,
|
||||
} from "../api/selection.types"
|
||||
import { ExecutionStatusTrigger } from "./execution-status-trigger"
|
||||
import { SignalDetailPanel } from "./signal-detail-panel"
|
||||
import { SignalRecordList } from "./signal-record-list"
|
||||
import {
|
||||
getSignalKey,
|
||||
getStockKey,
|
||||
matchesCategory,
|
||||
signalCategoryOptions,
|
||||
type SignalCategoryFilter,
|
||||
@@ -48,26 +51,26 @@ export function SelectionResultsWorkbench({
|
||||
new Set(),
|
||||
)
|
||||
|
||||
const visibleSignals = useMemo(() => {
|
||||
const visibleStocks = useMemo(() => {
|
||||
const normalized = query.trim().toLowerCase()
|
||||
return result.signals.filter((signal) => {
|
||||
return result.stocks.filter((stock) => {
|
||||
const matchesQuery =
|
||||
normalized.length === 0 ||
|
||||
signal.name.toLowerCase().includes(normalized) ||
|
||||
signal.ts_code.toLowerCase().includes(normalized)
|
||||
return matchesQuery && matchesCategory(signal, category)
|
||||
stock.name.toLowerCase().includes(normalized) ||
|
||||
stock.ts_code.toLowerCase().includes(normalized)
|
||||
return matchesQuery && matchesCategory(stock, category)
|
||||
})
|
||||
}, [category, query, result.signals])
|
||||
}, [category, query, result.stocks])
|
||||
|
||||
const page = search.page
|
||||
const pageSize = search.pageSize
|
||||
const signalsTotal = result.signals_total ?? result.signal_count
|
||||
const pageCount = Math.max(1, Math.ceil(signalsTotal / pageSize))
|
||||
const stocksTotal = result.stocks_total ?? result.selected_stock_count
|
||||
const pageCount = Math.max(1, Math.ceil(stocksTotal / pageSize))
|
||||
const currentPage = Math.min(page, pageCount)
|
||||
const currentSignals = visibleSignals
|
||||
const selectedSignal =
|
||||
currentSignals.find((signal) => getSignalKey(signal) === selectedKey) ??
|
||||
currentSignals[0]
|
||||
const currentStocks = visibleStocks
|
||||
const selectedStock =
|
||||
currentStocks.find((stock) => getStockKey(stock) === selectedKey) ??
|
||||
currentStocks[0]
|
||||
useEffect(() => {
|
||||
if (page > pageCount) {
|
||||
void navigate({
|
||||
@@ -93,8 +96,8 @@ export function SelectionResultsWorkbench({
|
||||
updateSearch({ category: value, page: 1 })
|
||||
}
|
||||
|
||||
function handleToggleExpanded(signal: SelectionSignal) {
|
||||
const key = getSignalKey(signal)
|
||||
function handleToggleExpanded(stock: SelectionStockResult) {
|
||||
const key = getStockKey(stock)
|
||||
setExpandedKeys((previous) => {
|
||||
const next = new Set(previous)
|
||||
if (next.has(key)) next.delete(key)
|
||||
@@ -108,7 +111,7 @@ export function SelectionResultsWorkbench({
|
||||
<section className="flex min-h-0 min-w-0 flex-1 flex-col overflow-visible rounded-md border border-border/80 bg-card md:overflow-hidden">
|
||||
<div className="flex shrink-0 flex-wrap items-center gap-1.5 border-b border-border/60 p-2.5">
|
||||
<Input
|
||||
aria-label="搜索命中信号"
|
||||
aria-label="搜索命中股票"
|
||||
className="h-11 min-w-0 flex-1 bg-background text-sm sm:max-w-[260px] md:h-8"
|
||||
onChange={(event) => handleQueryChange(event.target.value)}
|
||||
placeholder="搜索股票名称或代码"
|
||||
@@ -130,7 +133,7 @@ export function SelectionResultsWorkbench({
|
||||
>
|
||||
<SelectValue placeholder="筛选信号分类" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectContent align="start" alignItemWithTrigger={false}>
|
||||
<SelectGroup>
|
||||
{signalCategoryOptions.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
@@ -141,7 +144,7 @@ export function SelectionResultsWorkbench({
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span className="text-xs tabular-nums text-muted-foreground sm:ml-auto">
|
||||
筛选结果 {signalsTotal} 条
|
||||
筛选结果 {stocksTotal} 只
|
||||
</span>
|
||||
<ExecutionStatusTrigger
|
||||
drawerOpen={drawerOpen}
|
||||
@@ -153,15 +156,15 @@ export function SelectionResultsWorkbench({
|
||||
|
||||
<div className="flex min-h-0 min-w-0 flex-col md:flex-1 md:overflow-hidden">
|
||||
<SignalTable
|
||||
onSelect={(signal) => setSelectedKey(getSignalKey(signal))}
|
||||
selectedKey={selectedSignal ? getSignalKey(selectedSignal) : null}
|
||||
signals={currentSignals}
|
||||
onSelect={(stock) => setSelectedKey(getStockKey(stock))}
|
||||
selectedKey={selectedStock ? getStockKey(selectedStock) : null}
|
||||
stocks={currentStocks}
|
||||
/>
|
||||
<SignalRecordList
|
||||
expandedKeys={expandedKeys}
|
||||
onSelect={(signal) => setSelectedKey(getSignalKey(signal))}
|
||||
onSelect={(stock) => setSelectedKey(getStockKey(stock))}
|
||||
onToggleExpanded={handleToggleExpanded}
|
||||
signals={currentSignals}
|
||||
stocks={currentStocks}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -173,11 +176,11 @@ export function SelectionResultsWorkbench({
|
||||
page={currentPage}
|
||||
pageSize={pageSize}
|
||||
pageSizeOptions={PAGE_SIZE_OPTIONS}
|
||||
total={signalsTotal}
|
||||
total={stocksTotal}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<SignalDetailPanel signal={selectedSignal} />
|
||||
<SignalDetailPanel stock={selectedStock} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user