feat: 添加投资日历mock数据
投资日历提取计划列表卡片组件
This commit is contained in:
@@ -537,6 +537,31 @@ export const mockFutureEvents = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const mockCalendarEvents = [
|
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,
|
id: 401,
|
||||||
user_id: 1,
|
user_id: 1,
|
||||||
|
|||||||
@@ -6,31 +6,20 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
|
||||||
Badge,
|
|
||||||
Flex,
|
|
||||||
Modal,
|
Modal,
|
||||||
ModalOverlay,
|
ModalOverlay,
|
||||||
ModalContent,
|
ModalContent,
|
||||||
ModalHeader,
|
ModalHeader,
|
||||||
ModalFooter,
|
|
||||||
ModalBody,
|
ModalBody,
|
||||||
ModalCloseButton,
|
ModalCloseButton,
|
||||||
useDisclosure,
|
useDisclosure,
|
||||||
VStack,
|
VStack,
|
||||||
HStack,
|
|
||||||
Text,
|
Text,
|
||||||
Spinner,
|
Spinner,
|
||||||
Center,
|
Center,
|
||||||
Icon,
|
Icon,
|
||||||
Tag,
|
|
||||||
TagLabel,
|
|
||||||
TagLeftIcon,
|
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import {
|
import { FiCalendar } from 'react-icons/fi';
|
||||||
FiStar,
|
|
||||||
FiTrendingUp,
|
|
||||||
} from 'react-icons/fi';
|
|
||||||
import FullCalendar from '@fullcalendar/react';
|
import FullCalendar from '@fullcalendar/react';
|
||||||
import dayGridPlugin from '@fullcalendar/daygrid';
|
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||||
import interactionPlugin from '@fullcalendar/interaction';
|
import interactionPlugin from '@fullcalendar/interaction';
|
||||||
@@ -40,6 +29,7 @@ import dayjs, { Dayjs } from 'dayjs';
|
|||||||
import 'dayjs/locale/zh-cn';
|
import 'dayjs/locale/zh-cn';
|
||||||
|
|
||||||
import { usePlanningData } from './PlanningContext';
|
import { usePlanningData } from './PlanningContext';
|
||||||
|
import { EventDetailCard } from './EventDetailCard';
|
||||||
import type { InvestmentEvent } from '@/types';
|
import type { InvestmentEvent } from '@/types';
|
||||||
|
|
||||||
dayjs.locale('zh-cn');
|
dayjs.locale('zh-cn');
|
||||||
@@ -161,68 +151,27 @@ export const CalendarPanel: React.FC = () => {
|
|||||||
<ModalBody>
|
<ModalBody>
|
||||||
{selectedDateEvents.length === 0 ? (
|
{selectedDateEvents.length === 0 ? (
|
||||||
<Center py={8}>
|
<Center py={8}>
|
||||||
<Text color={secondaryText}>当天没有事件</Text>
|
<VStack spacing={3}>
|
||||||
|
<Icon as={FiCalendar} boxSize={10} color="gray.300" />
|
||||||
|
<Text color={secondaryText}>当天暂无事件</Text>
|
||||||
|
<Text fontSize="sm" color={secondaryText}>
|
||||||
|
可在「计划」或「复盘」添加,或关注投资日历中的未来事件
|
||||||
|
</Text>
|
||||||
|
</VStack>
|
||||||
</Center>
|
</Center>
|
||||||
) : (
|
) : (
|
||||||
<VStack align="stretch" spacing={4}>
|
<VStack align="stretch" spacing={4}>
|
||||||
{selectedDateEvents.map((event, idx) => (
|
{selectedDateEvents.map((event, idx) => (
|
||||||
<Box
|
<EventDetailCard
|
||||||
key={idx}
|
key={idx}
|
||||||
p={4}
|
event={event}
|
||||||
borderRadius="md"
|
|
||||||
border="1px"
|
|
||||||
borderColor={borderColor}
|
borderColor={borderColor}
|
||||||
>
|
secondaryText={secondaryText}
|
||||||
<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.source === 'future' ? (
|
|
||||||
<Badge colorScheme="blue" variant="subtle">系统事件</Badge>
|
|
||||||
) : event.type === 'plan' ? (
|
|
||||||
<Badge colorScheme="purple" variant="subtle">我的计划</Badge>
|
|
||||||
) : (
|
|
||||||
<Badge colorScheme="green" variant="subtle">我的复盘</Badge>
|
|
||||||
)}
|
|
||||||
</HStack>
|
|
||||||
{event.importance && (
|
|
||||||
<HStack spacing={2}>
|
|
||||||
<Icon as={FiStar} color="yellow.500" />
|
|
||||||
<Text fontSize="sm" color={secondaryText}>
|
|
||||||
重要度: {event.importance}/5
|
|
||||||
</Text>
|
|
||||||
</HStack>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
{event.description && (
|
|
||||||
<Text fontSize="sm" color={secondaryText} mb={2}>
|
|
||||||
{event.description}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{event.stocks && event.stocks.length > 0 && (
|
|
||||||
<HStack spacing={2} flexWrap="wrap">
|
|
||||||
<Text fontSize="sm" color={secondaryText}>相关股票:</Text>
|
|
||||||
{event.stocks.map((stock, i) => (
|
|
||||||
<Tag key={i} size="sm" colorScheme="blue">
|
|
||||||
<TagLeftIcon as={FiTrendingUp} />
|
|
||||||
<TagLabel>{stock}</TagLabel>
|
|
||||||
</Tag>
|
|
||||||
))}
|
|
||||||
</HStack>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
))}
|
))}
|
||||||
</VStack>
|
</VStack>
|
||||||
)}
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
|
||||||
<Button onClick={onClose}>关闭</Button>
|
|
||||||
</ModalFooter>
|
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
</Modal>
|
</Modal>
|
||||||
)}
|
)}
|
||||||
|
|||||||
145
src/views/Dashboard/components/EventDetailCard.tsx
Normal file
145
src/views/Dashboard/components/EventDetailCard.tsx
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
/**
|
||||||
|
* EventDetailCard - 事件详情卡片组件
|
||||||
|
* 用于日历视图中展示单个事件的详细信息
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Badge,
|
||||||
|
Flex,
|
||||||
|
HStack,
|
||||||
|
Text,
|
||||||
|
Tag,
|
||||||
|
TagLabel,
|
||||||
|
TagLeftIcon,
|
||||||
|
Button,
|
||||||
|
useColorModeValue,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import {
|
||||||
|
FiTrendingUp,
|
||||||
|
FiChevronDown,
|
||||||
|
FiChevronUp,
|
||||||
|
} from 'react-icons/fi';
|
||||||
|
import type { InvestmentEvent } from '@/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventDetailCard Props
|
||||||
|
*/
|
||||||
|
export interface EventDetailCardProps {
|
||||||
|
/** 事件数据 */
|
||||||
|
event: InvestmentEvent;
|
||||||
|
/** 边框颜色 */
|
||||||
|
borderColor?: string;
|
||||||
|
/** 次要文字颜色 */
|
||||||
|
secondaryText?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大显示行数
|
||||||
|
*/
|
||||||
|
const MAX_LINES = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventDetailCard 组件
|
||||||
|
*/
|
||||||
|
export const EventDetailCard: React.FC<EventDetailCardProps> = ({
|
||||||
|
event,
|
||||||
|
borderColor: borderColorProp,
|
||||||
|
secondaryText: secondaryTextProp,
|
||||||
|
}) => {
|
||||||
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
|
const [isOverflow, setIsOverflow] = useState(false);
|
||||||
|
const descriptionRef = useRef<HTMLParagraphElement>(null);
|
||||||
|
|
||||||
|
// 默认颜色
|
||||||
|
const defaultBorderColor = useColorModeValue('gray.200', 'gray.600');
|
||||||
|
const defaultSecondaryText = useColorModeValue('gray.600', 'gray.400');
|
||||||
|
|
||||||
|
const borderColor = borderColorProp || defaultBorderColor;
|
||||||
|
const secondaryText = secondaryTextProp || defaultSecondaryText;
|
||||||
|
|
||||||
|
// 检测内容是否溢出
|
||||||
|
useEffect(() => {
|
||||||
|
const el = descriptionRef.current;
|
||||||
|
if (el) {
|
||||||
|
// 计算行高和最大高度
|
||||||
|
const lineHeight = parseInt(getComputedStyle(el).lineHeight) || 20;
|
||||||
|
const maxHeight = lineHeight * MAX_LINES;
|
||||||
|
setIsOverflow(el.scrollHeight > maxHeight + 5); // 5px 容差
|
||||||
|
}
|
||||||
|
}, [event.description]);
|
||||||
|
|
||||||
|
// 获取事件类型标签
|
||||||
|
const getEventBadge = () => {
|
||||||
|
if (event.source === 'future') {
|
||||||
|
return <Badge colorScheme="blue" variant="subtle">系统事件</Badge>;
|
||||||
|
} else if (event.type === 'plan') {
|
||||||
|
return <Badge colorScheme="purple" variant="subtle">我的计划</Badge>;
|
||||||
|
} else if (event.type === 'review') {
|
||||||
|
return <Badge colorScheme="green" variant="subtle">我的复盘</Badge>;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
p={4}
|
||||||
|
borderRadius="md"
|
||||||
|
border="1px"
|
||||||
|
borderColor={borderColor}
|
||||||
|
>
|
||||||
|
{/* 标题和标签 */}
|
||||||
|
<Flex justify="space-between" align="start" mb={2}>
|
||||||
|
<HStack flexWrap="wrap" flex={1}>
|
||||||
|
<Text fontWeight="bold" fontSize="lg">
|
||||||
|
{event.title}
|
||||||
|
</Text>
|
||||||
|
{getEventBadge()}
|
||||||
|
</HStack>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
{/* 描述内容 - 支持展开/收起 */}
|
||||||
|
{event.description && (
|
||||||
|
<Box mb={2}>
|
||||||
|
<Text
|
||||||
|
ref={descriptionRef}
|
||||||
|
fontSize="sm"
|
||||||
|
color={secondaryText}
|
||||||
|
noOfLines={isExpanded ? undefined : MAX_LINES}
|
||||||
|
whiteSpace="pre-wrap"
|
||||||
|
>
|
||||||
|
{event.description}
|
||||||
|
</Text>
|
||||||
|
{isOverflow && (
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant="link"
|
||||||
|
colorScheme="blue"
|
||||||
|
mt={1}
|
||||||
|
onClick={() => setIsExpanded(!isExpanded)}
|
||||||
|
rightIcon={isExpanded ? <FiChevronUp /> : <FiChevronDown />}
|
||||||
|
>
|
||||||
|
{isExpanded ? '收起' : '展开'}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 相关股票 */}
|
||||||
|
{event.stocks && event.stocks.length > 0 && (
|
||||||
|
<HStack spacing={2} flexWrap="wrap">
|
||||||
|
<Text fontSize="sm" color={secondaryText}>相关股票:</Text>
|
||||||
|
{event.stocks.map((stock, i) => (
|
||||||
|
<Tag key={i} size="sm" colorScheme="blue" mb={1}>
|
||||||
|
<TagLeftIcon as={FiTrendingUp} />
|
||||||
|
<TagLabel>{stock}</TagLabel>
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</HStack>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EventDetailCard;
|
||||||
Reference in New Issue
Block a user