Compare commits

..

2 Commits

Author SHA1 Message Date
神码-方晓辉 7753ddbfbd fix: 优化部门管理页面表格布局
- 部门名称列使用 min-width 自动扩展填充
- 调整排序列和操作列宽度
- 消除右侧空白区域
2026-02-02 14:49:34 +08:00
神码-方晓辉 a5c380c90f fix: 修复系统管理模块字段显示问题
- 修复菜单管理:返回树形结构,权限标识和组件路径正常显示
- 修复部门管理:字段名转换为驼峰格式
- 修复岗位管理:字段名转换为驼峰格式
- 修复字典管理:字典类型和字典数据字段名转换
- 修复角色管理:字段名转换为驼峰格式
- 更新项目规则:添加前后端命名规范文档
2026-02-02 14:46:23 +08:00
7 changed files with 260 additions and 9 deletions

View File

@ -6,6 +6,10 @@ alwaysApply: true
# 盘古用户平台Pangu User Platform项目规范 # 盘古用户平台Pangu User Platform项目规范
> **项目路径**`/Users/felix/hbxhWorkSpace/pangu-user-platform`
>
> **重要声明**:本规范仅适用于 pangu-user-platform 项目,不受外部工程目录(如 `/Users/felix/hbxhWorkSpace/.cursorrules`)中其他规范的影响。当本规范与外部规范冲突时,以本规范为准。
## 作者规范 ## 作者规范
**重要**:本项目所有文档、代码注释的作者统一使用 **pangu** **重要**:本项目所有文档、代码注释的作者统一使用 **pangu**
@ -102,6 +106,117 @@ public class LoginController {
- 前端 API 调用路径如 `/system/user/list`,会被自动加上 `/dev-api` 前缀 - 前端 API 调用路径如 `/system/user/list`,会被自动加上 `/dev-api` 前缀
- 生产环境通过 nginx 配置同样的代理规则 - 生产环境通过 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<Map<String, Object>> rows = jdbcTemplate.queryForList(sql);
return AjaxResult.success(rows); // 前端收到 user_id, dept_name
// ✅ 正确:转换为驼峰格式
List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql);
List<Map<String, Object>> result = new ArrayList<>();
for (Map<String, Object> row : rows) {
Map<String, Object> 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<String, Object> item = new HashMap<>();
item.put("userId", row.get("user_id"));
Map<String, Object> 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": "系统管理" }]
}
```
## 业务模块 ## 业务模块
| 模块 | 路径 | 说明 | | 模块 | 路径 | 说明 |

View File

@ -43,7 +43,24 @@ public class SysDeptController extends BaseController {
sql.append("ORDER BY parent_id, order_num"); sql.append("ORDER BY parent_id, order_num");
List<Map<String, Object>> depts = jdbcTemplate.queryForList(sql.toString(), params.toArray()); List<Map<String, Object>> depts = jdbcTemplate.queryForList(sql.toString(), params.toArray());
return AjaxResult.success(depts);
// 转换字段名为驼峰格式
List<Map<String, Object>> result = new ArrayList<>();
for (Map<String, Object> row : depts) {
Map<String, Object> 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);
} }
/** /**

View File

@ -60,10 +60,23 @@ public class SysDictController extends BaseController {
List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray()); List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray());
// 转换字段名为驼峰格式
List<Map<String, Object>> result = new ArrayList<>();
for (Map<String, Object> row : rows) {
Map<String, Object> 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(); TableDataInfo dataInfo = new TableDataInfo();
dataInfo.setCode(200); dataInfo.setCode(200);
dataInfo.setMsg("查询成功"); dataInfo.setMsg("查询成功");
dataInfo.setRows(rows); dataInfo.setRows(result);
dataInfo.setTotal(total != null ? total : 0); dataInfo.setTotal(total != null ? total : 0);
return dataInfo; return dataInfo;
} }
@ -200,10 +213,28 @@ public class SysDictController extends BaseController {
List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray()); List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray());
// 转换字段名为驼峰格式
List<Map<String, Object>> result = new ArrayList<>();
for (Map<String, Object> row : rows) {
Map<String, Object> 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(); TableDataInfo dataInfo = new TableDataInfo();
dataInfo.setCode(200); dataInfo.setCode(200);
dataInfo.setMsg("查询成功"); dataInfo.setMsg("查询成功");
dataInfo.setRows(rows); dataInfo.setRows(result);
dataInfo.setTotal(total != null ? total : 0); dataInfo.setTotal(total != null ? total : 0);
return dataInfo; return dataInfo;
} }

View File

@ -44,7 +44,66 @@ public class SysMenuController extends BaseController {
sql.append("ORDER BY parent_id, order_num"); sql.append("ORDER BY parent_id, order_num");
List<Map<String, Object>> menus = jdbcTemplate.queryForList(sql.toString(), params.toArray()); List<Map<String, Object>> menus = jdbcTemplate.queryForList(sql.toString(), params.toArray());
return AjaxResult.success(menus);
// 转换字段名为驼峰格式
List<Map<String, Object>> menuList = new ArrayList<>();
for (Map<String, Object> row : menus) {
Map<String, Object> 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<Map<String, Object>> result = buildMenuTree(menuList);
return AjaxResult.success(result);
}
/**
* 构建菜单树形结构
*/
private List<Map<String, Object>> buildMenuTree(List<Map<String, Object>> menus) {
List<Map<String, Object>> result = new ArrayList<>();
Map<Long, Map<String, Object>> menuMap = new HashMap<>();
// 建立 menuId -> menu 的映射
for (Map<String, Object> menu : menus) {
Long menuId = ((Number) menu.get("menuId")).longValue();
menuMap.put(menuId, menu);
menu.put("children", new ArrayList<Map<String, Object>>());
}
// 构建树
for (Map<String, Object> menu : menus) {
Long parentId = ((Number) menu.get("parentId")).longValue();
if (parentId == 0) {
result.add(menu);
} else {
Map<String, Object> parent = menuMap.get(parentId);
if (parent != null) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> children = (List<Map<String, Object>>) parent.get("children");
children.add(menu);
} else {
// 父菜单不存在作为顶级菜单
result.add(menu);
}
}
}
return result;
} }
/** /**

View File

@ -58,10 +58,24 @@ public class SysPostController extends BaseController {
List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray()); List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray());
// 转换字段名为驼峰格式
List<Map<String, Object>> result = new ArrayList<>();
for (Map<String, Object> row : rows) {
Map<String, Object> 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(); TableDataInfo dataInfo = new TableDataInfo();
dataInfo.setCode(200); dataInfo.setCode(200);
dataInfo.setMsg("查询成功"); dataInfo.setMsg("查询成功");
dataInfo.setRows(rows); dataInfo.setRows(result);
dataInfo.setTotal(total != null ? total : 0); dataInfo.setTotal(total != null ? total : 0);
return dataInfo; return dataInfo;
} }

View File

@ -58,10 +58,25 @@ public class SysRoleController extends BaseController {
List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray()); List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray());
// 转换字段名为驼峰格式
List<Map<String, Object>> result = new ArrayList<>();
for (Map<String, Object> row : rows) {
Map<String, Object> 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(); TableDataInfo dataInfo = new TableDataInfo();
dataInfo.setCode(200); dataInfo.setCode(200);
dataInfo.setMsg("查询成功"); dataInfo.setMsg("查询成功");
dataInfo.setRows(rows); dataInfo.setRows(result);
dataInfo.setTotal(total != null ? total : 0); dataInfo.setTotal(total != null ? total : 0);
return dataInfo; return dataInfo;
} }

View File

@ -55,8 +55,8 @@
:default-expand-all="isExpandAll" :default-expand-all="isExpandAll"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
> >
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column> <el-table-column prop="deptName" label="部门名称" min-width="200"></el-table-column>
<el-table-column prop="orderNum" label="排序" width="200"></el-table-column> <el-table-column prop="orderNum" label="排序" width="80"></el-table-column>
<el-table-column prop="status" label="状态" width="100"> <el-table-column prop="status" label="状态" width="100">
<template #default="scope"> <template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" /> <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
@ -67,7 +67,7 @@
<span>{{ parseTime(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" width="200" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dept:edit']">修改</el-button> <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dept:edit']">修改</el-button>
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:dept:add']">新增</el-button> <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:dept:add']">新增</el-button>