From b39bc5c8bc599914c9258e9527d1bdc89990dfa1 Mon Sep 17 00:00:00 2001 From: ddshi <8811906+ddshi@user.noreply.gitee.com> Date: Tue, 10 Feb 2026 11:07:38 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=8F=90=E9=86=92?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E7=9B=B8=E5=85=B3=E7=9A=84=20UTC=20=E6=97=B6?= =?UTF-8?q?=E5=8C=BA=E5=92=8C=E7=BB=A7=E6=89=BF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主要修复: 1. 时间存储格式统一使用 UTC 时区 - HomePage.tsx: 修复 formDate 处理,使用 new Date() 自动转换 - 解决用户设置"14:00"保存后显示"22:00"问题 2. 重复计算函数统一使用 UTC - calculateNextDueDate: 使用 getUTC*() 和 Date.UTC() - calculateReminderTimes: 使用 UTC 时间计算提醒点 - getReminderValueFromTimes: 使用 UTC 时间戳反推选项 3. 修复重复提醒创建时继承 reminder_times - createNextRecurringEventData: 根据新日期重新计算 reminder_times - 修改接口类型支持 reminder_times 为 null - 解决原提醒"提前15分钟"新提醒变"准时"问题 影响: - 提醒时间显示正确(无时区偏差) - 跨天/跨月提醒计算正确 - 重复提醒自动创建时正确继承提醒设置 Co-Authored-By: Claude Opus 4.5 --- src/pages/HomePage.tsx | 125 +++++++++----- src/stores/index.ts | 28 +-- src/types/index.ts | 1 + src/utils/repeatCalculator.ts | 313 ++++++++++++++++++++++++++++++++-- 4 files changed, 389 insertions(+), 78 deletions(-) diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index 972fbc5..9134ae2 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -27,7 +27,7 @@ import { ReminderList } from '../components/reminder/ReminderList'; import { NoteEditor } from '../components/note/NoteEditor'; import { FloatingAIChat } from '../components/ai/FloatingAIChat'; import type { Event, EventType, RepeatType, PriorityType } from '../types'; -import { calculateNextReminderDate } from '../utils/repeatCalculator'; +import { calculateNextReminderDate, getReminderOptions, getDefaultReminderValue, calculateReminderTimes, getReminderValueFromTimes, formatReminderTimeDisplay } from '../utils/repeatCalculator'; export function HomePage() { const navigate = useNavigate(); @@ -54,6 +54,7 @@ export function HomePage() { const [formRepeatType, setFormRepeatType] = useState('none'); const [formIsHoliday, setFormIsHoliday] = useState(false); const [formPriority, setFormPriority] = useState('none'); + const [formReminderValue, setFormReminderValue] = useState('0'); // 提醒选项值 // Initialize auth and data on mount useEffect(() => { @@ -81,7 +82,10 @@ export function HomePage() { const eventDate = new Date(event.date); const hours = eventDate.getHours(); const minutes = eventDate.getMinutes(); - setFormTime(hours === 0 && minutes === 0 ? '' : `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`); + const hasTime = hours !== 0 || minutes !== 0; + setFormTime(hasTime ? `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}` : ''); + // 从 reminder_times 反推用户选择的提醒选项值 + setFormReminderValue(getReminderValueFromTimes(event.reminder_times, event.date, hasTime)); open(); }; @@ -97,6 +101,7 @@ export function HomePage() { setFormRepeatType('none'); setFormIsHoliday(type === 'anniversary'); setFormPriority('none'); + setFormReminderValue('0'); open(); }; @@ -112,13 +117,15 @@ export function HomePage() { const day = String(dateObj.getDate()).padStart(2, '0'); if (formTime) { - // 有时间:构建本地时间格式 - const hours = String(parseInt(formTime.split(':')[0])).padStart(2, '0'); - const minutes = String(parseInt(formTime.split(':')[1])).padStart(2, '0'); - dateStr = `${year}-${month}-${day}T${hours}:${minutes}:00`; + // 有时间:构建 UTC 时间格式(用户选择的是本地时间,需要转换为 UTC 存储) + const hours = parseInt(formTime.split(':')[0]); + const minutes = parseInt(formTime.split(':')[1]); + // 先用本地时间创建日期对象,然后获取 UTC 时间 + const localDate = new Date(year, dateObj.getMonth(), day, hours, minutes); + dateStr = localDate.toISOString(); } else { - // 无时间:只保存日期部分 - dateStr = `${year}-${month}-${day}T00:00:00`; + // 无时间:使用 UTC 日期格式 + dateStr = `${year}-${month}-${day}T00:00:00.000Z`; } // 构建事件数据,确保不包含 undefined 值 @@ -139,6 +146,12 @@ export function HomePage() { eventData.content = formContent; } + // 计算提醒时间点(仅对提醒事项) + if (formType === 'reminder') { + const hasTime = !!formTime; + eventData.reminder_times = calculateReminderTimes(dateStr, hasTime, formReminderValue); + } + if (isEdit && selectedEvent) { await updateEventById(selectedEvent.id, eventData); } else { @@ -273,6 +286,7 @@ export function HomePage() { setFormRepeatType('none'); setFormIsHoliday(false); setFormPriority('none'); + setFormReminderValue('0'); setSelectedEvent(null); setIsEdit(false); }; @@ -415,11 +429,13 @@ export function HomePage() { ]} value={formType} onChange={(value) => value && setFormType(value as EventType)} - disabled={isEdit} + readOnly={isEdit} + rightSectionPointerEvents={isEdit ? 'none' : 'auto'} styles={{ input: { borderRadius: 2, background: '#faf9f7', + pointerEvents: isEdit ? 'none' : 'auto', }, }} /> @@ -427,14 +443,13 @@ export function HomePage() { {/* Title */} - 标题 + + 标题* } placeholder="输入标题" value={formTitle} onChange={(e) => setFormTitle(e.target.value)} - required styles={{ input: { borderRadius: 2, @@ -491,11 +506,6 @@ export function HomePage() { position="bottom" withArrow shadow="md" - onOpenChange={(opened) => { - if (!opened && formDate) { - // Keep the date - } - }} > )} - {/* Repeat type */} - + 重复 + + } + data={[ + { value: 'none', label: '不重复' }, + { value: 'daily', label: '每天' }, + { value: 'weekly', label: '每周' }, + { value: 'monthly', label: '每月' }, + { value: 'yearly', label: '每年' }, + ]} + value={formRepeatType} + onChange={(value) => value && setFormRepeatType(value as RepeatType)} + styles={{ + input: { + borderRadius: 2, + background: '#faf9f7', + }, + }} + /> + + {/* Reminder options (only for reminders) */} + {formType === 'reminder' && ( +