Merge branch 'feature_bugfix/251201_vf_h5_ui' into feature_bugfix/251201_py_h5_ui

* feature_bugfix/251201_vf_h5_ui: (31 commits)
  fix: CompactSearchBox 股票选择和行业筛选优化
  fix: stocks 字段支持对象格式 {code, name}
  refactor: EventDetailCard 重命名为 EventCard,支持多变体模式
  fix: UI调试
  fix: 修复 key 重复
  feat: 修复数据结构访问
  refactor: EventFormModal 从 Chakra UI 迁移到 Ant Design
  fix: 适配 watchlist 新数据结构
  refactor: 股票数据管理迁移到 Redux,新增类型化 Hooks
  fix: 修复ts报错
  feat: 添加mock数据
  style: EventFormModal 和 InvestmentCalendar H5 响应式适配
  style: EventFormModal 和 InvestmentCalendar H5 响应式适配
  fix: 补充 investment.ts 类型定义变更(df90fc2 遗漏)
  feat: h5隐藏日历视图
  perf: EventPanel 性能优化,EventDetailCard H5适配,清理冗余类型
  refactor: CalendarPanel 性能优化,统一弹窗状态管理
  feat: 添加"我的计划"和"我的复盘"的 mock 数据
  refactor: CalendarPanel 性能优化,统一弹窗状态管理
  feat: 新增 EventDetailModal 和 EventEmptyState 组件 用于展示某一天的所有投资事件
  ...
This commit is contained in:
zdl
2025-12-05 18:29:05 +08:00
35 changed files with 3179 additions and 5749 deletions

View File

