Files
timeTableFix/docs/auto-save-design.md
zikai d32f8be018 refactor: 清理死代码 + 提前失败 + 错误记录控制台
- 移除 EventDetail.vue 未用的 computed 导入
- 移除 HeaderBar.vue 未用的 .btn-secondary CSS
- store (updateEvent/splitEvent/toggleOccurrence): uid 缺失改抛错 (fail-fast), 不再静默 return
- EventDetail onSplit: 捕获 splitEvent 抛错并提示用户
- DropZone/HeaderBar 解析失败: catch 内补 console.error
- ical-io getZone: 时区未注册回退 UTC 时 console.warn
- WeekPreview 周标签改用 i18n (weekPreview.rangeFmt), 与 MonthPreview 一致
- docs: 新增 error-handling.md; 修正 auto-save-design state 快照补 timezone
- README: 补充部署说明 (经 zMainPage apache2 托管)
2026-07-28 11:08:06 +08:00

3.0 KiB
Raw Blame History

自动保存设计

本文档记录 src/composables/useCalendar.jssrc/components/HeaderBar.vue 的保存模型重构。

背景

原设计有「dirty 标记 + 下载前确认弹窗 + 快照式 undo/redo最多 50 步)」。 EventDetail 的表单已改为自动应用(watch(form) 即时写回 store commit 1c6ecf9dirty 仅用于「下载前提示未保存」与红点显示。撤销是 独立的历史栈。

重构:移除 dirty / undo

纯前端工具,无持久化需求,所有编辑本就即时生效(自动应用 watch。 dirty 标记与确认弹窗是冗余的仪式感undo 栈在自动应用场景下也意义 有限(每次 keystroke 都会 push 历史,栈迅速填满噪声)。移除以降低 复杂度、减少状态字段。

删除的死代码(useCalendar.js

  • state.history(快照栈)、state.dirty
  • MAX_HISTORY 常量
  • snapshot()pushHistory()restore()
  • undo() action、canUndo computed
  • markSaved() action
  • 各 actionorganize/updateEvent/deleteEvent/addEvent/ splitEvent/toggleOccurrence)内的 pushHistory()state.dirty = true 调用
  • loadFile 内的 state.history = []state.dirty = false
  • 不再使用的 cloneEvent 导入snapshot 曾用)

HeaderBar.vue 改动

  • 移除「撤销」按钮
  • 移除下载按钮后的红点 <span class="dirty-dot">)与 .dirty-dot 样式
  • onDownload():移除 if (state.dirty && !confirm(...)) 确认弹窗与 markSaved() 调用;直接 serialize() 下载

自动保存语义

  • 所有编辑即时生效updateEvent/deleteEvent/addEvent/ splitEvent/toggleOccurrence 直接 mutate 响应式 state.events 无中间缓冲。EventDetail 的 watch(form, { deep: true }) 把表单变化 立即 patch 回 store。
  • 下载兜底onDownloadserialize() 序列化当前最新状态。 即便有任何未触发渲染的边界改动,下载时也会被序列化包含。文件名取 原文件名去 .ics.edited.ics
  • occurrences 不持久化EventModel 不存 occurrencesOccurrenceGrid 渲染时实时调 expandOccurrences(ev) 计算,toggleOccurrence 直接改 exdates。无缓存,无不同步风险。

状态字段(重构后)

const state = reactive({
  meta: null,
  events: [],
  selectedUid: null,
  fileName: null,
  viewMode: 'edit',        // 'edit' | 'month' | 'week'
  previewDate: todayISO(),
  timezone: detectTimezone(), // 日历级默认时区 (新建事件 tzid / X-WR-TIMEZONE)
})

history、无 dirty、无 redoStack。store 仅承载当前状态与视图锚点。

取消确认弹窗的理由

onDownloaddirty 时弹「有未保存的更改,仍要下载?」。但自动 应用下,所有更改已在 store 中,下载即序列化 store不存在「未保存」。 弹窗只会误导用户以为有数据丢失风险。移除后下载是一次性操作。