Files
bim_engine/docs-old/AI代码规范模板.md

50 KiB
Raw Permalink Blame History

AI 代码规范模板

本文档是通用的 AI 协作与代码规范模板,适用于 TypeScript、Java、React、Vue 等技术栈。 使用时请根据项目实际情况进行调整。


📋 目录

第一部分:通用规范

第二部分:语言特定规范

第三部分:框架特定规范

第四部分:工程化规范

附录


第一部分:通用规范

1. AI 协作基本原则

1.1 语言要求(强制)

输出语言

  • 所有输出必须使用中文,包括:
    • 代码注释(强制:所有代码注释必须使用中文,解释清晰详细
    • 文档说明
    • 与用户交流
    • 错误信息和日志输出

思考语言

  • 思考过程也必须使用中文
    • 分析问题时用中文思考
    • 解释代码逻辑时用中文
    • 讨论设计方案时用中文

代码中的字符串

  • 根据业务需求决定(支持国际化的项目使用翻译键)
  • 注释和文档必须使用中文

1.2 思考与沟通方式

思考过程要求

  • 分析问题时,用中文描述问题、分析思路、得出结论
  • 解释代码时,用中文说明逻辑、设计意图、实现方式
  • 讨论方案时,用中文描述优缺点、选择理由

工作流程

  1. 理解需求:用中文理解用户需求,明确任务目标
  2. 分析问题:用中文分析问题,梳理相关代码和架构
  3. 设计方案:用中文设计解决方案,考虑边界情况
  4. 实现代码:编写代码,添加中文注释
  5. 测试验证:用中文描述测试结果和发现的问题
  6. 更新文档:用中文更新相关文档

1.3 问答与开发流程

用户询问"如何实现"时的处理流程

当用户询问如何实现某个功能时,必须遵循以下流程:

  1. 分析需求:用中文理解用户需求,明确要实现的功能

  2. 制定详细开发计划:必须包含以下内容:

    • 需要修改的文件列表
    • 需要新增的文件列表
    • 需要删除的文件列表
    • 每个文件的作用说明
    • 对整体结构的影响
  3. 展示开发计划:以清晰的格式展示给用户

  4. 等待用户确认在用户明确同意之前,绝对不能修改任何代码

  5. 用户同意后执行:只有在用户明确表示同意后,才能开始修改代码

开发计划格式模板

## 开发计划

### 需要修改的文件
1. `src/xxx/xxx.ts`
   - 修改:添加新的 `xxxMethod()` 方法
   - 作用:提供某某功能

### 需要新增的文件
1. `src/xxx/index.ts`
   - 作用:实现某某功能
   - 内容:包含 XxxClass 类

### 需要删除的文件
1. `src/old/xxx.ts`
   - 原因:已被新组件替代
   - **处理方式**:移动到 `.recycle/YYYY-MM-DD/` 文件夹

### 对整体结构的影响
- **架构影响**:说明对现有架构的影响
- **功能影响**:说明对现有功能的影响
- **文档更新**:需要更新哪些文档
- **风险点**:可能的风险和注意事项

请确认是否按照此计划进行开发?

用户直接要求修改时的处理

当用户直接要求修改代码时(如"帮我修改XXX"、"实现XXX功能"),可以:

  • 直接执行代码修改
  • 但仍需遵循其他规范
  • 删除文件时仍需移动到回收文件夹

2. 通用编码规范

2.1 代码可读性

基本原则

  • 优先保证代码可读性,有时可以不使用高级函数,使用低级函数
  • 必须添加详细的中文注释,解释代码逻辑和设计意图
  • 函数、类、接口必须有文档注释(使用中文)
  • 复杂逻辑必须添加行内注释说明

代码组织

  • 单个文件不宜超过 500 行
  • 单个函数不宜超过 50 行
  • 单行代码不宜超过 120 字符
  • 嵌套层级不宜超过 4 层

2.2 命名规范

通用命名规则

类型 命名方式 示例
类名 大驼峰 (PascalCase) UserManager, OrderService
接口名 大驼峰,可选 I 前缀 IUserService, UserRepository
类型/枚举 大驼峰 UserStatus, OrderType
函数/方法 小驼峰 (camelCase) getUserInfo, handleSubmit
变量 小驼峰 userName, isActive, itemCount
常量 全大写下划线 MAX_COUNT, API_BASE_URL
私有属性 下划线前缀或 # _cache, #privateField
文件名 小写短横线或小写 user-manager.ts, index.ts
CSS 类名 小写短横线 (kebab-case) user-card, btn-primary

命名语义化

// ✅ 好的命名 - 语义清晰
const userList: User[] = [];
const isLoading: boolean = false;
const maxRetryCount: number = 3;
function calculateTotalPrice(items: Item[]): number { }
function validateUserInput(input: string): boolean { }

// ❌ 不好的命名 - 语义不清
const list: any[] = [];
const flag: boolean = false;
const num: number = 3;
function calc(arr: any[]): number { }
function check(str: string): boolean { }

布尔值命名

  • 使用 ishascanshouldwill 等前缀
  • 例如:isActivehasPermissioncanEditshouldUpdate

函数命名

  • 动词开头,表明行为
  • 查询:getfindqueryfetchload
  • 创建:createaddinsertsave
  • 更新:updatemodifysetchange
  • 删除:deleteremoveclearreset
  • 判断:ishascanshouldvalidatecheck
  • 转换:toconvertparseformat
  • 事件:handleontriggeremit

2.3 注释规范

文档注释JSDoc / JavaDoc

TypeScript / JavaScript

/**
 * 计算订单总价
 * 
 * @description 根据商品列表计算总价,包含折扣计算
 * @param items - 商品列表
 * @param discount - 折扣比例0-1默认为 1无折扣
 * @returns 计算后的总价
 * @throws {Error} 当商品列表为空时抛出错误
 * @example
 * const total = calculateTotal(items, 0.8); // 8折
 */
function calculateTotal(items: CartItem[], discount: number = 1): number {
    if (items.length === 0) {
        throw new Error('商品列表不能为空');
    }
    // 计算原价总和
    const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0);
    // 应用折扣
    return subtotal * discount;
}

