From 7f27221081c5d4867bba489701b24dd88a9b7a61 Mon Sep 17 00:00:00 2001 From: imbytecat Date: Sun, 18 Jan 2026 16:02:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=BF=E6=8D=A2=E9=A6=96=E9=A1=B5?= =?UTF-8?q?=E4=B8=BA=E5=AE=8C=E6=95=B4=E5=BE=85=E5=8A=9E=E4=BA=8B=E9=A1=B9?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E5=B9=B6=E6=B8=85=E7=90=86=E5=BA=9F=E5=BC=83?= =?UTF-8?q?=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将首页替换为功能完整的待办事项应用,支持添加、标记完成、删除任务及进度统计,并优化了UI交互与视觉反馈。 - 删除待办事项功能页面及其相关逻辑实现 - 移除已废弃的 todos 路由相关配置及引用,保持路由树结构与实际路由文件一致。 --- src/routeTree.gen.ts | 24 +---- src/routes/index.tsx | 207 +++++++++++++++++++++++++++++++++++++++++- src/routes/todos.tsx | 208 ------------------------------------------- 3 files changed, 207 insertions(+), 232 deletions(-) delete mode 100644 src/routes/todos.tsx diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 5d5b392..1025fc0 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -9,15 +9,9 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { Route as rootRouteImport } from './routes/__root' -import { Route as TodosRouteImport } from './routes/todos' import { Route as IndexRouteImport } from './routes/index' import { Route as ApiRpcSplatRouteImport } from './routes/api/rpc.$' -const TodosRoute = TodosRouteImport.update({ - id: '/todos', - path: '/todos', - getParentRoute: () => rootRouteImport, -} as any) const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', @@ -31,43 +25,32 @@ const ApiRpcSplatRoute = ApiRpcSplatRouteImport.update({ export interface FileRoutesByFullPath { '/': typeof IndexRoute - '/todos': typeof TodosRoute '/api/rpc/$': typeof ApiRpcSplatRoute } export interface FileRoutesByTo { '/': typeof IndexRoute - '/todos': typeof TodosRoute '/api/rpc/$': typeof ApiRpcSplatRoute } export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute - '/todos': typeof TodosRoute '/api/rpc/$': typeof ApiRpcSplatRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/todos' | '/api/rpc/$' + fullPaths: '/' | '/api/rpc/$' fileRoutesByTo: FileRoutesByTo - to: '/' | '/todos' | '/api/rpc/$' - id: '__root__' | '/' | '/todos' | '/api/rpc/$' + to: '/' | '/api/rpc/$' + id: '__root__' | '/' | '/api/rpc/$' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute - TodosRoute: typeof TodosRoute ApiRpcSplatRoute: typeof ApiRpcSplatRoute } declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/todos': { - id: '/todos' - path: '/todos' - fullPath: '/todos' - preLoaderRoute: typeof TodosRouteImport - parentRoute: typeof rootRouteImport - } '/': { id: '/' path: '/' @@ -87,7 +70,6 @@ declare module '@tanstack/react-router' { const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, - TodosRoute: TodosRoute, ApiRpcSplatRoute: ApiRpcSplatRoute, } export const routeTree = rootRouteImport diff --git a/src/routes/index.tsx b/src/routes/index.tsx index ccdc684..e6647d3 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,7 +1,208 @@ +import { useMutation, useSuspenseQuery } from '@tanstack/react-query' import { createFileRoute } from '@tanstack/react-router' +import type { ChangeEventHandler, FormEventHandler } from 'react' +import { useState } from 'react' +import { orpc } from '@/orpc' -export const Route = createFileRoute('/')({ component: App }) +export const Route = createFileRoute('/')({ + component: Todos, + loader: async ({ context }) => { + await context.queryClient.ensureQueryData(orpc.todo.list.queryOptions()) + }, +}) -function App() { - return
Hello, World!
+function Todos() { + const [newTodoTitle, setNewTodoTitle] = useState('') + + const listQuery = useSuspenseQuery(orpc.todo.list.queryOptions()) + const createMutation = useMutation(orpc.todo.create.mutationOptions()) + const updateMutation = useMutation(orpc.todo.update.mutationOptions()) + const deleteMutation = useMutation(orpc.todo.remove.mutationOptions()) + + const handleCreateTodo: FormEventHandler = (e) => { + e.preventDefault() + if (newTodoTitle.trim()) { + createMutation.mutate({ title: newTodoTitle.trim() }) + setNewTodoTitle('') + } + } + + const handleInputChange: ChangeEventHandler = (e) => { + setNewTodoTitle(e.target.value) + } + + const handleToggleTodo = (id: string, currentCompleted: boolean) => { + updateMutation.mutate({ + id, + data: { completed: !currentCompleted }, + }) + } + + const handleDeleteTodo = (id: string) => { + deleteMutation.mutate({ id }) + } + + const todos = listQuery.data + const completedCount = todos.filter((todo) => todo.completed).length + const totalCount = todos.length + const progress = totalCount > 0 ? (completedCount / totalCount) * 100 : 0 + + return ( +
+
+ {/* Header */} +
+
+

+ 我的待办 +

+

保持专注,逐个击破

+
+
+
+ {completedCount} + /{totalCount} +
+
+ 已完成 +
+
+
+ + {/* Add Todo Form */} +
+
+ + +
+
+ + {/* Progress Bar (Only visible when there are tasks) */} + {totalCount > 0 && ( +
+
+
+ )} + + {/* Todo List */} +
+ {todos.length === 0 ? ( +
+
+ +
+

没有待办事项

+

+ 输入上方内容添加您的第一个任务 +

+
+ ) : ( + todos.map((todo) => ( +
+ + +
+

+ {todo.title} +

+
+ +
+ + {new Date(todo.createdAt).toLocaleDateString('zh-CN')} + + +
+
+ )) + )} +
+
+
+ ) } diff --git a/src/routes/todos.tsx b/src/routes/todos.tsx deleted file mode 100644 index e370b2d..0000000 --- a/src/routes/todos.tsx +++ /dev/null @@ -1,208 +0,0 @@ -import { useMutation, useSuspenseQuery } from '@tanstack/react-query' -import { createFileRoute } from '@tanstack/react-router' -import type { ChangeEventHandler, FormEventHandler } from 'react' -import { useState } from 'react' -import { orpc } from '@/orpc' - -export const Route = createFileRoute('/todos')({ - component: Todos, - loader: async ({ context }) => { - await context.queryClient.ensureQueryData(orpc.todo.list.queryOptions()) - }, -}) - -function Todos() { - const [newTodoTitle, setNewTodoTitle] = useState('') - - const listQuery = useSuspenseQuery(orpc.todo.list.queryOptions()) - const createMutation = useMutation(orpc.todo.create.mutationOptions()) - const updateMutation = useMutation(orpc.todo.update.mutationOptions()) - const deleteMutation = useMutation(orpc.todo.remove.mutationOptions()) - - const handleCreateTodo: FormEventHandler = (e) => { - e.preventDefault() - if (newTodoTitle.trim()) { - createMutation.mutate({ title: newTodoTitle.trim() }) - setNewTodoTitle('') - } - } - - const handleInputChange: ChangeEventHandler = (e) => { - setNewTodoTitle(e.target.value) - } - - const handleToggleTodo = (id: string, currentCompleted: boolean) => { - updateMutation.mutate({ - id, - data: { completed: !currentCompleted }, - }) - } - - const handleDeleteTodo = (id: string) => { - deleteMutation.mutate({ id }) - } - - const todos = listQuery.data - const completedCount = todos.filter((todo) => todo.completed).length - const totalCount = todos.length - const progress = totalCount > 0 ? (completedCount / totalCount) * 100 : 0 - - return ( -
-
- {/* Header */} -
-
-

- 我的待办 -

-

保持专注,逐个击破

-
-
-
- {completedCount} - /{totalCount} -
-
- 已完成 -
-
-
- - {/* Add Todo Form */} -
-
- - -
-
- - {/* Progress Bar (Only visible when there are tasks) */} - {totalCount > 0 && ( -
-
-
- )} - - {/* Todo List */} -
- {todos.length === 0 ? ( -
-
- -
-

没有待办事项

-

- 输入上方内容添加您的第一个任务 -

-
- ) : ( - todos.map((todo) => ( -
- - -
-

- {todo.title} -

-
- -
- - {new Date(todo.createdAt).toLocaleDateString('zh-CN')} - - -
-
- )) - )} -
-
-
- ) -}