Files
junhong_cmp_fiber/openspec/changes/archive/2026-01-30-login-response-menus-buttons/tasks.md
2026-01-30 17:22:38 +08:00

8.7 KiB
Raw Blame History

1. DTO 结构定义

  • 1.1 在 internal/model/dto/auth_dto.go 中新增 MenuNode 结构体,包含 ID, PermCode, Name, URL, Sort, Children 字段,所有字段添加 JSON 标签
  • 1.2 修改 LoginResponse 结构体,新增 Menus []MenuNodeButtons []string 字段,添加 JSON 标签和 description 注释
  • 1.3 运行 lsp_diagnostics 验证 DTO 文件无错误

2. Service 层核心方法实现

  • 2.1 在 internal/service/auth/service.go 中新增 getUserPermissionsAndMenus() 方法,接收参数 ctx, userID, userType, device,返回 ([]string, []MenuNode, []string, error)
  • 2.2 在 getUserPermissionsAndMenus() 中实现超级管理员逻辑:调用 permissionStore.GetAll(ctx, nil) 查询所有启用的权限
  • 2.3 在 getUserPermissionsAndMenus() 中实现普通用户逻辑:复用现有的角色权限查询(accountRoleStore.GetByAccountID()rolePermStore.GetPermIDsByRoleIDs()permissionStore.GetByIDs()
  • 2.4 新增 classifyPermissions() 方法,接收参数 permissions []*model.Permission, device string,实现权限分类和平台过滤逻辑
  • 2.5 在 classifyPermissions() 中实现平台过滤:platform == "all"platform == device 时保留,否则跳过
  • 2.6 在 classifyPermissions() 中实现权限分类:perm_type == 1 的收集到 menuPermsperm_type == 2 的提取 perm_codebuttonCodes
  • 2.7 在 classifyPermissions() 中收集所有权限码到 allCodes 数组(用于 permissions 字段)

3. 菜单树构建逻辑

  • 3.1 新增 buildMenuTree() 方法,接收参数 permissions []*model.Permission,返回 []MenuNode
  • 3.2 在 buildMenuTree() 中实现第一步:创建节点映射 nodeMap := make(map[uint]*dto.MenuNode),遍历权限列表构建 MenuNode 对象
  • 3.3 在 buildMenuTree() 中实现第二步:组织父子关系,根据 parent_id 将节点追加到父节点的 Children 数组或 roots 数组
  • 3.4 在 buildMenuTree() 中实现孤儿节点处理:如果 parent_id 不在 nodeMap 中,将节点提升为根节点,并记录警告日志
  • 3.5 新增 sortMenuNodes() 方法,接收参数 nodes []MenuNode,实现递归排序(根据 Sort 字段升序)
  • 3.6 在 buildMenuTree() 中调用 sortMenuNodes(roots) 完成排序后返回

4. 超级管理员专用逻辑

  • 4.1 新增 getAllPermissionsForSuperAdmin() 方法,接收参数 ctx, device,返回 ([]string, []MenuNode, []string, error)
  • 4.2 在 getAllPermissionsForSuperAdmin() 中调用 permissionStore.GetAll(ctx, nil) 查询所有启用的权限
  • 4.3 在 getAllPermissionsForSuperAdmin() 中调用 classifyPermissions(allPerms, device) 完成分类和过滤

5. 修改 Login 方法

  • 5.1 在 auth.Service.Login() 方法中,将 getUserPermissions(ctx, account.ID) 替换为 getUserPermissionsAndMenus(ctx, account.ID, account.UserType, device)
  • 5.2 在 Login() 方法中,将返回的 (permissions, menus, buttons, err) 赋值到 LoginResponse 的对应字段
  • 5.3 处理错误:如果 getUserPermissionsAndMenus() 失败,记录错误日志,返回空的 menus: []buttons: [](不阻塞登录)
  • 5.4 运行 lsp_diagnostics 验证 Service 文件无错误

6. 单元测试 - buildMenuTree

  • 6.1 创建 internal/service/auth/menu_tree_test.go 文件
  • 6.2 编写测试 TestBuildMenuTree_RootNodes:测试只有根节点的场景(parent_id = NULL
  • 6.3 编写测试 TestBuildMenuTree_MultiLevel:测试两级或三级嵌套菜单场景
  • 6.4 编写测试 TestBuildMenuTree_OrphanNodes:测试孤儿节点提升为根节点的场景(parent_id 不存在)
  • 6.5 编写测试 TestBuildMenuTree_Sorting:测试菜单排序(根据 sort 字段升序)
  • 6.6 编写测试 TestBuildMenuTree_EmptyInput:测试空权限列表输入,验证返回空数组
  • 6.7 运行单元测试:source .env.local && go test -v ./internal/service/auth/...,确保所有测试通过

7. 单元测试 - classifyPermissions

  • 7.1 创建 internal/service/auth/classify_test.go 文件
  • 7.2 编写测试 TestClassifyPermissions_PlatformFilter:测试平台过滤(device="web" 时过滤 platform="h5" 的权限)
  • 7.3 编写测试 TestClassifyPermissions_MenuAndButton:测试菜单和按钮权限分类(perm_type=1 vs perm_type=2
  • 7.4 编写测试 TestClassifyPermissions_AllPermissions:测试所有权限码收集(包含菜单和按钮)
  • 7.5 编写测试 TestClassifyPermissions_PlatformAll:测试 platform="all" 的权限对所有端口可见
  • 7.6 运行单元测试:source .env.local && go test -v ./internal/service/auth/...,确保所有测试通过

8. 单元测试 - getUserPermissionsAndMenus

  • 8.1 编写测试 TestGetUserPermissionsAndMenus_SuperAdmin:测试超级管理员返回所有权限
  • 8.2 编写测试 TestGetUserPermissionsAndMenus_NormalUser:测试普通用户返回角色权限
  • 8.3 编写测试 TestGetUserPermissionsAndMenus_NoPermissions:测试用户无权限时返回空数组
  • 8.4 编写测试 TestGetUserPermissionsAndMenus_DeviceFilter:测试 device 参数过滤平台
  • 8.5 运行单元测试:source .env.local && go test -v ./internal/service/auth/...,确保所有测试通过

9. 集成测试 - Login API

  • 9.1 创建或修改 tests/integration/admin_auth_test.go 文件
  • 9.2 编写测试 TestAdminLogin_MenusAndButtons:验证登录响应包含 menus, buttons, permissions 三个字段
  • 9.3 编写测试 TestAdminLogin_MenuTreeStructure:验证 menus 为树形结构,包含 id, perm_code, name, url, sort, children 字段
  • 9.4 编写测试 TestAdminLogin_ButtonsArray:验证 buttons 为扁平数组,只包含 perm_type=2 的权限码
  • 9.5 编写测试 TestAdminLogin_SuperAdmin:验证超级管理员登录时返回所有菜单和按钮
  • 9.6 编写测试 TestAdminLogin_PlatformFilter:验证 device="web" 时不返回 platform="h5" 的菜单
  • 9.7 编写测试 TestAdminLogin_NoPermissions:验证无权限用户登录时返回空的 menusbuttons
  • 9.8 运行集成测试:source .env.local && go test -v ./tests/integration/...,确保所有测试通过

10. 集成测试 - GetMe API

  • 10.1 编写测试 TestAdminGetMe_NoMenus:验证 GetMe 接口不返回 menusbuttons 字段
  • 10.2 编写测试 TestAdminGetMe_OnlyUserAndPermissions:验证 GetMe 接口只返回 userpermissions 字段
  • 10.3 运行集成测试:source .env.local && go test -v ./tests/integration/...,确保所有测试通过

11. 性能测试

  • 11.1 编写性能基准测试 BenchmarkBuildMenuTree测试不同权限数量50、100、200的菜单树构建性能
  • 11.2 编写性能基准测试 BenchmarkClassifyPermissions:测试权限分类性能
  • 11.3 运行基准测试:source .env.local && go test -bench=. -benchmem ./internal/service/auth/...
  • 11.4 验证登录接口响应时间增加 < 50ms在 50 个权限的场景下)

12. 代码审查和优化

  • 12.1 运行 lsp_diagnostics 检查所有修改的文件,确保无类型错误和警告
  • 12.2 运行 gofmt -w ./internal/service/auth/service.go 格式化代码
  • 12.3 运行 gofmt -w ./internal/model/dto/auth_dto.go 格式化代码
  • 12.4 检查所有注释使用中文,变量名和函数名使用英文
  • 12.5 检查错误处理:使用 errors.New()errors.Wrap(),不使用 fmt.Errorf()
  • 12.6 检查日志记录:孤儿节点检测时记录警告日志(使用 Zap

13. 文档更新

  • 13.1 更新 README.md:在"核心功能"部分添加"登录接口返回菜单树和按钮权限"说明
  • 13.2 创建 docs/login-menu-button-response/使用指南.md:说明前端如何使用 menusbuttons 字段
  • 13.3 在使用指南中添加 localStorage 缓存示例代码
  • 13.4 在使用指南中添加 MenuNode 数据结构说明和示例响应
  • 13.5 在使用指南中添加性能影响说明和最佳实践建议

14. 最终验证

  • 14.1 运行完整测试套件:source .env.local && go test ./...,确保所有测试通过
  • 14.2 启动 API 服务:go run cmd/api/main.go,验证服务正常启动
  • 14.3 使用 Postman/curl 测试登录接口:验证响应包含 menus, buttons, permissions 三个字段
  • 14.4 验证响应体大小 < 20KB普通用户场景
  • 14.5 验证 GetMe 接口不返回 menusbuttons 字段
  • 14.6 验证向后兼容性:旧版前端仍可使用 permissions 字段