update ui

This commit is contained in:
2025-11-13 22:21:59 +08:00
parent 7e0358ede4
commit c6062efb00
3 changed files with 207 additions and 235 deletions

View File

@@ -398,49 +398,73 @@ const [currentMode, setCurrentMode] = useState('vertical');
} }
}} }}
> >
{/* 标题和搜索部分 - 一行布局 */} {/* 标题和搜索部分 - 一体化单行布局 */}
<CardHeader <CardHeader
ref={cardHeaderRef} ref={cardHeaderRef}
position="relative" position="relative"
zIndex={1} zIndex={1}
pb={4}
> >
{/* 第一行:标题 + 通知开关 + 更新时间 */} {/* 一体化标题栏:左侧标题+badges | 中间筛选组件 | 右侧通知+时间 */}
<Flex justify="space-between" align="center" mb={4}> <Flex
<VStack align="start" spacing={1}> justify="space-between"
<Heading size="md"> align="center"
<HStack> gap={4}
bg={useColorModeValue('gray.50', 'gray.800')}
borderRadius="lg"
p={3}
borderWidth="1px"
borderColor={borderColor}
>
{/* 左侧:标题 + Badges */}
<HStack spacing={3} minW="200px" flexShrink={0}>
<Heading size="md" whiteSpace="nowrap">
<HStack spacing={2}>
<TimeIcon /> <TimeIcon />
<Text>实时要闻·动态追踪</Text> <Text>实时要闻</Text>
</HStack> </HStack>
</Heading> </Heading>
<HStack fontSize="sm" color="gray.500"> <HStack spacing={1}>
<Badge colorScheme="red">实时</Badge> <Badge colorScheme="red" fontSize="xs">实时</Badge>
<Badge colorScheme="green">盘中</Badge> <Badge colorScheme="green" fontSize="xs">盘中</Badge>
<Badge colorScheme="blue">快讯</Badge> <Badge colorScheme="blue" fontSize="xs">快讯</Badge>
</HStack> </HStack>
</VStack> </HStack>
<VStack align="end" spacing={2}> {/* 中间:筛选组件(占据剩余空间) */}
{/* 通知开关 */} <Box flex="1" minW={0}>
<CompactSearchBox
onSearch={onSearch}
onSearchFocus={onSearchFocus}
filters={filters}
mode={mode}
pageSize={pageSize}
trackingFunctions={trackingFunctions}
/>
</Box>
{/* 右侧:通知开关 + 更新时间 */}
<VStack align="end" spacing={1} minW="140px" flexShrink={0}>
{/* 通知开关 - 紧凑版 */}
<Tooltip <Tooltip
label={browserPermission === 'granted' label={browserPermission === 'granted'
? '浏览器通知已开启,新事件将实时推送' ? '浏览器通知已开启'
: '开启后可接收实时事件推送通知'} : '开启实时推送通知'}
placement="left" placement="left"
hasArrow hasArrow
> >
<HStack <HStack
spacing={2} spacing={2}
px={3} px={2}
py={2} py={1}
borderRadius="md" borderRadius="md"
bg={browserPermission === 'granted' bg={browserPermission === 'granted'
? useColorModeValue('green.50', 'green.900') ? useColorModeValue('green.50', 'green.900')
: useColorModeValue('gray.50', 'gray.700')} : useColorModeValue('gray.100', 'gray.700')}
borderWidth="1px" borderWidth="1px"
borderColor={browserPermission === 'granted' borderColor={browserPermission === 'granted'
? useColorModeValue('green.200', 'green.700') ? useColorModeValue('green.200', 'green.700')
: useColorModeValue('gray.200', 'gray.600')} : useColorModeValue('gray.300', 'gray.600')}
cursor="pointer" cursor="pointer"
_hover={{ _hover={{
borderColor: browserPermission === 'granted' borderColor: browserPermission === 'granted'
@@ -452,19 +476,19 @@ const [currentMode, setCurrentMode] = useState('vertical');
> >
<Icon <Icon
as={BellIcon} as={BellIcon}
boxSize={4} boxSize={3}
color={browserPermission === 'granted' color={browserPermission === 'granted'
? useColorModeValue('green.600', 'green.300') ? useColorModeValue('green.600', 'green.300')
: useColorModeValue('gray.500', 'gray.400')} : useColorModeValue('gray.500', 'gray.400')}
/> />
<Text <Text
fontSize="sm" fontSize="xs"
fontWeight="medium" fontWeight="medium"
color={browserPermission === 'granted' color={browserPermission === 'granted'
? useColorModeValue('green.700', 'green.200') ? useColorModeValue('green.700', 'green.200')
: useColorModeValue('gray.600', 'gray.300')} : useColorModeValue('gray.600', 'gray.300')}
> >
{browserPermission === 'granted' ? '通知已开启' : '开启通知'} {browserPermission === 'granted' ? '已开启' : '开启通知'}
</Text> </Text>
<Switch <Switch
size="sm" size="sm"
@@ -475,21 +499,12 @@ const [currentMode, setCurrentMode] = useState('vertical');
</HStack> </HStack>
</Tooltip> </Tooltip>
<Text fontSize="xs" color="gray.500"> {/* 更新时间 */}
最后更新: {lastUpdateTime?.toLocaleTimeString() || '未知'} <Text fontSize="xs" color="gray.500" whiteSpace="nowrap">
更新: {lastUpdateTime?.toLocaleTimeString() || '--'}
</Text> </Text>
</VStack> </VStack>
</Flex> </Flex>
{/* 第二行:搜索和筛选组件 */}
<CompactSearchBox
onSearch={onSearch}
onSearchFocus={onSearchFocus}
filters={filters}
mode={mode}
pageSize={pageSize}
trackingFunctions={trackingFunctions}
/>
</CardHeader> </CardHeader>
{/* 主体内容 */} {/* 主体内容 */}

View File

@@ -1,17 +1,15 @@
// src/views/Community/components/DynamicNewsCard/VerticalModeLayout.js // src/views/Community/components/DynamicNewsCard/VerticalModeLayout.js
// 纵向分栏模式布局组件 // 纵向分栏模式布局组件
import React, { useState, useEffect } from 'react'; import React, { useState } from 'react';
import { Box, IconButton, Tooltip, VStack, Flex, Center, Text } from '@chakra-ui/react'; import { Box, VStack, Flex, Center, Text } from '@chakra-ui/react';
import { ViewIcon, ViewOffIcon, InfoIcon } from '@chakra-ui/icons'; import { InfoIcon } from '@chakra-ui/icons';
import HorizontalDynamicNewsEventCard from '../EventCard/HorizontalDynamicNewsEventCard'; import HorizontalDynamicNewsEventCard from '../EventCard/HorizontalDynamicNewsEventCard';
import EventDetailScrollPanel from './EventDetailScrollPanel'; import EventDetailScrollPanel from './EventDetailScrollPanel';
/** /**
* 纵向分栏模式布局 * 纵向分栏模式布局
* 支持两种展示模式: * 固定布局:左侧事件列表 3fr | 右侧详情 7fr
* - detail默认左侧事件列表 1fr | 右侧详情 2fr
* - list左侧事件列表 7fr | 右侧详情 300px
* *
* @param {string} display - CSS display 属性(用于显示/隐藏组件) * @param {string} display - CSS display 属性(用于显示/隐藏组件)
* @param {Array} events - 当前页的事件列表(分页数据) * @param {Array} events - 当前页的事件列表(分页数据)
@@ -32,33 +30,12 @@ const VerticalModeLayout = ({
getTimelineBoxStyle, getTimelineBoxStyle,
borderColor, borderColor,
}) => { }) => {
// 布局模式状态:'detail' = 聚焦详情(默认),'list' = 聚焦列表 // 详情面板重置 key预留用于未来功能
const [layoutMode, setLayoutMode] = useState('detail'); const [detailPanelKey] = useState(0);
// 详情面板重置 key切换到 list 模式时改变,强制重新渲染 // 固定布局比例左侧更窄3右侧更宽7
const [detailPanelKey, setDetailPanelKey] = useState(0); const leftFlex = '3';
const rightFlex = '7';
// 监听事件选择 - 自动切换到详情模式
useEffect(() => {
if (selectedEvent) {
setLayoutMode('detail');
}
}, [selectedEvent]);
// 切换布局模式
const toggleLayoutMode = () => {
const newMode = layoutMode === 'detail' ? 'list' : 'detail';
setLayoutMode(newMode);
// 如果切换到 list 模式,重置详情面板(收起所有 CollapsibleSection
if (newMode === 'list') {
setDetailPanelKey(prev => prev + 1); // 改变 key强制重新渲染
}
};
// 根据模式计算 flex 比例
const leftFlex = layoutMode === 'detail' ? '4' : '6';
const rightFlex = layoutMode === 'detail' ? '6' : '4';
return ( return (
<Flex <Flex
@@ -111,7 +88,7 @@ const VerticalModeLayout = ({
onToggleFollow={onToggleFollow} onToggleFollow={onToggleFollow}
timelineStyle={getTimelineBoxStyle()} timelineStyle={getTimelineBoxStyle()}
borderColor={borderColor} borderColor={borderColor}
indicatorSize={layoutMode === 'detail' ? 'default' : 'comfortable'} indicatorSize="default"
layout="vertical" layout="vertical"
/> />
))} ))}
@@ -140,25 +117,6 @@ const VerticalModeLayout = ({
overflow="hidden" overflow="hidden"
h="100%" h="100%"
> >
{/* 布局切换按钮 */}
<Tooltip
label={layoutMode === 'detail' ? '展开事件列表' : '展开详情面板'}
placement="left"
>
<IconButton
position="absolute"
top={2}
right={2}
zIndex={9999}
size="md"
icon={layoutMode === 'detail' ? <ViewOffIcon /> : <ViewIcon />}
onClick={toggleLayoutMode}
aria-label="切换布局模式"
colorScheme="blue"
variant="solid"
/>
</Tooltip>
{/* 详情面板 */} {/* 详情面板 */}
<EventDetailScrollPanel <EventDetailScrollPanel
key={detailPanelKey} key={detailPanelKey}

View File

@@ -125,157 +125,156 @@ const StockListItem = ({
transition="all 0.2s" transition="all 0.2s"
> >
{/* 单行紧凑布局:名称+涨跌幅 | 分时图 | K线图 | 关联描述 */} {/* 单行紧凑布局:名称+涨跌幅 | 分时图 | K线图 | 关联描述 */}
<HStack spacing={3} align="center" flexWrap="wrap"> <HStack spacing={2} align="center" flexWrap="wrap">
{/* 左侧:股票代码 + 名称 + 涨跌幅(垂直排列) */} {/* 左侧:股票信息区 */}
<VStack <HStack spacing={2} minW="360px" maxW="380px" flexShrink={0}>
align="stretch" {/* 股票代码 + 名称 + 涨跌幅 */}
spacing={1} <VStack
minW="110px" align="stretch"
maxW="130px" spacing={1}
justify="center" minW="95px"
flexShrink={0} maxW="110px"
> justify="center"
<Tooltip flexShrink={0}
label="点击查看股票详情"
placement="top"
hasArrow
bg="blue.600"
color="white"
fontSize="xs"
> >
<VStack spacing={0} align="stretch"> <Tooltip
<Text label="点击查看股票详情"
fontSize="xs" placement="top"
color={codeColor} hasArrow
noOfLines={1} bg="blue.600"
cursor="pointer" color="white"
onClick={handleViewDetail} fontSize="xs"
_hover={{ textDecoration: 'underline' }}
>
{stock.stock_code}
</Text>
<Text
fontSize="sm"
fontWeight="bold"
color={nameColor}
noOfLines={1}
cursor="pointer"
onClick={handleViewDetail}
_hover={{ textDecoration: 'underline' }}
>
{stock.stock_name}
</Text>
</VStack>
</Tooltip>
<HStack spacing={1} align="center">
<Text
fontSize="lg"
fontWeight="bold"
color={getChangeColor(change)}
> >
{formatChange(change)} <VStack spacing={0} align="stretch">
<Text
fontSize="xs"
color={codeColor}
noOfLines={1}
cursor="pointer"
onClick={handleViewDetail}
_hover={{ textDecoration: 'underline' }}
>
{stock.stock_code}
</Text>
<Text
fontSize="xs"
fontWeight="bold"
color={nameColor}
noOfLines={1}
cursor="pointer"
onClick={handleViewDetail}
_hover={{ textDecoration: 'underline' }}
>
{stock.stock_name}
</Text>
</VStack>
</Tooltip>
<HStack spacing={1} align="center">
<Text
fontSize="md"
fontWeight="bold"
color={getChangeColor(change)}
>
{formatChange(change)}
</Text>
{onWatchlistToggle && (
<IconButton
size="xs"
variant={isInWatchlist ? 'solid' : 'ghost'}
colorScheme={isInWatchlist ? 'yellow' : 'gray'}
icon={<StarIcon />}
onClick={handleWatchlistClick}
aria-label={isInWatchlist ? '已关注' : '加自选'}
borderRadius="full"
/>
)}
</HStack>
</VStack>
{/* 分时图 - 更紧凑 */}
<VStack
w="115px"
borderWidth="1px"
borderColor={useColorModeValue('blue.100', 'blue.700')}
borderRadius="md"
px={1.5}
py={1}
bg={useColorModeValue('blue.50', 'blue.900')}
onClick={(e) => {
e.stopPropagation();
setIsModalOpen(true);
}}
cursor="pointer"
flexShrink={0}
align="stretch"
spacing={0}
h="fit-content"
_hover={{
borderColor: useColorModeValue('blue.300', 'blue.500'),
boxShadow: 'md',
transform: 'translateY(-1px)'
}}
transition="all 0.2s"
>
<Text
fontSize="10px"
color={useColorModeValue('blue.700', 'blue.200')}
fontWeight="semibold"
whiteSpace="nowrap"
mb={0.5}
>
📈 分时
</Text> </Text>
{onWatchlistToggle && ( <Box h="32px">
<IconButton <MiniTimelineChart
size="xs" stockCode={stock.stock_code}
variant={isInWatchlist ? 'solid' : 'ghost'} eventTime={eventTime}
colorScheme={isInWatchlist ? 'yellow' : 'gray'}
icon={<StarIcon />}
onClick={handleWatchlistClick}
aria-label={isInWatchlist ? '已关注' : '加自选'}
borderRadius="full"
/> />
)} </Box>
</HStack> </VStack>
</VStack>
{/* 分时图 - 紧凑高度 */} {/* K线图 - 紧凑 */}
<VStack <VStack
minW="150px" w="115px"
maxW="180px" borderWidth="1px"
flex="1" borderColor={useColorModeValue('purple.100', 'purple.700')}
borderWidth="1px" borderRadius="md"
borderColor={useColorModeValue('blue.100', 'blue.700')} px={1.5}
borderRadius="md" py={1}
px={2} bg={useColorModeValue('purple.50', 'purple.900')}
py={1} onClick={(e) => {
bg={useColorModeValue('blue.50', 'blue.900')} e.stopPropagation();
onClick={(e) => { setIsModalOpen(true);
e.stopPropagation(); }}
setIsModalOpen(true); cursor="pointer"
}} flexShrink={0}
cursor="pointer" align="stretch"
flexShrink={1} spacing={0}
align="stretch" h="fit-content"
spacing={0} _hover={{
h="fit-content" borderColor: useColorModeValue('purple.300', 'purple.500'),
_hover={{ boxShadow: 'md',
borderColor: useColorModeValue('blue.300', 'blue.500'), transform: 'translateY(-1px)'
boxShadow: 'md', }}
transform: 'translateY(-1px)' transition="all 0.2s"
}}
transition="all 0.2s"
>
<Text
fontSize="xs"
color={useColorModeValue('blue.700', 'blue.200')}
fontWeight="semibold"
whiteSpace="nowrap"
mb={0.5}
> >
📈 分时 <Text
</Text> fontSize="10px"
<Box h="35px"> color={useColorModeValue('purple.700', 'purple.200')}
<MiniTimelineChart fontWeight="semibold"
stockCode={stock.stock_code} whiteSpace="nowrap"
eventTime={eventTime} mb={0.5}
/> >
</Box> 📊 日线
</VStack> </Text>
<Box h="32px">
{/* K线图 - 紧凑高度 */} <MiniKLineChart
<VStack stockCode={stock.stock_code}
minW="150px" eventTime={eventTime}
maxW="180px" />
flex="1" </Box>
borderWidth="1px" </VStack>
borderColor={useColorModeValue('purple.100', 'purple.700')} </HStack>
borderRadius="md"
px={2}
py={1}
bg={useColorModeValue('purple.50', 'purple.900')}
onClick={(e) => {
e.stopPropagation();
setIsModalOpen(true);
}}
cursor="pointer"
flexShrink={1}
align="stretch"
spacing={0}
h="fit-content"
_hover={{
borderColor: useColorModeValue('purple.300', 'purple.500'),
boxShadow: 'md',
transform: 'translateY(-1px)'
}}
transition="all 0.2s"
>
<Text
fontSize="xs"
color={useColorModeValue('purple.700', 'purple.200')}
fontWeight="semibold"
whiteSpace="nowrap"
mb={0.5}
>
📊 日线
</Text>
<Box h="35px">
<MiniKLineChart
stockCode={stock.stock_code}
eventTime={eventTime}
/>
</Box>
</VStack>
{/* 关联描述 - 升级和降级处理 */} {/* 关联描述 - 升级和降级处理 */}
{stock.relation_desc && ( {stock.relation_desc && (
@@ -347,11 +346,11 @@ const StockListItem = ({
position="relative" position="relative"
> >
{/* 去掉"关联描述"标题 */} {/* 去掉"关联描述"标题 */}
<Collapse in={isDescExpanded} startingHeight={40}> <Collapse in={isDescExpanded} startingHeight={36}>
<Text <Text
fontSize="sm" fontSize="xs"
color={nameColor} color={nameColor}
lineHeight="1.6" lineHeight="1.5"
> >
{relationText} {relationText}
</Text> </Text>