Java

/**
 * 计算订单总价
 * 
 * <p>根据商品列表计算总价,包含折扣计算</p>
 *
 * @param items 商品列表
 * @param discount 折扣比例0-1默认为 1无折扣
 * @return 计算后的总价
 * @throws IllegalArgumentException 当商品列表为空时抛出
 * @since 1.0.0
 * @author AI Assistant
 */
public BigDecimal calculateTotal(List<CartItem> items, BigDecimal discount) {
    // 实现逻辑
}

行内注释

// 单行注释:解释接下来一行或几行代码的作用

/*
 * 多行注释:
 * 用于解释复杂的逻辑块
 * 或临时禁用代码
 */

// TODO: 待完成的功能
// FIXME: 需要修复的问题
// HACK: 临时解决方案,需要优化
// NOTE: 重要说明
// DEPRECATED: 已废弃,请使用新方法

注释原则

  • 解释为什么,而不是是什么:代码本身说明做什么,注释说明为什么
  • 保持注释与代码同步:代码修改后必须更新注释
  • 不要注释显而易见的代码:避免无意义的注释
  • 复杂业务逻辑必须注释:特别是涉及特定业务规则的代码

2.4 错误处理

基本原则

  • 所有异步操作必须有错误处理
  • 错误信息必须清晰、有意义,使用中文
  • 区分可恢复错误和不可恢复错误
  • 不要吞掉异常(空 catch 块)

TypeScript 错误处理

// ✅ 正确的错误处理
async function fetchUserData(userId: string): Promise<User> {
    try {
        const response = await fetch(`/api/users/${userId}`);
        
        if (!response.ok) {
            // 根据状态码抛出具体错误
            if (response.status === 404) {
                throw new Error(`用户不存在:${userId}`);
            }
            throw new Error(`请求失败:${response.status}`);
        }
        
        return await response.json();
    } catch (error) {
        // 记录错误日志
        console.error('获取用户数据失败:', error);
        // 重新抛出或返回默认值
        throw error;
    }
}

// ❌ 错误的错误处理
async function badFetch(userId: string) {
    try {
        const res = await fetch(`/api/users/${userId}`);
        return await res.json();
    } catch (e) {
        // 空 catch 块,吞掉了错误
    }
}

Java 错误处理

// ✅ 正确的错误处理
public User getUserById(Long id) {
    try {
        return userRepository.findById(id)
            .orElseThrow(() -> new BusinessException("用户不存在:" + id));
    } catch (DataAccessException e) {
        log.error("查询用户失败ID{}", id, e);
        throw new ServiceException("数据库查询异常", e);
    }
}

// 自定义业务异常
public class BusinessException extends RuntimeException {
    private final String code;
    
    public BusinessException(String message) {
        super(message);
        this.code = "BUSINESS_ERROR";
    }
    
    public BusinessException(String code, String message) {
        super(message);
        this.code = code;
    }
}

2.5 日志规范

日志级别

级别 使用场景
ERROR 错误,影响功能正常运行
WARN 警告,潜在问题但不影响运行
INFO 重要业务信息,如用户操作、接口调用
DEBUG 调试信息,开发环境使用
TRACE 详细追踪信息,极少使用

日志内容要求

// ✅ 好的日志
logger.info(`用户登录成功用户ID${userId}IP${clientIp}`);
logger.error(`订单创建失败,订单号:${orderId},原因:${error.message}`, error);
logger.warn(`库存不足商品ID${productId},当前库存:${stock},请求数量:${quantity}`);

// ❌ 不好的日志
logger.info('success');           // 信息不完整
logger.error(error);              // 缺少上下文
console.log('here');              // 调试代码未清理

日志原则

  • 包含足够的上下文信息ID、参数等
  • 敏感信息脱敏(密码、手机号等)
  • 生产环境不使用 console.log
  • 异常日志要包含堆栈信息

2.6 安全规范

输入验证

// ✅ 验证所有外部输入
function processUserInput(input: unknown): string {
    // 类型检查
    if (typeof input !== 'string') {
        throw new Error('输入必须是字符串');
    }
    // 长度检查
    if (input.length > 1000) {
        throw new Error('输入长度超出限制');
    }
    // 内容清理
    return sanitize(input);
}

XSS 防护

// ❌ 危险:直接插入 HTML
element.innerHTML = userInput;

// ✅ 安全:使用 textContent 或转义
element.textContent = userInput;
// 或
element.innerHTML = escapeHtml(userInput);

敏感数据处理

// ❌ 不要在日志中输出敏感信息
console.log(`用户密码:${password}`);

// ✅ 脱敏处理
console.log(`手机号:${phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')}`);

3. 文件与文档管理

3.1 文件删除规范(强制)

严禁直接删除文件,必须遵循以下流程:

步骤 1创建回收文件夹

在项目根目录创建 .recycle/ 文件夹(如果不存在)

