From 1351d2626a29d95cabc3b3e79560d5b986db0b7d Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Fri, 5 Dec 2025 11:29:16 +0800 Subject: [PATCH] =?UTF-8?q?pref:=20PlansPanel=20=E5=92=8C=20ReviewsPanel?= =?UTF-8?q?=20=E4=BB=A3=E7=A0=81=E9=AB=98=E5=BA=A6=E9=87=8D=E5=A4=8D,?= =?UTF-8?q?=E6=8F=90=E5=8F=96=E5=85=AC=E5=85=B1=E7=BB=84=E4=BB=B6=20?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E9=80=9A=E7=94=A8=20EventPanel=20=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=20=E6=96=B0=E5=BB=BA=20EventPanel.tsx=20(~420=20?= =?UTF-8?q?=E8=A1=8C)=20-=20=E9=80=9A=E7=94=A8=E4=BA=8B=E4=BB=B6=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=E7=BB=84=E4=BB=B6=20=20=20-=20=E5=88=A0=E9=99=A4=20Pl?= =?UTF-8?q?ansPanel.tsx=20(495=20=E8=A1=8C=20=E2=86=92=2027=20=E8=A1=8C?= =?UTF-8?q?=EF=BC=8C=E5=87=8F=E5=B0=91=2094%)=20=20=20-=20=E5=88=A0?= =?UTF-8?q?=E9=99=A4=20ReviewsPanel.tsx=20(496=20=E8=A1=8C=20=E2=86=92=202?= =?UTF-8?q?7=20=E8=A1=8C=EF=BC=8C=E5=87=8F=E5=B0=91=2094%)=20=20=20-=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20CalendarPanel.tsx=20=E4=B8=AD=E7=9A=84=20s?= =?UTF-8?q?etActiveTab=20=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dashboard/components/CalendarPanel.tsx | 12 +- .../{ReviewsPanel.tsx => EventPanel.tsx} | 102 ++-- .../components/InvestmentPlanningCenter.tsx | 27 +- src/views/Dashboard/components/PlansPanel.tsx | 494 ------------------ 4 files changed, 82 insertions(+), 553 deletions(-) rename src/views/Dashboard/components/{ReviewsPanel.tsx => EventPanel.tsx} (84%) delete mode 100644 src/views/Dashboard/components/PlansPanel.tsx diff --git a/src/views/Dashboard/components/CalendarPanel.tsx b/src/views/Dashboard/components/CalendarPanel.tsx index 66a29da8..3f0a3730 100644 --- a/src/views/Dashboard/components/CalendarPanel.tsx +++ b/src/views/Dashboard/components/CalendarPanel.tsx @@ -91,7 +91,6 @@ export const CalendarPanel: React.FC = () => { allEvents, loadAllData, loading, - setActiveTab, toast, borderColor, secondaryText, @@ -246,13 +245,8 @@ export const CalendarPanel: React.FC = () => { } }; - // 跳转到计划或复盘标签页 - const handleViewDetails = (event: InvestmentEvent): void => { - if (event.type === 'plan') { - setActiveTab(1); // 跳转到"我的计划"标签页 - } else if (event.type === 'review') { - setActiveTab(2); // 跳转到"我的复盘"标签页 - } + // 查看事件详情(关闭弹窗) + const handleViewDetails = (): void => { onClose(); }; @@ -357,7 +351,7 @@ export const CalendarPanel: React.FC = () => { size="sm" variant="ghost" colorScheme="blue" - onClick={() => handleViewDetails(event)} + onClick={() => handleViewDetails()} aria-label="查看详情" /> diff --git a/src/views/Dashboard/components/ReviewsPanel.tsx b/src/views/Dashboard/components/EventPanel.tsx similarity index 84% rename from src/views/Dashboard/components/ReviewsPanel.tsx rename to src/views/Dashboard/components/EventPanel.tsx index fa967638..858bf471 100644 --- a/src/views/Dashboard/components/ReviewsPanel.tsx +++ b/src/views/Dashboard/components/EventPanel.tsx @@ -1,9 +1,14 @@ /** - * ReviewsPanel - 投资复盘列表面板组件 - * 显示、编辑和管理投资复盘 + * EventPanel - 通用事件面板组件 + * 用于显示、编辑和管理投资计划或复盘 + * + * 通过 props 配置差异化行为: + * - type: 'plan' | 'review' + * - colorScheme: 主题色 + * - label: 显示文案 */ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { Box, Button, @@ -71,10 +76,29 @@ interface StatusInfo { } /** - * ReviewsPanel 组件 - * 复盘列表面板,显示所有投资复盘 + * EventPanel Props */ -export const ReviewsPanel: React.FC = () => { +export interface EventPanelProps { + /** 事件类型 */ + type: 'plan' | 'review'; + /** 主题颜色 */ + colorScheme: string; + /** 显示标签(如 "计划" 或 "复盘") */ + label: string; + /** 外部触发打开模态框的计数器 */ + openModalTrigger?: number; +} + +/** + * EventPanel 组件 + * 通用事件列表面板,显示投资计划或复盘 + */ +export const EventPanel: React.FC = ({ + type, + colorScheme, + label, + openModalTrigger, +}) => { const { allEvents, loadAllData, @@ -83,8 +107,6 @@ export const ReviewsPanel: React.FC = () => { textColor, secondaryText, cardBg, - borderColor, - openReviewModalTrigger, } = usePlanningData(); const { isOpen, onOpen, onClose } = useDisclosure(); @@ -93,7 +115,7 @@ export const ReviewsPanel: React.FC = () => { date: dayjs().format('YYYY-MM-DD'), title: '', content: '', - type: 'review', + type, stocks: [], tags: [], status: 'active', @@ -101,25 +123,18 @@ export const ReviewsPanel: React.FC = () => { const [stockInput, setStockInput] = useState(''); const [tagInput, setTagInput] = useState(''); - // 筛选复盘列表(排除系统事件) - const reviews = allEvents.filter(event => event.type === 'review' && event.source !== 'future'); - - // 监听外部触发打开新建模态框 - useEffect(() => { - if (openReviewModalTrigger && openReviewModalTrigger > 0) { - handleOpenModal(null); - } - }, [openReviewModalTrigger]); + // 筛选事件列表(按类型过滤,排除系统事件) + const events = allEvents.filter(event => event.type === type && event.source !== 'future'); // 打开编辑/新建模态框 - const handleOpenModal = (item: InvestmentEvent | null = null): void => { + const handleOpenModal = useCallback((item: InvestmentEvent | null = null): void => { if (item) { setEditingItem(item); setFormData({ date: dayjs(item.event_date || item.date).format('YYYY-MM-DD'), title: item.title, content: item.description || item.content || '', - type: 'review', + type, stocks: item.stocks || [], tags: item.tags || [], status: item.status || 'active', @@ -130,14 +145,21 @@ export const ReviewsPanel: React.FC = () => { date: dayjs().format('YYYY-MM-DD'), title: '', content: '', - type: 'review', + type, stocks: [], tags: [], status: 'active', }); } onOpen(); - }; + }, [type, onOpen]); + + // 监听外部触发打开新建模态框 + useEffect(() => { + if (openModalTrigger && openModalTrigger > 0) { + handleOpenModal(null); + } + }, [openModalTrigger, handleOpenModal]); // 保存数据 const handleSave = async (): Promise => { @@ -160,7 +182,7 @@ export const ReviewsPanel: React.FC = () => { }); if (response.ok) { - logger.info('ReviewsPanel', `${editingItem ? '更新' : '创建'}成功`, { + logger.info('EventPanel', `${editingItem ? '更新' : '创建'}${label}成功`, { itemId: editingItem?.id, title: formData.title, }); @@ -175,7 +197,7 @@ export const ReviewsPanel: React.FC = () => { throw new Error('保存失败'); } } catch (error) { - logger.error('ReviewsPanel', 'handleSave', error, { + logger.error('EventPanel', 'handleSave', error, { itemId: editingItem?.id, title: formData?.title }); @@ -201,7 +223,7 @@ export const ReviewsPanel: React.FC = () => { }); if (response.ok) { - logger.info('ReviewsPanel', '删除成功', { itemId: id }); + logger.info('EventPanel', `删除${label}成功`, { itemId: id }); toast({ title: '删除成功', status: 'success', @@ -210,7 +232,7 @@ export const ReviewsPanel: React.FC = () => { loadAllData(); } } catch (error) { - logger.error('ReviewsPanel', 'handleDelete', error, { itemId: id }); + logger.error('EventPanel', 'handleDelete', error, { itemId: id }); toast({ title: '删除失败', status: 'error', @@ -270,7 +292,7 @@ export const ReviewsPanel: React.FC = () => { - + {item.title} @@ -294,7 +316,7 @@ export const ReviewsPanel: React.FC = () => { size="sm" variant="ghost" onClick={() => handleOpenModal(item)} - aria-label="编辑复盘" + aria-label={`编辑${label}`} /> } @@ -302,7 +324,7 @@ export const ReviewsPanel: React.FC = () => { variant="ghost" colorScheme="red" onClick={() => handleDelete(item.id)} - aria-label="删除复盘" + aria-label={`删除${label}`} /> @@ -327,7 +349,7 @@ export const ReviewsPanel: React.FC = () => { {item.tags && item.tags.length > 0 && ( <> {item.tags.map((tag, idx) => ( - + {tag} @@ -346,18 +368,18 @@ export const ReviewsPanel: React.FC = () => { {loading ? (
- +
- ) : reviews.length === 0 ? ( + ) : events.length === 0 ? (
- 暂无投资复盘 + 暂无投资{label}
) : ( - {reviews.map(renderCard)} + {events.map(renderCard)} )}
@@ -368,7 +390,7 @@ export const ReviewsPanel: React.FC = () => { - {editingItem ? '编辑' : '新建'}投资复盘 + {editingItem ? '编辑' : '新建'}投资{label} @@ -392,7 +414,7 @@ export const ReviewsPanel: React.FC = () => { setFormData({ ...formData, title: e.target.value })} - placeholder="例如:本周操作复盘" + placeholder={type === 'plan' ? '例如:布局新能源板块' : '例如:本周操作复盘'} /> @@ -401,7 +423,7 @@ export const ReviewsPanel: React.FC = () => {