Dockerfile

This commit is contained in:
2026-03-18 10:18:03 +08:00
parent 5c5dbc7420
commit b65f3439f3
189 changed files with 19027 additions and 0 deletions

View File

@@ -0,0 +1,176 @@
package service
import (
"assets/consts/stock"
dao "assets/dao/asset"
"assets/dao/base"
dto "assets/model/dto/asset"
"context"
"errors"
"fmt"
"gitea.com/red-future/common/http"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
"gitea.com/red-future/common/beans"
"gitea.com/red-future/common/minio"
"gitea.com/red-future/common/utils"
)
type asset struct{}
// Asset 资产服务
var Asset = new(asset)
// Create 创建资产
func (s *asset) Create(ctx context.Context, req *dto.CreateAssetReq) (res *dto.CreateAssetRes, err error) {
count, err := dao.Asset.Count(ctx, &dto.ListAssetReq{Name: req.Name})
if err != nil {
return
}
if count > 0 {
return nil, errors.New("资产名称已存在")
}
// 检查是否是超级管理员
isSuperAdmin := false
// 获取当前请求的 headers 并传递到下游
headers := make(map[string]string)
if r := g.RequestFromCtx(ctx); r != nil {
for k, v := range r.Request.Header {
if len(v) > 0 {
headers[k] = v[0]
}
}
}
if err = http.Get(ctx, "admin-go/api/v1/system/user/checkIsSuperAdmin", headers, &isSuperAdmin); err != nil {
return
}
if !isSuperAdmin {
req.StockMode = stock.StockModeDetail
//var getUserInfo beans.User
//getUserInfo, err = utils.GetUserInfo(ctx)
//if err != nil {
// return
//}
//var get *gvar.Var
//get, err = message.GetRedisClientTest("test").Get(ctx, fmt.Sprintf("module_tenant:tenantId-%v", getUserInfo.TenantId))
//if err != nil {
// return
//}
//if !g.IsEmpty(get.String()) {
// list := new(beans.ModuleTenant)
// if err = json.Unmarshal(get.Bytes(), &list); err != nil {
// return
// }
// req.TenantModuleType = list.TenantModuleType
//} else {
// moduleTenantRes := new(beans.ModuleTenant)
// err = message.CallRPC(ctx, "moduleService.AddRedisByTenantId", map[string]interface{}{"tenantId": getUserInfo.TenantId}, moduleTenantRes)
// if err != nil {
// return
// }
// if !g.IsEmpty(moduleTenantRes.TenantModuleType) {
// req.TenantModuleType = moduleTenantRes.TenantModuleType
// } else {
// return nil, errors.New("您未开通此模块,请开通后再使用")
// }
//}
} else {
req.TenantModuleType = beans.TenantModuleTypePlatform
}
// 插入数据库
id, err := dao.Asset.Insert(ctx, req)
if err != nil {
return
}
res = &dto.CreateAssetRes{
Id: gconv.Uint64(id),
}
return
}
// List 获取资产列表
func (s *asset) List(ctx context.Context, req *dto.ListAssetReq) (res *dto.ListAssetRes, err error) {
assetList, total, err := dao.Asset.List(ctx, req)
if err != nil {
return
}
user, err := utils.GetUserInfo(ctx)
if err != nil {
return
}
fmt.Println(user)
res = &dto.ListAssetRes{
Total: total,
}
err = utils.Struct(assetList, &res.List)
return
}
// GetOne 获取单个资产
func (s *asset) GetOne(ctx context.Context, req *dto.GetAssetReq) (res *dto.GetAssetRes, err error) {
assetOne, err := dao.Asset.GetOne(ctx, req)
if err != nil {
return
}
// TODO: CategoryId类型不匹配需要同步修改category为uint64
// getCategoryRes, err := dao.Category.GetOne(ctx, &dto.GetCategoryReq{
// Id: assetOne.CategoryId,
// })
// if err != nil {
// return
// }
return &dto.GetAssetRes{
Asset: assetOne,
CategoryName: "", // getCategoryRes.Name,
ImgAddressPrefix: minio.GetFileAddressPrefix(ctx),
}, nil
}
// GetAssetAndSku 获取资产和Sku详情
func (s *asset) GetAssetAndSku(ctx context.Context, req *dto.GetAssetAndSkuReq) (res *dto.GetAssetAndSkuRes, err error) {
// 跳过租户ID过滤获取资产
// TODO: AssetId 类型不匹配bson.ObjectID 需要转换为 uint64
// 使用 SkipTenantId 跳过租户ID过滤
assetOne, err := dao.Asset.GetOneById(base.SkipTenantId(ctx), 0)
_ = req.AssetId
if err != nil {
return
}
// TODO: AssetId类型不匹配需要适配
// moduleType, err := service.Enum.GetTenantModuleType(ctx, &enumDto.GetTenantModuleTypeReq{AssetId: req.AssetId.Hex()})
// if err != nil {
// return
// }
// TODO: AssetId类型不匹配需要同步修改AssetSku为uint64
// skus, _, err := dao.AssetSku.List(ctx, &dto.ListAssetSkuReq{AssetId: req.AssetId}, true)
// if err != nil {
// return
// }
return &dto.GetAssetAndSkuRes{
Asset: assetOne,
Skus: nil, // skus,
TenantModuleType: nil, // moduleType.Options,
ImgAddressPrefix: minio.GetFileAddressPrefix(ctx),
}, nil
}
// Update 更新资产
func (s *asset) Update(ctx context.Context, req *dto.UpdateAssetReq) error {
return dao.Asset.Update(ctx, req)
}
// UpdateStatus 更新资产状态
func (s *asset) UpdateStatus(ctx context.Context, req *dto.UpdateAssetStatusReq) (err error) {
var updateReq *dto.UpdateAssetReq
err = utils.Struct(req, &updateReq)
return dao.Asset.Update(ctx, updateReq)
}
// Delete 删除资产
func (s *asset) Delete(ctx context.Context, req *dto.DeleteAssetReq) error {
return dao.Asset.DeleteFake(ctx, req)
}

