# CRM Admin 项目开发指南(CLAUDE.md) > Vite 6 + React 18 + TypeScript(strict)+ Ant Design 5 + `@ant-design/pro-components` + Zustand 5 + Axios + SCSS 的后台管理平台。 > BrowserRouter SPA,包含多级路由菜单、登录 / 退出与登录态校验;日期库为 Day.js(已配置中文 locale)。 ## 一、常用命令 ```bash npm install # 安装依赖 npm run dev # 启动开发服务器(http://localhost:5173) npm run typecheck # TypeScript 类型检查 npm run build # 类型检查 + 生产构建 npm run preview # 预览生产构建 ``` 改动代码后至少执行 `npm run typecheck`;涉及构建配置或样式时再执行 `npm run build`。 ## 二、目录与核心架构 ```text src/ ├── api/ # request.ts(axios 封装)、auth.ts、authHeaders.ts ├── components/ # 通用组件(AntdAppBridge 等) ├── layouts/ # BasicLayout:侧边栏、头部、内容区、面包屑 ├── pages/ # 页面,按业务域分目录(页面目录结构见「三、3」) ├── router/ # routeConfig.tsx(路由 + 菜单唯一数据源)、menu.tsx、index.tsx ├── store/ # Zustand 登录态 ├── styles/ # 全局 SCSS、通用页面样式 ├── types/ # 全局类型(PageResult 等) ├── utils/ # 工具(feedback.ts 全局错误提示) └── main.tsx # ConfigProvider + AntdApp + BrowserRouter ``` - **路由与菜单**:`routeConfig.tsx` 是唯一数据源,配置 `path`、`title`、`icon`、`element` 后侧边栏与面包屑自动生效。支持 2-3 级嵌套;分组路由(无 `element`)通过 `` 渲染并默认跳转到第一个子页面;未匹配路由显示 404。 - **登录态**:`src/store/auth.ts` 持久化 `token` 与 `user`;`src/api/auth.ts` 调用 `POST /auth/tenant-login`(`{ phone, password, tenantCode }`)。未登录访问受保护页面跳转 `/login`,登录成功后返回原地址。 - **布局与样式**:页面只负责内容区。全局 CSS 变量 `--app-primary`、`--app-bg`、`--app-border`、`--app-text`、`--app-text-secondary`;通用类 `.page-header`、`.page-toolbar`、`.filter-card`、`.table-card`、`.text-muted`;Ant Design 主题在 `main.tsx` 的 `ConfigProvider` 统一配置。 ## 三、代码风格(必遵守) ### 1. 统一使用箭头函数 组件、工具函数、Hook、事件处理函数都使用箭头函数,不新增 `function` 声明。 ```tsx const UserList = () => { const handleSubmit = async () => { // ... }; return ; }; export default UserList; ``` ### 2. 优先使用现成组件 写功能前先找现成能力,不要重复造轮子: - **优先使用 Ant Design 组件**与已有封装:布局 `BasicLayout`、登录校验 `RequireAuth`、提示与确认框使用 `AntdApp.useApp()` 的 `message` / `modal`(**不要**用 `message.success()` / `Modal.confirm()` 静态方法)。 - **表格优先使用 ProTable**:搜索、分页、工具栏开箱即用,不要手写「筛选表单 + Table」。 - **表单内的接口选项必须用 ProForm 组件**:Select、TreeSelect、Cascader 等只要选项来自接口(含父组件传入的接口数据),使用 `ProFormSelect` / `ProFormTreeSelect` / `ProFormCascader`,不要用原生控件包 `Form.Item`;静态枚举不受此限制。远程搜索用 `request`(配合 `debounceTime`),已有数据通过 `options` / `fieldProps` 传入,校验规则直接写在组件的 `rules` 上。 ```tsx // ✅ 选项来自接口 getLeaderOptions({ keyword: keyWords })} /> // ❌ 原生控件包在 Form.Item 中