步骤 2按日期组织

  • .recycle/ 下按日期创建子文件夹
  • 格式:YYYY-MM-DD(如 2024-01-15
  • 同一天删除的文件存放在同一个日期文件夹中

步骤 3移动文件而非删除

# ❌ 错误方式
rm src/old-file.ts

# ✅ 正确方式
DATE=$(date +%Y-%m-%d)
mkdir -p .recycle/$DATE/src
mv src/old-file.ts .recycle/$DATE/src/old-file.ts

步骤 4保持目录结构

在日期文件夹中保持原文件的目录结构

例如:src/components/old.ts.recycle/2024-01-15/src/components/old.ts

回收文件夹结构示例

.recycle/
├── 2024-01-15/
│   ├── README.md          # 可选:记录删除原因
│   └── src/
│       └── components/
│           └── old-component.ts
└── 2024-02-20/
    └── src/
        └── services/
            └── old-service.ts

3.2 文档更新规则

必须更新的情况

操作 需要更新的文档
新增文件 在相关文档中添加文件描述
删除文件 从文档中移除对应条目
修改文件功能 更新对应文件的描述
新增组件/模块 添加说明,创建详细文档
修改 API 同步更新 API 文档
修改架构 更新架构设计部分
修改配置 更新配置说明

更新方式

  1. 修改代码后,立即更新相关文档
  2. 确保文档与代码保持一致
  3. 如果发现文档过时,优先更新文档

第二部分:语言特定规范

4. TypeScript 规范

4.1 类型定义规范

优先使用 interface 定义对象类型

// ✅ 推荐:使用 interface
interface UserInfo {
    id: string;
    name: string;
    email: string;
    age?: number;           // 可选属性
    readonly createdAt: Date; // 只读属性
}

// 接口继承
interface AdminUser extends UserInfo {
    role: 'admin';
    permissions: string[];
}

使用 type 定义联合类型、交叉类型

// 联合类型
type Status = 'pending' | 'processing' | 'completed' | 'failed';
type ID = string | number;

// 交叉类型
type UserWithMeta = UserInfo & {
    metadata: Record<string, unknown>;
};

// 工具类型
type PartialUser = Partial<UserInfo>;
type RequiredUser = Required<UserInfo>;
type ReadonlyUser = Readonly<UserInfo>;
type UserKeys = keyof UserInfo;

4.2 避免 any使用正确的类型

// ❌ 避免使用 any
function processData(data: any): any {
    return data.value;
}

// ✅ 使用 unknown + 类型守卫
function processData(data: unknown): string {
    if (typeof data === 'object' && data !== null && 'value' in data) {
        return String((data as { value: unknown }).value);
    }
    throw new Error('无效的数据格式');
}

// ✅ 使用泛型
function processData<T extends { value: string }>(data: T): string {
    return data.value;
}

4.3 泛型使用

// 基础泛型
function identity<T>(value: T): T {
    return value;
}

// 泛型约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key];
}

// 泛型接口
interface Repository<T> {
    findById(id: string): Promise<T | null>;
    findAll(): Promise<T[]>;
    save(entity: T): Promise<T>;
    delete(id: string): Promise<void>;
}

// 泛型类
class BaseService<T> {
    constructor(private repository: Repository<T>) {}
    
    async getById(id: string): Promise<T | null> {
        return this.repository.findById(id);
    }
}

4.4 模块导入导出

// ✅ 导入顺序(按此顺序组织)
// 1. Node.js 内置模块
import path from 'path';
import fs from 'fs';

// 2. 第三方库
import React from 'react';
import axios from 'axios';

// 3. 项目内部模块 - 绝对路径
import { UserService } from '@/services/user';
import { formatDate } from '@/utils/date';

// 4. 项目内部模块 - 相对路径
import { Button } from '../components/Button';
import { useAuth } from './hooks/useAuth';

// 5. 类型导入
import type { User, UserRole } from '@/types';

// 6. 样式文件
import './styles.css';
// ✅ 导出方式
// 命名导出 - 推荐用于工具函数、类型等
export function formatDate(date: Date): string { }
export interface UserInfo { }
export const MAX_COUNT = 100;

// 默认导出 - 推荐用于组件、类
export default class UserService { }
export default function UserCard() { }

// 重新导出
export { UserService } from './user-service';
export * from './types';
export { default as Button } from './Button';

4.5 异步编程

// ✅ 使用 async/await
async function fetchUserData(userId: string): Promise<User> {
    try {
        const response = await fetch(`/api/users/${userId}`);
        if (!response.ok) {
            throw new Error(`HTTP error: ${response.status}`);
        }
        return await response.json();
    } catch (error) {
        console.error('获取用户数据失败:', error);
        throw error;
    }
}

// ✅ 并行请求
async function fetchMultipleUsers(ids: string[]): Promise<User[]> {
    const promises = ids.map(id => fetchUserData(id));
    return Promise.all(promises);
}

// ✅ 带超时的请求
async function fetchWithTimeout<T>(
    promise: Promise<T>,
    timeoutMs: number
): Promise<T> {
    const timeout = new Promise<never>((_, reject) => {
        setTimeout(() => reject(new Error('请求超时')), timeoutMs);
    });
    return Promise.race([promise, timeout]);
}

4.6 枚举与常量

// ✅ 字符串枚举 - 推荐
enum OrderStatus {
    Pending = 'PENDING',
    Processing = 'PROCESSING',
    Completed = 'COMPLETED',
    Cancelled = 'CANCELLED'
}

// ✅ const 枚举 - 编译时内联
const enum Direction {
    Up = 'UP',
    Down = 'DOWN',
    Left = 'LEFT',
    Right = 'RIGHT'
}

// ✅ 常量对象 + as const - 更灵活
const HTTP_STATUS = {
    OK: 200,
    CREATED: 201,
    BAD_REQUEST: 400,
    UNAUTHORIZED: 401,
    NOT_FOUND: 404,
    INTERNAL_ERROR: 500
} as const;

type HttpStatusCode = typeof HTTP_STATUS[keyof typeof HTTP_STATUS];

5. Java 规范

5.1 包结构与命名

标准包结构

com.company.project
├── controller/          # 控制器层
│   └── UserController.java
├── service/             # 服务层
│   ├── UserService.java          # 接口
│   └── impl/
│       └── UserServiceImpl.java  # 实现
├── repository/          # 数据访问层
│   └── UserRepository.java
├── model/               # 数据模型
│   ├── entity/          # 数据库实体
│   │   └── User.java
│   ├── dto/             # 数据传输对象
│   │   ├── UserDTO.java
│   │   └── UserCreateRequest.java
│   └── vo/              # 视图对象
│       └── UserVO.java
├── config/              # 配置类
│   └── WebConfig.java
├── common/              # 公共模块
│   ├── exception/       # 异常类
│   ├── util/            # 工具类
│   └── constant/        # 常量类
└── Application.java     # 启动类

