Microsoft ToDo月视图看板
市面上的任务管理工具,但凡带个日历视图、数据导出功能,不是按月收费就是按年订阅。自己动手,用 Microsoft Graph API 一小时就能搭一个专属的 To Do 看板——月视图、周视图、CSV 导出,全部免费,数据还留在自己手里。
为什么做这个?
Microsoft To Do 本身非常轻量,但缺少一个直观的月视图/周视图。你只能按列表查看任务,无法一眼看出哪天有哪些事、哪些已经完成。更别说导出数据做周报、月报了。
市面上的“日历+任务”类应用,像 Todoist、TickTick 的高级版确实提供日历视图,但都放在了付费墙后面。对于个人开发者或者小团队,为了一个视图功能去订阅并不划算。
于是我花了一个晚上,基于 Microsoft Graph API 和纯前端技术,写了一个完全免费的 To Do 看板。它支持:
- 月视图(周一为起始,符合国内习惯)
- 周视图(显示 ISO 周数,每天的任务完成比例)
- 一键导出 CSV(按时间排序,包含创建时间、完成时间、备注等字段)
- 切换账号、实时统计(全部任务/已完成数量)
而且个人 Microsoft 账号(outlook.com、hotmail.com)和 E5 订阅账号都可以直接使用。
技术选型
| 需求 | 技术方案 |
|---|---|
| 登录与授权 | MSAL.js (Microsoft Authentication Library) |
| 获取任务数据 | Microsoft Graph API (/me/todo/lists 和 /tasks) |
| 日历渲染 | 手写 HTML/CSS/JS(轻量,不依赖第三方库) |
| 数据导出 | 动态生成 CSV 文件,浏览器下载 |
| 性能优化 | 并行请求 + 限流控制 |
之所以不直接用 FullCalendar 等现成库,是为了完全控制 UI 样式,并且避免额外的依赖加载。
核心功能实现
1. 登录与权限
使用 MSAL.js 实现 OAuth 2.0 授权码流(PKCE)。只需要在 Azure AD 中注册一个应用,配置重定向 URI 为 SPA 类型,然后请求 Tasks.Read 和 User.Read 权限即可。
const msalConfig = {
auth: {
clientId: '你的客户端ID',
authority: 'https://login.microsoftonline.com/common',
redirectUri: window.location.origin
}
};
const loginRequest = { scopes: ['Tasks.Read', 'User.Read'] };
个人账号注意:Azure 应用注册时,必须选择“任何组织目录中的帐户和个人 Microsoft 帐户”,否则个人账号无法登录。
2. 获取所有任务
Microsoft To Do 的数据模型是:用户有多个任务列表,每个列表下有多个任务。所以需要两步:
- 请求
GET /me/todo/lists获取所有列表。 - 对每个列表请求
GET /me/todo/lists/{id}/tasks?$top=500获取其中的任务。
性能瓶颈:如果列表较多(比如十几个),串行请求会非常慢(每个请求约 200~300ms,总耗时 = 列表数 × 单次耗时)。例如 16 个列表,串行需要 5 秒左右。
3. 并行请求 + 限流处理
为了提速,我们使用 Promise.all 并发请求,但并发量过大会触发 Microsoft Graph 的限流(HTTP 429)。解决方案是限制并发数,同时加入简单的重试机制。
// 限制同时最多 3 个请求
async function asyncPool(poolLimit, array, iteratorFn) {
// 实现略
}
const fetchListTasks = async (list) => {
// 遇到 429 则等待 Retry-After 秒后重试
};
const results = await asyncPool(3, lists, fetchListTasks);
实测并发数 3 时,16 个列表的加载时间从 5 秒降到 1.2 秒左右,且不会触发限流。
4. 月视图实现(周一为起始)
纯手写一个日历表格,关键点在于计算每月第一天是周几,并转换为周一为起始的索引。
let startWeekday = firstDay.getDay(); // 0=周日
startWeekday = (startWeekday === 0 ? 6 : startWeekday - 1); // 周一=0, 周日=6
然后生成 42 个格子(6 行×7 列),根据日期填充任务。每个格子内显示当天任务列表,按“进行中 → 已完成”排序。
5. 周视图与 ISO 周数
周视图展示当前周的 7 天,每天的任务以列表形式纵向排列。为了显示“第几周”,实现了一个 ISO 周数计算函数(根据周一为一周的第一天)。
function getWeekNumber(date) {
// 国际标准 ISO 8601 周数算法
}
6. CSV 导出
导出功能是看板的重要补充。将当前显示的任务(全部/本月/本周)转换为 CSV 格式,并自动下载。
- 排序:按显示日期(北京时间)从早到晚,同一天内按创建时间升序。
- 字段:创建日期、创建时间、状态、重要标记、销售(任务列表名)、任务内容、完成日期、备注。
- 文件名:
任务导出_账号_范围_时间戳.csv,避免覆盖。
7. 时区处理
Graph API 返回的时间是 UTC 格式(例如 2026-04-17T07:55:54Z)。为了正确显示北京时间(UTC+8),我们在前端进行转换:
function utcToBeijing(utcDateStr) {
const date = new Date(utcDateStr);
return new Date(date.getTime() + 8 * 3600 * 1000);
}
这样任务显示日期和详情弹窗的时间都与本地一致。
遇到的坑与解决
1. MSAL 弹窗被拦截
某些浏览器会阻止跨域弹窗。解决方案是在用户点击“登录”按钮时再调用 loginPopup,而不是页面加载时自动弹出。
2. 令牌过期
acquireTokenSilent 可能因会话过期失败,此时需要回退到 acquireTokenPopup 重新交互登录。
3. Graph API 字段不存在
尝试使用 $select 只获取必要字段(如 dueDateTime)时,可能会返回 invalidRequest。稳妥做法是先不筛选,后续再优化。
4. 并行请求限流
如上所述,必须控制并发数。我们用了 3 个并发,并加入指数退避重试(实际只重试一次就够)。
成果展示
最终实现的效果:
- 月视图:清晰展示整个月的任务分布,每天右上角显示
已完成/总数。 - 周视图:以表格形式展示本周七天,每行一个任务,每天下方显示
📋 已完成/总数。 - 统计卡片:顶部显示全部任务总数和已完成数。
- 导出:一键导出 CSV,可用 Excel 打开。
- 切换账号:一键登出并返回登录页,支持多账号切换。
性能数据
| 数据规模 | 列表数 | 串行耗时 | 并行+限流耗时 |
|---|---|---|---|
| 6天 107条 | 16 | ~5.0 秒 | ~1.2 秒 |
| 1个月 900条 | 16 | ~5.2 秒 | ~1.3 秒 |
| 1年 1万条 | 16 | ~5.5 秒 | ~1.5 秒 |
可见,请求次数是瓶颈,而非数据量。通过并行请求优化后,即使一年上万条任务,也能在 2 秒内完成加载。
开源与自定义
这个看板的所有代码都是纯前端的,你可以任意修改样式、增加字段、调整布局。唯一的“秘密”是你在 Azure 注册的应用客户端 ID,这个公开也无妨(因为重定向 URI 白名单和权限范围保证了安全)。
如果你想快速体验,只需:
- 在 Azure 注册一个应用,启用“个人帐户”支持。
- 添加重定向 URI 为你的本地地址(如
http://localhost:3000)。 - 将代码中的
CLIENT_ID替换成你自己的。 - 用任意静态服务器打开 HTML 文件。
全程不需要任何后端,数据直接从 Microsoft Graph 获取,安全又隐私。
总结
从想法到落地,这个 To Do 看板只用了不到一天。它证明了:通过开放的 API,开发者完全可以绕过付费工具的壁垒,自己打造满足特定需求的工具。
如果你也觉得任务管理工具的付费功能不够“值”,不妨试试这种 DIY 思路。技术栈简单(HTML + JS + MSAL),部署零成本,还能学到 OAuth 2.0、并行请求优化等实用技能。
最后,所有代码已整理成单个 HTML 文件,鉴于篇幅就不再贴了。
本文仅作技术分享,不涉及任何商业推广。使用 Microsoft Graph API 请遵守微软服务条款。
评论功能已关闭