395 lines
10 KiB
Go
395 lines
10 KiB
Go
package services
|
||
|
||
import (
|
||
"fmt"
|
||
"regexp"
|
||
"server/models"
|
||
"time"
|
||
|
||
"github.com/beego/beego/v2/client/orm"
|
||
)
|
||
|
||
// ========== 字典类型相关服务 ==========
|
||
|
||
// AddDictType 添加字典类型
|
||
func AddDictType(dictType *models.DictType) (int64, error) {
|
||
// 校验字典编码格式(只能包含字母、数字、下划线)
|
||
matched, err := regexp.MatchString(`^[A-Za-z0-9_]+$`, dictType.DictCode)
|
||
if err != nil || !matched {
|
||
return 0, fmt.Errorf("字典编码格式错误,只能包含字母、数字、下划线")
|
||
}
|
||
|
||
o := orm.NewOrm()
|
||
|
||
// 检查字典编码是否已存在(同一租户下唯一)
|
||
existType := &models.DictType{}
|
||
err = o.Raw("SELECT id FROM sys_dict_type WHERE dict_code = ? AND tenant_id = ? AND is_deleted = 0",
|
||
dictType.DictCode, dictType.TenantId).QueryRow(existType)
|
||
if err == nil {
|
||
return 0, fmt.Errorf("字典编码 %s 已存在", dictType.DictCode)
|
||
}
|
||
|
||
// 插入新字典类型
|
||
id, err := o.Insert(dictType)
|
||
if err != nil {
|
||
return 0, fmt.Errorf("添加字典类型失败: %v", err)
|
||
}
|
||
|
||
// 清除相关缓存
|
||
clearDictCache(dictType.TenantId, dictType.DictCode)
|
||
|
||
return id, nil
|
||
}
|
||
|
||
// UpdateDictType 更新字典类型
|
||
func UpdateDictType(dictType *models.DictType) error {
|
||
o := orm.NewOrm()
|
||
|
||
// 获取原字典类型信息
|
||
oldType := &models.DictType{Id: dictType.Id}
|
||
err := o.Read(oldType)
|
||
if err != nil {
|
||
return fmt.Errorf("字典类型不存在: %v", err)
|
||
}
|
||
|
||
// 不允许修改 dict_code(避免业务引用失效)
|
||
if oldType.DictCode != dictType.DictCode {
|
||
return fmt.Errorf("不允许修改字典编码")
|
||
}
|
||
|
||
// 更新字段(排除 dict_code)
|
||
_, err = o.Update(dictType, "dict_name", "parent_id", "status", "is_global", "sort", "remark", "update_by", "update_time")
|
||
if err != nil {
|
||
return fmt.Errorf("更新字典类型失败: %v", err)
|
||
}
|
||
|
||
// 清除相关缓存
|
||
clearDictCache(dictType.TenantId, dictType.DictCode)
|
||
|
||
return nil
|
||
}
|
||
|
||
// DeleteDictType 删除字典类型(逻辑删除)
|
||
func DeleteDictType(id int, tenantId int) error {
|
||
o := orm.NewOrm()
|
||
|
||
// 检查是否存在
|
||
dictType := &models.DictType{Id: id}
|
||
err := o.Read(dictType)
|
||
if err != nil {
|
||
return fmt.Errorf("字典类型不存在: %v", err)
|
||
}
|
||
|
||
// 检查租户权限
|
||
if dictType.TenantId != tenantId {
|
||
return fmt.Errorf("无权操作该字典类型")
|
||
}
|
||
|
||
// 检查是否关联字典项
|
||
var count int
|
||
err = o.Raw("SELECT COUNT(*) FROM sys_dict_item WHERE dict_type_id = ? AND is_deleted = 0", id).QueryRow(&count)
|
||
if err == nil && count > 0 {
|
||
return fmt.Errorf("该字典类型下存在字典项,请先删除字典项")
|
||
}
|
||
|
||
// 逻辑删除
|
||
dictType.IsDeleted = 1
|
||
dictType.UpdateTime = time.Now()
|
||
_, err = o.Update(dictType, "is_deleted", "update_time")
|
||
if err != nil {
|
||
return fmt.Errorf("删除字典类型失败: %v", err)
|
||
}
|
||
|
||
// 清除相关缓存
|
||
clearDictCache(dictType.TenantId, dictType.DictCode)
|
||
|
||
return nil
|
||
}
|
||
|
||
// GetDictTypeById 根据ID获取字典类型
|
||
func GetDictTypeById(id int) (*models.DictType, error) {
|
||
o := orm.NewOrm()
|
||
dictType := &models.DictType{Id: id}
|
||
err := o.Read(dictType)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if dictType.IsDeleted == 1 {
|
||
return nil, fmt.Errorf("字典类型已删除")
|
||
}
|
||
return dictType, nil
|
||
}
|
||
|
||
// GetDictTypes 获取字典类型列表
|
||
func GetDictTypes(tenantId int, userId int, parentId int, status *int8, pageNum int, pageSize int) ([]*models.DictType, int64, error) {
|
||
o := orm.NewOrm()
|
||
qs := o.QueryTable("sys_dict_type").Filter("is_deleted", 0)
|
||
|
||
// 租户过滤:0表示平台字典,>0表示租户字典
|
||
if tenantId > 0 {
|
||
// 租户用户需要根据角色判断是否可以看到私有字典
|
||
roleCode, err := GetUserRoleCode(userId)
|
||
if err != nil || (roleCode != "system_admin" && roleCode != "admin") {
|
||
// 非admin用户只能看到全局字典和自己租户的全局字典
|
||
qs = qs.Filter("is_global", 1)
|
||
} else {
|
||
// admin用户可以看到自己租户的所有字典和全局字典
|
||
qs = qs.Filter("tenant_id__in", 0, tenantId)
|
||
}
|
||
} else {
|
||
// 平台用户只能看到平台字典
|
||
qs = qs.Filter("tenant_id", 0)
|
||
}
|
||
|
||
// 父级过滤
|
||
if parentId >= 0 {
|
||
qs = qs.Filter("parent_id", parentId)
|
||
}
|
||
|
||
// 状态过滤
|
||
if status != nil {
|
||
qs = qs.Filter("status", *status)
|
||
}
|
||
|
||
// 获取总数
|
||
total, err := qs.Count()
|
||
if err != nil {
|
||
return nil, 0, err
|
||
}
|
||
|
||
// 分页处理
|
||
if pageNum <= 0 {
|
||
pageNum = 1
|
||
}
|
||
if pageSize <= 0 {
|
||
pageSize = 20
|
||
}
|
||
offset := (pageNum - 1) * pageSize
|
||
|
||
var dictTypes []*models.DictType
|
||
_, err = qs.OrderBy("-id", "sort").Offset(offset).Limit(pageSize).All(&dictTypes)
|
||
return dictTypes, total, err
|
||
}
|
||
|
||
// ========== 字典项相关服务 ==========
|
||
|
||
// AddDictItem 添加字典项
|
||
func AddDictItem(dictItem *models.DictItem) (int64, error) {
|
||
o := orm.NewOrm()
|
||
|
||
// 检查字典类型是否存在
|
||
dictType := &models.DictType{Id: dictItem.DictTypeId}
|
||
err := o.Read(dictType)
|
||
if err != nil {
|
||
return 0, fmt.Errorf("字典类型不存在: %v", err)
|
||
}
|
||
if dictType.IsDeleted == 1 || dictType.Status == 0 {
|
||
return 0, fmt.Errorf("字典类型已删除或已禁用")
|
||
}
|
||
|
||
// 检查同一字典类型下 dict_value 是否已存在
|
||
existItem := &models.DictItem{}
|
||
err = o.Raw("SELECT id FROM sys_dict_item WHERE dict_type_id = ? AND dict_value = ? AND is_deleted = 0",
|
||
dictItem.DictTypeId, dictItem.DictValue).QueryRow(existItem)
|
||
if err == nil {
|
||
return 0, fmt.Errorf("字典值 %s 已存在", dictItem.DictValue)
|
||
}
|
||
|
||
// 插入新字典项
|
||
id, err := o.Insert(dictItem)
|
||
if err != nil {
|
||
return 0, fmt.Errorf("添加字典项失败: %v", err)
|
||
}
|
||
|
||
// 清除相关缓存
|
||
clearDictCacheByTypeId(dictItem.DictTypeId)
|
||
|
||
return id, nil
|
||
}
|
||
|
||
// UpdateDictItem 更新字典项
|
||
func UpdateDictItem(dictItem *models.DictItem) error {
|
||
o := orm.NewOrm()
|
||
|
||
// 获取原字典项信息
|
||
oldItem := &models.DictItem{Id: dictItem.Id}
|
||
err := o.Read(oldItem)
|
||
if err != nil {
|
||
return fmt.Errorf("字典项不存在: %v", err)
|
||
}
|
||
|
||
// 不允许修改 dict_value(避免业务存储值与字典不匹配)
|
||
if oldItem.DictValue != dictItem.DictValue {
|
||
return fmt.Errorf("不允许修改字典值")
|
||
}
|
||
|
||
// 如果修改了 dict_type_id,需要检查新类型是否存在
|
||
if oldItem.DictTypeId != dictItem.DictTypeId {
|
||
dictType := &models.DictType{Id: dictItem.DictTypeId}
|
||
err = o.Read(dictType)
|
||
if err != nil {
|
||
return fmt.Errorf("字典类型不存在: %v", err)
|
||
}
|
||
}
|
||
|
||
// 更新字段(排除 dict_value)
|
||
_, err = o.Update(dictItem, "dict_label", "dict_type_id", "parent_id", "status", "sort", "color", "icon", "remark", "update_by", "update_time")
|
||
if err != nil {
|
||
return fmt.Errorf("更新字典项失败: %v", err)
|
||
}
|
||
|
||
// 清除相关缓存
|
||
clearDictCacheByTypeId(oldItem.DictTypeId)
|
||
if oldItem.DictTypeId != dictItem.DictTypeId {
|
||
clearDictCacheByTypeId(dictItem.DictTypeId)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// DeleteDictItem 删除字典项(逻辑删除)
|
||
func DeleteDictItem(id int) error {
|
||
o := orm.NewOrm()
|
||
|
||
// 检查是否存在
|
||
dictItem := &models.DictItem{Id: id}
|
||
err := o.Read(dictItem)
|
||
if err != nil {
|
||
return fmt.Errorf("字典项不存在: %v", err)
|
||
}
|
||
|
||
// 检查是否有子项
|
||
var count int
|
||
err = o.Raw("SELECT COUNT(*) FROM sys_dict_item WHERE parent_id = ? AND is_deleted = 0", id).QueryRow(&count)
|
||
if err == nil && count > 0 {
|
||
return fmt.Errorf("该字典项下存在子项,请先删除子项")
|
||
}
|
||
|
||
// 逻辑删除
|
||
dictItem.IsDeleted = 1
|
||
dictItem.UpdateTime = time.Now()
|
||
_, err = o.Update(dictItem, "is_deleted", "update_time")
|
||
if err != nil {
|
||
return fmt.Errorf("删除字典项失败: %v", err)
|
||
}
|
||
|
||
// 清除相关缓存
|
||
clearDictCacheByTypeId(dictItem.DictTypeId)
|
||
|
||
return nil
|
||
}
|
||
|
||
// GetDictItemById 根据ID获取字典项
|
||
func GetDictItemById(id int) (*models.DictItem, error) {
|
||
o := orm.NewOrm()
|
||
dictItem := &models.DictItem{Id: id}
|
||
err := o.Read(dictItem)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if dictItem.IsDeleted == 1 {
|
||
return nil, fmt.Errorf("字典项已删除")
|
||
}
|
||
return dictItem, nil
|
||
}
|
||
|
||
// GetDictItems 获取字典项列表
|
||
func GetDictItems(dictTypeId int, parentId *int, status *int8) ([]*models.DictItem, error) {
|
||
o := orm.NewOrm()
|
||
qs := o.QueryTable("sys_dict_item").Filter("is_deleted", 0).Filter("dict_type_id", dictTypeId)
|
||
|
||
// 父级过滤
|
||
if parentId != nil {
|
||
qs = qs.Filter("parent_id", *parentId)
|
||
}
|
||
|
||
// 状态过滤
|
||
if status != nil {
|
||
qs = qs.Filter("status", *status)
|
||
}
|
||
|
||
var dictItems []*models.DictItem
|
||
_, err := qs.OrderBy("sort", "create_time").All(&dictItems)
|
||
return dictItems, err
|
||
}
|
||
|
||
// GetDictItemsByCode 根据字典编码获取字典项列表(支持缓存)
|
||
func GetDictItemsByCode(dictCode string, tenantId int, includeDisabled bool) ([]*models.DictItem, error) {
|
||
o := orm.NewOrm()
|
||
|
||
// 先查询字典类型
|
||
dictType := &models.DictType{}
|
||
err := o.Raw("SELECT * FROM sys_dict_type WHERE dict_code = ? AND tenant_id = ? AND is_deleted = 0 AND status = 1",
|
||
dictCode, tenantId).QueryRow(dictType)
|
||
if err != nil {
|
||
// 如果租户字典不存在,尝试查询平台字典
|
||
if tenantId > 0 {
|
||
err = o.Raw("SELECT * FROM sys_dict_type WHERE dict_code = ? AND tenant_id = 0 AND is_deleted = 0 AND status = 1",
|
||
dictCode).QueryRow(dictType)
|
||
if err != nil {
|
||
return []*models.DictItem{}, nil // 返回空列表而不是错误
|
||
}
|
||
} else {
|
||
return []*models.DictItem{}, nil
|
||
}
|
||
}
|
||
|
||
// 查询字典项
|
||
qs := o.QueryTable("sys_dict_item").Filter("dict_type_id", dictType.Id).Filter("is_deleted", 0)
|
||
if !includeDisabled {
|
||
qs = qs.Filter("status", 1)
|
||
}
|
||
|
||
var dictItems []*models.DictItem
|
||
_, err = qs.OrderBy("sort", "create_time").All(&dictItems)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return dictItems, nil
|
||
}
|
||
|
||
// ========== 缓存相关(简化版,实际应使用Redis) ==========
|
||
|
||
// 清除字典缓存(简化实现,实际应使用Redis)
|
||
func clearDictCache(tenantId int, dictCode string) {
|
||
// TODO: 实现Redis缓存清除
|
||
// 格式:SYS_DICT:ITEM:{tenantId}:{dictCode}
|
||
}
|
||
|
||
// 根据字典类型ID清除缓存
|
||
func clearDictCacheByTypeId(dictTypeId int) {
|
||
o := orm.NewOrm()
|
||
dictType := &models.DictType{Id: dictTypeId}
|
||
err := o.Read(dictType)
|
||
if err == nil {
|
||
clearDictCache(dictType.TenantId, dictType.DictCode)
|
||
}
|
||
}
|
||
|
||
// ========== 批量操作 ==========
|
||
|
||
// BatchUpdateDictItemSort 批量更新字典项排序
|
||
func BatchUpdateDictItemSort(items []struct {
|
||
Id int `json:"id"`
|
||
Sort int `json:"sort"`
|
||
}) error {
|
||
o := orm.NewOrm()
|
||
|
||
for _, item := range items {
|
||
dictItem := &models.DictItem{Id: item.Id}
|
||
err := o.Read(dictItem)
|
||
if err != nil {
|
||
continue
|
||
}
|
||
dictItem.Sort = item.Sort
|
||
dictItem.UpdateTime = time.Now()
|
||
_, err = o.Update(dictItem, "sort", "update_time")
|
||
if err != nil {
|
||
return fmt.Errorf("更新字典项排序失败: %v", err)
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|