---
alwaysApply: true
---
# 编码规范
## 1. 命名
- 类名:大驼峰,见名知意
- 方法名:小驼峰,动词开头
- 常量:全大写下划线分隔
- 抽象类以 Abstract 或 Base 开头
- 测试类以被测类名开头,Test 结尾
- 禁止拼音、中英混拼命名
## 2. 异常处理
- 业务异常使用自定义 BusinessException,携带错误码
- 系统异常向上抛出,由统一异常处理器兜底
- 禁止吞掉异常(空 catch)
- catch 中必须记录日志
## 3. 日志
- Controller 入口打 INFO,含请求关键参数
- 异常打 ERROR,含完整堆栈
- 禁止在日志中打印用户敏感信息
## 4. 其他
- 写接口必须考虑幂等
- 涉及并发场景必须说明同步策略
- 魔法值必须定义为常量
## 5. git提交规范
- 禁止 master 分支变更:编码前检查当前分支,master 上立即停止
- 自动 Commit:每个 task/fix 完成后自动 commit,保持一个 task 一个 commit
- Commit 必须可编译:commit 前执行编译检查
- 禁止自动 Push:push 由用户主动触发,保留审查机会
- Message 格式:[<变更名>] <中文简述>
## 6. 数据库 SQL 规范
### 6.1 租户 ID 规则(重要)
- **业务数据**(字典 `sys_dict_type`/`sys_dict_data`、配置等需被租户查询到的数据)的 `tenant_id` **必须设为 `1`**(默认租户),**禁止设为 `0`**
- **原因**:项目的 `TenantLineInnerInterceptor` 会自动在所有 SELECT 查询中追加 `WHERE tenant_id = <当前登录用户租户ID>`,`tenant_id=0` 的数据对非零租户用户不可见,导致前端字典加载为空
- **例外**:`sys_resource`(菜单/权限)表不在租户拦截范围内,其 `tenant_id` 保持 `1` 即可
- **排查**:如果前端字典组件(DictSelect、DictTag、useDict)加载为空,首先检查数据库中对应字典数据的 tenant_id 是否为 1
### 6.2 其他 SQL 规范
- 所有业务表必须包含基础字段:`id`, `tenant_id`, `create_by`, `create_time`, `create_dept`, `update_by`, `update_time`
- 使用 `utf8mb4` 字符集,`InnoDB` 引擎
- 为高频查询字段创建索引,组合索引遵循最左前缀原则
- 禁止将数据库凭据提交到仓库
- Flyway 迁移脚本中禁止直接写业务 `${...}` 模板;确需入库时使用 `CONCAT('$', '{token}')` 拼接,并用 `rg -n '\$\{[^}]+\}' forge-server/db/migration` 确认无残留
## 7. 前端规范
### 7.1 字典使用
- 下拉选项、状态标签等**禁止硬编码**,必须使用字典组件
- 加载字典:`const { dict } = useDict('dict_type_1', 'dict_type_2')`
- 表单下拉:使用 `DictSelect` 组件,或在 editSchema 中通过 `computed` 引用 `dict.value['xxx']` 作为 `props.options`
- 表格标签渲染:使用 `DictTag` 组件,配合字典的 `listClass` 字段自动映射颜色
- Schema 必须定义为 `computed`,确保字典数据异步加载后选项能响应式更新
### 7.2 图片/文件字段渲染
- `imageUpload` 组件存储的值是 **fileId**,不是完整 URL
- 表格列渲染图片时,**必须使用 `getFileUrl()` 将 fileId 转换为下载链接**:
```js
import { getFileUrl } from '@/utils/file'
// 正确
h(NAvatar, { src: getFileUrl(row.logo), size: 32, round: true })
// 错误 - fileId 无法直接作为图片 src
h(NAvatar, { src: row.logo, size: 32, round: true })
```
- **鉴权图片必须使用 `AuthImage` 组件**:
- 文件下载接口 `/api/file/download/{fileId}` 需要鉴权(Bearer Token)
- 直接用 URL 作为 `
` 或 `` 的 `src` 属性**不会携带 Authorization header**,导致 token 无效错误
- **解决方案**:使用 `AuthImage` 组件,它会通过 fetch 带 token 获取图片并转为 blob URL:
```js
import AuthImage from '@/components/common/AuthImage.vue'
// 正确 - AuthImage 自动处理鉴权
h(AuthImage, {
src: row.logo,
imgStyle: { width: '32px', height: '32px', borderRadius: '50%', objectFit: 'cover' }
})
// 错误 - NAvatar src 不会带 token,接口返回"未能读取到有效 token"
h(NAvatar, { src: getFileUrl(row.logo), size: 32, round: true })
```
### 7.3 操作列按钮
- 操作列按钮超过 2 个时,`AiCrudPage` 会自动将多余的折叠到"更多"下拉菜单
- 按钮顺序安排:最常用的操作放前面(会被内联显示),低频操作放后面(收入"更多")
- 操作列宽度需根据按钮数量合理设置:2个内联按钮约 150-180px
## 8. 后端架构规范
### 8.1 循环依赖
- Service 之间**禁止相互注入**导致循环依赖
- 如需跨 Service 协调,将协调逻辑上提到 Controller 层
### 8.2 API Key 等敏感字段
- 接口返回中包含 API Key、Secret 等敏感字段时,**必须脱敏处理**
- 脱敏方式:保留前4后4位,中间用 `****` 替代