类命名规范

类型 命名规则 示例
控制器 Xxx Controller UserController
服务接口 XxxService UserService
服务实现 XxxServiceImpl UserServiceImpl
数据访问 XxxRepository / XxxMapper UserRepository
实体类 Xxx User, Order
DTO XxxDTO / XxxRequest / XxxResponse UserDTO
VO XxxVO UserVO
工具类 XxxUtil / XxxUtils / XxxHelper DateUtils
常量类 XxxConstants ApiConstants
枚举 XxxEnum / XxxType / XxxStatus OrderStatus
异常 XxxException BusinessException

5.2 类设计原则

实体类

/**
 * 用户实体
 * 
 * @author AI Assistant
 * @since 1.0.0
 */
@Data
@Entity
@Table(name = "t_user")
public class User implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    /**
     * 用户ID
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    /**
     * 用户名
     */
    @Column(nullable = false, length = 50)
    private String username;
    
    /**
     * 邮箱
     */
    @Column(nullable = false, unique = true)
    private String email;
    
    /**
     * 状态0-禁用1-启用
     */
    private Integer status;
    
    /**
     * 创建时间
     */
    @CreatedDate
    private LocalDateTime createdAt;
    
    /**
     * 更新时间
     */
    @LastModifiedDate
    private LocalDateTime updatedAt;
}

服务类

/**
 * 用户服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
    
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    
    /**
     * 根据ID获取用户
     *
     * @param id 用户ID
     * @return 用户信息
     * @throws BusinessException 用户不存在时抛出
     */
    @Override
    @Transactional(readOnly = true)
    public UserVO getUserById(Long id) {
        log.info("查询用户信息ID{}", id);
        
        User user = userRepository.findById(id)
            .orElseThrow(() -> new BusinessException("用户不存在:" + id));
        
        return convertToVO(user);
    }
    
    /**
     * 创建用户
     *
     * @param request 创建请求
     * @return 用户ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createUser(UserCreateRequest request) {
        log.info("创建用户,用户名:{}", request.getUsername());
        
        // 检查用户名是否存在
        if (userRepository.existsByUsername(request.getUsername())) {
            throw new BusinessException("用户名已存在");
        }
        
        // 创建用户实体
        User user = new User();
        user.setUsername(request.getUsername());
        user.setEmail(request.getEmail());
        user.setPassword(passwordEncoder.encode(request.getPassword()));
        user.setStatus(1);
        
        // 保存并返回ID
        User saved = userRepository.save(user);
        log.info("用户创建成功ID{}", saved.getId());
        
        return saved.getId();
    }
}

5.3 异常处理

自定义异常体系

/**
 * 基础业务异常
 */
@Getter
public class BusinessException extends RuntimeException {
    
    private final String code;
    private final String message;
    
    public BusinessException(String message) {
        super(message);
        this.code = "BUSINESS_ERROR";
        this.message = message;
    }
    
    public BusinessException(String code, String message) {
        super(message);
        this.code = code;
        this.message = message;
    }
}

/**
 * 全局异常处理器
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    /**
     * 处理业务异常
     */
    @ExceptionHandler(BusinessException.class)
    public Result<Void> handleBusinessException(BusinessException e) {
        log.warn("业务异常:{}", e.getMessage());
        return Result.fail(e.getCode(), e.getMessage());
    }
    
    /**
     * 处理参数校验异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> handleValidationException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldErrors().stream()
            .map(error -> error.getField() + ": " + error.getDefaultMessage())
            .collect(Collectors.joining(", "));
        log.warn("参数校验失败:{}", message);
        return Result.fail("VALIDATION_ERROR", message);
    }
    
    /**
     * 处理未知异常
     */
    @ExceptionHandler(Exception.class)
    public Result<Void> handleException(Exception e) {
        log.error("系统异常:", e);
        return Result.fail("SYSTEM_ERROR", "系统繁忙,请稍后重试");
    }
}

5.4 Controller 规范

/**
 * 用户管理接口
 */
@Slf4j
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
@Tag(name = "用户管理", description = "用户相关接口")
public class UserController {
    
    private final UserService userService;
    
    /**
     * 获取用户详情
     *
     * @param id 用户ID
     * @return 用户信息
     */
    @GetMapping("/{id}")
    @Operation(summary = "获取用户详情")
    public Result<UserVO> getUser(@PathVariable Long id) {
        return Result.success(userService.getUserById(id));
    }
    
    /**
     * 获取用户列表
     *
     * @param query 查询条件
     * @return 用户列表
     */
    @GetMapping
    @Operation(summary = "获取用户列表")
    public Result<PageResult<UserVO>> listUsers(@Valid UserQuery query) {
        return Result.success(userService.listUsers(query));
    }
    
    /**
     * 创建用户
     *
     * @param request 创建请求
     * @return 用户ID
     */
    @PostMapping
    @Operation(summary = "创建用户")
    public Result<Long> createUser(@Valid @RequestBody UserCreateRequest request) {
        return Result.success(userService.createUser(request));
    }
    
    /**
     * 更新用户
     *
     * @param id 用户ID
     * @param request 更新请求
     * @return 操作结果
     */
    @PutMapping("/{id}")
    @Operation(summary = "更新用户")
    public Result<Void> updateUser(
            @PathVariable Long id,
            @Valid @RequestBody UserUpdateRequest request) {
        userService.updateUser(id, request);
        return Result.success();
    }
    
