Files
vf_react/src/components/TradeDatePicker/index.tsx
2025-12-05 15:26:45 +08:00

169 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from 'react';
import {
HStack,
Input,
Text,
Icon,
Tooltip,
useColorModeValue,
} from '@chakra-ui/react';
import { InfoIcon } from '@chakra-ui/icons';
import { FaCalendarAlt } from 'react-icons/fa';
export interface TradeDatePickerProps {
/** 当前选中的日期 */
value: Date | null;
/** 日期变化回调 */
onChange: (date: Date) => void;
/** 默认日期(组件初始化时使用) */
defaultDate?: Date;
/** 最新交易日期(用于显示提示) */
latestTradeDate?: Date | null;
/** 最小可选日期 */
minDate?: Date;
/** 最大可选日期,默认今天 */
maxDate?: Date;
/** 标签文字,默认"交易日期" */
label?: string;
/** 输入框宽度 */
inputWidth?: string | object;
/** 是否显示标签图标 */
showIcon?: boolean;
/** 是否使用深色模式(强制覆盖 Chakra 颜色模式) */
isDarkMode?: boolean;
}
/**
* 交易日期选择器组件
*
* 提供日期输入框和最新交易日期提示,供概念中心、个股中心等页面复用。
* 快捷按钮(今天、昨天等)由各页面自行实现。
*/
const TradeDatePicker: React.FC<TradeDatePickerProps> = ({
value,
onChange,
defaultDate,
latestTradeDate,
minDate,
maxDate,
label = '交易日期',
inputWidth = { base: '100%', lg: '200px' },
showIcon = true,
isDarkMode = false,
}) => {
// 颜色主题 - 支持 isDarkMode 强制覆盖
const defaultLabelColor = useColorModeValue('purple.700', 'purple.300');
const defaultIconColor = useColorModeValue('purple.500', 'purple.400');
const defaultInputBorderColor = useColorModeValue('purple.200', 'purple.600');
const defaultTipBg = useColorModeValue('blue.50', 'blue.900');
const defaultTipBorderColor = useColorModeValue('blue.200', 'blue.600');
const defaultTipTextColor = useColorModeValue('blue.600', 'blue.200');
const defaultTipIconColor = useColorModeValue('blue.500', 'blue.300');
// 深色模式专用颜色
const darkModeColors = {
labelColor: 'white',
iconColor: 'cyan.400',
inputBorderColor: 'whiteAlpha.300',
inputBg: 'whiteAlpha.50',
inputColor: 'white',
tipBg: 'rgba(59, 130, 246, 0.15)',
tipBorderColor: 'blue.500',
tipTextColor: 'blue.200',
tipIconColor: 'blue.300',
};
// 根据 isDarkMode 选择颜色
const labelColor = isDarkMode ? darkModeColors.labelColor : defaultLabelColor;
const iconColor = isDarkMode ? darkModeColors.iconColor : defaultIconColor;
const inputBorderColor = isDarkMode ? darkModeColors.inputBorderColor : defaultInputBorderColor;
const tipBg = isDarkMode ? darkModeColors.tipBg : defaultTipBg;
const tipBorderColor = isDarkMode ? darkModeColors.tipBorderColor : defaultTipBorderColor;
const tipTextColor = isDarkMode ? darkModeColors.tipTextColor : defaultTipTextColor;
const tipIconColor = isDarkMode ? darkModeColors.tipIconColor : defaultTipIconColor;
// 使用默认日期初始化(仅在 value 为 null 且有 defaultDate 时)
React.useEffect(() => {
if (value === null && defaultDate) {
onChange(defaultDate);
}
}, []); // eslint-disable-line react-hooks/exhaustive-deps
// 处理日期变化
const handleDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const dateStr = e.target.value;
if (dateStr) {
const date = new Date(dateStr);
onChange(date);
}
};
// 格式化日期为 YYYY-MM-DD
const formatDateValue = (date: Date | null): string => {
if (!date) return '';
return date.toISOString().split('T')[0];
};
// 计算日期范围
const minDateStr = minDate ? formatDateValue(minDate) : undefined;
const maxDateStr = maxDate
? formatDateValue(maxDate)
: new Date().toISOString().split('T')[0];
return (
<>
{/* 标签 */}
<HStack spacing={3}>
{showIcon && <Icon as={FaCalendarAlt} color={iconColor} boxSize={5} />}
<Text fontWeight="bold" color={labelColor}>
{label}
</Text>
</HStack>
{/* 日期输入框 */}
<Input
type="date"
value={formatDateValue(value)}
onChange={handleDateChange}
min={minDateStr}
max={maxDateStr}
width={inputWidth}
focusBorderColor="purple.400"
borderColor={inputBorderColor}
borderRadius="lg"
fontWeight="medium"
bg={isDarkMode ? darkModeColors.inputBg : undefined}
color={isDarkMode ? darkModeColors.inputColor : undefined}
_hover={{ borderColor: isDarkMode ? 'purple.400' : 'purple.300' }}
sx={isDarkMode ? {
'&::-webkit-calendar-picker-indicator': {
filter: 'invert(1)',
},
} : undefined}
/>
{/* 最新交易日期提示 */}
{latestTradeDate && (
<Tooltip label="数据库中最新的交易日期">
<HStack
spacing={2}
bg={tipBg}
px={3}
py={1.5}
borderRadius="full"
border="1px solid"
borderColor={tipBorderColor}
>
<Icon as={InfoIcon} color={tipIconColor} boxSize={3} />
<Text fontSize="sm" color={tipTextColor} fontWeight="medium">
: {latestTradeDate.toLocaleDateString('zh-CN')}
</Text>
</HStack>
</Tooltip>
)}
</>
);
};
export default TradeDatePicker;