release: Elysia ToDo v1.0.0
鍏ㄦ爤涓汉淇℃伅绠$悊搴旂敤锛岄泦鎴愬緟鍔炰换鍔°€佷範鎯墦鍗°€佺邯蹇垫棩鎻愰啋銆佽祫浜ф€昏鍔熻兘銆 Made-with: Cursor
This commit is contained in:
180
WebUI/src/stores/useTaskStore.ts
Normal file
180
WebUI/src/stores/useTaskStore.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { taskApi, type TaskResponse } from '@/api/tasks'
|
||||
import type { TaskFormData, TaskFilters } from '@/api/types'
|
||||
import { matchWithPinyin } from '@/utils/pinyin'
|
||||
import { formatDate } from '@/utils/date'
|
||||
|
||||
export const useTaskStore = defineStore('task', () => {
|
||||
const allTasks = ref<TaskResponse[]>([])
|
||||
const loading = ref(false)
|
||||
const filters = ref<TaskFilters>({
|
||||
status: 'all',
|
||||
sort_by: 'priority',
|
||||
sort_order: 'desc'
|
||||
})
|
||||
|
||||
// 所有任务
|
||||
const tasks = computed(() => {
|
||||
let result = [...allTasks.value]
|
||||
|
||||
// 搜索过滤(支持拼音)
|
||||
if (filters.value.search?.trim()) {
|
||||
const keyword = filters.value.search.trim()
|
||||
result = result.filter(t =>
|
||||
matchWithPinyin(t.title, keyword) ||
|
||||
(t.description && matchWithPinyin(t.description, keyword)) ||
|
||||
t.tags?.some(tag => matchWithPinyin(tag.name, keyword))
|
||||
)
|
||||
}
|
||||
|
||||
// 状态筛选
|
||||
if (filters.value.status === 'active') {
|
||||
result = result.filter(t => !t.is_completed)
|
||||
} else if (filters.value.status === 'completed') {
|
||||
result = result.filter(t => t.is_completed)
|
||||
}
|
||||
|
||||
// 分类筛选
|
||||
if (filters.value.category_id) {
|
||||
result = result.filter(t => t.category_id === filters.value.category_id)
|
||||
}
|
||||
|
||||
// 排序
|
||||
if (filters.value.sort_by) {
|
||||
result.sort((a, b) => {
|
||||
let comparison = 0
|
||||
|
||||
if (filters.value.sort_by === 'priority') {
|
||||
const priorityOrder: Record<string, number> = { q1: 4, q2: 3, q3: 2, q4: 1 }
|
||||
const aOrder = priorityOrder[a.priority] || 0
|
||||
const bOrder = priorityOrder[b.priority] || 0
|
||||
comparison = aOrder - bOrder
|
||||
} else if (filters.value.sort_by === 'due_date') {
|
||||
if (!a.due_date && !b.due_date) comparison = 0
|
||||
else if (!a.due_date) comparison = 1
|
||||
else if (!b.due_date) comparison = -1
|
||||
else comparison = new Date(a.due_date).getTime() - new Date(b.due_date).getTime()
|
||||
} else {
|
||||
comparison = new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
||||
}
|
||||
|
||||
return filters.value.sort_order === 'asc' ? -comparison : comparison
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
})
|
||||
|
||||
// 计算进行中和已完成的任务数量(基于所有任务)
|
||||
const activeTasks = computed(() => allTasks.value.filter(t => !t.is_completed))
|
||||
const completedTasks = computed(() => allTasks.value.filter(t => t.is_completed))
|
||||
const totalTasks = computed(() => allTasks.value)
|
||||
|
||||
// 按日期分组的任务(用于月视图)
|
||||
const tasksByDate = computed(() => {
|
||||
const grouped = new Map<string, TaskResponse[]>()
|
||||
const today = new Date()
|
||||
const todayStr = formatDate(today)
|
||||
|
||||
allTasks.value.forEach(task => {
|
||||
let dateKey: string
|
||||
if (task.due_date) {
|
||||
dateKey = formatDate(new Date(task.due_date))
|
||||
} else {
|
||||
// 无截止日期的任务显示在当天
|
||||
dateKey = todayStr
|
||||
}
|
||||
|
||||
if (!grouped.has(dateKey)) {
|
||||
grouped.set(dateKey, [])
|
||||
}
|
||||
grouped.get(dateKey)!.push(task)
|
||||
})
|
||||
|
||||
return grouped
|
||||
})
|
||||
|
||||
async function fetchTasks() {
|
||||
loading.value = true
|
||||
try {
|
||||
// 一次获取所有任务,在前端进行筛选和排序
|
||||
allTasks.value = await taskApi.getTasks({ status: 'all' })
|
||||
} catch (error) {
|
||||
console.error('获取任务列表失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function createTask(data: TaskFormData) {
|
||||
try {
|
||||
const newTask = await taskApi.createTask(data)
|
||||
allTasks.value.unshift(newTask)
|
||||
return newTask
|
||||
} catch (error) {
|
||||
console.error('创建任务失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function updateTask(id: number, data: TaskFormData) {
|
||||
try {
|
||||
const updatedTask = await taskApi.updateTask(id, data)
|
||||
const index = allTasks.value.findIndex((t: TaskResponse) => t.id === id)
|
||||
if (index !== -1) {
|
||||
allTasks.value[index] = updatedTask
|
||||
}
|
||||
return updatedTask
|
||||
} catch (error) {
|
||||
console.error('更新任务失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteTask(id: number) {
|
||||
try {
|
||||
await taskApi.deleteTask(id)
|
||||
allTasks.value = allTasks.value.filter((t: TaskResponse) => t.id !== id)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('删除任务失败:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function toggleTask(id: number) {
|
||||
try {
|
||||
const updatedTask = await taskApi.toggleTask(id)
|
||||
const index = allTasks.value.findIndex((t: TaskResponse) => t.id === id)
|
||||
if (index !== -1) {
|
||||
allTasks.value[index] = updatedTask
|
||||
}
|
||||
return updatedTask
|
||||
} catch (error) {
|
||||
console.error('切换任务状态失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function setFilters(newFilters: TaskFilters) {
|
||||
filters.value = { ...filters.value, ...newFilters }
|
||||
// 筛选现在在前端完成,不需要重新请求
|
||||
}
|
||||
|
||||
return {
|
||||
tasks,
|
||||
loading,
|
||||
filters,
|
||||
activeTasks,
|
||||
completedTasks,
|
||||
totalTasks: allTasks,
|
||||
tasksByDate,
|
||||
fetchTasks,
|
||||
createTask,
|
||||
updateTask,
|
||||
deleteTask,
|
||||
toggleTask,
|
||||
setFilters
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user