View File

@@ -0,0 +1,191 @@
package service
import (
"assets/consts/public"
dao "assets/dao/asset"
dto "assets/model/dto/asset"
entity "assets/model/entity/asset"
"context"
"errors"
"reflect"
"gitea.com/red-future/common/beans"
"gitea.com/red-future/common/utils"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
"go.mongodb.org/mongo-driver/v2/bson"
)
type assetSku struct{}
var AssetSku = new(assetSku)
// CreateAssetSku 创建SKU
func (s *assetSku) CreateAssetSku(ctx context.Context, req *dto.CreateAssetSkuReq) (res *dto.CreateAssetSkuRes, err error) {
// 验证资产是否存在, 如果存在,则获取资产信息(用于下面验证,自定义属性传过来的全不全)
assetEntity, err := dao.Asset.GetOne(ctx, &dto.GetAssetReq{Id: req.AssetId})
if err != nil {
return nil, errors.New("关联资产不存在")
}
// 根据资产ID查询SKU列表用于下面验证自定义属性和sku名称重不重复
skusList, _, err := dao.AssetSku.List(ctx, &dto.ListAssetSkuReq{AssetId: req.AssetId}, false)
if err != nil {
return
}
// 验证参数
err = s.parameterValidation(ctx, assetEntity, skusList, req.SkuName, req.SpecValues)
if err != nil {
return
}
req.UnlimitedStock = assetEntity.UnlimitedStock
req.StockMode = assetEntity.StockMode
// TODO: 类型不匹配 uint64 vs *bson.ObjectID
// req.CategoryId = assetEntity.CategoryId
req.CategoryPath = assetEntity.CategoryPath
// TODO: 类型不匹配 string vs beans.TenantModuleType
// req.TenantModuleType = assetEntity.TenantModuleType
// 插入数据库
ids, err := dao.AssetSku.Insert(ctx, req)
if err != nil {
return
}
id := ids[0].(bson.ObjectID)
res = &dto.CreateAssetSkuRes{
Id: &id,
}
return
}
// UpdateAssetSku 更新SKU
func (s *assetSku) UpdateAssetSku(ctx context.Context, req *dto.UpdateAssetSkuReq) error {
getOne, err := dao.AssetSku.GetOne(ctx, &dto.GetAssetSkuReq{Id: req.Id}, false)
if err != nil {
return errors.New("SUK不存在")
}
// 根据资产ID查询SKU列表用于下面验证自定义属性和sku名称重不重复
skusList, _, err := dao.AssetSku.GetListByAssetIdExcludeCurrentSku(ctx, getOne.AssetId, &dto.ListAssetSkuReq{Id: req.Id, Page: &beans.Page{PageSize: -1}})
if err != nil {
return err
}
// 验证资产是否存在, 如果存在,则获取资产信息(用于下面验证,自定义属性传过来的全不全)
assetEntity, err := dao.Asset.GetOne(ctx, &dto.GetAssetReq{Id: getOne.AssetId})
if err != nil {
return errors.New("关联资产不存在")
}
// 验证参数
err = s.parameterValidation(ctx, assetEntity, skusList, req.SkuName, req.SpecValues)
if err != nil {
return err
}
// 更新数据库
return dao.AssetSku.Update(ctx, req)
}
func (s *assetSku) parameterValidation(ctx context.Context, assetEntity *entity.Asset, list []entity.AssetSku, skuName string, specValues []map[string]interface{}) (err error) {
_ = ctx
specNoExist := true
metadataList := make([]string, 0)
// 验证,自定义属性传过来的全不全
// TODO: Metadata类型从[]map[string]interface{}变为*gjson.Json需要适配
// if assetEntity.Metadata != nil {
// for _, metadata := range assetEntity.Metadata {
// attributeType := gconv.String(gconv.Map(metadata)["type"])
// if attributeType == string(consts.AttributeTypeMultiSelect) {
// metadataList = append(metadataList, attributeType)
// }
// }
// if len(metadataList) != len(specValues) {
// // 如果请求参数中不存在该键,则跳过
// return errors.New("规格参数填写不完整")
// }
// }
// 验证自定义属性和sku名称重不重复
for _, list := range list {
if list.SkuName == skuName {
return errors.New("SKU名称已存在")
}
if !g.IsEmpty(metadataList) && len(metadataList) > 0 {
if !g.IsEmpty(specValues) {
exist := true
// 遍历请求参数 map
for key, subValue := range specValues {
// 1. 检查请求参数 map 中是否存在该键
for _, subValues := range list.SpecValues {
parentValue, ok := subValues[gconv.String(key)]
if ok {
// 2. 检查对应的值是否相等
if reflect.DeepEqual(parentValue, subValue) {
exist = false
} else {
exist = true
break
}
} else {
exist = true
break
}
}
}
if exist {
specNoExist = true
} else {
specNoExist = false
break
}
} else {
return errors.New("规格参数不能为空")
}
}
}
if !specNoExist {
return errors.New("规格参数已存在")
}
return nil
}
// DeleteAssetSku 删除SKU软删除
func (s *assetSku) DeleteAssetSku(ctx context.Context, req *dto.DeleteAssetSkuReq) error {
return dao.AssetSku.DeleteFake(ctx, req)
}
// GetAssetSku 获取SKU详情
func (s *assetSku) GetAssetSku(ctx context.Context, req *dto.GetAssetSkuReq) (res *dto.GetAssetSkuRes, err error) {
one, err := dao.AssetSku.GetOne(ctx, req, false)
if err != nil {
return
}
err = utils.Struct(one, &res)
return
}
// ListAssetSkus 获取SKU列表
func (s *assetSku) ListAssetSkus(ctx context.Context, req *dto.ListAssetSkuReq) (res *dto.ListAssetSkuRes, err error) {
// 查询数据库
list, total, err := dao.AssetSku.List(ctx, req, false)
if err != nil {
return
}
res = &dto.ListAssetSkuRes{
Total: total,
}
err = utils.Struct(list, &res.List)
return
}
// GetAssetSkuModule 获取SKU详情
func (s *assetSku) GetAssetSkuModule(ctx context.Context, req *dto.GetAssetSkuModuleReq) (res *dto.GetAssetSkuModuleRes, err error) {
one, err := dao.AssetSku.GetOne(ctx, &dto.GetAssetSkuReq{Id: req.Id}, true)
if err != nil {
return
}
res = &dto.GetAssetSkuModuleRes{}
// 计算到期时间
if one.SpecsUnit != nil && one.SpecsCount > 0 {
durationType := public.DurationType(one.SpecsUnit.Key)
res.ExpireAt = durationType.AddTime(one.SpecsCount)
res.AssetId = one.AssetId
}
return
}

