package model import ( "backend/util" "fmt" "strings" ) type PermissionUserGroup struct { ID int `json:"id" db:"id"` GroupCode string `json:"group_code" db:"group_code"` GroupName string `json:"group_name" db:"group_name"` Status int `json:"status" db:"status"` Remark string `json:"remark" db:"remark"` CreateTime int `json:"createTime" db:"createTime"` UpdateTime int `json:"updateTime" db:"updateTime"` } type PermissionRole struct { ID int `json:"id" db:"id"` RoleCode string `json:"role_code" db:"role_code"` RoleName string `json:"role_name" db:"role_name"` Status int `json:"status" db:"status"` IsSystem int `json:"is_system" db:"is_system"` Remark string `json:"remark" db:"remark"` CreateTime int `json:"createTime" db:"createTime"` UpdateTime int `json:"updateTime" db:"updateTime"` } type PermissionPoint struct { ID int `json:"id" db:"id"` PermissionCode string `json:"permission_code" db:"permission_code"` PermissionName string `json:"permission_name" db:"permission_name"` PermissionGroup string `json:"permission_group" db:"permission_group"` APIPath string `json:"api_path" db:"api_path"` HTTPMethod string `json:"http_method" db:"http_method"` Status int `json:"status" db:"status"` Remark string `json:"remark" db:"remark"` CreateTime int `json:"createTime" db:"createTime"` UpdateTime int `json:"updateTime" db:"updateTime"` } type PermissionUserGroupListParams struct { Page int `json:"page"` PageSize int `json:"pageSize"` GroupCode string `json:"group_code"` GroupName string `json:"group_name"` } type PermissionRoleListParams struct { Page int `json:"page"` PageSize int `json:"pageSize"` RoleCode string `json:"role_code"` RoleName string `json:"role_name"` } type PermissionPointListParams struct { Page int `json:"page"` PageSize int `json:"pageSize"` PermissionCode string `json:"permission_code"` PermissionName string `json:"permission_name"` PermissionGroup string `json:"permission_group"` } func normalizePage(page, pageSize int) (int, int) { if page <= 0 { page = 1 } if pageSize <= 0 { pageSize = 20 } return page, pageSize } func ListPermissionUserGroups(params PermissionUserGroupListParams) ([]PermissionUserGroup, int, error) { page, pageSize := normalizePage(params.Page, params.PageSize) db := util.MPool.GetGameDB() defer db.Close() if db == nil { return nil, 0, fmt.Errorf("failed to get database connection") } whereParts := []string{"1=1"} args := []interface{}{} if params.GroupCode != "" { whereParts = append(whereParts, "group_code LIKE ?") args = append(args, "%"+params.GroupCode+"%") } if params.GroupName != "" { whereParts = append(whereParts, "group_name LIKE ?") args = append(args, "%"+params.GroupName+"%") } where := strings.Join(whereParts, " AND ") var total int countArgs := append([]interface{}{}, args...) if err := db.Get(&total, "SELECT COUNT(*) FROM admin_user_group WHERE "+where, countArgs...); err != nil { return nil, 0, err } list := []PermissionUserGroup{} listArgs := append(args, pageSize, (page-1)*pageSize) query := "SELECT id, group_code, group_name, status, remark, createTime, updateTime FROM admin_user_group WHERE " + where + " ORDER BY id DESC LIMIT ? OFFSET ?" if err := db.Select(&list, query, listArgs...); err != nil { return nil, 0, err } return list, total, nil } func CreatePermissionUserGroup(item *PermissionUserGroup, admin string) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } now := int(util.Now()) item.CreateTime = now item.UpdateTime = now result, err := db.NamedExec("INSERT INTO admin_user_group (group_code, group_name, status, remark, create_admin, update_admin, createTime, updateTime) VALUES (:group_code, :group_name, :status, :remark, :create_admin, :update_admin, :createTime, :updateTime)", map[string]interface{}{ "group_code": item.GroupCode, "group_name": item.GroupName, "status": item.Status, "remark": item.Remark, "create_admin": admin, "update_admin": admin, "createTime": item.CreateTime, "updateTime": item.UpdateTime, }) if err != nil { return err } id, err := result.LastInsertId() if err == nil { item.ID = int(id) } return nil } func UpdatePermissionUserGroup(item *PermissionUserGroup, admin string) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } item.UpdateTime = int(util.Now()) _, err := db.NamedExec("UPDATE admin_user_group SET group_code = :group_code, group_name = :group_name, status = :status, remark = :remark, update_admin = :update_admin, updateTime = :updateTime WHERE id = :id", map[string]interface{}{ "id": item.ID, "group_code": item.GroupCode, "group_name": item.GroupName, "status": item.Status, "remark": item.Remark, "update_admin": admin, "updateTime": item.UpdateTime, }) return err } func DeletePermissionUserGroup(id int) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } _, err := db.Exec("DELETE FROM admin_user_group WHERE id = ?", id) return err } func ListPermissionRoles(params PermissionRoleListParams) ([]PermissionRole, int, error) { page, pageSize := normalizePage(params.Page, params.PageSize) db := util.MPool.GetGameDB() defer db.Close() if db == nil { return nil, 0, fmt.Errorf("failed to get database connection") } whereParts := []string{"1=1"} args := []interface{}{} if params.RoleCode != "" { whereParts = append(whereParts, "role_code LIKE ?") args = append(args, "%"+params.RoleCode+"%") } if params.RoleName != "" { whereParts = append(whereParts, "role_name LIKE ?") args = append(args, "%"+params.RoleName+"%") } where := strings.Join(whereParts, " AND ") var total int if err := db.Get(&total, "SELECT COUNT(*) FROM admin_role WHERE "+where, args...); err != nil { return nil, 0, err } list := []PermissionRole{} listArgs := append(args, pageSize, (page-1)*pageSize) query := "SELECT id, role_code, role_name, status, is_system, remark, createTime, updateTime FROM admin_role WHERE " + where + " ORDER BY id DESC LIMIT ? OFFSET ?" if err := db.Select(&list, query, listArgs...); err != nil { return nil, 0, err } return list, total, nil } func CreatePermissionRole(item *PermissionRole, admin string) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } now := int(util.Now()) item.CreateTime = now item.UpdateTime = now result, err := db.NamedExec("INSERT INTO admin_role (role_code, role_name, status, is_system, remark, create_admin, update_admin, createTime, updateTime) VALUES (:role_code, :role_name, :status, :is_system, :remark, :create_admin, :update_admin, :createTime, :updateTime)", map[string]interface{}{ "role_code": item.RoleCode, "role_name": item.RoleName, "status": item.Status, "is_system": item.IsSystem, "remark": item.Remark, "create_admin": admin, "update_admin": admin, "createTime": item.CreateTime, "updateTime": item.UpdateTime, }) if err != nil { return err } id, err := result.LastInsertId() if err == nil { item.ID = int(id) } return nil } func UpdatePermissionRole(item *PermissionRole, admin string) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } item.UpdateTime = int(util.Now()) _, err := db.NamedExec("UPDATE admin_role SET role_code = :role_code, role_name = :role_name, status = :status, is_system = :is_system, remark = :remark, update_admin = :update_admin, updateTime = :updateTime WHERE id = :id", map[string]interface{}{ "id": item.ID, "role_code": item.RoleCode, "role_name": item.RoleName, "status": item.Status, "is_system": item.IsSystem, "remark": item.Remark, "update_admin": admin, "updateTime": item.UpdateTime, }) return err } func DeletePermissionRole(id int) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } var isSystem int if err := db.Get(&isSystem, "SELECT is_system FROM admin_role WHERE id = ?", id); err != nil { return err } if isSystem == 1 { return fmt.Errorf("system role cannot be deleted") } _, err := db.Exec("DELETE FROM admin_role WHERE id = ?", id) return err } func ListPermissionPoints(params PermissionPointListParams) ([]PermissionPoint, int, error) { page, pageSize := normalizePage(params.Page, params.PageSize) db := util.MPool.GetGameDB() defer db.Close() if db == nil { return nil, 0, fmt.Errorf("failed to get database connection") } whereParts := []string{"1=1"} args := []interface{}{} if params.PermissionCode != "" { whereParts = append(whereParts, "permission_code LIKE ?") args = append(args, "%"+params.PermissionCode+"%") } if params.PermissionName != "" { whereParts = append(whereParts, "permission_name LIKE ?") args = append(args, "%"+params.PermissionName+"%") } if params.PermissionGroup != "" { whereParts = append(whereParts, "permission_group LIKE ?") args = append(args, "%"+params.PermissionGroup+"%") } where := strings.Join(whereParts, " AND ") var total int if err := db.Get(&total, "SELECT COUNT(*) FROM admin_permission WHERE "+where, args...); err != nil { return nil, 0, err } list := []PermissionPoint{} listArgs := append(args, pageSize, (page-1)*pageSize) query := "SELECT id, permission_code, permission_name, permission_group, api_path, http_method, status, remark, createTime, updateTime FROM admin_permission WHERE " + where + " ORDER BY id DESC LIMIT ? OFFSET ?" if err := db.Select(&list, query, listArgs...); err != nil { return nil, 0, err } return list, total, nil } func CreatePermissionPoint(item *PermissionPoint, admin string) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } now := int(util.Now()) item.CreateTime = now item.UpdateTime = now result, err := db.NamedExec("INSERT INTO admin_permission (permission_code, permission_name, permission_group, api_path, http_method, status, remark, create_admin, update_admin, createTime, updateTime) VALUES (:permission_code, :permission_name, :permission_group, :api_path, :http_method, :status, :remark, :create_admin, :update_admin, :createTime, :updateTime)", map[string]interface{}{ "permission_code": item.PermissionCode, "permission_name": item.PermissionName, "permission_group": item.PermissionGroup, "api_path": item.APIPath, "http_method": item.HTTPMethod, "status": item.Status, "remark": item.Remark, "create_admin": admin, "update_admin": admin, "createTime": item.CreateTime, "updateTime": item.UpdateTime, }) if err != nil { return err } id, err := result.LastInsertId() if err == nil { item.ID = int(id) } return nil } func UpdatePermissionPoint(item *PermissionPoint, admin string) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } item.UpdateTime = int(util.Now()) _, err := db.NamedExec("UPDATE admin_permission SET permission_code = :permission_code, permission_name = :permission_name, permission_group = :permission_group, api_path = :api_path, http_method = :http_method, status = :status, remark = :remark, update_admin = :update_admin, updateTime = :updateTime WHERE id = :id", map[string]interface{}{ "id": item.ID, "permission_code": item.PermissionCode, "permission_name": item.PermissionName, "permission_group": item.PermissionGroup, "api_path": item.APIPath, "http_method": item.HTTPMethod, "status": item.Status, "remark": item.Remark, "update_admin": admin, "updateTime": item.UpdateTime, }) return err } func DeletePermissionPoint(id int) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } _, err := db.Exec("DELETE FROM admin_permission WHERE id = ?", id) return err } func SetGroupRoles(groupID int, roleIDs []int, admin string) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } tx, err := db.Begin() if err != nil { return err } defer tx.Rollback() if _, err = tx.Exec("DELETE FROM admin_group_role_rel WHERE group_id = ?", groupID); err != nil { return err } now := int(util.Now()) for _, roleID := range roleIDs { if _, err = tx.Exec("INSERT INTO admin_group_role_rel (group_id, role_id, create_admin, createTime) VALUES (?, ?, ?, ?)", groupID, roleID, admin, now); err != nil { return err } } return tx.Commit() } func ListGroupRoles(groupID int) ([]PermissionRole, error) { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return nil, fmt.Errorf("failed to get database connection") } list := []PermissionRole{} query := "SELECT r.id, r.role_code, r.role_name, r.status, r.is_system, r.remark, r.createTime, r.updateTime FROM admin_role r INNER JOIN admin_group_role_rel rel ON rel.role_id = r.id WHERE rel.group_id = ? ORDER BY r.id DESC" if err := db.Select(&list, query, groupID); err != nil { return nil, err } return list, nil } func SetRolePermissions(roleID int, permissionIDs []int, admin string) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } tx, err := db.Begin() if err != nil { return err } defer tx.Rollback() if _, err = tx.Exec("DELETE FROM admin_role_permission_rel WHERE role_id = ?", roleID); err != nil { return err } now := int(util.Now()) for _, permissionID := range permissionIDs { if _, err = tx.Exec("INSERT INTO admin_role_permission_rel (role_id, permission_id, create_admin, createTime) VALUES (?, ?, ?, ?)", roleID, permissionID, admin, now); err != nil { return err } } return tx.Commit() } func ListRolePermissions(roleID int) ([]PermissionPoint, error) { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return nil, fmt.Errorf("failed to get database connection") } list := []PermissionPoint{} query := "SELECT p.id, p.permission_code, p.permission_name, p.permission_group, p.api_path, p.http_method, p.status, p.remark, p.createTime, p.updateTime FROM admin_permission p INNER JOIN admin_role_permission_rel rel ON rel.permission_id = p.id WHERE rel.role_id = ? ORDER BY p.id DESC" if err := db.Select(&list, query, roleID); err != nil { return nil, err } return list, nil } func SetUserGroups(adminID int, groupIDs []int, operator string) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } tx, err := db.Begin() if err != nil { return err } defer tx.Rollback() if _, err = tx.Exec("DELETE FROM admin_user_group_rel WHERE admin_id = ?", adminID); err != nil { return err } now := int(util.Now()) for _, groupID := range groupIDs { if _, err = tx.Exec("INSERT INTO admin_user_group_rel (admin_id, group_id, create_admin, createTime) VALUES (?, ?, ?, ?)", adminID, groupID, operator, now); err != nil { return err } } return tx.Commit() } func ListUserGroups(adminID int) ([]PermissionUserGroup, error) { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return nil, fmt.Errorf("failed to get database connection") } list := []PermissionUserGroup{} query := "SELECT g.id, g.group_code, g.group_name, g.status, g.remark, g.createTime, g.updateTime FROM admin_user_group g INNER JOIN admin_user_group_rel rel ON rel.group_id = g.id WHERE rel.admin_id = ? ORDER BY g.id DESC" if err := db.Select(&list, query, adminID); err != nil { return nil, err } return list, nil } // UserPermissionItem 用户直接单点权限条目 type UserPermissionItem struct { PermissionID int `json:"permission_id" db:"permission_id"` GrantType int `json:"grant_type" db:"grant_type"` // 1=允许 2=拒绝 } func ListUserPermissions(adminID int) ([]UserPermissionItem, error) { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return nil, fmt.Errorf("failed to get database connection") } list := []UserPermissionItem{} query := "SELECT permission_id, grant_type FROM admin_user_permission_rel WHERE admin_id = ? ORDER BY permission_id ASC" if err := db.Select(&list, query, adminID); err != nil { return nil, err } return list, nil } func SetUserPermissions(adminID int, permissions []UserPermissionItem, operator string) error { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return fmt.Errorf("failed to get database connection") } tx, err := db.Begin() if err != nil { return err } defer tx.Rollback() if _, err = tx.Exec("DELETE FROM admin_user_permission_rel WHERE admin_id = ?", adminID); err != nil { return err } now := int(util.Now()) for _, p := range permissions { if _, err = tx.Exec("INSERT INTO admin_user_permission_rel (admin_id, permission_id, grant_type, create_admin, createTime) VALUES (?, ?, ?, ?, ?)", adminID, p.PermissionID, p.GrantType, operator, now); err != nil { return err } } return tx.Commit() } // ListUserRoles 返回用户通过用户组继承的所有角色(去重) func ListUserRoles(adminID int) ([]PermissionRole, error) { db := util.MPool.GetGameDB() defer db.Close() if db == nil { return nil, fmt.Errorf("failed to get database connection") } list := []PermissionRole{} query := `SELECT DISTINCT r.id, r.role_code, r.role_name, r.status, r.is_system, r.remark, r.createTime, r.updateTime FROM admin_role r INNER JOIN admin_group_role_rel grr ON grr.role_id = r.id INNER JOIN admin_user_group_rel ugr ON ugr.group_id = grr.group_id WHERE ugr.admin_id = ? ORDER BY r.id DESC` if err := db.Select(&list, query, adminID); err != nil { return nil, err } return list, nil } func ListUserRolesByAdminIDs(adminIDs []int) (map[int][]PermissionRole, error) { result := make(map[int][]PermissionRole, len(adminIDs)) if len(adminIDs) == 0 { return result, nil } db := util.MPool.GetGameDB() defer db.Close() if db == nil { return nil, fmt.Errorf("failed to get database connection") } placeholders := strings.TrimRight(strings.Repeat("?,", len(adminIDs)), ",") args := make([]interface{}, 0, len(adminIDs)) for _, adminID := range adminIDs { args = append(args, adminID) result[adminID] = []PermissionRole{} } type userRoleRow struct { AdminID int `db:"admin_id"` PermissionRole } rows := []userRoleRow{} query := `SELECT DISTINCT ugr.admin_id, r.id, r.role_code, r.role_name, r.status, r.is_system, r.remark, r.createTime, r.updateTime FROM admin_role r INNER JOIN admin_group_role_rel grr ON grr.role_id = r.id INNER JOIN admin_user_group_rel ugr ON ugr.group_id = grr.group_id WHERE ugr.admin_id IN (` + placeholders + `) ORDER BY ugr.admin_id ASC, r.id DESC` if err := db.Select(&rows, query, args...); err != nil { return nil, err } for _, row := range rows { result[row.AdminID] = append(result[row.AdminID], row.PermissionRole) } return result, nil } // UserEffectiveInfo 用户登录后的有效权限摘要 type UserEffectiveInfo struct { // Roles 用户通过用户组继承的角色 code 列表 Roles []string `json:"roles"` // Permissions 用户最终有效的权限 code 列表: // 角色链路授予 + 直接允许(grant_type=1),再减去直接拒绝(grant_type=2) Permissions []string `json:"permissions"` } // GetUserEffectiveInfo 一次查询返回用户的有效角色和权限列表。 // adminID 为 admin 表的 id,isSuperAdmin 时直接返回空列表(表示不受控)。 func GetUserEffectiveInfo(adminID int, isSuperAdmin bool) (*UserEffectiveInfo, error) { if isSuperAdmin { return &UserEffectiveInfo{Roles: []string{}, Permissions: []string{}}, nil } db := util.MPool.GetGameDB() if db == nil { return nil, fmt.Errorf("failed to get database connection") } defer db.Close() // 1. 角色 code 列表(用户组 → 角色) var roleCodes []string roleQuery := `SELECT DISTINCT r.role_code FROM admin_role r INNER JOIN admin_group_role_rel grr ON grr.role_id = r.id INNER JOIN admin_user_group_rel ugr ON ugr.group_id = grr.group_id WHERE ugr.admin_id = ? AND r.status = 1` if err := db.Select(&roleCodes, roleQuery, adminID); err != nil { return nil, err } if roleCodes == nil { roleCodes = []string{} } // 2. 通过角色链路获得的权限 code 集合 permSet := map[string]struct{}{} if len(roleCodes) > 0 { ph := strings.Repeat("?,", len(roleCodes)) ph = ph[:len(ph)-1] args := make([]interface{}, len(roleCodes)) for i, c := range roleCodes { args[i] = c } var rolePerm []string q := fmt.Sprintf(`SELECT DISTINCT p.permission_code FROM admin_permission p INNER JOIN admin_role_permission_rel rpr ON rpr.permission_id = p.id INNER JOIN admin_role r ON r.id = rpr.role_id WHERE r.role_code IN (%s) AND p.status = 1`, ph) if err := db.Select(&rolePerm, q, args...); err != nil { return nil, err } for _, code := range rolePerm { permSet[code] = struct{}{} } } // 3. 直接单点权限:允许补入,拒绝剔除 var directPerms []struct { Code string `db:"permission_code"` GrantType int `db:"grant_type"` } directQuery := `SELECT p.permission_code, rel.grant_type FROM admin_permission p INNER JOIN admin_user_permission_rel rel ON rel.permission_id = p.id WHERE rel.admin_id = ? AND p.status = 1` if err := db.Select(&directPerms, directQuery, adminID); err != nil { return nil, err } for _, dp := range directPerms { if dp.GrantType == 1 { permSet[dp.Code] = struct{}{} } else if dp.GrantType == 2 { delete(permSet, dp.Code) } } perms := make([]string, 0, len(permSet)) for code := range permSet { perms = append(perms, code) } return &UserEffectiveInfo{ Roles: roleCodes, Permissions: perms, }, nil }