- organize: seriesKey 移除 weekday, 解锁每3天等 DAILY 序列合并 - organize: fitSeries 放宽阈值(稀疏序列如 BUS LAW Workshop 合并) - organize: 新增 splitIntoChains, GCD=1 的交错多班次拆为多个系列 - useCalendar: 移除 dirty/history/undo/snapshot/markSaved 死代码 - HeaderBar: 移除撤销按钮与红点●, 下载兜底序列化当前状态 - 测试: 42 项(原32), 覆盖 DAILY/稀疏/交错拆分/两两和候选等场景 - 文档: README 精简, 新增 docs/organize-algorithm.md 与 auto-save-design.md - 保留移动端 CSS 适配
2.9 KiB
2.9 KiB
自动保存设计
本文档记录 src/composables/useCalendar.js 与
src/components/HeaderBar.vue 的保存模型重构。
背景
原设计有「dirty 标记 + 下载前确认弹窗 + 快照式 undo/redo(最多 50 步)」。
EventDetail 的表单已改为自动应用(watch(form) 即时写回 store,
commit 1c6ecf9),dirty 仅用于「下载前提示未保存」与红点显示。撤销是
独立的历史栈。
重构:移除 dirty / undo
纯前端工具,无持久化需求,所有编辑本就即时生效(自动应用 watch)。 dirty 标记与确认弹窗是冗余的仪式感;undo 栈在自动应用场景下也意义 有限(每次 keystroke 都会 push 历史,栈迅速填满噪声)。移除以降低 复杂度、减少状态字段。
删除的死代码(useCalendar.js)
state.history(快照栈)、state.dirtyMAX_HISTORY常量snapshot()、pushHistory()、restore()undo()action、canUndocomputedmarkSaved()action- 各 action(
organize/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。 - 下载兜底:
onDownload调serialize()序列化当前最新状态。 即便有任何未触发渲染的边界改动,下载时也会被序列化包含。文件名取 原文件名去.ics加.edited.ics。 - occurrences 不持久化:EventModel 不存 occurrences,
OccurrenceGrid渲染时实时调expandOccurrences(ev)计算,toggleOccurrence直接改exdates。无缓存,无不同步风险。
状态字段(重构后)
const state = reactive({
meta: null,
events: [],
selectedUid: null,
fileName: null,
viewMode: 'edit', // 'edit' | 'month' | 'week'
previewDate: todayISO(),
})
无 history、无 dirty、无 redoStack。store 仅承载当前状态与视图锚点。
取消确认弹窗的理由
原 onDownload 在 dirty 时弹「有未保存的更改,仍要下载?」。但自动
应用下,所有更改已在 store 中,下载即序列化 store,不存在「未保存」。
弹窗只会误导用户以为有数据丢失风险。移除后下载是一次性操作。