402 lines
13 KiB
Go
402 lines
13 KiB
Go
package models
|
||
|
||
import (
|
||
"database/sql"
|
||
"encoding/json"
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/beego/beego/v2/client/orm"
|
||
)
|
||
|
||
// Role 角色模型
|
||
type Role struct {
|
||
RoleId int `orm:"pk;auto;column(role_id)" json:"roleId"`
|
||
TenantId int `orm:"column(tenant_id)" json:"tenantId"`
|
||
Default int8 `orm:"column(default);default(2)" json:"default"` // 角色默认分配:1-只给租户1,2-所有租户可用,3-租户专属
|
||
RoleCode string `orm:"size(50);unique" json:"roleCode"`
|
||
RoleName string `orm:"size(100)" json:"roleName"`
|
||
Description string `orm:"type(text);null" json:"description"`
|
||
MenuIds []int `orm:"-" json:"menuIds"` // 前端使用的菜单ID数组(不存储在数据库)
|
||
MenuIdsJson sql.NullString `orm:"column(menu_ids);type(json);null" json:"-"` // 数据库存储的JSON字段
|
||
Status int8 `orm:"default(1)" json:"status"` // 1:启用 0:禁用
|
||
SortOrder int `orm:"default(0)" json:"sortOrder"` // 排序
|
||
CreateTime time.Time `orm:"auto_now_add;type(datetime)" json:"createTime"`
|
||
UpdateTime time.Time `orm:"auto_now;type(datetime)" json:"updateTime"`
|
||
DeleteTime *time.Time `orm:"null;type(datetime)" json:"deleteTime"`
|
||
CreateBy string `orm:"size(50);null" json:"createBy"`
|
||
UpdateBy string `orm:"size(50);null" json:"updateBy"`
|
||
}
|
||
|
||
// AfterRead 读取数据后解析JSON字段
|
||
func (r *Role) AfterRead() {
|
||
// 调试输出
|
||
fmt.Printf("AfterRead: MenuIdsJson.Valid=%v, MenuIdsJson.String=%s\n", r.MenuIdsJson.Valid, r.MenuIdsJson.String)
|
||
|
||
if r.MenuIdsJson.Valid && r.MenuIdsJson.String != "" && r.MenuIdsJson.String != "[]" {
|
||
// 清理可能的空白字符
|
||
jsonStr := strings.TrimSpace(r.MenuIdsJson.String)
|
||
jsonStr = strings.ReplaceAll(jsonStr, "\n", "")
|
||
jsonStr = strings.ReplaceAll(jsonStr, "\r", "")
|
||
|
||
err := json.Unmarshal([]byte(jsonStr), &r.MenuIds)
|
||
if err != nil {
|
||
// 如果解析失败,记录错误但使用空数组
|
||
fmt.Printf("AfterRead: JSON解析失败: %v, 原始值: %s\n", err, jsonStr)
|
||
r.MenuIds = []int{}
|
||
} else {
|
||
fmt.Printf("AfterRead: 成功解析 %d 个菜单ID\n", len(r.MenuIds))
|
||
}
|
||
} else {
|
||
fmt.Printf("AfterRead: MenuIdsJson 无效或为空\n")
|
||
r.MenuIds = []int{}
|
||
}
|
||
}
|
||
|
||
// BeforeInsert 插入前序列化JSON字段
|
||
func (r *Role) BeforeInsert() {
|
||
if len(r.MenuIds) > 0 {
|
||
jsonData, _ := json.Marshal(r.MenuIds)
|
||
r.MenuIdsJson = sql.NullString{String: string(jsonData), Valid: true}
|
||
} else {
|
||
r.MenuIdsJson = sql.NullString{String: "[]", Valid: true}
|
||
}
|
||
}
|
||
|
||
// BeforeUpdate 更新前序列化JSON字段
|
||
func (r *Role) BeforeUpdate() {
|
||
if len(r.MenuIds) > 0 {
|
||
jsonData, _ := json.Marshal(r.MenuIds)
|
||
r.MenuIdsJson = sql.NullString{String: string(jsonData), Valid: true}
|
||
} else {
|
||
r.MenuIdsJson = sql.NullString{String: "[]", Valid: true}
|
||
}
|
||
}
|
||
|
||
func (r *Role) TableName() string {
|
||
return "yz_roles"
|
||
}
|
||
|
||
func init() {
|
||
orm.RegisterModel(new(Role))
|
||
}
|
||
|
||
// GetRoleById 根据ID获取角色
|
||
func GetRoleById(roleId int) (*Role, error) {
|
||
o := orm.NewOrm()
|
||
|
||
// 使用Raw查询以正确读取JSON字段
|
||
// 定义一个临时结构体来接收查询结果
|
||
type roleResult struct {
|
||
RoleId int
|
||
TenantId int
|
||
Default int8
|
||
RoleCode string
|
||
RoleName string
|
||
Description string
|
||
MenuIdsJson sql.NullString
|
||
Status int8
|
||
SortOrder int
|
||
CreateTime time.Time
|
||
UpdateTime time.Time
|
||
DeleteTime *time.Time
|
||
CreateBy string
|
||
UpdateBy string
|
||
}
|
||
|
||
var result roleResult
|
||
// 先读取其他字段(不包括 menu_ids),因为 Beego ORM 可能无法直接读取 JSON 类型
|
||
err := o.Raw("SELECT role_id, tenant_id, `default`, role_code, role_name, description, status, sort_order, create_time, update_time, delete_time, create_by, update_by FROM yz_roles WHERE role_id = ? AND delete_time IS NULL", roleId).QueryRow(
|
||
&result.RoleId, &result.TenantId, &result.Default, &result.RoleCode, &result.RoleName, &result.Description,
|
||
&result.Status, &result.SortOrder, &result.CreateTime, &result.UpdateTime,
|
||
&result.DeleteTime, &result.CreateBy, &result.UpdateBy,
|
||
)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 单独读取 menu_ids JSON 字段,使用 JSON_UNQUOTE 确保正确读取
|
||
var menuIdsStr string
|
||
err2 := o.Raw("SELECT IFNULL(JSON_UNQUOTE(JSON_EXTRACT(menu_ids, '$')), '[]') FROM yz_roles WHERE role_id = ? AND delete_time IS NULL", roleId).QueryRow(&menuIdsStr)
|
||
if err2 != nil {
|
||
fmt.Printf("GetRoleById: JSON_UNQUOTE 读取失败: %v,尝试 CAST\n", err2)
|
||
// 如果 JSON_UNQUOTE 失败,尝试直接 CAST
|
||
err3 := o.Raw("SELECT CAST(IFNULL(menu_ids, '[]') AS CHAR) FROM yz_roles WHERE role_id = ? AND delete_time IS NULL", roleId).QueryRow(&menuIdsStr)
|
||
if err3 != nil {
|
||
fmt.Printf("GetRoleById: CAST 也失败: %v,使用空数组\n", err3)
|
||
menuIdsStr = "[]"
|
||
}
|
||
}
|
||
|
||
// 设置 MenuIdsJson
|
||
if menuIdsStr != "" && menuIdsStr != "[]" && menuIdsStr != "null" {
|
||
result.MenuIdsJson = sql.NullString{String: menuIdsStr, Valid: true}
|
||
// 只打印前100个字符,避免日志过长
|
||
preview := menuIdsStr
|
||
if len(preview) > 100 {
|
||
preview = preview[:100] + "..."
|
||
}
|
||
fmt.Printf("GetRoleById: 角色 %d 的 menu_ids 读取成功: %s (总长度: %d)\n", roleId, preview, len(menuIdsStr))
|
||
} else {
|
||
result.MenuIdsJson = sql.NullString{String: "[]", Valid: true}
|
||
fmt.Printf("GetRoleById: 角色 %d 的 menu_ids 为空,使用空数组\n", roleId)
|
||
}
|
||
|
||
// 检查是否已删除(虽然SQL已经过滤了,但为了安全还是检查一下)
|
||
if result.DeleteTime != nil {
|
||
return nil, orm.ErrNoRows
|
||
}
|
||
|
||
// 构建Role对象
|
||
role := &Role{
|
||
RoleId: result.RoleId,
|
||
TenantId: result.TenantId,
|
||
Default: result.Default,
|
||
RoleCode: result.RoleCode,
|
||
RoleName: result.RoleName,
|
||
Description: result.Description,
|
||
MenuIdsJson: result.MenuIdsJson,
|
||
Status: result.Status,
|
||
SortOrder: result.SortOrder,
|
||
CreateTime: result.CreateTime,
|
||
UpdateTime: result.UpdateTime,
|
||
DeleteTime: result.DeleteTime,
|
||
CreateBy: result.CreateBy,
|
||
UpdateBy: result.UpdateBy,
|
||
}
|
||
|
||
// 解析JSON字段
|
||
role.AfterRead()
|
||
|
||
return role, nil
|
||
}
|
||
|
||
// GetAllRoles 获取所有角色(未删除的)
|
||
func GetAllRoles() ([]*Role, error) {
|
||
o := orm.NewOrm()
|
||
var roles []*Role
|
||
|
||
// 使用Raw查询以正确读取JSON字段
|
||
var results []struct {
|
||
RoleId int
|
||
TenantId int
|
||
Default int8
|
||
RoleCode string
|
||
RoleName string
|
||
Description string
|
||
MenuIdsJson sql.NullString
|
||
Status int8
|
||
SortOrder int
|
||
CreateTime time.Time
|
||
UpdateTime time.Time
|
||
DeleteTime *time.Time
|
||
CreateBy string
|
||
UpdateBy string
|
||
}
|
||
|
||
_, err := o.Raw("SELECT role_id, tenant_id, `default`, role_code, role_name, description, CAST(IFNULL(menu_ids, '[]') AS CHAR) as menu_ids, status, sort_order, create_time, update_time, delete_time, create_by, update_by FROM yz_roles WHERE delete_time IS NULL ORDER BY sort_order ASC, role_id ASC").QueryRows(&results)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
for _, r := range results {
|
||
role := &Role{
|
||
RoleId: r.RoleId,
|
||
TenantId: r.TenantId,
|
||
Default: r.Default,
|
||
RoleCode: r.RoleCode,
|
||
RoleName: r.RoleName,
|
||
Description: r.Description,
|
||
MenuIdsJson: r.MenuIdsJson,
|
||
Status: r.Status,
|
||
SortOrder: r.SortOrder,
|
||
CreateTime: r.CreateTime,
|
||
UpdateTime: r.UpdateTime,
|
||
DeleteTime: r.DeleteTime,
|
||
CreateBy: r.CreateBy,
|
||
UpdateBy: r.UpdateBy,
|
||
}
|
||
role.AfterRead()
|
||
roles = append(roles, role)
|
||
}
|
||
|
||
return roles, nil
|
||
}
|
||
|
||
// GetRoleByTenantId 根据租户ID获取角色列表(未删除的)
|
||
func GetRoleByTenantId(tenantId int) ([]*Role, error) {
|
||
o := orm.NewOrm()
|
||
var roles []*Role
|
||
|
||
// 使用Raw查询以正确读取JSON字段
|
||
var results []struct {
|
||
RoleId int
|
||
TenantId int
|
||
Default int8
|
||
RoleCode string
|
||
RoleName string
|
||
Description string
|
||
MenuIdsJson sql.NullString
|
||
Status int8
|
||
SortOrder int
|
||
CreateTime time.Time
|
||
UpdateTime time.Time
|
||
DeleteTime *time.Time
|
||
CreateBy string
|
||
UpdateBy string
|
||
}
|
||
|
||
_, err := o.Raw("SELECT role_id, tenant_id, `default`, role_code, role_name, description, CAST(IFNULL(menu_ids, '[]') AS CHAR) as menu_ids, status, sort_order, create_time, update_time, delete_time, create_by, update_by FROM yz_roles WHERE (tenant_id = ? OR tenant_id = 0) AND delete_time IS NULL ORDER BY sort_order ASC, role_id ASC", tenantId).QueryRows(&results)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
for _, r := range results {
|
||
role := &Role{
|
||
RoleId: r.RoleId,
|
||
TenantId: r.TenantId,
|
||
Default: r.Default,
|
||
RoleCode: r.RoleCode,
|
||
RoleName: r.RoleName,
|
||
Description: r.Description,
|
||
MenuIdsJson: r.MenuIdsJson,
|
||
Status: r.Status,
|
||
SortOrder: r.SortOrder,
|
||
CreateTime: r.CreateTime,
|
||
UpdateTime: r.UpdateTime,
|
||
DeleteTime: r.DeleteTime,
|
||
CreateBy: r.CreateBy,
|
||
UpdateBy: r.UpdateBy,
|
||
}
|
||
role.AfterRead()
|
||
roles = append(roles, role)
|
||
}
|
||
|
||
return roles, nil
|
||
}
|
||
|
||
// GetRoleByCode 根据角色代码获取角色
|
||
func GetRoleByCode(roleCode string) (*Role, error) {
|
||
o := orm.NewOrm()
|
||
|
||
// 使用Raw查询以正确读取所有字段,包括 default 和 menu_ids
|
||
type roleResult struct {
|
||
RoleId int
|
||
TenantId int
|
||
Default int8
|
||
RoleCode string
|
||
RoleName string
|
||
Description string
|
||
MenuIdsJson sql.NullString
|
||
Status int8
|
||
SortOrder int
|
||
CreateTime time.Time
|
||
UpdateTime time.Time
|
||
DeleteTime *time.Time
|
||
CreateBy string
|
||
UpdateBy string
|
||
}
|
||
|
||
var result roleResult
|
||
err := o.Raw("SELECT role_id, tenant_id, `default`, role_code, role_name, description, status, sort_order, create_time, update_time, delete_time, create_by, update_by FROM yz_roles WHERE role_code = ? AND delete_time IS NULL", roleCode).QueryRow(
|
||
&result.RoleId, &result.TenantId, &result.Default, &result.RoleCode, &result.RoleName, &result.Description,
|
||
&result.Status, &result.SortOrder, &result.CreateTime, &result.UpdateTime,
|
||
&result.DeleteTime, &result.CreateBy, &result.UpdateBy,
|
||
)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 手动读取 menu_ids JSON 字段
|
||
var menuIdsStr string
|
||
err2 := o.Raw("SELECT IFNULL(JSON_UNQUOTE(JSON_EXTRACT(menu_ids, '$')), '[]') FROM yz_roles WHERE role_code = ? AND delete_time IS NULL", roleCode).QueryRow(&menuIdsStr)
|
||
if err2 == nil && menuIdsStr != "" && menuIdsStr != "[]" {
|
||
result.MenuIdsJson = sql.NullString{String: menuIdsStr, Valid: true}
|
||
}
|
||
|
||
role := &Role{
|
||
RoleId: result.RoleId,
|
||
TenantId: result.TenantId,
|
||
Default: result.Default,
|
||
RoleCode: result.RoleCode,
|
||
RoleName: result.RoleName,
|
||
Description: result.Description,
|
||
MenuIdsJson: result.MenuIdsJson,
|
||
Status: result.Status,
|
||
SortOrder: result.SortOrder,
|
||
CreateTime: result.CreateTime,
|
||
UpdateTime: result.UpdateTime,
|
||
DeleteTime: result.DeleteTime,
|
||
CreateBy: result.CreateBy,
|
||
UpdateBy: result.UpdateBy,
|
||
}
|
||
|
||
role.AfterRead()
|
||
return role, nil
|
||
}
|
||
|
||
// CreateRole 创建角色
|
||
func CreateRole(role *Role) error {
|
||
o := orm.NewOrm()
|
||
role.BeforeInsert()
|
||
|
||
// 使用Raw插入以正确处理JSON字段,并获取插入后的ID
|
||
// 如果没有设置 default 值,根据 tenant_id 自动设置:tenant_id=0 时 default=2,否则 default=3
|
||
defaultValue := role.Default
|
||
if defaultValue == 0 {
|
||
if role.TenantId == 0 {
|
||
defaultValue = 2 // 所有租户可用
|
||
} else {
|
||
defaultValue = 3 // 租户专属
|
||
}
|
||
}
|
||
res, err := o.Raw("INSERT INTO yz_roles (tenant_id, `default`, role_code, role_name, description, menu_ids, status, sort_order, create_time, update_time, create_by, update_by) VALUES (?, ?, ?, ?, ?, CAST(? AS JSON), ?, ?, NOW(), NOW(), ?, ?)",
|
||
role.TenantId, defaultValue, role.RoleCode, role.RoleName, role.Description, role.MenuIdsJson.String, role.Status, role.SortOrder, role.CreateBy, role.UpdateBy).Exec()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 获取插入后的ID
|
||
lastInsertId, err := res.LastInsertId()
|
||
if err != nil {
|
||
// 如果无法获取 LastInsertId,尝试通过角色代码查询
|
||
createdRole, queryErr := GetRoleByCode(role.RoleCode)
|
||
if queryErr == nil && createdRole != nil {
|
||
role.RoleId = createdRole.RoleId
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 设置插入后的ID
|
||
role.RoleId = int(lastInsertId)
|
||
return nil
|
||
}
|
||
|
||
// UpdateRole 更新角色
|
||
func UpdateRole(role *Role) error {
|
||
o := orm.NewOrm()
|
||
role.BeforeUpdate()
|
||
|
||
// 使用Raw更新以正确处理JSON字段
|
||
// 如果没有设置 default 值,根据 tenant_id 自动设置:tenant_id=0 时 default=2,否则 default=3
|
||
defaultValue := role.Default
|
||
if defaultValue == 0 {
|
||
if role.TenantId == 0 {
|
||
defaultValue = 2 // 所有租户可用
|
||
} else {
|
||
defaultValue = 3 // 租户专属
|
||
}
|
||
}
|
||
_, err := o.Raw("UPDATE yz_roles SET tenant_id = ?, `default` = ?, role_code = ?, role_name = ?, description = ?, menu_ids = CAST(? AS JSON), status = ?, sort_order = ?, update_time = NOW(), update_by = ? WHERE role_id = ? AND delete_time IS NULL",
|
||
role.TenantId, defaultValue, role.RoleCode, role.RoleName, role.Description, role.MenuIdsJson.String, role.Status, role.SortOrder, role.UpdateBy, role.RoleId).Exec()
|
||
return err
|
||
}
|
||
|
||
// DeleteRole 软删除角色
|
||
func DeleteRole(roleId int, updateBy string) error {
|
||
o := orm.NewOrm()
|
||
_, err := o.Raw("UPDATE yz_roles SET delete_time = NOW(), update_by = ? WHERE role_id = ? AND delete_time IS NULL", updateBy, roleId).Exec()
|
||
return err
|
||
}
|