任务三
This commit is contained in:
@@ -0,0 +1,357 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Dictionary 字典实体
|
||||
type Dictionary struct {
|
||||
ID uint
|
||||
Name string
|
||||
Type string
|
||||
Status *bool
|
||||
Desc string
|
||||
ParentID *uint
|
||||
Children []*Dictionary
|
||||
}
|
||||
|
||||
// DictionaryDetail 字典详情实体
|
||||
type DictionaryDetail struct {
|
||||
ID uint
|
||||
Label string
|
||||
Value string
|
||||
Extend string
|
||||
Status *bool
|
||||
Sort int
|
||||
SysDictionaryID uint
|
||||
ParentID *uint
|
||||
Level int
|
||||
Path string
|
||||
Disabled bool
|
||||
Children []*DictionaryDetail
|
||||
}
|
||||
|
||||
// DictionaryRepo 字典仓储接口
|
||||
type DictionaryRepo interface {
|
||||
Create(ctx context.Context, dict *Dictionary) error
|
||||
Update(ctx context.Context, dict *Dictionary) error
|
||||
Delete(ctx context.Context, id uint) error
|
||||
FindByID(ctx context.Context, id uint) (*Dictionary, error)
|
||||
FindByType(ctx context.Context, typ string) (*Dictionary, error)
|
||||
GetByTypeOrID(ctx context.Context, typ string, id uint, status *bool) (*Dictionary, error)
|
||||
List(ctx context.Context, name string) ([]*Dictionary, error)
|
||||
CheckCircularReference(ctx context.Context, currentID, parentID uint) error
|
||||
}
|
||||
|
||||
// DictionaryDetailRepo 字典详情仓储接口
|
||||
type DictionaryDetailRepo interface {
|
||||
Create(ctx context.Context, detail *DictionaryDetail) error
|
||||
Update(ctx context.Context, detail *DictionaryDetail) error
|
||||
Delete(ctx context.Context, id uint) error
|
||||
FindByID(ctx context.Context, id uint) (*DictionaryDetail, error)
|
||||
List(ctx context.Context, page, pageSize int, filters map[string]interface{}) ([]*DictionaryDetail, int64, error)
|
||||
GetListByDictionaryID(ctx context.Context, dictionaryID uint) ([]*DictionaryDetail, error)
|
||||
GetTreeList(ctx context.Context, dictionaryID uint) ([]*DictionaryDetail, error)
|
||||
GetByParent(ctx context.Context, dictionaryID uint, parentID *uint, includeChildren bool) ([]*DictionaryDetail, error)
|
||||
GetByDictionaryIDAndValue(ctx context.Context, dictionaryID uint, value string) (*DictionaryDetail, error)
|
||||
GetByTypeAndValue(ctx context.Context, typ, value string) (*DictionaryDetail, error)
|
||||
GetTreeListByType(ctx context.Context, typ string) ([]*DictionaryDetail, error)
|
||||
GetListByType(ctx context.Context, typ string) ([]*DictionaryDetail, error)
|
||||
HasChildren(ctx context.Context, id uint) (bool, error)
|
||||
CheckCircularReference(ctx context.Context, id, parentID uint) bool
|
||||
UpdateChildrenLevelAndPath(ctx context.Context, parentID uint) error
|
||||
GetPath(ctx context.Context, id uint) ([]*DictionaryDetail, error)
|
||||
DeleteByDictionaryID(ctx context.Context, dictionaryID uint) error
|
||||
BatchCreate(ctx context.Context, details []*DictionaryDetail) error
|
||||
BatchUpdateParentID(ctx context.Context, idMap map[uint]uint) error
|
||||
}
|
||||
|
||||
// DictionaryUsecase 字典用例
|
||||
type DictionaryUsecase struct {
|
||||
repo DictionaryRepo
|
||||
detailRepo DictionaryDetailRepo
|
||||
}
|
||||
|
||||
// NewDictionaryUsecase 创建字典用例
|
||||
func NewDictionaryUsecase(repo DictionaryRepo, detailRepo DictionaryDetailRepo) *DictionaryUsecase {
|
||||
return &DictionaryUsecase{repo: repo, detailRepo: detailRepo}
|
||||
}
|
||||
|
||||
// CreateDictionary 创建字典
|
||||
func (uc *DictionaryUsecase) CreateDictionary(ctx context.Context, dict *Dictionary) error {
|
||||
// 检查type是否重复
|
||||
existing, err := uc.repo.FindByType(ctx, dict.Type)
|
||||
if err == nil && existing != nil {
|
||||
return errors.New("存在相同的type,不允许创建")
|
||||
}
|
||||
return uc.repo.Create(ctx, dict)
|
||||
}
|
||||
|
||||
// UpdateDictionary 更新字典
|
||||
func (uc *DictionaryUsecase) UpdateDictionary(ctx context.Context, dict *Dictionary) error {
|
||||
old, err := uc.repo.FindByID(ctx, dict.ID)
|
||||
if err != nil {
|
||||
return errors.New("查询字典数据失败")
|
||||
}
|
||||
// 如果type变更,检查是否重复
|
||||
if old.Type != dict.Type {
|
||||
existing, err := uc.repo.FindByType(ctx, dict.Type)
|
||||
if err == nil && existing != nil {
|
||||
return errors.New("存在相同的type,不允许创建")
|
||||
}
|
||||
}
|
||||
// 检查循环引用
|
||||
if dict.ParentID != nil && *dict.ParentID != 0 {
|
||||
if err := uc.repo.CheckCircularReference(ctx, dict.ID, *dict.ParentID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return uc.repo.Update(ctx, dict)
|
||||
}
|
||||
|
||||
// DeleteDictionary 删除字典
|
||||
func (uc *DictionaryUsecase) DeleteDictionary(ctx context.Context, id uint) error {
|
||||
dict, err := uc.repo.FindByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("请不要搞事")
|
||||
}
|
||||
if err := uc.repo.Delete(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
// 删除关联的字典详情
|
||||
return uc.detailRepo.DeleteByDictionaryID(ctx, dict.ID)
|
||||
}
|
||||
|
||||
// GetDictionary 获取字典
|
||||
func (uc *DictionaryUsecase) GetDictionary(ctx context.Context, typ string, id uint, status *bool) (*Dictionary, error) {
|
||||
return uc.repo.GetByTypeOrID(ctx, typ, id, status)
|
||||
}
|
||||
|
||||
// GetDictionaryList 获取字典列表
|
||||
func (uc *DictionaryUsecase) GetDictionaryList(ctx context.Context, name string) ([]*Dictionary, error) {
|
||||
return uc.repo.List(ctx, name)
|
||||
}
|
||||
|
||||
// ExportDictionary 导出字典
|
||||
func (uc *DictionaryUsecase) ExportDictionary(ctx context.Context, id uint) (map[string]interface{}, error) {
|
||||
dict, err := uc.repo.FindByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := uc.detailRepo.GetListByDictionaryID(ctx, dict.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 清理详情数据
|
||||
var cleanDetails []map[string]interface{}
|
||||
for _, detail := range details {
|
||||
cleanDetail := map[string]interface{}{
|
||||
"label": detail.Label,
|
||||
"value": detail.Value,
|
||||
"extend": detail.Extend,
|
||||
"status": detail.Status,
|
||||
"sort": detail.Sort,
|
||||
"level": detail.Level,
|
||||
"path": detail.Path,
|
||||
}
|
||||
cleanDetails = append(cleanDetails, cleanDetail)
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"name": dict.Name,
|
||||
"type": dict.Type,
|
||||
"status": dict.Status,
|
||||
"desc": dict.Desc,
|
||||
"sysDictionaryDetails": cleanDetails,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ImportDictionary 导入字典
|
||||
func (uc *DictionaryUsecase) ImportDictionary(ctx context.Context, jsonStr string) error {
|
||||
var importData struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Status *bool `json:"status"`
|
||||
Desc string `json:"desc"`
|
||||
SysDictionaryDetails []*DictionaryDetail `json:"sysDictionaryDetails"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(jsonStr), &importData); err != nil {
|
||||
return errors.New("JSON 格式错误: " + err.Error())
|
||||
}
|
||||
if importData.Name == "" {
|
||||
return errors.New("字典名称不能为空")
|
||||
}
|
||||
if importData.Type == "" {
|
||||
return errors.New("字典类型不能为空")
|
||||
}
|
||||
// 检查type是否重复
|
||||
existing, err := uc.repo.FindByType(ctx, importData.Type)
|
||||
if err == nil && existing != nil {
|
||||
return errors.New("存在相同的type,不允许导入")
|
||||
}
|
||||
|
||||
// 创建字典
|
||||
dict := &Dictionary{
|
||||
Name: importData.Name,
|
||||
Type: importData.Type,
|
||||
Status: importData.Status,
|
||||
Desc: importData.Desc,
|
||||
}
|
||||
if err := uc.repo.Create(ctx, dict); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 处理字典详情
|
||||
if len(importData.SysDictionaryDetails) > 0 {
|
||||
idMap := make(map[uint]uint)
|
||||
for _, detail := range importData.SysDictionaryDetails {
|
||||
if detail.Label == "" || detail.Value == "" {
|
||||
continue
|
||||
}
|
||||
oldID := detail.ID
|
||||
newDetail := &DictionaryDetail{
|
||||
Label: detail.Label,
|
||||
Value: detail.Value,
|
||||
Extend: detail.Extend,
|
||||
Status: detail.Status,
|
||||
Sort: detail.Sort,
|
||||
Level: detail.Level,
|
||||
Path: detail.Path,
|
||||
SysDictionaryID: dict.ID,
|
||||
}
|
||||
if err := uc.detailRepo.Create(ctx, newDetail); err != nil {
|
||||
return err
|
||||
}
|
||||
if oldID > 0 {
|
||||
idMap[oldID] = newDetail.ID
|
||||
}
|
||||
}
|
||||
// 更新parent_id关系
|
||||
if len(idMap) > 0 {
|
||||
if err := uc.detailRepo.BatchUpdateParentID(ctx, idMap); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateDictionaryDetail 创建字典详情
|
||||
func (uc *DictionaryUsecase) CreateDictionaryDetail(ctx context.Context, detail *DictionaryDetail) error {
|
||||
// 计算层级和路径
|
||||
if detail.ParentID != nil && *detail.ParentID != 0 {
|
||||
parent, err := uc.detailRepo.FindByID(ctx, *detail.ParentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
detail.Level = parent.Level + 1
|
||||
if parent.Path == "" {
|
||||
detail.Path = strconv.Itoa(int(parent.ID))
|
||||
} else {
|
||||
detail.Path = parent.Path + "," + strconv.Itoa(int(parent.ID))
|
||||
}
|
||||
} else {
|
||||
detail.Level = 0
|
||||
detail.Path = ""
|
||||
}
|
||||
return uc.detailRepo.Create(ctx, detail)
|
||||
}
|
||||
|
||||
// UpdateDictionaryDetail 更新字典详情
|
||||
func (uc *DictionaryUsecase) UpdateDictionaryDetail(ctx context.Context, detail *DictionaryDetail) error {
|
||||
// 如果更新了父级ID,重新计算层级和路径
|
||||
if detail.ParentID != nil && *detail.ParentID != 0 {
|
||||
parent, err := uc.detailRepo.FindByID(ctx, *detail.ParentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 检查循环引用
|
||||
if uc.detailRepo.CheckCircularReference(ctx, detail.ID, *detail.ParentID) {
|
||||
return errors.New("不能将字典详情设置为自己或其子项的父级")
|
||||
}
|
||||
detail.Level = parent.Level + 1
|
||||
if parent.Path == "" {
|
||||
detail.Path = strconv.Itoa(int(parent.ID))
|
||||
} else {
|
||||
detail.Path = parent.Path + "," + strconv.Itoa(int(parent.ID))
|
||||
}
|
||||
} else {
|
||||
detail.Level = 0
|
||||
detail.Path = ""
|
||||
}
|
||||
if err := uc.detailRepo.Update(ctx, detail); err != nil {
|
||||
return err
|
||||
}
|
||||
// 更新所有子项的层级和路径
|
||||
return uc.detailRepo.UpdateChildrenLevelAndPath(ctx, detail.ID)
|
||||
}
|
||||
|
||||
// DeleteDictionaryDetail 删除字典详情
|
||||
func (uc *DictionaryUsecase) DeleteDictionaryDetail(ctx context.Context, id uint) error {
|
||||
hasChildren, err := uc.detailRepo.HasChildren(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if hasChildren {
|
||||
return errors.New("该字典详情下还有子项,无法删除")
|
||||
}
|
||||
return uc.detailRepo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// GetDictionaryDetail 获取字典详情
|
||||
func (uc *DictionaryUsecase) GetDictionaryDetail(ctx context.Context, id uint) (*DictionaryDetail, error) {
|
||||
return uc.detailRepo.FindByID(ctx, id)
|
||||
}
|
||||
|
||||
// GetDictionaryDetailList 获取字典详情列表
|
||||
func (uc *DictionaryUsecase) GetDictionaryDetailList(ctx context.Context, page, pageSize int, filters map[string]interface{}) ([]*DictionaryDetail, int64, error) {
|
||||
return uc.detailRepo.List(ctx, page, pageSize, filters)
|
||||
}
|
||||
|
||||
// GetDictionaryTreeList 获取字典树形列表
|
||||
func (uc *DictionaryUsecase) GetDictionaryTreeList(ctx context.Context, dictionaryID uint) ([]*DictionaryDetail, error) {
|
||||
return uc.detailRepo.GetTreeList(ctx, dictionaryID)
|
||||
}
|
||||
|
||||
// GetDictionaryDetailsByParent 根据父级获取字典详情
|
||||
func (uc *DictionaryUsecase) GetDictionaryDetailsByParent(ctx context.Context, dictionaryID uint, parentID *uint, includeChildren bool) ([]*DictionaryDetail, error) {
|
||||
return uc.detailRepo.GetByParent(ctx, dictionaryID, parentID, includeChildren)
|
||||
}
|
||||
|
||||
// GetDictionaryInfoByValue 根据字典ID和值获取详情
|
||||
func (uc *DictionaryUsecase) GetDictionaryInfoByValue(ctx context.Context, dictionaryID uint, value string) (*DictionaryDetail, error) {
|
||||
return uc.detailRepo.GetByDictionaryIDAndValue(ctx, dictionaryID, value)
|
||||
}
|
||||
|
||||
// GetDictionaryInfoByTypeValue 根据字典类型和值获取详情
|
||||
func (uc *DictionaryUsecase) GetDictionaryInfoByTypeValue(ctx context.Context, typ, value string) (*DictionaryDetail, error) {
|
||||
return uc.detailRepo.GetByTypeAndValue(ctx, typ, value)
|
||||
}
|
||||
|
||||
// GetDictionaryTreeListByType 根据类型获取树形列表
|
||||
func (uc *DictionaryUsecase) GetDictionaryTreeListByType(ctx context.Context, typ string) ([]*DictionaryDetail, error) {
|
||||
return uc.detailRepo.GetTreeListByType(ctx, typ)
|
||||
}
|
||||
|
||||
// GetDictionaryListByType 根据类型获取列表
|
||||
func (uc *DictionaryUsecase) GetDictionaryListByType(ctx context.Context, typ string) ([]*DictionaryDetail, error) {
|
||||
return uc.detailRepo.GetListByType(ctx, typ)
|
||||
}
|
||||
|
||||
// GetDictionaryPath 获取字典详情路径
|
||||
func (uc *DictionaryUsecase) GetDictionaryPath(ctx context.Context, id uint) ([]*DictionaryDetail, error) {
|
||||
return uc.detailRepo.GetPath(ctx, id)
|
||||
}
|
||||
|
||||
// GetDictionaryPathByValue 根据值获取字典详情路径
|
||||
func (uc *DictionaryUsecase) GetDictionaryPathByValue(ctx context.Context, dictionaryID uint, value string) ([]*DictionaryDetail, error) {
|
||||
detail, err := uc.detailRepo.GetByDictionaryIDAndValue(ctx, dictionaryID, value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return uc.detailRepo.GetPath(ctx, detail.ID)
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package system
|
||||
|
||||
import "context"
|
||||
|
||||
// OperationRecord 操作记录实体
|
||||
type OperationRecord struct {
|
||||
ID uint
|
||||
IP string
|
||||
Method string
|
||||
Path string
|
||||
Status int
|
||||
Latency int64
|
||||
Agent string
|
||||
ErrorMessage string
|
||||
Body string
|
||||
Resp string
|
||||
UserID uint
|
||||
User *User
|
||||
}
|
||||
|
||||
// OperationRecordRepo 操作记录仓储接口
|
||||
type OperationRecordRepo interface {
|
||||
Create(ctx context.Context, record *OperationRecord) error
|
||||
Delete(ctx context.Context, id uint) error
|
||||
DeleteByIds(ctx context.Context, ids []uint) error
|
||||
FindByID(ctx context.Context, id uint) (*OperationRecord, error)
|
||||
List(ctx context.Context, page, pageSize int, filters map[string]interface{}) ([]*OperationRecord, int64, error)
|
||||
}
|
||||
|
||||
// OperationRecordUsecase 操作记录用例
|
||||
type OperationRecordUsecase struct {
|
||||
repo OperationRecordRepo
|
||||
}
|
||||
|
||||
// NewOperationRecordUsecase 创建操作记录用例
|
||||
func NewOperationRecordUsecase(repo OperationRecordRepo) *OperationRecordUsecase {
|
||||
return &OperationRecordUsecase{repo: repo}
|
||||
}
|
||||
|
||||
// CreateOperationRecord 创建操作记录
|
||||
func (uc *OperationRecordUsecase) CreateOperationRecord(ctx context.Context, record *OperationRecord) error {
|
||||
return uc.repo.Create(ctx, record)
|
||||
}
|
||||
|
||||
// DeleteOperationRecord 删除操作记录
|
||||
func (uc *OperationRecordUsecase) DeleteOperationRecord(ctx context.Context, id uint) error {
|
||||
return uc.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// DeleteOperationRecordByIds 批量删除操作记录
|
||||
func (uc *OperationRecordUsecase) DeleteOperationRecordByIds(ctx context.Context, ids []uint) error {
|
||||
return uc.repo.DeleteByIds(ctx, ids)
|
||||
}
|
||||
|
||||
// GetOperationRecord 获取操作记录
|
||||
func (uc *OperationRecordUsecase) GetOperationRecord(ctx context.Context, id uint) (*OperationRecord, error) {
|
||||
return uc.repo.FindByID(ctx, id)
|
||||
}
|
||||
|
||||
// GetOperationRecordList 获取操作记录列表
|
||||
func (uc *OperationRecordUsecase) GetOperationRecordList(ctx context.Context, page, pageSize int, filters map[string]interface{}) ([]*OperationRecord, int64, error) {
|
||||
return uc.repo.List(ctx, page, pageSize, filters)
|
||||
}
|
||||
Reference in New Issue
Block a user