zikai e9fc10c89d fix: WEEKLY 事件的 BYDAY 与 dtstartDate 不一致导致 ICS 输出错误
applyChanges 中 BYDAY 此前取自表单下拉框(默认 'MO'), 与 dtstartDate
的星期可能不一致。expandOccurrences 按 dtstartDate 展开 occurrence,
但序列化的 RRULE 写入表单选择的 BYDAY, 两者不匹配时日历应用会显示
错误的星期。

修复: BYDAY 始终由 dtstartDate 的星期自动推导(bydayFromDate), 下拉框
改为只读展示。确保 RRULE BYDAY 与实际 occurrence 日期始终一致。
2026-07-22 02:45:04 +00:00
2026-07-13 17:31:43 +08:00

timeTableFix - 纯前端 ICS 日历整理器

浏览器内解析、去重、编辑 ICS 日历文件,全程无需后端服务。拖入 .ics -> 整理去重 -> 编辑 -> 下载。

功能

  • 📥 拖入即用:拖拽或选择 .ics 文件,浏览器内直接解析
  • 🔁 智能去重:自动检测重复模式,将扁平事件合并为 RRULE 重复事件 + EXDATE
  • ✏️ 可视化编辑:编辑标题/地点/时间/重复规则,点击网格切换排除日期
  • ✂️ 拆分事件:把一个重复事件按日期拆成前后两段
  • 增删事件:新增单次/重复事件,删除任意事件
  • ↶ 撤销重做:快照式 undo/redo最多 50 步
  • ⬇️ 导出 ICS下载整理后的 .ics,可直接导入日历应用

项目结构

timeTableFix/
├── index.html                  Vite 入口
├── package.json
├── vite.config.js              构建配置(含 preview.allowedHosts
├── vitest.config.js
├── .npmrc                      npmmirror 镜像加速
├── src/
│   ├── main.js                 应用挂载
│   ├── App.vue                 布局装配
│   ├── composables/
│   │   └── useCalendar.js      中心 store + 快照 undo/redo
│   ├── lib/
│   │   ├── weekday.js          星期常量与工具
│   │   ├── date.js             日期工具
│   │   ├── ical-io.js          ICS 文本 <-> plain model
│   │   ├── recur.js            RRULE 网格展开
│   │   ├── organize.js         GCD 去重算法
│   │   ├── event-factory.js    事件构造工厂
│   │   └── split.js            事件拆分逻辑
│   └── components/
│       ├── HeaderBar.vue       顶栏:整理/撤销/重做/导入/下载
│       ├── DropZone.vue        拖拽/选择文件
│       ├── EventList.vue       侧栏事件列表
│       ├── EventDetail.vue     编辑表单 + 拆分
│       └── OccurrenceGrid.vue  排除日期网格
├── test/                       Vitest 单元测试
│   ├── golden-org.ics          测试用例61 事件的真实课表)
│   ├── weekday.test.js
│   ├── ical-io.test.js
│   ├── recur.test.js
│   └── organize.test.js
└── docs/                       设计文档

Ubuntu 从零安装

1. 安装 Node.js 18+

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
node --version   # 确认 v18.x

2. 克隆并安装依赖

git clone https://git.zikai.wang/zikai/timeTableFix.git
cd timeTableFix
npm install        # 已配 npmmirror 镜像加速

3. 构建生产版本

npm run build      # 产物输出到 dist/
npm test           # (可选)运行单元测试

4. 部署为系统服务systemd

创建服务文件 /etc/systemd/system/timetable-fix.service

[Unit]
Description=timeTableFix ICS Calendar Organizer
After=network.target

[Service]
Type=simple
WorkingDirectory=/path/to/timeTableFix
ExecStart=/path/to/timeTableFix/node_modules/.bin/vite preview --host 0.0.0.0 --port 8888
Restart=on-failure
RestartSec=3
Environment=NODE_ENV=production
StandardOutput=append:/var/log/timetable-preview.log
StandardError=append:/var/log/timetable-preview.log

[Install]
WantedBy=multi-user.target

将上述 WorkingDirectoryExecStart 中的路径替换为实际的 timeTableFix 绝对路径。

加载并启动:

sudo systemctl daemon-reload
sudo systemctl enable --now timetable-fix

5. 放行防火墙端口

sudo ufw allow 8888/tcp

浏览器访问 http://<服务器IP>:8888 即可。若通过域名访问(如 f.zikai.wang),需在 vite.config.jspreview.allowedHosts 中添加该域名。

使用(启动 / 关闭)

服务由 systemd 管理,开机自启、崩溃自动恢复。

# 启动
sudo systemctl start timetable-fix

# 关闭
sudo systemctl stop timetable-fix

# 重启
sudo systemctl restart timetable-fix

# 查看状态
sudo systemctl status timetable-fix

# 查看日志
tail -f /var/log/timetable-preview.log

开发模式(无需 systemd前台运行

cd timeTableFix
npm run dev       # http://localhost:5173

技术栈

选择
框架 Vue 3.5SFC<script setup>
构建 Vite 6
ICS 库 ical.js 2.x
状态管理 composable 单例 store
测试 Vitest
包源 npmmirror.com中国镜像加速
Description
No description provided
Readme 377 KiB
Languages
JavaScript 59.7%
Vue 38.7%
CSS 1.3%
HTML 0.3%