Dockerfile
This commit is contained in:
265
service/asset/category_service.go
Normal file
265
service/asset/category_service.go
Normal file
@@ -0,0 +1,265 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
dao "assets/dao/asset"
|
||||
dto "assets/model/dto/asset"
|
||||
entity "assets/model/entity/asset"
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"gitea.com/red-future/common/db/gfdb"
|
||||
"gitea.com/red-future/common/utils"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultPathSeparator 路径分隔符
|
||||
DefaultPathSeparator = "/"
|
||||
)
|
||||
|
||||
// CategoryService 分类服务
|
||||
type CategoryService struct{}
|
||||
|
||||
var Category = new(CategoryService)
|
||||
|
||||
// Create 创建分类
|
||||
func (s *CategoryService) Create(ctx context.Context, req *dto.CreateCategoryReq) (res *dto.CreateCategoryRes, err error) {
|
||||
|
||||
// 构建分类路径和层级
|
||||
parent, err := dao.Category.GetOne(ctx, &dto.GetCategoryReq{Bid: req.ParentId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Path = parent.Path + DefaultPathSeparator + req.ParentId
|
||||
req.Level = parent.Level + 1
|
||||
|
||||
err = gfdb.DB(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
var r *entity.Category
|
||||
|
||||
if r, err = dao.Category.Insert(ctx, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新新创建分类的 IsLeafNode 为 true
|
||||
if err = s.updateLeafNode(ctx, r.Bid, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新父节点的 IsLeafNode 为 false
|
||||
if err = s.updateLeafNode(ctx, req.ParentId, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res = &dto.CreateCategoryRes{
|
||||
Bid: r.Bid,
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// updateLeafNode 更新分类的 IsLeafNode 字段
|
||||
func (s *CategoryService) updateLeafNode(ctx context.Context, categoryId string, isLeaf bool) error {
|
||||
return dao.Category.Update(ctx, &dto.UpdateCategoryReq{
|
||||
Bid: categoryId,
|
||||
IsLeafNode: isLeaf,
|
||||
})
|
||||
}
|
||||
|
||||
// GetOne 获取单个分类
|
||||
func (s *CategoryService) GetOne(ctx context.Context, req *dto.GetCategoryReq) (*dto.GetCategoryRes, error) {
|
||||
one, err := dao.Category.GetOne(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := new(dto.GetCategoryRes)
|
||||
err = utils.Struct(one, &res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// List 获取分类列表
|
||||
func (s *CategoryService) List(ctx context.Context, req *dto.ListCategoryReq) (*dto.ListCategoryRes, error) {
|
||||
list, total, err := dao.Category.List(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := &dto.ListCategoryRes{Total: total}
|
||||
err = gconv.Struct(list, &res.List)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetTree 获取分类树
|
||||
func (s *CategoryService) GetTree(ctx context.Context, req *dto.GetCategoryTreeReq) (*dto.GetCategoryTreeRes, error) {
|
||||
list, _, err := dao.Category.List(ctx, &dto.ListCategoryReq{
|
||||
Keyword: req.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tree, err := s.buildTree(ctx, list, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dto.GetCategoryTreeRes{Tree: tree}, nil
|
||||
}
|
||||
|
||||
// buildTree 构建树形结构
|
||||
func (s *CategoryService) buildTree(ctx context.Context, categories []entity.Category, parentId string) ([]*dto.CategoryTreeNode, error) {
|
||||
tree := make([]*dto.CategoryTreeNode, 0)
|
||||
for _, cat := range categories {
|
||||
if !s.isChildOf(cat.ParentId, parentId) {
|
||||
continue
|
||||
}
|
||||
node, err := s.convertToTreeNode(ctx, &cat, categories)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tree = append(tree, node)
|
||||
}
|
||||
return tree, nil
|
||||
}
|
||||
|
||||
// isChildOf 判断分类是否为指定父节点的子节点
|
||||
func (s *CategoryService) isChildOf(childParentId, parentId string) bool {
|
||||
if g.IsEmpty(childParentId) && g.IsEmpty(parentId) {
|
||||
return true
|
||||
}
|
||||
if g.IsEmpty(childParentId) || g.IsEmpty(parentId) {
|
||||
return false
|
||||
}
|
||||
return childParentId == parentId
|
||||
}
|
||||
|
||||
// convertToTreeNode 将分类实体转换为树节点
|
||||
func (s *CategoryService) convertToTreeNode(ctx context.Context, category *entity.Category, allCategories []entity.Category) (*dto.CategoryTreeNode, error) {
|
||||
res := new(dto.CategoryTreeNode)
|
||||
if err := gconv.Struct(&category, &res); err != nil {
|
||||
return res, err
|
||||
}
|
||||
children, err := s.buildTree(ctx, allCategories, category.Bid)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
res.Children = children
|
||||
res.IsLeafNode = len(children) == 0
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// hasChildren 检查分类是否有子分类
|
||||
func (s *CategoryService) hasChildren(ctx context.Context, parentId string) (bool, error) {
|
||||
count, err := dao.Category.Count(ctx, &dto.ListCategoryReq{
|
||||
ParentId: parentId,
|
||||
})
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// updateLeafNodeIfNoChildren 如果父分类没有子分类了,更新为叶子节点
|
||||
func (s *CategoryService) updateLeafNodeIfNoChildren(ctx context.Context, parentId string) error {
|
||||
hasChildren, err := s.hasChildren(ctx, parentId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.updateLeafNode(ctx, parentId, !hasChildren)
|
||||
}
|
||||
|
||||
// UpdateStatus 更新分类状态
|
||||
func (s *CategoryService) UpdateStatus(ctx context.Context, req *dto.UpdateCategoryStatusReq) error {
|
||||
var updateReq *dto.UpdateCategoryReq
|
||||
if err := gconv.Struct(req, &updateReq); err != nil {
|
||||
return err
|
||||
}
|
||||
return dao.Category.Update(ctx, updateReq)
|
||||
}
|
||||
|
||||
// Update 更新分类
|
||||
func (s *CategoryService) Update(ctx context.Context, req *dto.UpdateCategoryReq) error {
|
||||
oldCategory, err := dao.Category.GetOne(ctx, &dto.GetCategoryReq{Id: req.Id})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = gfdb.DB(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
if err = dao.Category.Update(ctx, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果修改了父分类,需要更新相关节点的 IsLeafNode
|
||||
if s.parentIdChanged(req.ParentId, oldCategory.ParentId) {
|
||||
if !g.IsEmpty(req.ParentId) {
|
||||
if err = s.updateLeafNode(ctx, req.ParentId, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !g.IsEmpty(oldCategory.ParentId) {
|
||||
if err = s.updateLeafNodeIfNoChildren(ctx, oldCategory.ParentId); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// parentIdChanged 判断父分类是否发生变化
|
||||
func (s *CategoryService) parentIdChanged(newParentId, oldParentId string) bool {
|
||||
if g.IsEmpty(newParentId) && g.IsEmpty(oldParentId) {
|
||||
return false
|
||||
}
|
||||
if g.IsEmpty(newParentId) || g.IsEmpty(oldParentId) {
|
||||
return true
|
||||
}
|
||||
return newParentId != oldParentId
|
||||
}
|
||||
|
||||
// Delete 删除分类
|
||||
func (s *CategoryService) Delete(ctx context.Context, req *dto.DeleteCategoryReq) error {
|
||||
// 检查是否有子分类
|
||||
hasChildren, err := s.hasChildren(ctx, req.Bid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if hasChildren {
|
||||
return errors.New("该分类下有子分类,无法删除")
|
||||
}
|
||||
|
||||
// 检查是否有资产
|
||||
if count, err := dao.Asset.Count(ctx, &dto.ListAssetReq{
|
||||
CategoryId: req.Bid,
|
||||
}); err != nil {
|
||||
return err
|
||||
} else if count > 0 {
|
||||
return errors.New("该分类下有资产信息,无法删除")
|
||||
}
|
||||
|
||||
// 获取分类信息用于后续操作
|
||||
category, err := dao.Category.GetOne(ctx, &dto.GetCategoryReq{Bid: req.Bid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = gfdb.DB(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
// 删除分类
|
||||
if err := dao.Category.DeleteFake(ctx, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果删除的是叶子节点,更新父节点为叶子节点
|
||||
if !g.IsEmpty(category.ParentId) {
|
||||
return s.updateLeafNodeIfNoChildren(ctx, category.ParentId)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user