    /**
     * 删除用户
     *
     * @param id 用户ID
     * @return 操作结果
     */
    @DeleteMapping("/{id}")
    @Operation(summary = "删除用户")
    public Result<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return Result.success();
    }
}

5.5 统一响应格式

/**
 * 统一响应结果
 *
 * @param <T> 数据类型
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    /**
     * 状态码
     */
    private String code;
    
    /**
     * 消息
     */
    private String message;
    
    /**
     * 数据
     */
    private T data;
    
    /**
     * 时间戳
     */
    private long timestamp = System.currentTimeMillis();
    
    /**
     * 成功响应
     */
    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode("SUCCESS");
        result.setMessage("操作成功");
        result.setData(data);
        return result;
    }
    
    /**
     * 成功响应(无数据)
     */
    public static <T> Result<T> success() {
        return success(null);
    }
    
    /**
     * 失败响应
     */
    public static <T> Result<T> fail(String code, String message) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(message);
        return result;
    }
}

第三部分:框架特定规范

6. React 规范

6.1 组件设计原则

函数组件 + TypeScript

/**
 * 用户卡片组件
 * 
 * @description 展示用户基本信息的卡片组件
 */
interface UserCardProps {
    /** 用户信息 */
    user: User;
    /** 是否显示详情 */
    showDetails?: boolean;
    /** 编辑回调 */
    onEdit?: (user: User) => void;
    /** 删除回调 */
    onDelete?: (userId: string) => void;
    /** 子元素 */
    children?: React.ReactNode;
}

const UserCard: React.FC<UserCardProps> = ({
    user,
    showDetails = false,
    onEdit,
    onDelete,
    children
}) => {
    // 组件逻辑
    return (
        <div className="user-card">
            {/* 组件内容 */}
        </div>
    );
};

export default UserCard;

组件文件结构

components/
└── UserCard/
    ├── index.tsx           # 组件主文件
    ├── UserCard.tsx        # 组件实现(可选,复杂组件时分离)
    ├── UserCard.module.css # 样式文件CSS Modules
    ├── UserCard.test.tsx   # 测试文件
    ├── types.ts            # 类型定义(复杂时分离)
    └── hooks.ts            # 组件专用 Hooks可选

6.2 Hooks 使用规范

Hooks 使用顺序

function UserProfile({ userId }: { userId: string }) {
    // 1. useState - 状态定义
    const [user, setUser] = useState<User | null>(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState<Error | null>(null);
    
    // 2. useRef - 引用
    const containerRef = useRef<HTMLDivElement>(null);
    
    // 3. useContext - 上下文
    const { theme } = useContext(ThemeContext);
    
    // 4. 自定义 Hooks
    const { data, isLoading } = useQuery(['user', userId], fetchUser);
    
    // 5. useCallback - 缓存回调
    const handleEdit = useCallback(() => {
        // 处理编辑
    }, [userId]);
    
    // 6. useMemo - 缓存计算结果
    const displayName = useMemo(() => {
        return user ? `${user.firstName} ${user.lastName}` : '';
    }, [user]);
    
    // 7. useEffect - 副作用
    useEffect(() => {
        // 副作用逻辑
        return () => {
            // 清理函数
        };
    }, [userId]);
    
    // 8. 条件渲染和返回
    if (loading) return <Loading />;
    if (error) return <Error message={error.message} />;
    
    return <div ref={containerRef}>{/* 内容 */}</div>;
}

自定义 Hook 规范

/**
 * 用户数据获取 Hook
 * 
 * @param userId 用户ID
 * @returns 用户数据、加载状态、错误信息
 */
function useUser(userId: string) {
    const [user, setUser] = useState<User | null>(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState<Error | null>(null);
    
    useEffect(() => {
        let cancelled = false;
        
        async function fetchUser() {
            try {
                setLoading(true);
                setError(null);
                const data = await userApi.getUser(userId);
                if (!cancelled) {
                    setUser(data);
                }
            } catch (err) {
                if (!cancelled) {
                    setError(err instanceof Error ? err : new Error('未知错误'));
                }
            } finally {
                if (!cancelled) {
                    setLoading(false);
                }
            }
        }
        
        fetchUser();
        
        // 清理函数:防止组件卸载后设置状态
        return () => {
            cancelled = true;
        };
    }, [userId]);
    
    return { user, loading, error };
}

6.3 状态管理

本地状态 vs 全局状态

// ✅ 本地状态:组件内部使用,不需要共享
const [isOpen, setIsOpen] = useState(false);
const [inputValue, setInputValue] = useState('');

// ✅ 全局状态:多个组件共享,使用状态管理库
// 例如:用户信息、主题设置、购物车等

使用 Zustand推荐

import { create } from 'zustand';

/**
 * 用户状态 Store
 */
interface UserStore {
    user: User | null;
    isAuthenticated: boolean;
    login: (user: User) => void;
    logout: () => void;
    updateUser: (updates: Partial<User>) => void;
}

const useUserStore = create<UserStore>((set) => ({
    user: null,
    isAuthenticated: false,
    
    login: (user) => set({ user, isAuthenticated: true }),
    
    logout: () => set({ user: null, isAuthenticated: false }),
    
    updateUser: (updates) => set((state) => ({
        user: state.user ? { ...state.user, ...updates } : null
    }))
}));

// 使用
function UserProfile() {
    const { user, logout } = useUserStore();
    // ...
}

6.4 性能优化

// ✅ 使用 React.memo 避免不必要的重渲染
const UserCard = React.memo(function UserCard({ user }: UserCardProps) {
    return <div>{user.name}</div>;
});

// ✅ 使用 useCallback 缓存回调函数
const handleClick = useCallback((id: string) => {
    // 处理点击
}, [/* 依赖项 */]);

// ✅ 使用 useMemo 缓存计算结果
const sortedItems = useMemo(() => {
    return [...items].sort((a, b) => a.name.localeCompare(b.name));
}, [items]);

// ✅ 列表渲染使用稳定的 key
{items.map((item) => (
    <ListItem key={item.id} item={item} />  // ✅ 使用唯一 ID
    // <ListItem key={index} item={item} />  // ❌ 避免使用索引
))}

// ✅ 懒加载组件
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));

function App() {
    return (
        <Suspense fallback={<Loading />}>
            <HeavyComponent />
        </Suspense>
    );
}

7. Vue 规范

7.1 组件设计Vue 3 Composition API

单文件组件结构

<script setup lang="ts">
/**
 * 用户卡片组件
 * 
 * @description 展示用户基本信息的卡片组件
 */
import { ref, computed, onMounted, watch } from 'vue';
import type { User } from '@/types';

// ============ Props 定义 ============
interface Props {
    /** 用户信息 */
    user: User;
    /** 是否显示详情 */
    showDetails?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
    showDetails: false
});

// ============ Emits 定义 ============
const emit = defineEmits<{
    /** 编辑事件 */
    (e: 'edit', user: User): void;
    /** 删除事件 */
    (e: 'delete', userId: string): void;
}>();

// ============ 响应式数据 ============
const isExpanded = ref(false);
const loading = ref(false);

// ============ 计算属性 ============
const displayName = computed(() => {
    return `${props.user.firstName} ${props.user.lastName}`;
});

const cardClasses = computed(() => ({
    'user-card': true,
    'user-card--expanded': isExpanded.value,
    'user-card--loading': loading.value
}));

// ============ 方法 ============
function handleEdit() {
    emit('edit', props.user);
}

function handleDelete() {
    emit('delete', props.user.id);
}

function toggleExpand() {
    isExpanded.value = !isExpanded.value;
}

// ============ 生命周期 ============
onMounted(() => {
    console.log('组件已挂载');
});

// ============ 侦听器 ============
watch(
    () => props.user.id,
    (newId, oldId) => {
        console.log(`用户ID变更${oldId} -> ${newId}`);
    }
);

// ============ 暴露给父组件的方法 ============
defineExpose({
    toggleExpand
});
</script>

<template>
    <div :class="cardClasses">
        <div class="user-card__header">
            <h3>{{ displayName }}</h3>
            <button @click="toggleExpand">
                {{ isExpanded ? '收起' : '展开' }}
            </button>
        </div>
        
        <div v-if="showDetails || isExpanded" class="user-card__details">
            <p>邮箱{{ user.email }}</p>
            <p>电话{{ user.phone }}</p>
        </div>
        
        <div class="user-card__actions">
            <button @click="handleEdit">编辑</button>
            <button @click="handleDelete">删除</button>
        </div>
        
        <!-- 插槽 -->
        <slot name="footer" />
    </div>
</template>

<style scoped>
.user-card {
    padding: 16px;
    border: 1px solid #e0e0e0;
    border-radius: 8px;
}

