9.1 KiB
Raw Blame History

代码规范

分析日期: 2026-05-07

命名规范

文件命名:

  • 组件文件PascalCase + .tsx 扩展名(如 DashboardShell.tsxAddOutfitDialog.tsx
  • 工具函数/库文件kebab-case + .ts 扩展名(如 error-handler.tsclient.ts
  • 特殊情况:对话框类组件使用 kebab-caseadd-outfit-dialog.tsxdelete-confirmation-dialog.tsx

函数命名:

  • 使用 camelCasehandleLoginfetchOutfitsmapBackendOutfit
  • API 函数:动词 + 名词camelCasegetOutfitscreateOutfitupdateOutfitdeleteOutfit
  • 事件处理函数:handle + 事件名(如 handleSubmithandleChangehandleSendVerificationCode
  • 工具函数:动词 + 目标(如 formatDatetoDisplayOutfit

变量命名:

  • 状态变量camelCaseemailpasswordisLoadingselectedOutfit
  • 布尔值:ishas 前缀(如 isLoadingisSubmittinghasPermission
  • 常量UPPER_SNAKE_CASETOAST_LIMITTOAST_REMOVE_DELAYAPI_BASE_URL

类型/接口命名:

  • PascalCaseEmailLoginResponseDashboardShellPropsApiResponse<T>
  • Props 接口:组件名Props 后缀(如 ButtonPropsDashboardShellProps
  • 联合类型:RoleNamePermissionModule

代码样式

格式化:

  • 使用 TypeScript strict 模式(tsconfig.json"strict": true
  • 目标ES6target: "ES6"
  • 模块化解析:bundler 模式(用于 Next.js
  • 无 ESLint/Prettier 配置文件(next.config.mjseslint.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. 本项目 hooksimport { 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.tsoutfits.ts
  • 创建自定义错误类 ApiError 扩展 Error,包含 status 属性(见 error-handler.ts 第 46-54 行)
  • 统一的错误处理函数 handleApiException() 将不同类型的错误转换为用户友好的消息(见 error-handler.ts 第 79-90 行)
  • 错误信息映射表 errorMessages 定义特定错误代码(USER_NOT_FOUNDROLE_EXISTS 等)的消息

API 错误处理:

  • 在 Axios 响应拦截器中处理 401 未授权错误:清除 token 并重定向到登录页面(见 client.ts 第 54-61 行)
  • 对 API 失败使用 Radix Toast 组件显示错误提示(见 error-handler.ts 第 69-76 行、第 93-100 行)
  • 统一的 handleApiRequest() 包装器函数处理成功/失败情况并自动显示 toasterror-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 风格:

/**
 * 邮箱登录接口
 * @param email 邮箱
 * @param password 密码
 * @returns 包含token的响应
 */
export const emailLogin = async (email: string, password: string): Promise<EmailLoginResponse> => {
  // ...
}

中文注释: 所有注释使用中文(符合 CLAUDE.md 的语言偏好)

函数设计

大小:

  • 函数长度通常 20-50 行(见 handleLoginlogin/page.tsx 第 28-63 行)
  • 超过 100 行的函数应考虑拆分(如 AddOutfitDialog 组件中的多步表单分离为 Tabs

参数:

  • 单个参数优于多个参数
  • 对象参数用于选项(如 handleApiRequest() 的 options 对象,第 104-110 行)
  • 类型参数用于泛型函数(如 handleResponse<T>()ApiResponse<T>

返回值:

  • 异步函数返回 Promise<T>
  • 布尔查询函数返回 boolean(如 hasPermission()isAuthenticated()
  • 数据获取返回具体类型或 null(见 getOutfit() 返回 Promise<Outfit>

模块设计

导出:

  • 公共 API 函数从 lib/api/ 模块导出(如 emailLogingetOutfits
  • 类型从 lib/api/types.ts 集中导出
  • Utility 函数从 lib/utils.ts 导出(如 cn() 用于样式合并)

Barrel 文件:

  • lib/api/index.ts 作为 barrel 文件,导出所有 API 函数以便统一导入
  • 组件库采用 Radix UI + shadcn 风格,每个组件文件独立,无 barrel 文件

React 和组件规范

状态管理:

  • 使用 React HooksuseStateuseEffectuseCallback)进行本地状态管理
  • 在客户端组件中集中管理表单状态(见 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<HTMLButtonElement>

样式:

  • 使用 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