任务三

This commit is contained in:
Yvan
2026-01-07 14:34:18 +08:00
parent 8eeda7736e
commit 1a06053b30
38 changed files with 2107 additions and 405 deletions
+357
View File
@@ -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)
}
+63
View File
@@ -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)
}