From dc2758a150924df33009dde74220c493a7d97308 Mon Sep 17 00:00:00 2001 From: shy3130 <415333856@qq.com> Date: Thu, 20 Aug 2026 14:36:03 +0800 Subject: [PATCH] =?UTF-8?q?feat(monitor):=20=E6=96=B0=E5=BB=BA=E7=9B=91?= =?UTF-8?q?=E6=8E=A7=E6=A0=87=E7=9A=84=E5=B1=95=E7=A4=BA=E9=87=8D=E6=9E=84?= =?UTF-8?q?=20=E2=80=94=20=E6=B1=87=E6=80=BB+=E5=B1=95=E5=BC=80=E7=AE=A1?= =?UTF-8?q?=E7=90=86=20=E5=90=8D=E7=A7=B0/=E6=9D=BF=E6=A0=87/=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=20tag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原「从自选导入」后逐个显示纯代码 chip, 长列表难读且无名称。改为: - 收起态(默认): 「已加入 N 只」汇总胶囊, 点击展开管理 - 展开态: 标签流「名称 [创/科/北板标] 代码 ×」— 板标复用 boardTag (搜索下拉同款样式), 每个可单独删除, 附「清空」「收起」操作; 数量多时容器限高滚动 - 名称解析: 本地缓存(搜索结果/自选数据, 即时) + 批量名称接口 api.instrumentNames 兜底(编辑旧规则等本地无名称场景), key 随 标的集变化, staleTime 5min 验证: tsc 通过; 浏览器实测 — 自选导入 22 只 → 「已加入 22 只」汇总, 展开后 tag 显示「捷捷微电·创·300623.SZ」等(名称+板标+代码), 删除 单只后计数 22→21, 清空/收起可用。 --- .../src/components/monitor/RuleEditor.tsx | 95 ++++++++++++++++--- 1 file changed, 84 insertions(+), 11 deletions(-) diff --git a/frontend/src/components/monitor/RuleEditor.tsx b/frontend/src/components/monitor/RuleEditor.tsx index 7e9b411..dbb4216 100644 --- a/frontend/src/components/monitor/RuleEditor.tsx +++ b/frontend/src/components/monitor/RuleEditor.tsx @@ -1,7 +1,7 @@ -import { useEffect, useRef, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import { Link } from 'react-router-dom' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' -import { Activity, Building2, ChartNoAxesCombined, Check, Layers3, ListPlus, Plus, RadioTower, Save, Search, Tags, TrendingUp, Waypoints, X } from 'lucide-react' +import { Activity, Building2, ChartNoAxesCombined, Check, ChevronDown, ChevronUp, Eraser, Layers3, ListPlus, Plus, RadioTower, Save, Search, Tags, TrendingUp, Waypoints, X } from 'lucide-react' import { api, genRuleId, type MonitorRule, type MonitorCondition, type SectorKind, type SectorMonitorTarget, type StrategyNotifyEvent } from '@/lib/api' import { DEFAULT_STRATEGY_NOTIFY_EVENTS, LEGACY_STRATEGY_NOTIFY_EVENTS, STRATEGY_NOTIFY_EVENT_OPTIONS } from '@/lib/strategyMonitorEvents' import { QK } from '@/lib/queryKeys' @@ -234,6 +234,30 @@ export function RuleEditor({ rule, preset, simple, onClose, onSaved }: Props) { }) setWatchMenuOpen(false) } + + // ── 标的标签: 名称 + 板标(创/科/北) + 代码, 可逐个删除 ── + const [symbolsExpanded, setSymbolsExpanded] = useState(false) + const symbolsKey = draft.symbols.join(',') + // 名称映射: 本地即时缓存(搜索/自选数据) 优先, 缺失的由批量名称接口补齐 + // (覆盖编辑旧规则等本地无名称的场景)。key 随标的集变化, staleTime 长防抖。 + const localNamesRef = useRef>({}) + const recordLocalNames = (pairs: { symbol: string; name?: string | null }[]) => { + for (const p of pairs) { + if (p.name) localNamesRef.current[p.symbol] = p.name + } + } + if (watchlistQ.data?.symbols) recordLocalNames(watchlistQ.data.symbols) + if (symbolSearch.data?.results) recordLocalNames(symbolSearch.data.results) + const namesQ = useQuery({ + queryKey: ['instrument-names', symbolsKey], + queryFn: () => api.instrumentNames(draft.symbols), + enabled: draft.symbols.length > 0, + staleTime: 5 * 60_000, + }) + const nameBySymbol = useMemo( + () => ({ ...localNamesRef.current, ...(namesQ.data?.names ?? {}) }), + [symbolsKey, namesQ.data], + ) // 自选导入选项: 全部自选 + 各分组 (空分组隐藏) + 未分组 const watchImportOptions = (() => { const entries = watchlistQ.data?.symbols ?? [] @@ -732,15 +756,64 @@ export function RuleEditor({ rule, preset, simple, onClose, onSaved }: Props) { {visibleScopes.map(s => )} {draft.scope === 'symbols' && ( -
- {draft.symbols.map(sym => ( - - {sym} - - - ))} +
+ {/* 收起态: 只显示「已加入 N 只」汇总, 点击展开管理 */} + {draft.symbols.length > 0 && !symbolsExpanded && ( + + )} + {/* 展开态: 名称+板标+代码 tag 流, 可逐个删除/清空/收起 */} + {draft.symbols.length > 0 && symbolsExpanded && ( + <> +
+ 已加入 {draft.symbols.length} + + + + +
+
+ {draft.symbols.map(sym => { + const b = boardTag(sym) + const name = nameBySymbol[sym] + return ( + + {name ?? sym} + {b && {b.label}} + {sym} + + + ) + })} +
+ + )} {/* 从自选/自选分组批量导入标的 */}