kra/internal/data/system/dictionary.go

473 lines
14 KiB
Go

package system
import (
"context"
"errors"
"strconv"
"kra/internal/biz/system"
"kra/internal/data/model"
"gorm.io/gorm"
)
type dictionaryRepo struct {
db *gorm.DB
}
// NewDictionaryRepo 创建字典仓储
func NewDictionaryRepo(db *gorm.DB) system.DictionaryRepo {
return &dictionaryRepo{db: db}
}
func (r *dictionaryRepo) Create(ctx context.Context, dict *system.Dictionary) error {
m := toModelDictionary(dict)
if err := r.db.WithContext(ctx).Create(m).Error; err != nil {
return err
}
dict.ID = uint(m.ID)
return nil
}
func (r *dictionaryRepo) Update(ctx context.Context, dict *system.Dictionary) error {
updates := map[string]interface{}{
"name": dict.Name,
"type": dict.Type,
"status": dict.Status,
"desc": dict.Desc,
"parent_id": dict.ParentID,
}
return r.db.WithContext(ctx).Model(&model.SysDictionary{}).Where("id = ?", dict.ID).Updates(updates).Error
}
func (r *dictionaryRepo) Delete(ctx context.Context, id uint) error {
return r.db.WithContext(ctx).Delete(&model.SysDictionary{}, id).Error
}
func (r *dictionaryRepo) FindByID(ctx context.Context, id uint) (*system.Dictionary, error) {
var m model.SysDictionary
if err := r.db.WithContext(ctx).First(&m, id).Error; err != nil {
return nil, err
}
return toBizDictionary(&m), nil
}
func (r *dictionaryRepo) FindByType(ctx context.Context, typ string) (*system.Dictionary, error) {
var m model.SysDictionary
if err := r.db.WithContext(ctx).Where("type = ?", typ).First(&m).Error; err != nil {
return nil, err
}
return toBizDictionary(&m), nil
}
func (r *dictionaryRepo) GetByTypeOrID(ctx context.Context, typ string, id uint, status *bool) (*system.Dictionary, error) {
flag := true
if status != nil {
flag = *status
}
var m model.SysDictionary
db := r.db.WithContext(ctx).Where("(type = ? OR id = ?) AND status = ?", typ, id, flag)
if err := db.First(&m).Error; err != nil {
return nil, err
}
dict := toBizDictionary(&m)
// 加载详情
var details []model.SysDictionaryDetail
r.db.WithContext(ctx).Where("sys_dictionary_id = ? AND status = ?", m.ID, true).Order("sort").Find(&details)
// 详情在service层处理
return dict, nil
}
func (r *dictionaryRepo) List(ctx context.Context, name string) ([]*system.Dictionary, error) {
db := r.db.WithContext(ctx).Model(&model.SysDictionary{})
if name != "" {
db = db.Where("name LIKE ? OR type LIKE ?", "%"+name+"%", "%"+name+"%")
}
// 预加载子字典
db = db.Preload("Children")
var list []model.SysDictionary
if err := db.Find(&list).Error; err != nil {
return nil, err
}
result := make([]*system.Dictionary, len(list))
for i, m := range list {
result[i] = toBizDictionary(&m)
}
return result, nil
}
func (r *dictionaryRepo) CheckCircularReference(ctx context.Context, currentID, parentID uint) error {
if currentID == parentID {
return errors.New("不能将字典设置为自己的父级")
}
var parent model.SysDictionary
if err := r.db.WithContext(ctx).Where("id = ?", parentID).First(&parent).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
return err
}
if parent.ParentID != 0 {
return r.CheckCircularReference(ctx, currentID, uint(parent.ParentID))
}
return nil
}
type dictionaryDetailRepo struct {
db *gorm.DB
}
// NewDictionaryDetailRepo 创建字典详情仓储
func NewDictionaryDetailRepo(db *gorm.DB) system.DictionaryDetailRepo {
return &dictionaryDetailRepo{db: db}
}
func (r *dictionaryDetailRepo) Create(ctx context.Context, detail *system.DictionaryDetail) error {
m := toModelDictionaryDetail(detail)
if err := r.db.WithContext(ctx).Create(m).Error; err != nil {
return err
}
detail.ID = uint(m.ID)
return nil
}
func (r *dictionaryDetailRepo) Update(ctx context.Context, detail *system.DictionaryDetail) error {
m := toModelDictionaryDetail(detail)
return r.db.WithContext(ctx).Save(m).Error
}
func (r *dictionaryDetailRepo) Delete(ctx context.Context, id uint) error {
return r.db.WithContext(ctx).Delete(&model.SysDictionaryDetail{}, id).Error
}
func (r *dictionaryDetailRepo) FindByID(ctx context.Context, id uint) (*system.DictionaryDetail, error) {
var m model.SysDictionaryDetail
if err := r.db.WithContext(ctx).First(&m, id).Error; err != nil {
return nil, err
}
return toBizDictionaryDetail(&m), nil
}
func (r *dictionaryDetailRepo) List(ctx context.Context, page, pageSize int, filters map[string]interface{}) ([]*system.DictionaryDetail, int64, error) {
db := r.db.WithContext(ctx).Model(&model.SysDictionaryDetail{})
if v, ok := filters["label"]; ok && v != "" {
db = db.Where("label LIKE ?", "%"+v.(string)+"%")
}
if v, ok := filters["value"]; ok && v != "" {
db = db.Where("value = ?", v)
}
if v, ok := filters["status"]; ok {
db = db.Where("status = ?", v)
}
if v, ok := filters["sys_dictionary_id"]; ok && v.(uint) != 0 {
db = db.Where("sys_dictionary_id = ?", v)
}
if v, ok := filters["parent_id"]; ok {
db = db.Where("parent_id = ?", v)
}
if v, ok := filters["level"]; ok {
db = db.Where("level = ?", v)
}
var total int64
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
offset := (page - 1) * pageSize
var list []model.SysDictionaryDetail
if err := db.Offset(offset).Limit(pageSize).Order("sort").Order("id").Find(&list).Error; err != nil {
return nil, 0, err
}
result := make([]*system.DictionaryDetail, len(list))
for i, m := range list {
result[i] = toBizDictionaryDetail(&m)
}
return result, total, nil
}
func (r *dictionaryDetailRepo) GetListByDictionaryID(ctx context.Context, dictionaryID uint) ([]*system.DictionaryDetail, error) {
var list []model.SysDictionaryDetail
if err := r.db.WithContext(ctx).Where("sys_dictionary_id = ?", dictionaryID).Find(&list).Error; err != nil {
return nil, err
}
result := make([]*system.DictionaryDetail, len(list))
for i, m := range list {
result[i] = toBizDictionaryDetail(&m)
}
return result, nil
}
func (r *dictionaryDetailRepo) GetTreeList(ctx context.Context, dictionaryID uint) ([]*system.DictionaryDetail, error) {
var list []model.SysDictionaryDetail
if err := r.db.WithContext(ctx).Where("sys_dictionary_id = ? AND parent_id IS NULL", dictionaryID).Order("sort").Find(&list).Error; err != nil {
return nil, err
}
result := make([]*system.DictionaryDetail, len(list))
for i, m := range list {
result[i] = toBizDictionaryDetail(&m)
r.setDisabled(result[i])
if err := r.loadChildren(ctx, result[i]); err != nil {
return nil, err
}
}
return result, nil
}
func (r *dictionaryDetailRepo) loadChildren(ctx context.Context, detail *system.DictionaryDetail) error {
var children []model.SysDictionaryDetail
if err := r.db.WithContext(ctx).Where("parent_id = ?", detail.ID).Order("sort").Find(&children).Error; err != nil {
return err
}
for _, m := range children {
child := toBizDictionaryDetail(&m)
r.setDisabled(child)
if err := r.loadChildren(ctx, child); err != nil {
return err
}
detail.Children = append(detail.Children, child)
}
return nil
}
func (r *dictionaryDetailRepo) setDisabled(detail *system.DictionaryDetail) {
if detail.Status != nil {
detail.Disabled = !*detail.Status
} else {
detail.Disabled = false
}
}
func (r *dictionaryDetailRepo) GetByParent(ctx context.Context, dictionaryID uint, parentID *uint, includeChildren bool) ([]*system.DictionaryDetail, error) {
db := r.db.WithContext(ctx).Model(&model.SysDictionaryDetail{}).Where("sys_dictionary_id = ?", dictionaryID)
if parentID != nil {
db = db.Where("parent_id = ?", *parentID)
} else {
db = db.Where("parent_id IS NULL")
}
var list []model.SysDictionaryDetail
if err := db.Order("sort").Find(&list).Error; err != nil {
return nil, err
}
result := make([]*system.DictionaryDetail, len(list))
for i, m := range list {
result[i] = toBizDictionaryDetail(&m)
r.setDisabled(result[i])
if includeChildren {
if err := r.loadChildren(ctx, result[i]); err != nil {
return nil, err
}
}
}
return result, nil
}
func (r *dictionaryDetailRepo) GetByDictionaryIDAndValue(ctx context.Context, dictionaryID uint, value string) (*system.DictionaryDetail, error) {
var m model.SysDictionaryDetail
if err := r.db.WithContext(ctx).Where("sys_dictionary_id = ? AND value = ?", dictionaryID, value).First(&m).Error; err != nil {
return nil, err
}
return toBizDictionaryDetail(&m), nil
}
func (r *dictionaryDetailRepo) GetByTypeAndValue(ctx context.Context, typ, value string) (*system.DictionaryDetail, error) {
var m model.SysDictionaryDetail
if err := r.db.WithContext(ctx).Model(&model.SysDictionaryDetail{}).
Joins("JOIN sys_dictionaries ON sys_dictionaries.id = sys_dictionary_details.sys_dictionary_id").
Where("sys_dictionaries.type = ? AND sys_dictionary_details.value = ?", typ, value).
First(&m).Error; err != nil {
return nil, err
}
return toBizDictionaryDetail(&m), nil
}
func (r *dictionaryDetailRepo) GetTreeListByType(ctx context.Context, typ string) ([]*system.DictionaryDetail, error) {
var list []model.SysDictionaryDetail
if err := r.db.WithContext(ctx).Model(&model.SysDictionaryDetail{}).
Joins("JOIN sys_dictionaries ON sys_dictionaries.id = sys_dictionary_details.sys_dictionary_id").
Where("sys_dictionaries.type = ? AND sys_dictionary_details.parent_id IS NULL", typ).
Order("sys_dictionary_details.sort").
Find(&list).Error; err != nil {
return nil, err
}
result := make([]*system.DictionaryDetail, len(list))
for i, m := range list {
result[i] = toBizDictionaryDetail(&m)
r.setDisabled(result[i])
if err := r.loadChildren(ctx, result[i]); err != nil {
return nil, err
}
}
return result, nil
}
func (r *dictionaryDetailRepo) GetListByType(ctx context.Context, typ string) ([]*system.DictionaryDetail, error) {
var list []model.SysDictionaryDetail
if err := r.db.WithContext(ctx).Model(&model.SysDictionaryDetail{}).
Joins("JOIN sys_dictionaries ON sys_dictionaries.id = sys_dictionary_details.sys_dictionary_id").
Where("sys_dictionaries.type = ?", typ).
Find(&list).Error; err != nil {
return nil, err
}
result := make([]*system.DictionaryDetail, len(list))
for i, m := range list {
result[i] = toBizDictionaryDetail(&m)
}
return result, nil
}
func (r *dictionaryDetailRepo) HasChildren(ctx context.Context, id uint) (bool, error) {
var count int64
if err := r.db.WithContext(ctx).Model(&model.SysDictionaryDetail{}).Where("parent_id = ?", id).Count(&count).Error; err != nil {
return false, err
}
return count > 0, nil
}
func (r *dictionaryDetailRepo) CheckCircularReference(ctx context.Context, id, parentID uint) bool {
if id == parentID {
return true
}
var parent model.SysDictionaryDetail
if err := r.db.WithContext(ctx).First(&parent, parentID).Error; err != nil {
return false
}
if parent.ParentID == 0 {
return false
}
return r.CheckCircularReference(ctx, id, uint(parent.ParentID))
}
func (r *dictionaryDetailRepo) UpdateChildrenLevelAndPath(ctx context.Context, parentID uint) error {
var children []model.SysDictionaryDetail
if err := r.db.WithContext(ctx).Where("parent_id = ?", parentID).Find(&children).Error; err != nil {
return err
}
var parent model.SysDictionaryDetail
if err := r.db.WithContext(ctx).First(&parent, parentID).Error; err != nil {
return err
}
for _, child := range children {
child.Level = parent.Level + 1
if parent.Path == "" {
child.Path = strconv.Itoa(int(parent.ID))
} else {
child.Path = parent.Path + "," + strconv.Itoa(int(parent.ID))
}
if err := r.db.WithContext(ctx).Save(&child).Error; err != nil {
return err
}
if err := r.UpdateChildrenLevelAndPath(ctx, uint(child.ID)); err != nil {
return err
}
}
return nil
}
func (r *dictionaryDetailRepo) GetPath(ctx context.Context, id uint) ([]*system.DictionaryDetail, error) {
var m model.SysDictionaryDetail
if err := r.db.WithContext(ctx).First(&m, id).Error; err != nil {
return nil, err
}
detail := toBizDictionaryDetail(&m)
path := []*system.DictionaryDetail{detail}
if m.ParentID != 0 {
parentPath, err := r.GetPath(ctx, uint(m.ParentID))
if err != nil {
return nil, err
}
path = append(parentPath, path...)
}
return path, nil
}
func (r *dictionaryDetailRepo) DeleteByDictionaryID(ctx context.Context, dictionaryID uint) error {
return r.db.WithContext(ctx).Where("sys_dictionary_id = ?", dictionaryID).Delete(&model.SysDictionaryDetail{}).Error
}
func (r *dictionaryDetailRepo) BatchCreate(ctx context.Context, details []*system.DictionaryDetail) error {
models := make([]*model.SysDictionaryDetail, len(details))
for i, d := range details {
models[i] = toModelDictionaryDetail(d)
}
return r.db.WithContext(ctx).Create(&models).Error
}
func (r *dictionaryDetailRepo) BatchUpdateParentID(ctx context.Context, idMap map[uint]uint) error {
// idMap: oldID -> newID
// 这里需要根据实际导入逻辑处理
return nil
}
// 转换函数
func toModelDictionary(d *system.Dictionary) *model.SysDictionary {
m := &model.SysDictionary{
ID: int64(d.ID),
Name: d.Name,
Type: d.Type,
Desc: d.Desc,
}
if d.Status != nil {
m.Status = *d.Status
}
if d.ParentID != nil {
m.ParentID = int64(*d.ParentID)
}
return m
}
func toBizDictionary(m *model.SysDictionary) *system.Dictionary {
d := &system.Dictionary{
ID: uint(m.ID),
Name: m.Name,
Type: m.Type,
Status: &m.Status,
Desc: m.Desc,
}
if m.ParentID != 0 {
pid := uint(m.ParentID)
d.ParentID = &pid
}
return d
}
func toModelDictionaryDetail(d *system.DictionaryDetail) *model.SysDictionaryDetail {
m := &model.SysDictionaryDetail{
ID: int64(d.ID),
Label: d.Label,
Value: d.Value,
Extend: d.Extend,
Sort: int64(d.Sort),
SysDictionaryID: int64(d.SysDictionaryID),
Level: int64(d.Level),
Path: d.Path,
}
if d.Status != nil {
m.Status = *d.Status
}
if d.ParentID != nil {
m.ParentID = int64(*d.ParentID)
}
return m
}
func toBizDictionaryDetail(m *model.SysDictionaryDetail) *system.DictionaryDetail {
d := &system.DictionaryDetail{
ID: uint(m.ID),
Label: m.Label,
Value: m.Value,
Extend: m.Extend,
Status: &m.Status,
Sort: int(m.Sort),
SysDictionaryID: uint(m.SysDictionaryID),
Level: int(m.Level),
Path: m.Path,
}
if m.ParentID != 0 {
pid := uint(m.ParentID)
d.ParentID = &pid
}
return d
}