事件中心的涨停原因里面和事件相关

This commit is contained in:
2026-01-10 18:44:58 +08:00
parent 654c6cff04
commit 4d077adcf2
4 changed files with 389 additions and 316 deletions

View File

@@ -2,7 +2,7 @@
* RelatedEventCard - 关联事件卡片组件 * RelatedEventCard - 关联事件卡片组件
* 在板块卡片内显示涨停归因的关联事件 * 在板块卡片内显示涨停归因的关联事件
*/ */
import React, { memo } from 'react'; import React, { memo } from "react";
import { import {
Box, Box,
HStack, HStack,
@@ -12,10 +12,10 @@ import {
Icon, Icon,
Progress, Progress,
Tooltip, Tooltip,
} from '@chakra-ui/react'; } from "@chakra-ui/react";
import { Newspaper, TrendingUp, ExternalLink } from 'lucide-react'; import { Newspaper, TrendingUp, ExternalLink } from "lucide-react";
import type { RelatedEvent } from '@/types/limitAnalyse'; import type { RelatedEvent } from "@/types/limitAnalyse";
import { textColors, bgColors } from '@/constants/limitAnalyseTheme'; import { textColors, bgColors } from "@/constants/limitAnalyseTheme";
interface RelatedEventCardProps { interface RelatedEventCardProps {
/** 事件数据 */ /** 事件数据 */
@@ -30,210 +30,218 @@ interface RelatedEventCardProps {
* 根据相关度分数获取颜色 * 根据相关度分数获取颜色
*/ */
const getRelevanceColor = (score: number): string => { const getRelevanceColor = (score: number): string => {
if (score >= 80) return '#10B981'; // 高相关 - 绿色 if (score >= 80) return "#10B981"; // 高相关 - 绿色
if (score >= 60) return '#F59E0B'; // 中相关 - 橙色 if (score >= 60) return "#F59E0B"; // 中相关 - 橙色
return '#6B7280'; // 低相关 - 灰色 return "#6B7280"; // 低相关 - 灰色
}; };
/** /**
* 根据相关度分数获取标签 * 根据相关度分数获取标签
*/ */
const getRelevanceLabel = (score: number): string => { const getRelevanceLabel = (score: number): string => {
if (score >= 80) return '高度相关'; if (score >= 80) return "高度相关";
if (score >= 60) return '中度相关'; if (score >= 60) return "中度相关";
return '参考'; return "参考";
}; };
/** /**
* RelatedEventCard 组件 * RelatedEventCard 组件
*/ */
const RelatedEventCard: React.FC<RelatedEventCardProps> = memo(({ const RelatedEventCard: React.FC<RelatedEventCardProps> = memo(
event, ({ event, compact = false, onClick }) => {
compact = false, const relevanceColor = getRelevanceColor(event.relevance_score || 0);
onClick const relevanceLabel = getRelevanceLabel(event.relevance_score || 0);
}) => {
const relevanceColor = getRelevanceColor(event.relevance_score || 0);
const relevanceLabel = getRelevanceLabel(event.relevance_score || 0);
const handleClick = () => { const handleClick = () => {
onClick?.(event); onClick?.(event);
}; };
// 紧凑模式(板块卡片内摘要) // 紧凑模式(板块卡片内摘要)
if (compact) { if (compact) {
return (
<Box
p={2}
bg="rgba(96, 165, 250, 0.08)"
borderRadius="md"
cursor={onClick ? "pointer" : "default"}
onClick={handleClick}
_hover={onClick ? { bg: "rgba(96, 165, 250, 0.15)" } : undefined}
transition="background 0.2s"
>
<HStack spacing={2} align="start">
<Icon
as={Newspaper}
boxSize={3.5}
color="#60A5FA"
mt={0.5}
flexShrink={0}
/>
<VStack align="start" spacing={0.5} flex={1} minW={0}>
<Text
fontSize="xs"
color={textColors.secondary}
noOfLines={1}
fontWeight="500"
>
{event.title}
</Text>
<HStack spacing={2}>
<Badge
size="xs"
bg={`${relevanceColor}20`}
color={relevanceColor}
fontSize="10px"
px={1.5}
borderRadius="sm"
>
{relevanceLabel}
</Badge>
{event.match_score && event.match_score > 1 && (
<Text fontSize="10px" color={textColors.muted}>
{event.match_score}
</Text>
)}
</HStack>
</VStack>
</HStack>
</Box>
);
}
// 完整模式(弹窗列表)
return ( return (
<Box <Box
p={2} p={4}
bg="rgba(96, 165, 250, 0.08)" bg={bgColors.item}
borderRadius="md" borderRadius="12px"
cursor={onClick ? 'pointer' : 'default'} border="1px solid rgba(255, 255, 255, 0.06)"
cursor={onClick ? "pointer" : "default"}
onClick={handleClick} onClick={handleClick}
_hover={onClick ? { bg: 'rgba(96, 165, 250, 0.15)' } : undefined} _hover={
transition="background 0.2s" onClick
? {
bg: bgColors.hover,
borderColor: "rgba(96, 165, 250, 0.3)",
transform: "translateY(-1px)",
}
: undefined
}
transition="all 0.2s"
> >
<HStack spacing={2} align="start"> <VStack align="stretch" spacing={3}>
<Icon as={Newspaper} boxSize={3.5} color="#60A5FA" mt={0.5} flexShrink={0} /> {/* 标题和跳转图标 */}
<VStack align="start" spacing={0.5} flex={1} minW={0}> <HStack justify="space-between" align="start">
<Text <HStack spacing={2} flex={1}>
fontSize="xs" <Icon as={Newspaper} boxSize={4} color="#60A5FA" />
color={textColors.secondary} <Text
noOfLines={1} fontSize="sm"
fontWeight="500" fontWeight="600"
> color={textColors.primary}
{event.title} noOfLines={2}
</Text>
<HStack spacing={2}>
<Badge
size="xs"
bg={`${relevanceColor}20`}
color={relevanceColor}
fontSize="10px"
px={1.5}
borderRadius="sm"
> >
{relevanceLabel} {event.title}
</Badge> </Text>
{event.match_score && event.match_score > 1 && (
<Text fontSize="10px" color={textColors.muted}>
{event.match_score}
</Text>
)}
</HStack> </HStack>
</VStack> {onClick && (
</HStack> <Icon
as={ExternalLink}
boxSize={4}
color={textColors.muted}
_hover={{ color: "#60A5FA" }}
/>
)}
</HStack>
{/* 相关度分数 */}
<HStack spacing={3}>
<HStack spacing={1.5}>
<Icon as={TrendingUp} boxSize={3.5} color={relevanceColor} />
<Text fontSize="xs" color={textColors.muted}>
</Text>
</HStack>
<Box flex={1}>
<Progress
value={event.relevance_score || 0}
size="xs"
borderRadius="full"
bg="rgba(255, 255, 255, 0.1)"
sx={{
"& > div": {
background: `linear-gradient(90deg, ${relevanceColor}80, ${relevanceColor})`,
},
}}
/>
</Box>
<Badge
bg={`${relevanceColor}20`}
color={relevanceColor}
fontSize="xs"
px={2}
borderRadius="md"
>
{event.relevance_score || 0}
</Badge>
</HStack>
{/* 匹配的概念 */}
{event.matched_concepts && event.matched_concepts.length > 0 && (
<Box>
<Text fontSize="xs" color={textColors.muted} mb={1.5}>
</Text>
<HStack spacing={1.5} flexWrap="wrap">
{event.matched_concepts.slice(0, 5).map((concept, idx) => (
<Badge
key={idx}
size="sm"
bg="rgba(139, 92, 246, 0.15)"
color="#A78BFA"
fontSize="10px"
px={2}
py={0.5}
borderRadius="md"
>
{concept}
</Badge>
))}
{event.matched_concepts.length > 5 && (
<Badge
size="sm"
bg="rgba(255, 255, 255, 0.1)"
color={textColors.muted}
fontSize="10px"
px={2}
py={0.5}
borderRadius="md"
>
+{event.matched_concepts.length - 5}
</Badge>
)}
</HStack>
</Box>
)}
{/* 相关原因 */}
{event.relevance_reason && (
<Tooltip label={event.relevance_reason} placement="top" hasArrow>
<Text
fontSize="xs"
color={textColors.muted}
noOfLines={2}
lineHeight="1.5"
cursor="help"
>
{event.relevance_reason}
</Text>
</Tooltip>
)}
</VStack>
</Box> </Box>
); );
} }
);
// 完整模式(弹窗列表) RelatedEventCard.displayName = "RelatedEventCard";
return (
<Box
p={4}
bg={bgColors.item}
borderRadius="12px"
border="1px solid rgba(255, 255, 255, 0.06)"
cursor={onClick ? 'pointer' : 'default'}
onClick={handleClick}
_hover={onClick ? {
bg: bgColors.hover,
borderColor: 'rgba(96, 165, 250, 0.3)',
transform: 'translateY(-1px)',
} : undefined}
transition="all 0.2s"
>
<VStack align="stretch" spacing={3}>
{/* 标题和跳转图标 */}
<HStack justify="space-between" align="start">
<HStack spacing={2} flex={1}>
<Icon as={Newspaper} boxSize={4} color="#60A5FA" />
<Text
fontSize="sm"
fontWeight="600"
color={textColors.primary}
noOfLines={2}
>
{event.title}
</Text>
</HStack>
{onClick && (
<Icon
as={ExternalLink}
boxSize={4}
color={textColors.muted}
_hover={{ color: '#60A5FA' }}
/>
)}
</HStack>
{/* 相关度分数 */}
<HStack spacing={3}>
<HStack spacing={1.5}>
<Icon as={TrendingUp} boxSize={3.5} color={relevanceColor} />
<Text fontSize="xs" color={textColors.muted}>
</Text>
</HStack>
<Box flex={1}>
<Progress
value={event.relevance_score || 0}
size="xs"
borderRadius="full"
bg="rgba(255, 255, 255, 0.1)"
sx={{
'& > div': {
background: `linear-gradient(90deg, ${relevanceColor}80, ${relevanceColor})`,
},
}}
/>
</Box>
<Badge
bg={`${relevanceColor}20`}
color={relevanceColor}
fontSize="xs"
px={2}
borderRadius="md"
>
{event.relevance_score || 0}
</Badge>
</HStack>
{/* 匹配的概念 */}
{event.matched_concepts && event.matched_concepts.length > 0 && (
<Box>
<Text fontSize="xs" color={textColors.muted} mb={1.5}>
</Text>
<HStack spacing={1.5} flexWrap="wrap">
{event.matched_concepts.slice(0, 5).map((concept, idx) => (
<Badge
key={idx}
size="sm"
bg="rgba(139, 92, 246, 0.15)"
color="#A78BFA"
fontSize="10px"
px={2}
py={0.5}
borderRadius="md"
>
{concept}
</Badge>
))}
{event.matched_concepts.length > 5 && (
<Badge
size="sm"
bg="rgba(255, 255, 255, 0.1)"
color={textColors.muted}
fontSize="10px"
px={2}
py={0.5}
borderRadius="md"
>
+{event.matched_concepts.length - 5}
</Badge>
)}
</HStack>
</Box>
)}
{/* 相关原因 */}
{event.relevance_reason && (
<Tooltip label={event.relevance_reason} placement="top" hasArrow>
<Text
fontSize="xs"
color={textColors.muted}
noOfLines={2}
lineHeight="1.5"
cursor="help"
>
{event.relevance_reason}
</Text>
</Tooltip>
)}
</VStack>
</Box>
);
});
RelatedEventCard.displayName = 'RelatedEventCard';
export default RelatedEventCard; export default RelatedEventCard;

View File

@@ -2,7 +2,7 @@
* RelatedEventsModal - 关联事件弹窗 * RelatedEventsModal - 关联事件弹窗
* 显示板块完整的关联事件列表 * 显示板块完整的关联事件列表
*/ */
import React, { memo, useCallback } from 'react'; import React, { memo, useCallback } from "react";
import { import {
Modal, Modal,
ModalOverlay, ModalOverlay,
@@ -17,13 +17,18 @@ import {
Icon, Icon,
Box, Box,
Divider, Divider,
} from '@chakra-ui/react'; } from "@chakra-ui/react";
import { Newspaper, TrendingUp, Layers } from 'lucide-react'; import { Newspaper, TrendingUp, Layers } from "lucide-react";
import { useNavigate } from 'react-router-dom'; import { useNavigate } from "react-router-dom";
import type { RelatedEvent } from '@/types/limitAnalyse'; import type { RelatedEvent } from "@/types/limitAnalyse";
import { textColors, bgColors, borderColors, goldColors } from '@/constants/limitAnalyseTheme'; import {
import { scrollbarStyles } from '@/styles/limitAnalyseStyles'; textColors,
import RelatedEventCard from './RelatedEventCard'; bgColors,
borderColors,
goldColors,
} from "@/constants/limitAnalyseTheme";
import { scrollbarStyles } from "@/styles/limitAnalyseStyles";
import RelatedEventCard from "./RelatedEventCard";
interface RelatedEventsModalProps { interface RelatedEventsModalProps {
/** 是否打开 */ /** 是否打开 */
@@ -41,110 +46,128 @@ interface RelatedEventsModalProps {
/** /**
* RelatedEventsModal 组件 * RelatedEventsModal 组件
*/ */
const RelatedEventsModal: React.FC<RelatedEventsModalProps> = memo(({ const RelatedEventsModal: React.FC<RelatedEventsModalProps> = memo(
isOpen, ({ isOpen, onClose, sectorName, events, limitUpCount = 0 }) => {
onClose, const navigate = useNavigate();
sectorName,
events,
limitUpCount = 0,
}) => {
const navigate = useNavigate();
// 点击事件跳转到事件详情 // 点击事件跳转到事件详情
const handleEventClick = useCallback((event: RelatedEvent) => { const handleEventClick = useCallback(
onClose(); (event: RelatedEvent) => {
navigate(`/community?event_id=${event.event_id}`); onClose();
}, [navigate, onClose]); navigate(`/community?event_id=${event.event_id}`);
},
[navigate, onClose]
);
// 按相关度排序 // 按相关度排序
const sortedEvents = [...events].sort( const sortedEvents = [...events].sort(
(a, b) => (b.relevance_score || 0) - (a.relevance_score || 0) (a, b) => (b.relevance_score || 0) - (a.relevance_score || 0)
); );
// 高相关事件数量 // 高相关事件数量
const highRelevanceCount = events.filter(e => (e.relevance_score || 0) >= 80).length; const highRelevanceCount = events.filter(
(e) => (e.relevance_score || 0) >= 80
).length;
return ( return (
<Modal <Modal
isOpen={isOpen} isOpen={isOpen}
onClose={onClose} onClose={onClose}
size="xl" size="xl"
isCentered isCentered
scrollBehavior="inside" scrollBehavior="inside"
>
<ModalOverlay bg="blackAlpha.700" backdropFilter="blur(10px)" />
<ModalContent
bg={bgColors.card}
border={`1px solid ${borderColors.gold}`}
borderRadius="20px"
maxH="80vh"
> >
{/* 头部 */} <ModalOverlay bg="blackAlpha.700" backdropFilter="blur(10px)" />
<ModalHeader pb={2}> <ModalContent
<VStack align="start" spacing={2}> bg={bgColors.card}
<HStack spacing={3}> border={`1px solid ${borderColors.gold}`}
<Icon as={Layers} boxSize={5} color={goldColors.primary} /> borderRadius="20px"
<Text fontSize="lg" fontWeight="bold" color={textColors.primary}> maxH="80vh"
{sectorName} - >
</Text> {/* 头部 */}
</HStack> <ModalHeader pb={2}>
<HStack spacing={4}> <VStack align="start" spacing={2}>
<HStack spacing={1.5}> <HStack spacing={3}>
<Icon as={TrendingUp} boxSize={4} color="#EF4444" /> <Icon as={Layers} boxSize={5} color={goldColors.primary} />
<Text fontSize="sm" color={textColors.secondary}> <Text
<Text as="span" color="#EF4444" fontWeight="bold">{limitUpCount}</Text> fontSize="lg"
</Text> fontWeight="bold"
</HStack> color={textColors.primary}
<HStack spacing={1.5}>
<Icon as={Newspaper} boxSize={4} color="#60A5FA" />
<Text fontSize="sm" color={textColors.secondary}>
<Text as="span" color="#60A5FA" fontWeight="bold">{events.length}</Text>
</Text>
</HStack>
{highRelevanceCount > 0 && (
<Badge
bg="rgba(16, 185, 129, 0.15)"
color="#10B981"
fontSize="xs"
px={2}
borderRadius="md"
> >
{highRelevanceCount} {sectorName} -
</Badge> </Text>
)} </HStack>
</HStack> <HStack spacing={4}>
</VStack> <HStack spacing={1.5}>
</ModalHeader> <Icon as={TrendingUp} boxSize={4} color="#EF4444" />
<Text fontSize="sm" color={textColors.secondary}>
<ModalCloseButton color={textColors.muted} /> {" "}
<Text as="span" color="#EF4444" fontWeight="bold">
<Divider borderColor="rgba(255, 255, 255, 0.1)" /> {limitUpCount}
</Text>{" "}
{/* 事件列表 */}
<ModalBody py={4} sx={scrollbarStyles}> </Text>
{sortedEvents.length === 0 ? ( </HStack>
<Box textAlign="center" py={10}> <HStack spacing={1.5}>
<Icon as={Newspaper} boxSize={10} color={textColors.muted} mb={3} /> <Icon as={Newspaper} boxSize={4} color="#60A5FA" />
<Text color={textColors.muted}></Text> <Text fontSize="sm" color={textColors.secondary}>
</Box> {" "}
) : ( <Text as="span" color="#60A5FA" fontWeight="bold">
<VStack spacing={3} align="stretch"> {events.length}
{sortedEvents.map((event, index) => ( </Text>{" "}
<RelatedEventCard
key={event.event_id || index} </Text>
event={event} </HStack>
compact={false} {highRelevanceCount > 0 && (
onClick={handleEventClick} <Badge
/> bg="rgba(16, 185, 129, 0.15)"
))} color="#10B981"
fontSize="xs"
px={2}
borderRadius="md"
>
{highRelevanceCount}
</Badge>
)}
</HStack>
</VStack> </VStack>
)} </ModalHeader>
</ModalBody>
</ModalContent>
</Modal>
);
});
RelatedEventsModal.displayName = 'RelatedEventsModal'; <ModalCloseButton color={textColors.muted} />
<Divider borderColor="rgba(255, 255, 255, 0.1)" />
{/* 事件列表 */}
<ModalBody py={4} sx={scrollbarStyles}>
{sortedEvents.length === 0 ? (
<Box textAlign="center" py={10}>
<Icon
as={Newspaper}
boxSize={10}
color={textColors.muted}
mb={3}
/>
<Text color={textColors.muted}></Text>
</Box>
) : (
<VStack spacing={3} align="stretch">
{sortedEvents.map((event, index) => (
<RelatedEventCard
key={event.event_id || index}
event={event}
compact={false}
onClick={handleEventClick}
/>
))}
</VStack>
)}
</ModalBody>
</ModalContent>
</Modal>
);
}
);
RelatedEventsModal.displayName = "RelatedEventsModal";
export default RelatedEventsModal; export default RelatedEventsModal;

View File

@@ -1,5 +1,5 @@
/** /**
* RelatedEvents 组件导出 * RelatedEvents 组件导出
*/ */
export { default as RelatedEventCard } from './RelatedEventCard'; export { default as RelatedEventCard } from "./RelatedEventCard";
export { default as RelatedEventsModal } from './RelatedEventsModal'; export { default as RelatedEventsModal } from "./RelatedEventsModal";

View File

@@ -2,7 +2,7 @@
* 单个板块项组件 * 单个板块项组件
* 支持 accordion 和 card 两种显示模式 * 支持 accordion 和 card 两种显示模式
*/ */
import React, { memo, useCallback, useMemo, useState } from "react"; import React, { memo, useCallback, useMemo } from "react";
import { import {
Box, Box,
VStack, VStack,
@@ -17,7 +17,6 @@ import {
WrapItem, WrapItem,
Tag, Tag,
TagLabel, TagLabel,
Accordion,
AccordionItem, AccordionItem,
AccordionButton, AccordionButton,
AccordionPanel, AccordionPanel,
@@ -26,15 +25,22 @@ import {
useDisclosure, useDisclosure,
Divider, Divider,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { Star, Zap, ChevronDown, ChevronUp, Sparkles, Newspaper, ChevronRight } from "lucide-react"; import {
import type { SectorData, LimitUpStock } from "@/types/limitAnalyse"; Star,
import { formatLimitUpTime, getSectorColor } from "@/utils/limitAnalyseUtils"; Zap,
ChevronDown,
ChevronUp,
Sparkles,
Newspaper,
ChevronRight,
} from "lucide-react";
import type { SectorData } from "@/types/limitAnalyse";
import { formatLimitUpTime } from "@/utils/limitAnalyseUtils";
import { import {
goldColors, goldColors,
textColors, textColors,
bgColors, bgColors,
marketColors, marketColors,
SECTOR_COLORS,
} from "@/constants/limitAnalyseTheme"; } from "@/constants/limitAnalyseTheme";
import StockListItem from "./StockListItem"; import StockListItem from "./StockListItem";
import { RelatedEventCard, RelatedEventsModal } from "./RelatedEvents"; import { RelatedEventCard, RelatedEventsModal } from "./RelatedEvents";
@@ -112,11 +118,13 @@ const SectorItem = memo<SectorItemProps>(
const sectorColor = getSectorSingleColor(sector); const sectorColor = getSectorSingleColor(sector);
// 关联事件弹窗控制 // 关联事件弹窗控制
const { isOpen: isEventsModalOpen, onOpen: onOpenEventsModal, onClose: onCloseEventsModal } = useDisclosure(); const {
isOpen: isEventsModalOpen,
onOpen: onOpenEventsModal,
onClose: onCloseEventsModal,
} = useDisclosure();
const firstLimitTime = leadingStock const firstLimitTime = leadingStock ? formatLimitUpTime(leadingStock) : "-";
? formatLimitUpTime(leadingStock)
: "-";
// 按时间排序的股票 // 按时间排序的股票
const sortedStocks = useMemo(() => { const sortedStocks = useMemo(() => {
@@ -133,10 +141,13 @@ const SectorItem = memo<SectorItemProps>(
}, [relatedEvents]); }, [relatedEvents]);
// 点击查看更多事件 // 点击查看更多事件
const handleViewMoreEvents = useCallback((e: React.MouseEvent) => { const handleViewMoreEvents = useCallback(
e.stopPropagation(); (e: React.MouseEvent) => {
onOpenEventsModal(); e.stopPropagation();
}, [onOpenEventsModal]); onOpenEventsModal();
},
[onOpenEventsModal]
);
// Card 模式 // Card 模式
if (displayMode === "card") { if (displayMode === "card") {
@@ -185,11 +196,19 @@ const SectorItem = memo<SectorItemProps>(
<VStack align="start" spacing={0} flex={1}> <VStack align="start" spacing={0} flex={1}>
<HStack spacing={2}> <HStack spacing={2}>
<Text fontWeight="bold" fontSize="md" color={textColors.primary}> <Text
fontWeight="bold"
fontSize="md"
color={textColors.primary}
>
{sector} {sector}
</Text> </Text>
{sector === "公告" && ( {sector === "公告" && (
<Icon as={Sparkles} boxSize={4} color={goldColors.primary} /> <Icon
as={Sparkles}
boxSize={4}
color={goldColors.primary}
/>
)} )}
</HStack> </HStack>
<HStack spacing={3} fontSize="xs" color={textColors.muted}> <HStack spacing={3} fontSize="xs" color={textColors.muted}>
@@ -214,7 +233,11 @@ const SectorItem = memo<SectorItemProps>(
<HStack spacing={4}> <HStack spacing={4}>
{leadingStock && ( {leadingStock && (
<HStack spacing={2}> <HStack spacing={2}>
<Text color={goldColors.light} fontWeight="500" fontSize="sm"> <Text
color={goldColors.light}
fontWeight="500"
fontSize="sm"
>
{leadingStock.sname} {leadingStock.sname}
</Text> </Text>
<Badge <Badge
@@ -270,14 +293,25 @@ const SectorItem = memo<SectorItemProps>(
{/* Body - 展开的个股明细 */} {/* Body - 展开的个股明细 */}
<Collapse in={isExpanded} animateOpacity> <Collapse in={isExpanded} animateOpacity>
<Box borderTop="1px solid rgba(255, 255, 255, 0.06)" bg="rgba(0, 0, 0, 0.2)"> <Box
borderTop="1px solid rgba(255, 255, 255, 0.06)"
bg="rgba(0, 0, 0, 0.2)"
>
{/* 关联事件区域 */} {/* 关联事件区域 */}
{relatedEvents.length > 0 && ( {relatedEvents.length > 0 && (
<Box px={4} py={3} borderBottom="1px solid rgba(255, 255, 255, 0.06)"> <Box
px={4}
py={3}
borderBottom="1px solid rgba(255, 255, 255, 0.06)"
>
<HStack justify="space-between" mb={2}> <HStack justify="space-between" mb={2}>
<HStack spacing={2}> <HStack spacing={2}>
<Icon as={Newspaper} boxSize={4} color="#60A5FA" /> <Icon as={Newspaper} boxSize={4} color="#60A5FA" />
<Text fontSize="sm" fontWeight="600" color={textColors.secondary}> <Text
fontSize="sm"
fontWeight="600"
color={textColors.secondary}
>
</Text> </Text>
<Badge <Badge
@@ -371,7 +405,11 @@ const SectorItem = memo<SectorItemProps>(
<VStack align="start" spacing={0} flex={1}> <VStack align="start" spacing={0} flex={1}>
<HStack spacing={2}> <HStack spacing={2}>
<Text fontWeight="bold" fontSize="md" color={textColors.primary}> <Text
fontWeight="bold"
fontSize="md"
color={textColors.primary}
>
{sector} {sector}
</Text> </Text>
{sector === "公告" && ( {sector === "公告" && (
@@ -399,7 +437,11 @@ const SectorItem = memo<SectorItemProps>(
<HStack justify="space-between" mb={2}> <HStack justify="space-between" mb={2}>
<HStack spacing={2}> <HStack spacing={2}>
<Icon as={Newspaper} boxSize={4} color="#60A5FA" /> <Icon as={Newspaper} boxSize={4} color="#60A5FA" />
<Text fontSize="sm" fontWeight="600" color={textColors.secondary}> <Text
fontSize="sm"
fontWeight="600"
color={textColors.secondary}
>
</Text> </Text>
<Badge <Badge