feat: 个人中心页添加mock数据
This commit is contained in:
499
src/mocks/data/account.js
Normal file
499
src/mocks/data/account.js
Normal file
@@ -0,0 +1,499 @@
|
||||
// src/mocks/data/account.js
|
||||
// 个人中心相关的 Mock 数据
|
||||
|
||||
// ==================== 自选股数据 ====================
|
||||
|
||||
export const mockWatchlist = [
|
||||
{
|
||||
id: 1,
|
||||
user_id: 1,
|
||||
stock_code: '600519.SH',
|
||||
stock_name: '贵州茅台',
|
||||
industry: '白酒',
|
||||
current_price: 1650.50,
|
||||
change_percent: 2.5,
|
||||
added_at: '2025-01-10T10:30:00Z'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
user_id: 1,
|
||||
stock_code: '000001.SZ',
|
||||
stock_name: '平安银行',
|
||||
industry: '银行',
|
||||
current_price: 12.34,
|
||||
change_percent: 4.76,
|
||||
added_at: '2025-01-15T14:20:00Z'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
user_id: 1,
|
||||
stock_code: '000858.SZ',
|
||||
stock_name: '五粮液',
|
||||
industry: '白酒',
|
||||
current_price: 156.78,
|
||||
change_percent: 1.52,
|
||||
added_at: '2025-01-08T09:15:00Z'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
user_id: 1,
|
||||
stock_code: '300750.SZ',
|
||||
stock_name: '宁德时代',
|
||||
industry: '新能源',
|
||||
current_price: 168.90,
|
||||
change_percent: -1.23,
|
||||
added_at: '2025-01-12T16:45:00Z'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
user_id: 1,
|
||||
stock_code: '002594.SZ',
|
||||
stock_name: 'BYD比亚迪',
|
||||
industry: '新能源汽车',
|
||||
current_price: 256.88,
|
||||
change_percent: 3.45,
|
||||
added_at: '2025-01-05T11:20:00Z'
|
||||
}
|
||||
];
|
||||
|
||||
// ==================== 实时行情数据 ====================
|
||||
|
||||
export const mockRealtimeQuotes = [
|
||||
{
|
||||
stock_code: '600519.SH',
|
||||
current_price: 1650.50,
|
||||
change_percent: 2.5,
|
||||
change: 40.25,
|
||||
volume: 2345678,
|
||||
turnover: 3945678901.23,
|
||||
high: 1665.00,
|
||||
low: 1645.00,
|
||||
open: 1648.80,
|
||||
prev_close: 1610.25,
|
||||
update_time: '15:00:00'
|
||||
},
|
||||
{
|
||||
stock_code: '000001.SZ',
|
||||
current_price: 12.34,
|
||||
change_percent: 4.76,
|
||||
change: 0.56,
|
||||
volume: 123456789,
|
||||
turnover: 1523456789.12,
|
||||
high: 12.50,
|
||||
low: 11.80,
|
||||
open: 11.90,
|
||||
prev_close: 11.78,
|
||||
update_time: '15:00:00'
|
||||
},
|
||||
{
|
||||
stock_code: '000858.SZ',
|
||||
current_price: 156.78,
|
||||
change_percent: 1.52,
|
||||
change: 2.34,
|
||||
volume: 45678901,
|
||||
turnover: 7123456789.45,
|
||||
high: 158.00,
|
||||
low: 154.50,
|
||||
open: 155.00,
|
||||
prev_close: 154.44,
|
||||
update_time: '15:00:00'
|
||||
},
|
||||
{
|
||||
stock_code: '300750.SZ',
|
||||
current_price: 168.90,
|
||||
change_percent: -1.23,
|
||||
change: -2.10,
|
||||
volume: 98765432,
|
||||
turnover: 16678945612.34,
|
||||
high: 172.30,
|
||||
low: 167.50,
|
||||
open: 171.00,
|
||||
prev_close: 171.00,
|
||||
update_time: '15:00:00'
|
||||
},
|
||||
{
|
||||
stock_code: '002594.SZ',
|
||||
current_price: 256.88,
|
||||
change_percent: 3.45,
|
||||
change: 8.56,
|
||||
volume: 56789012,
|
||||
turnover: 14567890123.45,
|
||||
high: 260.00,
|
||||
low: 252.00,
|
||||
open: 253.50,
|
||||
prev_close: 248.32,
|
||||
update_time: '15:00:00'
|
||||
}
|
||||
];
|
||||
|
||||
// ==================== 关注事件数据 ====================
|
||||
|
||||
export const mockFollowingEvents = [
|
||||
{
|
||||
id: 101,
|
||||
title: '央行宣布降准0.5个百分点,释放长期资金约1.2万亿元',
|
||||
tags: ['货币政策', '央行', '降准', '银行'],
|
||||
view_count: 12340,
|
||||
comment_count: 156,
|
||||
upvote_count: 489,
|
||||
heat_score: 95,
|
||||
exceed_expectation_score: 85,
|
||||
creator: {
|
||||
id: 1001,
|
||||
username: '财经分析师',
|
||||
avatar_url: 'https://i.pravatar.cc/150?img=11'
|
||||
},
|
||||
created_at: '2025-01-15T09:00:00Z',
|
||||
followed_at: '2025-01-15T10:30:00Z'
|
||||
},
|
||||
{
|
||||
id: 102,
|
||||
title: 'ChatGPT-5 即将发布,AI 算力需求将迎来爆发式增长',
|
||||
tags: ['人工智能', 'ChatGPT', '算力', '科技'],
|
||||
view_count: 8950,
|
||||
comment_count: 234,
|
||||
upvote_count: 567,
|
||||
heat_score: 88,
|
||||
exceed_expectation_score: 78,
|
||||
creator: {
|
||||
id: 1002,
|
||||
username: '科技观察者',
|
||||
avatar_url: 'https://i.pravatar.cc/150?img=12'
|
||||
},
|
||||
created_at: '2025-01-14T14:20:00Z',
|
||||
followed_at: '2025-01-14T15:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 103,
|
||||
title: '新能源汽车补贴政策延续至2026年,行业持续受益',
|
||||
tags: ['新能源', '汽车', '补贴政策', '产业政策'],
|
||||
view_count: 6780,
|
||||
comment_count: 98,
|
||||
upvote_count: 345,
|
||||
heat_score: 72,
|
||||
exceed_expectation_score: 68,
|
||||
creator: {
|
||||
id: 1003,
|
||||
username: '产业研究员',
|
||||
avatar_url: 'https://i.pravatar.cc/150?img=13'
|
||||
},
|
||||
created_at: '2025-01-13T11:15:00Z',
|
||||
followed_at: '2025-01-13T12:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 104,
|
||||
title: '芯片法案正式实施,国产半导体迎来黄金发展期',
|
||||
tags: ['半导体', '芯片', '国产替代', '政策'],
|
||||
view_count: 9540,
|
||||
comment_count: 178,
|
||||
upvote_count: 432,
|
||||
heat_score: 80,
|
||||
exceed_expectation_score: 72,
|
||||
creator: {
|
||||
id: 1004,
|
||||
username: '半导体观察',
|
||||
avatar_url: 'https://i.pravatar.cc/150?img=14'
|
||||
},
|
||||
created_at: '2025-01-12T16:30:00Z',
|
||||
followed_at: '2025-01-12T17:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 105,
|
||||
title: '医保目录调整,创新药企业有望获得更多市场份额',
|
||||
tags: ['医药', '医保', '创新药', '政策'],
|
||||
view_count: 5430,
|
||||
comment_count: 87,
|
||||
upvote_count: 234,
|
||||
heat_score: 65,
|
||||
exceed_expectation_score: null,
|
||||
creator: {
|
||||
id: 1005,
|
||||
username: '医药行业专家',
|
||||
avatar_url: 'https://i.pravatar.cc/150?img=15'
|
||||
},
|
||||
created_at: '2025-01-11T10:00:00Z',
|
||||
followed_at: '2025-01-11T11:30:00Z'
|
||||
}
|
||||
];
|
||||
|
||||
// ==================== 评论数据 ====================
|
||||
|
||||
export const mockEventComments = [
|
||||
{
|
||||
id: 201,
|
||||
user_id: 1,
|
||||
event_id: 101,
|
||||
event_title: '央行宣布降准0.5个百分点,释放长期资金约1.2万亿元',
|
||||
content: '这次降准对银行股是重大利好!预计四大行和股份制银行都会受益,特别是净息差承压的中小银行。建议重点关注招商银行、兴业银行等优质标的。',
|
||||
created_at: '2025-01-15T11:20:00Z',
|
||||
likes: 45,
|
||||
replies: 12
|
||||
},
|
||||
{
|
||||
id: 202,
|
||||
user_id: 1,
|
||||
event_id: 102,
|
||||
event_title: 'ChatGPT-5 即将发布,AI 算力需求将迎来爆发式增长',
|
||||
content: 'AI 板块又要起飞了!重点关注算力基础设施概念股,如服务器、芯片、数据中心等。另外,AI 应用端也值得关注,特别是已经有成熟产品的公司。',
|
||||
created_at: '2025-01-14T16:45:00Z',
|
||||
likes: 38,
|
||||
replies: 8
|
||||
},
|
||||
{
|
||||
id: 203,
|
||||
user_id: 1,
|
||||
event_id: 103,
|
||||
event_title: '新能源汽车补贴政策延续至2026年,行业持续受益',
|
||||
content: '政策延续对整个产业链都是好消息。上游的锂电池、下游的整车厂都会受益。比亚迪和宁德时代可以继续持有,长期看好新能源汽车的渗透率提升。',
|
||||
created_at: '2025-01-13T14:30:00Z',
|
||||
likes: 56,
|
||||
replies: 15
|
||||
},
|
||||
{
|
||||
id: 204,
|
||||
user_id: 1,
|
||||
event_id: 104,
|
||||
event_title: '芯片法案正式实施,国产半导体迎来黄金发展期',
|
||||
content: '国产替代是大趋势!设备材料、设计封测、制造都有机会。关注那些有核心技术、已经打入国内大厂供应链的公司。半导体是长期主线,波动中坚定持有。',
|
||||
created_at: '2025-01-12T18:00:00Z',
|
||||
likes: 67,
|
||||
replies: 20
|
||||
},
|
||||
{
|
||||
id: 205,
|
||||
user_id: 1,
|
||||
event_id: 105,
|
||||
event_title: '医保目录调整,创新药企业有望获得更多市场份额',
|
||||
content: '医保谈判结果出来了,创新药企业普遍受益。重点关注有多个重磅品种的药企,以及 CXO 产业链。医药板块经过调整后,估值已经比较合理,可以逐步配置。',
|
||||
created_at: '2025-01-11T13:15:00Z',
|
||||
likes: 42,
|
||||
replies: 10
|
||||
}
|
||||
];
|
||||
|
||||
// ==================== 投资计划与复盘数据 ====================
|
||||
|
||||
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%',
|
||||
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月']
|
||||
},
|
||||
{
|
||||
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%以内',
|
||||
target_date: '2025-02-28',
|
||||
status: 'pending',
|
||||
created_at: '2025-01-14T16:00:00Z',
|
||||
updated_at: '2025-01-14T16:00:00Z',
|
||||
tags: ['AI', '算力', '波段交易']
|
||||
},
|
||||
{
|
||||
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- 加强行业研究,提前布局',
|
||||
target_date: '2024-12-31',
|
||||
status: 'completed',
|
||||
created_at: '2025-01-01T10:00:00Z',
|
||||
updated_at: '2025-01-01T10:00:00Z',
|
||||
tags: ['年度复盘', '2024年', '总结']
|
||||
}
|
||||
];
|
||||
|
||||
// ==================== 投资日历事件数据 ====================
|
||||
|
||||
export const mockCalendarEvents = [
|
||||
{
|
||||
id: 401,
|
||||
user_id: 1,
|
||||
title: '贵州茅台年报披露',
|
||||
date: '2025-12-20',
|
||||
event_date: '2025-12-20',
|
||||
type: 'earnings',
|
||||
category: 'financial_report',
|
||||
description: '关注营收和净利润增速,以及渠道库存情况',
|
||||
stock_code: '600519.SH',
|
||||
stock_name: '贵州茅台',
|
||||
importance: 5,
|
||||
source: 'future',
|
||||
stocks: ['600519'],
|
||||
created_at: '2025-01-10T10:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 402,
|
||||
user_id: 1,
|
||||
title: '宁德时代业绩快报',
|
||||
date: '2025-11-28',
|
||||
event_date: '2025-11-28',
|
||||
type: 'earnings',
|
||||
category: 'financial_report',
|
||||
description: '重点关注出货量和单位盈利情况',
|
||||
stock_code: '300750.SZ',
|
||||
stock_name: '宁德时代',
|
||||
importance: 5,
|
||||
source: 'future',
|
||||
stocks: ['300750'],
|
||||
created_at: '2025-01-12T14:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 403,
|
||||
user_id: 1,
|
||||
title: '央行货币政策委员会例会',
|
||||
date: '2025-10-25',
|
||||
event_date: '2025-10-25',
|
||||
type: 'policy',
|
||||
category: 'macro_policy',
|
||||
description: '关注货币政策基调和利率调整信号',
|
||||
importance: 4,
|
||||
source: 'future',
|
||||
stocks: [],
|
||||
created_at: '2025-01-08T09:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 404,
|
||||
user_id: 1,
|
||||
title: '春节假期后首个交易日',
|
||||
date: '2025-11-15',
|
||||
event_date: '2025-11-15',
|
||||
type: 'reminder',
|
||||
category: 'trading',
|
||||
description: '节后第一天,关注资金面和市场情绪',
|
||||
importance: 3,
|
||||
source: 'future',
|
||||
stocks: [],
|
||||
created_at: '2025-01-05T16:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 405,
|
||||
user_id: 1,
|
||||
title: '定投日 - 沪深300ETF',
|
||||
date: '2025-10-20',
|
||||
event_date: '2025-10-20',
|
||||
type: 'reminder',
|
||||
category: 'investment',
|
||||
description: '每月20日定投3000元',
|
||||
importance: 2,
|
||||
source: 'user',
|
||||
stocks: [],
|
||||
is_recurring: true,
|
||||
recurrence_rule: 'monthly',
|
||||
created_at: '2024-12-15T10:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 406,
|
||||
user_id: 1,
|
||||
title: '美联储FOMC会议',
|
||||
date: '2025-11-07',
|
||||
event_date: '2025-11-07',
|
||||
type: 'policy',
|
||||
category: 'macro_policy',
|
||||
description: '关注美联储利率决议和鲍威尔讲话',
|
||||
importance: 5,
|
||||
source: 'future',
|
||||
stocks: [],
|
||||
created_at: '2025-01-07T11:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 407,
|
||||
user_id: 1,
|
||||
title: '持仓股票复盘日',
|
||||
date: '2025-10-26',
|
||||
event_date: '2025-10-26',
|
||||
type: 'reminder',
|
||||
category: 'review',
|
||||
description: '每周六进行持仓复盘和下周计划',
|
||||
importance: 3,
|
||||
source: 'user',
|
||||
stocks: [],
|
||||
is_recurring: true,
|
||||
recurrence_rule: 'weekly',
|
||||
created_at: '2025-01-01T10:00:00Z'
|
||||
}
|
||||
];
|
||||
|
||||
// ==================== 订阅信息数据 ====================
|
||||
|
||||
export const mockSubscriptionCurrent = {
|
||||
type: 'pro',
|
||||
status: 'active',
|
||||
is_active: true,
|
||||
days_left: 90,
|
||||
end_date: '2025-04-15T23:59:59Z',
|
||||
plan_name: 'Pro版',
|
||||
features: [
|
||||
'无限事件查看',
|
||||
'实时行情推送',
|
||||
'专业分析报告',
|
||||
'优先客服支持',
|
||||
'关联股票分析',
|
||||
'历史事件对比'
|
||||
],
|
||||
price: 0.01,
|
||||
currency: 'CNY',
|
||||
billing_cycle: 'monthly',
|
||||
auto_renew: true,
|
||||
next_billing_date: '2025-02-15T00:00:00Z'
|
||||
};
|
||||
|
||||
// ==================== 辅助函数 ====================
|
||||
|
||||
// 根据用户ID获取自选股
|
||||
export function getWatchlistByUserId(userId) {
|
||||
return mockWatchlist.filter(item => item.user_id === userId);
|
||||
}
|
||||
|
||||
// 根据用户ID获取关注事件
|
||||
export function getFollowingEventsByUserId(userId) {
|
||||
return mockFollowingEvents;
|
||||
}
|
||||
|
||||
// 根据用户ID获取评论
|
||||
export function getCommentsByUserId(userId) {
|
||||
return mockEventComments.filter(comment => comment.user_id === userId);
|
||||
}
|
||||
|
||||
// 根据用户ID获取投资计划
|
||||
export function getInvestmentPlansByUserId(userId) {
|
||||
return mockInvestmentPlans.filter(plan => plan.user_id === userId);
|
||||
}
|
||||
|
||||
// 根据用户ID获取日历事件
|
||||
export function getCalendarEventsByUserId(userId) {
|
||||
return mockCalendarEvents.filter(event => event.user_id === userId);
|
||||
}
|
||||
|
||||
// 获取指定日期范围的日历事件
|
||||
export function getCalendarEventsByDateRange(userId, startDate, endDate) {
|
||||
const start = new Date(startDate);
|
||||
const end = new Date(endDate);
|
||||
|
||||
return mockCalendarEvents.filter(event => {
|
||||
if (event.user_id !== userId) return false;
|
||||
const eventDate = new Date(event.date);
|
||||
return eventDate >= start && eventDate <= end;
|
||||
});
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -311,179 +311,183 @@ export default function InvestmentCalendarChakra() {
|
||||
)}
|
||||
</CardBody>
|
||||
|
||||
{/* 查看事件详情 Modal */}
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
{selectedDate && selectedDate.format('YYYY年MM月DD日')} 的事件
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
{selectedDateEvents.length === 0 ? (
|
||||
<Center py={8}>
|
||||
<VStack>
|
||||
<Text color={secondaryText}>当天没有事件</Text>
|
||||
<Button
|
||||
size="sm"
|
||||
colorScheme="blue"
|
||||
leftIcon={<FiPlus />}
|
||||
onClick={() => {
|
||||
onClose();
|
||||
onAddOpen();
|
||||
}}
|
||||
>
|
||||
添加投资计划
|
||||
</Button>
|
||||
</VStack>
|
||||
</Center>
|
||||
) : (
|
||||
<VStack align="stretch" spacing={4}>
|
||||
{selectedDateEvents.map((event, idx) => (
|
||||
<Box
|
||||
key={idx}
|
||||
p={4}
|
||||
borderRadius="md"
|
||||
border="1px"
|
||||
borderColor={borderColor}
|
||||
>
|
||||
<Flex justify="space-between" align="start" mb={2}>
|
||||
<VStack align="start" spacing={1} flex={1}>
|
||||
<HStack>
|
||||
<Text fontWeight="bold" fontSize="lg">
|
||||
{event.title}
|
||||
</Text>
|
||||
{event.extendedProps?.isSystem ? (
|
||||
<Badge colorScheme="blue" variant="subtle">系统事件</Badge>
|
||||
) : (
|
||||
<Badge colorScheme="purple" variant="subtle">我的计划</Badge>
|
||||
)}
|
||||
</HStack>
|
||||
<HStack spacing={2}>
|
||||
<Icon as={FiStar} color="yellow.500" />
|
||||
<Text fontSize="sm" color={secondaryText}>
|
||||
重要度: {event.extendedProps?.importance || 3}/5
|
||||
</Text>
|
||||
</HStack>
|
||||
</VStack>
|
||||
{!event.extendedProps?.isSystem && (
|
||||
<IconButton
|
||||
icon={<FiTrash2 />}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
colorScheme="red"
|
||||
onClick={() => handleDeleteEvent(event.extendedProps?.id)}
|
||||
/>
|
||||
{/* 查看事件详情 Modal - 条件渲染 */}
|
||||
{isOpen && (
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="xl" closeOnOverlayClick={false} closeOnEsc={true}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
{selectedDate && selectedDate.format('YYYY年MM月DD日')} 的事件
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
{selectedDateEvents.length === 0 ? (
|
||||
<Center py={8}>
|
||||
<VStack>
|
||||
<Text color={secondaryText}>当天没有事件</Text>
|
||||
<Button
|
||||
size="sm"
|
||||
colorScheme="blue"
|
||||
leftIcon={<FiPlus />}
|
||||
onClick={() => {
|
||||
onClose();
|
||||
onAddOpen();
|
||||
}}
|
||||
>
|
||||
添加投资计划
|
||||
</Button>
|
||||
</VStack>
|
||||
</Center>
|
||||
) : (
|
||||
<VStack align="stretch" spacing={4}>
|
||||
{selectedDateEvents.map((event, idx) => (
|
||||
<Box
|
||||
key={idx}
|
||||
p={4}
|
||||
borderRadius="md"
|
||||
border="1px"
|
||||
borderColor={borderColor}
|
||||
>
|
||||
<Flex justify="space-between" align="start" mb={2}>
|
||||
<VStack align="start" spacing={1} flex={1}>
|
||||
<HStack>
|
||||
<Text fontWeight="bold" fontSize="lg">
|
||||
{event.title}
|
||||
</Text>
|
||||
{event.extendedProps?.isSystem ? (
|
||||
<Badge colorScheme="blue" variant="subtle">系统事件</Badge>
|
||||
) : (
|
||||
<Badge colorScheme="purple" variant="subtle">我的计划</Badge>
|
||||
)}
|
||||
</HStack>
|
||||
<HStack spacing={2}>
|
||||
<Icon as={FiStar} color="yellow.500" />
|
||||
<Text fontSize="sm" color={secondaryText}>
|
||||
重要度: {event.extendedProps?.importance || 3}/5
|
||||
</Text>
|
||||
</HStack>
|
||||
</VStack>
|
||||
{!event.extendedProps?.isSystem && (
|
||||
<IconButton
|
||||
icon={<FiTrash2 />}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
colorScheme="red"
|
||||
onClick={() => handleDeleteEvent(event.extendedProps?.id)}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
{event.extendedProps?.description && (
|
||||
<Text fontSize="sm" color={secondaryText} mb={2}>
|
||||
{event.extendedProps.description}
|
||||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
{event.extendedProps?.description && (
|
||||
<Text fontSize="sm" color={secondaryText} mb={2}>
|
||||
{event.extendedProps.description}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{event.extendedProps?.stocks && event.extendedProps.stocks.length > 0 && (
|
||||
<HStack spacing={2} flexWrap="wrap">
|
||||
<Text fontSize="sm" color={secondaryText}>相关股票:</Text>
|
||||
{event.extendedProps.stocks.map((stock, i) => (
|
||||
<Tag key={i} size="sm" colorScheme="blue">
|
||||
<TagLeftIcon as={FiTrendingUp} />
|
||||
<TagLabel>{stock}</TagLabel>
|
||||
</Tag>
|
||||
))}
|
||||
</HStack>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
|
||||
{event.extendedProps?.stocks && event.extendedProps.stocks.length > 0 && (
|
||||
<HStack spacing={2} flexWrap="wrap">
|
||||
<Text fontSize="sm" color={secondaryText}>相关股票:</Text>
|
||||
{event.extendedProps.stocks.map((stock, i) => (
|
||||
<Tag key={i} size="sm" colorScheme="blue">
|
||||
<TagLeftIcon as={FiTrendingUp} />
|
||||
<TagLabel>{stock}</TagLabel>
|
||||
</Tag>
|
||||
))}
|
||||
</HStack>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
</VStack>
|
||||
)}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button onClick={onClose}>关闭</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)}
|
||||
|
||||
{/* 添加投资计划 Modal - 条件渲染 */}
|
||||
{isAddOpen && (
|
||||
<Modal isOpen={isAddOpen} onClose={onAddClose} size="lg" closeOnOverlayClick={false} closeOnEsc={true}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
添加投资计划
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<VStack spacing={4}>
|
||||
<FormControl isRequired>
|
||||
<FormLabel>标题</FormLabel>
|
||||
<Input
|
||||
value={newEvent.title}
|
||||
onChange={(e) => setNewEvent({ ...newEvent, title: e.target.value })}
|
||||
placeholder="例如:关注半导体板块"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>描述</FormLabel>
|
||||
<Textarea
|
||||
value={newEvent.description}
|
||||
onChange={(e) => setNewEvent({ ...newEvent, description: e.target.value })}
|
||||
placeholder="详细描述您的投资计划..."
|
||||
rows={3}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>类型</FormLabel>
|
||||
<Select
|
||||
value={newEvent.type}
|
||||
onChange={(e) => setNewEvent({ ...newEvent, type: e.target.value })}
|
||||
>
|
||||
<option value="plan">投资计划</option>
|
||||
<option value="reminder">提醒事项</option>
|
||||
<option value="analysis">分析任务</option>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>重要度</FormLabel>
|
||||
<Select
|
||||
value={newEvent.importance}
|
||||
onChange={(e) => setNewEvent({ ...newEvent, importance: parseInt(e.target.value) })}
|
||||
>
|
||||
<option value={5}>⭐⭐⭐⭐⭐ 非常重要</option>
|
||||
<option value={4}>⭐⭐⭐⭐ 重要</option>
|
||||
<option value={3}>⭐⭐⭐ 一般</option>
|
||||
<option value={2}>⭐⭐ 次要</option>
|
||||
<option value={1}>⭐ 不重要</option>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>相关股票(用逗号分隔)</FormLabel>
|
||||
<Input
|
||||
value={newEvent.stocks}
|
||||
onChange={(e) => setNewEvent({ ...newEvent, stocks: e.target.value })}
|
||||
placeholder="例如:600519,000858,002415"
|
||||
/>
|
||||
</FormControl>
|
||||
</VStack>
|
||||
)}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button onClick={onClose}>关闭</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
||||
{/* 添加投资计划 Modal */}
|
||||
<Modal isOpen={isAddOpen} onClose={onAddClose} size="lg">
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
添加投资计划
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<VStack spacing={4}>
|
||||
<FormControl isRequired>
|
||||
<FormLabel>标题</FormLabel>
|
||||
<Input
|
||||
value={newEvent.title}
|
||||
onChange={(e) => setNewEvent({ ...newEvent, title: e.target.value })}
|
||||
placeholder="例如:关注半导体板块"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>描述</FormLabel>
|
||||
<Textarea
|
||||
value={newEvent.description}
|
||||
onChange={(e) => setNewEvent({ ...newEvent, description: e.target.value })}
|
||||
placeholder="详细描述您的投资计划..."
|
||||
rows={3}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>类型</FormLabel>
|
||||
<Select
|
||||
value={newEvent.type}
|
||||
onChange={(e) => setNewEvent({ ...newEvent, type: e.target.value })}
|
||||
>
|
||||
<option value="plan">投资计划</option>
|
||||
<option value="reminder">提醒事项</option>
|
||||
<option value="analysis">分析任务</option>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>重要度</FormLabel>
|
||||
<Select
|
||||
value={newEvent.importance}
|
||||
onChange={(e) => setNewEvent({ ...newEvent, importance: parseInt(e.target.value) })}
|
||||
>
|
||||
<option value={5}>⭐⭐⭐⭐⭐ 非常重要</option>
|
||||
<option value={4}>⭐⭐⭐⭐ 重要</option>
|
||||
<option value={3}>⭐⭐⭐ 一般</option>
|
||||
<option value={2}>⭐⭐ 次要</option>
|
||||
<option value={1}>⭐ 不重要</option>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>相关股票(用逗号分隔)</FormLabel>
|
||||
<Input
|
||||
value={newEvent.stocks}
|
||||
onChange={(e) => setNewEvent({ ...newEvent, stocks: e.target.value })}
|
||||
placeholder="例如:600519,000858,002415"
|
||||
/>
|
||||
</FormControl>
|
||||
</VStack>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant="ghost" mr={3} onClick={onAddClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
onClick={handleAddEvent}
|
||||
isDisabled={!newEvent.title}
|
||||
>
|
||||
添加
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant="ghost" mr={3} onClick={onAddClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
onClick={handleAddEvent}
|
||||
isDisabled={!newEvent.title}
|
||||
>
|
||||
添加
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -452,134 +452,136 @@ export default function InvestmentPlansAndReviews({ type = 'both' }) {
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
|
||||
{/* 编辑/新建模态框 */}
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
{editingItem ? '编辑' : '新建'}
|
||||
{formData.type === 'plan' ? '投资计划' : '复盘记录'}
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<VStack spacing={4}>
|
||||
<FormControl isRequired>
|
||||
<FormLabel>日期</FormLabel>
|
||||
<InputGroup>
|
||||
<InputLeftElement pointerEvents="none">
|
||||
<Icon as={FiCalendar} color={secondaryText} />
|
||||
</InputLeftElement>
|
||||
{/* 编辑/新建模态框 - 条件渲染 */}
|
||||
{isOpen && (
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="xl" closeOnOverlayClick={false} closeOnEsc={true}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
{editingItem ? '编辑' : '新建'}
|
||||
{formData.type === 'plan' ? '投资计划' : '复盘记录'}
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<VStack spacing={4}>
|
||||
<FormControl isRequired>
|
||||
<FormLabel>日期</FormLabel>
|
||||
<InputGroup>
|
||||
<InputLeftElement pointerEvents="none">
|
||||
<Icon as={FiCalendar} color={secondaryText} />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
type="date"
|
||||
value={formData.date}
|
||||
onChange={(e) => setFormData({ ...formData, date: e.target.value })}
|
||||
/>
|
||||
</InputGroup>
|
||||
</FormControl>
|
||||
|
||||
<FormControl isRequired>
|
||||
<FormLabel>标题</FormLabel>
|
||||
<Input
|
||||
type="date"
|
||||
value={formData.date}
|
||||
onChange={(e) => setFormData({ ...formData, date: e.target.value })}
|
||||
value={formData.title}
|
||||
onChange={(e) => setFormData({ ...formData, title: e.target.value })}
|
||||
placeholder={formData.type === 'plan' ? '例如:布局新能源板块' : '例如:本周交易复盘'}
|
||||
/>
|
||||
</InputGroup>
|
||||
</FormControl>
|
||||
</FormControl>
|
||||
|
||||
<FormControl isRequired>
|
||||
<FormLabel>标题</FormLabel>
|
||||
<Input
|
||||
value={formData.title}
|
||||
onChange={(e) => setFormData({ ...formData, title: e.target.value })}
|
||||
placeholder={formData.type === 'plan' ? '例如:布局新能源板块' : '例如:本周交易复盘'}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>内容</FormLabel>
|
||||
<Textarea
|
||||
value={formData.content}
|
||||
onChange={(e) => setFormData({ ...formData, content: e.target.value })}
|
||||
placeholder={formData.type === 'plan' ?
|
||||
'详细描述您的投资计划...' :
|
||||
'记录您的交易心得和经验教训...'}
|
||||
rows={6}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>相关股票</FormLabel>
|
||||
<HStack>
|
||||
<Input
|
||||
value={stockInput}
|
||||
onChange={(e) => setStockInput(e.target.value)}
|
||||
placeholder="输入股票代码"
|
||||
onKeyPress={(e) => e.key === 'Enter' && handleAddStock()}
|
||||
<FormControl>
|
||||
<FormLabel>内容</FormLabel>
|
||||
<Textarea
|
||||
value={formData.content}
|
||||
onChange={(e) => setFormData({ ...formData, content: e.target.value })}
|
||||
placeholder={formData.type === 'plan' ?
|
||||
'详细描述您的投资计划...' :
|
||||
'记录您的交易心得和经验教训...'}
|
||||
rows={6}
|
||||
/>
|
||||
<Button onClick={handleAddStock}>添加</Button>
|
||||
</HStack>
|
||||
<HStack mt={2} spacing={2} flexWrap="wrap">
|
||||
{formData.stocks.map((stock, idx) => (
|
||||
<Tag key={idx} size="sm" colorScheme="blue">
|
||||
<TagLeftIcon as={FiTrendingUp} />
|
||||
<TagLabel>{stock}</TagLabel>
|
||||
<TagCloseButton
|
||||
onClick={() => setFormData({
|
||||
...formData,
|
||||
stocks: formData.stocks.filter((_, i) => i !== idx)
|
||||
})}
|
||||
/>
|
||||
</Tag>
|
||||
))}
|
||||
</HStack>
|
||||
</FormControl>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>标签</FormLabel>
|
||||
<HStack>
|
||||
<Input
|
||||
value={tagInput}
|
||||
onChange={(e) => setTagInput(e.target.value)}
|
||||
placeholder="输入标签"
|
||||
onKeyPress={(e) => e.key === 'Enter' && handleAddTag()}
|
||||
/>
|
||||
<Button onClick={handleAddTag}>添加</Button>
|
||||
</HStack>
|
||||
<HStack mt={2} spacing={2} flexWrap="wrap">
|
||||
{formData.tags.map((tag, idx) => (
|
||||
<Tag key={idx} size="sm" colorScheme="purple">
|
||||
<TagLeftIcon as={FiHash} />
|
||||
<TagLabel>{tag}</TagLabel>
|
||||
<TagCloseButton
|
||||
onClick={() => setFormData({
|
||||
...formData,
|
||||
tags: formData.tags.filter((_, i) => i !== idx)
|
||||
})}
|
||||
/>
|
||||
</Tag>
|
||||
))}
|
||||
</HStack>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>相关股票</FormLabel>
|
||||
<HStack>
|
||||
<Input
|
||||
value={stockInput}
|
||||
onChange={(e) => setStockInput(e.target.value)}
|
||||
placeholder="输入股票代码"
|
||||
onKeyPress={(e) => e.key === 'Enter' && handleAddStock()}
|
||||
/>
|
||||
<Button onClick={handleAddStock}>添加</Button>
|
||||
</HStack>
|
||||
<HStack mt={2} spacing={2} flexWrap="wrap">
|
||||
{formData.stocks.map((stock, idx) => (
|
||||
<Tag key={idx} size="sm" colorScheme="blue">
|
||||
<TagLeftIcon as={FiTrendingUp} />
|
||||
<TagLabel>{stock}</TagLabel>
|
||||
<TagCloseButton
|
||||
onClick={() => setFormData({
|
||||
...formData,
|
||||
stocks: formData.stocks.filter((_, i) => i !== idx)
|
||||
})}
|
||||
/>
|
||||
</Tag>
|
||||
))}
|
||||
</HStack>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>状态</FormLabel>
|
||||
<Select
|
||||
value={formData.status}
|
||||
onChange={(e) => setFormData({ ...formData, status: e.target.value })}
|
||||
>
|
||||
<option value="active">进行中</option>
|
||||
<option value="completed">已完成</option>
|
||||
<option value="cancelled">已取消</option>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</VStack>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant="ghost" mr={3} onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
onClick={handleSave}
|
||||
isDisabled={!formData.title || !formData.date}
|
||||
leftIcon={<FiSave />}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
<FormControl>
|
||||
<FormLabel>标签</FormLabel>
|
||||
<HStack>
|
||||
<Input
|
||||
value={tagInput}
|
||||
onChange={(e) => setTagInput(e.target.value)}
|
||||
placeholder="输入标签"
|
||||
onKeyPress={(e) => e.key === 'Enter' && handleAddTag()}
|
||||
/>
|
||||
<Button onClick={handleAddTag}>添加</Button>
|
||||
</HStack>
|
||||
<HStack mt={2} spacing={2} flexWrap="wrap">
|
||||
{formData.tags.map((tag, idx) => (
|
||||
<Tag key={idx} size="sm" colorScheme="purple">
|
||||
<TagLeftIcon as={FiHash} />
|
||||
<TagLabel>{tag}</TagLabel>
|
||||
<TagCloseButton
|
||||
onClick={() => setFormData({
|
||||
...formData,
|
||||
tags: formData.tags.filter((_, i) => i !== idx)
|
||||
})}
|
||||
/>
|
||||
</Tag>
|
||||
))}
|
||||
</HStack>
|
||||
</FormControl>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>状态</FormLabel>
|
||||
<Select
|
||||
value={formData.status}
|
||||
onChange={(e) => setFormData({ ...formData, status: e.target.value })}
|
||||
>
|
||||
<option value="active">进行中</option>
|
||||
<option value="completed">已完成</option>
|
||||
<option value="cancelled">已取消</option>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</VStack>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant="ghost" mr={3} onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
onClick={handleSave}
|
||||
isDisabled={!formData.title || !formData.date}
|
||||
leftIcon={<FiSave />}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -665,18 +665,19 @@ function Subscription() {
|
||||
)))}
|
||||
</Grid>
|
||||
|
||||
{/* 支付模态框 */}
|
||||
<Modal
|
||||
isOpen={isPaymentModalOpen}
|
||||
onClose={() => {
|
||||
stopAutoPaymentCheck();
|
||||
setPaymentOrder(null);
|
||||
setPaymentCountdown(0);
|
||||
onPaymentModalClose();
|
||||
}}
|
||||
size='lg'
|
||||
closeOnOverlayClick={false}
|
||||
>
|
||||
{/* 支付模态框 - 条件渲染 */}
|
||||
{isPaymentModalOpen && (
|
||||
<Modal
|
||||
isOpen={isPaymentModalOpen}
|
||||
onClose={() => {
|
||||
stopAutoPaymentCheck();
|
||||
setPaymentOrder(null);
|
||||
setPaymentCountdown(0);
|
||||
onPaymentModalClose();
|
||||
}}
|
||||
size='lg'
|
||||
closeOnOverlayClick={false}
|
||||
>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
@@ -862,7 +863,8 @@ function Subscription() {
|
||||
)}
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</Modal>
|
||||
)}
|
||||
|
||||
{/* 调试面板 */}
|
||||
{process.env.NODE_ENV === 'development' && (
|
||||
|
||||
Reference in New Issue
Block a user