1
0
mirror of https://github.com/zuiidea/antd-admin synced 2026-09-24 01:55:12 +00:00

docs: restructure Nextra IA, migrate middleware to proxy

Sync apps/basic instructions, hooks, and vercel config; refresh lockfile.

Made-with: Cursor
This commit is contained in:
zuiidea
2026-04-28 11:53:31 +08:00
parent 6ac8a62770
commit 1cb0819011
52 changed files with 1046 additions and 487 deletions

View File

@@ -1,6 +1,7 @@
---
## applyTo: "src/api/**/*.ts,src/utils/http.ts,src/mocks/handlers/**/*.ts,src/mocks/createHandler.ts"
## applyTo: "src/api/**/\*.ts,src/utils/http.ts,src/mocks/handlers/**/\*.ts,src/mocks/createHandler.ts"
description: "Use when editing API clients, schemas, HTTP behavior, response types, or MSW endpoint handlers. Keywords: api, http, schema, zod, handler, endpoint, auth, users."
# API Instructions
@@ -26,4 +27,4 @@ Maintain strict API contracts and consistent server/client mock behavior.
## Validation
- Verify TypeScript and schema parsing paths compile cleanly.
- Run: `vp check --no-fmt`
- Run: `vp check --no-fmt`

View File

@@ -1,6 +1,7 @@
---
## applyTo: "src/**/*.{ts,tsx,css}"
## applyTo: "src/\*_/_.{ts,tsx,css}"
description: "Use when editing React UI, route pages, components, styles, layout, i18n text, or Ant Design behavior. Keywords: frontend, component, page, ui, layout, style, antd, i18n."
# Frontend Instructions
@@ -28,4 +29,4 @@ Keep frontend changes predictable, minimal, and reusable for AI-assisted edits.
## Validation
- Run: `vp check --no-fmt`
- For UI flow changes, run focused e2e where possible.
- For UI flow changes, run focused e2e where possible.

View File

@@ -1,6 +1,6 @@
---
## applyTo: "src/*/*.{ts,tsx}"
## applyTo: "src/_/_.{ts,tsx}"
description: "Use when refactoring existing code for deduplication, modularization, naming cleanup, or maintainability improvements without behavior changes. Keywords: refactor, cleanup, simplify, deduplicate, maintainability."
@@ -34,4 +34,4 @@ Reduce duplication while preserving behavior and public contracts.
- Confirm no new diagnostics in touched files.
- Run: `vp check --no-fmt`
- For significant changes, verify bundle size impact: `vp build 2>&1 | grep "kB"`
- For significant changes, verify bundle size impact: `vp build 2>&1 | grep "kB"`

View File

@@ -1,6 +1,6 @@
---
## applyTo: "tests/**/.ts,tests/**/*.tsx,src/mocks//*.ts,playwright.config.ts"
## applyTo: "tests/**/.ts,tests/**/_.tsx,src/mocks//_.ts,playwright.config.ts"
description: "Use when adding or editing tests, Playwright cases, MSW handlers, mock data, or test configuration. Keywords: test, e2e, playwright, mock, msw, coverage."
@@ -27,4 +27,4 @@ Keep tests fast, deterministic, and aligned with core business flows.
## Validation
- Run focused tests first, then broader checks if needed.
- Run: `vp check --no-fmt`
- Run: `vp check --no-fmt`

View File

@@ -1 +1 @@
pnpm lint && pnpm fmt
vp staged

View File

@@ -81,4 +81,4 @@ This repository also uses scoped AI instruction files in `.github/instructions/`
- `api.instructions.md` for API/schema/handler changes
- `refactor.instructions.md` for behavior-preserving cleanup
See `.github/instructions/README.md` for usage and authoring rules.
See `.github/instructions/README.md` for usage and authoring rules.

View File