View 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
}

View File

@@ -0,0 +1,176 @@
package service
import (
dao "assets/dao/asset"
dto "assets/model/dto/asset"
"context"
"github.com/gogf/gf/v2/errors/gerror"
"go.mongodb.org/mongo-driver/v2/bson"
)
type privateCategory struct{}
// PrivateCategory 私域分类服务
var PrivateCategory = new(privateCategory)
// CreatePrivateCategory 创建私域分类
func (s *privateCategory) CreatePrivateCategory(ctx context.Context, req *dto.CreatePrivateCategoryReq) (*dto.CreatePrivateCategoryRes, error) {
// 自动设置level
if !req.ParentID.IsZero() {
parentCategory, err := dao.PrivateCategory.GetOne(ctx, req.ParentID)
if err == nil && parentCategory != nil {
req.Level = parentCategory.Level + 1
req.Path = parentCategory.Path + "/" + parentCategory.Id.Hex()
}
} else {
req.Level = 0
req.Path = "/root"
}
// 保存到数据库
ids, err := dao.PrivateCategory.Insert(ctx, req)
if err != nil {
return nil, gerror.Wrap(err, "创建私域分类失败")
}
var id *bson.ObjectID
if len(ids) > 0 {
if objectID, ok := ids[0].(bson.ObjectID); ok {
id = &objectID
}
}
return &dto.CreatePrivateCategoryRes{ID: id}, nil
}
// BatchCreatePrivateCategory 批量创建私域分类
func (s *privateCategory) BatchCreatePrivateCategory(ctx context.Context, req *dto.BatchCreatePrivateCategoryReq) (*dto.BatchCreatePrivateCategoryRes, error) {
// 保存到数据库
ids, err := dao.PrivateCategory.BatchInsert(ctx, req)
if err != nil {
return nil, gerror.Wrap(err, "批量创建私域分类失败")
}
// 转换ID列表
idList := make([]*bson.ObjectID, 0, len(ids))
for _, id := range ids {
if objectID, ok := id.(bson.ObjectID); ok {
idList = append(idList, &objectID)
}
}
return &dto.BatchCreatePrivateCategoryRes{IDs: idList}, nil
}
// UpdatePrivateCategory 更新私域分类
func (s *privateCategory) UpdatePrivateCategory(ctx context.Context, req *dto.UpdatePrivateCategoryReq) error {
// 更新到数据库
err := dao.PrivateCategory.Update(ctx, req)
if err != nil {
return gerror.Wrap(err, "更新私域分类失败")
}
return nil
}
// DeletePrivateCategory 删除私域分类
func (s *privateCategory) DeletePrivateCategory(ctx context.Context, id *bson.ObjectID) error {
return dao.PrivateCategory.DeleteFake(ctx, id)
}
// GetPrivateCategory 获取私域分类详情
func (s *privateCategory) GetPrivateCategory(ctx context.Context, id *bson.ObjectID) (*dto.GetPrivateCategoryRes, error) {
category, err := dao.PrivateCategory.GetOne(ctx, id)
if err != nil {
return nil, gerror.Wrap(err, "获取私域分类失败")
}
// 转换为响应
res := &dto.GetPrivateCategoryRes{
ID: category.Id,
Name: category.Name,
ParentID: category.ParentID,
Path: category.Path,
Level: category.Level,
IsLeafNode: category.IsLeafNode,
Sort: category.Sort,
Image: category.Image,
CreatedAt: category.CreatedAt.Format("2006-01-02 15:04:05"),
UpdatedAt: category.UpdatedAt.Format("2006-01-02 15:04:05"),
}
return res, nil
}
// ListPrivateCategory 获取私域分类列表
func (s *privateCategory) ListPrivateCategory(ctx context.Context, req *dto.ListPrivateCategoryReq) (*dto.ListPrivateCategoryRes, error) {
// 获取数据
categories, total, err := dao.PrivateCategory.List(ctx, req)
if err != nil {
return nil, gerror.Wrap(err, "获取私域分类列表失败")
}
// 转换为响应
listItems := make([]*dto.PrivateCategoryListItem, 0, len(categories))
for _, category := range categories {
listItems = append(listItems, &dto.PrivateCategoryListItem{
ID: category.Id,
Name: category.Name,
ParentID: category.ParentID,
Path: category.Path,
Level: category.Level,
IsLeafNode: category.IsLeafNode,
Sort: category.Sort,
Image: category.Image,
CreatedAt: category.CreatedAt.Format("2006-01-02 15:04:05"),
UpdatedAt: category.UpdatedAt.Format("2006-01-02 15:04:05"),
})
}
return &dto.ListPrivateCategoryRes{
List: listItems,
Total: total,
}, nil
}
// GetPrivateCategoryTree 获取私域分类树
func (s *privateCategory) GetPrivateCategoryTree(ctx context.Context) (*dto.GetPrivateCategoryTreeRes, error) {
categories, err := dao.PrivateCategory.GetTree(ctx)
if err != nil {
return nil, gerror.Wrap(err, "获取私域分类树失败")
}
// 转换为响应
treeItems := make([]*dto.PrivateCategoryTreeItem, 0, len(categories))
for _, category := range categories {
treeItems = append(treeItems, &dto.PrivateCategoryTreeItem{
ID: category.Id,
Name: category.Name,
ParentID: category.ParentID,
Path: category.Path,
Level: category.Level,
IsLeafNode: category.IsLeafNode,
Sort: category.Sort,
Image: category.Image,
})
}
return &dto.GetPrivateCategoryTreeRes{
Tree: treeItems,
}, nil
}
// GenerateTestData 生成测试数据
func (s *privateCategory) GenerateTestData(ctx context.Context) error {
testData := &dto.BatchCreatePrivateCategoryReq{
Categories: []dto.CreatePrivateCategoryReq{},
}
_, err := s.BatchCreatePrivateCategory(ctx, testData)
if err != nil {
return gerror.Wrap(err, "生成测试数据失败")
}
return nil
}

View File

@@ -0,0 +1,189 @@
package service
import (
dao "assets/dao/asset"
dto "assets/model/dto/asset"
"context"
"github.com/gogf/gf/v2/errors/gerror"
"go.mongodb.org/mongo-driver/v2/bson"
)
type privateSku struct{}
// PrivateSku 私域SKU服务
var PrivateSku = new(privateSku)
// CreatePrivateSku 创建私域SKU
func (s *privateSku) CreatePrivateSku(ctx context.Context, req *dto.CreatePrivateSkuReq) (*dto.CreatePrivateSkuRes, error) {
// 保存到数据库
ids, err := dao.PrivateSku.Insert(ctx, req)
if err != nil {
return nil, gerror.Wrap(err, "创建私域SKU失败")
}
var id *bson.ObjectID
if len(ids) > 0 {
if objectID, ok := ids[0].(bson.ObjectID); ok {
id = &objectID
}
}
return &dto.CreatePrivateSkuRes{ID: id}, nil
}
// BatchCreatePrivateSku 批量创建私域SKU
func (s *privateSku) BatchCreatePrivateSku(ctx context.Context, req *dto.BatchCreatePrivateSkuReq) (*dto.BatchCreatePrivateSkuRes, error) {
// 保存到数据库
ids, err := dao.PrivateSku.BatchInsert(ctx, req)
if err != nil {
return nil, gerror.Wrap(err, "批量创建私域SKU失败")
}
// 转换ID列表
idList := make([]*bson.ObjectID, 0, len(ids))
for _, id := range ids {
if objectID, ok := id.(bson.ObjectID); ok {
idList = append(idList, &objectID)
}
}
return &dto.BatchCreatePrivateSkuRes{IDs: idList}, nil
}
// UpdatePrivateSku 更新私域SKU
func (s *privateSku) UpdatePrivateSku(ctx context.Context, req *dto.UpdatePrivateSkuReq) error {
// 更新到数据库
err := dao.PrivateSku.Update(ctx, req)
if err != nil {
return gerror.Wrap(err, "更新私域SKU失败")
}
return nil
}
// DeletePrivateSku 删除私域SKU
func (s *privateSku) DeletePrivateSku(ctx context.Context, id *bson.ObjectID) error {
return dao.PrivateSku.DeleteFake(ctx, id)
}
// GetPrivateSku 获取私域SKU详情
func (s *privateSku) GetPrivateSku(ctx context.Context, id *bson.ObjectID) (*dto.GetPrivateSkuRes, error) {
sku, err := dao.PrivateSku.GetOne(ctx, id)
if err != nil {
return nil, gerror.Wrap(err, "获取私域SKU失败")
}
// 转换为响应
res := &dto.GetPrivateSkuRes{
ID: sku.Id,
SkuName: sku.SkuName,
ImageURL: sku.ImageURL,
Price: sku.Price,
Stock: sku.Stock,
Sort: sku.Sort,
PrivateCategoryPath: sku.PrivateCategoryPath,
CreatedAt: sku.CreatedAt.Format("2006-01-02 15:04:05"),
UpdatedAt: sku.UpdatedAt.Format("2006-01-02 15:04:05"),
}
return res, nil
}
// ListPrivateSku 获取私域SKU列表
func (s *privateSku) ListPrivateSku(ctx context.Context, req *dto.ListPrivateSkuReq) (*dto.ListPrivateSkuRes, error) {
// 获取数据
skus, total, err := dao.PrivateSku.List(ctx, req)
if err != nil {
return nil, gerror.Wrap(err, "获取私域SKU列表失败")
}
// 转换为响应
listItems := make([]*dto.PrivateSkuListItem, 0, len(skus))
for _, sku := range skus {
listItems = append(listItems, &dto.PrivateSkuListItem{
ID: sku.Id,
SkuName: sku.SkuName,
ImageURL: sku.ImageURL,
Price: sku.Price,
Stock: sku.Stock,
Sort: sku.Sort,
PrivateCategoryPath: sku.PrivateCategoryPath,
CreatedAt: sku.CreatedAt.Format("2006-01-02 15:04:05"),
UpdatedAt: sku.UpdatedAt.Format("2006-01-02 15:04:05"),
})
}
return &dto.ListPrivateSkuRes{
List: listItems,
Total: total,
}, nil
}
// UpdatePrivateSkuStock 更新私域SKU库存
func (s *privateSku) UpdatePrivateSkuStock(ctx context.Context, id *bson.ObjectID, stockChange int) error {
return dao.PrivateSku.UpdateStock(ctx, id, stockChange)
}
// GenerateTestData 生成测试数据
func (s *privateSku) GenerateTestData(ctx context.Context) error {
testData := &dto.BatchCreatePrivateSkuReq{
Skus: []dto.CreatePrivateSkuReq{
{
SkuName: "联想ThinkPad X1 Carbon 14英寸 i7 16G 512G",
ImageURL: "https://example.com/images/lenovo_x1_carbon.jpg",
Price: 899900, // 8999.00元
Stock: 100,
Sort: 1,
PrivateCategoryPath: "/笔记本电脑/ThinkPad",
},
{
SkuName: "联想ThinkPad X1 Carbon 14英寸 i7 32G 1T",
ImageURL: "https://example.com/images/lenovo_x1_carbon_32g.jpg",
Price: 1199900, // 11999.00元
Stock: 50,
Sort: 2,
PrivateCategoryPath: "/笔记本电脑/ThinkPad",
},
{
SkuName: "戴尔Latitude 7440 14英寸 i7 16G 512G",
ImageURL: "https://example.com/images/dell_latitude_7440.jpg",
Price: 750000, // 7500.00元
Stock: 80,
Sort: 1,
PrivateCategoryPath: "/笔记本电脑/Latitude",
},
{
SkuName: "戴尔Latitude 7440 14英寸 i7 32G 1T",
ImageURL: "https://example.com/images/dell_latitude_7440_32g.jpg",
Price: 999900, // 9999.00元
Stock: 60,
Sort: 2,
PrivateCategoryPath: "/笔记本电脑/Latitude",
},
{
SkuName: "惠普暗影精灵9 16.1英寸 i7 32G 1T RTX4060",
ImageURL: "https://example.com/images/hp_omen_9.jpg",
Price: 849900, // 8499.00元
Stock: 70,
Sort: 1,
PrivateCategoryPath: "/游戏笔记本/暗影精灵",
},
{
SkuName: "惠普暗影精灵9 16.1英寸 i9 32G 2T RTX4070",
ImageURL: "https://example.com/images/hp_omen_9_i9.jpg",
Price: 1249900, // 12499.00元
Stock: 40,
Sort: 2,
PrivateCategoryPath: "/游戏笔记本/暗影精灵",
},
},
}
_, err := s.BatchCreatePrivateSku(ctx, testData)
if err != nil {
return gerror.Wrap(err, "生成测试数据失败")
}
return nil
}