feat: 提交迷你分时图组件
This commit is contained in:
@@ -15,9 +15,10 @@ import {
|
|||||||
*
|
*
|
||||||
* @param {string} stockCode - 股票代码
|
* @param {string} stockCode - 股票代码
|
||||||
* @param {string} eventTime - 事件时间(可选)
|
* @param {string} eventTime - 事件时间(可选)
|
||||||
|
* @param {Function} onClick - 点击回调(可选)
|
||||||
* @returns {JSX.Element}
|
* @returns {JSX.Element}
|
||||||
*/
|
*/
|
||||||
const MiniTimelineChart = React.memo(function MiniTimelineChart({ stockCode, eventTime }) {
|
const MiniTimelineChart = React.memo(function MiniTimelineChart({ stockCode, eventTime, onClick }) {
|
||||||
const [data, setData] = useState([]);
|
const [data, setData] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const mountedRef = useRef(true);
|
const mountedRef = useRef(true);
|
||||||
@@ -162,7 +163,14 @@ const MiniTimelineChart = React.memo(function MiniTimelineChart({ stockCode, eve
|
|||||||
}, [data, loading, stableEventTime]);
|
}, [data, loading, stableEventTime]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: 140, height: 40 }}>
|
<div
|
||||||
|
style={{
|
||||||
|
width: 140,
|
||||||
|
height: 40,
|
||||||
|
cursor: onClick ? 'pointer' : 'default'
|
||||||
|
}}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
<ReactECharts
|
<ReactECharts
|
||||||
option={chartOption}
|
option={chartOption}
|
||||||
style={{ width: '100%', height: '100%' }}
|
style={{ width: '100%', height: '100%' }}
|
||||||
@@ -172,9 +180,10 @@ const MiniTimelineChart = React.memo(function MiniTimelineChart({ stockCode, eve
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}, (prevProps, nextProps) => {
|
}, (prevProps, nextProps) => {
|
||||||
// 自定义比较函数,只有当stockCode或eventTime变化时才重新渲染
|
// 自定义比较函数,只有当stockCode、eventTime或onClick变化时才重新渲染
|
||||||
return prevProps.stockCode === nextProps.stockCode &&
|
return prevProps.stockCode === nextProps.stockCode &&
|
||||||
prevProps.eventTime === nextProps.eventTime;
|
prevProps.eventTime === nextProps.eventTime &&
|
||||||
|
prevProps.onClick === nextProps.onClick;
|
||||||
});
|
});
|
||||||
|
|
||||||
export default MiniTimelineChart;
|
export default MiniTimelineChart;
|
||||||
|
|||||||
@@ -15,11 +15,12 @@ const REQUEST_INTERVAL = 30000; // 30秒内不重复请求同一只股票的数
|
|||||||
* 获取缓存键
|
* 获取缓存键
|
||||||
* @param {string} stockCode - 股票代码
|
* @param {string} stockCode - 股票代码
|
||||||
* @param {string} eventTime - 事件时间
|
* @param {string} eventTime - 事件时间
|
||||||
|
* @param {string} chartType - 图表类型(timeline/daily)
|
||||||
* @returns {string} 缓存键
|
* @returns {string} 缓存键
|
||||||
*/
|
*/
|
||||||
export const getCacheKey = (stockCode, eventTime) => {
|
export const getCacheKey = (stockCode, eventTime, chartType = 'timeline') => {
|
||||||
const date = eventTime ? moment(eventTime).format('YYYY-MM-DD') : moment().format('YYYY-MM-DD');
|
const date = eventTime ? moment(eventTime).format('YYYY-MM-DD') : moment().format('YYYY-MM-DD');
|
||||||
return `${stockCode}|${date}`;
|
return `${stockCode}|${date}|${chartType}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,10 +53,11 @@ export const shouldRefreshData = (cacheKey) => {
|
|||||||
* 获取K线数据(带缓存和防重复请求)
|
* 获取K线数据(带缓存和防重复请求)
|
||||||
* @param {string} stockCode - 股票代码
|
* @param {string} stockCode - 股票代码
|
||||||
* @param {string} eventTime - 事件时间
|
* @param {string} eventTime - 事件时间
|
||||||
|
* @param {string} chartType - 图表类型(timeline/daily)
|
||||||
* @returns {Promise<Array>} K线数据
|
* @returns {Promise<Array>} K线数据
|
||||||
*/
|
*/
|
||||||
export const fetchKlineData = async (stockCode, eventTime) => {
|
export const fetchKlineData = async (stockCode, eventTime, chartType = 'timeline') => {
|
||||||
const cacheKey = getCacheKey(stockCode, eventTime);
|
const cacheKey = getCacheKey(stockCode, eventTime, chartType);
|
||||||
|
|
||||||
// 1. 检查缓存
|
// 1. 检查缓存
|
||||||
if (klineDataCache.has(cacheKey)) {
|
if (klineDataCache.has(cacheKey)) {
|
||||||
@@ -73,10 +75,10 @@ export const fetchKlineData = async (stockCode, eventTime) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. 发起新请求
|
// 3. 发起新请求
|
||||||
logger.debug('klineDataCache', '发起新K线数据请求', { cacheKey });
|
logger.debug('klineDataCache', '发起新K线数据请求', { cacheKey, chartType });
|
||||||
const normalizedEventTime = eventTime ? moment(eventTime).format('YYYY-MM-DD HH:mm') : undefined;
|
const normalizedEventTime = eventTime ? moment(eventTime).format('YYYY-MM-DD HH:mm') : undefined;
|
||||||
const requestPromise = stockService
|
const requestPromise = stockService
|
||||||
.getKlineData(stockCode, 'timeline', normalizedEventTime)
|
.getKlineData(stockCode, chartType, normalizedEventTime)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const data = Array.isArray(res?.data) ? res.data : [];
|
const data = Array.isArray(res?.data) ? res.data : [];
|
||||||
// 更新缓存
|
// 更新缓存
|
||||||
@@ -86,12 +88,13 @@ export const fetchKlineData = async (stockCode, eventTime) => {
|
|||||||
pendingRequests.delete(cacheKey);
|
pendingRequests.delete(cacheKey);
|
||||||
logger.debug('klineDataCache', 'K线数据请求完成并缓存', {
|
logger.debug('klineDataCache', 'K线数据请求完成并缓存', {
|
||||||
cacheKey,
|
cacheKey,
|
||||||
|
chartType,
|
||||||
dataPoints: data.length
|
dataPoints: data.length
|
||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
logger.error('klineDataCache', 'fetchKlineData', error, { stockCode, cacheKey });
|
logger.error('klineDataCache', 'fetchKlineData', error, { stockCode, chartType, cacheKey });
|
||||||
// 清除pending状态
|
// 清除pending状态
|
||||||
pendingRequests.delete(cacheKey);
|
pendingRequests.delete(cacheKey);
|
||||||
// 如果有旧缓存,返回旧数据
|
// 如果有旧缓存,返回旧数据
|
||||||
|
|||||||
Reference in New Issue
Block a user