从零开始打造一个「个人番茄钟与任务管理」Web 应用

看完就能上手


🎯 适合人群

  • 掌握基础 HTML/CSS/JavaScript
  • 了解 Vue/Node.js 基本语法
  • 想通过完整项目打通前后端、提升工程化思维的开发者

📦 完整源码

文末附 GitHub 仓库地址,Star 收藏防丢失,跟着写一遍胜过看十篇理论。


📖 项目介绍

这是一个全栈轻量级个人效率工具,核心解决三个痛点:

  1. 专注计时:25分钟工作 + 5分钟休息的番茄钟,自动循环切换。
  2. 任务管理:支持待办任务的增删改查、完成状态标记、与当前番茄钟绑定。
  3. 数据持久化:本地刷新不丢失,支持一键导出备份。

🛠 技术栈

  • 前端:Vue 3 (Composition API) + Vite + TailwindCSS
  • 后端:Node.js + Express + better-sqlite3
  • 部署:Docker + Nginx + PM2

🖥 最终效果

  • 响应式深色/浅色 UI
  • 流畅的倒计时动画
  • 实时同步任务状态
  • 支持本地与云端双模式切换
  • 整体打包体积 < 50KB,首屏加载 < 1s

🛠 环境搭建

我们采用前后端分离架构,先初始化项目目录并安装核心依赖。

# 创建项目根目录
mkdir pomodoro-app && cd pomodoro-app

# 前端初始化
npm create vite@latest client -- --template vue-ts
cd client && npm install && npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
cd ..

# 后端初始化
mkdir server && cd server
npm init -y
npm install express cors better-sqlite3 dotenv
npm install -D nodemon typescript ts-node @types/express @types/node

✅ 配置提示

server/tsconfig.json 中开启 "esModuleInterop": true,确保 better-sqlite3 正常导入。前后端均配置 tsconfig.json 避免类型漂移。


🧩 核心功能实现


🔹 功能 1:番茄钟计时器核心逻辑

需求分析:需要实现倒计时、暂停/继续、工作/休息自动切换,且组件卸载时自动清理定时器,防止内存泄漏。

代码文件src/composables/usePomodoro.ts

import { ref, onUnmounted } from 'vue'

export function usePomodoro() {
  const timeLeft = ref(25 * 60)
  const isRunning = ref(false)
  const mode = ref<'work' | 'break'>('work')
  let timer: number | null = null

  const toggle = () => {
    isRunning.value ? pause() : start()
  }

  const start = () => {
    if (timer) return
    isRunning.value = true
    timer = window.setInterval(() => {
      timeLeft.value--
      if (timeLeft.value <= 0) {
        mode.value = mode.value === 'work' ? 'break' : 'work'
        timeLeft.value = mode.value === 'work' ? 25 * 60 : 5 * 60
        pause()
      }
    }, 1000)
  }

  const pause = () => {
    if (timer) {
      clearInterval(timer)
      timer = null
      isRunning.value = false
    }
  }

  const reset = () => {
    pause()
    mode.value = 'work'
    timeLeft.value = 25 * 60
  }

  onUnmounted(() => pause()) // 组件销毁时清理定时器

  return { timeLeft, isRunning, mode, toggle, pause, reset }
}

💡 亮点:采用 Composable 封装,状态与视图解耦,可复用到其他页面。


🔹 功能 2:任务列表增删改与状态管理

需求分析:提供任务数组响应式管理,支持添加新任务、切换完成状态、删除,并实时过滤“进行中”任务。

代码文件src/components/TaskList.vue(核心逻辑片段)

<script setup lang="ts">
import { ref, computed } from 'vue'

interface Task {
  id: number
  title: string
  completed: boolean
}

const tasks = ref<Task[]>([])
const newTask = ref('')

const activeTasks = computed(() => tasks.value.filter(t => !t.completed))
const completedCount = computed(() => tasks.value.filter(t => t.completed).length)

const addTask = () => {
  if (!newTask.value.trim()) return
  tasks.value.push({ id: Date.now(), title: newTask.value, completed: false })
  newTask.value = ''
}

