yunzer_go/server/services/dict.go
2025-11-07 17:38:59 +08:00

374 lines
9.9 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 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", "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, parentId int, status *int8) ([]*models.DictType, error) {
o := orm.NewOrm()
qs := o.QueryTable("sys_dict_type").Filter("is_deleted", 0)
// 租户过滤0表示平台字典>0表示租户字典
if tenantId > 0 {
// 租户用户只能看到自己的字典和平台字典
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)
}
var dictTypes []*models.DictType
_, err := qs.OrderBy("sort", "create_time").All(&dictTypes)
return dictTypes, 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
}