.user-card--expanded {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.user-card--loading {
    opacity: 0.6;
    pointer-events: none;
}
</style>

7.2 组合式函数Composables

// composables/useUser.ts
import { ref, computed, watch } from 'vue';
import type { Ref } from 'vue';
import type { User } from '@/types';
import { userApi } from '@/api';

/**
 * 用户数据组合式函数
 * 
 * @param userId 用户ID响应式引用
 * @returns 用户数据、加载状态、错误信息、刷新方法
 */
export function useUser(userId: Ref<string> | string) {
    const user = ref<User | null>(null);
    const loading = ref(false);
    const error = ref<Error | null>(null);
    
    // 获取用户数据
    async function fetchUser(id: string) {
        loading.value = true;
        error.value = null;
        
        try {
            user.value = await userApi.getUser(id);
        } catch (err) {
            error.value = err instanceof Error ? err : new Error('获取用户失败');
            user.value = null;
        } finally {
            loading.value = false;
        }
    }
    
    // 刷新数据
    function refresh() {
        const id = typeof userId === 'string' ? userId : userId.value;
        return fetchUser(id);
    }
    
    // 计算属性
    const displayName = computed(() => {
        if (!user.value) return '';
        return `${user.value.firstName} ${user.value.lastName}`;
    });
    
    // 侦听 userId 变化
    if (typeof userId !== 'string') {
        watch(userId, (newId) => {
            if (newId) {
                fetchUser(newId);
            }
        }, { immediate: true });
    } else {
        // 立即获取数据
        fetchUser(userId);
    }
    
    return {
        user,
        loading,
        error,
        displayName,
        refresh
    };
}

7.3 Pinia 状态管理

// stores/user.ts
import { defineStore } from 'pinia';
import type { User } from '@/types';
import { userApi } from '@/api';

/**
 * 用户状态 Store
 */
export const useUserStore = defineStore('user', {
    // 状态
    state: () => ({
        currentUser: null as User | null,
        isAuthenticated: false,
        loading: false
    }),
    
    // 计算属性
    getters: {
        /** 用户显示名称 */
        displayName(): string {
            if (!this.currentUser) return '游客';
            return `${this.currentUser.firstName} ${this.currentUser.lastName}`;
        },
        
        /** 是否是管理员 */
        isAdmin(): boolean {
            return this.currentUser?.role === 'admin';
        }
    },
    
    // 方法
    actions: {
        /**
         * 用户登录
         */
        async login(credentials: { username: string; password: string }) {
            this.loading = true;
            try {
                const user = await userApi.login(credentials);
                this.currentUser = user;
                this.isAuthenticated = true;
            } finally {
                this.loading = false;
            }
        },
        
        /**
         * 用户登出
         */
        logout() {
            this.currentUser = null;
            this.isAuthenticated = false;
        },
        
        /**
         * 更新用户信息
         */
        updateUser(updates: Partial<User>) {
            if (this.currentUser) {
                this.currentUser = { ...this.currentUser, ...updates };
            }
        }
    }
});

// 使用 Setup Store 语法(更灵活)
export const useUserStore2 = defineStore('user', () => {
    // 状态
    const currentUser = ref<User | null>(null);
    const isAuthenticated = ref(false);
    
    // 计算属性
    const displayName = computed(() => {
        return currentUser.value?.name ?? '游客';
    });
    
    // 方法
    async function login(credentials: LoginCredentials) {
        const user = await userApi.login(credentials);
        currentUser.value = user;
        isAuthenticated.value = true;
    }
    
    function logout() {
        currentUser.value = null;
        isAuthenticated.value = false;
    }
    
    return {
        currentUser,
        isAuthenticated,
        displayName,
        login,
        logout
    };
});

第四部分:工程化规范

8. Git 提交规范

8.1 提交信息格式

<type>(<scope>): <subject>

<body>

<footer>

8.2 Type 类型说明

类型 说明 示例
feat 新功能 feat(user): 添加用户登录功能
fix 修复 Bug fix(cart): 修复购物车数量计算错误
docs 文档更新 docs: 更新 README 安装说明
style 代码格式(不影响功能) style: 格式化代码
refactor 重构(不是新功能也不是修复) refactor(api): 重构请求封装
perf 性能优化 perf: 优化列表渲染性能
test 测试相关 test(user): 添加用户服务单元测试
chore 构建/工具/依赖更新 chore: 升级 webpack 到 5.x
revert 回滚提交 revert: 回滚 feat(user) 提交
ci CI/CD 配置 ci: 添加 GitHub Actions 配置
build 构建系统或外部依赖 build: 更新构建脚本

8.3 提交示例

# 简短提交
git commit -m "feat(user): 添加用户注册功能"

# 详细提交
git commit -m "feat(user): 添加用户注册功能

- 实现用户名密码注册
- 添加邮箱验证
- 添加表单校验

Closes #123"

# 修复 Bug
git commit -m "fix(order): 修复订单金额计算错误

订单金额在应用折扣后计算不正确,
原因是折扣百分比未正确转换。

Fixes #456"

# 破坏性变更
git commit -m "feat(api): 重构用户 API 接口

BREAKING CHANGE: 用户 API 响应格式已变更
- data 字段改为 result
- 添加 pagination 字段"

8.4 分支命名规范

分支类型 命名格式 示例
主分支 main / master main
开发分支 develop / dev develop
功能分支 feature/<name> feature/user-login
修复分支 fix/<name>bugfix/<name> fix/cart-calculation
发布分支 release/<version> release/1.2.0
热修复分支 hotfix/<name> hotfix/security-patch

9. API 设计规范

9.1 RESTful API 设计

URL 设计原则

# 资源命名使用复数名词
GET    /api/v1/users           # 获取用户列表
GET    /api/v1/users/:id       # 获取单个用户
POST   /api/v1/users           # 创建用户
PUT    /api/v1/users/:id       # 更新用户(全量)
PATCH  /api/v1/users/:id       # 更新用户(部分)
DELETE /api/v1/users/:id       # 删除用户

# 资源关联
GET    /api/v1/users/:id/orders        # 获取用户的订单
POST   /api/v1/users/:id/orders        # 为用户创建订单

# 查询参数
GET    /api/v1/users?page=1&size=10             # 分页
GET    /api/v1/users?sort=createdAt&order=desc  # 排序
GET    /api/v1/users?status=active&role=admin   # 筛选
GET    /api/v1/users?keyword=john               # 搜索

HTTP 状态码

状态码 说明 使用场景
200 OK 请求成功
201 Created 创建成功
204 No Content 删除成功
400 Bad Request 请求参数错误
401 Unauthorized 未认证
403 Forbidden 无权限
404 Not Found 资源不存在
409 Conflict 资源冲突
422 Unprocessable Entity 参数校验失败
500 Internal Server Error 服务器错误

9.2 请求/响应格式

统一响应格式

// 成功响应
{
    "code": "SUCCESS",
    "message": "操作成功",
    "data": {
        // 业务数据
    },
    "timestamp": 1642234567890
}

// 分页响应
{
    "code": "SUCCESS",
    "message": "操作成功",
    "data": {
        "list": [...],
        "pagination": {
            "page": 1,
            "size": 10,
            "total": 100,
            "totalPages": 10
        }
    },
    "timestamp": 1642234567890
}

// 错误响应
{
    "code": "VALIDATION_ERROR",
    "message": "参数校验失败",
    "errors": [
        { "field": "email", "message": "邮箱格式不正确" },
        { "field": "password", "message": "密码长度至少6位" }
    ],
    "timestamp": 1642234567890
}

9.3 错误码设计

// 错误码枚举
enum ErrorCode {
    // 成功
    SUCCESS = 'SUCCESS',
    
    // 客户端错误 (4xx)
    BAD_REQUEST = 'BAD_REQUEST',
    UNAUTHORIZED = 'UNAUTHORIZED',
    FORBIDDEN = 'FORBIDDEN',
    NOT_FOUND = 'NOT_FOUND',
    VALIDATION_ERROR = 'VALIDATION_ERROR',
    
    // 业务错误
    USER_NOT_FOUND = 'USER_NOT_FOUND',
    USER_ALREADY_EXISTS = 'USER_ALREADY_EXISTS',
    INVALID_PASSWORD = 'INVALID_PASSWORD',
    ORDER_NOT_FOUND = 'ORDER_NOT_FOUND',
    INSUFFICIENT_STOCK = 'INSUFFICIENT_STOCK',
    
    // 服务端错误 (5xx)
    INTERNAL_ERROR = 'INTERNAL_ERROR',
    SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE',
    DATABASE_ERROR = 'DATABASE_ERROR'
}

10. 测试规范

10.1 单元测试

测试文件命名

src/
├── utils/
│   ├── format.ts
│   └── format.test.ts      # 或 format.spec.ts
├── components/
│   └── UserCard/
│       ├── index.tsx
│       └── UserCard.test.tsx

测试用例命名

// 使用 describe + it 结构
describe('formatDate', () => {
    it('应该正确格式化日期', () => {
        // 测试代码
    });
    
    it('当输入为空时应该返回空字符串', () => {
        // 测试代码
    });
    
    it('当输入无效时应该抛出错误', () => {
        // 测试代码
    });
});

// 使用中文描述测试场景
describe('用户服务', () => {
    describe('创建用户', () => {
        it('应该成功创建用户并返回用户ID', async () => {
            // 测试代码
        });
        
        it('当用户名已存在时应该抛出错误', async () => {
            // 测试代码
        });
    });
});

测试结构AAA 模式)

