# Workbuddy Calendar

> WorkBuddy 侧边栏日历。提供月历视图、日程增删改查、分类标签（开庭/会议/截止日期/个人/研究/其他），支持从对话中提取事件并自动同步到日历。当用户提到"日历""日程""打开日历""添加日程""我的日程""calendar""安排"或询问已记录的日程信息时使用。

- Skill: `cslawyer1985/workbuddy-calendar` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add cslawyer1985/workbuddy-calendar`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cslawyer1985/workbuddy-calendar/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: cslawyer1985 (https://skillmd.com/u/cslawyer1985)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cslawyer1985/workbuddy-calendar

---


# WorkBuddy 侧边栏日历

## Overview

本技能提供一个可视化日历应用，可在 WorkBuddy 侧边栏「预览」标签页中运行。支持月历视图、事件的增删改查、颜色分类标签，以及从对话中自动同步日程事件。数据通过 localStorage 持久化，纯本地运行，无需网络。

## 核心能力

### 1. 打开日历

当用户说「日历」「打开日历」或类似短语时，执行：

1. 检查当前工作区是否已有 `calendar.html` 文件
2. 若无，从 `assets/calendar.html` 复制到工作区根目录
3. 用 `preview_url` 打开该文件（使用绝对文件路径，无需 HTTP 服务器）
4. 日历加载后会自动从嵌入数据中导入对话日程

**重要提示：** 打开日历时，用 `preview_url` 传入文件的绝对路径即可，不要在回复中展示 `file://` 开头的完整路径。只需简洁告知「日历已打开，可在侧边栏查看」。

### 2. 添加对话日程到日历

当用户在对话中口述日程（如「6月20日开庭」「下周三提醒交代理词」）或上传传票/通知书等文件时：

1. 解析出日期、标题、时间、描述、分类等信息
2. 读取工作区 `calendar.html`，找到 `<script id="chat-events-data" type="application/json">` 标签
3. 在该 JSON 数组中追加新事件对象，格式如下：
```json
{
  "id": "chat_NNN",
  "title": "事件标题",
  "date": "YYYY-MM-DD",
  "time": "HH:MM",
  "desc": "详细描述",
  "color": "#ef4444",
  "source": "chat"
}
```
4. 递增 id 序号（如已存在 chat_001、chat_002，则新建 chat_003）
5. 同时更新 `calendar-events.json` 保持一致（如有该文件）
6. 告知用户：「已写入日历，点击 📥 导入 即可同步」

**颜色分类映射：**
| 类型 | 颜色 | 色值 |
|------|------|------|
| 开庭/诉讼/仲裁 | 红色 | `#ef4444` |
| 会议/会面/出差 | 蓝色 | `#3b82f6` |
| 截止日期/到期 | 橙色 | `#f59e0b` |
| 个人/生活 | 绿色 | `#10b981` |
| 研究/写作/学习 | 紫色 | `#8b5cf6` |
| 其他/默认 | 灰色 | `#6b7280` |

### 2.1 在对话中修改日程

当用户在对话中要求修改某个日程（如「把6月20日的开庭改成6月21日」「修改chat_002的时间为10:00」「把开庭颜色改成蓝色」）时：

1. 读取工作区 `calendar.html`，找到 `<script id="chat-events-data" type="application/json">` 标签
2. 解析 JSON 数组，找到目标事件（按 id 或按 title + date 匹配）
3. 修改对应字段（title、date、time、desc、color 等）
4. 写回 HTML 文件
5. 告知用户：「已更新日程，点击 📥 导入 即可同步到日历」
6. 如果目标事件来自对话添加（source=chat）但已被用户导入到 localStorage，需提醒用户：「该日程可能已在日历中手动修改过，导入时将覆盖本地修改」

**匹配规则：**
- 优先按 `id`（如 `chat_002`）精确匹配
- 若无 id，按 `title` + `date` 模糊匹配（取第一个匹配项）
- 若匹配不到，告知用户未找到对应日程

### 2.2 在对话中删除日程

当用户在对话中要求删除某个日程（如「删除chat_001」「把下周三的会议删掉」「取消开庭日程」）时：

1. 读取工作区 `calendar.html`，找到 `<script id="chat-events-data" type="application/json">` 标签
2. 解析 JSON 数组，找到目标事件（匹配规则同 2.1）
3. 从数组中移除该事件
4. 写回 HTML 文件
5. 告知用户：「已从对话日程中删除，日历中的本地日程需手动删除（点击日程 → 编辑 → 删除日程）」

**重要提示：** 对话删除仅移除 `chat-events-data` 中的条目，不会自动删除 localStorage 中已导入的本地日程。用户需要在日历 UI 中手动删除对应的本地条目。

### 3. 查询日历中的日程

当用户询问「XX哪天开庭」「XX事件什么时候」「今天有什么安排」「这周有什么日程」等问题时：

