Compare commits
2 Commits
b85f332e44
...
7753ddbfbd
| Author | SHA1 | Date |
|---|---|---|
|
|
7753ddbfbd | |
|
|
a5c380c90f |
|
|
@ -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": "系统管理" }]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## 业务模块
|
## 业务模块
|
||||||
|
|
||||||
| 模块 | 路径 | 说明 |
|
| 模块 | 路径 | 说明 |
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue