From a5c380c90f819278135e8e20739d25cd9ce60782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A5=9E=E7=A0=81-=E6=96=B9=E6=99=93=E8=BE=89?= Date: Mon, 2 Feb 2026 14:46:23 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97=E5=AD=97=E6=AE=B5=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复菜单管理:返回树形结构,权限标识和组件路径正常显示 - 修复部门管理:字段名转换为驼峰格式 - 修复岗位管理:字段名转换为驼峰格式 - 修复字典管理:字典类型和字典数据字段名转换 - 修复角色管理:字段名转换为驼峰格式 - 更新项目规则:添加前后端命名规范文档 --- .cursor/rules/pangu-project.mdc | 115 ++++++++++++++++++ .../system/controller/SysDeptController.java | 19 ++- .../system/controller/SysDictController.java | 35 +++++- .../system/controller/SysMenuController.java | 61 +++++++++- .../system/controller/SysPostController.java | 16 ++- .../system/controller/SysRoleController.java | 17 ++- 6 files changed, 257 insertions(+), 6 deletions(-) diff --git a/.cursor/rules/pangu-project.mdc b/.cursor/rules/pangu-project.mdc index f887347..01637ac 100644 --- a/.cursor/rules/pangu-project.mdc +++ b/.cursor/rules/pangu-project.mdc @@ -6,6 +6,10 @@ alwaysApply: true # 盘古用户平台(Pangu User Platform)项目规范 +> **项目路径**:`/Users/felix/hbxhWorkSpace/pangu-user-platform` +> +> **重要声明**:本规范仅适用于 pangu-user-platform 项目,不受外部工程目录(如 `/Users/felix/hbxhWorkSpace/.cursorrules`)中其他规范的影响。当本规范与外部规范冲突时,以本规范为准。 + ## 作者规范 **重要**:本项目所有文档、代码注释的作者统一使用 **pangu** @@ -102,6 +106,117 @@ public class LoginController { - 前端 API 调用路径如 `/system/user/list`,会被自动加上 `/dev-api` 前缀 - 生产环境通过 nginx 配置同样的代理规则 +## 前后端数据命名规范 + +本项目前后端数据交互时,必须遵循以下命名规范: + +### 命名风格对照 + +| 位置 | 命名风格 | 示例 | +|------|----------|------| +| 数据库字段 | snake_case(下划线) | `user_id`, `dept_name`, `create_time` | +| 后端返回 JSON | camelCase(小驼峰) | `userId`, `deptName`, `createTime` | +| 前端变量 | camelCase(小驼峰) | `userId`, `deptName`, `createTime` | + +### 后端 Controller 返回规范 + +**重要**:后端使用 JdbcTemplate 直接查询时,必须将 snake_case 字段名转换为 camelCase 后再返回。 + +```java +// ❌ 错误:直接返回数据库字段名 +List> rows = jdbcTemplate.queryForList(sql); +return AjaxResult.success(rows); // 前端收到 user_id, dept_name + +// ✅ 正确:转换为驼峰格式 +List> rows = jdbcTemplate.queryForList(sql); +List> result = new ArrayList<>(); +for (Map row : rows) { + Map item = new HashMap<>(); + item.put("userId", row.get("user_id")); + item.put("deptName", row.get("dept_name")); + item.put("createTime", row.get("create_time")); + result.add(item); +} +return AjaxResult.success(result); // 前端收到 userId, deptName +``` + +### 嵌套对象规范 + +当前端期望嵌套对象时(如 `user.dept.deptName`),后端需要构造嵌套结构: + +```java +// 前端期望格式: { userId: 1, dept: { deptId: 100, deptName: "技术部" } } +Map item = new HashMap<>(); +item.put("userId", row.get("user_id")); + +Map dept = new HashMap<>(); +dept.put("deptId", row.get("dept_id")); +dept.put("deptName", row.get("dept_name")); +item.put("dept", dept); +``` + +### 常见字段转换对照表 + +| 数据库字段 | 后端返回 JSON | 说明 | +|------------|---------------|------| +| `user_id` | `userId` | 用户ID | +| `user_name` | `userName` | 用户名 | +| `nick_name` | `nickName` | 昵称 | +| `dept_id` | `deptId` | 部门ID | +| `dept_name` | `deptName` | 部门名称 | +| `role_id` | `roleId` | 角色ID | +| `role_name` | `roleName` | 角色名称 | +| `menu_id` | `menuId` | 菜单ID | +| `menu_name` | `menuName` | 菜单名称 | +| `post_id` | `postId` | 岗位ID | +| `post_name` | `postName` | 岗位名称 | +| `dict_id` | `dictId` | 字典ID | +| `dict_name` | `dictName` | 字典名称 | +| `dict_type` | `dictType` | 字典类型 | +| `dict_label` | `dictLabel` | 字典标签 | +| `dict_value` | `dictValue` | 字典值 | +| `parent_id` | `parentId` | 父级ID | +| `order_num` | `orderNum` | 排序号 | +| `create_time` | `createTime` | 创建时间 | +| `update_time` | `updateTime` | 更新时间 | +| `create_by` | `createBy` | 创建人 | +| `update_by` | `updateBy` | 更新人 | + +### 分页接口返回格式 + +分页列表接口统一使用 `TableDataInfo` 格式: + +```java +TableDataInfo dataInfo = new TableDataInfo(); +dataInfo.setCode(200); +dataInfo.setMsg("查询成功"); +dataInfo.setRows(result); // 转换后的驼峰格式数据 +dataInfo.setTotal(total); +return dataInfo; +``` + +前端接收格式: +```json +{ + "code": 200, + "msg": "查询成功", + "rows": [{ "userId": 1, "userName": "admin" }], + "total": 100 +} +``` + +### 非分页接口返回格式 + +使用 `AjaxResult.success(data)` 格式: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": [{ "menuId": 1, "menuName": "系统管理" }] +} +``` + ## 业务模块 | 模块 | 路径 | 说明 | diff --git a/backend/pangu-system/src/main/java/com/pangu/system/controller/SysDeptController.java b/backend/pangu-system/src/main/java/com/pangu/system/controller/SysDeptController.java index b361f88..b6c82e1 100644 --- a/backend/pangu-system/src/main/java/com/pangu/system/controller/SysDeptController.java +++ b/backend/pangu-system/src/main/java/com/pangu/system/controller/SysDeptController.java @@ -43,7 +43,24 @@ public class SysDeptController extends BaseController { sql.append("ORDER BY parent_id, order_num"); List> depts = jdbcTemplate.queryForList(sql.toString(), params.toArray()); - return AjaxResult.success(depts); + + // 转换字段名为驼峰格式 + List> result = new ArrayList<>(); + for (Map row : depts) { + Map item = new HashMap<>(); + item.put("deptId", row.get("dept_id")); + item.put("parentId", row.get("parent_id")); + item.put("ancestors", row.get("ancestors")); + item.put("deptName", row.get("dept_name")); + item.put("orderNum", row.get("order_num")); + item.put("leader", row.get("leader")); + item.put("phone", row.get("phone")); + item.put("email", row.get("email")); + item.put("status", row.get("status")); + item.put("createTime", row.get("create_time")); + result.add(item); + } + return AjaxResult.success(result); } /** diff --git a/backend/pangu-system/src/main/java/com/pangu/system/controller/SysDictController.java b/backend/pangu-system/src/main/java/com/pangu/system/controller/SysDictController.java index 0b76821..93ddc87 100644 --- a/backend/pangu-system/src/main/java/com/pangu/system/controller/SysDictController.java +++ b/backend/pangu-system/src/main/java/com/pangu/system/controller/SysDictController.java @@ -60,10 +60,23 @@ public class SysDictController extends BaseController { List> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray()); + // 转换字段名为驼峰格式 + List> result = new ArrayList<>(); + for (Map row : rows) { + Map item = new HashMap<>(); + item.put("dictId", row.get("dict_id")); + item.put("dictName", row.get("dict_name")); + item.put("dictType", row.get("dict_type")); + item.put("status", row.get("status")); + item.put("createTime", row.get("create_time")); + item.put("remark", row.get("remark")); + result.add(item); + } + TableDataInfo dataInfo = new TableDataInfo(); dataInfo.setCode(200); dataInfo.setMsg("查询成功"); - dataInfo.setRows(rows); + dataInfo.setRows(result); dataInfo.setTotal(total != null ? total : 0); return dataInfo; } @@ -200,10 +213,28 @@ public class SysDictController extends BaseController { List> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray()); + // 转换字段名为驼峰格式 + List> result = new ArrayList<>(); + for (Map row : rows) { + Map item = new HashMap<>(); + item.put("dictCode", row.get("dict_code")); + item.put("dictSort", row.get("dict_sort")); + item.put("dictLabel", row.get("dict_label")); + item.put("dictValue", row.get("dict_value")); + item.put("dictType", row.get("dict_type")); + item.put("cssClass", row.get("css_class")); + item.put("listClass", row.get("list_class")); + item.put("isDefault", row.get("is_default")); + item.put("status", row.get("status")); + item.put("createTime", row.get("create_time")); + item.put("remark", row.get("remark")); + result.add(item); + } + TableDataInfo dataInfo = new TableDataInfo(); dataInfo.setCode(200); dataInfo.setMsg("查询成功"); - dataInfo.setRows(rows); + dataInfo.setRows(result); dataInfo.setTotal(total != null ? total : 0); return dataInfo; } diff --git a/backend/pangu-system/src/main/java/com/pangu/system/controller/SysMenuController.java b/backend/pangu-system/src/main/java/com/pangu/system/controller/SysMenuController.java index b4a30f3..1f2388f 100644 --- a/backend/pangu-system/src/main/java/com/pangu/system/controller/SysMenuController.java +++ b/backend/pangu-system/src/main/java/com/pangu/system/controller/SysMenuController.java @@ -44,7 +44,66 @@ public class SysMenuController extends BaseController { sql.append("ORDER BY parent_id, order_num"); List> menus = jdbcTemplate.queryForList(sql.toString(), params.toArray()); - return AjaxResult.success(menus); + + // 转换字段名为驼峰格式 + List> menuList = new ArrayList<>(); + for (Map row : menus) { + Map item = new HashMap<>(); + item.put("menuId", row.get("menu_id")); + item.put("menuName", row.get("menu_name")); + item.put("parentId", row.get("parent_id")); + item.put("orderNum", row.get("order_num")); + item.put("path", row.get("path")); + item.put("component", row.get("component")); + item.put("query", row.get("query")); + item.put("isFrame", row.get("is_frame")); + item.put("isCache", row.get("is_cache")); + item.put("menuType", row.get("menu_type")); + item.put("visible", row.get("visible")); + item.put("status", row.get("status")); + item.put("perms", row.get("perms")); + item.put("icon", row.get("icon")); + item.put("createTime", row.get("create_time")); + menuList.add(item); + } + + // 构建树形结构 + List> result = buildMenuTree(menuList); + return AjaxResult.success(result); + } + + /** + * 构建菜单树形结构 + */ + private List> buildMenuTree(List> menus) { + List> result = new ArrayList<>(); + Map> menuMap = new HashMap<>(); + + // 建立 menuId -> menu 的映射 + for (Map menu : menus) { + Long menuId = ((Number) menu.get("menuId")).longValue(); + menuMap.put(menuId, menu); + menu.put("children", new ArrayList>()); + } + + // 构建树 + for (Map menu : menus) { + Long parentId = ((Number) menu.get("parentId")).longValue(); + if (parentId == 0) { + result.add(menu); + } else { + Map parent = menuMap.get(parentId); + if (parent != null) { + @SuppressWarnings("unchecked") + List> children = (List>) parent.get("children"); + children.add(menu); + } else { + // 父菜单不存在,作为顶级菜单 + result.add(menu); + } + } + } + return result; } /** diff --git a/backend/pangu-system/src/main/java/com/pangu/system/controller/SysPostController.java b/backend/pangu-system/src/main/java/com/pangu/system/controller/SysPostController.java index 2d7e7f8..674201f 100644 --- a/backend/pangu-system/src/main/java/com/pangu/system/controller/SysPostController.java +++ b/backend/pangu-system/src/main/java/com/pangu/system/controller/SysPostController.java @@ -58,10 +58,24 @@ public class SysPostController extends BaseController { List> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray()); + // 转换字段名为驼峰格式 + List> result = new ArrayList<>(); + for (Map row : rows) { + Map item = new HashMap<>(); + item.put("postId", row.get("post_id")); + item.put("postCode", row.get("post_code")); + item.put("postName", row.get("post_name")); + item.put("postSort", row.get("post_sort")); + item.put("status", row.get("status")); + item.put("createTime", row.get("create_time")); + item.put("remark", row.get("remark")); + result.add(item); + } + TableDataInfo dataInfo = new TableDataInfo(); dataInfo.setCode(200); dataInfo.setMsg("查询成功"); - dataInfo.setRows(rows); + dataInfo.setRows(result); dataInfo.setTotal(total != null ? total : 0); return dataInfo; } diff --git a/backend/pangu-system/src/main/java/com/pangu/system/controller/SysRoleController.java b/backend/pangu-system/src/main/java/com/pangu/system/controller/SysRoleController.java index d03e202..70b0643 100644 --- a/backend/pangu-system/src/main/java/com/pangu/system/controller/SysRoleController.java +++ b/backend/pangu-system/src/main/java/com/pangu/system/controller/SysRoleController.java @@ -58,10 +58,25 @@ public class SysRoleController extends BaseController { List> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray()); + // 转换字段名为驼峰格式 + List> result = new ArrayList<>(); + for (Map row : rows) { + Map item = new HashMap<>(); + item.put("roleId", row.get("role_id")); + item.put("roleName", row.get("role_name")); + item.put("roleKey", row.get("role_key")); + item.put("roleSort", row.get("role_sort")); + item.put("dataScope", row.get("data_scope")); + item.put("status", row.get("status")); + item.put("createTime", row.get("create_time")); + item.put("remark", row.get("remark")); + result.add(item); + } + TableDataInfo dataInfo = new TableDataInfo(); dataInfo.setCode(200); dataInfo.setMsg("查询成功"); - dataInfo.setRows(rows); + dataInfo.setRows(result); dataInfo.setTotal(total != null ? total : 0); return dataInfo; }