diff --git a/README.md b/README.md index 9325f0a..d96cd59 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ timeTableFix/ | Node.js | ≥ 18 | | ical.js | ICS 解析库(npm 依赖) | -> 纯前端应用,无运行期后端依赖。 +> 纯前端应用,无运行期后端依赖。生产部署经 [zMainPage](https://git.zikai.wang/zikai/zMainPage) 作为子模块集成,由其 apache2 静态托管(无独立 apache2 配置);详见 zMainPage 的部署文档。 ## 如何使用 @@ -84,4 +84,5 @@ npm test # 单元测试(57 项) - [时区选择(自动检测 / 回退墨尔本)](./docs/timezone.md) - [间隔合并与链拆分算法](./docs/organize-algorithm.md) - [自动保存设计](./docs/auto-save-design.md) +- [错误处理与日志约定](./docs/error-handling.md) - [初始设计文档](./docs/superpowers/specs/2026-07-13-timetable2-design.md) diff --git a/docs/auto-save-design.md b/docs/auto-save-design.md index cba4625..b83183a 100644 --- a/docs/auto-save-design.md +++ b/docs/auto-save-design.md @@ -61,6 +61,7 @@ const state = reactive({ fileName: null, viewMode: 'edit', // 'edit' | 'month' | 'week' previewDate: todayISO(), + timezone: detectTimezone(), // 日历级默认时区 (新建事件 tzid / X-WR-TIMEZONE) }) ``` diff --git a/docs/error-handling.md b/docs/error-handling.md new file mode 100644 index 0000000..637951c --- /dev/null +++ b/docs/error-handling.md @@ -0,0 +1,25 @@ +# 错误处理与日志约定 + +timeTableFix 的错误处理分两层:纯库函数 fail-fast,UI 层捕获后既写控制台又给用户反馈。 + +## 纯库层(src/lib/) + +- 解析/算法错误直接抛出或返回 `null`,由调用方决定如何反馈。 + - `parseICS`:`ICAL.parse` 对非法文本抛错,向上传播。 + - `splitRecurringEvent` / `fitSeries`:不可处理时返回 `null`(合法的「拒绝」语义)。 + - `getZone`:时区未注册(VTIMEZONE 缺失)时回退 UTC 并 `console.warn`,避免静默时间偏移。 + +## store 层(src/composables/useCalendar.js) + +- `loadFile`:不吞错,`parseICS` 的异常直接 reject 给调用方。 +- `updateEvent` / `splitEvent` / `toggleOccurrence`:uid 不存在视为编程错误,**抛错**而非静默 return。调用方(EventDetail)在调前已校验 `selectedEvent`,正常流程不会触发;触发即暴露 bug。 + +## UI 层(src/components/) + +- 文件解析失败(DropZone / HeaderBar):`.catch` 内 `console.error` 记录原始错误,再用 `alert` 告知用户。 +- 拆分失败(EventDetail `onSplit`):`splitEvent` 抛错被 `try/catch` 捕获,`console.error` + 提示日期无效。 +- 时区检测/列表降级(timezone.js):旧环境 `Intl` 不可用时静默回退墨尔本(有测试覆盖),属可接受的降级。 + +## 控制台前缀 + +所有 `[timeTableFix]` 前缀的日志均来自本子项目,便于在嵌入宿主时与宿主日志区分。 diff --git a/src/components/DropZone.vue b/src/components/DropZone.vue index 0ba76ef..056147d 100644 --- a/src/components/DropZone.vue +++ b/src/components/DropZone.vue @@ -18,6 +18,7 @@ function onDrop(e) { return } loadFile(file).catch((err) => { + console.error('[timeTableFix] 解析 ICS 失败', err) error.value = t('dropzone.parseError') + (err.message || err) }) } @@ -27,6 +28,7 @@ function onPick(e) { const file = e.target.files[0] if (!file) return loadFile(file).catch((err) => { + console.error('[timeTableFix] 解析 ICS 失败', err) error.value = t('dropzone.parseError') + (err.message || err) }) } diff --git a/src/components/EventDetail.vue b/src/components/EventDetail.vue index 7104a83..cb52717 100644 --- a/src/components/EventDetail.vue +++ b/src/components/EventDetail.vue @@ -1,5 +1,5 @@