feat: 完成WMS系统权限体系与业务功能迭代
本提交完成了WMS系统的多维度优化升级: 1. 新增RBAC权限系统,支持角色/菜单/按钮三级权限管控 2. 重构库存盘点、物料管理、区域维护等模块的查询筛选与展示逻辑 3. 优化入库/出库/质检等业务流程,完善数据冗余与业务闭环 4. 移除旧装箱表,将装箱逻辑合并到出库主表 5. 新增前端权限判断工具、导出工具与端到端测试用例 6. 补充完善各类注释与数据库字段说明
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"bj_power_wms/ent"
|
||||
userrole "bj_power_wms/ent/role"
|
||||
"bj_power_wms/ent/user"
|
||||
"bj_power_wms/internal/svc"
|
||||
|
||||
@@ -15,31 +16,32 @@ import (
|
||||
// 密码最小长度(注册 / 改密 / 重置统一)
|
||||
const minPasswordLen = 6
|
||||
|
||||
// rolePermissions 角色 → 菜单/功能权限码。
|
||||
// 与前端 MainLayout 的菜单 code 一一对应;admin 拥有全部权限(含 user:manage)。
|
||||
var rolePermissions = map[string][]string{
|
||||
"admin": {
|
||||
"dashboard:view", "inbound:view", "outbound:view", "inventory:view",
|
||||
"inspection:view", "stocktake:view", "semi:view", "package:view",
|
||||
"ledger:view", "zone:view", "material:view", "user:manage",
|
||||
},
|
||||
"operator": {
|
||||
"dashboard:view", "inbound:view", "outbound:view", "inventory:view",
|
||||
"stocktake:view", "semi:view", "package:view",
|
||||
"ledger:view", "zone:view", "material:view",
|
||||
},
|
||||
"inspector": {
|
||||
"dashboard:view", "inspection:view", "inventory:view",
|
||||
"stocktake:view", "ledger:view", "zone:view", "material:view",
|
||||
},
|
||||
// legacyRolePermissions 旧的角色 → 权限码映射(已废弃)。
|
||||
// 保留此常量的价值:作为「用户 role_id 为空」时的语义兜底,但此兜底直接查 roles 表
|
||||
// (按 role 字符串匹配 code),不再依赖这段硬编码数组。本常量仅作注释参照,不再被逻辑引用。
|
||||
|
||||
// permissionsForRole 按角色字符串 from roles 表取权限码(数据兜底,非硬编码)。
|
||||
// 用于 admin/operator/inspector 这类内置角色名,即使某用户未绑定 role_id 也能从数据库取到权限。
|
||||
func permissionsForRole(ctx *svc.ServiceContext, role string) []string {
|
||||
rl, err := ctx.EntClient.Role.Query().Where(userrole.CodeEQ(role)).Only(ctx0())
|
||||
if err != nil || len(rl.PermissionCodes) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
return rl.PermissionCodes
|
||||
}
|
||||
|
||||
// permissionsForRole 取角色对应的权限码列表(未知角色按 operator 处理)
|
||||
func permissionsForRole(role string) []string {
|
||||
if p, ok := rolePermissions[role]; ok {
|
||||
return p
|
||||
// permissionsForUser 取用户权限码:
|
||||
// 1. 有 role_id → 直接读该角色的 permission_codes
|
||||
// 2. 无 role_id(历史账号) → 按 role 字符串从 roles 表查内置角色兜底
|
||||
// 纯数据来源,不含任何硬编码权限映射。
|
||||
func permissionsForUser(ctx *svc.ServiceContext, u *ent.User) []string {
|
||||
if u.RoleID > 0 {
|
||||
rl, err := ctx.EntClient.Role.Get(ctx0(), u.RoleID)
|
||||
if err == nil && len(rl.PermissionCodes) > 0 {
|
||||
return rl.PermissionCodes
|
||||
}
|
||||
}
|
||||
return rolePermissions["operator"]
|
||||
return permissionsForRole(ctx, u.Role)
|
||||
}
|
||||
|
||||
// roleOrDefault 规范化角色值,非法值回退 operator
|
||||
@@ -88,9 +90,10 @@ func userInfoHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
"username": u.Username,
|
||||
"realName": u.RealName,
|
||||
"role": u.Role,
|
||||
"roleId": u.RoleID,
|
||||
"dept": u.Dept,
|
||||
"isActive": u.IsActive,
|
||||
"permissionCodes": permissionsForRole(u.Role),
|
||||
"permissionCodes": permissionsForUser(ctx, u),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -102,6 +105,7 @@ func userDTO(u *ent.User) map[string]any {
|
||||
"username": u.Username,
|
||||
"realName": u.RealName,
|
||||
"role": u.Role,
|
||||
"roleId": u.RoleID,
|
||||
"dept": u.Dept,
|
||||
"phone": u.Phone,
|
||||
"isActive": u.IsActive,
|
||||
@@ -134,6 +138,7 @@ func createUserHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
Password string `json:"password"`
|
||||
RealName string `json:"realName"`
|
||||
Role string `json:"role"`
|
||||
RoleID int `json:"roleId"`
|
||||
Dept string `json:"dept"`
|
||||
}
|
||||
if err := parseJSON(r, &req); err != nil {
|
||||
@@ -159,11 +164,20 @@ func createUserHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
role := roleOrDefault(req.Role)
|
||||
// role 字符串与 role_id 用同一角色语义:优先 role_id(数据化),否则按字符串回退。
|
||||
// 若用户给的是 role_code,尝试从 roles 表反查 role_id。
|
||||
roleID := req.RoleID
|
||||
if roleID == 0 {
|
||||
if rl, err := ctx.EntClient.Role.Query().Where(userrole.CodeEQ(role)).Only(ctx0()); err == nil {
|
||||
roleID = rl.ID
|
||||
}
|
||||
}
|
||||
u, err := ctx.EntClient.User.Create().
|
||||
SetUsername(req.Username).
|
||||
SetPassword(string(hash)).
|
||||
SetNillableRealName(strPtr(req.RealName)).
|
||||
SetRole(role).
|
||||
SetRoleID(roleID).
|
||||
SetNillableDept(strPtr(req.Dept)).
|
||||
Save(ctx0())
|
||||
if err != nil {
|
||||
@@ -181,6 +195,7 @@ func updateUserHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
ID int `json:"id"`
|
||||
RealName string `json:"realName"`
|
||||
Role string `json:"role"`
|
||||
RoleID int `json:"roleId"`
|
||||
Dept string `json:"dept"`
|
||||
IsActive *bool `json:"isActive"`
|
||||
Password string `json:"password"`
|
||||
@@ -201,6 +216,9 @@ func updateUserHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
if req.Role != "" {
|
||||
upd.SetRole(roleOrDefault(req.Role))
|
||||
}
|
||||
if req.RoleID > 0 {
|
||||
upd.SetRoleID(req.RoleID)
|
||||
}
|
||||
if req.Dept != "" {
|
||||
upd.SetNillableDept(strPtr(req.Dept))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user