357 lines
7.7 KiB
Go
357 lines
7.7 KiB
Go
/*
|
|
todo.go - 待办事项数据结构
|
|
定义了任务的基本数据结构和相关方法
|
|
*/
|
|
|
|
package todo
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Priority 任务优先级
|
|
type Priority int
|
|
|
|
const (
|
|
Low Priority = iota
|
|
Medium
|
|
High
|
|
Urgent
|
|
)
|
|
|
|
// String 返回优先级的字符串表示
|
|
func (p Priority) String() string {
|
|
switch p {
|
|
case Low:
|
|
return "低"
|
|
case Medium:
|
|
return "中"
|
|
case High:
|
|
return "高"
|
|
case Urgent:
|
|
return "紧急"
|
|
default:
|
|
return "未知"
|
|
}
|
|
}
|
|
|
|
// Task 表示一个待办事项
|
|
type Task struct {
|
|
ID int `json:"id"` // 任务ID
|
|
Content string `json:"content"` // 任务内容
|
|
Completed bool `json:"completed"` // 是否完成
|
|
Priority Priority `json:"priority"` // 优先级
|
|
CreatedAt time.Time `json:"created_at"` // 创建时间
|
|
UpdatedAt time.Time `json:"updated_at"` // 更新时间
|
|
CompletedAt *time.Time `json:"completed_at,omitempty"` // 完成时间
|
|
Tags []string `json:"tags,omitempty"` // 标签
|
|
Description string `json:"description,omitempty"` // 详细描述
|
|
}
|
|
|
|
// NewTask 创建新的任务
|
|
func NewTask(id int, content string) *Task {
|
|
now := time.Now()
|
|
return &Task{
|
|
ID: id,
|
|
Content: content,
|
|
Completed: false,
|
|
Priority: Medium,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
Tags: make([]string, 0),
|
|
}
|
|
}
|
|
|
|
// Complete 标记任务为完成
|
|
func (t *Task) Complete() {
|
|
if !t.Completed {
|
|
t.Completed = true
|
|
now := time.Now()
|
|
t.CompletedAt = &now
|
|
t.UpdatedAt = now
|
|
}
|
|
}
|
|
|
|
// Uncomplete 标记任务为未完成
|
|
func (t *Task) Uncomplete() {
|
|
if t.Completed {
|
|
t.Completed = false
|
|
t.CompletedAt = nil
|
|
t.UpdatedAt = time.Now()
|
|
}
|
|
}
|
|
|
|
// Update 更新任务内容
|
|
func (t *Task) Update(content string) {
|
|
if content != "" && content != t.Content {
|
|
t.Content = content
|
|
t.UpdatedAt = time.Now()
|
|
}
|
|
}
|
|
|
|
// SetPriority 设置任务优先级
|
|
func (t *Task) SetPriority(priority Priority) {
|
|
if priority != t.Priority {
|
|
t.Priority = priority
|
|
t.UpdatedAt = time.Now()
|
|
}
|
|
}
|
|
|
|
// AddTag 添加标签
|
|
func (t *Task) AddTag(tag string) {
|
|
if tag == "" {
|
|
return
|
|
}
|
|
|
|
// 检查标签是否已存在
|
|
for _, existingTag := range t.Tags {
|
|
if existingTag == tag {
|
|
return
|
|
}
|
|
}
|
|
|
|
t.Tags = append(t.Tags, tag)
|
|
t.UpdatedAt = time.Now()
|
|
}
|
|
|
|
// RemoveTag 移除标签
|
|
func (t *Task) RemoveTag(tag string) {
|
|
for i, existingTag := range t.Tags {
|
|
if existingTag == tag {
|
|
t.Tags = append(t.Tags[:i], t.Tags[i+1:]...)
|
|
t.UpdatedAt = time.Now()
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// HasTag 检查是否包含指定标签
|
|
func (t *Task) HasTag(tag string) bool {
|
|
for _, existingTag := range t.Tags {
|
|
if existingTag == tag {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// SetDescription 设置任务描述
|
|
func (t *Task) SetDescription(description string) {
|
|
if description != t.Description {
|
|
t.Description = description
|
|
t.UpdatedAt = time.Now()
|
|
}
|
|
}
|
|
|
|
// String 返回任务的字符串表示
|
|
func (t *Task) String() string {
|
|
status := "⏳"
|
|
if t.Completed {
|
|
status = "✅"
|
|
}
|
|
|
|
return fmt.Sprintf("[%d] %s %s (优先级: %s)",
|
|
t.ID, status, t.Content, t.Priority)
|
|
}
|
|
|
|
// DetailedString 返回任务的详细字符串表示
|
|
func (t *Task) DetailedString() string {
|
|
status := "待完成"
|
|
if t.Completed {
|
|
status = "已完成"
|
|
}
|
|
|
|
result := fmt.Sprintf("任务 #%d\n", t.ID)
|
|
result += fmt.Sprintf("内容: %s\n", t.Content)
|
|
result += fmt.Sprintf("状态: %s\n", status)
|
|
result += fmt.Sprintf("优先级: %s\n", t.Priority)
|
|
result += fmt.Sprintf("创建时间: %s\n", t.CreatedAt.Format("2006-01-02 15:04:05"))
|
|
result += fmt.Sprintf("更新时间: %s\n", t.UpdatedAt.Format("2006-01-02 15:04:05"))
|
|
|
|
if t.Completed && t.CompletedAt != nil {
|
|
result += fmt.Sprintf("完成时间: %s\n", t.CompletedAt.Format("2006-01-02 15:04:05"))
|
|
}
|
|
|
|
if t.Description != "" {
|
|
result += fmt.Sprintf("描述: %s\n", t.Description)
|
|
}
|
|
|
|
if len(t.Tags) > 0 {
|
|
result += fmt.Sprintf("标签: %v\n", t.Tags)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// IsOverdue 检查任务是否过期(如果有截止日期的话)
|
|
func (t *Task) IsOverdue() bool {
|
|
// 这里可以扩展添加截止日期功能
|
|
return false
|
|
}
|
|
|
|
// Age 返回任务的存在时间
|
|
func (t *Task) Age() time.Duration {
|
|
return time.Since(t.CreatedAt)
|
|
}
|
|
|
|
// CompletionTime 返回任务的完成耗时
|
|
func (t *Task) CompletionTime() time.Duration {
|
|
if !t.Completed || t.CompletedAt == nil {
|
|
return 0
|
|
}
|
|
return t.CompletedAt.Sub(t.CreatedAt)
|
|
}
|
|
|
|
// Clone 创建任务的副本
|
|
func (t *Task) Clone() *Task {
|
|
clone := *t
|
|
|
|
// 深拷贝切片
|
|
if len(t.Tags) > 0 {
|
|
clone.Tags = make([]string, len(t.Tags))
|
|
copy(clone.Tags, t.Tags)
|
|
}
|
|
|
|
// 深拷贝时间指针
|
|
if t.CompletedAt != nil {
|
|
completedAt := *t.CompletedAt
|
|
clone.CompletedAt = &completedAt
|
|
}
|
|
|
|
return &clone
|
|
}
|
|
|
|
// Validate 验证任务数据的有效性
|
|
func (t *Task) Validate() error {
|
|
if t.ID <= 0 {
|
|
return fmt.Errorf("任务ID必须大于0")
|
|
}
|
|
|
|
if t.Content == "" {
|
|
return fmt.Errorf("任务内容不能为空")
|
|
}
|
|
|
|
if t.Priority < Low || t.Priority > Urgent {
|
|
return fmt.Errorf("无效的优先级")
|
|
}
|
|
|
|
if t.CreatedAt.IsZero() {
|
|
return fmt.Errorf("创建时间不能为空")
|
|
}
|
|
|
|
if t.UpdatedAt.IsZero() {
|
|
return fmt.Errorf("更新时间不能为空")
|
|
}
|
|
|
|
if t.Completed && t.CompletedAt == nil {
|
|
return fmt.Errorf("已完成的任务必须有完成时间")
|
|
}
|
|
|
|
if !t.Completed && t.CompletedAt != nil {
|
|
return fmt.Errorf("未完成的任务不应该有完成时间")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// TaskList 任务列表类型
|
|
type TaskList []Task
|
|
|
|
// Len 返回任务列表长度
|
|
func (tl TaskList) Len() int {
|
|
return len(tl)
|
|
}
|
|
|
|
// Less 比较两个任务的顺序(用于排序)
|
|
func (tl TaskList) Less(i, j int) bool {
|
|
// 首先按完成状态排序(未完成的在前)
|
|
if tl[i].Completed != tl[j].Completed {
|
|
return !tl[i].Completed
|
|
}
|
|
|
|
// 然后按优先级排序(高优先级在前)
|
|
if tl[i].Priority != tl[j].Priority {
|
|
return tl[i].Priority > tl[j].Priority
|
|
}
|
|
|
|
// 最后按创建时间排序(新创建的在前)
|
|
return tl[i].CreatedAt.After(tl[j].CreatedAt)
|
|
}
|
|
|
|
// Swap 交换两个任务的位置
|
|
func (tl TaskList) Swap(i, j int) {
|
|
tl[i], tl[j] = tl[j], tl[i]
|
|
}
|
|
|
|
// Filter 过滤任务列表
|
|
func (tl TaskList) Filter(predicate func(Task) bool) TaskList {
|
|
var filtered TaskList
|
|
for _, task := range tl {
|
|
if predicate(task) {
|
|
filtered = append(filtered, task)
|
|
}
|
|
}
|
|
return filtered
|
|
}
|
|
|
|
// FindByID 根据ID查找任务
|
|
func (tl TaskList) FindByID(id int) (*Task, bool) {
|
|
for i, task := range tl {
|
|
if task.ID == id {
|
|
return &tl[i], true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
// GetCompleted 获取已完成的任务
|
|
func (tl TaskList) GetCompleted() TaskList {
|
|
return tl.Filter(func(t Task) bool {
|
|
return t.Completed
|
|
})
|
|
}
|
|
|
|
// GetPending 获取待完成的任务
|
|
func (tl TaskList) GetPending() TaskList {
|
|
return tl.Filter(func(t Task) bool {
|
|
return !t.Completed
|
|
})
|
|
}
|
|
|
|
// GetByPriority 根据优先级获取任务
|
|
func (tl TaskList) GetByPriority(priority Priority) TaskList {
|
|
return tl.Filter(func(t Task) bool {
|
|
return t.Priority == priority
|
|
})
|
|
}
|
|
|
|
// Search 搜索包含关键词的任务
|
|
func (tl TaskList) Search(keyword string) TaskList {
|
|
return tl.Filter(func(t Task) bool {
|
|
return contains(t.Content, keyword) ||
|
|
contains(t.Description, keyword) ||
|
|
containsInTags(t.Tags, keyword)
|
|
})
|
|
}
|
|
|
|
// contains 检查字符串是否包含子字符串(忽略大小写)
|
|
func contains(s, substr string) bool {
|
|
if substr == "" {
|
|
return true
|
|
}
|
|
return len(s) >= len(substr) &&
|
|
strings.Contains(strings.ToLower(s), strings.ToLower(substr))
|
|
}
|
|
|
|
// containsInTags 检查标签列表是否包含关键词
|
|
func containsInTags(tags []string, keyword string) bool {
|
|
for _, tag := range tags {
|
|
if contains(tag, keyword) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|