-
+
支持精确到分钟的时间范围选择(不能超过当前时间)
);
- // 移动端模式:下拉选择器
+ // 移动端模式
if (mobile) {
const allButtons = [...timeRangeConfig.dynamic, ...timeRangeConfig.fixed];
const handleMobileSelect = (key) => {
if (key === selectedKey) {
- // 取消选中
setSelectedKey(null);
onChange(null);
} else {
- const config = allButtons.find(b => b.key === key);
+ const config = allButtons.find((b) => b.key === key);
if (config) {
handleButtonClick(config);
}
@@ -407,7 +224,7 @@ const TradingTimeFilter = ({ value, onChange, compact = false, mobile = false })
value={selectedKey}
onChange={handleMobileSelect}
placeholder={
-
+
筛选
@@ -421,7 +238,7 @@ const TradingTimeFilter = ({ value, onChange, compact = false, mobile = false })
className="transparent-select"
popupMatchSelectWidth={false}
>
- {allButtons.map(config => (
+ {allButtons.map((config) => (
@@ -430,18 +247,20 @@ const TradingTimeFilter = ({ value, onChange, compact = false, mobile = false })
);
}
- // 紧凑模式:PC 端搜索栏内的样式
+ // 紧凑模式
if (compact) {
- // 合并所有按钮配置
const allButtons = [...timeRangeConfig.dynamic, ...timeRangeConfig.fixed];
return (
-
+
{allButtons.map((config, index) =>
renderCompactButton(config, index < allButtons.length - 1)
)}
- {/* 更多时间 */}
-
|
+
+ |
+
@@ -476,16 +301,16 @@ const TradingTimeFilter = ({ value, onChange, compact = false, mobile = false })
);
}
- // 默认模式:移动端/独立使用
+ // 默认模式
return (
-
- {/* 动态按钮(根据时段显示多个) */}
- {timeRangeConfig.dynamic.map(config => renderButton(config))}
+
+ {timeRangeConfig.dynamic.map((config) => renderButton(config))}
+ {timeRangeConfig.fixed.map((config) => renderButton(config))}
- {/* 固定按钮(始终显示) */}
- {timeRangeConfig.fixed.map(config => renderButton(config))}
-
- {/* 更多时间 - 自定义范围 */}
- {selectedKey === 'custom' ? (
+ {selectedKey === "custom" ? (
-
+
- {customRange ? `${customRange[0].format('MM-DD HH:mm')} - ${customRange[1].format('MM-DD HH:mm')}` : '自定义'}
+ {customRange
+ ? `${customRange[0].format("MM-DD HH:mm")} - ${customRange[1].format("MM-DD HH:mm")}`
+ : "自定义"}
) : (
- } style={{ fontSize: 12 }}>
+ }
+ style={{ fontSize: 12 }}
+ >
更多时间
diff --git a/src/views/Community/components/SearchFilters/TradingTimeFilter/constants.js b/src/views/Community/components/SearchFilters/TradingTimeFilter/constants.js
new file mode 100644
index 00000000..01c9c01e
--- /dev/null
+++ b/src/views/Community/components/SearchFilters/TradingTimeFilter/constants.js
@@ -0,0 +1,18 @@
+// TradingTimeFilter 常量定义
+
+// 时段边界(分钟数)
+export const TIME_BOUNDARIES = {
+ PRE_MARKET_END: 9 * 60 + 30, // 09:30
+ MORNING_END: 11 * 60 + 30, // 11:30
+ AFTERNOON_START: 13 * 60, // 13:00
+ MARKET_CLOSE: 15 * 60, // 15:00
+};
+
+// 时段类型
+export const TRADING_SESSIONS = {
+ PRE_MARKET: "pre-market", // 盘前
+ MORNING: "morning", // 早盘
+ LUNCH: "lunch", // 午休
+ AFTERNOON: "afternoon", // 午盘
+ AFTER_HOURS: "after-hours", // 盘后
+};
diff --git a/src/views/Community/components/SearchFilters/TradingTimeFilter/index.js b/src/views/Community/components/SearchFilters/TradingTimeFilter/index.js
new file mode 100644
index 00000000..01a4f735
--- /dev/null
+++ b/src/views/Community/components/SearchFilters/TradingTimeFilter/index.js
@@ -0,0 +1,10 @@
+// TradingTimeFilter 模块导出
+
+export { TIME_BOUNDARIES, TRADING_SESSIONS } from "./constants";
+export {
+ getCurrentTradingSession,
+ getPrevTradingDay,
+ generateTimeRangeConfig,
+ disabledDate,
+ disabledTime,
+} from "./utils";
diff --git a/src/views/Community/components/SearchFilters/TradingTimeFilter/utils.js b/src/views/Community/components/SearchFilters/TradingTimeFilter/utils.js
new file mode 100644
index 00000000..4fadd81a
--- /dev/null
+++ b/src/views/Community/components/SearchFilters/TradingTimeFilter/utils.js
@@ -0,0 +1,224 @@
+// TradingTimeFilter 工具函数
+
+import dayjs from "dayjs";
+import { TIME_BOUNDARIES, TRADING_SESSIONS } from "./constants";
+import { logger } from "@utils/logger";
+import tradingDayUtils from "@utils/tradingDayUtils";
+
+/**
+ * 获取当前交易时段
+ * @returns {string} 时段标识
+ */
+export const getCurrentTradingSession = () => {
+ const now = dayjs();
+ const hour = now.hour();
+ const minute = now.minute();
+ const currentMinutes = hour * 60 + minute;
+
+ if (currentMinutes < TIME_BOUNDARIES.PRE_MARKET_END) {
+ return TRADING_SESSIONS.PRE_MARKET;
+ } else if (currentMinutes < TIME_BOUNDARIES.MORNING_END) {
+ return TRADING_SESSIONS.MORNING;
+ } else if (currentMinutes < TIME_BOUNDARIES.AFTERNOON_START) {
+ return TRADING_SESSIONS.LUNCH;
+ } else if (currentMinutes < TIME_BOUNDARIES.MARKET_CLOSE) {
+ return TRADING_SESSIONS.AFTERNOON;
+ } else {
+ return TRADING_SESSIONS.AFTER_HOURS;
+ }
+};
+
+/**
+ * 获取上一个交易日
+ * @param {dayjs.Dayjs} now - 当前时间
+ * @returns {dayjs.Dayjs} 上一交易日
+ */
+export const getPrevTradingDay = (now) => {
+ try {
+ const prevTradingDay = tradingDayUtils.getPreviousTradingDay(now.toDate());
+ return dayjs(prevTradingDay);
+ } catch (e) {
+ logger.warn("TradingTimeFilter", "获取上一交易日失败,降级处理", e);
+ return now.subtract(1, "day");
+ }
+};
+
+/**
+ * 生成时间范围配置
+ * @returns {Object} 包含 dynamic 和 fixed 按钮配置
+ */
+export const generateTimeRangeConfig = () => {
+ const session = getCurrentTradingSession();
+ const now = dayjs();
+
+ // 今日关键时间点
+ const today0930 = now.hour(9).minute(30).second(0);
+ const today1130 = now.hour(11).minute(30).second(0);
+ const today1300 = now.hour(13).minute(0).second(0);
+ const today1500 = now.hour(15).minute(0).second(0);
+ const todayStart = now.startOf("day");
+ const todayEnd = now.endOf("day");
+
+ // 昨日关键时间点
+ const yesterdayStart = now.subtract(1, "day").startOf("day");
+ const yesterdayEnd = now.subtract(1, "day").endOf("day");
+
+ // 动态按钮配置(根据时段)
+ const dynamicButtonsMap = {
+ [TRADING_SESSIONS.PRE_MARKET]: [],
+ [TRADING_SESSIONS.MORNING]: [
+ {
+ key: "intraday",
+ label: "盘中",
+ range: [today0930, today1500],
+ tooltip: "盘中交易时段",
+ timeHint: "今日 09:30 - 15:00",
+ color: "blue",
+ type: "precise",
+ },
+ ],
+ [TRADING_SESSIONS.LUNCH]: [],
+ [TRADING_SESSIONS.AFTERNOON]: [
+ {
+ key: "intraday",
+ label: "盘中",
+ range: [today0930, today1500],
+ tooltip: "盘中交易时段",
+ timeHint: "今日 09:30 - 15:00",
+ color: "blue",
+ type: "precise",
+ },
+ {
+ key: "afternoon",
+ label: "午盘",
+ range: [today1300, today1500],
+ tooltip: "午盘交易时段",
+ timeHint: "今日 13:00 - 15:00",
+ color: "cyan",
+ type: "precise",
+ },
+ ],
+ [TRADING_SESSIONS.AFTER_HOURS]: [],
+ };
+
+ const prevTradingDay = getPrevTradingDay(now);
+ const prevTradingDay1500 = prevTradingDay.hour(15).minute(0).second(0);
+
+ // 固定按钮配置
+ const fixedButtons = [
+ {
+ key: "current-trading-day",
+ label: "当前交易日",
+ range: [prevTradingDay1500, now],
+ tooltip: "当前交易日事件",
+ timeHint: `${prevTradingDay.format("MM-DD")} 15:00 - 现在`,
+ color: "green",
+ type: "precise",
+ },
+ {
+ key: "morning-fixed",
+ label: "早盘",
+ range: [today0930, today1130],
+ tooltip: "早盘交易时段",
+ timeHint: "09:30 - 11:30",
+ color: "geekblue",
+ type: "precise",
+ },
+ {
+ key: "today",
+ label: "今日全天",
+ range: [todayStart, todayEnd],
+ tooltip: "今日全天",
+ timeHint: "今日 00:00 - 23:59",
+ color: "purple",
+ type: "precise",
+ },
+ {
+ key: "yesterday",
+ label: "昨日",
+ range: [yesterdayStart, yesterdayEnd],
+ tooltip: "昨日全天",
+ timeHint: "昨日 00:00 - 23:59",
+ color: "orange",
+ type: "precise",
+ },
+ {
+ key: "week",
+ label: "近一周",
+ range: 7,
+ tooltip: "过去7个交易日",
+ timeHint: "过去7天",
+ color: "magenta",
+ type: "recent_days",
+ },
+ {
+ key: "month",
+ label: "近一月",
+ range: 30,
+ tooltip: "过去30个交易日",
+ timeHint: "过去30天",
+ color: "volcano",
+ type: "recent_days",
+ },
+ {
+ key: "all",
+ label: "全部",
+ range: null,
+ tooltip: "显示全部事件",
+ timeHint: "不限时间",
+ color: "default",
+ type: "all",
+ },
+ ];
+
+ return {
+ dynamic: dynamicButtonsMap[session] || [],
+ fixed: fixedButtons,
+ };
+};
+
+/**
+ * 禁用未来日期
+ * @param {dayjs.Dayjs} current - 当前日期
+ * @returns {boolean} 是否禁用
+ */
+export const disabledDate = (current) => {
+ return current && current > dayjs().endOf("day");
+};
+
+/**
+ * 禁用未来时间(精确到分钟)
+ * @param {dayjs.Dayjs} current - 当前时间
+ * @returns {Object} 禁用配置
+ */
+export const disabledTime = (current) => {
+ if (!current) return {};
+
+ const now = dayjs();
+ const isToday = current.isSame(now, "day");
+
+ if (!isToday) return {};
+
+ const currentHour = now.hour();
+ const currentMinute = now.minute();
+
+ return {
+ disabledHours: () => {
+ const hours = [];
+ for (let i = currentHour + 1; i < 24; i++) {
+ hours.push(i);
+ }
+ return hours;
+ },
+ disabledMinutes: (selectedHour) => {
+ if (selectedHour === currentHour) {
+ const minutes = [];
+ for (let i = currentMinute + 1; i < 60; i++) {
+ minutes.push(i);
+ }
+ return minutes;
+ }
+ return [];
+ },
+ };
+};