update ui

This commit is contained in:
2025-11-13 16:17:32 +08:00
parent 5aa0507a65
commit 5ddf8d3c09
2 changed files with 45 additions and 20 deletions

View File

@@ -14,11 +14,6 @@ import {
useColorModeValue,
SimpleGrid,
Icon,
Stat,
StatLabel,
StatNumber,
StatHelpText,
StatArrow,
Spinner,
Center,
} from '@chakra-ui/react';
@@ -27,15 +22,20 @@ import ReactECharts from 'echarts-for-react';
import { logger } from '../../../utils/logger';
/**
* 获取指数行情数据
* 获取指数行情数据(日线数据)
*/
const fetchIndexKline = async (indexCode) => {
try {
const response = await fetch(`/api/index/${indexCode}/kline`);
// 使用日线数据获取最近60个交易日
const response = await fetch(`/api/index/${indexCode}/kline?type=daily`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
logger.debug('HeroPanel', 'fetchIndexKline success', { indexCode, dataLength: data?.data?.length });
return data;
} catch (error) {
logger.error('HeroPanel', 'fetchIndexKline', error);
logger.error('HeroPanel', 'fetchIndexKline error', { indexCode, error: error.message });
return null;
}
};
@@ -86,30 +86,41 @@ const MiniIndexChart = ({ indexCode, indexName }) => {
const areaColor = useColorModeValue('rgba(255, 215, 0, 0.15)', 'rgba(255, 215, 0, 0.1)');
useEffect(() => {
let isMounted = true;
const loadData = async () => {
setLoading(true);
const data = await fetchIndexKline(indexCode);
if (data && data.data && data.data.length > 0) {
if (isMounted && data && data.data && data.data.length > 0) {
// 取最近一个交易日的数据
const latest = data.data[data.data.length - 1];
const prevClose = latest.prev_close || latest.close;
setLatestData({
close: latest[2],
change: ((latest[2] - latest[1]) / latest[1] * 100).toFixed(2),
isPositive: latest[2] >= latest[1]
close: latest.close,
change: prevClose ? (((latest.close - prevClose) / prevClose) * 100).toFixed(2) : '0.00',
isPositive: latest.close >= prevClose
});
// 准备图表数据最近60个交易日
const recentData = data.data.slice(-60);
setChartData({
dates: recentData.map(item => item[0]),
values: recentData.map(item => item[2])
dates: recentData.map(item => item.time),
values: recentData.map(item => item.close)
});
}
setLoading(false);
if (isMounted) {
setLoading(false);
}
};
loadData();
return () => {
isMounted = false;
};
}, [indexCode]);
const chartOption = useMemo(() => {
@@ -184,13 +195,12 @@ const MiniIndexChart = ({ indexCode, indexName }) => {
</Text>
</VStack>
<HStack spacing={1}>
<StatArrow type={latestData?.isPositive ? 'increase' : 'decrease'} />
<Text
fontSize="sm"
fontWeight="bold"
color={latestData?.isPositive ? 'green.300' : 'red.300'}
>
{latestData?.isPositive ? '+' : ''}{latestData?.change}%
{latestData?.isPositive ? '↑' : '↓'} {latestData?.isPositive ? '+' : ''}{latestData?.change}%
</Text>
</HStack>
</HStack>
@@ -215,14 +225,24 @@ const ConceptWordCloud = () => {
const chartBg = useColorModeValue('transparent', 'transparent');
useEffect(() => {
let isMounted = true;
const loadConcepts = async () => {
setLoading(true);
const data = await fetchPopularConcepts();
setConcepts(data);
setLoading(false);
if (isMounted && data && data.length > 0) {
setConcepts(data);
}
if (isMounted) {
setLoading(false);
}
};
loadConcepts();
return () => {
isMounted = false;
};
}, []);
const chartOption = useMemo(() => {

View File

@@ -120,10 +120,15 @@ const Community = () => {
};
// ⚡ 首次进入页面时滚动到内容区域(考虑导航栏高度)
const hasScrolled = useRef(false);
useEffect(() => {
// 只在第一次挂载时执行滚动
if (hasScrolled.current) return;
// 延迟执行确保DOM已完全渲染
const timer = setTimeout(() => {
if (containerRef.current) {
hasScrolled.current = true;
// 滚动到容器顶部,自动考虑导航栏的高度
containerRef.current.scrollIntoView({
behavior: 'auto',
@@ -131,7 +136,7 @@ const Community = () => {
inline: 'nearest'
});
}
}, 0);
}, 100);
return () => clearTimeout(timer);
}, []); // 空依赖数组,只在组件挂载时执行一次