fix: habits view api fields + remove multi-select
ci / docker (push) Successful in 7m7s

This commit is contained in:
2026-09-05 18:01:17 +08:00
parent 799b522f9b
commit e8c49b045f
3 changed files with 27 additions and 29 deletions
+1 -22
View File
@@ -27,7 +27,6 @@ const trash = ref<Task[]>([])
const activeList = ref('')
const activeView = ref<View>('tasks')
const selectedTask = ref<Task | null>(null)
const selectedIds = ref(new Set<string>())
const title = ref('')
const query = ref('')
const error = ref('')
@@ -64,8 +63,6 @@ const visibleTasks = computed(() => {
})
const filteredTaskTree = computed(() => groupTaskTree(visibleTasks.value))
const taskTree = computed(() => filteredTaskTree.value)
const selectedCount = computed(() => selectedIds.value.size)
const parentTasks = computed(() => tasks.value.filter((task) => !task.parent_id))
let searchTimer: number | undefined
watch(query, () => {
if (searchTimer) window.clearTimeout(searchTimer)
@@ -177,7 +174,7 @@ async function switchView(view: View, listId?: string) {
activeView.value = view
if (listId) activeList.value = listId
page.value = 1
selectedTask.value = null; selectedIds.value = new Set(); mobileSidebar.value = false; mobileDetail.value = false
selectedTask.value = null; mobileSidebar.value = false; mobileDetail.value = false
if (view === 'trash') await loadTrash()
else await loadAll()
}
@@ -227,22 +224,6 @@ function selectTask(task: Task) {
selectedTask.value = { ...task, tags: task.tags ? [...task.tags] : [] }
markdownPreview.value = false; mobileDetail.value = true
}
function toggleSelect(id: string) {
const next = new Set(selectedIds.value); next.has(id) ? next.delete(id) : next.add(id); selectedIds.value = next
}
async function batch(action: 'complete' | 'move' | 'delete') {
if (!selectedIds.value.size) return
const payload: Record<string, unknown> = { task_ids: [...selectedIds.value] }
if (action === 'complete') payload.completed = true
if (action === 'move') {
const listId = window.prompt('输入目标清单 ID', activeList.value)?.trim(); if (!listId) return; payload.list_id = listId
}
try {
if (action === 'delete') payload.soft_delete = true
await api('/tasks/batch', { method: 'POST', body: JSON.stringify(payload) })
selectedIds.value = new Set(); await loadAll(); toast(action === 'delete' ? '已批量移到回收站' : '批量操作完成')
} catch (reason) { fail(reason) }
}
async function createFolder() {
const name = window.prompt('文件夹名称')?.trim(); if (!name) return
try { folders.value.push(await api('/folders', { method: 'POST', body: JSON.stringify({ name }) })); toast('文件夹已创建') } catch (reason) { fail(reason) }
@@ -333,11 +314,9 @@ onMounted(bootstrap)
<form v-if="activeView!=='trash'" class="quick" @submit.prevent="addTask"><CirclePlus/><input v-model="title" class="quick-input" placeholder="添加任务,按回车保存"><button>添加</button></form>
<div class="list-toolbar"><label v-if="activeView!=='trash'"><input v-model="showCompleted" type="checkbox"> 显示已完成</label><span>第 {{page}} / {{totalPages}} 页 · 共 {{totalTasks}} 项</span><button v-if="query" class="link" @click="query=''">清除搜索</button></div>
<div v-if="activeView!=='trash' && totalPages > 1" class="pager"><button class="secondary" :disabled="page<=1 || loading" @click="previousPage">上一页</button><span>{{page}} / {{totalPages}}</span><button class="secondary" :disabled="page>=totalPages || loading" @click="nextPage">下一页</button></div>
<div v-if="selectedCount" class="batch-bar"><b>已选 {{selectedCount}} 项</b><button @click="batch('complete')"><Check/>完成</button><button @click="batch('move')"><Folder/>移动</button><button class="danger" @click="batch('delete')"><Trash2/>删除</button><button class="icon" aria-label="取消选择" @click="selectedIds=new Set()"><X/></button></div>
<section class="task-list" :class="{loading}">
<template v-for="node in taskTree" :key="node.task.id">
<article class="task-row" :class="{done:node.task.completed,selected:selectedTask?.id===node.task.id}">
<button v-if="activeView!=='trash'" class="select-box" :class="{checked:selectedIds.has(node.task.id)}" aria-label="选择任务" @click.stop="toggleSelect(node.task.id)"><Check v-if="selectedIds.has(node.task.id)"/></button>
<button v-if="activeView!=='trash'" class="check" :class="`p${node.task.priority}`" aria-label="切换完成状态" @click.stop="toggle(node.task)"><Check v-if="node.task.completed"/></button>
<button class="task-main" @click="activeView==='trash'?undefined:selectTask(node.task)"><strong>{{node.task.title}}</strong><span class="meta"><span v-if="node.task.due_at"><CalendarDays/>{{formatDue(node.task.due_at)}}</span><span v-if="node.subtasks.length"><ListChecks/>{{node.subtasks.filter(t=>t.completed).length}}/{{node.subtasks.length}}</span><i v-for="tag in node.task.tags" :key="tag.id" class="tag-dot" :style="{background:tag.color}" :title="tag.name"/></span></button>
<span v-if="node.task.priority" class="priority" :class="`p${node.task.priority}`">{{['','','',''][node.task.priority]}}</span>