fix: load tasks by selected list
ci / docker (push) Successful in 3m47s

This commit is contained in:
2026-09-05 16:04:55 +08:00
parent a52a543384
commit 3bf8c7c3d9
3 changed files with 34 additions and 5 deletions
+7
View File
@@ -464,6 +464,8 @@ async def create_task(
@app.get("/api/v1/tasks", response_model=TaskPage)
async def list_tasks(
q: str | None = None,
list_id: UUID | None = None,
completed: bool | None = None,
cursor: str | None = None,
limit: int = Query(default=50, ge=1, le=100),
user: User = Depends(current_user),
@@ -472,6 +474,11 @@ async def list_tasks(
query = select(Task).where(
Task.user_id == user.id, Task.deleted_at.is_(None), Task.parent_id.is_(None)
)
if list_id is not None:
await _owned_list(db, user.id, list_id)
query = query.where(Task.list_id == list_id)
if completed is not None:
query = query.where(Task.completed.is_(completed))
if q:
pattern = f"%{q}%"
tag_match = exists(
+13 -5
View File
@@ -35,7 +35,7 @@ const loading = ref(false)
const mobileSidebar = ref(false)
const mobileDetail = ref(false)
const markdownPreview = ref(false)
const showCompleted = ref(true)
const showCompleted = ref(false)
const expandedFolders = ref(new Set<string>())
const activeName = computed(() => {
@@ -70,6 +70,9 @@ watch(query, () => {
if (activeView.value === 'trash') return
searchTimer = window.setTimeout(() => loadAll(), 250)
})
watch(showCompleted, () => {
if (activeView.value !== 'trash') loadAll()
})
async function api(path: string, options: RequestInit = {}) {
const response = await fetch('/api/v1' + path, {
@@ -125,12 +128,16 @@ async function loadTaskPages(path: string) {
async function loadAll() {
loading.value = true; error.value = ''
try {
const taskPath = query.value ? `/tasks?q=${encodeURIComponent(query.value)}` : '/tasks'
const [folderData, listData, tagData, taskData] = await Promise.all([
api('/folders'), api('/lists'), api('/tags').catch(() => []), loadTaskPages(taskPath),
const [folderData, listData, tagData] = await Promise.all([
api('/folders'), api('/lists'), api('/tags').catch(() => []),
])
folders.value = folderData; lists.value = listData; tags.value = tagData; tasks.value = taskData
folders.value = folderData; lists.value = listData; tags.value = tagData
activeList.value ||= lists.value.find((item) => item.is_inbox)?.id || lists.value[0]?.id || ''
const params = new URLSearchParams()
if (query.value) params.set('q', query.value)
else if (activeView.value === 'tasks' && activeList.value) params.set('list_id', activeList.value)
if (!showCompleted.value && activeView.value !== 'trash') params.set('completed', 'false')
tasks.value = await loadTaskPages(`/tasks${params.size ? `?${params}` : ''}`)
expandedFolders.value = new Set(folders.value.map((folder) => folder.id))
} catch (reason) { fail(reason) } finally { loading.value = false }
}
@@ -142,6 +149,7 @@ async function switchView(view: View, listId?: string) {
if (listId) activeList.value = listId
selectedTask.value = null; selectedIds.value = new Set(); mobileSidebar.value = false; mobileDetail.value = false
if (view === 'trash') await loadTrash()
else await loadAll()
}
async function addTask() {
if (!title.value.trim() || !activeList.value) return
+14
View File
@@ -107,6 +107,20 @@ def test_attachment_security_ownership_and_size(client, tmp_path, monkeypatch):
assert client.delete(f"/api/v1/attachments/{attachment['id']}").status_code == 204
def test_tasks_can_be_loaded_by_list_and_completion_filter(client):
inbox = boot(client)
other = client.post("/api/v1/lists", json={"name": "其他清单"}).json()
client.post("/api/v1/tasks", json={"title": "收集箱未完成", "list_id": inbox["id"]})
done = client.post("/api/v1/tasks", json={"title": "收集箱已完成", "list_id": inbox["id"]}).json()
client.patch(f"/api/v1/tasks/{done['id']}", json={"completed": True, "version": done["version"]})
client.post("/api/v1/tasks", json={"title": "其他清单未完成", "list_id": other["id"]})
response = client.get("/api/v1/tasks", params={"list_id": inbox["id"], "completed": False})
assert response.status_code == 200
assert [item["title"] for item in response.json()["items"]] == ["收集箱未完成"]
def test_ticktick_preview_import_dedupe_and_json_restore(client):
boot(client)
csv_data = "Title,List Name,Due Date,Status,ID\nImported,Inbox,2026-10-01,0,ext-1\n"