@@ -8,191 +8,184 @@
// You should NOT make any changes in this file as it will be overwritten.
// 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 AuthRouteImport } from './routes/_auth'
import { Route as IndexRouteImport } from './routes/index'
import { Route as RegisterIndexRouteImport } from './routes/register/index'
import { Route as LoginIndexRouteImport } from './routes/login/index'
import { Route as R404IndexRouteImport } from './routes/404/index'
import { Route as AuthUsersIndexRouteImport } from './routes/_auth/users/index'
import { Route as AuthDashboardIndexRouteImport } from './routes/_auth/dashboard/index'
import { Route as Auth403IndexRouteImport } from './routes/_auth/403/index'
import { Route as rootRouteImport } from "./routes/__root";
import { Route as AuthRouteImport } from "./routes/_auth";
import { Route as IndexRouteImport } from "./routes/index";
import { Route as RegisterIndexRouteImport } from "./routes/register/index";
import { Route as LoginIndexRouteImport } from "./routes/login/index";
import { Route as R404IndexRouteImport } from "./routes/404/index";
import { Route as AuthUsersIndexRouteImport } from "./routes/_auth/users/index";
import { Route as AuthDashboardIndexRouteImport } from "./routes/_auth/dashboard/index";
import { Route as Auth403IndexRouteImport } from "./routes/_auth/403/index";
const AuthRoute = AuthRouteImport.update({
id: '/_auth',
id: "/_auth",
getParentRoute: () => rootRouteImport,
} as any)
} as any);
const IndexRoute = IndexRouteImport.update({
id: '/',
path: '/',
id: "/",
path: "/",
getParentRoute: () => rootRouteImport,
} as any)
} as any);
const RegisterIndexRoute = RegisterIndexRouteImport.update({
id: '/register/',
path: '/register/',
id: "/register/",
path: "/register/",
getParentRoute: () => rootRouteImport,
} as any)
} as any);
const LoginIndexRoute = LoginIndexRouteImport.update({
id: '/login/',
path: '/login/',
id: "/login/",
path: "/login/",
getParentRoute: () => rootRouteImport,
} as any)
} as any);
const R404IndexRoute = R404IndexRouteImport.update({
id: '/404/',
path: '/404/',
id: "/404/",
path: "/404/",
getParentRoute: () => rootRouteImport,
} as any)
} as any);
const AuthUsersIndexRoute = AuthUsersIndexRouteImport.update({
id: '/users/',
path: '/users/',
id: "/users/",
path: "/users/",
getParentRoute: () => AuthRoute,
} as any)
} as any);
const AuthDashboardIndexRoute = AuthDashboardIndexRouteImport.update({
id: '/dashboard/',
path: '/dashboard/',
id: "/dashboard/",
path: "/dashboard/",
getParentRoute: () => AuthRoute,
} as any)
} as any);
const Auth403IndexRoute = Auth403IndexRouteImport.update({
id: '/403/',
path: '/403/',
id: "/403/",
path: "/403/",
getParentRoute: () => AuthRoute,
} as any)
} as any);
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/404/': typeof R404IndexRoute
'/login/': typeof LoginIndexRoute
'/register/': typeof RegisterIndexRoute
'/403/': typeof Auth403IndexRoute
'/dashboard/': typeof AuthDashboardIndexRoute
'/users/': typeof AuthUsersIndexRoute
"/": typeof IndexRoute;
"/404/": typeof R404IndexRoute;
"/login/": typeof LoginIndexRoute;
"/register/": typeof RegisterIndexRoute;
"/403/": typeof Auth403IndexRoute;
"/dashboard/": typeof AuthDashboardIndexRoute;
"/users/": typeof AuthUsersIndexRoute;
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/404': typeof R404IndexRoute
'/login': typeof LoginIndexRoute
'/register': typeof RegisterIndexRoute
'/403': typeof Auth403IndexRoute
'/dashboard': typeof AuthDashboardIndexRoute
'/users': typeof AuthUsersIndexRoute
"/": typeof IndexRoute;
"/404": typeof R404IndexRoute;
"/login": typeof LoginIndexRoute;
"/register": typeof RegisterIndexRoute;
"/403": typeof Auth403IndexRoute;
"/dashboard": typeof AuthDashboardIndexRoute;
"/users": typeof AuthUsersIndexRoute;
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/_auth': typeof AuthRouteWithChildren
'/404/': typeof R404IndexRoute
'/login/': typeof LoginIndexRoute
'/register/': typeof RegisterIndexRoute
'/_auth/403/': typeof Auth403IndexRoute
'/_auth/dashboard/': typeof AuthDashboardIndexRoute
'/_auth/users/': typeof AuthUsersIndexRoute
__root__: typeof rootRouteImport;
"/": typeof IndexRoute;
"/_auth": typeof AuthRouteWithChildren;
"/404/": typeof R404IndexRoute;
"/login/": typeof LoginIndexRoute;
"/register/": typeof RegisterIndexRoute;
"/_auth/403/": typeof Auth403IndexRoute;
"/_auth/dashboard/": typeof AuthDashboardIndexRoute;
"/_auth/users/": typeof AuthUsersIndexRoute;
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/'
| '/404/'
| '/login/'
| '/register/'
| '/403/'
| '/dashboard/'
| '/users/'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/404' | '/login' | '/register' | '/403' | '/dashboard' | '/users'
fileRoutesByFullPath: FileRoutesByFullPath;
fullPaths: "/" | "/404/" | "/login/" | "/register/" | "/403/" | "/dashboard/" | "/users/";
fileRoutesByTo: FileRoutesByTo;
to: "/" | "/404" | "/login" | "/register" | "/403" | "/dashboard" | "/users";
id:
| '__root__'
| '/'
| '/_auth'
| '/404/'
| '/login/'
| '/register/'
| '/_auth/403/'
| '/_auth/dashboard/'
| '/_auth/users/'
fileRoutesById: FileRoutesById
| "__root__"
| "/"
| "/_auth"
| "/404/"
| "/login/"
| "/register/"
| "/_auth/403/"
| "/_auth/dashboard/"
| "/_auth/users/";
fileRoutesById: FileRoutesById;
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
AuthRoute: typeof AuthRouteWithChildren
R404IndexRoute: typeof R404IndexRoute
LoginIndexRoute: typeof LoginIndexRoute
RegisterIndexRoute: typeof RegisterIndexRoute
IndexRoute: typeof IndexRoute;
AuthRoute: typeof AuthRouteWithChildren;
R404IndexRoute: typeof R404IndexRoute;
LoginIndexRoute: typeof LoginIndexRoute;
RegisterIndexRoute: typeof RegisterIndexRoute;
}
declare module '@tanstack/react-router' {
declare module "@tanstack/react-router" {
interface FileRoutesByPath {
'/_auth': {
id: '/_auth'
path: ''
fullPath: '/'
preLoaderRoute: typeof AuthRouteImport
parentRoute: typeof rootRouteImport
}
'/': {
id: '/'
path: '/'
fullPath: '/'
preLoaderRoute: typeof IndexRouteImport
parentRoute: typeof rootRouteImport
}
'/register/': {
id: '/register/'
path: '/register'
fullPath: '/register/'
preLoaderRoute: typeof RegisterIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/login/': {
id: '/login/'
path: '/login'
fullPath: '/login/'
preLoaderRoute: typeof LoginIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/404/': {
id: '/404/'
path: '/404'
fullPath: '/404/'
preLoaderRoute: typeof R404IndexRouteImport
parentRoute: typeof rootRouteImport
}
'/_auth/users/': {
id: '/_auth/users/'
path: '/users'
fullPath: '/users/'
preLoaderRoute: typeof AuthUsersIndexRouteImport
parentRoute: typeof AuthRoute
}
'/_auth/dashboard/': {
id: '/_auth/dashboard/'
path: '/dashboard'
fullPath: '/dashboard/'
preLoaderRoute: typeof AuthDashboardIndexRouteImport
parentRoute: typeof AuthRoute
}
'/_auth/403/': {
id: '/_auth/403/'
path: '/403'
fullPath: '/403/'
preLoaderRoute: typeof Auth403IndexRouteImport
parentRoute: typeof AuthRoute
}
"/_auth": {
id: "/_auth";
path: "";
fullPath: "/";
preLoaderRoute: typeof AuthRouteImport;
parentRoute: typeof rootRouteImport;
};
"/": {
id: "/";
path: "/";
fullPath: "/";
preLoaderRoute: typeof IndexRouteImport;
parentRoute: typeof rootRouteImport;
};
"/register/": {
id: "/register/";
path: "/register";
fullPath: "/register/";
preLoaderRoute: typeof RegisterIndexRouteImport;
parentRoute: typeof rootRouteImport;
};
"/login/": {
id: "/login/";
path: "/login";
fullPath: "/login/";
preLoaderRoute: typeof LoginIndexRouteImport;
parentRoute: typeof rootRouteImport;
};
"/404/": {
id: "/404/";
path: "/404";
fullPath: "/404/";
preLoaderRoute: typeof R404IndexRouteImport;
parentRoute: typeof rootRouteImport;
};
"/_auth/users/": {
id: "/_auth/users/";
path: "/users";
fullPath: "/users/";
preLoaderRoute: typeof AuthUsersIndexRouteImport;
parentRoute: typeof AuthRoute;
};
"/_auth/dashboard/": {
id: "/_auth/dashboard/";
path: "/dashboard";
fullPath: "/dashboard/";
preLoaderRoute: typeof AuthDashboardIndexRouteImport;
parentRoute: typeof AuthRoute;
};
"/_auth/403/": {
id: "/_auth/403/";
path: "/403";
fullPath: "/403/";
preLoaderRoute: typeof Auth403IndexRouteImport;
parentRoute: typeof AuthRoute;
};
}
}
interface AuthRouteChildren {
Auth403IndexRoute: typeof Auth403IndexRoute
AuthDashboardIndexRoute: typeof AuthDashboardIndexRoute
AuthUsersIndexRoute: typeof AuthUsersIndexRoute
Auth403IndexRoute: typeof Auth403IndexRoute;
AuthDashboardIndexRoute: typeof AuthDashboardIndexRoute;
AuthUsersIndexRoute: typeof AuthUsersIndexRoute;
}
const AuthRouteChildren: AuthRouteChildren = {
Auth403IndexRoute: Auth403IndexRoute,
AuthDashboardIndexRoute: AuthDashboardIndexRoute,
AuthUsersIndexRoute: AuthUsersIndexRoute,
}
};
const AuthRouteWithChildren = AuthRoute._addFileChildren(AuthRouteChildren)
const AuthRouteWithChildren = AuthRoute._addFileChildren(AuthRouteChildren);
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
@@ -200,7 +193,7 @@ const rootRouteChildren: RootRouteChildren = {
R404IndexRoute: R404IndexRoute,
LoginIndexRoute: LoginIndexRoute,
RegisterIndexRoute: RegisterIndexRoute,
}
};
export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren)
._addFileTypes<FileRouteTypes>()
._addFileTypes<FileRouteTypes>();