1. 读取 `calendar.html` 中 `<script id="chat-events-data">` 的 JSON 数组
2. 结合对话上下文中已告知的信息
3. 用自然语言回答用户，包含日期、时间、地点等关键信息

### 4. 日历功能概览

日历 HTML 应用本身提供以下交互功能（用户手动操作）：

#### 方式一：在日历 UI 中直接编辑

- **新建日程**：点击日历上的日期 → 点击「＋ 新建」按钮 → 填写标题、日期、时间、分类颜色、备注 → 点击「保存」。新建的日程自动保存到 localStorage。
- **编辑日程**：在左侧事件列表中点击对应条目 → 弹出编辑窗口 → 修改任意字段（标题、日期、时间、颜色、备注）→ 点击「保存」。修改立即生效并持久化。
- **删除日程**：点击日程打开编辑弹窗 → 点击左下角红色「删除日程」按钮 → 弹出确认对话框显示日程标题 → 点击「确定删除」按钮确认。删除后：
  - 从 localStorage 中移除该日程
  - 同步更新 `chat_imported` 记录，防止重新导入时复活
  - 弹窗自动关闭，日历和侧边栏即时刷新
- **快捷操作**：点击日历日期即可筛选当天所有日程，在左侧面板中一目了然

**删除功能注意事项：**
- 删除操作不可恢复，确认对话框会显示日程标题以供确认
- 确认对话框是自定义 UI 组件（非浏览器原生 `confirm()`），兼容嵌入式 WebView 环境
- 支持键盘操作：`Enter` 确认删除，`Esc` 取消
- 点击遮罩层也可关闭确认对话框
- 删除已导入的对话日程后，需重新点击 📥 导入才能再次导入（因为 `chat_imported` 记录已清除）
- 如果删除的是对话日程（source=chat），仅删除 localStorage 中的副本，`chat-events-data` 中的原始数据不变
- **实现细节：** `deleteEvent()` 中使用局部变量 `idToDelete` 立即捕获 `editingId` 的值，避免因 `doCloseModal()` 异步重置 `editingId` 导致闭包引用失效（删除无效）

#### 方式二：在 WorkBuddy 对话中发指令

- **添加日程**：口述日程信息（如「6月20日开庭」），AI 自动解析并写入 `chat-events-data`。用户在日历中点击 📥 导入即可同步。
- **修改日程**：发出修改指令（如「把 chat_002 的时间改成 10:00」），AI 更新 `chat-events-data` 中对应条目。用户点击 📥 导入后覆盖本地日程。
- **删除日程**：发出删除指令（如「删除 chat_001」），AI 从 `chat-events-data` 中移除。注意：这仅删除对话数据源中的条目，已导入到 localStorage 的本地日程需用户在日历 UI 中手动删除。
- **查询日程**：询问「今天有什么安排」「这周有什么日程」，AI 从 `chat-events-data` 和对话上下文中检索并回答。

**对话操作与日历 UI 的协作流程：**
1. 用户在对话中口述 → AI 写入 `chat-events-data` → 用户在日历中点击 📥 导入 → 数据进入 localStorage
2. 用户在日历 UI 中手动操作 → 直接读写 localStorage → 不修改 `chat-events-data`
3. 两个数据源相互独立，通过 📥 导入按钮桥接

#### 其他功能

- **月历视图**：左侧大日历，当前日期蓝色高亮
- **颜色分类**：六种颜色标签，顶部可点击筛选
- **月导航**：◀ ▶ 箭头切换，「今天」按钮回当月
- **快捷键**：`Ctrl/Cmd+N` 新建、`← →` 翻月、`Esc` 关闭弹窗
- **自定义对话框**：确认删除和提示信息均使用自定义 UI 组件（非浏览器原生 `alert`/`confirm`），确保在 WorkBuddy 嵌入式 WebView 中可靠运行

## 技术实现说明

- **事件绑定**：所有按钮均通过 `addEventListener` 绑定事件（不使用内联 `onclick` 属性），避免 ID 注入问题和事件冒泡异常
- **确认对话框**：使用自定义 HTML 弹窗替代原生 `confirm()`，支持键盘快捷键（Enter 确认 / Esc 取消）和遮罩层点击关闭
- **事件委托**：侧边栏日程列表使用事件委托（`data-event-id` 属性 + 父容器 click 监听），安全可靠

## 数据持久化说明

- 用户在日历 UI 中手动添加的事件：存于浏览器 `localStorage`（`workbuddy_calendar_events`）
- AI 从对话中提取的事件：嵌入在 HTML 的 `<script id="chat-events-data">` 中
- 双源合并：日历加载时自动从嵌入数据导入，按 id 去重，合并到 localStorage
- 已导入 id 记录在 `localStorage` 的 `workbuddy_calendar_chat_imported` 中，避免重复导入

## 资源

### assets/calendar.html

完整的日历 HTML 应用，包含月历视图、事件管理、颜色分类、导入机制。部署到工作区后可通过 WorkBuddy 侧边栏预览标签页打开，无需任何服务器或外部依赖。

