# 代码规范 **分析日期:** 2026-05-07 ## 命名规范 **文件命名:** - 组件文件:PascalCase + `.tsx` 扩展名(如 `DashboardShell.tsx`、`AddOutfitDialog.tsx`) - 工具函数/库文件:kebab-case + `.ts` 扩展名(如 `error-handler.ts`、`client.ts`) - 特殊情况:对话框类组件使用 kebab-case(如 `add-outfit-dialog.tsx`、`delete-confirmation-dialog.tsx`) **函数命名:** - 使用 camelCase(如 `handleLogin`、`fetchOutfits`、`mapBackendOutfit`) - API 函数:动词 + 名词,camelCase(如 `getOutfits`、`createOutfit`、`updateOutfit`、`deleteOutfit`) - 事件处理函数:`handle` + 事件名(如 `handleSubmit`、`handleChange`、`handleSendVerificationCode`) - 工具函数:动词 + 目标(如 `formatDate`、`toDisplayOutfit`) **变量命名:** - 状态变量:camelCase(如 `email`、`password`、`isLoading`、`selectedOutfit`) - 布尔值:`is` 或 `has` 前缀(如 `isLoading`、`isSubmitting`、`hasPermission`) - 常量:UPPER_SNAKE_CASE(如 `TOAST_LIMIT`、`TOAST_REMOVE_DELAY`、`API_BASE_URL`) **类型/接口命名:** - PascalCase(如 `EmailLoginResponse`、`DashboardShellProps`、`ApiResponse`) - Props 接口:`组件名Props` 后缀(如 `ButtonProps`、`DashboardShellProps`) - 联合类型:`RoleName`、`PermissionModule` ## 代码样式 **格式化:** - 使用 TypeScript strict 模式(`tsconfig.json` 中 `"strict": true`) - 目标:ES6(`target: "ES6"`) - 模块化解析:`bundler` 模式(用于 Next.js) - 无 ESLint/Prettier 配置文件(`next.config.mjs` 中 `eslint.ignoreDuringBuilds: true`) - 代码风格通过 TypeScript 编译器和 Next.js 内置检查 **缩进和空格:** - 使用 2 空格缩进(根据代码库一致性) - 函数声明和块语句间使用一致空格 **类型注解:** - 所有函数参数必须有类型注解 - 所有变量应有类型注解(特别是导出的接口和公共函数返回值) - 使用 TypeScript 严格模式防止隐式 `any` ## 导入组织 **顺序:** 1. React 和 Next.js 核心库(`import React from "react"`、`import { useState } from "react"`) 2. Next.js 功能(`import { useRouter } from "next/navigation"`、`import Link from "next/link"`) 3. 第三方库(`import axios from "axios"`、`import Cookies from "js-cookie"`) 4. 本项目组件(`import { Button } from "@/components/ui/button"`) 5. 本项目库和工具(`import { cn } from "@/lib/utils"`) 6. 本项目 hooks(`import { useToast } from "@/components/ui/use-toast"`) 7. 类型导入(`import type { ApiResponse } from "./client"`) **路径别名:** - 项目配置 `@/*` 指向项目根目录 - 组件:`@/components/...` - 库函数:`@/lib/...` - Hooks:`@/hooks/...` - 类型和接口:通过 `@/lib/api/types` 集中导入 - UI 组件:`@/components/ui/...` ## 错误处理 **模式:** - 使用 `try-catch` 处理异步操作和 API 调用(见 `auth.ts`、`outfits.ts`) - 创建自定义错误类 `ApiError` 扩展 `Error`,包含 `status` 属性(见 `error-handler.ts` 第 46-54 行) - 统一的错误处理函数 `handleApiException()` 将不同类型的错误转换为用户友好的消息(见 `error-handler.ts` 第 79-90 行) - 错误信息映射表 `errorMessages` 定义特定错误代码(`USER_NOT_FOUND`、`ROLE_EXISTS` 等)的消息 **API 错误处理:** - 在 Axios 响应拦截器中处理 401 未授权错误:清除 token 并重定向到登录页面(见 `client.ts` 第 54-61 行) - 对 API 失败使用 Radix Toast 组件显示错误提示(见 `error-handler.ts` 第 69-76 行、第 93-100 行) - 统一的 `handleApiRequest()` 包装器函数处理成功/失败情况并自动显示 toast(见 `error-handler.ts` 第 102-144 行) **日志:** - 使用 `console.log()`、`console.warn()`、`console.error()` 进行调试和错误追踪 - API 请求/响应在拦截器中记录详细日志,包括 token 检查、请求头、响应状态(见 `client.ts` 第 20-66 行) - 使用 emoji 表情增强日志可读性(`🔍 Token检查`、`✅ Token已添加`、`❌ 响应错误`) ## 日志记录 **框架:** `console`(浏览器原生) **使用规范:** - API 请求/响应日志在 Axios 拦截器中集中管理 - 所有认证流程加日志(token 检查、保存、清除) - 错误信息带上上下文(URL、状态码、方法) - 生产环境应考虑减少日志或使用第三方服务(未配置) ## 注释 **何时写注释:** - JSDoc 风格注释用于公共 API 函数(见 `auth.ts` 第 5-7 行、第 24-30 行) - 注释解释"为什么"而不是"是什么" - 复杂业务逻辑或算法需要行内注释 **JSDoc/TSDoc 风格:** ```typescript /** * 邮箱登录接口 * @param email 邮箱 * @param password 密码 * @returns 包含token的响应 */ export const emailLogin = async (email: string, password: string): Promise => { // ... } ``` **中文注释:** 所有注释使用中文(符合 CLAUDE.md 的语言偏好) ## 函数设计 **大小:** - 函数长度通常 20-50 行(见 `handleLogin` 在 `login/page.tsx` 第 28-63 行) - 超过 100 行的函数应考虑拆分(如 `AddOutfitDialog` 组件中的多步表单分离为 Tabs) **参数:** - 单个参数优于多个参数 - 对象参数用于选项(如 `handleApiRequest()` 的 options 对象,第 104-110 行) - 类型参数用于泛型函数(如 `handleResponse()`、`ApiResponse`) **返回值:** - 异步函数返回 `Promise` - 布尔查询函数返回 `boolean`(如 `hasPermission()`、`isAuthenticated()`) - 数据获取返回具体类型或 `null`(见 `getOutfit()` 返回 `Promise`) ## 模块设计 **导出:** - 公共 API 函数从 `lib/api/` 模块导出(如 `emailLogin`、`getOutfits`) - 类型从 `lib/api/types.ts` 集中导出 - Utility 函数从 `lib/utils.ts` 导出(如 `cn()` 用于样式合并) **Barrel 文件:** - `lib/api/index.ts` 作为 barrel 文件,导出所有 API 函数以便统一导入 - 组件库采用 Radix UI + shadcn 风格,每个组件文件独立,无 barrel 文件 ## React 和组件规范 **状态管理:** - 使用 React Hooks(`useState`、`useEffect`、`useCallback`)进行本地状态管理 - 在客户端组件中集中管理表单状态(见 `add-outfit-dialog.tsx` 第 24-36 行) **组件模式:** - 所有表单和交互组件用 `"use client"` 指令标记 - Page 组件(`app/*/page.tsx`)使用 `"use client"` 支持交互 - 使用 Radix UI 和 shadcn 风格组件库,组件文件在 `components/ui/` - Props 接口扩展原生 HTML 属性(如 `ButtonProps extends React.ButtonHTMLAttributes`) **样式:** - 使用 Tailwind CSS 类名 - 使用 `cn()` 工具函数(基于 `clsx` + `tailwind-merge`)合并条件样式(见 `button.tsx` 第 47 行) - 使用 `class-variance-authority` (CVA) 定义组件变体(见 `button.tsx` 第 7-34 行) - 颜色、间距、圆角通过 Tailwind 配置变量(CSS 变量)定义 ## 表单与验证 **表单状态:** - 使用 `useState` 管理表单字段状态 - 表单提交通过 `handleSubmit()` 函数处理(见 `add-outfit-dialog.tsx` 第 38-56 行) **验证:** - 基本的客户端验证(如检查空值:`if (!formData.name || !formData.description)`) - React Hook Form + Zod 在 package.json 中定义但代码中未广泛使用 - 服务器端验证通过 API 响应处理(返回 400/422 等错误状态) **通知:** - 成功/错误提示使用 Sonner toast 或 Radix Toast(通过 `useToast()` hook) - toast 样式变体:`"default"`、`"destructive"`(见 `error-handler.ts` 第 71-75 行) ## 权限控制 **权限检查:** - 运行时权限检查通过 `hasPermission(module)` 函数(见 `permissions.ts` 第 85-87 行) - 权限矩阵定义在 `PERMISSION_MATRIX` 对象,映射角色到模块列表 - 路由保护:中间件 `middleware.ts` 检查 cookie 中的 token,无 token 重定向到登录 - 组件级权限检查:`DashboardShell` 使用 `hasPathPermission()` 处理访问拒绝(见 `dashboard-shell.tsx` 第 23-24 行) **角色存储:** - 登录后在 `localStorage` 中存储 `user_role` 字符串(见 `auth.ts` 第 58 行) - 超级管理员标识存储为 `is_superuser`(见 `auth.ts` 第 53 行) - token 同时存储在 `localStorage` 和 Cookie 中(见 `auth.ts` 第 49、63 行) ## 异步操作 **模式:** - 使用 `async/await` 处理异步 API 调用 - 加载状态通过 `isLoading` 布尔值跟踪(见 `login/page.tsx` 第 19、30 行) - 模拟延迟用于开发和测试(见 `client.ts` `simulateDelay()` 和 `mockResponse()` 函数) ## API 集成 **Axios 配置:** - 在 `lib/api/client.ts` 创建 Axios 实例,基础 URL 来自环境变量 `NEXT_PUBLIC_API_BASE_URL` - 请求拦截器自动注入 Authorization 头(Bearer token) - 响应拦截器处理 401 错误并触发重新登录 - API 端点前缀:`/api/v1/admin/` **适配器模式:** - 后端返回数据结构与前端显示结构不同 - 使用 `mapBackendOutfit()` 等适配器函数转换数据(见 `outfits.ts` 第 5-22 行) - 适配器在 `lib/api/adapters.ts` 中集中管理 --- *规范分析日期:2026-05-07*