View File

@@ -66,7 +66,15 @@ export const Toolbar = forwardRef<HTMLDivElement, ToolbarProps>(function Toolbar
),
},
],
[keywordInput, onClearSearch, onKeywordChange, onRoleChange, onSearch, roleValue, token.fontSize],
[
keywordInput,
onClearSearch,
onKeywordChange,
onRoleChange,
onSearch,
roleValue,
token.fontSize,
],
);
return (

View File

@@ -1,8 +1,8 @@
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/index.html"
}
]
}
"rewrites": [
{
"source": "/(.*)",
"destination": "/index.html"
}
]
}

View File

@@ -2,6 +2,23 @@
基于 [Next.js](https://nextjs.org) App Router、[Nextra 4](https://nextra.site) 与 `nextra-theme-docs` 的中文文档与模板应用Vite+、`apps/basic``apps/with-lingui`)同仓维护。
## 内容目录(侧栏分组)
| 分组 | 路径(`content/` 下) |
|------|------------------------|
| 概述 | `index.mdx` |
| 欢迎 | `welcome/documentation-intro.mdx` |
| 入门 | `getting-started/`(快速开始、`folder-structure``available-scripts` …) |
| 模板 | `templates/`(模板列表、`basic``with-lingui` |
| 开发 | `development/` |
| 样式与资源 | `styles-and-assets/` |
| 构建应用 | `building/` |
| 测试 | `testing/` |
| 后端对接 | `backend/` |
| 部署 | `deployment/` |
侧边栏顺序与标题由各目录旁 `_meta.js` 及根目录 `content/_meta.js` 配置。
## 端口说明
| 项目 | 默认开发地址 |
@@ -29,4 +46,4 @@ cd apps/docs && pnpm install && pnpm dev
## 设计说明
实现与信息架构见:`docs/specs/2026-04-15-apps-docs-nextra-plan.md`(及同目录 design spec若存在
初始实现见 `docs/specs/2026-04-15-apps-docs-nextra-plan.md`

View File

@@ -0,0 +1,13 @@
/** @type {import('nextra').MetaRecord} */
export default {
index: "概述",
welcome: "欢迎",
"getting-started": "入门",
templates: "模板",
development: "开发",
"styles-and-assets": "样式与资源",
building: "构建应用",
testing: "测试",
backend: "后端对接",
deployment: "部署",
};

View File

@@ -0,0 +1,4 @@
/** @type {import('nextra').MetaRecord} */
export default {
"proxying-api-requests": "开发代理与 Mock",
};

View File

@@ -0,0 +1,18 @@
---
title: 开发代理与 Mock
description: MSW、API 基地址与对接真实后端
---
# 开发代理与 Mock
## MSW开发默认
模板在开发环境使用 **MSW** 拦截 HTTP**handlers** 位于 `src/mocks/handlers`。无后端即可演示登录、菜单、用户 CRUD 等。
**Worker 目录**由 `package.json` 的 **`msw.workerDirectory`** 配置为 `public`,与 [public 目录](/styles-and-assets/public-folder) 说明一致。
## 对接真实 API
将 **`src/utils/http.ts`(或项目内统一 HTTP 封装)** 中的 **baseURL** 指向真实网关,并按环境关闭或绕过 MSW 初始化(具体开关以模板 `main.tsx` / 环境变量为准)。
跨域时需由**浏览器可访问**的网关配置 **CORS**;或通过开发代理将 `/api` 转发到后端(在 `vite.config.ts` 配置 `server.proxy`,按团队规范填写目标地址)。

View File

@@ -0,0 +1,7 @@
/** @type {import('nextra').MetaRecord} */
export default {
router: "路由",
"environment-variables": "环境变量",
performance: "性能测量",
"production-build": "生产构建",
};

View File

@@ -0,0 +1,12 @@
---
title: 环境变量
description: Vite 环境变量与 import.meta.env
---
# 环境变量
模板使用 **Vite**,请在 `.env`、`.env.development`、`.env.production` 等文件中定义变量,且 **客户端可访问的变量必须以 `VITE_` 前缀** 暴露。
在代码中通过 **`import.meta.env.VITE_*`** 读取。API 基地址等常量见各应用 **`src/utils/constants.ts`** 及 README。
不要把密钥写入前端可见的 `VITE_` 变量;敏感逻辑放在后端或构建时注入的服务端配置中。

View File

@@ -0,0 +1,11 @@
---
title: 性能测量
description: 开发与生产环境下的性能关注点
---
# 性能测量
- **开发**:关注 React/Ant Design 不必要的重渲染与过大列表;表格场景可结合虚拟滚动等方案(按需引入)。
- **生产**:使用浏览器 **Performance / Lighthouse** 与 **`vp build`** 产物体积联合判断。
模板未内置专用 APM接入外部监控时请在隐私与合规前提下配置采样率与错误上报范围。

View File

@@ -0,0 +1,17 @@
---
title: 生产构建
description: vp build 与预览
---
# 生产构建
在各模板目录:
```bash
vp build
vp preview
```
模板 `package.json` 中 **`build`** 脚本通常包含 **`tsc`** 与 **`vp build`**,请先通过类型检查再部署产物。
静态资源托管时,注意 **SPA 回退路由**(所有前端路径回退到 `index.html`)。若部署在子路径,需配置 Vite **`base`** 与路由一致。

View File

@@ -0,0 +1,16 @@
---
title: 路由
description: TanStack Router 文件路由与布局
---
# 路由
模板使用 **[TanStack Router](https://tanstack.com/router)** **文件路由**(插件根据 `src/routes` 生成 **`routeTree.gen.ts`**)。
常见模式:
- **根布局**`__root.tsx` 中包裹 `ConfigProvider`、Outlet 等。
- **认证布局**:如 `_auth.tsx`,与登录页路由分离。
- **鉴权**:在路由 `beforeLoad` 或组件内结合 **权限与 `/login` 跳转**(实现以模板代码为准)。
新增业务页时,在同目录追加路由文件并遵循现有目录约定;类型安全依赖生成的 route tree。

View File

@@ -1,17 +0,0 @@
---
title: 配置参考
description: 环境变量与构建相关简短说明
---
# 配置参考
## 模板应用(`apps/basic`、`apps/with-lingui`
- 使用 **Vite+**`vp`)管理依赖与开发/构建;具体脚本见各目录 `package.json`。
- **MSW** 在开发环境拦截 APIworker 目录由各应用 `package.json` 的 `msw.workerDirectory` 配置。
- 更完整的栈说明、目录树与测试命令见对应应用的 **README**(仓库内 `apps/basic/README.md`、`apps/with-lingui/README.md`)。
## 文档站(`apps/docs`
- **Next.js + Nextra**,无首期 `basePath`;生产构建:`pnpm run build`。
- 本地开发端口 **3000**,见 [apps/docs README](https://github.com/zuiidea/antd-admin/blob/master/apps/docs/README.md) 与设计说明 `docs/specs/2026-04-15-apps-docs-nextra-design.md`(若存在于仓库中)。

View File

@@ -0,0 +1,20 @@
---
title: 部署
sidebarTitle: 部署
description: 静态资源托管与 SPA 路由
asIndexPage: true
---
# 部署
## 构建产物
执行 **`vp build`** 后,产物默认位于各应用约定的 **`dist/`**(以 Vite 输出为准)。将 **`dist`** 部署到静态文件托管OSS、CDN、Netlify、Vercel 等)。
## SPA 路由
前端路由由 **TanStack Router** 管理,服务器需将所有 **文档路径回退到 `index.html`**,否则刷新子路径会 **404**。
## 应用若部署在子路径
设置 Vite **`base`** 为子路径前缀,并确保静态资源与路由跳转使用该前缀。仓库内若包含 **`vercel.json`** 等,可作为部署规则参考。

View File

@@ -0,0 +1,5 @@
/** @type {import('nextra').MetaRecord} */
export default {
"bundle-analysis": "构建体积分析",
"https-in-development": "开发环境 HTTPS",
};

View File

@@ -0,0 +1,13 @@
---
title: 构建体积分析
description: 查看打包体积与依赖分布的常用方式
---
# 构建体积分析
模板使用 **Vite**(经 Vite+ 调用)。分析产物体积的常见做法:
1. **`vp build`** 后查看终端输出的 chunk 大小汇总。
2. 需要可视化时,可在应用内按需接入 **rollup-plugin-visualizer**(或等价插件)生成 `stats.html`,再打开报告查看各模块占比。
本仓库模板**默认不内置**可视化分析插件;按需添加后记得仅在分析构建 profile 下启用,避免常驻增加配置复杂度。

View File

@@ -0,0 +1,10 @@
---
title: 开发环境 HTTPS
description: 本地启用 HTTPS 时的提示
---
# 开发环境 HTTPS
若需在开发环境启用 **HTTPS**(例如调试安全 Cookie、第三方 OAuth 回调),请参考 [Vite 服务器 HTTPS 配置](https://vite.dev/config/server-options.html#server-https):在模板 `vite.config.ts` 的 `server.https` 中配置证书,或通过 `vp dev` 支持的参数透传(以 Vite+ 当前版本文档为准)。
团队应统一证书来源(如 mkcert并在文档中注明 **勿将私钥提交到仓库**。

View File

@@ -1,22 +0,0 @@
---
title: 功能与约定
description: 能力概览并指向各应用 README 与源码
---
# 功能与约定
本 monorepo 在 **`apps/basic`** 与 **`apps/with-lingui`** 中提供同一套产品能力JWT、动态菜单与 RBAC、表格 URL 状态、MSW、Playwright 等)。差异主要在 **国际化与包名**,详见 [模板对比](/templates)。
## 进一步阅读
- **Basic 应用说明:** [apps/basic/README.md](https://github.com/zuiidea/antd-admin/blob/master/apps/basic/README.md)
- **Lingui 变体说明:** [apps/with-lingui/README.md](https://github.com/zuiidea/antd-admin/blob/master/apps/with-lingui/README.md)
- **通用 AI 指引Vite+** 各应用目录下的 `AGENTS.md`
## 源码入口(便于跳转)
| 主题 | 路径(两应用结构类似) |
|------|-------------------------|
| 根路由与 Ant Design 包裹 | `src/routes/__root.tsx` |
| 持久化 Store 工厂 | `src/stores/createPersistentStore.ts` |
| 设置与主题 | `src/stores/settings.ts` |

View File

@@ -0,0 +1,8 @@
/** @type {import('nextra').MetaRecord} */
export default {
"folder-structure": "目录结构",
"available-scripts": "可用脚本",
"supported-browsers": "浏览器与运行环境",
"supported-features": "模板自带能力",
"updating-releases": "升级与更新",
};

View File

@@ -0,0 +1,43 @@
---
title: 可用脚本
description: package.json 中与开发相关的 npm 脚本
---
# 可用脚本
在模板目录执行(需先 `vp install`)。两模板大部分脚本相同;**仅 with-lingui** 含 `i18n:*` 脚本。
## 开发与构建
| 脚本 | 说明 |
|------|------|
| `vp dev` | 启动开发服务器(默认端口 5173 |
| `vp build` | 生产构建(模板中常与 `tsc` 组合,见各 `package.json` |
| `vp preview` | 预览构建产物 |
## 质量
| 脚本 | 说明 |
|------|------|
| `vp fmt` | 格式化 |
| `vp lint` | Lint |
| `vp check --no-fmt` | 类型检查等(模板内常用 `check` |
## 测试
| 脚本 | 说明 |
|------|------|
| `pnpm run test:unit` | Vitest 单元测试 |
| `pnpm run test:e2e` | Playwright 全部 E2E |
| `pnpm run test:e2e:core` | 核心场景子集登录、users CRUD、refresh、RBAC、URL 状态) |
| `pnpm run test:e2e:ui` | Playwright UI 模式 |
## With Lingui 专有
| 脚本 | 说明 |
|------|------|
| `pnpm run i18n:extract` | 抽取文案 |
| `pnpm run i18n:compile` | 编译 catalog |
| `pnpm run i18n:check` | 抽取后校验 git diffCI 友好) |
具体以各应用 **`package.json` 的 `scripts`** 为准。

View File

@@ -0,0 +1,25 @@
---
title: 目录结构
description: 模板应用 src 目录职责说明
---
# 目录结构
两个模板的目录高度一致,差异主要在 **i18n`locales/`** 与 **部分脚本**。以下以 `apps/with-lingui` 为例(`apps/basic` 无 `locales/`,且无 Lingui 相关脚本)。
```
src/
├── api/ # Zod schema、接口常量与类型
├── components/ # 通用 UI表格壳、表单弹窗、布局等
├── hooks/ # 主题、权限、CRUD 等组合逻辑
├── locales/ # Lingui仅 with-linguien/zh .po
├── mocks/ # MSW handlers 与浏览器 worker
├── routes/ # TanStack Router 文件路由
├── stores/ # Zustandauth、settings 等持久化)
└── utils/ # HTTP 客户端、常量等
```
更完整的树状说明见:
- [apps/basic/README.md](https://github.com/zuiidea/antd-admin/blob/master/apps/basic/README.md)
- [apps/with-lingui/README.md](https://github.com/zuiidea/antd-admin/blob/master/apps/with-lingui/README.md)

View File

@@ -1,6 +1,8 @@
---
title: 快速开始
sidebarTitle: 快速开始
description: 环境要求、安装与本地运行(文档站与模板端口)
asIndexPage: true
---
# 快速开始

View File

@@ -0,0 +1,17 @@
---
title: 浏览器与运行环境
description: Node 版本与现代浏览器支持
---
# 浏览器与运行环境
## Node.js
- **要求 ≥ 20**(与仓库及 Vite+ 工具链一致)。
- 推荐使用与 `package.json` 中 **`packageManager`** 一致的 pnpm 版本,团队协作可减少锁文件漂移。
## 浏览器
模板面向 **现代 evergreen 浏览器**Chromium / Firefox / Safari 近年版本)。后台场景通常不要求 IE。
本地开发时使用 **HTTPS**、旧版浏览器或嵌入式 WebView 等约束,参见 [开发环境 HTTPS](/development/https-in-development)。

View File

@@ -0,0 +1,20 @@
---
title: 模板自带能力
description: 两模板共同具备的产品与技术能力
---
# 模板自带能力
**`apps/basic`** 与 **`apps/with-lingui`** 在业务能力上对齐,差异主要在 **国际化与包名、持久化键**等(见 [模板列表](/templates))。
两模板均包含:
- **JWT 登录**access / refreshZustand 持久化
- **动态菜单与 RBAC**服务端菜单、路由权限、403
- **表格 URL 状态**:分页、关键字、排序等与查询参数同步
- **MSW**:开发环境 Mock无需真实后端即可跑通流程
- **Playwright E2E**覆盖登录、CRUD、鉴权刷新、RBAC、URL 状态等(`test:e2e:core` 为核心子集)
**With Lingui** 额外包含LinguiJS 中英文、Ant Design locale 随语言切换、`.po` 抽取/编译工作流。
权威细节与代码入口仍以各应用 **README** 与 `src/` 为准;本页用于快速对齐「能做什么」。

View File

@@ -0,0 +1,19 @@
---
title: 升级与更新
description: 依赖与模板演进时的建议
---
# 升级与更新
## 依赖升级
- 使用 **Vite+**`vp`)管理依赖,避免绕过 `vp` 直接大面积 `pnpm up` 导致与模板锁定的工具链不一致。
- 升级 **Ant Design / TanStack / React** 大版本前,建议先阅读官方迁移说明,并在单分支上跑通 `vp check`、`test:unit`、`test:e2e:core` 与 `vp build`。
## 跟随本仓库模板
若从本 monorepo 拷贝或对比模板代码,可用 `git` 按需 cherry-pick 改动,并注意 **`apps/basic` 与 `apps/with-lingui` 在 i18n 与文案上的差异**,避免把 Lingui 专用改动误合并到 basic。
## With Lingui 文案
升级 `@lingui/*` 后建议执行 `pnpm run i18n:extract` 与 `pnpm run i18n:compile`,并检查 `src/locales` 是否有冲突或弃用 API。

View File

@@ -1,8 +1,12 @@
---
title: 概述
description: antd-admin monorepo 与模板说明
description: antd-admin monorepo 与文档导读
---
# 概述
本仓库提供两个可运行模板:**`apps/basic`**(英文-only)与 **`apps/with-lingui`**Lingui 中英文)。详细对比见「模板对比」。
本仓库提供两个可运行的后台管理模板:**[`apps/basic`](https://github.com/zuiidea/antd-admin/tree/master/apps/basic)**(英文界面)与 **[`apps/with-lingui`](https://github.com/zuiidea/antd-admin/tree/master/apps/with-lingui)**Lingui 中英文)。技术栈以 **React 19、Ant Design 6、TanStack Router & Query、Vite+`vp`、MSW、Playwright** 为核心。
侧栏按「欢迎 → 入门 → 模板 → 开发 → 样式与资源 → 构建 → 测试 → 后端对接 → 部署」组织。建议从 **[入门](/getting-started)** 开始,再在 **[模板](/templates)** 中选择应用。
GitHub[zuiidea/antd-admin](https://github.com/zuiidea/antd-admin)

View File

@@ -0,0 +1,8 @@
/** @type {import('nextra').MetaRecord} */
export default {
stylesheet: "添加样式",
"css-modules": "CSS Modules",
"images-fonts-files": "图片、字体与静态文件",
"public-folder": "public 目录",
"code-splitting": "代码分割",
};

View File

@@ -0,0 +1,10 @@
---
title: 代码分割
description: 动态 import 与路由懒加载
---
# 代码分割
基于 **Vite** 与 **TanStack Router**,可按路由或大屏块使用 **`import()` 动态导入** 实现懒加载,减小首屏 bundle。
拆分粒度需在「首屏体验」与「请求次数」之间权衡;后台系统常见做法是对低频管理页做 lazy对登录后首屏必要依赖保持同步加载。

View File

@@ -0,0 +1,10 @@
---
title: CSS Modules
description: 组件旁 *.module.css 的用法提示
---
# CSS Modules
可在组件旁增加 **`*.module.css`**,由 Vite 按模块作用域编译,避免类名污染全局。
布局与侧边栏等目录下已有 **少量 `.css` 与组件同目录** 的写法,可按相同模式扩展。与 Ant Design 共存时,注意层级与 `:global` 的使用范围,避免破坏组件库默认样式。

View File

@@ -0,0 +1,11 @@
---
title: 图片、字体与静态文件
description: 资源放置与引用方式
---
# 图片、字体与静态文件
- **`src/` 内 import**:图片等可作为模块 import适合需要哈希与打包优化的资源。
- **`public/`**:适合固定 URL、不经打包处理的静态文件见 [public 目录](/styles-and-assets/public-folder))。
字体文件若体积较大,注意浏览器加载策略与子集化,避免阻塞首屏。

View File

@@ -0,0 +1,10 @@
---
title: public 目录
description: public 与 MSW Service Worker
---
# public 目录
模板将 **`public/`** 用于不会被 bundler 改名的静态资源(如 `favicon`)。
同时,**MSW** 浏览器端 worker 的路径由 **`package.json` → `msw.workerDirectory`** 指向 `public`(两模板一致)。调整 `public` 结构时注意 **不要破坏 Mock Service Worker** 所需的生成文件与服务注册路径。

View File

@@ -0,0 +1,13 @@
---
title: 添加样式
description: 全局样式与 Ant Design 主题入口
---
# 添加样式
模板通常包含:
- **全局样式**:如 `src/index.css`,用于 reset、滚动条或少量全局覆盖。
- **Ant Design 主题**:通过 `ConfigProvider` 与项目内 **`tokenBuilders` / `useAppTheme`** 等组合(见 `src/hooks`、`src/routes/__root.tsx`)。
新增页面级样式时,优先使用 **Ant Design 组件与 token**,减少全局 `!important`;必要时再使用 CSS 文件或 CSS Modules见下一节

View File

@@ -0,0 +1,5 @@
/** @type {import('nextra').MetaRecord} */
export default {
basic: "Basic",
"with-lingui": "With Lingui",
};

View File

@@ -0,0 +1,30 @@
---
title: Basic 模板
description: apps/basic — 英文-only 模板说明摘要
---
# Basic 模板
路径:**[`apps/basic`](https://github.com/zuiidea/antd-admin/tree/master/apps/basic)**。
## 定位
英文界面、**不包含 Lingui**Ant Design 使用固定 **`en_US`** locale。依赖相对精简适合只需英文后台或自行接入其它 i18n 方案的团队。
## 技术栈摘要
构建:[Vite+](https://viteplus.dev)UIAnt Design 6路由TanStack Router数据TanStack Query本地状态Zustand校验ZodMockMSWE2EPlaywright。
## 常用命令
```bash
cd apps/basic
vp install
vp dev
```
详见 **[可用脚本](/getting-started/available-scripts)** 与各应用 `package.json`。
## 权威文档
完整特性、目录树与脚本说明以仓库内 **[apps/basic/README.md](https://github.com/zuiidea/antd-admin/blob/master/apps/basic/README.md)** 为准。

View File

@@ -1,9 +1,11 @@
---
title: 模板对比
description: basic 与 with-lingui 的包名、国际化与持久化键对比
title: 模板列表
sidebarTitle: 模板列表
description: Basic 与 With Lingui 的选型与差异总览
asIndexPage: true
---
# 模板对比
# 模板列表
以下字段以仓库内 **`package.json`** 与 **`src/stores/settings.ts`** 为准。
@@ -14,7 +16,12 @@ description: basic 与 with-lingui 的包名、国际化与持久化键对比
| **Ant Design `ConfigProvider` locale** | 固定 `antd/locale/en_US` | 随设置切换:`en` → `en_US``zh` → `zh_CN`(见 `src/routes/__root.tsx` |
| **Zustand persistsettings`name`** | `settings-storage-basic` | `settings-storage` |
选型建议
## 选型建议
- 只要英文、希望依赖最少:选 **`apps/basic`**。
- 需要中英文切换、Lingui 工作流与 Ant Design 随语言联动:选 **`apps/with-lingui`**。
- 只要英文、希望依赖最少:选 **[Basic](/templates/basic)**。
- 需要中英文切换、Lingui 工作流与 Ant Design 随语言联动:选 **[With Lingui](/templates/with-lingui)**。
## 子页面
- [Basic 模板](/templates/basic)
- [With Lingui 模板](/templates/with-lingui)

View File

@@ -0,0 +1,36 @@
---
title: With Lingui 模板
description: apps/with-lingui — 中英双语与 Lingui 工作流
---
# With Lingui 模板
路径:**[`apps/with-lingui`](https://github.com/zuiidea/antd-admin/tree/master/apps/with-lingui)**。
## 定位
在 Basic 能力集之上提供 **LinguiJS** 中英双语文案、**Ant Design locale** 与语言设置联动,以及 **`.po` 抽取/编译** 流程。为仓库中更完整的一号模板(`package.json` 的 `name` 为 `antd-admin`)。
## 技术栈补充
在 Basic 技术栈基础上增加 Lingui 6`src/locales/{en,zh}/messages.po` 为翻译源;`lingui.config.ts` 与 Vite 插件见应用内配置。
## 国际化命令
| 命令 | 作用 |
|------|------|
| `pnpm run i18n:extract` | 从源码抽取可翻译字符串 |
| `pnpm run i18n:compile` | 编译为运行时可加载的 message |
| `pnpm run i18n:check` | 抽取后检查工作区无未提交变更(适合 CI |
## 常用命令
```bash
cd apps/with-lingui
vp install
vp dev
```
## 权威文档
完整技术栈表、功能列表、目录树、E2E 子集说明、以及 **Cursor 与 `.github/instructions` 的 AI 指引** 以 **[apps/with-lingui/README.md](https://github.com/zuiidea/antd-admin/blob/master/apps/with-lingui/README.md)** 为准。

View File

@@ -0,0 +1,5 @@
/** @type {import('nextra').MetaRecord} */
export default {
"running-tests": "运行测试",
"debugging-tests": "调试测试",
};

View File

@@ -0,0 +1,16 @@
---
title: 调试测试
description: Playwright 调试与 UI 模式
---
# 调试测试
- **UI 模式**(模板已提供脚本):
```bash
pnpm run test:e2e:ui
```
- ** headed / debug**:可使用 Playwright CLI 标志对单测文件调试,例如 `pnpm exec playwright test --debug`。
MSW 与真实网络环境差异可能导致用例不稳定;调试时可先确认 **Mock 是否按预期拦截**(见 [开发代理与 Mock](/backend/proxying-api-requests))。

View File

@@ -0,0 +1,23 @@
---
title: 运行测试
description: Vitest 单元测试与 Playwright E2E
---
# 运行测试
## 单元测试Vitest
```bash
pnpm run test:unit
```
由 **Vite+** 封装 Vitest请勿脱离 `vp`/`pnpm scripts` 随意单独安装冲突版本的 Vitest参见各应用 **`AGENTS.md`**)。
## E2EPlaywright
```bash
pnpm run test:e2e # 全部
pnpm run test:e2e:core # 核心子集登录、users、refresh、RBAC、URL 状态)
```
首次在机器上跑 E2E 前,按 Playwright 文档安装浏览器依赖(`pnpm exec playwright install` 等,以官方说明为准)。

View File

@@ -0,0 +1,4 @@
/** @type {import('nextra').MetaRecord} */
export default {
"documentation-intro": "文档介绍",
};

View File

@@ -0,0 +1,25 @@
---
title: 文档介绍
description: 本文档的阅读方式与章节说明
---
# 文档介绍
欢迎使用 **Antd Admin** 模板文档。本站与模板应用(`apps/basic`、`apps/with-lingui`)同仓维护,面向在前台仓库中选型、运行与扩展模板的开发者。
## 章节结构
| 章节 | 内容侧重 |
|------|-----------|
| **概述** | 仓库与模板一句话定位 |
| **欢迎 · 文档介绍** | 本节:导航说明 |
| **入门** | 环境、目录、脚本、浏览器支持、模板能力、升级提示 |
| **模板** | [模板列表](/templates)Basic / With Lingui 选型与子页 |
| **开发** | 本地开发、体积分析、HTTPS 等 |
| **样式与资源** | 全局样式、CSS Modules、静态资源、public、代码分割 |
| **构建应用** | 路由、环境变量、性能、生产构建 |
| **测试** | 单元测试与 E2E |
| **后端对接** | MSW Mock、API 基地址与代理思路 |
| **部署** | 构建产物与部署注意点 |
更完整的模板说明仍以仓库内 **`apps/*/README.md`** 为准;本站用中文串联常用路径,减少在 GitHub 间跳转的成本。

View File

@@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />
import "./.next/dev/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

View File

@@ -3,25 +3,25 @@
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "next dev -p 3000",
"dev": "next dev -p 3003",
"build": "next build",
"start": "next start -p 3000",
"lint": "next lint"
},
"dependencies": {
"next": "^15.1.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"nextra": "^4.0.0",
"nextra-theme-docs": "^4.0.0"
"next": "^16.2.4",
"react": "^19.2.5",
"react-dom": "^19.2.5",
"nextra": "^4.6.1",
"nextra-theme-docs": "^4.6.1"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
"@types/node": "^22.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"typescript": "~5.9.0",
"eslint": "^9.0.0",
"eslint-config-next": "^15.1.0"
"@eslint/eslintrc": "^3.3.5",
"@types/node": "^25.6.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"typescript": "~6.0.3",
"eslint": "^10.2.1",
"eslint-config-next": "^16.2.4"
}
}
}

View File

@@ -5,7 +5,7 @@ import { NextResponse } from "next/server";
* Browsers or other localhost apps (e.g. MSW) may request `/mockServiceWorker.js`.
* Without this, the request hits `[[...mdxPath]]` and Nextra tries to load it as MDX.
*/
export function middleware(request: NextRequest) {
export function proxy(request: NextRequest) {
if (request.nextUrl.pathname === "/mockServiceWorker.js") {
return new NextResponse(
"// antd-admin docs: no MSW; unregister stray workers from other localhost apps if needed.\n",

View File

@@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["dom", "dom.iterable", "esnext"],
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -11,11 +15,27 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"jsx": "react-jsx",
"incremental": true,
"plugins": [{ "name": "next" }],
"paths": { "@/*": ["./*"] }
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./*"
]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}

569
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff