yunzer_go/server/models/role.go
2025-11-06 15:56:29 +08:00

338 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}