Auto commit: 2026-03-24 13:04
This commit is contained in:
22
AGENTS.md
22
AGENTS.md
@@ -30,23 +30,20 @@ pages/page-app/
|
||||
└── store/ # 模块状态管理(Zustand)
|
||||
```
|
||||
|
||||
### hooks/ 文件夹说明
|
||||
### api 请求
|
||||
|
||||
每个模块的 `hooks/` 文件夹用于封装与该模块相关的 React Query hooks:
|
||||
`modules/*-api.ts` 文件用于封装 API 请求函数,使用 `@kevisual/query` 进行底层请求处理。
|
||||
|
||||
- **use-api-query.ts**: 使用 `@tanstack/react-query` 的 `useQuery` 封装 API 调用
|
||||
- 定义 `queryKeys` 常量用于缓存标识
|
||||
- 封装 `useQuery` hooks 用于数据获取(GET 请求)
|
||||
- 封装 `useMutation` hooks 用于数据修改(POST/PUT/DELETE 请求)
|
||||
- 支持预取(prefetch)和无限滚动(infinite query)
|
||||
- **index.ts**: 导出模块所有 hooks,便于统一导入使用
|
||||
参考示例
|
||||
```ts
|
||||
// src/modules/mark-api.ts
|
||||
import { queryApi as markApi } from '@/modules/mark-api.ts';
|
||||
|
||||
const res = await markApi.mark.list({ page: 1, pageSize: 10 });
|
||||
```
|
||||
|
||||
### 状态和数据获取
|
||||
|
||||
- **@tanstack/react-query** 用于数据获取、缓存和状态管理
|
||||
- 在模块的 `hooks/` 文件夹中封装 API 调用
|
||||
- QueryClient 实例位于 `src/modules/query.ts`
|
||||
- 在 `src/routes/__root.tsx` 中通过 `QueryClientProvider` 提供
|
||||
- **Zustand** 用于全局状态管理
|
||||
- **@kevisual/query** 用于底层 API 请求封装
|
||||
- **React Hook Form** 用于表单管理
|
||||
@@ -54,7 +51,6 @@ pages/page-app/
|
||||
## 核心依赖
|
||||
|
||||
- **@base-ui/react**: Headless UI 基础组件
|
||||
- **@tanstack/react-query**: 数据获取、缓存和状态管理(配合 hooks/ 使用)
|
||||
- **@tanstack/react-router**: 基于 TanStack Router 插件的文件路由
|
||||
- **class-variance-authority**: 基于变体的样式系统
|
||||
- **clsx + tailwind-merge**: 通过 `cn()` 提供 className 工具函数
|
||||
|
||||
22
package.json
22
package.json
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "vite-react",
|
||||
"name": "@kevisual/app",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
@@ -9,6 +9,7 @@
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"ui": "bunx shadcn@latest add ",
|
||||
"template": "ev deploy . -k vite-react-template -v 0.0.1 -y y -u",
|
||||
"pub": "envision deploy ./dist -k vite-react -v 0.0.1 -y y -u"
|
||||
},
|
||||
"files": [
|
||||
@@ -20,9 +21,9 @@
|
||||
"@base-ui/react": "^1.3.0",
|
||||
"@kevisual/api": "^0.0.65",
|
||||
"@kevisual/context": "^0.0.8",
|
||||
"@kevisual/router": "0.1.6",
|
||||
"@tanstack/react-query": "^5.91.3",
|
||||
"@tanstack/react-router": "^1.168.1",
|
||||
"@kevisual/router": "0.2.2",
|
||||
"@tanstack/react-query": "^5.95.2",
|
||||
"@tanstack/react-router": "^1.168.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
@@ -30,12 +31,12 @@
|
||||
"dayjs": "^1.11.20",
|
||||
"es-toolkit": "^1.45.1",
|
||||
"fuse.js": "^7.1.0",
|
||||
"lucide-react": "^0.577.0",
|
||||
"lucide-react": "^1.0.1",
|
||||
"nanoid": "^5.1.7",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"react-hook-form": "^7.71.2",
|
||||
"react-hook-form": "^7.72.0",
|
||||
"sonner": "^2.0.7",
|
||||
"zustand": "^5.0.12"
|
||||
},
|
||||
@@ -49,18 +50,19 @@
|
||||
"@kevisual/types": "^0.0.12",
|
||||
"@kevisual/vite-html-plugin": "^0.0.1",
|
||||
"@tailwindcss/vite": "^4.2.2",
|
||||
"@tanstack/react-router-devtools": "^1.166.10",
|
||||
"@tanstack/router-plugin": "^1.167.2",
|
||||
"@tanstack/react-router-devtools": "^1.166.11",
|
||||
"@tanstack/router-plugin": "^1.167.4",
|
||||
"@types/node": "^25.5.0",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^6.0.1",
|
||||
"dotenv": "^17.3.1",
|
||||
"re-resizable": "^6.11.2",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"tailwindcss": "^4.2.2",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "v8.0.1",
|
||||
"typescript": "^6.0.2",
|
||||
"vite": "v8.0.2",
|
||||
"vite-plugin-pwa": "^1.2.0"
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ export interface SidebarProps {
|
||||
children?: React.ReactNode
|
||||
logo?: React.ReactNode
|
||||
title?: React.ReactNode
|
||||
footer?: React.ReactNode
|
||||
defaultCollapsed?: boolean
|
||||
defaultWidth?: number
|
||||
minWidth?: number
|
||||
@@ -44,6 +45,7 @@ export function Sidebar({
|
||||
children,
|
||||
logo,
|
||||
title,
|
||||
footer,
|
||||
defaultCollapsed = false,
|
||||
defaultWidth = 208,
|
||||
minWidth = 120,
|
||||
@@ -80,7 +82,7 @@ export function Sidebar({
|
||||
|
||||
if (item.isDeveloping) {
|
||||
setDevelopingDialog({ open: true, title: item.title })
|
||||
} else if (item.external && item.path.startsWith('http')) {
|
||||
} else if (item.external) {
|
||||
window.open(item.path, '_blank')
|
||||
} else if (item.path.startsWith('/')) {
|
||||
navigate({ to: item.path })
|
||||
@@ -172,7 +174,6 @@ export function Sidebar({
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={cn('flex h-full', className)}>
|
||||
@@ -194,7 +195,7 @@ export function Sidebar({
|
||||
>
|
||||
<aside
|
||||
className={cn(
|
||||
'border-r bg-white flex-shrink-0 flex flex-col'
|
||||
'h-full border-r bg-white flex-shrink-0 flex flex-col'
|
||||
)}
|
||||
style={{ width: sidebarWidth }}
|
||||
>
|
||||
@@ -223,11 +224,18 @@ export function Sidebar({
|
||||
{items.map((item) => renderNavItem(item))}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{/* Footer */}
|
||||
{footer && (
|
||||
<div className="border-t flex-shrink-0">
|
||||
{footer}
|
||||
</div>
|
||||
)}
|
||||
</aside>
|
||||
</Resizable>
|
||||
) : (
|
||||
// 收起状态
|
||||
<aside className="w-14 border-r bg-white flex-shrink-0 flex flex-col">
|
||||
<aside className="h-full w-14 border-r bg-white flex-shrink-0 flex flex-col">
|
||||
{/* Logo 区域 */}
|
||||
<div className="h-12 flex items-center justify-center border-b px-2">
|
||||
<div className="group relative flex-shrink-0">
|
||||
@@ -248,6 +256,13 @@ export function Sidebar({
|
||||
{items.map((item) => renderNavItem(item))}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{/* Footer */}
|
||||
{footer && (
|
||||
<div className="border-t flex-shrink-0">
|
||||
{footer}
|
||||
</div>
|
||||
)}
|
||||
</aside>
|
||||
)}
|
||||
|
||||
|
||||
378
src/modules/mark-api.ts
Normal file
378
src/modules/mark-api.ts
Normal file
@@ -0,0 +1,378 @@
|
||||
import { createQueryApi } from '@kevisual/query/api';
|
||||
const api = {
|
||||
"mark": {
|
||||
/**
|
||||
* 获取mark列表
|
||||
*
|
||||
* @param data - Request parameters
|
||||
* @param data.page - {number} 页码
|
||||
* @param data.pageSize - {number} 每页数量
|
||||
* @param data.search - {string} 搜索关键词
|
||||
* @param data.markType - {string} mark类型,simple,wallnote,md,draw等
|
||||
* @param data.sort - {"DESC" | "ASC"} 排序字段
|
||||
*/
|
||||
"list": {
|
||||
"path": "mark",
|
||||
"key": "list",
|
||||
"description": "获取mark列表",
|
||||
"metadata": {
|
||||
"args": {
|
||||
"page": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"description": "页码",
|
||||
"type": "number",
|
||||
"optional": true
|
||||
},
|
||||
"pageSize": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"description": "每页数量",
|
||||
"type": "number",
|
||||
"optional": true
|
||||
},
|
||||
"search": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"description": "搜索关键词",
|
||||
"type": "string",
|
||||
"optional": true
|
||||
},
|
||||
"markType": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"description": "mark类型,simple,wallnote,md,draw等",
|
||||
"type": "string",
|
||||
"optional": true
|
||||
},
|
||||
"sort": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": "DESC",
|
||||
"description": "排序字段",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"DESC",
|
||||
"ASC"
|
||||
],
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"url": "/api/router",
|
||||
"source": "query-proxy-api"
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 获取mark版本信息
|
||||
*
|
||||
* @param data - Request parameters
|
||||
* @param data.id - {string} mark id
|
||||
*/
|
||||
"getVersion": {
|
||||
"path": "mark",
|
||||
"key": "getVersion",
|
||||
"description": "获取mark版本信息",
|
||||
"metadata": {
|
||||
"args": {
|
||||
"id": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "string",
|
||||
"description": "mark id"
|
||||
}
|
||||
},
|
||||
"url": "/api/router",
|
||||
"source": "query-proxy-api"
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 获取mark详情
|
||||
*
|
||||
* @param data - Request parameters
|
||||
* @param data.id - {string} mark id
|
||||
*/
|
||||
"get": {
|
||||
"path": "mark",
|
||||
"key": "get",
|
||||
"description": "获取mark详情",
|
||||
"metadata": {
|
||||
"args": {
|
||||
"id": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "string",
|
||||
"description": "mark id"
|
||||
}
|
||||
},
|
||||
"url": "/api/router",
|
||||
"source": "query-proxy-api"
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 更新mark内容
|
||||
*
|
||||
* @param data - Request parameters
|
||||
* @param data.data - {object}
|
||||
*/
|
||||
"update": {
|
||||
"path": "mark",
|
||||
"key": "update",
|
||||
"description": "更新mark内容",
|
||||
"metadata": {
|
||||
"args": {
|
||||
"data": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "mark id"
|
||||
},
|
||||
"title": {
|
||||
"default": "",
|
||||
"type": "string"
|
||||
},
|
||||
"tags": {
|
||||
"default": []
|
||||
},
|
||||
"link": {
|
||||
"default": "",
|
||||
"type": "string"
|
||||
},
|
||||
"summary": {
|
||||
"default": "",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"default": "",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"tags",
|
||||
"link",
|
||||
"summary",
|
||||
"description"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"url": "/api/router",
|
||||
"source": "query-proxy-api"
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 更新mark节点,支持更新和删除操作
|
||||
*
|
||||
* @param data - Request parameters
|
||||
* @param data.id - {string} mark id
|
||||
* @param data.operate - {"update" | "delete"} 节点操作类型,update或delete
|
||||
* @param data.data - {object} 要更新的节点数据
|
||||
*/
|
||||
"updateNode": {
|
||||
"path": "mark",
|
||||
"key": "updateNode",
|
||||
"description": "更新mark节点,支持更新和删除操作",
|
||||
"metadata": {
|
||||
"args": {
|
||||
"id": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "string",
|
||||
"description": "mark id"
|
||||
},
|
||||
"operate": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": "update",
|
||||
"description": "节点操作类型,update或delete",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"update",
|
||||
"delete"
|
||||
],
|
||||
"optional": true
|
||||
},
|
||||
"data": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "节点id"
|
||||
},
|
||||
"node": {
|
||||
"description": "要更新的节点数据"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"node"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"description": "要更新的节点数据"
|
||||
}
|
||||
},
|
||||
"url": "/api/router",
|
||||
"source": "query-proxy-api"
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 批量更新mark节点,支持更新和删除操作
|
||||
*
|
||||
* @param data - Request parameters
|
||||
* @param data.id - {string} mark id
|
||||
* @param data.nodeOperateList - {array} 要更新的节点列表
|
||||
*/
|
||||
"updateNodes": {
|
||||
"path": "mark",
|
||||
"key": "updateNodes",
|
||||
"description": "批量更新mark节点,支持更新和删除操作",
|
||||
"metadata": {
|
||||
"args": {
|
||||
"id": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "string",
|
||||
"description": "mark id"
|
||||
},
|
||||
"nodeOperateList": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"operate": {
|
||||
"default": "update",
|
||||
"description": "节点操作类型,update或delete",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"update",
|
||||
"delete"
|
||||
]
|
||||
},
|
||||
"node": {
|
||||
"description": "要更新的节点数据"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"operate",
|
||||
"node"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"description": "要更新的节点列表"
|
||||
}
|
||||
},
|
||||
"url": "/api/router",
|
||||
"source": "query-proxy-api"
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param data - Request parameters
|
||||
* @param data.id - {string} mark id
|
||||
*/
|
||||
"delete": {
|
||||
"path": "mark",
|
||||
"key": "delete",
|
||||
"metadata": {
|
||||
"args": {
|
||||
"id": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "string",
|
||||
"description": "mark id"
|
||||
}
|
||||
},
|
||||
"url": "/api/router",
|
||||
"source": "query-proxy-api"
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 创建一个新的mark.
|
||||
*
|
||||
* @param data - Request parameters
|
||||
* @param data.title - {string} 标题
|
||||
* @param data.tags - {unknown} 标签
|
||||
* @param data.link - {string} 链接
|
||||
* @param data.summary - {string} 摘要
|
||||
* @param data.description - {string} 描述
|
||||
* @param data.markType - {string} mark类型
|
||||
* @param data.config - {unknown} 配置
|
||||
* @param data.data - {unknown} 数据
|
||||
*/
|
||||
"create": {
|
||||
"path": "mark",
|
||||
"key": "create",
|
||||
"description": "创建一个新的mark.",
|
||||
"metadata": {
|
||||
"args": {
|
||||
"title": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": "",
|
||||
"description": "标题",
|
||||
"type": "string",
|
||||
"optional": true
|
||||
},
|
||||
"tags": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": [],
|
||||
"description": "标签",
|
||||
"optional": true
|
||||
},
|
||||
"link": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": "",
|
||||
"description": "链接",
|
||||
"type": "string",
|
||||
"optional": true
|
||||
},
|
||||
"summary": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": "",
|
||||
"description": "摘要",
|
||||
"type": "string",
|
||||
"optional": true
|
||||
},
|
||||
"description": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": "",
|
||||
"description": "描述",
|
||||
"type": "string",
|
||||
"optional": true
|
||||
},
|
||||
"markType": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": "md",
|
||||
"description": "mark类型",
|
||||
"type": "string",
|
||||
"optional": true
|
||||
},
|
||||
"config": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": {},
|
||||
"description": "配置",
|
||||
"optional": true
|
||||
},
|
||||
"data": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"default": {},
|
||||
"description": "数据",
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"url": "/api/router",
|
||||
"source": "query-proxy-api"
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 获取mark菜单
|
||||
*/
|
||||
"getMenu": {
|
||||
"path": "mark",
|
||||
"key": "getMenu",
|
||||
"description": "获取mark菜单",
|
||||
"metadata": {
|
||||
"url": "/api/router",
|
||||
"source": "query-proxy-api"
|
||||
}
|
||||
}
|
||||
}
|
||||
} as const;
|
||||
const queryApi = createQueryApi({ api });
|
||||
|
||||
export { queryApi };
|
||||
|
||||
// 使用例子,方法为对应的方法,data 为对应的 args 的参数的定义数据
|
||||
// queryApi['user-app'].delete(data)
|
||||
Reference in New Issue
Block a user