| | |
| | | - **UI**:Ant Design 5 + `@ant-design/icons` |
| | | - **高级组件**:`@ant-design/pro-components`(表格优先使用其 `ProTable`) |
| | | - **状态**:Zustand 5(登录态持久化到 localStorage) |
| | | - **请求**:Axios(统一封装在 `src/api/request.ts`) |
| | | - **样式**:SCSS + Ant Design 主题 token + CSS 变量 |
| | | - **日期**:Day.js(已配置中文 locale) |
| | | |
| | |
| | | |
| | | ```text |
| | | src/ |
| | | ├── api/ # 接口层;当前只有模拟登录 auth.ts |
| | | ├── api/ # 接口层:request.ts(axios 封装)与登录 auth.ts |
| | | ├── components/ # 通用组件:AntdAppBridge(message 注入) |
| | | ├── layouts/ # BasicLayout:侧边栏、头部、内容区、面包屑 |
| | | ├── pages/ # 页面,按业务域分目录 |
| | | │ ├── login/ |
| | | │ ├── dashboard/ |
| | | │ ├── system/users/ |
| | | │ ├── business/{orders,customers}/ |
| | | │ ├── business/orders/ |
| | | │ ├── customers/list/ |
| | | │ └── error/NotFound.tsx |
| | | │ # 页面目录:index.tsx、columns.tsx、types.ts、server.ts、同名 .scss(按需) |
| | | ├── router/ |
| | | │ ├── routeConfig.tsx # 路由 + 菜单唯一数据源(含页面组件) |
| | | │ ├── menu.tsx # 菜单过滤与 antd Menu 结构生成 |
| | |
| | | ├── store/ # Zustand 登录态 |
| | | ├── styles/ # 全局 SCSS、通用页面样式 |
| | | ├── types/ # 全局类型 |
| | | ├── utils/ # 工具:feedback.ts(全局错误提示) |
| | | └── main.tsx # ConfigProvider + AntdApp + BrowserRouter |
| | | ``` |
| | | |
| | |
| | | |
| | | `src/router/routeConfig.tsx` 是**唯一数据源**。新增页面只需在这里配置 `path`、`title`、`icon`、`element`,侧边栏、面包屑会自动读取。 |
| | | |
| | | - 支持 2-3 级嵌套,例如:`系统管理 → 用户管理`。 |
| | | - 支持 2-3 级嵌套,例如:`用户与权限 → 用户管理`。 |
| | | - `src/router/index.tsx` 把菜单配置转换成 React Router 的嵌套路由。 |
| | | - 分组路由(无 `element`)通过 `<Outlet />` 渲染子页面,默认跳转到第一个子页面。 |
| | | - 未匹配路由显示 404,普通页面组件位于 `BasicLayout` 内。 |
| | |
| | | ### 2. 登录态 |
| | | |
| | | - `src/store/auth.ts`:Zustand store,持久化 `token` 与 `user`。 |
| | | - 登录 / 退出:`src/api/auth.ts` 提供模拟登录。 |
| | | - 演示账号: |
| | | - `admin / admin123`:超级管理员。 |
| | | - `user / user123`:普通运营账号。 |
| | | - 登录 / 退出:`src/api/auth.ts` 调用 `POST /auth/tenant-login`,参数为 `{ phone, password, tenantCode }`。 |
| | | - 接口基础地址由 `.env` 中的 `VITE_API_BASE_URL` 配置。 |
| | | - 未登录访问受保护页面会跳转 `/login`,登录成功后返回原地址。 |
| | | |
| | | ### 3. 布局与样式 |
| | |
| | | |
| | | ## 六、新增页面流程 |
| | | |
| | | 1. 在 `src/pages/<业务域>/<页面>/` 下创建 `index.tsx`(有表格时增加 `columns.tsx`,有独立样式时增加同名 `.scss`)。 |
| | | 1. 在 `src/pages/<业务域>/<页面>/` 下创建 `index.tsx`(有表格时增加 `columns.tsx`,接口调用放在 `server.ts`,类型放 `types.ts`,有独立样式时增加同名 `.scss`)。 |
| | | 2. 在 `src/router/routeConfig.tsx` 中增加路由配置: |
| | | - 使用完整路径(如 `/system/users`)。 |
| | | - 配置 `title`、`icon`、`element`。 |
| | |
| | | |
| | | ## 七、接口与状态约定 |
| | | |
| | | - 所有请求统一放在 `src/api/` 下,按业务域拆分文件;不要在页面内直接写请求实现。 |
| | | - 当前 `src/api/auth.ts` 是前端模拟接口。接入真实后端时替换为实际请求,并保留登录态写入 store 的流程。 |
| | | - **每个接口都必须为其请求(request)与响应(response)定义 `interface`**,并在 `server.ts` 中通过 `request<TReq, TRes>` 显式标注泛型;禁止使用 `any` 或省略类型。 |
| | | - 类型统一定义在页面目录的 `types.ts` 中(跨页面复用的放在 `src/api/` 对应业务域文件)。 |
| | | - 命名约定:`<业务>Request` / `<业务>Response`,例如 `TenantRoleListRequest`、`TenantRoleListResponse`。 |
| | | - 请求体 / 查询参数建模为 `XxxRequest`;响应建模为 `XxxResponse`,对应接口返回 `data` 的结构(若后端是 `Result<T>`,`Response` 指 `data` 部分)。 |
| | | - 无请求参数时也应显式定义,例如 `type TenantRoleListRequest = Record<string, never>`,不要留空或使用 `undefined`。 |
| | | |
| | | ```ts |
| | | // types.ts |
| | | export interface TenantRoleToggleStatusRequest { |
| | | id: number; |
| | | } |
| | | export interface TenantRoleToggleStatusResponse { |
| | | id: number; |
| | | status: RoleStatus; |
| | | } |
| | | |
| | | // server.ts |
| | | export const toggleRoleStatus = ({ id }: TenantRoleToggleStatusRequest) => |
| | | request<TenantRoleToggleStatusRequest, TenantRoleToggleStatusResponse>({ |
| | | url: `/tenant/roles/${id}/toggle-status`, |
| | | method: 'PUT', |
| | | headers: getAuthHeaders(), |
| | | }); |
| | | ``` |
| | | |
| | | - 页面级接口调用统一放在页面目录下的 `server.ts`,页面组件通过它调用接口,不要在组件内直接写请求实现。 |
| | | - 跨页面复用的接口可放在 `src/api/` 下,按业务域拆分文件。 |
| | | - 网络请求统一使用 `src/api/request.ts` 的 `request`(基于 axios),不要在页面或 `server.ts` 中直接使用 axios。 |
| | | - 开发环境通过 Vite 代理 `/proxy-api` 转发到 `VITE_API_PROXY_TARGET`(未配置时取 `VITE_API_BASE_URL`),因此浏览器端不会产生跨域请求;生产环境需后端配置 CORS,或使用同域反向代理。 |
| | | - 泛型:`request<TReq, TRes>(config, options)`,分别表示请求参数/请求体与响应 `data` 的类型。 |
| | | - 默认只返回响应 `data`;传 `parse: false` 时返回完整 `AxiosResponse`。 |
| | | - 默认自动提示错误,`showError: false` 可关闭;失败抛出 `ApiError`,包含 `status`、`data`、`response`、`config` 与原始错误。 |
| | | - 默认合并方法、URL、参数与请求体都相同的并发请求;`merge: false` 时每次都单独发送。 |
| | | - 通过 `signal: AbortSignal` 取消当前调用方的请求。 |
| | | - `src/api/auth.ts` 调用真实登录接口,登录成功后仍由 `src/store/auth.ts` 写入登录态。 |
| | | - 全局登录态只放在 `src/store/auth.ts`;页面局部状态使用 `useState` / `useMemo`。 |
| | | - 不要在前端持久化敏感信息;真实项目的 Token 建议使用 HttpOnly Cookie,并由后端处理过期与刷新。 |
| | | |
| | |
| | | |
| | | - 使用 BrowserRouter,生产环境需要配置 SPA fallback:所有前端路由回退到 `index.html`。 |
| | | - 构建产物在 `dist/`。 |
| | | - 开发环境的跨域由 Vite 代理 `/proxy-api` 处理;生产环境需要后端开启 CORS,或将前端与接口部署在同一域名下由反向代理转发。 |
| | | - 当前主包较大(Ant Design 全量依赖),后续可通过路由懒加载 / 手动分包优化。 |