签入版本
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# 12.1 API 响应规范
|
||||
|
||||
:::tip 概述
|
||||
必须遵守的响应契约:统一信封四字段、code 语义、data 形态、命名驼峰(含下划线例外)。机制详解见 [8.1 统一响应格式](../api-spec/response),本节为强制规范条目。
|
||||
:::
|
||||
|
||||
## 强制规范
|
||||
|
||||
```text
|
||||
1. 全部接口返回 {code, ok, msg, data} 四字段信封——禁止裸数组/裸对象
|
||||
2. 成功 code=0;失败 code=1(细分码在服务端语义,401 原样返回)
|
||||
3. data 失败时为 {}(非 null);records 为空时为 [](非 null)
|
||||
4. 分页统一 PageData[T]:{records, total, size, current, pages}
|
||||
5. 新增返回 {id};修改/删除返回 {}
|
||||
6. 出入参 json 一律驼峰
|
||||
唯一例外:登录/令牌接口返回 access_token/refresh_token/expires_in/token_type
|
||||
(OAuth2 惯例,前端按此读取,禁止"修正"为驼峰)
|
||||
7. 业务错误经 gerror 上抛由包装层统一 Fail——禁止业务代码手写 JSON 响应
|
||||
8. 未认证必须 code=401 且 HTTP 401(前端跳登录依赖此约定)
|
||||
```
|
||||
|
||||
## 代码层对应(防呆)
|
||||
|
||||
```go
|
||||
// 响应由 Bind 包装层统一写出——业务只管返回出参与 error
|
||||
func (s *sExample) Add(ctx context.Context, req *v1.ExampleAddReq) (*v1.ExampleIdRes, error) {
|
||||
id, err := exampleSpec.Add(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err // 包装层 → response.Fail
|
||||
}
|
||||
return &v1.ExampleIdRes{Id: id}, nil // 包装层 → response.Ok
|
||||
}
|
||||
```
|
||||
|
||||
## Review 检查项
|
||||
|
||||
```text
|
||||
□ 新接口返回类型是否用 PageData/IdRes/空结构体(而非自造形态)
|
||||
□ 错误是否 gerror 上抛(而非手写 {code:1})
|
||||
□ 字段 json 标签是否驼峰
|
||||
□ 是否误改了登录接口的下划线字段
|
||||
□ msg 是否用户可读(前端会弹出)
|
||||
□ data 为 nil 的路径是否验证过(框架兜底 {} / [])
|
||||
```
|
||||
|
||||
## 反例(禁止)
|
||||
|
||||
```text
|
||||
❌ {"status":200, "result": {...}} 自造信封
|
||||
❌ {"code":0, "data":null} data null(应 {} / [])
|
||||
❌ {"code":1003,"msg":"密码错误"} 直接返回细分码 (除 401 外应降级 1,细分在 msg/日志)
|
||||
❌ 裸数组 [ {...} ] 作为响应体 (应包信封)
|
||||
❌ {"access_token":...} 改为 accessToken (破坏 OAuth2 惯例)
|
||||
```
|
||||
@@ -0,0 +1,86 @@
|
||||
# 12.6 后端编码规范
|
||||
|
||||
:::tip 概述
|
||||
后端规范汇总:分层职责、命名、错误处理、事务纪律、注释风格。多数条目在前文有机制详解,本节为速查总表。
|
||||
:::
|
||||
|
||||
## 分层与依赖
|
||||
|
||||
```text
|
||||
□ controller 薄层:只透传,无业务/无 dao/无手写响应
|
||||
□ service 接口手维护:方法签名变更同步接口文件;禁 gf gen service 整体运行
|
||||
□ logic 差异进 spec 声明与钩子;装不下就手写(逃生舱)
|
||||
□ dao.Ctx 唯一查询入口;自定义 dao 方法也必须 Ctx 起手
|
||||
□ 依赖红线:task→logic 单向;middleware 经 wire 接线;migrate 不走 dao
|
||||
□ base.go 只依赖 dao/utility/consts;导出 ≤15
|
||||
```
|
||||
|
||||
## 命名
|
||||
|
||||
```text
|
||||
□ 文件:表名去 goframe_ 前缀 snake_case(config_item.go)
|
||||
□ 控制器:CXxx(CConfigItem);logic 实现:sXxx
|
||||
□ spec 变量:xxxSpec;字典映射:xxxSerializeMaps
|
||||
□ service:IXxx 接口 / Xxx() 取用 / RegisterXxx() 注册
|
||||
□ 权限码:sys:{module小驼峰}:{action}
|
||||
□ 缓存键:easygoadmin: 前缀(consts/cache_key.go 统一)
|
||||
□ json:驼峰(登录/令牌四字段下划线例外)
|
||||
```
|
||||
|
||||
## 请求与响应
|
||||
|
||||
```text
|
||||
□ 每接口一 Req/Res 结构体;内嵌 gmeta.Meta 全标签
|
||||
□ 校验用 v 标签(required#文案);复杂校验在钩子
|
||||
□ 分页 PageData;新增 {id};空结果 struct{}
|
||||
□ 出参字段 dc 注释 + 行注释(OpenAPI 文档质量)
|
||||
```
|
||||
|
||||
## 错误与日志
|
||||
|
||||
```text
|
||||
□ gerror 上抛(NewCodef 语义码+消息);不吞 err
|
||||
□ 钩子错误记 stage 日志后原样上抛
|
||||
□ fmt.Println 禁用——用 glog(带上下文)
|
||||
□ 敏感字段(password/salt/token)不进日志
|
||||
□ panic 只在编程错误(mustAs 失败等);运行期错误返回 error
|
||||
```
|
||||
|
||||
## 事务与并发
|
||||
|
||||
```text
|
||||
□ WithTrans 包裹多表写;错误自动回滚
|
||||
□ 事务内禁 HTTP/文件 IO;bcrypt 事务外预计算
|
||||
□ 共享 map 加锁;goroutine 有生命周期管理
|
||||
□ 大数据量用 ChunkQuery 分批;循环内禁止查库(批查)
|
||||
```
|
||||
|
||||
## 注释风格
|
||||
|
||||
```text
|
||||
□ 按当前功能直述(禁比较/来源痕迹/历史考古)
|
||||
□ 导出函数/类型有注释(godoc 风格,首句概括)
|
||||
□ 关键设计决策注释"为什么"(而非复述代码)
|
||||
□ 生成物注释保留工具标记(勿删头注释)
|
||||
```
|
||||
|
||||
## 静态门禁
|
||||
|
||||
```sh
|
||||
go build ./... # 编译
|
||||
go vet ./... # vet
|
||||
test -z "$(gofmt -l .)" # 格式(CI 同款)
|
||||
go test ./... # sqlite + hooks MySQL 集成测试
|
||||
```
|
||||
|
||||
## 反例速查
|
||||
|
||||
```text
|
||||
❌ g.DB().Table("goframe_user").Where(...) 绕过 dao
|
||||
❌ .Where("del_flag", 0) 手写 应由 Ctx 注入
|
||||
❌ WithTrans 内 bcrypt 拉长锁
|
||||
❌ for range ids { dao.Xxx.One } N+1
|
||||
❌ err 被 _ 丢弃 吞错误
|
||||
❌ 接口返回 map[string]any 拼装 应有结构体契约
|
||||
❌ 在钩子里 if module == "user" 基座禁止按模块分支
|
||||
```
|
||||
@@ -0,0 +1,72 @@
|
||||
# 12.5 代码审查清单
|
||||
|
||||
:::tip 概述
|
||||
Review 按"架构红线 → 安全 → 正确性 → 规范"四层组织。红线项(绕过 dao/反向依赖等)任何一项都应直接打回。
|
||||
:::
|
||||
|
||||
## 架构红线(一票否决)
|
||||
|
||||
```text
|
||||
□ 绕过 dao.Ctx 直连 g.DB() 查业务表
|
||||
□ 手写 del_flag / tenant_id 条件
|
||||
□ 租户级新表未登记 hooks.tenantTables
|
||||
□ logic 反向 import internal/task
|
||||
□ middleware 直接 import 业务包(应走 wire.go 函数变量)
|
||||
□ internal/migrate 走 dao/logic(应 gdb 裸连)
|
||||
□ base.go 导出函数超 15 个(应拆子包)
|
||||
□ 整体运行 gf gen service 覆盖手工接口文件
|
||||
□ 唯一预检范围 ≠ 唯一索引范围(Group 缺失)
|
||||
□ gmeta path 带 /v1 版本段 / public 白名单三处不一致
|
||||
```
|
||||
|
||||
## 安全 Review
|
||||
|
||||
```text
|
||||
□ 新接口声明了 permission(或评审确认留空=登录即可)
|
||||
□ 权限码符合 sys:{module小驼峰}:{action}
|
||||
□ 入参有 gvalid 校验(required/范围/格式)
|
||||
□ 敏感字段不出接口(password/salt)
|
||||
□ 日志不打印密码/令牌(maskSecret 覆盖)
|
||||
□ SQL 无字符串拼接(全参数化)
|
||||
□ 文件上传走白名单+嗅探链(未自造上传口)
|
||||
□ 富文本处理未破坏 [IMG_URL] 契约 / 未引入外站抓取(SSRF)
|
||||
□ 新缓存键有失效点或短 TTL(对照 4.8 原则)
|
||||
```
|
||||
|
||||
## 正确性 Review
|
||||
|
||||
```text
|
||||
□ 事务边界正确(bcrypt/HTTP/文件 IO 不在事务内)
|
||||
□ 钩子内无 append / 无 IO / 错误上抛
|
||||
□ 错误处理不吞 err(不 _ = 忽略关键错误)
|
||||
□ 分页走 PageData;空集 []
|
||||
□ 导出走 applyFilters(导出=所见)
|
||||
□ N+1 查询(循环内查库)→ 批查改造(userExpandNames 模式)
|
||||
□ 并发安全(共享 map 加锁;goroutine 泄漏)
|
||||
□ LastInsertId 回主键(禁雪花)
|
||||
□ 前端三件套对齐(querySchemas/Req/spec)
|
||||
□ 前端按钮 v-permission 对齐 gmeta
|
||||
```
|
||||
|
||||
## 规范 Review
|
||||
|
||||
```text
|
||||
□ 文件命名 snake_case(后端)/ 驼峰(前端)
|
||||
□ 注释按当前功能直述(无比较/来源痕迹)
|
||||
□ json 驼峰(下划线仅登录/令牌例外)
|
||||
□ service 接口同步更新(手维护)
|
||||
□ 日志标题 "{模块中文名}-{动作}"、logType 正确
|
||||
□ gofmt / go vet / vue-tsc / eslint 通过
|
||||
□ 文档同步(接口清单/表清单/配置项有变更时)
|
||||
□ 破坏性变更走版本化说明 + 黄金样本更新
|
||||
```
|
||||
|
||||
## Review 实践建议
|
||||
|
||||
```text
|
||||
小 PR(<400 行)优先;大重构拆分提交
|
||||
先看设计(spec 声明/钩子划分)再看细节
|
||||
生成器产物看增量 diff(不逐行 review 模板产物)
|
||||
测试:修复类看是否有回归测试;新功能看冒烟路径
|
||||
评论给"为什么+建议",不只给"改成什么"
|
||||
```
|
||||
@@ -0,0 +1,80 @@
|
||||
# 12.4 数据删除规范
|
||||
|
||||
:::tip 概述
|
||||
删除一律软删(del_flag=1,由全局钩子强制改写);物理删除只在定时清理任务中出现。删除守卫保护引用完整性。本节为强制规范与操作红线。
|
||||
:::
|
||||
|
||||
## 强制规范
|
||||
|
||||
```text
|
||||
1. 删除接口全部软删:deleteHook 把物理 DELETE 改写为 UPDATE del_flag=1
|
||||
——业务代码无需(也不允许)自己写 del_flag 更新
|
||||
|
||||
2. 查询一律经 dao.Ctx(自动过滤 del_flag=0)
|
||||
——禁止绕过 dao 直连 g.DB()(已删数据会"复活"可见)
|
||||
|
||||
3. 禁止手写 del_flag 条件(手写易漏:忘 filter 或写错值)
|
||||
|
||||
4. 物理删除仅允许出现在清理类定时任务(LogClean/CleanTemp)
|
||||
——业务代码禁止 Data/Delete 真实物理删除
|
||||
|
||||
5. 删除前守卫:存在子级/引用时拒绝(1011/1014),先处理关联
|
||||
|
||||
6. 唯一索引含 del_flag(软删行不占唯一坑位——uk 设计规范)
|
||||
```
|
||||
|
||||
## 守卫模式(真实模块)
|
||||
|
||||
```text
|
||||
dept:存在子部门拒绝(1011);存在用户引用拒绝
|
||||
menu:存在子菜单拒绝(1011)+ 同步清理 role_menu(防悬挂授权)
|
||||
role:存在用户引用拒绝(1014/1011 语义)
|
||||
user:删除守卫 + 清理 user_role 关联
|
||||
category:存在子分类/文章引用检查
|
||||
```
|
||||
|
||||
spec 钩子:`BeforeDelete`(守卫)→ 基座软删 → `AfterDelete`(关联清理/缓存清理)。
|
||||
|
||||
## 软删的工程含义
|
||||
|
||||
```text
|
||||
可恢复:del_flag 改回 0 即恢复(无官方恢复接口时可 DB 操作/数据修复)
|
||||
存储增长:软删行永久占用——靠唯一索引含 del_flag 设计兼容
|
||||
唯一性:uk 含 del_flag → 同名删除后可再建(软删行不占坑)
|
||||
审计:create_user/update_user 保留最后操作人;恢复时注意盖章语义
|
||||
```
|
||||
|
||||
## 数据清理策略
|
||||
|
||||
```text
|
||||
日志三表(operation_log/login_log/job_log):
|
||||
LogClean 任务每日 02:30 物理删除超保留期记录
|
||||
保留天数 job.logRetentionDays(默认 90),任务参数 retentionDays 可覆盖
|
||||
单批 5000 行循环;单表单次上限 20 万行(防长事务)
|
||||
|
||||
业务表软删数据:
|
||||
默认不清理(可恢复性优先)
|
||||
如需归档清理:新建归档任务(参考 LogClean 模式),先归档再物理删
|
||||
清理前备份
|
||||
```
|
||||
|
||||
## Review 检查项
|
||||
|
||||
```text
|
||||
□ 删除走 spec.Delete/手写 dao.Ctx 软删(无物理 DELETE)
|
||||
□ BeforeDelete 守卫齐全(子级/引用)
|
||||
□ AfterDelete 关联清理(user_role/role_menu 等)
|
||||
□ 唯一索引含 del_flag(新建表时)
|
||||
□ 无绕过 dao 的删除路径
|
||||
□ 批量删除逐条守卫(非绕过逐条检查的批量 SQL)
|
||||
```
|
||||
|
||||
## 反例(禁止)
|
||||
|
||||
```text
|
||||
❌ dao.Xxx.Ctx(ctx).Where(...).Delete() 未确认 deleteHook 生效(绕过 dao 时物理删除!)
|
||||
❌ UPDATE goframe_xxx SET del_flag=1 手写(应交给钩子)
|
||||
❌ 清理任务直接 DELETE 大表无分批(长事务锁表)
|
||||
❌ 唯一索引不含 del_flag(软删后无法再建同名)
|
||||
❌ 删除后不清理关联(悬挂 role_menu/user_role)
|
||||
```
|
||||
@@ -0,0 +1,83 @@
|
||||
# 12.7 前端编码规范
|
||||
|
||||
:::tip 概述
|
||||
前端规范汇总:三件套对齐、组件使用、权限、状态管理、类型与样式。配套工具链:ESLint + Prettier + Stylelint + vue-tsc + commitlint。
|
||||
:::
|
||||
|
||||
## 三件套与契约(最高优先级)
|
||||
|
||||
```text
|
||||
□ api url 对齐 gmeta path(无 /api 前缀重复、无 /v1)
|
||||
□ querySchemas field ↔ PageReq json ↔ LikeFields/EqFields(三件同步)
|
||||
□ columns prop ↔ Item/DetailRes json
|
||||
□ edit 表单 ↔ AddReq/UpdateReq(全量提交语义)
|
||||
□ 按钮 v-permission ↔ gmeta permission(复制粘贴防拼错)
|
||||
□ 枚举列展示 {field}Text(不硬编码文案)
|
||||
□ 登录读 data.access_token(下划线)
|
||||
```
|
||||
|
||||
## 组件使用
|
||||
|
||||
```text
|
||||
□ 列表用 Page 容器 + Table(columns 配置) + pagination
|
||||
□ 复杂列用 render 函数(h + Element Plus 组件)
|
||||
□ 筛选用 querySchemas 配置(勿手写搜索区)
|
||||
□ 下拉选项优先字典驱动(getDictItemList)
|
||||
□ 上传用 Upload 组件(持 URL,后端转正)
|
||||
□ 图片展示用后端已补域名字段(GetFileUrl)
|
||||
□ 弹窗用 Modal 封装;确认删除用 ElMessageBox
|
||||
```
|
||||
|
||||
## 状态与逻辑
|
||||
|
||||
```text
|
||||
□ 状态走 Pinia store(token/用户/路由/标签页);勿全局变量
|
||||
□ 本地存储统一 storage 封装 + mutation-types 常量
|
||||
□ HTTP 统一 http.request(勿绕过封装裸 axios)
|
||||
□ 公共逻辑抽 hooks/;工具函数进 utils/
|
||||
□ 类型:接口出入参定义类型;跑通 pnpm type:check
|
||||
```
|
||||
|
||||
## 样式
|
||||
|
||||
```text
|
||||
□ scoped 样式;颜色用 Element CSS 变量(随主题)
|
||||
□ 布局用栅格组件;少 deep 覆盖
|
||||
□ 样式改动过 stylelint
|
||||
```
|
||||
|
||||
## 质量门禁
|
||||
|
||||
```sh
|
||||
pnpm type:check # vue-tsc
|
||||
pnpm lint:eslint # ESLint
|
||||
pnpm lint:prettier # 格式化
|
||||
pnpm lint:stylelint # 样式
|
||||
pnpm build # 构建验证
|
||||
```
|
||||
|
||||
## 反例速查
|
||||
|
||||
```text
|
||||
❌ 直接 axios.get('/api/user/page') 绕封装 + url 重复 /api
|
||||
❌ options: [{label:'正常',value:1}] 硬编码 应字典驱动
|
||||
❌ status 直接展示(显示 1/2) 应展示 statusText
|
||||
❌ 按钮无 v-permission 权限裸奔(UX 层缺失)
|
||||
❌ 每次请求重新登录拿 token 用 refresh 轮换
|
||||
❌ 组件内大量业务逻辑 抽 hooks/store
|
||||
❌ 直接 localStorage.setItem('token') 统一 storage + 常量
|
||||
❌ 页面硬编码颜色 #1890ff 用 var(--el-color-primary)
|
||||
❌ 布尔/枚举用魔法数字散落 用 enums 常量
|
||||
```
|
||||
|
||||
## Review 检查项
|
||||
|
||||
```text
|
||||
□ 新页面走三件套结构(index/edit/detail/columns/querySchemas)
|
||||
□ 接口函数 JSDoc 注释(生成器同款风格)
|
||||
□ 列表空态/加载态/错误态处理
|
||||
□ 表单校验(前端提示 + 对齐后端 v 标签)
|
||||
□ 删除/危险操作二次确认
|
||||
□ 权限变更后按钮正确显隐(超管/普通角色双测)
|
||||
□ type:check 与 build 通过
|
||||
```
|
||||
@@ -0,0 +1,92 @@
|
||||
# 12.3 Git 提交规范
|
||||
|
||||
:::tip 概述
|
||||
提交遵循 Conventional Commits(前端工程内置 commitlint + husky 校验)。规范的提交信息支撑自动生成变更日志与可追溯的历史。
|
||||
:::
|
||||
|
||||
## 提交格式(Conventional Commits)
|
||||
|
||||
```text
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
<body>
|
||||
<footer>
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
feat(user): 用户列表支持职级筛选
|
||||
|
||||
- querySchemas 新增 levelId 选择器
|
||||
- UserPageReq 增加 levelId 字段并接入 EqFields
|
||||
|
||||
Closes #123
|
||||
```
|
||||
|
||||
## type 类型
|
||||
|
||||
| type | 含义 |
|
||||
|------|------|
|
||||
| feat | 新功能 |
|
||||
| fix | 缺陷修复 |
|
||||
| docs | 文档 |
|
||||
| style | 格式(不影响逻辑) |
|
||||
| refactor | 重构(非新功能非修复) |
|
||||
| perf | 性能优化 |
|
||||
| test | 测试 |
|
||||
| build | 构建/依赖 |
|
||||
| ci | CI 配置 |
|
||||
| chore | 杂项 |
|
||||
| revert | 回滚 |
|
||||
|
||||
## scope 建议(对齐模块)
|
||||
|
||||
```text
|
||||
后端:user/role/menu/dept/…(模块名)/ middleware/hooks/generator/migrator/base
|
||||
前端:api/views/store/router/components…
|
||||
其他:config/docs/ui…
|
||||
```
|
||||
|
||||
## 提交纪律
|
||||
|
||||
```text
|
||||
1. 一个提交一件事(功能/修复不混杂重构)
|
||||
2. 提交前本地过门禁:go build/vet/gofmt + go test;pnpm type:check/eslint
|
||||
3. 生成器产物与手工修改分开提交(或提交信息注明)
|
||||
4. 破坏性变更(改名/删字段/改枚举值)提交信息标注 BREAKING CHANGE:
|
||||
5. 敏感信息(密钥/密码/个人数据)严禁入仓
|
||||
6. 中文提交信息(团队约定)subject 不超 50 字
|
||||
```
|
||||
|
||||
## 分支与合并
|
||||
|
||||
```text
|
||||
main 可发布主干(保护分支,PR + CI 必过 + review)
|
||||
feature/* 功能(从 main 切)
|
||||
fix/* 修复
|
||||
hotfix/* 紧急修复(快速通道,双人确认)
|
||||
release/* 发布分支(打 tag)
|
||||
|
||||
合并策略:PR 合并(禁止直接 push main);冲突在 feature 分支 rebase 解决
|
||||
```
|
||||
|
||||
## hook 保障
|
||||
|
||||
```text
|
||||
前端:husky + lint-staged(提交时 lint/格式化)+ commitlint(信息格式校验)
|
||||
后端:gofmt/vet 经 CI 门禁(可加 pre-commit hook)
|
||||
```
|
||||
|
||||
## 好的提交 vs 差的提交
|
||||
|
||||
```text
|
||||
✅ feat(job): 任务模块支持暂停恢复接口
|
||||
✅ fix(auth): 修复 refresh 轮换旧令牌未拉黑的重放风险
|
||||
✅ chore(generator): overwrite 开关默认 false
|
||||
|
||||
❌ update (无类型无内容)
|
||||
❌ 修改了一些东西 (不可追溯)
|
||||
❌ fix: fix fix fix (无信息量)
|
||||
❌ 一次提交跨 30 个文件混杂多主题 (无法回滚单个变更)
|
||||
```
|
||||
@@ -0,0 +1,68 @@
|
||||
# 12.2 分页查询规范
|
||||
|
||||
:::tip 概述
|
||||
必须遵守的查询契约:筛选对齐三件套、分页默认值与上限、导出=所见、排序白名单。机制详解见 [8.3 分页查询规范](../api-spec/pagination)。
|
||||
:::
|
||||
|
||||
## 强制规范(三件套对齐)
|
||||
|
||||
```text
|
||||
1. 前端 querySchemas.ts 每个筛选输入 ↔ XxxPageReq 同名驼峰字段 ↔ spec 声明
|
||||
——三处任一缺失即视为筛选缺陷
|
||||
|
||||
2. 组件类型与后端声明对应:
|
||||
字符串 Input → LikeFields(逐列模糊,列名显式声明)
|
||||
Select/InputNumber → EqFields(零值跳过)
|
||||
KeywordFields(req.keyword 多列 OR)能力保留在基座,模块不声明,需要时再用
|
||||
|
||||
3. 分页:PageReq 内嵌 common.PageReq(pageNo 默认 1;pageSize 默认 10 上限 500)
|
||||
|
||||
4. 导出统一走 xxxSpec.applyFilters 与列表同套筛选(导出=所见,含数据权限)
|
||||
|
||||
5. 排序:前端排序字段仅 OrderableFields 白名单内生效(防注入)
|
||||
|
||||
6. 复杂条件写 Filter 钩子——不重复声明 Like/Eq 已覆盖条件
|
||||
```
|
||||
|
||||
## spec 声明模板(标准形态)
|
||||
|
||||
```go
|
||||
var xxxSpec = ModuleSpec[...]{
|
||||
Model: dao.Xxx.Ctx,
|
||||
LikeFields: []string{"name"}, // 对应 querySchemas 的 Input
|
||||
EqFields: []string{"status", "type"}, // 对应 Select/InputNumber
|
||||
OrderBy: "id DESC",
|
||||
// DataScope: ApplyDataScope("dept_id"), // 有部门列且需行级权限时
|
||||
}
|
||||
```
|
||||
|
||||
## Review 检查项
|
||||
|
||||
```text
|
||||
□ querySchemas 新增输入 → Req 加字段 + spec 加 Like/Eq 声明(三件同步)
|
||||
□ Req 筛选字段命名与表单 field 完全一致(驼峰)
|
||||
□ 导出接口 ExportReq 携带同套筛选字段且走 applyFilters
|
||||
□ 排序字段在白名单内
|
||||
□ 零值语义确认(status=0 为有效筛选时的处理)
|
||||
□ 分页上限未绕过(未自定义 pageSize 无上限)
|
||||
```
|
||||
|
||||
## 反例(禁止)
|
||||
|
||||
```text
|
||||
❌ querySchemas 有输入但 Req 无字段(提交了后端不读)
|
||||
❌ Req 有字段但 spec 未声明(读了不过滤——筛选假生效)
|
||||
❌ 导出另写查询条件(导出 ≠ 所见)
|
||||
❌ Filter 里重复写 LikeFields 已覆盖的条件
|
||||
❌ 前端传 orderField 直通 SQL(必须白名单)
|
||||
❌ 手写 del_flag/tenant_id 条件混入筛选(dao.Ctx 已注入)
|
||||
```
|
||||
|
||||
## 一致性验证方法
|
||||
|
||||
```text
|
||||
1. 页面输入筛选值 → Network 看请求参数
|
||||
2. 对照 Req 字段名(驼峰)是否接收
|
||||
3. 对照 spec 声明过滤是否生效(结果集变化)
|
||||
4. 导出同一筛选 → Excel 行数 = 列表 total
|
||||
```
|
||||
Reference in New Issue
Block a user