it('应该正确计算订单总价', () => {
    // Arrange准备
    const items = [
        { name: '商品A', price: 100, quantity: 2 },
        { name: '商品B', price: 50, quantity: 3 }
    ];
    
    // Act执行
    const total = calculateTotal(items);
    
    // Assert断言
    expect(total).toBe(350);
});

10.2 React 组件测试

import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import UserCard from './UserCard';

describe('UserCard 组件', () => {
    const mockUser = {
        id: '1',
        name: '张三',
        email: 'zhangsan@example.com'
    };
    
    it('应该正确渲染用户信息', () => {
        render(<UserCard user={mockUser} />);
        
        expect(screen.getByText('张三')).toBeInTheDocument();
        expect(screen.getByText('zhangsan@example.com')).toBeInTheDocument();
    });
    
    it('点击编辑按钮应该触发 onEdit 回调', async () => {
        const handleEdit = jest.fn();
        render(<UserCard user={mockUser} onEdit={handleEdit} />);
        
        await userEvent.click(screen.getByRole('button', { name: '编辑' }));
        
        expect(handleEdit).toHaveBeenCalledWith(mockUser);
    });
    
    it('当 showDetails 为 false 时不应该显示详情', () => {
        render(<UserCard user={mockUser} showDetails={false} />);
        
        expect(screen.queryByText('详情')).not.toBeInTheDocument();
    });
});

10.3 Vue 组件测试

import { mount } from '@vue/test-utils';
import { describe, it, expect, vi } from 'vitest';
import UserCard from './UserCard.vue';

describe('UserCard 组件', () => {
    const mockUser = {
        id: '1',
        name: '张三',
        email: 'zhangsan@example.com'
    };
    
    it('应该正确渲染用户信息', () => {
        const wrapper = mount(UserCard, {
            props: { user: mockUser }
        });
        
        expect(wrapper.text()).toContain('张三');
        expect(wrapper.text()).toContain('zhangsan@example.com');
    });
    
    it('点击编辑按钮应该触发 edit 事件', async () => {
        const wrapper = mount(UserCard, {
            props: { user: mockUser }
        });
        
        await wrapper.find('[data-test="edit-btn"]').trigger('click');
        
        expect(wrapper.emitted('edit')).toBeTruthy();
        expect(wrapper.emitted('edit')![0]).toEqual([mockUser]);
    });
});

附录

附录 A代码审查清单

A.1 开发流程检查

  • 如果是询问"如何实现",是否先提供了详细的开发计划
  • 是否在用户同意后才修改代码
  • 删除的文件是否移动到 .recycle/ 文件夹而非直接删除

A.2 代码质量检查

  • 命名是否清晰、语义化
  • 注释是否完整且为中文
  • 错误处理是否完善
  • 类型定义是否完整TypeScript
  • 是否有重复代码可以抽取

A.3 TypeScript 检查

  • 是否避免使用 any
  • 接口和类型是否正确定义
  • 泛型使用是否恰当
  • 导入导出是否规范

A.4 React/Vue 检查

  • 组件职责是否单一
  • Props 和事件是否正确定义
  • Hooks 使用是否规范
  • 是否有性能问题(不必要的重渲染)

A.5 Java 检查

  • 包结构是否规范
  • 类命名是否符合约定
  • 是否正确使用注解
  • 异常处理是否完善

A.6 安全检查

  • 是否验证了所有外部输入
  • 是否避免了 XSS 风险
  • 敏感数据是否正确处理
  • 错误信息是否避免泄露敏感信息

A.7 文档检查

  • 是否更新了相关文档
  • API 文档是否同步更新
  • README 是否需要更新

附录 B常见任务快速参考

B.1 添加新文件

  1. 创建文件,添加必要的类型定义
  2. 添加中文注释
  3. 在相关入口文件中导出(如需要)
  4. 更新文档

B.2 删除文件

  1. 确认文件不再使用
  2. 创建回收目录:.recycle/YYYY-MM-DD/
  3. 移动文件到回收目录(保持目录结构)
  4. 更新相关导入和引用
  5. 更新文档

B.3 重构代码

  1. 先与用户确认重构范围
  2. 制定详细的重构计划
  3. 分步骤执行,每步验证
  4. 确保测试通过
  5. 更新文档

B.4 添加新 API

  1. 设计 API 接口URL、参数、响应
  2. 定义 TypeScript 类型
  3. 实现后端接口
  4. 实现前端调用
  5. 添加错误处理
  6. 编写测试
  7. 更新 API 文档

附录 C模板使用说明

本模板可直接复制到新项目中使用。使用时请注意:

  1. 根据项目调整

    • 删除不适用的语言/框架章节
    • 根据团队习惯调整具体规范
  2. 补充项目特定内容

    • 项目特定的架构规范
    • 项目特定的命名规范
    • 项目特定的目录结构
  3. 定期更新

    • 随着项目发展,及时更新规范内容
    • 根据团队反馈优化规范
  4. 配合其他文档使用

    • 项目 README
    • API 文档
    • 架构设计文档
    • 部署文档

文档版本v2.0 最后更新2026-01-21