@@ -24,70 +24,123 @@ const timeLineGroups = reactive<TimeLineGroup[]>([])
2424
2525// 组件状态
2626const loading = ref <boolean >(true )
27- const userScrolled = ref (false ); // 是否发生过用户滑动
28- let fixedBaseIndex = - 1 ; // 固定的 baseIndex,仅在用户滑动后生效
27+ const userScrolled = ref (false ) // 是否发生过用户滑动
28+ let fixedBaseIndex = - 1 // 固定的 baseIndex,仅在用户滑动后生效
2929
3030// 当前已加载的天数范围
3131const loadedRange = reactive ({
3232 before: 0 , // 已加载的过去天数
3333 after: 0 , // 已加载的未来天数
34- });
34+ })
3535
36- async function fetchTimeLineGroups(beforeDays , afterDays ) {
36+ async function fetchTimeLineGroups(beforeDays : number , afterDays : number ) {
3737 try {
38- const res: Object = await props .api .get (` plugin/SubscribeCal/grouped_events ` , {
38+ const res: any [] = await props .api .get (` plugin/SubscribeCal/grouped_events ` , {
3939 params: { before_days: beforeDays , after_days: afterDays }
40- });
41-
42- // 提取并排序
43- const groups = Object .entries (res )
44- .map (([date , items ]) => ({
45- date ,
46- items
47- }))
48- .sort ((a , b ) => new Date (a .date ).getTime () - new Date (b .date ).getTime ());
49-
50- // 使用Map进行去重,保证每个日期只保留一条数据
51- const uniqueGroups = new Map ();
40+ })
41+
42+ // 按日期分组
43+ const grouped = new Map <string , TimeLineGroup >()
44+
45+ res .forEach (item => {
46+ // 解析UTC时间
47+ const startDate = parseUTCDateTime (item .dtstart )
48+
49+ if (startDate ) {
50+ const localDateStr = getLocalISODateString (startDate )
51+ const endDate = parseUTCDateTime (item .dtend )
52+
53+ if (endDate ) item .dtend = endDate
54+ // 格式化项目,使用解析后的Date对象
55+ const formattedItem = {
56+ ... item ,
57+ // 使用本地时间
58+ dtstart: startDate ,
59+ }
60+
61+ if (! grouped .has (localDateStr )) {
62+ grouped .set (localDateStr , {
63+ date: localDateStr ,
64+ items: []
65+ })
66+ }
67+
68+ grouped .get (localDateStr )! .items .push (formattedItem )
69+ }
70+ })
71+
72+ // 转换为数组并排序
73+ const groups = Array .from (grouped .values ())
74+ .sort ((a , b ) => new Date (a .date ).getTime () - new Date (b .date ).getTime ())
75+
76+ // 去重
77+ const uniqueGroups = new Map <string , TimeLineGroup >()
5278 groups .forEach (group => {
5379 if (! uniqueGroups .has (group .date )) {
54- uniqueGroups .set (group .date , group );
80+ uniqueGroups .set (group .date , group )
5581 }
56- });
82+ })
5783
58- const filteredGroups = Array .from (uniqueGroups .values ());
84+ const filteredGroups = Array .from (uniqueGroups .values ())
5985
6086 if (beforeDays > loadedRange .before ) {
6187 // 添加过往数据
62- timeLineGroups .unshift (... filteredGroups );
63- loadedRange .before = beforeDays ;
88+ timeLineGroups .unshift (... filteredGroups )
89+ loadedRange .before = beforeDays
6490 }
6591
6692 if (afterDays > loadedRange .after ) {
6793 // 添加未来数据
68- timeLineGroups .push (... filteredGroups );
69- loadedRange .after = afterDays ;
94+ timeLineGroups .push (... filteredGroups )
95+ loadedRange .after = afterDays
7096 }
7197 } catch (error ) {
72- console .error (error );
98+ console .error (error )
99+ }
100+ }
101+
102+ /**
103+ * 将 %Y%m%dT%H%M%SZ 格式的时间字符串转为 Date 对象(UTC 时间)
104+ * @param dateStr 输入格式如 '20250405T160000Z'
105+ * @returns {Date|null} 解析后的 本地时间 Date 对象,失败返回 null
106+ */
107+ const parseUTCDateTime = (dateStr : string ): Date | null => {
108+ // 简单校验格式是否符合 YYYYMMDDTHHMMSSZ
109+ const regex = / ^ \d {8} T\d {6} Z$ /
110+ if (! regex .test (dateStr )) {
111+ console .warn (` Invalid date format: ${dateStr } ` )
112+ return null
73113 }
114+
115+ const year = parseInt (dateStr .slice (0 , 4 ), 10 )
116+ const month = parseInt (dateStr .slice (4 , 6 ), 10 ) - 1 // 月份从 0 开始
117+ const day = parseInt (dateStr .slice (6 , 8 ), 10 )
118+ const hour = parseInt (dateStr .slice (9 , 11 ), 10 )
119+ const minute = parseInt (dateStr .slice (11 , 13 ), 10 )
120+ const second = parseInt (dateStr .slice (13 , 15 ), 10 )
121+
122+ return new Date (Date .UTC (year , month , day , hour , minute , second ))
74123}
75124
125+ function getLocalISODateString(date : Date = new Date ()): string {
126+ const offset = date .getTimezoneOffset () * 60000
127+ return new Date (date .getTime () - offset ).toISOString ().slice (0 , 10 )
128+ }
76129
77130function getBaseIndex(): number {
78131 if (userScrolled .value && fixedBaseIndex >= 0 ) {
79- return fixedBaseIndex ;
132+ return fixedBaseIndex
80133 }
81- const todayStr = new Date (). toISOString (). split ( ' T ' )[ 0 ];
82- const todayIndex = timeLineGroups .findIndex (g => g .date === todayStr );
134+ const todayStr = getLocalISODateString ()
135+ const todayIndex = timeLineGroups .findIndex (g => g .date === todayStr )
83136
84137 if (todayIndex !== - 1 ) {
85- return todayIndex ;
138+ return todayIndex
86139 }
87140
88141 const futureIndex = timeLineGroups .findIndex (g => {
89- const groupDate = new Date (g .date );
90- const today = new Date ();
142+ const groupDate = new Date (g .date )
143+ const today = new Date ()
91144 return groupDate >= new Date (today .getFullYear (), today .getMonth (), today .getDate ())
92145 })
93146
0 commit comments