const toggleTask = (id: number) => {
  const task = tasks.value.find(t => t.id === id)
  if (task) task.completed = !task.completed
}

const removeTask = (id: number) => {
  tasks.value = tasks.value.filter(t => t.id !== id)
}
</script>

💡 亮点:利用 computed 自动派生状态,避免手动维护冗余变量;配合 Tailwind 可快速实现交互动画。


🔹 功能 3:后端 API 与 SQLite 数据持久化

需求分析:提供 RESTful API 接收前端任务数据,使用轻量级 SQLite 实现本地持久化,支持跨域请求与基础错误处理。

代码文件server/src/index.ts

import express from 'express'
import cors from 'cors'
import Database from 'better-sqlite3'

const app = express()
const db = new Database('tasks.db')
app.use(cors())
app.use(express.json())

// 初始化表
db.prepare(`
  CREATE TABLE IF NOT EXISTS tasks (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT NOT NULL,
    completed INTEGER DEFAULT 0,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
  )
`).run()

app.get('/tasks', (_, res) => {
  const tasks = db.prepare('SELECT * FROM tasks ORDER BY created_at DESC').all()
  res.json(tasks.map(t => ({ ...t, completed: Boolean(t.completed) })))
})

app.post('/tasks', (req, res) => {
  const { title } = req.body
  if (!title) return res.status(400).json({ error: 'Title required' })
  const info = db.prepare('INSERT INTO tasks (title) VALUES (?)').run(title)
  res.status(201).json({ id: info.lastInsertRowid, title, completed: false })
})

app.put('/tasks/:id', (req, res) => {
  const { completed } = req.body
  db.prepare('UPDATE tasks SET completed = ? WHERE id = ?').run(Number(completed), Number(req.params.id))
  res.json({ success: true })
})

app.listen(3000, () => console.log('🚀 Server running on http://localhost:3000'))

💡 亮点better-sqlite3 同步 API 性能更高,代码更简洁;生产环境建议替换为异步驱动或 PostgreSQL。


🚀 项目部署

我们将前后端打包,使用 Docker Compose 一键部署到云服务器(如阿里云/腾讯云)。

代码文件docker-compose.yml

version: '3.8'
services:
  backend:
    build: ./server
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    volumes:
      - db-data:/app/data
    restart: always

  frontend:
    build: ./client
    ports:
      - "80:80"
    depends_on:
      - backend
    restart: always

volumes:
  db-data:

📦 配合 Dockerfile:后端使用 node:20-alpine 多阶段构建,前端使用 nginx:alpine 托管静态文件。执行 docker compose up -d 即可完成生产级部署,自带健康检查与自动重启。


🔮 扩展方向(你的下一步)

这个项目已经具备完整的工程骨架,你可以按以下路线持续迭代,打造个人作品集:

  1. 用户系统:接入 JWT + 邮箱登录,实现多端数据同步。
  2. PWA 支持:添加 vite-plugin-pwa,实现离线可用与桌面安装。
  3. 数据统计:集成 Chart.js,展示每日专注时长折线图、任务完成率雷达图。
  4. AI 增强:调用大模型 API,实现“智能任务拆解”、“专注力语音提醒”。
  5. CI/CD 流水线:配置 GitHub Actions,代码 push 后自动测试、构建、部署。

🤝 写在最后

实战项目是打破“收藏等于学会”魔咒的最佳武器。这篇文章只展示了核心骨架,完整可运行代码、UI 主题切换逻辑、环境变量配置、详细部署文档已开源至 GitHub。

📌 如何获取完整源码?

关注本公众号/专栏,回复关键词 番茄钟 即可获取 GitHub 仓库直链。已 Star 的同学可在 Issues 提交你的优化 PR,我会亲自 Code Review 并合并。

💬 互动话题

你在做项目时最常卡在哪个环节?环境配置、状态管理还是部署?留言区告诉我,下期针对性拆解。

⭐ 星标/订阅

每周更新一个“从零到一”高转化实战项目,不卷理论,只写能跑、能部署、能写进简历的代码。


下一期预告:《手把手教你用 Rust + WebAssembly 给前端提速 300% 的完整实战》

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