@@ -289,53 +289,412 @@ export const mockEventComments = [
// ==================== 投资计划与复盘数据 ====================
export const mockInvestmentPlans = [
// ==================== 计划数据(符合计划模板) ====================
{
id: 301,
user_id: 1,
type: 'plan',
title: '2025年Q1 新能源板块布局计划',
content: '计划在Q1分批建仓新能源板块重点关注宁德时代、比亚迪、隆基绿能三只标的。目标仓位15%预计收益率20%。\n\n具体策略\n1. 宁德时代占比6%等待回调至160元附近分批买入\n2. 比亚迪占比6%,当前价位可以开始建仓\n3. 隆基绿能占比3%,观察光伏行业景气度再决定\n\n风险控制单只个股止损-8%,板块整体止损-10%',
content: `【目标】
在Q1末实现新能源板块仓位15%预计收益率20%,重点捕捉新能源政策利好和销量数据催化。
【策略】
1. 宁德时代占比6%等待回调至160元附近分批买入技术面看好底部放量信号
2. 比亚迪占比6%,当前价位可以开始建仓,采用金字塔式加仓
3. 隆基绿能占比3%,观察光伏行业景气度再决定,等待基本面拐点确认
【风险控制】
- 单只个股止损-8%
- 板块整体止损-10%
- 遇到系统性风险事件果断减仓50%
- 避免在重大财报日前重仓
【时间规划】
- 1月中旬完成第一批建仓5%仓位)
- 2月春节后根据市场情况加仓5%仓位)
- 3月中旬完成最终布局5%仓位)
- 季度末复盘调整决定是否持有到Q2`,
target_date: '2025-03-31',
status: 'in_progress',
created_at: '2025-01-10T10:00:00Z',
updated_at: '2025-01-15T14:30:00Z',
tags: ['新能源', '布局计划', 'Q1计划']
},
{
id: 302,
user_id: 1,
type: 'review',
title: '2024年12月投资复盘 - 白酒板块大涨',
content: '12月白酒板块表现优异贵州茅台上涨12%五粮液上涨8%。\n\n操作回顾\n1. 11月底在1550元加仓茅台获利6.5%\n2. 五粮液持仓未动获利4.2%\n\n经验总结\n- 消费板块在年底有明显的估值修复行情\n- 龙头白马股在市场震荡时更具韧性\n- 应该更大胆一些仓位可以再提高2-3个点\n\n下月计划\n- 继续持有茅台、五粮液,不轻易卖出\n- 关注春节前的消费旺季催化',
target_date: '2024-12-31',
status: 'completed',
created_at: '2025-01-02T09:00:00Z',
updated_at: '2025-01-02T09:00:00Z',
tags: ['月度复盘', '白酒', '2024年12月']
tags: ['新能源', '布局计划', 'Q1计划'],
stocks: ['300750.SZ', '002594.SZ', '601012.SH']
},
{
id: 303,
user_id: 1,
type: 'plan',
title: 'AI 算力板块波段交易计划',
content: '随着ChatGPT-5即将发布AI算力板块有望迎来新一轮炒作。\n\n标的选择\n- 寒武纪AI芯片龙头弹性最大\n- 中科曙光:服务器厂商,业绩支撑\n- 浪潮信息:算力基础设施\n\n交易策略\n- 仓位控制在10%以内(高风险高弹性)\n- 采用金字塔式买入第一笔3%\n- 快进快出涨幅20%分批止盈\n- 破位及时止损,控制在-5%以内',
content: `【目标】
捕捉ChatGPT-5发布带来的AI算力板块短期行情目标收益15-20%控制最大回撤在8%以内。
【策略】
- 寒武纪AI芯片龙头弹性最大首选标的
- 中科曙光:服务器厂商,业绩支撑更扎实
- 浪潮信息:算力基础设施,流动性好
- 采用金字塔式买入第一笔3%,后续根据走势加仓
- 快进快出涨幅20%分批止盈
【风险控制】
- 仓位控制在10%以内(高风险高弹性)
- 单只个股止损-5%
- 破位及时止损,不恋战
- 避免追高,只在回调时介入
【时间规划】
- 本周:观察消息面发酵情况,确定进场时机
- 发布前1周逐步建仓
- 发布后:根据市场反应决定持有还是止盈
- 2月底前完成此轮操作`,
target_date: '2025-02-28',
status: 'pending',
created_at: '2025-01-14T16:00:00Z',
updated_at: '2025-01-14T16:00:00Z',
tags: ['AI', '算力', '波段交易']
tags: ['AI', '算力', '波段交易'],
stocks: ['688256.SH', '603019.SH', '000977.SZ']
},
{
id: 305,
user_id: 1,
type: 'plan',
title: '银行股防守配置计划',
content: `【目标】
构建15%仓位的银行股防守配置获取稳定分红收益股息率5%+),同时等待估值修复带来的资本利得。
【策略】
1. 招商银行零售银行龙头ROE持续优秀配置8%
2. 兴业银行同业业务优势明显配置4%
3. 成都银行城商行中成长性最好配置3%
选股逻辑优先选择ROE高、资产质量好、分红稳定的标的
【风险控制】
- 银行股整体波动较小,但需关注宏观经济风险
- 如遇利率大幅下行或地产风险暴露,需重新评估持仓
- 单只银行股止损-15%(较宽松,适合长线持有)
- 定期关注季报中的不良贷款率和拨备覆盖率
【时间规划】
- 春节前:完成建仓
- 全年持有:享受分红收益
- 年中复盘:根据半年报调整配置比例
- 年底:评估是否继续持有到下一年`,
target_date: '2025-06-30',
status: 'active',
created_at: '2025-01-08T11:00:00Z',
updated_at: '2025-01-08T11:00:00Z',
tags: ['银行', '防守配置', '高股息'],
stocks: ['600036.SH', '601166.SH', '601838.SH']
},
{
id: 306,
user_id: 1,
type: 'plan',
title: '医药创新药中长线布局',
content: `【目标】
布局医药创新药板块目标3-6个月内获得25%收益,享受创新药产品上市带来的业绩爆发。
【策略】
1. 恒瑞医药创新药管线最丰富PD-1放量进行中
2. 药明康德CRO龙头受益于全球创新药研发外包
3. 百济神州:海外收入占比高,泽布替尼持续放量
采用分批建仓策略,避免一次性重仓
【风险控制】
- 总仓位不超过12%
- 单只个股止损-10%
- 关注集采政策风险,如有利空政策出台立即减仓
- 关注核心产品的销售数据和临床进展
【时间规划】
- 第1个月建立6%底仓
- 第2-3个月根据业绩催化加仓至12%
- 第4-6个月达到目标收益后分批止盈
- 每月关注:产品获批进展、销售数据、研报观点`,
target_date: '2025-06-30',
status: 'active',
created_at: '2025-01-05T14:00:00Z',
updated_at: '2025-01-12T09:30:00Z',
tags: ['医药', '创新药', '中长线'],
stocks: ['600276.SH', '603259.SH', '688235.SH']
},
{
id: 307,
user_id: 1,
type: 'plan',
title: '消费复苏主题布局计划',
content: `【目标】
捕捉春节消费旺季和全年消费复苏趋势目标收益20%,重点布局白酒和免税龙头。
【策略】
1. 贵州茅台:高端白酒龙头,提价预期+渠道优化
2. 五粮液:次高端领军,估值修复空间大
3. 中国中免:免税龙头,海南自贸港政策利好
分散配置每只占比3-5%
【风险控制】
- 总仓位控制在15%以内
- 单只个股止损-8%
- 关注消费数据变化,如不及预期及时调整
- 警惕宏观经济下行风险对消费的冲击
【时间规划】
- 春节前2周完成建仓
- 春节后:观察销售数据和股价反应
- Q1末根据一季度消费数据决定是否加仓
- 全年跟踪:月度社零数据、旅游数据`,
target_date: '2025-04-30',
status: 'pending',
created_at: '2025-01-03T10:30:00Z',
updated_at: '2025-01-03T10:30:00Z',
tags: ['消费', '白酒', '免税'],
stocks: ['600519.SH', '000858.SZ', '601888.SH']
},
// ==================== 复盘数据(符合复盘模板) ====================
{
id: 302,
user_id: 1,
type: 'review',
title: '2024年12月投资复盘 - 白酒板块大涨',
content: `【操作回顾】
1. 11月底在1550元加仓茅台0.5%仓位,持有至今
2. 五粮液持仓未动从11月初一直持有
3. 错过了洋河股份的反弹行情
4. 月中短线做了一次泸州老窖小赚2%出局
【盈亏分析】
- 贵州茅台获利6.5%贡献账户收益约0.65%
- 五粮液获利4.2%贡献账户收益约0.42%
- 泸州老窖短线获利2%贡献约0.06%
- 月度总收益约1.13%
- 同期沪深300涨幅0.8%跑赢指数0.33%
【经验总结】
- 消费板块在年底有明显的估值修复行情,这个规律可以记住
- 龙头白马股在市场震荡时更具韧性,应该坚定持有
- 应该更大胆一些茅台仓位可以再提高2-3个点
- 洋河的机会没把握住,主要是对二线白酒信心不足
【后续调整】
- 继续持有茅台、五粮液,不轻易卖出
- 关注春节前的消费旺季催化
- 如果有回调考虑加仓茅台至5%总仓位
- 下月开始关注春节消费数据`,
target_date: '2024-12-31',
status: 'completed',
created_at: '2025-01-02T09:00:00Z',
updated_at: '2025-01-02T09:00:00Z',
tags: ['月度复盘', '白酒', '2024年12月'],
stocks: ['600519.SH', '000858.SZ', '000568.SZ']
},
{
id: 304,
user_id: 1,
type: 'review',
title: '2024年全年投资总结 - 收益率25.6%',
content: '2024年全年收益率25.6%跑赢沪深300指数12个百分点。\n\n全年亮点\n1. 新能源板块贡献最大年度收益35%\n2. 白酒板块稳健增长年度收益18%\n3. 半导体板块波动较大年度收益8%\n\n教训与反思\n1. 年初追高了一些热门概念股,后续回调损失较大\n2. 止损执行不够坚决,有两次错过最佳止损时机\n3. 仓位管理有待提高,牛市时仓位偏低\n\n2025年目标\n- 收益率目标30%\n- 优化仓位管理,提高资金使用效率\n- 严格执行止损纪律\n- 加强行业研究,提前布局',
content: `【操作回顾】
1. 全年共进行交易52次其中胜率62%
2. 主要盈利来源:新能源(+35%)、白酒(+18%
3. 主要亏损来源:年初追高的概念股(-8%
4. 最成功操作5月底抄底宁德时代持有3个月获利45%
5. 最失败操作3月追高机器人概念亏损12%割肉
【盈亏分析】
- 全年总收益率25.6%
- 沪深300涨幅13.6%
- 超额收益12个百分点
- 最大回撤:-8.5%3月份
- 夏普比率约1.8
- 各板块贡献:
- 新能源:+12.6%
- 白酒:+7.2%
- 半导体:+3.2%
- 其他:+2.6%
【经验总结】
1. 年初追高热门概念股是最大教训,后续回调损失较大
2. 止损执行不够坚决,有两次错过最佳止损时机
3. 仓位管理有待提高牛市时仓位偏低最高才70%
4. 成功的操作都是逆向买入+耐心持有
5. 频繁交易并没有带来更好收益
【后续调整】
2025年目标
- 收益率目标30%
- 优化仓位管理提高资金使用效率至80%+
- 严格执行止损纪律,设置自动止损提醒
- 加强行业研究,提前布局而非追高
- 减少交易频率,提高单次交易质量`,
target_date: '2024-12-31',
status: 'completed',
created_at: '2025-01-01T10:00:00Z',
updated_at: '2025-01-01T10:00:00Z',
tags: ['年度复盘', '2024年', '总结']
tags: ['年度复盘', '2024年', '总结'],
stocks: []
},
{
id: 308,
user_id: 1,
type: 'review',
title: '宁德时代波段操作复盘',
content: `【操作回顾】
- 5月25日在160元附近建仓3%,理由是估值回到历史低位+储能业务放量预期
- 6月10日加仓2%价格172元技术面突破关键阻力
- 7月20日再加仓2%价格195元财报预告超预期
- 8月15日开始分批止盈卖出3%仓位均价235元
- 8月28日清仓剩余4%仓位均价228元
【盈亏分析】
- 第一笔160元买入平均卖出231.5元收益率44.7%
- 第二笔172元买入平均卖出231.5元收益率34.6%
- 第三笔195元买入平均卖出231.5元收益率18.7%
- 加权平均收益率约35%
- 持仓时间约3个月
- 年化收益率约140%
【经验总结】
1. 在估值底部+催化剂出现时建仓是正确的选择
2. 金字塔式加仓策略有效控制了成本
3. 分批止盈策略让我吃到了大部分涨幅
4. 但最后一笔加仓195元价格偏高拉低了整体收益
5. 应该在涨幅达到30%时就开始止盈而非等到40%+
【后续调整】
- 下次操作宁德时代设置150-170元为合理买入区间
- 涨幅达到25%开始分批止盈
- 储能业务是长期逻辑可以保留2%底仓长期持有
- 关注Q4业绩和2025年指引`,
target_date: '2024-08-31',
status: 'completed',
created_at: '2024-09-01T10:00:00Z',
updated_at: '2024-09-01T10:00:00Z',
tags: ['个股复盘', '宁德时代', '波段'],
stocks: ['300750.SZ']
},
{
id: 309,
user_id: 1,
type: 'review',
title: '11月第三周交易复盘',
content: `【操作回顾】
周一:观望,未操作
周二买入比亚迪2%仓位价格248元
周三加仓比亚迪1%价格252元卖出中芯国际1%仓位
周四买入恒瑞医药1.5%仓位价格42元
周五:观望,持仓未动
【盈亏分析】
- 本周账户收益:+0.8%
- 比亚迪浮盈1.2%
- 恒瑞医药浮亏0.5%
- 中芯国际卖出盈利3%
- 同期沪深300+0.5%
- 超额收益:+0.3%
【经验总结】
1. 比亚迪买入时机较好,趁回调建仓
2. 恒瑞医药买得稍早,本周没有继续下跌但也没涨
3. 中芯国际止盈时机把握得不错,避免了后续调整
4. 交易频率偏高,手续费成本需要注意
【后续调整】
- 下周继续持有比亚迪和恒瑞,等待催化
- 如果恒瑞跌破40元考虑加仓
- 比亚迪如果突破260元可以继续加仓
- 下周计划观察AI板块是否有机会`,
target_date: '2024-11-24',
status: 'completed',
created_at: '2024-11-25T18:00:00Z',
updated_at: '2024-11-25T18:00:00Z',
tags: ['周度复盘', '11月第三周'],
stocks: ['002594.SZ', '600276.SH', '688981.SH']
},
{
id: 310,
user_id: 1,
type: 'review',
title: '机器人概念追高教训复盘',
content: `【操作回顾】
- 3月5日看到机器人概念连续大涨FOMO心态买入机器人ETF 5%仓位
- 3月8日继续上涨追加3%仓位
- 3月12日见顶回落犹豫不决
- 3月18日跌破成本价仍抱有侥幸心理
- 3月25日止损出局平均亏损12%
【盈亏分析】
- 买入成本约1.05元(均价)
- 卖出价格约0.92元
- 亏损金额约8%仓位 × 12% = 0.96%账户净值
- 这是本年度最大单笔亏损
- 教训成本约5000元
【经验总结】
1. 追高是最大的错误,概念炒作往往来去匆匆
2. FOMO心态害死人看到别人赚钱就想追
3. 止损不坚决,跌破成本价时就应该走
4. 对机器人行业基本面了解不够,纯粹是跟风
5. 仓位太重首次买入就5%,完全不符合试仓原则
【后续调整】
- 概念炒作坚决不追高,只在调整时考虑
- 任何新建仓位首次买入不超过2%
- 设置硬性止损-5%,坚决执行
- 不熟悉的领域少碰或只做小仓位
- 记住这次教训,下次遇到类似情况要克制`,
target_date: '2024-03-31',
status: 'completed',
created_at: '2024-04-01T09:00:00Z',
updated_at: '2024-04-01T09:00:00Z',
tags: ['教训复盘', '追高', '机器人'],
stocks: []
},
{
id: 311,
user_id: 1,
type: 'review',
title: '半导体板块Q3操作复盘',
content: `【操作回顾】
7月份
- 买入中芯国际3%仓位价格45元
- 买入北方华创2%仓位价格180元
8月份
- 中芯国际加仓1%价格48元
- 北方华创持仓不动
9月份
- 中芯国际在55元分批止盈2%
- 北方华创在195元全部止盈
- 保留中芯国际2%底仓
【盈亏分析】
- 中芯国际:
- 已止盈部分收益率约20%
- 剩余持仓浮盈约15%
- 北方华创:
- 全部止盈收益率约8%
- Q3半导体板块总收益约+3.2%账户净值
- 板块贡献排名:第三(仅次于新能源和白酒)
【经验总结】
1. 半导体板块波动大,不适合重仓长持
2. 北方华创止盈过早后来又涨了10%
3. 中芯国际的分批止盈策略比较成功
4. 应该更多关注设备和材料,而非制造环节
5. 华为产业链相关标的值得持续关注
【后续调整】
- Q4继续持有中芯国际底仓
- 关注北方华创回调机会
- 新增关注标的:长电科技、华虹半导体
- 仓位目标半导体板块不超过10%`,
target_date: '2024-09-30',
status: 'completed',
created_at: '2024-10-08T10:00:00Z',
updated_at: '2024-10-08T10:00:00Z',
tags: ['季度复盘', '半导体', 'Q3'],
stocks: ['688981.SH', '002371.SZ']
}
];
@@ -537,6 +896,31 @@ export const mockFutureEvents = [
];
export const mockCalendarEvents = [
{
id: 408,
user_id: 1,
title: '2025中医药高质量发展大会将于12月5日至7日举办',
date: '2025-12-05',
event_date: '2025-12-05',
type: 'policy',
category: 'industry_event',
description: `基于提供的路演记录、新闻动态以及上市公司公告,以下是与"2025中医药高质量发展大会将于12月5日至7日举办"相关的信息整理:
事件背景:
"2025中医药高质量发展大会"将于12月5日至7日在北京召开由国家中医药管理局主办旨在总结十四五期间中医药发展成果部署下一阶段重点任务。大会主题为"守正创新、传承发展",将邀请国内外中医药领域专家学者、企业代表共商中医药现代化发展路径。
政策支持:
1. 国务院办公厅印发《中医药振兴发展重大工程实施方案》明确到2025年中医药服务体系更加完善
2. 国家医保局持续推进中成药集采,优质中药企业有望受益于市场集中度提升
3. 各地出台中医药产业发展支持政策,加大对中药创新药研发的资金支持
行业展望:
中医药行业正处于政策红利期,创新中药、配方颗粒、中药材种植等细分领域景气度较高。预计大会将释放更多利好政策信号,推动行业高质量发展。`,
importance: 5,
source: 'future',
stocks: ['002424.SZ', '002873.SZ', '600518.SH', '002907.SZ', '600129.SH', '300519.SZ', '300878.SZ', '002275.SZ', '600222.SH'],
created_at: '2025-12-01T10:00:00Z'
},
{
id: 401,
user_id: 1,

View File

@@ -873,14 +873,17 @@ export function generateMockEvents(params = {}) {
filteredEvents = filteredEvents.filter(e =>
e.title.toLowerCase().includes(query) ||
e.description.toLowerCase().includes(query) ||
e.keywords.some(k => k.toLowerCase().includes(query))
// keywords 是对象数组 { concept, score, ... },需要访问 concept 属性
e.keywords.some(k => k.concept && k.concept.toLowerCase().includes(query))
);
}
// 行业筛选
if (industry_code) {
filteredEvents = filteredEvents.filter(e =>
e.industry.includes(industry_code) || e.keywords.includes(industry_code)
e.industry.includes(industry_code) ||
// keywords 是对象数组 { concept, ... },需要检查 concept 属性
e.keywords.some(k => k.concept && k.concept.includes(industry_code))
);
}
@@ -893,9 +896,11 @@ export function generateMockEvents(params = {}) {
return false;
}
// 检查事件的 related_stocks 中是否包含该股票代码
return e.related_stocks.some(code => {
const cleanCode = code.replace(/\.(SH|SZ)$/, '');
return cleanCode === cleanStockCode || code === stock_code;
// related_stocks 是对象数组 { stock_code, stock_name, ... }
return e.related_stocks.some(stock => {
const stockCodeStr = stock.stock_code || '';
const cleanCode = stockCodeStr.replace(/\.(SH|SZ)$/, '');
return cleanCode === cleanStockCode || stockCodeStr === stock_code;
});
});
}

View File

@@ -434,13 +434,8 @@ export const accountHandlers = [
http.get('/api/account/calendar/events', async ({ request }) => {
await delay(NETWORK_DELAY);
const currentUser = getCurrentUser();
if (!currentUser) {
return HttpResponse.json(
{ success: false, error: '未登录' },
{ status: 401 }
);
}
// Mock 模式下允许无登录访问,使用默认用户 id: 1
const currentUser = getCurrentUser() || { id: 1 };
const url = new URL(request.url);
const startDate = url.searchParams.get('start_date');
@@ -455,8 +450,8 @@ export const accountHandlers = [
}
// 2. 获取投资计划和复盘,转换为日历事件格式
// Mock 模式:不过滤 user_id显示所有 mock 数据(方便开发测试)
const investmentPlansAsEvents = mockInvestmentPlans
.filter(plan => plan.user_id === currentUser.id)
.map(plan => ({
id: plan.id,
user_id: plan.user_id,
@@ -489,10 +484,13 @@ export const accountHandlers = [
});
}
console.log('[Mock] 合并后的日历事件数量:', {
console.log('[Mock] 日历事件详情:', {
currentUserId: currentUser.id,
calendarEvents: calendarEvents.length,
investmentPlansAsEvents: investmentPlansAsEvents.length,
total: filteredEvents.length
total: filteredEvents.length,
plansCount: filteredEvents.filter(e => e.type === 'plan').length,
reviewsCount: filteredEvents.filter(e => e.type === 'review').length
});
return HttpResponse.json({

View File

@@ -123,12 +123,12 @@ const generateStockList = () => {
// 股票相关的 Handlers
export const stockHandlers = [
// 搜索股票(个股中心页面使用)
// 搜索股票(个股中心页面使用)- 支持模糊搜索
http.get('/api/stocks/search', async ({ request }) => {
await delay(200);
const url = new URL(request.url);
const query = url.searchParams.get('q') || '';
const query = (url.searchParams.get('q') || '').toLowerCase().trim();
const limit = parseInt(url.searchParams.get('limit') || '10');
console.log('[Mock Stock] 搜索股票:', { query, limit });
@@ -136,22 +136,44 @@ export const stockHandlers = [
const stocks = generateStockList();
// 如果没有搜索词,返回空结果
if (!query.trim()) {
if (!query) {
return HttpResponse.json({
success: true,
data: []
});
}
// 过滤匹配的股票
const results = stocks.filter(s =>
s.code.includes(query) || s.name.includes(query)
).slice(0, limit);
// 模糊搜索:代码 + 名称(不区分大小写)
const results = stocks.filter(s => {
const code = s.code.toLowerCase();
const name = s.name.toLowerCase();
return code.includes(query) || name.includes(query);
});
// 按相关性排序:完全匹配 > 开头匹配 > 包含匹配
results.sort((a, b) => {
const aCode = a.code.toLowerCase();
const bCode = b.code.toLowerCase();
const aName = a.name.toLowerCase();
const bName = b.name.toLowerCase();
// 计算匹配分数
const getScore = (code, name) => {
if (code === query || name === query) return 100; // 完全匹配
if (code.startsWith(query)) return 80; // 代码开头
if (name.startsWith(query)) return 60; // 名称开头
if (code.includes(query)) return 40; // 代码包含
if (name.includes(query)) return 20; // 名称包含
return 0;
};
return getScore(bCode, bName) - getScore(aCode, aName);
});
// 返回格式化数据
return HttpResponse.json({
success: true,
data: results.map(s => ({
data: results.slice(0, limit).map(s => ({
stock_code: s.code,
stock_name: s.name,
market: s.code.startsWith('6') ? 'SH' : 'SZ',