1、将排序做到border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted里,无需单独做个button 2、指定重命名使用ICO,无需使用菜单

This commit is contained in:
pphua committed 2026-08-25 14:56:15 +08:00
1 parent 48e85b33d6
commit 86eb67ea0a
15 files changed
+957 -20

No files matched your search

+5
View File
@@ -215,6 +215,9 @@ export const api = {
coverage_enabled: input.coverageEnabled ?? true, // 默认开;false=关闭资产覆盖度功能
}),
taskCategories: () => get<{ categories: TaskCategory[] }>("/task-categories").then((r) => arr(r.categories)),
updateTask: (id: string, input: { name?: string; pinned?: boolean }) => patch<Task>(`/tasks/${id}`, input),
renameTask: (id: string, name: string) => patch<Task>(`/tasks/${id}`, { name }),
pinTask: (id: string, pinned: boolean) => patch<Task>(`/tasks/${id}`, { pinned }),
createTaskCategory: (name: string) => post<TaskCategory>("/task-categories", { name }),
renameTaskCategory: (id: number, name: string) => patch<TaskCategory>(`/task-categories/${id}`, { name }),
deleteTaskCategory: (id: number) => del<{ deleted: number }>(`/task-categories/${id}`),
@@ -704,6 +707,8 @@ export const api = {
updateConversationProfile: (id: number, llm_profile_id: number | null) =>
patch<{ ok: boolean }>(`/conversations/${id}/profile`, { llm_profile_id }),
deleteConversation: (id: number) => del<{ deleted: number }>(`/conversations/${id}`),
deleteConversations: (ids: number[]) =>
post<{ items: { id: number; ok: boolean; error?: string }[] }>("/conversations/delete/batch", { ids }),
// Incremental tail: steps after `since` (id ASC) — live poll + post-send fetch.
conversationMessages: (id: number, since = 0) =>
get<{ items: Activity[]; cursor: number; running: boolean }>(`/conversations/${id}/messages?since=${since}`).then(
+37 -1
View File
@@ -233,6 +233,16 @@ function sortMockConversations() {
});
}
function sortMockTasks() {
mockTasks.sort((a, b) => {
const aPinned = a.pinned_at ? 1 : 0;
const bPinned = b.pinned_at ? 1 : 0;
if (aPinned !== bPinned) return bPinned - aPinned;
if (a.pinned_at !== b.pinned_at) return (b.pinned_at ?? "").localeCompare(a.pinned_at ?? "");
return b.id.localeCompare(a.id, undefined, { numeric: true });
});
}
function normalizedTemplateName(value: unknown): string {
return String(value ?? "")
.trim()
@@ -268,7 +278,10 @@ function route(m: string, path: string, seg: string[], q: URLSearchParams, b: Re
if (path === "/auth/change-password") return { ok: true };
// ── tasks ──
if (path === "/tasks" && m === "GET") return { tasks: mockTasks, active: mockActiveTask };
if (path === "/tasks" && m === "GET") {
sortMockTasks();
return { tasks: mockTasks, active: mockActiveTask };
}
if (path === "/tasks" && m === "POST") {
let suffix = 1;
while (mockTasks.some((item) => item.id === `t-new-${suffix}`)) suffix++;
@@ -436,6 +449,17 @@ function route(m: string, path: string, seg: string[], q: URLSearchParams, b: Re
if (index >= 0) mockTaskTemplates.splice(index, 1);
return { deleted: id };
}
if (seg[0] === "tasks" && seg.length === 2 && m === "PATCH") {
const task = mockTasks.find((item) => item.id === seg[1]);
if (!task) throw new Error("任务不存在");
if (typeof b.name === "string") task.name = b.name.trim();
if (typeof b.pinned === "boolean") {
task.pinned = b.pinned;
task.pinned_at = b.pinned ? (task.pinned_at ?? new Date().toISOString()) : null;
}
sortMockTasks();
return structuredClone(task);
}
if (seg[0] === "tasks" && seg.length === 2 && m === "DELETE") {
const id = seg[1];
const index = mockTasks.findIndex((item) => item.id === id);
@@ -1187,6 +1211,18 @@ function route(m: string, path: string, seg: string[], q: URLSearchParams, b: Re
if (index >= 0) mockConversations.splice(index, 1);
return { deleted: id };
}
if (path === "/conversations/delete/batch" && m === "POST") {
const ids = Array.isArray(b.ids)
? [...new Set(b.ids.map(Number).filter((id) => Number.isInteger(id) && id > 0))]
: [];
const items = ids.map((id) => {
const index = mockConversations.findIndex((item) => item.id === id);
if (index < 0) return { id, ok: false, error: "conversation not found" };
mockConversations.splice(index, 1);
return { id, ok: true };
});
return { items };
}
if (seg[0] === "conversations" && seg[2] === "messages" && seg.length === 3 && m === "GET") {
const items = D.conversationMessages[Number(seg[1])] ?? [];
return { items, cursor: items.length ? items[items.length - 1].seq : 0, running: false };
+2
View File
@@ -9,6 +9,8 @@ export interface Task {
name?: string; // 可选任务名称;空/缺省=未命名,展示时回退到描述
category_id?: number;
category_name?: string;
pinned?: boolean;
pinned_at?: string | null;
description: string;
goal: string;
status: TaskStatus;