用华为云码道开发番茄钟让AI完成计时逻辑、状态切换与界面交互深圳技术大学 - 开源代码托管,代码协作 - AtomGit番茄钟专注管理工具:基于原生 HTML/CSS/JavaScript 的专注计时管理项目 - AtomGit很多网页小工具看起来功能并不复杂但真正开始编写之后往往会发现难点并不在页面本身而在不同状态之间的切换。番茄钟就是一个很典型的例子。如果只是做一个显示“25:00”的静态页面用 HTML 和 CSS 很快就能完成。但如果希望它真正能够用于日常学习和工作就需要继续解决开始、暂停、继续、重置、专注与休息自动切换、数据保存等问题。尤其是计时器状态管理稍有疏忽就可能出现连续点击“开始”后倒计时加速、暂停后继续却重新回到 25 分钟、倒计时结束重复触发、刷新页面后今日统计消失等情况。这次我使用华为云码道完成一个可以实际使用的网页番茄钟并把重点放在一个更具体的问题上如何借助 AI 编程工具处理容易出错的计时与状态切换逻辑。整个项目使用原生 HTML、CSS 和 JavaScript 开发不依赖前端框架也不需要数据库。一、确定番茄钟需要实现的功能这次没有加入任务清单、账号系统、云同步等额外功能而是把范围控制在番茄钟最核心的使用流程。最终需要完成这些功能默认专注时间 25 分钟默认休息时间 5 分钟支持开始、暂停、继续和重置专注结束后自动进入休息休息结束后重新进入专注状态每完成一次完整专注今日专注次数自动增加今日完成次数保存在浏览器本地刷新网页后今日统计仍然存在日期发生变化后自动重新统计浏览器标签页标题同步显示剩余时间防止重复启动多个计时器。表面上看都是比较小的功能但它们实际上对应着多个程序状态。例如let currentMode focus; let remainingSeconds 25 * 60; let timerId null; let isRunning false;其中currentMode决定当前处于专注还是休息阶段remainingSeconds保存剩余时间而timerId则用于判断当前是否已经存在正在工作的计时器。只要其中一个变量管理不正确程序的行为就可能出现异常。【图1华为云码道中输入番茄钟完整开发需求的界面】二、让码道先完成第一个可运行版本创建项目以后我把功能需求直接交给华为云码道让它在当前项目中完成 HTML、CSS 和 JavaScript 文件的创建。项目结构比较简单tomato-focus-timer/ ├── index.html ├── style.css ├── script.js └── README.md其中index.html负责页面结构style.css负责视觉效果而真正决定番茄钟是否能够稳定运行的是script.js。码道生成代码后页面已经可以完成基本倒计时。25 分钟会先被转换为秒数const FOCUS_TIME 25 * 60; const BREAK_TIME 5 * 60;然后根据剩余秒数计算分钟和秒数function formatTime(seconds) { const minutes Math.floor(seconds / 60); const secs seconds % 60; return ${String(minutes).padStart(2, 0)}:${String(secs).padStart(2, 0)}; }这样无论剩余时间是多少都可以统一显示成25:00、08:37、00:09这样的格式。三、真正值得检查的是计时器状态第一版能够运行并不意味着开发已经结束。我首先测试了一个非常简单的操作连续快速点击两次“开始”。这其实是 JavaScript 倒计时程序中非常常见的问题。如果每点击一次按钮就直接执行setInterval(...)那么连续点击两次就可能创建两个计时器。正常情况下应该是25:00 24:59 24:58 24:57如果同时运行两个定时器就可能出现倒计时速度异常。所以开始函数不能只是启动setInterval还需要先判断程序当前有没有正在运行的计时器。核心思路类似function startTimer() { if (timerId ! null) { return; } timerId setInterval(() { remainingSeconds--; updateDisplay(); }, 1000); }只有在timerId为空的时候才能创建新的计时器。这一步看似只是增加一个判断却直接决定了整个番茄钟能不能稳定使用。【图2番茄钟运行页面显示“专注中”和 25:00 倒计时】四、暂停和继续不能被当成重新开始接下来测试暂停和继续。假设已经从 25:00 运行到了 18:42。这时点击暂停再等待一段时间然后选择继续。正确结果应该是18:42 18:41 18:40 ……而不是重新变成25:00因此“开始”和“继续”虽然最终都会启动计时器但它们背后的状态并不完全一样。暂停时需要停止定时器但不能修改remainingSeconds。例如function pauseTimer() { clearInterval(timerId); timerId null; isRunning false; }这样暂停以后剩余秒数仍然保存在变量中。再次继续时只需要重新启动计时器而不是重新给remainingSeconds赋值。与此相反“重置”才需要主动恢复时间remainingSeconds currentMode focus ? FOCUS_TIME : BREAK_TIME;这也是我在这次开发中比较明显的一个感受对于这类小型程序代码数量并不大但必须先分清楚不同按钮究竟代表什么状态变化。五、处理 00:00 后的自动状态切换接下来是整个番茄钟最核心的状态切换。专注模式结束以后需要执行几个连续动作专注倒计时结束 ↓ 今日完成次数 1 ↓ 保存今日统计 ↓ 切换为休息模式 ↓ 时间恢复为 05:00 ↓ 继续休息倒计时休息结束后则执行休息倒计时结束 ↓ 切换为专注模式 ↓ 恢复到 25:00为了测试这个过程如果真的等待 25 分钟效率会比较低所以开发阶段可以临时将时间缩短。例如const FOCUS_TIME 10; const BREAK_TIME 5;这样十几秒就可以完整测试一次“专注 → 休息 → 专注”的状态循环。测试通过以后再把时间恢复为const FOCUS_TIME 25 * 60; const BREAK_TIME 5 * 60;相比只阅读代码我更倾向于实际让程序完整运行一次因为很多与时间和状态相关的问题只有在真正执行时才会暴露出来。六、使用 localStorage 保存今日专注次数如果每次刷新网页以后统计数字都重新变成 0这个番茄钟的实用性会明显下降。由于这里保存的只是一个非常简单的当天统计并不需要专门搭建后端服务器或者数据库因此可以直接使用浏览器提供的localStorage。例如保存localStorage.setItem(pomodoroCount, todayCount); localStorage.setItem(pomodoroDate, today);重新打开页面时再读取const savedCount localStorage.getItem(pomodoroCount); const savedDate localStorage.getItem(pomodoroDate);不过只保存次数还不够。如果一直保存同一个数字第二天打开番茄钟以后仍然会看到昨天的数据。因此程序还需要比较当前日期。如果保存日期 今天就继续读取已有统计。如果保存日期 ! 今天则把今日完成次数重新设置为 0并更新保存日期。这样既不需要账号也不需要服务器就能完成一个简单的每日统计功能。七、让浏览器标题也成为倒计时的一部分番茄钟使用过程中我并不一定会始终停留在这个网页。例如专注时可能会切换到文档、代码编辑器或者资料页面。因此我还让页面标题同步显示当前剩余时间document.title ${formatTime(remainingSeconds)} - ${ currentMode focus ? 专注中 : 休息中 };最终即使切换到其他浏览器标签页也可以从顶部标签看到21:36 - 专注中或者03:42 - 休息中这个功能代码很少但实际使用体验提升比较明显。八、把第一版交给码道继续检查第一版完成以后我没有重新创建项目而是直接让码道继续检查当前代码。这一次提出的重点不再是“帮我开发番茄钟”而是非常具体地检查重复点击开始会不会创建多个定时器 暂停以后能否从剩余时间继续 重置以后有没有残留的计时任务 00:00 后状态是否只切换一次 专注次数有没有重复增加 刷新页面以后统计是否保留 日期变化以后能不能自动重新统计这种使用方式和第一次直接生成项目有明显区别。第一次更接近于根据需求完成程序框架而第二次则是让 AI 在已有代码的基础上定位状态管理问题并修改程序。对于逻辑型功能来说后一个过程往往更重要。因为一个程序“可以运行”和“各种操作顺序下都能正确运行”是两件不同的事情。九、最终效果经过测试和修改以后这个番茄钟已经能够完成完整的专注循环。打开页面默认显示专注中 25:00点击开始以后进入倒计时。中途可以暂停再从当前剩余时间继续。专注时间结束以后程序会自动记录一次完成次数并进入 5 分钟休息。休息结束以后重新进入下一轮 25 分钟专注。同时今日完成次数会保存在浏览器本地即使刷新页面也不会消失。十、总结这个项目本身并不庞大但很适合用来理解 AI 编程工具真正能参与哪些开发环节。如果只是让 AI 生成 HTML 和 CSS那么它解决的更多是代码编写效率问题。但在这个番茄钟项目中我更关注的是后续过程先描述需求让码道完成第一版程序然后真正运行程序通过连续点击、暂停恢复、倒计时结束和页面刷新等操作寻找问题再把这些边界情况重新交给码道让它检查已有代码中的计时器和状态管理逻辑。最终完成的并不是一个只有界面的演示页面而是一个可以实际使用的网页番茄钟。这也是这次开发中比较有价值的一点AI 编程不只是把需求转换成代码还可以参与“实现功能—运行测试—发现问题—修改代码”的完整开发过程。对于番茄钟这种代码规模不大、但状态变化比较多的小型项目来说这种方式尤其直观。