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"` 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 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, 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.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, 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 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, 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, 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 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, 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, 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() var role Role err := o.QueryTable("yz_roles").Filter("role_code", roleCode).Filter("delete_time__isnull", true).One(&role) 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 != "[]" { role.MenuIdsJson = sql.NullString{String: menuIdsStr, Valid: true} } role.AfterRead() return &role, nil } // CreateRole 创建角色 func CreateRole(role *Role) error { o := orm.NewOrm() role.BeforeInsert() // 使用Raw插入以正确处理JSON字段,并获取插入后的ID res, err := o.Raw("INSERT INTO yz_roles (tenant_id, 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, 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字段 _, err := o.Raw("UPDATE yz_roles SET tenant_id = ?, 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, 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 }