Skip to content

todo cli.go

文件信息

  • 📄 原文件:01_todo_cli.go
  • 🔤 语言:go

完整代码

go
package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"
)

// ============================================================
//                      小项目1:命令行 Todo 应用
// ============================================================
// 功能:添加、列出、完成、删除待办事项
// 知识点:结构体、切片、文件操作、JSON、用户输入

// Task 待办事项
type Task struct {
	ID        int       `json:"id"`
	Title     string    `json:"title"`
	Completed bool      `json:"completed"`
	CreatedAt time.Time `json:"created_at"`
}

// TodoList 待办列表
type TodoList struct {
	Tasks    []Task `json:"tasks"`
	NextID   int    `json:"next_id"`
	filename string
}

// NewTodoList 创建待办列表
func NewTodoList(filename string) *TodoList {
	tl := &TodoList{
		Tasks:    []Task{},
		NextID:   1,
		filename: filename,
	}
	tl.Load() // 尝试加载已有数据
	return tl
}

// Add 添加任务
func (tl *TodoList) Add(title string) {
	task := Task{
		ID:        tl.NextID,
		Title:     title,
		Completed: false,
		CreatedAt: time.Now(),
	}
	tl.Tasks = append(tl.Tasks, task)
	tl.NextID++
	tl.Save()
	fmt.Printf("✅ 添加任务: [%d] %s\n", task.ID, task.Title)
}

// List 列出所有任务
func (tl *TodoList) List() {
	if len(tl.Tasks) == 0 {
		fmt.Println("📭 没有待办事项")
		return
	}

	fmt.Println("\n📋 待办事项列表:")
	fmt.Println(strings.Repeat("-", 50))

	for _, task := range tl.Tasks {
		status := "[ ]"
		if task.Completed {
			status = "[✓]"
		}
		fmt.Printf("%s %d. %s\n", status, task.ID, task.Title)
	}
	fmt.Println(strings.Repeat("-", 50))
	fmt.Printf("共 %d 项,已完成 %d\n", len(tl.Tasks), tl.CompletedCount())
}

// Complete 完成任务
func (tl *TodoList) Complete(id int) {
	for i := range tl.Tasks {
		if tl.Tasks[i].ID == id {
			tl.Tasks[i].Completed = true
			tl.Save()
			fmt.Printf("✅ 完成任务: [%d] %s\n", id, tl.Tasks[i].Title)
			return
		}
	}
	fmt.Printf("❌ 未找到任务 ID: %d\n", id)
}

// Delete 删除任务
func (tl *TodoList) Delete(id int) {
	for i, task := range tl.Tasks {
		if task.ID == id {
			tl.Tasks = append(tl.Tasks[:i], tl.Tasks[i+1:]...)
			tl.Save()
			fmt.Printf("🗑️  删除任务: [%d] %s\n", id, task.Title)
			return
		}
	}
	fmt.Printf("❌ 未找到任务 ID: %d\n", id)
}

// CompletedCount 已完成数量
func (tl *TodoList) CompletedCount() int {
	count := 0
	for _, task := range tl.Tasks {
		if task.Completed {
			count++
		}
	}
	return count
}

// Save 保存到文件
func (tl *TodoList) Save() error {
	data, err := json.MarshalIndent(tl, "", "  ")
	if err != nil {
		return err
	}
	return os.WriteFile(tl.filename, data, 0644)
}

// Load 从文件加载
func (tl *TodoList) Load() error {
	data, err := os.ReadFile(tl.filename)
	if err != nil {
		return err // 文件不存在时返回错误,但不影响使用
	}
	return json.Unmarshal(data, tl)
}

// runTodoApp 运行 Todo 应用
func runTodoApp() {
	fmt.Println("=== 小项目1: 命令行 Todo 应用 ===")

	// 使用临时文件
	todoList := NewTodoList("todos.json")

	// 演示操作
	fmt.Println("\n--- 演示操作 ---")

	todoList.Add("学习 Go 语言基础")
	todoList.Add("完成 goroutine 练习")
	todoList.Add("阅读 Go 标准库文档")

	todoList.List()

	todoList.Complete(1)
	todoList.Delete(2)

	todoList.List()

	// 清理演示文件
	os.Remove("todos.json")

	// 交互式使用说明
	fmt.Println("\n--- 交互式命令 ---")
	fmt.Println("add <title>  - 添加任务")
	fmt.Println("list         - 列出任务")
	fmt.Println("done <id>    - 完成任务")
	fmt.Println("del <id>     - 删除任务")
	fmt.Println("quit         - 退出")
}

// interactiveTodo 交互式 Todo(可选运行)
func interactiveTodo() {
	todoList := NewTodoList("todos.json")
	scanner := bufio.NewScanner(os.Stdin)

	for {
		fmt.Print("\n> ")
		if !scanner.Scan() {
			break
		}

		input := strings.TrimSpace(scanner.Text())
		parts := strings.SplitN(input, " ", 2)
		cmd := parts[0]

		switch cmd {
		case "add":
			if len(parts) < 2 {
				fmt.Println("用法: add <title>")
				continue
			}
			todoList.Add(parts[1])

		case "list":
			todoList.List()

		case "done":
			if len(parts) < 2 {
				fmt.Println("用法: done <id>")
				continue
			}
			id, _ := strconv.Atoi(parts[1])
			todoList.Complete(id)

		case "del":
			if len(parts) < 2 {
				fmt.Println("用法: del <id>")
				continue
			}
			id, _ := strconv.Atoi(parts[1])
			todoList.Delete(id)

		case "quit", "exit", "q":
			fmt.Println("再见!")
			return

		default:
			fmt.Println("未知命令:", cmd)
		}
	}
}

💬 讨论

使用 GitHub 账号登录后即可参与讨论

基于 MIT 许可发布