refactor: 重构资产模型与DAO层实现

This commit is contained in:
2026-03-19 17:45:06 +08:00
parent 5236c45a39
commit f30141679c
24 changed files with 570 additions and 600 deletions

View File

@@ -1,6 +1,7 @@
server: server:
address: ":3003" address: ":3003"
name: "assets" name: "assets"
workerId: 1
#logPath: "resource/log/server" #logPath: "resource/log/server"
logStdout: true logStdout: true
errorStack: true errorStack: true

View File

@@ -1,17 +1,9 @@
package consts package consts
// AssetSkuStatus SKU状态枚举 // AssetSkuStatus SKU状态枚举
type AssetSkuStatus int
const ( type AssetSkuStatusType *int
AssetSkuStatusActive AssetSkuStatus = 1 // 启用
AssetSkuStatusInactive AssetSkuStatus = 0 // 停用
)
// GetAllSkuStatuses 获取所有SKU状态 type AssetSkuStatus struct {
func GetAllSkuStatuses() []AssetSkuStatus { Status AssetSkuStatusType
return []AssetSkuStatus{
AssetSkuStatusActive,
AssetSkuStatusInactive,
}
} }

View File

@@ -1,17 +1,9 @@
package consts package consts
// AssetStatus 资产状态枚举 // AssetStatus 资产状态枚举
type AssetStatus int
const ( type AssetStatusType *int
AssetStatusActive AssetStatus = 1 // 启用
AssetStatusInactive AssetStatus = 0 // 停用
)
// GetAllAssetStatuses 获取所有资产状态 type AssetStatus struct {
func GetAllAssetStatuses() []AssetStatus { Status AssetStatusType
return []AssetStatus{
AssetStatusActive,
AssetStatusInactive,
}
} }

View File

@@ -5,8 +5,6 @@ type AttributeType string
const ( const (
AttributeTypeText AttributeType = "text" // 文本 AttributeTypeText AttributeType = "text" // 文本
//AttributeTypeNumber AttributeType = "number" // 数字
//AttributeTypeDate AttributeType = "date" // 日期
AttributeTypeSelect AttributeType = "select" // 单选 AttributeTypeSelect AttributeType = "select" // 单选
AttributeTypeMultiSelect AttributeType = "multi_select" // 多选 AttributeTypeMultiSelect AttributeType = "multi_select" // 多选
) )
@@ -15,8 +13,6 @@ const (
func GetAllAttributeTypes() []AttributeType { func GetAllAttributeTypes() []AttributeType {
return []AttributeType{ return []AttributeType{
AttributeTypeText, AttributeTypeText,
//AttributeTypeNumber,
//AttributeTypeDate,
AttributeTypeSelect, AttributeTypeSelect,
AttributeTypeMultiSelect, AttributeTypeMultiSelect,
} }
@@ -30,8 +26,6 @@ type AttrTypeKeyValue struct {
// 定义枚举实例Key-Value 绑定),相当于改造后的常量 // 定义枚举实例Key-Value 绑定),相当于改造后的常量
var ( var (
AttrTypeTextKeyValue = AttrTypeKeyValue{Key: AttributeTypeText, Value: "文本"} AttrTypeTextKeyValue = AttrTypeKeyValue{Key: AttributeTypeText, Value: "文本"}
//AttrTypeNumberKeyValue = AttrTypeKeyValue{Key: AttributeTypeNumber, Value: "数字"}
//AttrTypeDateKeyValue = AttrTypeKeyValue{Key: AttributeTypeDate, Value: "日期"}
AttrTypeSelectKeyValue = AttrTypeKeyValue{Key: AttributeTypeSelect, Value: "单选"} AttrTypeSelectKeyValue = AttrTypeKeyValue{Key: AttributeTypeSelect, Value: "单选"}
AttrTypeMultiSelectKeyValue = AttrTypeKeyValue{Key: AttributeTypeMultiSelect, Value: "多选"} AttrTypeMultiSelectKeyValue = AttrTypeKeyValue{Key: AttributeTypeMultiSelect, Value: "多选"}
) )
@@ -39,8 +33,6 @@ var (
func GetAllAttrTypeKeyValue() []AttrTypeKeyValue { func GetAllAttrTypeKeyValue() []AttrTypeKeyValue {
return []AttrTypeKeyValue{ return []AttrTypeKeyValue{
AttrTypeTextKeyValue, AttrTypeTextKeyValue,
//AttrTypeNumberKeyValue,
//AttrTypeDateKeyValue,
AttrTypeSelectKeyValue, AttrTypeSelectKeyValue,
AttrTypeMultiSelectKeyValue, AttrTypeMultiSelectKeyValue,
} }

View File

@@ -19,92 +19,79 @@ type assetDao struct {
// Insert 插入资产 // Insert 插入资产
func (d *assetDao) Insert(ctx context.Context, req *dto.CreateAssetReq) (id int64, err error) { func (d *assetDao) Insert(ctx context.Context, req *dto.CreateAssetReq) (id int64, err error) {
var result entity.Asset var res *entity.Asset
if err = gconv.Struct(req, &result); err != nil { if err = gconv.Struct(req, &res); err != nil {
return return
} }
return gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).Data(&result).InsertAndGetId() r, err := gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).Data(&res).Insert()
} if err != nil {
// GetOne 获取单个资产
func (d *assetDao) GetOne(ctx context.Context, req *dto.GetAssetReq) (res *entity.Asset, err error) {
err = gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).Where("id", req.Id).Scan(&res)
return return
} }
return r.LastInsertId()
}
// Update 更新资产 // Update 更新资产
func (d *assetDao) Update(ctx context.Context, req *dto.UpdateAssetReq) (err error) { func (d *assetDao) Update(ctx context.Context, req *dto.UpdateAssetReq) (rows int64, err error) {
data := g.Map{ r, err := gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).OmitEmpty().Where(entity.AssetCol.Id, req.Id).Update()
"name": req.Name, if err != nil {
"description": req.Description,
"type": req.Type,
"category_id": req.CategoryId,
"image_url": req.ImageURL,
"images": req.Images,
"status": req.Status,
"online_time": req.OnlineTime,
"offline_time": req.OfflineTime,
"physical_asset_config": req.PhysicalAssetConfig,
"service_asset_config": req.ServiceAssetConfig,
"virtual_asset_config": req.VirtualAssetConfig,
"metadata": req.Metadata,
}
_, err = gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).Where("id", req.Id).Update(data)
return return
} }
return r.RowsAffected()
// DeleteFake 删除资产-根据id进行假删
func (d *assetDao) DeleteFake(ctx context.Context, req *dto.DeleteAssetReq) (err error) {
_, err = gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).Where("id", req.Id).Update(g.Map{
"is_deleted": true,
})
return
} }
// GetOneById 通过ID获取单个资产内部使用uint64 // Delete 删除资产-根据id进行假删
func (d *assetDao) GetOneById(ctx context.Context, id uint64) (res *entity.Asset, err error) { func (d *assetDao) Delete(ctx context.Context, req *dto.DeleteAssetReq) (rows int64, err error) {
err = gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).Where("id", id).Scan(&res) r, err := gfdb.DB(ctx).Model(ctx, public.AssetCollection).Where(entity.AssetCol.Id, req.Id).Delete()
if err != nil {
return
}
return r.RowsAffected()
}
// GetOne 获取单个资产
func (d *assetDao) GetOne(ctx context.Context, req *dto.GetAssetReq, fields ...string) (res *entity.Asset, err error) {
r, err := gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).Where(entity.AssetCol.Id, req.Id).Fields(fields).One()
if err != nil {
return
}
err = r.Struct(&res)
return return
} }
// Count 获取资产数量 // Count 获取资产数量
func (d *assetDao) Count(ctx context.Context, req *dto.ListAssetReq) (count int64, err error) { func (d *assetDao) Count(ctx context.Context, req *dto.ListAssetReq) (count int, err error) {
m := d.buildListFilter(ctx, req) return d.buildListFilter(ctx, req).Count()
c, err := m.Count()
return int64(c), err
} }
// List 获取资产列表 // List 获取资产列表
func (d *assetDao) List(ctx context.Context, req *dto.ListAssetReq) (res []entity.Asset, total int, err error) { func (d *assetDao) List(ctx context.Context, req *dto.ListAssetReq, fields ...string) (res []entity.Asset, total int, err error) {
m := d.buildListFilter(ctx, req) model := d.buildListFilter(ctx, req)
model.Fields(fields)
model.OrderDesc(entity.AssetCol.CreatedAt)
if req.Page != nil { if req.Page != nil {
m = m.Page(int(req.Page.PageNum), int(req.Page.PageSize)) model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
} }
err = m.ScanAndCount(&res, &total, false) r, total, err := model.AllAndCount(false)
if err != nil {
return
}
err = r.Structs(&res)
return return
} }
// buildListFilter 构建列表查询的过滤条件 // buildListFilter 构建列表查询的过滤条件
func (d *assetDao) buildListFilter(ctx context.Context, req *dto.ListAssetReq) *gdb.Model { func (d *assetDao) buildListFilter(ctx context.Context, req *dto.ListAssetReq) *gdb.Model {
m := gfdb.DB(ctx).Model(ctx, public.AssetCollection).Cache(ctx).Where("is_deleted", false) model := gfdb.DB(ctx).Model(ctx, public.AssetCollection).Model
if !g.IsEmpty(req.Keyword) {
if !g.IsEmpty(req.Name) { model.WhereLike(entity.AssetCol.Name, "%"+req.Keyword+"%")
m = m.Where("name", req.Name)
}
if !g.IsEmpty(req.Type) {
m = m.Where("type", req.Type)
}
if !g.IsEmpty(req.CategoryId) {
m = m.Where("category_id", req.CategoryId)
}
if !g.IsEmpty(req.Status) {
m = m.Where("status", req.Status)
} }
if !g.IsEmpty(req.CategoryPath) { if !g.IsEmpty(req.CategoryPath) {
m = m.WhereLike("category_path", req.CategoryPath+"%") model.WhereLike(entity.AssetCol.CategoryPath, req.CategoryPath+"%")
} }
if !g.IsEmpty(req.Keyword) { model.Where(entity.AssetCol.Name, req.Name)
m = m.WhereLike("name", "%"+req.Keyword+"%") model.Where(entity.AssetCol.Type, req.Type)
} model.Where(entity.AssetCol.CategoryId, req.CategoryId)
return m model.Where(entity.AssetCol.Status, req.Status)
model.OmitEmptyWhere()
return model
} }

View File

@@ -6,11 +6,10 @@ import (
"assets/model/entity/asset" "assets/model/entity/asset"
"context" "context"
"gitea.com/red-future/common/beans" "gitea.com/red-future/common/db/gfdb"
"gitea.com/red-future/common/db/mongo" "github.com/gogf/gf/v2/database/gdb"
"gitea.com/red-future/common/utils"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"go.mongodb.org/mongo-driver/v2/bson" "github.com/gogf/gf/v2/util/gconv"
) )
var AssetSku = new(assetSku) var AssetSku = new(assetSku)
@@ -19,112 +18,94 @@ type assetSku struct {
} }
// Insert 插入SKU // Insert 插入SKU
func (d *assetSku) Insert(ctx context.Context, req *dto.CreateAssetSkuReq) (ids []any, err error) { func (d *assetSku) Insert(ctx context.Context, req *dto.CreateAssetSkuReq) (id int64, err error) {
var result *entity.AssetSku var res *entity.AssetSku
if err = utils.Struct(req, &result); err != nil { if err = gconv.Struct(req, &res); err != nil {
return return
} }
ids, err = mongo.DB().Insert(ctx, []interface{}{&result}, public.AssetSkuCollection) r, err := gfdb.DB(ctx).Model(ctx, public.AssetSkuCollection).Ctx(ctx).Data(&res).Insert()
return
}
// Update 更新SKU
func (d *assetSku) Update(ctx context.Context, req *dto.UpdateAssetSkuReq) (err error) {
buildUpdateData, err := mongo.BuildUpdateData(ctx, req)
if err != nil { if err != nil {
return return
} }
filter := bson.M{"_id": req.Id} return r.LastInsertId()
update := bson.M{"$set": buildUpdateData}
if !g.IsEmpty(req.Stock) {
// 从$set中移除stock字段避免$set和$inc冲突
delete(buildUpdateData, "stock")
update = bson.M{
"$inc": bson.M{
"stock": req.Stock,
},
}
if len(buildUpdateData) > 0 {
update["$set"] = buildUpdateData
}
}
_, err = mongo.DB().Update(ctx, filter, update, public.AssetSkuCollection)
return
} }
// DeleteFake 删除SKU-根据id进行假删 // Update 更新SKU
func (d *assetSku) DeleteFake(ctx context.Context, req *dto.DeleteAssetSkuReq) (err error) { func (d *assetSku) Update(ctx context.Context, req *dto.UpdateAssetSkuReq) (rows int64, err error) {
filter := bson.M{"_id": req.Id} r, err := gfdb.DB(ctx).Model(ctx, public.AssetSkuCollection).Ctx(ctx).OmitEmpty().Where(entity.AssetCol.Id, req.Id).Update()
_, err = mongo.DB().DeleteSoft(ctx, filter, public.AssetSkuCollection) if err != nil {
return return
} }
return r.RowsAffected()
}
// Delete 删除SKU-根据id进行假删
func (d *assetSku) Delete(ctx context.Context, req *dto.DeleteAssetSkuReq) (rows int64, err error) {
r, err := gfdb.DB(ctx).Model(ctx, public.AssetSkuCollection).Where(entity.AssetSkuCol.Id, req.Id).Delete()
if err != nil {
return
}
return r.RowsAffected()
}
// GetOne 获取单个SKU // GetOne 获取单个SKU
func (d *assetSku) GetOne(ctx context.Context, req *dto.GetAssetSkuReq, noTenantId bool) (res *entity.AssetSku, err error) { func (d *assetSku) GetOne(ctx context.Context, req *dto.GetAssetSkuReq, fields ...string) (res *entity.AssetSku, err error) {
filter := bson.M{"_id": req.Id} r, err := gfdb.DB(ctx).Model(ctx, public.AssetSkuCollection).Ctx(ctx).Where(entity.AssetCol.Id, req.Id).Fields(fields).One()
if noTenantId { if err != nil {
err = mongo.DB().NoTenantId().FindOne(ctx, filter, &res, public.AssetSkuCollection) return
} else {
err = mongo.DB().FindOne(ctx, filter, &res, public.AssetSkuCollection)
} }
err = r.Struct(&res)
return return
} }
// GetListByAssetIdExcludeCurrentSku 根据资产ID获取SKU列表并且排除当前SKU // GetListByAssetIdExcludeCurrentSku 根据资产ID获取SKU列表并且排除当前SKU
func (d *assetSku) GetListByAssetIdExcludeCurrentSku(ctx context.Context, assetId *bson.ObjectID, req *dto.ListAssetSkuReq) (res []entity.AssetSku, total int64, err error) { func (d *assetSku) GetListByAssetIdExcludeCurrentSku(ctx context.Context, assetId int64, req *dto.ListAssetSkuReq, fields ...string) (res []entity.AssetSku, total int, err error) {
filter := bson.M{"assetId": assetId, "_id": bson.M{"$ne": req.Id}} model := gfdb.DB(ctx).Model(ctx, public.AssetSkuCollection)
total, err = mongo.DB().Find(ctx, filter, &res, public.AssetSkuCollection, req.Page, req.OrderBy) model.Fields(fields)
model.Where(entity.AssetSkuCol.AssetId, assetId)
model.WhereNot(entity.AssetSkuCol.Id, req.Id)
if req.Page != nil {
model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
}
r, total, err := model.AllAndCount(false)
if err != nil {
return
}
err = r.Structs(&res)
return return
} }
// List 获取SKU列表 // List 获取SKU列表
func (d *assetSku) List(ctx context.Context, req *dto.ListAssetSkuReq, noTenantId bool) (res []entity.AssetSku, total int64, err error) { func (d *assetSku) List(ctx context.Context, req *dto.ListAssetSkuReq, fields ...string) (res []entity.AssetSku, total int, err error) {
// 构建查询过滤条件 model := d.buildListFilter(ctx, req)
filter, err := d.buildListFilter(ctx, req) model.Fields(fields)
model.OrderAsc(entity.AssetSkuCol.Sort)
model.OrderDesc(entity.AssetSkuCol.CreatedAt)
if req.Page != nil {
model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
}
r, total, err := model.AllAndCount(false)
if err != nil { if err != nil {
return return
} }
// 排序处理 err = r.Structs(&res)
req.OrderBy = []beans.OrderBy{
{Field: "sort", Order: beans.Asc},
{Field: "createdAt", Order: beans.Desc},
}
if noTenantId {
total, err = mongo.DB().NoTenantId().Find(ctx, filter, &res, public.AssetSkuCollection, req.Page, req.OrderBy)
} else {
total, err = mongo.DB().Find(ctx, filter, &res, public.AssetSkuCollection, req.Page, req.OrderBy)
}
return return
} }
// buildListFilter 构建列表查询的过滤条件 // buildListFilter 构建列表查询的过滤条件
func (d *assetSku) buildListFilter(ctx context.Context, req *dto.ListAssetSkuReq) (filter bson.M, err error) { func (d *assetSku) buildListFilter(ctx context.Context, req *dto.ListAssetSkuReq) *gdb.Model {
_ = ctx model := gfdb.DB(ctx).Model(ctx, public.AssetSkuCollection).Model
filter = bson.M{} if !g.IsEmpty(req.Keyword) {
if !g.IsEmpty(req.AssetId) { model.WhereLike(entity.AssetCol.Name, "%"+req.Keyword+"%")
filter["assetId"] = req.AssetId model.WhereOrLike(entity.AssetSkuCol.SkuName, "%"+req.Keyword+"%")
}
if !g.IsEmpty(req.Status) {
filter["status"] = req.Status
} }
if !g.IsEmpty(req.CategoryPath) { if !g.IsEmpty(req.CategoryPath) {
filter["categoryPath"] = bson.M{"$regex": "^" + req.CategoryPath, "$options": "i"} model.WhereLike(entity.AssetSkuCol.CategoryPath, req.CategoryPath+"%")
} }
if !g.IsEmpty(req.Keyword) { model.Where(entity.AssetSkuCol.Id, req.Id)
orConditions := bson.A{ model.Where(entity.AssetSkuCol.Status, req.Status)
bson.M{"skuName": bson.M{"$regex": req.Keyword, "$options": "i"}}, model.WhereGT(entity.AssetSkuCol.Price, req.MinPrice)
bson.M{"assetName": bson.M{"$regex": req.Keyword, "$options": "i"}}, model.WhereLT(entity.AssetSkuCol.Price, req.MaxPrice)
} model.OmitEmptyWhere()
filter["$or"] = orConditions return model
}
if req.MinPrice > 0 {
filter["price"] = bson.M{"$gte": req.MinPrice}
}
if req.MaxPrice > 0 {
if filter["price"] == nil {
filter["price"] = bson.M{}
}
filter["price"].(bson.M)["$lte"] = req.MaxPrice
}
return
} }

View File

@@ -8,10 +8,8 @@ import (
"gitea.com/red-future/common/db/gfdb" "gitea.com/red-future/common/db/gfdb"
"github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/guid"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
) )
var Category = new(category) var Category = new(category)
@@ -20,63 +18,65 @@ type category struct {
} }
// Insert 插入分类 // Insert 插入分类
func (d *category) Insert(ctx context.Context, req *dto.CreateCategoryReq) (res *entity.Category, err error) { func (d *category) Insert(ctx context.Context, req *dto.CreateCategoryReq) (id int64, err error) {
var res *entity.Category
if err = gconv.Struct(req, &res); err != nil { if err = gconv.Struct(req, &res); err != nil {
return return
} }
res.Bid = guid.S() r, err := gfdb.DB(ctx).Model(ctx, public.CategoryCollection).Insert(&res)
_, err = gfdb.DB(ctx).Model(ctx, public.CategoryCollection).Insert(&res) if err != nil {
return res, nil return
}
return r.LastInsertId()
} }
// Update 更新分类 // Update 更新分类
func (d *category) Update(ctx context.Context, req *dto.UpdateCategoryReq) (err error) { func (d *category) Update(ctx context.Context, req *dto.UpdateCategoryReq) (rows int64, err error) {
model := gfdb.DB(ctx).Model(ctx, public.CategoryCollection).Data(gconv.Map(&req)).OmitEmpty() r, err := gfdb.DB(ctx).Model(ctx, public.CategoryCollection).Data(&req).OmitEmpty().Where(entity.CategoryCol.Id, req.Id).Update()
if !g.IsEmpty(req.Bid) { if err != nil {
model.Where("bid", req.Bid)
}
if !g.IsEmpty(req.Id) {
model.Where("id", req.Id)
}
_, err = model.Update()
return return
} }
return r.RowsAffected()
}
// Delete 删除分类-根据id及父id进行假删
func (d *category) Delete(ctx context.Context, req *dto.DeleteCategoryReq) (rows int64, err error) {
r, err := gfdb.DB(ctx).Model(ctx, public.CategoryCollection).Where(entity.CategoryCol.Id, req.Id).Delete()
if err != nil {
return
}
return r.RowsAffected()
}
// GetOne 获取单个分类 // GetOne 获取单个分类
func (d *category) GetOne(ctx context.Context, req *dto.GetCategoryReq, fields ...string) (category *entity.Category, err error) { func (d *category) GetOne(ctx context.Context, req *dto.GetCategoryReq, fields ...string) (res *entity.Category, err error) {
model := gfdb.DB(ctx).Model(ctx, public.CategoryCollection) r, err := gfdb.DB(ctx).Model(ctx, public.CategoryCollection).Where(entity.CategoryCol.Id, req.Id).Fields(fields).One()
if !g.IsEmpty(req.Bid) { if err != nil {
model.Where(entity.CategoryCol.Bid, req.Bid)
}
if !g.IsEmpty(req.Id) {
model.Where(entity.CategoryCol.Id, req.Id)
}
res, err := model.Fields(fields).One()
err = res.Struct(&category)
return return
} }
err = r.Struct(&res)
// DeleteFake 删除分类-根据id及父id进行假删
func (d *category) DeleteFake(ctx context.Context, req *dto.DeleteCategoryReq) (err error) {
model := gfdb.DB(ctx).Model(ctx, public.CategoryCollection)
model.Where(entity.CategoryCol.Bid, req.Bid)
_, err = model.Delete()
return return
} }
// Count 根据条件统计分类数量 // Count 根据条件统计分类数量
func (d *category) Count(ctx context.Context, req *dto.ListCategoryReq) (count int64, err error) { func (d *category) Count(ctx context.Context, req *dto.ListCategoryReq) (count int, err error) {
m := d.buildListFilter(ctx, req) return d.buildListFilter(ctx, req).Count()
c, err := m.Count()
return int64(c), err
} }
// List 获取分类列表 // List 获取分类列表
func (d *category) List(ctx context.Context, req *dto.ListCategoryReq, fields ...string) (res []entity.Category, total int, err error) { func (d *category) List(ctx context.Context, req *dto.ListCategoryReq, fields ...string) (res []entity.Category, total int, err error) {
model := d.buildListFilter(ctx, req) model := d.buildListFilter(ctx, req)
model.Fields(fields) model.Fields(fields)
model.OrderAsc(entity.CategoryCol.Sort)
model.OrderDesc(entity.CategoryCol.CreatedAt)
if req.Page != nil {
model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
}
r, total, err := model.AllAndCount(false) r, total, err := model.AllAndCount(false)
err = gconv.Structs(r.List(), &res) if err != nil {
return
}
err = r.Structs(&res)
return return
} }
@@ -88,8 +88,6 @@ func (d *category) buildListFilter(ctx context.Context, req *dto.ListCategoryReq
} }
model.Where(entity.CategoryCol.ParentId, req.ParentId) model.Where(entity.CategoryCol.ParentId, req.ParentId)
model.Where(entity.CategoryCol.Status, req.Status) model.Where(entity.CategoryCol.Status, req.Status)
model.OrderAsc(entity.CategoryCol.Sort)
model.OrderDesc(entity.CategoryCol.CreatedAt)
model.OmitEmptyWhere() model.OmitEmptyWhere()
return model return model
} }

View File

@@ -39,7 +39,7 @@ func (d *stockDetails) DeleteManyByIds(ctx context.Context, allStockIds []*bson.
} }
// GetStockCountBySkuId 获取库存数根据SKU ID // GetStockCountBySkuId 获取库存数根据SKU ID
func (d *stockDetails) GetStockCountBySkuId(ctx context.Context, assetSkuId *bson.ObjectID) (total int64, err error) { func (d *stockDetails) GetStockCountBySkuId(ctx context.Context, assetSkuId int64) (total int64, err error) {
// 构建查询过滤条件 // 构建查询过滤条件
filter := bson.M{} filter := bson.M{}
filter["assetSkuId"] = assetSkuId filter["assetSkuId"] = assetSkuId

View File

@@ -5,13 +5,10 @@ import (
"assets/consts/stock" "assets/consts/stock"
"assets/model/config" "assets/model/config"
enumDto "assets/model/dto/enum" enumDto "assets/model/dto/enum"
entity "assets/model/entity/asset"
"time"
"gitea.com/red-future/common/beans" "gitea.com/red-future/common/beans"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
"go.mongodb.org/mongo-driver/v2/bson"
) )
// CreateAssetReq 创建资产请求 // CreateAssetReq 创建资产请求
@@ -21,16 +18,15 @@ type CreateAssetReq struct {
Name string `json:"name" v:"required" dc:"资产名称"` Name string `json:"name" v:"required" dc:"资产名称"`
Description string `json:"description" dc:"资产描述"` Description string `json:"description" dc:"资产描述"`
Type consts.AssetType `json:"type" v:"required" dc:"资产类型physical实物/virtual虚拟/service服务"` Type consts.AssetType `json:"type" v:"required" dc:"资产类型physical实物/virtual虚拟/service服务"`
CategoryId uint64 `json:"categoryId" v:"required" dc:"分类ID"` CategoryId int64 `json:"categoryId" v:"required" dc:"分类ID"`
CategoryPath string `json:"categoryPath" dc:"分类路径"` CategoryPath string `json:"categoryPath" dc:"分类路径"`
ImageURL string `json:"imageUrl" dc:"主图URL"` ImageURL string `json:"imageUrl" dc:"主图URL"`
Images []string `json:"images" dc:"图片列表"` Images []string `json:"images" dc:"图片列表"`
Status *consts.AssetStatus `json:"status" dc:"状态1/0" d:"1"` Status consts.AssetStatusType `json:"status" dc:"状态1/0" d:"1"`
UnlimitedStock bool `json:"unlimitedStock" dc:"是否无库存限制"` UnlimitedStock bool `json:"unlimitedStock" dc:"是否无库存限制"`
StockMode stock.StockMode `json:"stockMode" dc:"库存管理模式1-明细模式 2-批次模式" d:"2"` StockMode stock.StockMode `json:"stockMode" dc:"库存管理模式1-明细模式 2-批次模式" d:"2"`
// 上线和下线时间配置(由定时任务处理资产状态) OnlineTime *gtime.Time `json:"onlineTime,omitempty" dc:"上线时间格式2006-01-02 15:04:05"`
OnlineTime *time.Time `json:"onlineTime,omitempty" dc:"线时间格式2006-01-02 15:04:05"` OfflineTime *gtime.Time `json:"offlineTime,omitempty" dc:"线时间格式2006-01-02 15:04:05"`
OfflineTime *time.Time `json:"offlineTime,omitempty" dc:"下线时间格式2006-01-02 15:04:05"`
// 类型专用配置 - 实物资产配置 // 类型专用配置 - 实物资产配置
PhysicalAssetConfig *config.PhysicalAssetConfig `json:"physicalAssetConfig"` PhysicalAssetConfig *config.PhysicalAssetConfig `json:"physicalAssetConfig"`
// 类型专用配置 - 服务资产配置 // 类型专用配置 - 服务资产配置
@@ -45,37 +41,36 @@ type CreateAssetReq struct {
// CreateAssetRes 创建资产响应 // CreateAssetRes 创建资产响应
type CreateAssetRes struct { type CreateAssetRes struct {
Id uint64 `json:"id" dc:"资产ID"` Id int64 `json:"id" dc:"资产ID"`
} }
// ListAssetReq 获取资产列表请求 // ListAssetReq 获取资产列表请求
type ListAssetReq struct { type ListAssetReq struct {
g.Meta `path:"/listAssets" method:"get" tags:"资产管理" summary:"获取资产列表" dc:"分页查询资产列表,支持多条件筛选"` g.Meta `path:"/listAssets" method:"get" tags:"资产管理" summary:"获取资产列表" dc:"分页查询资产列表,支持多条件筛选"`
*beans.Page *beans.Page
OrderBy []beans.OrderBy `json:"orderBy" dc:"排序规则"`
Name string `json:"name" dc:"资产名称"` Name string `json:"name" dc:"资产名称"`
Type consts.AssetType `json:"type" dc:"资产类型"` Type consts.AssetType `json:"type" dc:"资产类型"`
CategoryId string `json:"categoryId" dc:"分类ID"` CategoryId int64 `json:"categoryId" dc:"分类ID"`
CategoryPath string `json:"categoryPath" dc:"分类路径"` CategoryPath string `json:"categoryPath" dc:"分类路径"`
Status *consts.AssetStatus `json:"status" dc:"状态"` Status consts.AssetStatusType `json:"status" dc:"状态"`
TenantModuleType beans.TenantModuleType `json:"tenantModuleType" dc:"租户模块类型"`
Keyword string `json:"keyword" dc:"关键词搜索"` Keyword string `json:"keyword" dc:"关键词搜索"`
} }
// ListAssetRes 获取资产列表响应 // ListAssetRes 获取资产列表响应
type ListAssetRes struct { type ListAssetRes struct {
List []AssetListItem `json:"list" dc:"资产列表"` List []AssetItem `json:"list" dc:"资产列表"`
Total int `json:"total" dc:"总数"` Total int `json:"total" dc:"总数"`
} }
type AssetListItem struct { type AssetItem struct {
// 基础信息 Id int64 `json:"id"` // 资产ID
Id uint64 `json:"id"` // 资产ID
Name string `json:"name"` // 资产名称 Name string `json:"name"` // 资产名称
Type consts.AssetType `json:"type"` // 资产类型physical实物/virtual虚拟/service服务 Type consts.AssetType `json:"type"` // 资产类型physical实物/virtual虚拟/service服务
TypeName string `json:"typeName"` // 资产类型physical实物/virtual虚拟/service服务 TypeName string `json:"typeName"` // 资产类型physical实物/virtual虚拟/service服务
CategoryId uint64 `json:"categoryId"` // 分类ID CategoryId int64 `json:"categoryId"` // 分类ID
UnlimitedStock bool `json:"unlimitedStock"` // 是否无库存限制 UnlimitedStock bool `json:"unlimitedStock"` // 是否无库存限制
Status *consts.AssetStatus `json:"status"` // 资产状态active启用/inactive停用 Status consts.AssetStatusType `json:"status"` // 资产状态active启用/inactive停用
BasePrice int `json:"basePrice"` // 基础价格(分为单位) BasePrice int `json:"basePrice"` // 基础价格(分为单位)
OnlineTime *gtime.Time `json:"onlineTime,omitempty"` // 上线时间 OnlineTime *gtime.Time `json:"onlineTime,omitempty"` // 上线时间
OfflineTime *gtime.Time `json:"offlineTime,omitempty"` // 下线时间 OfflineTime *gtime.Time `json:"offlineTime,omitempty"` // 下线时间
@@ -86,12 +81,12 @@ type AssetListItem struct {
// GetAssetReq 获取资产详情请求 // GetAssetReq 获取资产详情请求
type GetAssetReq struct { type GetAssetReq struct {
g.Meta `path:"/getAsset" method:"get" tags:"资产管理" summary:"获取资产详情" dc:"获取资产详情"` g.Meta `path:"/getAsset" method:"get" tags:"资产管理" summary:"获取资产详情" dc:"获取资产详情"`
Id *bson.ObjectID `json:"id" v:"required" dc:"资产ID"` Id int64 `json:"id" v:"required" dc:"资产ID"`
} }
// GetAssetRes 获取资产详情响应 // GetAssetRes 获取资产详情响应
type GetAssetRes struct { type GetAssetRes struct {
*entity.Asset *AssetItem
CategoryName string `json:"categoryName" dc:"分类名称"` CategoryName string `json:"categoryName" dc:"分类名称"`
ImgAddressPrefix string `json:"imgAddressPrefix"` ImgAddressPrefix string `json:"imgAddressPrefix"`
} }
@@ -99,13 +94,13 @@ type GetAssetRes struct {
// GetAssetAndSkuReq 获取资产和Sku详情请求 // GetAssetAndSkuReq 获取资产和Sku详情请求
type GetAssetAndSkuReq struct { type GetAssetAndSkuReq struct {
g.Meta `path:"/getAssetAndSku" method:"get" tags:"资产管理" summary:"获取资产和SKU详情" dc:"获取资产和SKU详情"` g.Meta `path:"/getAssetAndSku" method:"get" tags:"资产管理" summary:"获取资产和SKU详情" dc:"获取资产和SKU详情"`
AssetId *bson.ObjectID `json:"assetId" v:"required" dc:"资产ID"` Id int64 `json:"id" v:"required" dc:"资产ID"`
} }
// GetAssetAndSkuRes 获取资产详情响应 // GetAssetAndSkuRes 获取资产详情响应
type GetAssetAndSkuRes struct { type GetAssetAndSkuRes struct {
*entity.Asset *AssetItem
Skus []entity.AssetSku `json:"skus" dc:"SKU列表"` Skus []AssetSkuItem `json:"skus" dc:"SKU列表"`
TenantModuleType []enumDto.KeyValue `json:"tenantModuleType" dc:"租户模块类型"` TenantModuleType []enumDto.KeyValue `json:"tenantModuleType" dc:"租户模块类型"`
ImgAddressPrefix string `json:"imgAddressPrefix"` ImgAddressPrefix string `json:"imgAddressPrefix"`
} }
@@ -113,18 +108,16 @@ type GetAssetAndSkuRes struct {
// UpdateAssetReq 更新资产请求 // UpdateAssetReq 更新资产请求
type UpdateAssetReq struct { type UpdateAssetReq struct {
g.Meta `path:"/updateAsset" method:"put" tags:"资产管理" summary:"更新资产" dc:"更新资产信息"` g.Meta `path:"/updateAsset" method:"put" tags:"资产管理" summary:"更新资产" dc:"更新资产信息"`
Id *bson.ObjectID `json:"id" v:"required" dc:"资产ID"` Id int64 `json:"id" v:"required" dc:"资产ID"`
// 基础信息
Name string `json:"name" dc:"资产名称"` Name string `json:"name" dc:"资产名称"`
Description string `json:"description" dc:"资产描述"` Description string `json:"description" dc:"资产描述"`
Type consts.AssetType `json:"type" dc:"资产类型physical实物/virtual虚拟/service服务"` Type consts.AssetType `json:"type" dc:"资产类型physical实物/virtual虚拟/service服务"`
CategoryId *bson.ObjectID `json:"categoryId" dc:"分类ID"` CategoryId int64 `json:"categoryId" dc:"分类ID"`
ImageURL string `json:"imageUrl" dc:"主图URL"` ImageURL string `json:"imageUrl" dc:"主图URL"`
Images []string `json:"images" dc:"图片列表"` Images []string `json:"images" dc:"图片列表"`
Status *consts.AssetStatus `json:"status,omitempty" dc:"状态1/0"` Status consts.AssetStatusType `json:"status,omitempty" dc:"状态1/0"`
// 上线和下线时间配置(由定时任务处理资产状态) OnlineTime *gtime.Time `json:"onlineTime,omitempty" dc:"上线时间格式2006-01-02 15:04:05"`
OnlineTime *time.Time `json:"onlineTime,omitempty" dc:"线时间格式2006-01-02 15:04:05"` OfflineTime *gtime.Time `json:"offlineTime,omitempty" dc:"线时间格式2006-01-02 15:04:05"`
OfflineTime *time.Time `json:"offlineTime,omitempty" dc:"下线时间格式2006-01-02 15:04:05"`
// 类型专用配置 - 实物资产配置 // 类型专用配置 - 实物资产配置
PhysicalAssetConfig *config.PhysicalAssetConfig `json:"physicalAssetConfig"` PhysicalAssetConfig *config.PhysicalAssetConfig `json:"physicalAssetConfig"`
// 类型专用配置 - 服务资产配置 // 类型专用配置 - 服务资产配置
@@ -138,12 +131,12 @@ type UpdateAssetReq struct {
// UpdateAssetStatusReq 更新资产状态请求 // UpdateAssetStatusReq 更新资产状态请求
type UpdateAssetStatusReq struct { type UpdateAssetStatusReq struct {
g.Meta `path:"/updateAssetStatus" method:"put" tags:"资产管理" summary:"更新资产状态" dc:"更新资产状态"` g.Meta `path:"/updateAssetStatus" method:"put" tags:"资产管理" summary:"更新资产状态" dc:"更新资产状态"`
Id *bson.ObjectID `json:"id" v:"required" dc:"资产ID"` Id int64 `json:"id" v:"required" dc:"资产ID"`
Status *consts.AssetStatus `json:"status" v:"required|in:1,0" dc:"状态1启用/0停用"` Status consts.AssetStatusType `json:"status" v:"required|in:1,0" dc:"状态1启用/0停用"`
} }
// DeleteAssetReq 删除资产请求 // DeleteAssetReq 删除资产请求
type DeleteAssetReq struct { type DeleteAssetReq struct {
g.Meta `path:"/deleteAsset" method:"delete" tags:"资产管理" summary:"删除资产" dc:"删除资产"` g.Meta `path:"/deleteAsset" method:"delete" tags:"资产管理" summary:"删除资产" dc:"删除资产"`
Id *bson.ObjectID `json:"id" v:"required" dc:"资产ID"` Id int64 `json:"id" v:"required" dc:"资产ID"`
} }

View File

@@ -8,14 +8,13 @@ import (
"gitea.com/red-future/common/beans" "gitea.com/red-future/common/beans"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
"go.mongodb.org/mongo-driver/v2/bson"
) )
// CreateAssetSkuReq 创建SKU请求 // CreateAssetSkuReq 创建SKU请求
type CreateAssetSkuReq struct { type CreateAssetSkuReq struct {
g.Meta `path:"/createAssetSku" method:"post" tags:"SKU管理" summary:"创建SKU" dc:"创建新的资产SKU"` g.Meta `path:"/createAssetSku" method:"post" tags:"SKU管理" summary:"创建SKU" dc:"创建新的资产SKU"`
AssetId *bson.ObjectID `json:"assetId" v:"required" dc:"关联资产ID"` AssetId int64 `json:"assetId" v:"required" dc:"关联资产ID"`
AssetName string `json:"assetName" v:"required" dc:"关联资产名称"` AssetName string `json:"assetName" v:"required" dc:"关联资产名称"`
SkuName string `json:"skuName" v:"required" dc:"SKU名称"` SkuName string `json:"skuName" v:"required" dc:"SKU名称"`
SpecsCount int `json:"specsCount" v:"required|min:1" dc:"规格数量"` SpecsCount int `json:"specsCount" v:"required|min:1" dc:"规格数量"`
@@ -24,24 +23,24 @@ type CreateAssetSkuReq struct {
ImageURL string `json:"imageUrl" v:"required" dc:"SKU主图"` ImageURL string `json:"imageUrl" v:"required" dc:"SKU主图"`
Price int `json:"price" v:"required|min:0" dc:"价格(分为单位)"` Price int `json:"price" v:"required|min:0" dc:"价格(分为单位)"`
Sort int `json:"sort" v:"required|min:0" dc:"排序"` Sort int `json:"sort" v:"required|min:0" dc:"排序"`
Status *consts.AssetSkuStatus `json:"status" v:"required|in:1,0" dc:"状态"` Status consts.AssetSkuStatusType `json:"status" v:"required|in:1,0" dc:"状态"`
UnlimitedStock bool `json:"unlimitedStock" v:"required" dc:"是否无库存限制"` UnlimitedStock bool `json:"unlimitedStock" v:"required" dc:"是否无库存限制"`
StockMode stock.StockMode `json:"stockMode" dc:"库存管理模式:1-明细模式 2-批次模式"` StockMode stock.StockMode `json:"stockMode" dc:"库存管理模式:1-明细模式 2-批次模式"`
CategoryId *bson.ObjectID `json:"categoryId" dc:"分类ID"` CategoryId int64 `json:"categoryId" dc:"分类ID"`
CategoryPath string `json:"categoryPath" dc:"分类路径"` CategoryPath string `json:"categoryPath" dc:"分类路径"`
TenantModuleType beans.TenantModuleType `json:"tenantModuleType" dc:"租户模块类型"` TenantModuleType beans.TenantModuleType `json:"tenantModuleType" dc:"租户模块类型"`
} }
// CreateAssetSkuRes 创建SKU响应 // CreateAssetSkuRes 创建SKU响应
type CreateAssetSkuRes struct { type CreateAssetSkuRes struct {
Id *bson.ObjectID `json:"id" dc:"SKU ID"` Id int64 `json:"id" dc:"SKU ID"`
} }
// UpdateAssetSkuReq 更新SKU请求 // UpdateAssetSkuReq 更新SKU请求
type UpdateAssetSkuReq struct { type UpdateAssetSkuReq struct {
g.Meta `path:"/updateAssetSku" method:"put" tags:"SKU管理" summary:"更新SKU" dc:"更新SKU信息"` g.Meta `path:"/updateAssetSku" method:"put" tags:"SKU管理" summary:"更新SKU" dc:"更新SKU信息"`
Id *bson.ObjectID `json:"id" v:"required" dc:"SKU ID"` Id int64 `json:"id" v:"required" dc:"SKU ID"`
SkuName string `json:"skuName" dc:"SKU名称"` SkuName string `json:"skuName" dc:"SKU名称"`
SpecsCount int `json:"specsCount" dc:"规格数量"` SpecsCount int `json:"specsCount" dc:"规格数量"`
SpecsUnit *entity.SpecsUnitKeyValue `json:"specsUnit" dc:"规格单位"` SpecsUnit *entity.SpecsUnitKeyValue `json:"specsUnit" dc:"规格单位"`
@@ -50,36 +49,36 @@ type UpdateAssetSkuReq struct {
Price int `json:"price" dc:"价格(分为单位)"` Price int `json:"price" dc:"价格(分为单位)"`
Sort int `json:"sort" dc:"排序"` Sort int `json:"sort" dc:"排序"`
Stock int `json:"stock" dc:"库存数量"` Stock int `json:"stock" dc:"库存数量"`
Status *consts.AssetSkuStatus `json:"status" dc:"状态"` Status consts.AssetSkuStatusType `json:"status" dc:"状态"`
} }
// DeleteAssetSkuReq 删除SKU请求 // DeleteAssetSkuReq 删除SKU请求
type DeleteAssetSkuReq struct { type DeleteAssetSkuReq struct {
g.Meta `path:"/deleteAssetSku" method:"delete" tags:"SKU管理" summary:"删除SKU" dc:"删除SKU"` g.Meta `path:"/deleteAssetSku" method:"delete" tags:"SKU管理" summary:"删除SKU" dc:"删除SKU"`
Id *bson.ObjectID `json:"id" v:"required" dc:"SKU ID"` Id int64 `json:"id" v:"required" dc:"SKU ID"`
} }
// GetAssetSkuModuleReq 获取SKU详情请求 // GetAssetSkuModuleReq 获取SKU详情请求
type GetAssetSkuModuleReq struct { type GetAssetSkuModuleReq struct {
g.Meta `path:"/getAssetSkuModule" method:"get" tags:"SKU管理" summary:"获取SKU模块详情" dc:"获取SKU模块详情"` g.Meta `path:"/getAssetSkuModule" method:"get" tags:"SKU管理" summary:"获取SKU模块详情" dc:"获取SKU模块详情"`
Id *bson.ObjectID `json:"id" v:"required" dc:"SKU ID"` Id int64 `json:"id" v:"required" dc:"SKU ID"`
} }
// GetAssetSkuModuleRes 获取SKU详情响应 // GetAssetSkuModuleRes 获取SKU详情响应
type GetAssetSkuModuleRes struct { type GetAssetSkuModuleRes struct {
AssetId *bson.ObjectID `json:"assetId"` AssetId int64 `json:"assetId"`
ExpireAt *gtime.Time `json:"expireAt"` ExpireAt *gtime.Time `json:"expireAt"`
} }
// GetAssetSkuReq 获取SKU详情请求 // GetAssetSkuReq 获取SKU详情请求
type GetAssetSkuReq struct { type GetAssetSkuReq struct {
g.Meta `path:"/getAssetSku" method:"get" tags:"SKU管理" summary:"获取SKU详情" dc:"获取SKU详情"` g.Meta `path:"/getAssetSku" method:"get" tags:"SKU管理" summary:"获取SKU详情" dc:"获取SKU详情"`
Id *bson.ObjectID `json:"id" v:"required" dc:"SKU ID"` Id int64 `json:"id" v:"required" dc:"SKU ID"`
} }
// GetAssetSkuRes 获取SKU详情响应 // GetAssetSkuRes 获取SKU详情响应
type GetAssetSkuRes struct { type GetAssetSkuRes struct {
*entity.AssetSku *AssetSkuItem
ImgAddressPrefix string `json:"imgAddressPrefix"` ImgAddressPrefix string `json:"imgAddressPrefix"`
} }
@@ -87,10 +86,9 @@ type GetAssetSkuRes struct {
type ListAssetSkuReq struct { type ListAssetSkuReq struct {
g.Meta `path:"/listAssetSkus" method:"get" tags:"SKU管理" summary:"获取SKU列表" dc:"分页查询SKU列表支持多条件筛选"` g.Meta `path:"/listAssetSkus" method:"get" tags:"SKU管理" summary:"获取SKU列表" dc:"分页查询SKU列表支持多条件筛选"`
*beans.Page *beans.Page
OrderBy []beans.OrderBy `json:"orderBy" dc:"排序规则"` Id int64 `json:"id" dc:"SKU ID"`
Id *bson.ObjectID `json:"id" dc:"SKU ID"` AssetId int64 `json:"assetId" v:"required" dc:"资产ID"`
AssetId *bson.ObjectID `json:"assetId" v:"required" dc:"资产ID"` Status consts.AssetSkuStatusType `json:"status" dc:"状态"`
Status *consts.AssetSkuStatus `json:"status" dc:"状态"`
Keyword string `json:"keyword" dc:"关键词搜索"` Keyword string `json:"keyword" dc:"关键词搜索"`
MinPrice int `json:"minPrice" dc:"最低价格"` MinPrice int `json:"minPrice" dc:"最低价格"`
MaxPrice int `json:"maxPrice" dc:"最高价格"` MaxPrice int `json:"maxPrice" dc:"最高价格"`
@@ -99,13 +97,13 @@ type ListAssetSkuReq struct {
// ListAssetSkuRes 获取SKU列表响应 // ListAssetSkuRes 获取SKU列表响应
type ListAssetSkuRes struct { type ListAssetSkuRes struct {
List []*AssetSkuListResItem `json:"list" dc:"SKU列表"` List []AssetSkuItem `json:"list" dc:"SKU列表"`
Total int64 `json:"total" dc:"总数"` Total int `json:"total" dc:"总数"`
} }
type AssetSkuListResItem struct { type AssetSkuItem struct {
Id *bson.ObjectID `json:"id"` // SKU ID Id int64 `json:"id"` // SKU ID
AssetId *bson.ObjectID `json:"assetId"` AssetId int64 `json:"assetId"`
AssetName string `json:"assetName"` // 资产名称 AssetName string `json:"assetName"` // 资产名称
SkuName string `json:"skuName"` // SKU名称 SkuName string `json:"skuName"` // SKU名称
SpecsCount int `json:"specsCount"` // 规格数量 SpecsCount int `json:"specsCount"` // 规格数量
@@ -115,7 +113,7 @@ type AssetSkuListResItem struct {
UnlimitedStock bool `json:"unlimitedStock"` // 是否无库存限制 UnlimitedStock bool `json:"unlimitedStock"` // 是否无库存限制
Stock int `json:"stock"` // 库存数量 Stock int `json:"stock"` // 库存数量
Sort int `json:"sort"` // 排序 Sort int `json:"sort"` // 排序
Status *consts.AssetSkuStatus `json:"status"` // 状态active/inactive/disabled Status consts.AssetSkuStatusType `json:"status"` // 状态active/inactive/disabled
StockMode stock.StockMode `json:"stockMode"` // 库存管理模式1-明细模式 2-批次模式 StockMode stock.StockMode `json:"stockMode"` // 库存管理模式1-明细模式 2-批次模式
CreatedAt *gtime.Time `json:"createdAt"` // 创建时间 CreatedAt *gtime.Time `json:"createdAt"` // 创建时间
UpdatedAt *gtime.Time `json:"updatedAt"` // 更新时间 UpdatedAt *gtime.Time `json:"updatedAt"` // 更新时间

View File

@@ -13,7 +13,8 @@ import (
type CreateCategoryReq struct { type CreateCategoryReq struct {
g.Meta `path:"/createCategory" method:"post" tags:"分类管理" summary:"创建分类" dc:"创建新的分类"` g.Meta `path:"/createCategory" method:"post" tags:"分类管理" summary:"创建分类" dc:"创建新的分类"`
Name string `json:"name" v:"required" dc:"分类名称"` Name string `json:"name" v:"required" dc:"分类名称"`
ParentId string `json:"parentId" dc:"父分类ID"` ParentId int64 `json:"parentId" dc:"父分类ID"`
IsLeafNode *bool `json:"isLeafNode" dc:"是否叶子节点"`
Image string `json:"image" dc:"分类图片"` Image string `json:"image" dc:"分类图片"`
Sort int `json:"sort" dc:"排序"` Sort int `json:"sort" dc:"排序"`
Path string `json:"path" dc:"分类路径"` Path string `json:"path" dc:"分类路径"`
@@ -24,19 +25,18 @@ type CreateCategoryReq struct {
// CreateCategoryRes 创建分类响应 // CreateCategoryRes 创建分类响应
type CreateCategoryRes struct { type CreateCategoryRes struct {
Bid string `json:"bid" dc:"分类ID"` Id int64 `json:"id,string" dc:"分类ID"`
} }
// UpdateCategoryReq 更新分类请求 // UpdateCategoryReq 更新分类请求
type UpdateCategoryReq struct { type UpdateCategoryReq struct {
g.Meta `path:"/updateCategory" method:"put" tags:"分类管理" summary:"更新分类" dc:"更新分类信息"` g.Meta `path:"/updateCategory" method:"put" tags:"分类管理" summary:"更新分类" dc:"更新分类信息"`
Id uint64 `json:"id" v:"required-without:Bid|integer#Id不能为空|Id必须是整数" dc:"分类ID"` Id int64 `json:"id" v:"required" dc:"分类ID"`
Bid string `json:"bid" v:"required-without:Id|string#Bid不能为空|Bid必须是字符串" dc:"分类ID"`
Name string `json:"name" dc:"分类名称"` Name string `json:"name" dc:"分类名称"`
ParentId string `json:"parentId" dc:"父分类ID"` ParentId int64 `json:"parentId" dc:"父分类ID"`
Image string `json:"image" dc:"分类图片"` Image string `json:"image" dc:"分类图片"`
Sort int `json:"sort" dc:"排序"` Sort int `json:"sort" dc:"排序"`
IsLeafNode bool `json:"isLeafNode" dc:"是否叶子节点"` IsLeafNode *bool `json:"isLeafNode" dc:"是否叶子节点"`
Attrs []entity.CategoryAttr `json:"attrs" dc:"分类属性"` Attrs []entity.CategoryAttr `json:"attrs" dc:"分类属性"`
Status consts.CategoryStatusType `json:"status" dc:"状态1启用0禁用"` Status consts.CategoryStatusType `json:"status" dc:"状态1启用0禁用"`
} }
@@ -44,14 +44,14 @@ type UpdateCategoryReq struct {
// UpdateCategoryStatusReq 更新分类状态请求 // UpdateCategoryStatusReq 更新分类状态请求
type UpdateCategoryStatusReq struct { type UpdateCategoryStatusReq struct {
g.Meta `path:"/updateCategoryStatus" method:"put" tags:"分类管理" summary:"更新分类状态" dc:"更新分类状态"` g.Meta `path:"/updateCategoryStatus" method:"put" tags:"分类管理" summary:"更新分类状态" dc:"更新分类状态"`
Id string `json:"id" v:"required" dc:"分类ID"` Id int64 `json:"id" v:"required" dc:"分类ID"`
Status consts.CategoryStatusType `json:"status" v:"in:1,0" dc:"状态1启用0禁用"` Status consts.CategoryStatusType `json:"status" v:"in:1,0" dc:"状态1启用0禁用"`
} }
// DeleteCategoryReq 删除分类请求 // DeleteCategoryReq 删除分类请求
type DeleteCategoryReq struct { type DeleteCategoryReq struct {
g.Meta `path:"/deleteCategory" method:"delete" tags:"分类管理" summary:"删除分类" dc:"删除分类"` g.Meta `path:"/deleteCategory" method:"delete" tags:"分类管理" summary:"删除分类" dc:"删除分类"`
Bid string `json:"bid" v:"required" dc:"分类ID"` Id int64 `json:"id" v:"required" dc:"分类ID"`
} }
// GetCategoryTreeReq 获取分类树请求 // GetCategoryTreeReq 获取分类树请求
@@ -67,8 +67,7 @@ type GetCategoryTreeRes struct {
// CategoryTreeNode 分类树节点 // CategoryTreeNode 分类树节点
type CategoryTreeNode struct { type CategoryTreeNode struct {
Id uint64 `json:"id" dc:"分类ID"` Id int64 `json:"id,string" dc:"分类ID"`
Bid string `json:"bid" dc:"分类ID"`
Name string `json:"name" dc:"分类名称"` Name string `json:"name" dc:"分类名称"`
Level int `json:"level" dc:"分类层级"` Level int `json:"level" dc:"分类层级"`
Type string `json:"type" dc:"分类类型"` Type string `json:"type" dc:"分类类型"`
@@ -85,8 +84,7 @@ type CategoryTreeNode struct {
type ListCategoryReq struct { type ListCategoryReq struct {
g.Meta `path:"/listCategories" method:"get" tags:"分类管理" summary:"获取分类列表" dc:"获取分类列表"` g.Meta `path:"/listCategories" method:"get" tags:"分类管理" summary:"获取分类列表" dc:"获取分类列表"`
*beans.Page *beans.Page
OrderBy []beans.OrderBy `json:"orderBy" dc:"排序规则"` ParentId int64 `json:"parentId" dc:"父分类ID"`
ParentId string `json:"parentId" dc:"父分类ID"`
Status consts.CategoryStatusType `json:"status" dc:"状态1启用0禁用"` Status consts.CategoryStatusType `json:"status" dc:"状态1启用0禁用"`
Keyword string `json:"keyword" dc:"关键词搜索"` Keyword string `json:"keyword" dc:"关键词搜索"`
} }
@@ -100,16 +98,14 @@ type ListCategoryRes struct {
// GetCategoryReq 获取分类详情请求 // GetCategoryReq 获取分类详情请求
type GetCategoryReq struct { type GetCategoryReq struct {
g.Meta `path:"/getCategory" method:"get" tags:"分类管理" summary:"获取分类详情" dc:"获取分类详情"` g.Meta `path:"/getCategory" method:"get" tags:"分类管理" summary:"获取分类详情" dc:"获取分类详情"`
Id uint64 `json:"id" v:"required-without:Bid|integer#Id不能为空|Id必须是整数" dc:"分类ID"` Id int64 `json:"id" v:"required" dc:"分类ID"`
Bid string `json:"bid" v:"required-without:Id|string#Bid不能为空|Bid必须是字符串" dc:"分类ID"`
} }
// GetCategoryRes 获取分类详情响应 // GetCategoryRes 获取分类详情响应
type GetCategoryRes struct { type GetCategoryRes struct {
Id uint64 `json:"id" dc:"分类ID"` Id int64 `json:"id,string" dc:"分类ID"`
Bid string `json:"bid" dc:"分类ID"`
Name string `json:"name" dc:"分类名称"` Name string `json:"name" dc:"分类名称"`
ParentId string `json:"parentId" dc:"父分类ID"` ParentId int64 `json:"parentId,string" dc:"父分类ID"`
Path string `json:"path" dc:"分类路径"` Path string `json:"path" dc:"分类路径"`
Level int `json:"level" dc:"分类层级"` Level int `json:"level" dc:"分类层级"`
IsLeafNode bool `json:"isLeafNode" dc:"是否叶子节点"` IsLeafNode bool `json:"isLeafNode" dc:"是否叶子节点"`

View File

@@ -2,6 +2,7 @@ package dto
import ( import (
"assets/consts/asset" "assets/consts/asset"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
) )
@@ -39,7 +40,7 @@ type GetSpecsUnitRes struct {
// GetTenantModuleTypeReq 获取租户模块类型请求 // GetTenantModuleTypeReq 获取租户模块类型请求
type GetTenantModuleTypeReq struct { type GetTenantModuleTypeReq struct {
g.Meta `path:"/getTenantModuleType" method:"get" tags:"枚举管理" summary:"获取租户模块类型" dc:"获取租户模块类型"` g.Meta `path:"/getTenantModuleType" method:"get" tags:"枚举管理" summary:"获取租户模块类型" dc:"获取租户模块类型"`
AssetId string `json:"assetId" v:"required|in:physical,virtual,service" dc:"资产id"` AssetId int64 `json:"assetId" v:"required|in:physical,virtual,service" dc:"资产id"`
} }
// GetTenantModuleTypeRes 获取租户模块类型响应 // GetTenantModuleTypeRes 获取租户模块类型响应

View File

@@ -21,8 +21,8 @@ type CommonResp struct {
type CreateBatchReq struct { type CreateBatchReq struct {
g.Meta `path:"/createBatch" method:"post" tags:"库存批次管理" summary:"创建批次" dc:"创建新的库存批次"` g.Meta `path:"/createBatch" method:"post" tags:"库存批次管理" summary:"创建批次" dc:"创建新的库存批次"`
AssetId *bson.ObjectID `json:"assetId" v:"required" dc:"资产ID"` AssetId int64 `json:"assetId" v:"required" dc:"资产ID"`
AssetSkuId *bson.ObjectID `json:"assetSkuId" v:"required" dc:"SKU ID"` AssetSkuId int64 `json:"assetSkuId" v:"required" dc:"SKU ID"`
BatchNo string `json:"batchNo" v:"required" dc:"批次号"` BatchNo string `json:"batchNo" v:"required" dc:"批次号"`
BatchQty int `json:"batchQty" v:"required|min:1" dc:"批次数量"` BatchQty int `json:"batchQty" v:"required|min:1" dc:"批次数量"`
AvailableQty int `json:"availableQty" v:"required|min:1" dc:"可用数量"` AvailableQty int `json:"availableQty" v:"required|min:1" dc:"可用数量"`
@@ -42,7 +42,7 @@ type CreateBatchRes struct {
type UpdateBatchReq struct { type UpdateBatchReq struct {
g.Meta `path:"/updateBatch" method:"put" tags:"库存批次管理" summary:"更新批次" dc:"更新批次信息"` g.Meta `path:"/updateBatch" method:"put" tags:"库存批次管理" summary:"更新批次" dc:"更新批次信息"`
Id *bson.ObjectID `json:"id" v:"required" dc:"批次ID"` Id int64 `json:"id" v:"required" dc:"批次ID"`
BatchQty int `json:"batchQty" v:"required|min:1" dc:"批次数量"` BatchQty int `json:"batchQty" v:"required|min:1" dc:"批次数量"`
AvailableQty int `json:"availableQty" v:"required|min:1" dc:"可用数量"` AvailableQty int `json:"availableQty" v:"required|min:1" dc:"可用数量"`
} }

View File

@@ -37,8 +37,8 @@ type ListStockDetailsReq struct {
*beans.Page *beans.Page
OrderBy []beans.OrderBy `json:"orderBy" dc:"排序规则"` OrderBy []beans.OrderBy `json:"orderBy" dc:"排序规则"`
AssetId *bson.ObjectID `json:"assetId" dc:"资产ID"` AssetId int64 `json:"assetId" dc:"资产ID"`
AssetSkuId *bson.ObjectID `json:"assetSkuId" dc:"SKU ID"` AssetSkuId int64 `json:"assetSkuId" dc:"SKU ID"`
CategoryPath string `json:"categoryPath" dc:"分类路径"` CategoryPath string `json:"categoryPath" dc:"分类路径"`
Status stock.StockStatus `json:"status" dc:"状态"` Status stock.StockStatus `json:"status" dc:"状态"`
} }

View File

@@ -11,7 +11,7 @@ import (
type StockOperationReq struct { type StockOperationReq struct {
g.Meta `path:"/stockOperation" method:"post" tags:"库存管理" summary:"库存操作(创建/修改)" dc:"库存操作(创建/修改)"` g.Meta `path:"/stockOperation" method:"post" tags:"库存管理" summary:"库存操作(创建/修改)" dc:"库存操作(创建/修改)"`
AssetSkuId *bson.ObjectID `json:"assetSkuId" v:"required" dc:"关联资产SKU ID"` AssetSkuId int64 `json:"assetSkuId" v:"required" dc:"关联资产SKU ID"`
Stock int `json:"stock" v:"required|min:1" dc:"库存数量"` Stock int `json:"stock" v:"required|min:1" dc:"库存数量"`
// 批次模式专用字段 // 批次模式专用字段
BatchNo string `json:"batchNo" dc:"批次号(批次模式必填)"` BatchNo string `json:"batchNo" dc:"批次号(批次模式必填)"`
@@ -22,8 +22,8 @@ type StockOperationReq struct {
// StockPublishMessage 库存发布消息 // StockPublishMessage 库存发布消息
type StockPublishMessage struct { type StockPublishMessage struct {
AssetId string `json:"assetId"` AssetId int64 `json:"assetId"`
AssetSkuId string `json:"assetSkuId"` AssetSkuId int64 `json:"assetSkuId"`
TenantId interface{} `json:"tenantId"` TenantId interface{} `json:"tenantId"`
UserName interface{} `json:"userName"` UserName interface{} `json:"userName"`
StockCount int `json:"stockCount"` StockCount int `json:"stockCount"`
@@ -41,7 +41,7 @@ type StockPublishMessage struct {
type GetStockFormFieldsReq struct { type GetStockFormFieldsReq struct {
g.Meta `path:"/getStockFormFields" method:"get" tags:"库存管理" summary:"获取库存操作表单字段" dc:"根据资产SKU的库存管理模式动态返回表单字段"` g.Meta `path:"/getStockFormFields" method:"get" tags:"库存管理" summary:"获取库存操作表单字段" dc:"根据资产SKU的库存管理模式动态返回表单字段"`
AssetSkuId *bson.ObjectID `json:"assetSkuId" v:"required" dc:"关联资产ID"` AssetSkuId int64 `json:"assetSkuId" v:"required" dc:"关联资产ID"`
} }
// GetStockFormFieldsRes 获取库存表单字段响应 // GetStockFormFieldsRes 获取库存表单字段响应

View File

@@ -5,30 +5,74 @@ import (
"assets/consts/stock" "assets/consts/stock"
"gitea.com/red-future/common/beans" "gitea.com/red-future/common/beans"
"github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
) )
type assetCol struct {
beans.SQLBaseCol
Name string
Description string
Type string
CategoryId string
CategoryPath string
ImageURL string
Images string
Status string
BasePrice string
Currency string
UnlimitedStock string
StockMode string
OnlineTime string
OfflineTime string
PhysicalAssetConfig string
ServiceAssetConfig string
VirtualAssetConfig string
Metadata string
TenantModuleType string
}
var AssetCol = assetCol{
SQLBaseCol: beans.DefSQLBaseCol,
Name: "name",
Description: "description",
Type: "type",
CategoryId: "category_id",
CategoryPath: "category_path",
ImageURL: "image_url",
Images: "images",
Status: "status",
BasePrice: "base_price",
Currency: "currency",
UnlimitedStock: "unlimited_stock",
StockMode: "stock_mode",
OnlineTime: "online_time",
OfflineTime: "offline_time",
PhysicalAssetConfig: "physical_asset_config",
ServiceAssetConfig: "service_asset_config",
VirtualAssetConfig: "virtual_asset_config",
Metadata: "metadata",
TenantModuleType: "tenant_module_type",
}
// Asset 资产实体 // Asset 资产实体
type Asset struct { type Asset struct {
beans.SQLBaseDO `orm:",inherit"` // 嵌入基础字段Id, Creator, CreatedAt, Updater, UpdatedAt, IsDeleted beans.SQLBaseDO `orm:",inherit"`
// 基础信息 // 基础信息
Name string `orm:"name" json:"name" description:"资产名称"` Name string `orm:"name" json:"name" description:"资产名称"`
Description string `orm:"description" json:"description" description:"资产描述"` Description string `orm:"description" json:"description" description:"资产描述"`
Type consts.AssetType `orm:"type" json:"type" description:"资产类型physical实物/virtual虚拟/service服务"` Type consts.AssetType `orm:"type" json:"type" description:"资产类型physical实物/virtual虚拟/service服务"`
CategoryId uint64 `orm:"category_id" json:"categoryId" description:"分类ID"` CategoryId int64 `orm:"category_id" json:"categoryId" description:"分类ID"`
CategoryPath string `orm:"category_path" json:"categoryPath" description:"分类路径"` CategoryPath string `orm:"category_path" json:"categoryPath" description:"分类路径"`
ImageURL string `orm:"image_url" json:"imageUrl" description:"主图URL"` ImageURL string `orm:"image_url" json:"imageUrl" description:"主图URL"`
Images []string `orm:"images" json:"images" description:"图片列表(JSONB)"` Images []string `orm:"images" json:"images" description:"图片列表(JSONB)"`
Status *consts.AssetStatus `orm:"status" json:"status" description:"资产状态1启用/0停用"` Status consts.AssetStatusType `orm:"status" json:"status" description:"资产状态1启用/0停用"`
BasePrice int `orm:"base_price" json:"basePrice" description:"基础价格(分为单位)"` BasePrice int `orm:"base_price" json:"basePrice" description:"基础价格(分为单位)"`
Currency string `orm:"currency" json:"currency" description:"货币单位默认CNY"` Currency string `orm:"currency" json:"currency" description:"货币单位默认CNY"`
UnlimitedStock bool `orm:"unlimited_stock" json:"unlimitedStock" description:"是否无库存限制"` UnlimitedStock bool `orm:"unlimited_stock" json:"unlimitedStock" description:"是否无库存限制"`
StockMode stock.StockMode `orm:"stock_mode" json:"stockMode" description:"库存管理模式1-明细模式 2-批次模式"` StockMode stock.StockMode `orm:"stock_mode" json:"stockMode" description:"库存管理模式1-明细模式 2-批次模式"`
// 上线和下线时间配置(由定时任务处理资产状态) OnlineTime *gtime.Time `orm:"online_time" json:"onlineTime,omitempty" description:"上线时间"` // 上线和下线时间配置(由定时任务处理资产状态)
OnlineTime *gtime.Time `orm:"online_time" json:"onlineTime,omitempty" description:"线时间"` OfflineTime *gtime.Time `orm:"offline_time" json:"offlineTime,omitempty" description:"线时间"` // 上线和下线时间配置(由定时任务处理资产状态)
OfflineTime *gtime.Time `orm:"offline_time" json:"offlineTime,omitempty" description:"下线时间"`
// 类型专用配置 - 实物资产配置(JSONB) // 类型专用配置 - 实物资产配置(JSONB)
PhysicalAssetConfig *gjson.Json `orm:"physical_asset_config" json:"physicalAssetConfig" description:"实物资产配置(JSONB)"` PhysicalAssetConfig *gjson.Json `orm:"physical_asset_config" json:"physicalAssetConfig" description:"实物资产配置(JSONB)"`
@@ -37,7 +81,7 @@ type Asset struct {
// 类型专用配置 - 虚拟资产配置(JSONB) // 类型专用配置 - 虚拟资产配置(JSONB)
VirtualAssetConfig *gjson.Json `orm:"virtual_asset_config" json:"virtualAssetConfig" description:"虚拟资产配置(JSONB)"` VirtualAssetConfig *gjson.Json `orm:"virtual_asset_config" json:"virtualAssetConfig" description:"虚拟资产配置(JSONB)"`
// 扩展字段(JSONB) // 扩展字段(JSONB)
Metadata *gjson.Json `orm:"metadata" json:"metadata" description:"动态元数据(JSONB)"` Metadata []gjson.Json `orm:"metadata" json:"metadata" description:"动态元数据(JSONB)"`
TenantModuleType string `orm:"tenant_module_type" json:"tenantModuleType" description:"租户模块类型"` TenantModuleType beans.TenantModuleType `orm:"tenant_module_type" json:"tenantModuleType" description:"租户模块类型"`
} }

View File

@@ -2,43 +2,81 @@ package entity
import ( import (
consts "assets/consts/asset" consts "assets/consts/asset"
"assets/consts/public"
"assets/consts/stock" "assets/consts/stock"
"assets/model/config" "assets/model/config"
"gitea.com/red-future/common/beans" "gitea.com/red-future/common/beans"
"go.mongodb.org/mongo-driver/v2/bson" "github.com/gogf/gf/v2/encoding/gjson"
) )
type assetSkuCol struct {
beans.SQLBaseCol
AssetId string
AssetName string
SkuName string
ImageURL string
SpecValues string
Price string
UnlimitedStock string
Stock string
SpecsCount string
SpecsUnit string
Sort string
Status string
StockMode string
CategoryId string
CategoryPath string
CapacityUnitType string
Capacity string
TenantModuleType string
}
var AssetSkuCol = assetSkuCol{
SQLBaseCol: beans.DefSQLBaseCol,
AssetId: "asset_id",
AssetName: "asset_name",
SkuName: "sku_name",
ImageURL: "image_url",
SpecValues: "spec_values",
Price: "price",
UnlimitedStock: "unlimited_stock",
Stock: "stock",
SpecsCount: "specs_count",
SpecsUnit: "specs_unit",
Sort: "sort",
Status: "status",
StockMode: "stock_mode",
CategoryId: "category_id",
CategoryPath: "category_path",
CapacityUnitType: "capacity_unit_type",
Capacity: "capacity",
TenantModuleType: "tenant_module_type",
}
// AssetSku 资产SKU实体 // AssetSku 资产SKU实体
type AssetSku struct { type AssetSku struct {
beans.MongoBaseDO `bson:",inline"` // 嵌入基础字段Id, Creator, CreatedAt, Updater, UpdatedAt, TenantId, IsDeleted beans.SQLBaseDO `orm:",inherit"`
AssetId *bson.ObjectID `bson:"assetId" json:"assetId"` // 关联资产ID AssetId int64 `orm:"asset_id" json:"assetId"` // 关联资产ID
AssetName string `bson:"assetName" json:"assetName"` // 资产名称 AssetName string `orm:"asset_name" json:"assetName"` // 资产名称
SkuName string `bson:"skuName" json:"skuName"` // SKU名称 SkuName string `orm:"sku_name" json:"skuName"` // SKU名称
ImageURL string `bson:"imageUrl,omitempty" json:"imageUrl"` // SKU主图 ImageURL string `orm:"image_url,omitempty" json:"imageUrl"` // SKU主图
SpecValues []map[string]interface{} `bson:"specValues" json:"specValues"` // 规格值:{"颜色":"红色","尺寸":"L","时长":"1个月","平台":"抖音"} SpecValues []gjson.Json `orm:"spec_values" json:"specValues"` // 规格值:{"颜色":"红色","尺寸":"L","时长":"1个月","平台":"抖音"}
Price int `bson:"price" json:"price"` // 价格(分为单位) Price int `orm:"price" json:"price"` // 价格(分为单位)
UnlimitedStock bool `bson:"unlimitedStock" json:"unlimitedStock"` // 是否无库存限制 UnlimitedStock bool `orm:"unlimited_stock" json:"unlimitedStock"` // 是否无库存限制
Stock int `bson:"stock" json:"stock"` // 库存数量 Stock int `orm:"stock" json:"stock"` // 库存数量
SpecsCount int `bson:"specsCount" json:"specsCount"` // 规格数量 SpecsCount int `orm:"specs_count" json:"specsCount"` // 规格数量
SpecsUnit *SpecsUnitKeyValue `bson:"specsUnit" json:"specsUnit"` // 规格单位 SpecsUnit *gjson.Json `orm:"specs_unit" json:"specsUnit"` // 规格单位 SpecsUnitKeyValue
Sort int `bson:"sort" json:"sort"` // 排序 Sort int `orm:"sort" json:"sort"` // 排序
Status *consts.AssetSkuStatus `bson:"status" json:"status"` // 状态active/inactive/disabled Status consts.AssetSkuStatusType `orm:"status" json:"status"` // 状态active/inactive/disabled
StockMode stock.StockMode `bson:"stockMode" json:"stockMode"` // 库存管理模式1-明细模式 2-批次模式 StockMode stock.StockMode `orm:"stock_mode" json:"stockMode"` // 库存管理模式1-明细模式 2-批次模式
CategoryId *bson.ObjectID `bson:"categoryId" json:"categoryId"` // 分类ID CategoryId int64 `orm:"category_id" json:"categoryId"` // 分类ID
CategoryPath string `bson:"categoryPath" json:"categoryPath"` // 分类路径 CategoryPath string `orm:"category_path" json:"categoryPath"` // 分类路径
CapacityUnitType stock.CapacityUnitType `bson:"capacityUnitType" json:"capacityUnitType"` // 容量单位类型 CapacityUnitType stock.CapacityUnitType `orm:"capacity_unit_type" json:"capacityUnitType"` // 容量单位类型
Capacity config.Capacity `bson:"capacity" json:"capacity"` //容量 Capacity config.Capacity `orm:"capacity" json:"capacity"` // 容量
TenantModuleType beans.TenantModuleType `bson:"tenantModuleType" json:"tenantModuleType"` TenantModuleType beans.TenantModuleType `orm:"tenant_module_type" json:"tenantModuleType"` // 租户模块类型
} }
type SpecsUnitKeyValue struct { type SpecsUnitKeyValue struct {
Key string `bson:"key" json:"key"` // 对应原有常量值 Key string `bson:"key" json:"key"` // 对应原有常量值
Value string `bson:"value" json:"value"` // 对应描述信息 Value string `bson:"value" json:"value"` // 对应描述信息
} }
// CollectionName 获取集合名称
func (AssetSku) CollectionName() string {
return public.AssetSkuCollection
}

View File

@@ -4,7 +4,6 @@ import (
consts "assets/consts/category" consts "assets/consts/category"
"gitea.com/red-future/common/beans" "gitea.com/red-future/common/beans"
"github.com/gogf/gf/v2/encoding/gjson"
) )
type categoryCol struct { type categoryCol struct {
@@ -26,7 +25,7 @@ var CategoryCol = categoryCol{
ParentId: "parent_id", ParentId: "parent_id",
Path: "path", Path: "path",
Level: "level", Level: "level",
IsLeafNode: "isLeaf_node", IsLeafNode: "is_leaf_node",
Sort: "sort", Sort: "sort",
Image: "image", Image: "image",
Attrs: "attrs", Attrs: "attrs",
@@ -35,15 +34,16 @@ var CategoryCol = categoryCol{
// Category 分类实体 // Category 分类实体
type Category struct { type Category struct {
beans.SQLBaseDO `orm:",inherit"` // 嵌入基础字段Id, Creator, CreatedAt, Updater, UpdatedAt, IsDeleted beans.SQLBaseDO `orm:",inherit"`
Name string `orm:"name" json:"name"` // 分类名称 Name string `orm:"name" json:"name"` // 分类名称
ParentId string `orm:"parent_id" json:"parentId"` // 父分类ID为空表示根分类 ParentId int64 `orm:"parent_id" json:"parentId"` // 父分类ID为空表示根分类
Path string `orm:"path" json:"path"` // 分类路径,如:/root/parent/child Path string `orm:"path" json:"path"` // 分类路径,如:/root/parent/child
Level int `orm:"level" json:"level"` // 分类层级 Level int `orm:"level" json:"level"` // 分类层级
IsLeafNode bool `orm:"isLeaf_node" json:"isLeafNode"` // 是叶子节点 IsLeafNode *bool `orm:"is_leaf_node" json:"isLeafNode"` // 是叶子节点
Sort int `orm:"sort" json:"sort"` // 排序 Sort int `orm:"sort" json:"sort"` // 排序
Image string `orm:"image" json:"image"` // 分类图片 Image string `orm:"image" json:"image"` // 分类图片
Attrs []gjson.Json `orm:"attrs" json:"attrs,omitempty"` // 分类属性 Status consts.CategoryStatusType `orm:"status" json:"status"` // 状态1启用/0禁用
Attrs []CategoryAttr `orm:"attrs" json:"attrs,omitempty"` // 分类属性 CategoryAttr
// 使用场景说明: // 使用场景说明:
// 1. 商品分类属性:为该分类下的商品定义标准化的属性模板,如服装分类可定义尺寸、颜色、材质等属性 // 1. 商品分类属性:为该分类下的商品定义标准化的属性模板,如服装分类可定义尺寸、颜色、材质等属性
// 2. 服务分类属性:为服务类目定义特性参数,如咨询服务可定义服务时长、服务方式、专业领域等 // 2. 服务分类属性:为服务类目定义特性参数,如咨询服务可定义服务时长、服务方式、专业领域等
@@ -51,18 +51,16 @@ type Category struct {
// 4. 搜索筛选:基于分类属性进行商品筛选和搜索,提升用户体验 // 4. 搜索筛选:基于分类属性进行商品筛选和搜索,提升用户体验
// 5. 数据标准化:确保同一分类下的商品具有统一的属性结构,便于数据管理 // 5. 数据标准化:确保同一分类下的商品具有统一的属性结构,便于数据管理
// 支持的属性类型:文本(text)、数字(number)、日期(date)、单选(select)、多选(multi_select)、布尔(boolean)、图片(image) // 支持的属性类型:文本(text)、数字(number)、日期(date)、单选(select)、多选(multi_select)、布尔(boolean)、图片(image)
Status consts.CategoryStatusType `orm:"status" json:"status"` // 状态1启用/0禁用
} }
// CategoryAttr 分类属性 // CategoryAttr 分类属性
// 用于定义分类下商品或服务的标准化属性模板,确保同类商品属性统一 // Attrs 用于定义分类下商品或服务的标准化属性模板,确保同类商品属性统一
type CategoryAttr struct { type CategoryAttr struct {
Name string `json:"name"` // 属性名称,如:尺寸、颜色、品牌等 Name string `json:"name"` // 属性名称,如:尺寸、颜色、品牌等
Type string `json:"type"` // 属性类型text文本/number数字/date日期/select选择/multi_select多选/boolean布尔/image图片 Type string `json:"type"` // 属性类型text文本/number数字/date日期/select选择/multi_select多选/boolean布尔/image图片
DictType string `json:"dictType"` // 字典类型如果是select/multi_select类型时有效 DictType string `json:"dictType"` // 字典类型如果是select/multi_select类型时有效
Required bool `json:"required"` // 是否必填true表示商品发布时必须填写此属性 Required bool `json:"required"` // 是否必填true表示商品发布时必须填写此属性
Options []FieldOption `json:"options"` // 选项配置JSON字符串格式用于select/multi_select类型的可选值列表 Options []FieldOption `json:"options"` // 选项配置JSON字符串格式用于select/multi_select类型的可选值列表 // 示例:'{"options":[{"label":"红色","value":"red"},{"label":"蓝色","value":"blue"}]}'
// 示例:'{"options":[{"label":"红色","value":"red"},{"label":"蓝色","value":"blue"}]}'
Description string `json:"description"` // 属性描述,向用户说明此属性的具体含义和填写要求 Description string `json:"description"` // 属性描述,向用户说明此属性的具体含义和填写要求
Sort int `json:"sort"` // 排序权重,数值越小排序越靠前,用于属性在界面的显示顺序 Sort int `json:"sort"` // 排序权重,数值越小排序越靠前,用于属性在界面的显示顺序
} }

View File

@@ -13,8 +13,8 @@ import (
type StockDetails struct { type StockDetails struct {
beans.MongoBaseDO `bson:",inline"` // 嵌入基础字段Id, Creator, CreatedAt, Updater, UpdatedAt, TenantId, IsDeleted beans.MongoBaseDO `bson:",inline"` // 嵌入基础字段Id, Creator, CreatedAt, Updater, UpdatedAt, TenantId, IsDeleted
AssetId *bson.ObjectID `bson:"assetId" json:"assetId"` // 关联资产ID AssetId int64 `bson:"assetId" json:"assetId"` // 关联资产ID
AssetSkuId *bson.ObjectID `bson:"assetSkuId" json:"assetSkuId"` // 关联资产SKU ID AssetSkuId int64 `bson:"assetSkuId" json:"assetSkuId"` // 关联资产SKU ID
Status stock.StockStatus `bson:"status" json:"status"` // 库存状态 Status stock.StockStatus `bson:"status" json:"status"` // 库存状态
OrderId *bson.ObjectID `bson:"orderId" json:"orderId"` // 关联订单ID如果有 OrderId *bson.ObjectID `bson:"orderId" json:"orderId"` // 关联订单ID如果有
LockExpire *gtime.Time `bson:"lockExpire" json:"lockExpire"` // 锁定过期时间 LockExpire *gtime.Time `bson:"lockExpire" json:"lockExpire"` // 锁定过期时间

View File

@@ -3,18 +3,19 @@ package service
import ( import (
"assets/consts/stock" "assets/consts/stock"
dao "assets/dao/asset" dao "assets/dao/asset"
"assets/dao/base"
dto "assets/model/dto/asset" dto "assets/model/dto/asset"
enumDto "assets/model/dto/enum"
entity "assets/model/entity/asset"
service "assets/service/enum"
"context" "context"
"errors" "errors"
"fmt"
"gitea.com/red-future/common/http" "gitea.com/red-future/common/http"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
"gitea.com/red-future/common/beans" "gitea.com/red-future/common/beans"
"gitea.com/red-future/common/minio" "gitea.com/red-future/common/minio"
"gitea.com/red-future/common/utils"
) )
type asset struct{} type asset struct{}
@@ -45,38 +46,8 @@ func (s *asset) Create(ctx context.Context, req *dto.CreateAssetReq) (res *dto.C
if err = http.Get(ctx, "admin-go/api/v1/system/user/checkIsSuperAdmin", headers, &isSuperAdmin); err != nil { if err = http.Get(ctx, "admin-go/api/v1/system/user/checkIsSuperAdmin", headers, &isSuperAdmin); err != nil {
return return
} }
if !isSuperAdmin { if !isSuperAdmin {
req.StockMode = stock.StockModeDetail 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 { } else {
req.TenantModuleType = beans.TenantModuleTypePlatform req.TenantModuleType = beans.TenantModuleTypePlatform
} }
@@ -87,7 +58,7 @@ func (s *asset) Create(ctx context.Context, req *dto.CreateAssetReq) (res *dto.C
return return
} }
res = &dto.CreateAssetRes{ res = &dto.CreateAssetRes{
Id: gconv.Uint64(id), Id: id,
} }
return return
} }
@@ -98,79 +69,88 @@ func (s *asset) List(ctx context.Context, req *dto.ListAssetReq) (res *dto.ListA
if err != nil { if err != nil {
return return
} }
user, err := utils.GetUserInfo(ctx)
if err != nil {
return
}
fmt.Println(user)
res = &dto.ListAssetRes{ res = &dto.ListAssetRes{
Total: total, Total: total,
} }
err = utils.Struct(assetList, &res.List) err = gconv.Struct(assetList, &res.List)
return return
} }
// GetOne 获取单个资产 // GetOne 获取单个资产
func (s *asset) GetOne(ctx context.Context, req *dto.GetAssetReq) (res *dto.GetAssetRes, err error) { func (s *asset) GetOne(ctx context.Context, req *dto.GetAssetReq) (res *dto.GetAssetRes, err error) {
assetOne, err := dao.Asset.GetOne(ctx, req) var assetOne *entity.Asset
if assetOne, err = dao.Asset.GetOne(ctx, req); err != nil {
return
}
var assetListItem *dto.AssetItem
if err = gconv.Struct(assetOne, assetListItem); err != nil {
return
}
getCategoryRes, err := dao.Category.GetOne(ctx, &dto.GetCategoryReq{
Id: assetOne.CategoryId,
})
if err != nil { if err != nil {
return return
} }
// TODO: CategoryId类型不匹配需要同步修改category为uint64
// getCategoryRes, err := dao.Category.GetOne(ctx, &dto.GetCategoryReq{
// Id: assetOne.CategoryId,
// })
// if err != nil {
// return
// }
return &dto.GetAssetRes{ return &dto.GetAssetRes{
Asset: assetOne, AssetItem: assetListItem,
CategoryName: "", // getCategoryRes.Name, CategoryName: getCategoryRes.Name,
ImgAddressPrefix: minio.GetFileAddressPrefix(ctx), ImgAddressPrefix: minio.GetFileAddressPrefix(ctx),
}, nil }, nil
} }
// GetAssetAndSku 获取资产和Sku详情 // GetAssetAndSku 获取资产和Sku详情
func (s *asset) GetAssetAndSku(ctx context.Context, req *dto.GetAssetAndSkuReq) (res *dto.GetAssetAndSkuRes, err error) { func (s *asset) GetAssetAndSku(ctx context.Context, req *dto.GetAssetAndSkuReq) (res *dto.GetAssetAndSkuRes, err error) {
// 跳过租户ID过滤获取资产 var updateReq *dto.GetAssetReq
// TODO: AssetId 类型不匹配bson.ObjectID 需要转换为 uint64 if err = gconv.Struct(req, &updateReq); err != nil {
// 使用 SkipTenantId 跳过租户ID过滤 return
assetOne, err := dao.Asset.GetOneById(base.SkipTenantId(ctx), 0) }
_ = req.AssetId assetOne, err := dao.Asset.GetOne(ctx, updateReq)
if err != nil { if err != nil {
return return
} }
// TODO: AssetId类型不匹配需要适配 var assetListItem *dto.AssetItem
// moduleType, err := service.Enum.GetTenantModuleType(ctx, &enumDto.GetTenantModuleTypeReq{AssetId: req.AssetId.Hex()}) if err = gconv.Struct(assetOne, assetListItem); err != nil {
// if err != nil { return
// return }
// } moduleType, err := service.Enum.GetTenantModuleType(ctx, &enumDto.GetTenantModuleTypeReq{AssetId: assetOne.Id})
// TODO: AssetId类型不匹配需要同步修改AssetSku为uint64 if err != nil {
// skus, _, err := dao.AssetSku.List(ctx, &dto.ListAssetSkuReq{AssetId: req.AssetId}, true) return
// if err != nil { }
// return skus, _, err := dao.AssetSku.List(ctx, &dto.ListAssetSkuReq{AssetId: assetOne.Id})
// } if err != nil {
return
}
var assetSkuListResItem []dto.AssetSkuItem
if err = gconv.Structs(skus, assetSkuListResItem); err != nil {
return
}
return &dto.GetAssetAndSkuRes{ return &dto.GetAssetAndSkuRes{
Asset: assetOne, AssetItem: assetListItem,
Skus: nil, // skus, Skus: assetSkuListResItem,
TenantModuleType: nil, // moduleType.Options, TenantModuleType: moduleType.Options,
ImgAddressPrefix: minio.GetFileAddressPrefix(ctx), ImgAddressPrefix: minio.GetFileAddressPrefix(ctx),
}, nil }, nil
} }
// Update 更新资产 // Update 更新资产
func (s *asset) Update(ctx context.Context, req *dto.UpdateAssetReq) error { func (s *asset) Update(ctx context.Context, req *dto.UpdateAssetReq) (err error) {
return dao.Asset.Update(ctx, req) _, err = dao.Asset.Update(ctx, req)
return
} }
// UpdateStatus 更新资产状态 // UpdateStatus 更新资产状态
func (s *asset) UpdateStatus(ctx context.Context, req *dto.UpdateAssetStatusReq) (err error) { func (s *asset) UpdateStatus(ctx context.Context, req *dto.UpdateAssetStatusReq) (err error) {
var updateReq *dto.UpdateAssetReq var updateReq *dto.UpdateAssetReq
err = utils.Struct(req, &updateReq) if err = gconv.Struct(req, &updateReq); err != nil {
return dao.Asset.Update(ctx, updateReq) return err
}
_, err = dao.Asset.Update(ctx, updateReq)
return
} }
// Delete 删除资产 // Delete 删除资产
func (s *asset) Delete(ctx context.Context, req *dto.DeleteAssetReq) error { func (s *asset) Delete(ctx context.Context, req *dto.DeleteAssetReq) (err error) {
return dao.Asset.DeleteFake(ctx, req) _, err = dao.Asset.Delete(ctx, req)
return
} }

View File

@@ -13,7 +13,6 @@ import (
"gitea.com/red-future/common/utils" "gitea.com/red-future/common/utils"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
"go.mongodb.org/mongo-driver/v2/bson"
) )
type assetSku struct{} type assetSku struct{}
@@ -28,7 +27,7 @@ func (s *assetSku) CreateAssetSku(ctx context.Context, req *dto.CreateAssetSkuRe
return nil, errors.New("关联资产不存在") return nil, errors.New("关联资产不存在")
} }
// 根据资产ID查询SKU列表用于下面验证自定义属性和sku名称重不重复 // 根据资产ID查询SKU列表用于下面验证自定义属性和sku名称重不重复
skusList, _, err := dao.AssetSku.List(ctx, &dto.ListAssetSkuReq{AssetId: req.AssetId}, false) skusList, _, err := dao.AssetSku.List(ctx, &dto.ListAssetSkuReq{AssetId: assetEntity.Id})
if err != nil { if err != nil {
return return
} }
@@ -39,26 +38,23 @@ func (s *assetSku) CreateAssetSku(ctx context.Context, req *dto.CreateAssetSkuRe
} }
req.UnlimitedStock = assetEntity.UnlimitedStock req.UnlimitedStock = assetEntity.UnlimitedStock
req.StockMode = assetEntity.StockMode req.StockMode = assetEntity.StockMode
// TODO: 类型不匹配 uint64 vs *bson.ObjectID req.CategoryId = assetEntity.CategoryId
// req.CategoryId = assetEntity.CategoryId
req.CategoryPath = assetEntity.CategoryPath req.CategoryPath = assetEntity.CategoryPath
// TODO: 类型不匹配 string vs beans.TenantModuleType req.TenantModuleType = assetEntity.TenantModuleType
// req.TenantModuleType = assetEntity.TenantModuleType
// 插入数据库 // 插入数据库
ids, err := dao.AssetSku.Insert(ctx, req) id, err := dao.AssetSku.Insert(ctx, req)
if err != nil { if err != nil {
return return
} }
id := ids[0].(bson.ObjectID)
res = &dto.CreateAssetSkuRes{ res = &dto.CreateAssetSkuRes{
Id: &id, Id: id,
} }
return return
} }
// UpdateAssetSku 更新SKU // UpdateAssetSku 更新SKU
func (s *assetSku) UpdateAssetSku(ctx context.Context, req *dto.UpdateAssetSkuReq) error { func (s *assetSku) UpdateAssetSku(ctx context.Context, req *dto.UpdateAssetSkuReq) (err error) {
getOne, err := dao.AssetSku.GetOne(ctx, &dto.GetAssetSkuReq{Id: req.Id}, false) getOne, err := dao.AssetSku.GetOne(ctx, &dto.GetAssetSkuReq{Id: req.Id})
if err != nil { if err != nil {
return errors.New("SUK不存在") return errors.New("SUK不存在")
} }
@@ -78,7 +74,8 @@ func (s *assetSku) UpdateAssetSku(ctx context.Context, req *dto.UpdateAssetSkuRe
return err return err
} }
// 更新数据库 // 更新数据库
return dao.AssetSku.Update(ctx, req) _, err = dao.AssetSku.Update(ctx, req)
return
} }
func (s *assetSku) parameterValidation(ctx context.Context, assetEntity *entity.Asset, list []entity.AssetSku, skuName string, specValues []map[string]interface{}) (err error) { func (s *assetSku) parameterValidation(ctx context.Context, assetEntity *entity.Asset, list []entity.AssetSku, skuName string, specValues []map[string]interface{}) (err error) {
@@ -112,7 +109,8 @@ func (s *assetSku) parameterValidation(ctx context.Context, assetEntity *entity.
for key, subValue := range specValues { for key, subValue := range specValues {
// 1. 检查请求参数 map 中是否存在该键 // 1. 检查请求参数 map 中是否存在该键
for _, subValues := range list.SpecValues { for _, subValues := range list.SpecValues {
parentValue, ok := subValues[gconv.String(key)] mapSubValues := gconv.Map(subValues)
parentValue, ok := mapSubValues[gconv.String(key)]
if ok { if ok {
// 2. 检查对应的值是否相等 // 2. 检查对应的值是否相等
if reflect.DeepEqual(parentValue, subValue) { if reflect.DeepEqual(parentValue, subValue) {
@@ -146,13 +144,14 @@ func (s *assetSku) parameterValidation(ctx context.Context, assetEntity *entity.
} }
// DeleteAssetSku 删除SKU软删除 // DeleteAssetSku 删除SKU软删除
func (s *assetSku) DeleteAssetSku(ctx context.Context, req *dto.DeleteAssetSkuReq) error { func (s *assetSku) DeleteAssetSku(ctx context.Context, req *dto.DeleteAssetSkuReq) (err error) {
return dao.AssetSku.DeleteFake(ctx, req) _, err = dao.AssetSku.Delete(ctx, req)
return
} }
// GetAssetSku 获取SKU详情 // GetAssetSku 获取SKU详情
func (s *assetSku) GetAssetSku(ctx context.Context, req *dto.GetAssetSkuReq) (res *dto.GetAssetSkuRes, err error) { func (s *assetSku) GetAssetSku(ctx context.Context, req *dto.GetAssetSkuReq) (res *dto.GetAssetSkuRes, err error) {
one, err := dao.AssetSku.GetOne(ctx, req, false) one, err := dao.AssetSku.GetOne(ctx, req)
if err != nil { if err != nil {
return return
} }
@@ -163,7 +162,7 @@ func (s *assetSku) GetAssetSku(ctx context.Context, req *dto.GetAssetSkuReq) (re
// ListAssetSkus 获取SKU列表 // ListAssetSkus 获取SKU列表
func (s *assetSku) ListAssetSkus(ctx context.Context, req *dto.ListAssetSkuReq) (res *dto.ListAssetSkuRes, err error) { func (s *assetSku) ListAssetSkus(ctx context.Context, req *dto.ListAssetSkuReq) (res *dto.ListAssetSkuRes, err error) {
// 查询数据库 // 查询数据库
list, total, err := dao.AssetSku.List(ctx, req, false) list, total, err := dao.AssetSku.List(ctx, req)
if err != nil { if err != nil {
return return
} }
@@ -176,14 +175,19 @@ func (s *assetSku) ListAssetSkus(ctx context.Context, req *dto.ListAssetSkuReq)
// GetAssetSkuModule 获取SKU详情 // GetAssetSkuModule 获取SKU详情
func (s *assetSku) GetAssetSkuModule(ctx context.Context, req *dto.GetAssetSkuModuleReq) (res *dto.GetAssetSkuModuleRes, err error) { 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) one, err := dao.AssetSku.GetOne(ctx, &dto.GetAssetSkuReq{Id: req.Id})
if err != nil { if err != nil {
return return
} }
res = &dto.GetAssetSkuModuleRes{} res = &dto.GetAssetSkuModuleRes{}
// 计算到期时间 // 计算到期时间
if one.SpecsUnit != nil && one.SpecsCount > 0 { if one.SpecsUnit != nil && one.SpecsCount > 0 {
durationType := public.DurationType(one.SpecsUnit.Key) var specsUnit *entity.SpecsUnitKeyValue
err = gconv.Struct(one.SpecsUnit, &specsUnit)
if err != nil {
return
}
durationType := public.DurationType(specsUnit.Key)
res.ExpireAt = durationType.AddTime(one.SpecsCount) res.ExpireAt = durationType.AddTime(one.SpecsCount)
res.AssetId = one.AssetId res.AssetId = one.AssetId
} }

View File

@@ -8,7 +8,6 @@ import (
"errors" "errors"
"gitea.com/red-future/common/db/gfdb" "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/database/gdb"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
@@ -29,22 +28,20 @@ var Category = new(CategoryService)
func (s *CategoryService) Create(ctx context.Context, req *dto.CreateCategoryReq) (res *dto.CreateCategoryRes, err error) { 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}) parent, err := dao.Category.GetOne(ctx, &dto.GetCategoryReq{Id: req.ParentId})
if err != nil { if err != nil {
return nil, err return nil, err
} }
req.Path = parent.Path + DefaultPathSeparator + req.ParentId if g.IsEmpty(parent) {
return nil, errors.New("父分类不存在")
}
req.Path = parent.Path + DefaultPathSeparator + gconv.String(req.ParentId)
req.Level = parent.Level + 1 req.Level = parent.Level + 1
err = gfdb.DB(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { err = gfdb.DB(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
var r *entity.Category var id int64
req.IsLeafNode = gconv.PtrBool(true)
if r, err = dao.Category.Insert(ctx, req); err != nil { if id, err = dao.Category.Insert(ctx, req); err != nil {
return err
}
// 更新新创建分类的 IsLeafNode 为 true
if err = s.updateLeafNode(ctx, r.Bid, true); err != nil {
return err return err
} }
@@ -54,7 +51,7 @@ func (s *CategoryService) Create(ctx context.Context, req *dto.CreateCategoryReq
} }
res = &dto.CreateCategoryRes{ res = &dto.CreateCategoryRes{
Bid: r.Bid, Id: id,
} }
return nil return nil
@@ -64,11 +61,12 @@ func (s *CategoryService) Create(ctx context.Context, req *dto.CreateCategoryReq
} }
// updateLeafNode 更新分类的 IsLeafNode 字段 // updateLeafNode 更新分类的 IsLeafNode 字段
func (s *CategoryService) updateLeafNode(ctx context.Context, categoryId string, isLeaf bool) error { func (s *CategoryService) updateLeafNode(ctx context.Context, categoryId int64, isLeaf bool) (err error) {
return dao.Category.Update(ctx, &dto.UpdateCategoryReq{ _, err = dao.Category.Update(ctx, &dto.UpdateCategoryReq{
Bid: categoryId, Id: categoryId,
IsLeafNode: isLeaf, IsLeafNode: &isLeaf,
}) })
return
} }
// GetOne 获取单个分类 // GetOne 获取单个分类
@@ -78,11 +76,12 @@ func (s *CategoryService) GetOne(ctx context.Context, req *dto.GetCategoryReq) (
return nil, err return nil, err
} }
res := new(dto.GetCategoryRes) res := new(dto.GetCategoryRes)
err = utils.Struct(one, &res)
if err != nil { if err = gconv.Scan(one, &res); err != nil {
return nil, err panic(err)
} }
return res, nil
return res, err
} }
// List 获取分类列表 // List 获取分类列表
@@ -107,7 +106,7 @@ func (s *CategoryService) GetTree(ctx context.Context, req *dto.GetCategoryTreeR
if err != nil { if err != nil {
return nil, err return nil, err
} }
tree, err := s.buildTree(ctx, list, "") tree, err := s.buildTree(ctx, list, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -115,7 +114,7 @@ func (s *CategoryService) GetTree(ctx context.Context, req *dto.GetCategoryTreeR
} }
// buildTree 构建树形结构 // buildTree 构建树形结构
func (s *CategoryService) buildTree(ctx context.Context, categories []entity.Category, parentId string) ([]*dto.CategoryTreeNode, error) { func (s *CategoryService) buildTree(ctx context.Context, categories []entity.Category, parentId int64) ([]*dto.CategoryTreeNode, error) {
tree := make([]*dto.CategoryTreeNode, 0) tree := make([]*dto.CategoryTreeNode, 0)
for _, cat := range categories { for _, cat := range categories {
if !s.isChildOf(cat.ParentId, parentId) { if !s.isChildOf(cat.ParentId, parentId) {
@@ -131,7 +130,7 @@ func (s *CategoryService) buildTree(ctx context.Context, categories []entity.Cat
} }
// isChildOf 判断分类是否为指定父节点的子节点 // isChildOf 判断分类是否为指定父节点的子节点
func (s *CategoryService) isChildOf(childParentId, parentId string) bool { func (s *CategoryService) isChildOf(childParentId, parentId int64) bool {
if g.IsEmpty(childParentId) && g.IsEmpty(parentId) { if g.IsEmpty(childParentId) && g.IsEmpty(parentId) {
return true return true
} }
@@ -147,7 +146,7 @@ func (s *CategoryService) convertToTreeNode(ctx context.Context, category *entit
if err := gconv.Struct(&category, &res); err != nil { if err := gconv.Struct(&category, &res); err != nil {
return res, err return res, err
} }
children, err := s.buildTree(ctx, allCategories, category.Bid) children, err := s.buildTree(ctx, allCategories, category.Id)
if err != nil { if err != nil {
return res, err return res, err
} }
@@ -157,7 +156,7 @@ func (s *CategoryService) convertToTreeNode(ctx context.Context, category *entit
} }
// hasChildren 检查分类是否有子分类 // hasChildren 检查分类是否有子分类
func (s *CategoryService) hasChildren(ctx context.Context, parentId string) (bool, error) { func (s *CategoryService) hasChildren(ctx context.Context, parentId int64) (bool, error) {
count, err := dao.Category.Count(ctx, &dto.ListCategoryReq{ count, err := dao.Category.Count(ctx, &dto.ListCategoryReq{
ParentId: parentId, ParentId: parentId,
}) })
@@ -165,7 +164,7 @@ func (s *CategoryService) hasChildren(ctx context.Context, parentId string) (boo
} }
// updateLeafNodeIfNoChildren 如果父分类没有子分类了,更新为叶子节点 // updateLeafNodeIfNoChildren 如果父分类没有子分类了,更新为叶子节点
func (s *CategoryService) updateLeafNodeIfNoChildren(ctx context.Context, parentId string) error { func (s *CategoryService) updateLeafNodeIfNoChildren(ctx context.Context, parentId int64) error {
hasChildren, err := s.hasChildren(ctx, parentId) hasChildren, err := s.hasChildren(ctx, parentId)
if err != nil { if err != nil {
return err return err
@@ -174,12 +173,13 @@ func (s *CategoryService) updateLeafNodeIfNoChildren(ctx context.Context, parent
} }
// UpdateStatus 更新分类状态 // UpdateStatus 更新分类状态
func (s *CategoryService) UpdateStatus(ctx context.Context, req *dto.UpdateCategoryStatusReq) error { func (s *CategoryService) UpdateStatus(ctx context.Context, req *dto.UpdateCategoryStatusReq) (err error) {
var updateReq *dto.UpdateCategoryReq var updateReq *dto.UpdateCategoryReq
if err := gconv.Struct(req, &updateReq); err != nil { if err = gconv.Struct(req, &updateReq); err != nil {
return err return
} }
return dao.Category.Update(ctx, updateReq) _, err = dao.Category.Update(ctx, updateReq)
return
} }
// Update 更新分类 // Update 更新分类
@@ -189,7 +189,7 @@ func (s *CategoryService) Update(ctx context.Context, req *dto.UpdateCategoryReq
return err return err
} }
err = gfdb.DB(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { err = gfdb.DB(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
if err = dao.Category.Update(ctx, req); err != nil { if rows, err := dao.Category.Update(ctx, req); err != nil && rows > 0 {
return err return err
} }
@@ -213,7 +213,7 @@ func (s *CategoryService) Update(ctx context.Context, req *dto.UpdateCategoryReq
} }
// parentIdChanged 判断父分类是否发生变化 // parentIdChanged 判断父分类是否发生变化
func (s *CategoryService) parentIdChanged(newParentId, oldParentId string) bool { func (s *CategoryService) parentIdChanged(newParentId, oldParentId int64) bool {
if g.IsEmpty(newParentId) && g.IsEmpty(oldParentId) { if g.IsEmpty(newParentId) && g.IsEmpty(oldParentId) {
return false return false
} }
@@ -226,7 +226,7 @@ func (s *CategoryService) parentIdChanged(newParentId, oldParentId string) bool
// Delete 删除分类 // Delete 删除分类
func (s *CategoryService) Delete(ctx context.Context, req *dto.DeleteCategoryReq) error { func (s *CategoryService) Delete(ctx context.Context, req *dto.DeleteCategoryReq) error {
// 检查是否有子分类 // 检查是否有子分类
hasChildren, err := s.hasChildren(ctx, req.Bid) hasChildren, err := s.hasChildren(ctx, req.Id)
if err != nil { if err != nil {
return err return err
} }
@@ -236,7 +236,7 @@ func (s *CategoryService) Delete(ctx context.Context, req *dto.DeleteCategoryReq
// 检查是否有资产 // 检查是否有资产
if count, err := dao.Asset.Count(ctx, &dto.ListAssetReq{ if count, err := dao.Asset.Count(ctx, &dto.ListAssetReq{
CategoryId: req.Bid, CategoryId: req.Id,
}); err != nil { }); err != nil {
return err return err
} else if count > 0 { } else if count > 0 {
@@ -244,13 +244,13 @@ func (s *CategoryService) Delete(ctx context.Context, req *dto.DeleteCategoryReq
} }
// 获取分类信息用于后续操作 // 获取分类信息用于后续操作
category, err := dao.Category.GetOne(ctx, &dto.GetCategoryReq{Bid: req.Bid}) category, err := dao.Category.GetOne(ctx, &dto.GetCategoryReq{Id: req.Id})
if err != nil { if err != nil {
return err return err
} }
err = gfdb.DB(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { err = gfdb.DB(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
// 删除分类 // 删除分类
if err := dao.Category.DeleteFake(ctx, req); err != nil { if rows, err := dao.Category.Delete(ctx, req); err != nil && rows > 0 {
return err return err
} }

View File

@@ -39,7 +39,7 @@ var StockManage = new(stockManage)
// GetStockFormFields 获取库存操作表单字段 // GetStockFormFields 获取库存操作表单字段
func (s *stockManage) GetStockFormFields(ctx context.Context, req *stockDto.GetStockFormFieldsReq) (*stockDto.GetStockFormFieldsRes, error) { func (s *stockManage) GetStockFormFields(ctx context.Context, req *stockDto.GetStockFormFieldsReq) (*stockDto.GetStockFormFieldsRes, error) {
// 获取资产SKU信息 // 获取资产SKU信息
assetSku, err := assetDao.AssetSku.GetOne(ctx, &assetDto.GetAssetSkuReq{Id: req.AssetSkuId}, false) assetSku, err := assetDao.AssetSku.GetOne(ctx, &assetDto.GetAssetSkuReq{Id: req.AssetSkuId})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -89,7 +89,7 @@ func (s *stockManage) GetStockFormFields(ctx context.Context, req *stockDto.GetS
// StockOperation 库存操作入口(入库/出库) // StockOperation 库存操作入口(入库/出库)
// 根据SKU的StockMode区分明细模式和批次模式计算差值后发布消息到NATS // 根据SKU的StockMode区分明细模式和批次模式计算差值后发布消息到NATS
func (s *stockManage) StockOperation(ctx context.Context, req *stockDto.StockOperationReq) (err error) { func (s *stockManage) StockOperation(ctx context.Context, req *stockDto.StockOperationReq) (err error) {
assetSku, err := assetDao.AssetSku.GetOne(ctx, &assetDto.GetAssetSkuReq{Id: req.AssetSkuId}, false) assetSku, err := assetDao.AssetSku.GetOne(ctx, &assetDto.GetAssetSkuReq{Id: req.AssetSkuId})
if err != nil { if err != nil {
return return
} }
@@ -145,13 +145,13 @@ func (s *stockManage) stockPublishMessage(ctx context.Context, assetSku *assetEn
return return
} }
publishMessage := stockDto.StockPublishMessage{ publishMessage := stockDto.StockPublishMessage{
AssetId: assetSku.AssetId.Hex(), AssetId: assetSku.AssetId,
AssetSkuId: assetSku.Id.Hex(), AssetSkuId: assetSku.Id,
TenantId: user.TenantId, TenantId: user.TenantId,
UserName: user.UserName, UserName: user.UserName,
StockCount: stockCount, StockCount: stockCount,
OperationType: operationType, OperationType: operationType,
Metadata: assetSku.SpecValues, Metadata: gconv.Maps(assetSku.SpecValues),
StockMode: int(assetSku.StockMode), StockMode: int(assetSku.StockMode),
BatchNo: req.BatchNo, BatchNo: req.BatchNo,
ProductionDate: req.ProductionDate, ProductionDate: req.ProductionDate,
@@ -186,21 +186,9 @@ func (s *stockManage) stockPublishMessage(ctx context.Context, assetSku *assetEn
// AddStock NATS消费者调用执行实际的入库/出库操作 // AddStock NATS消费者调用执行实际的入库/出库操作
// 使用Redis分布式锁防止并发冲突支持明细模式和批次模式 // 使用Redis分布式锁防止并发冲突支持明细模式和批次模式
func (s *stockManage) AddStock(ctx context.Context, msg map[string]interface{}) error { func (s *stockManage) AddStock(ctx context.Context, msg map[string]interface{}) error {
assetId, err := bson.ObjectIDFromHex(gconv.String(msg["assetId"])) assetId := gconv.Int64(msg["assetId"])
if err != nil { assetSkuId := gconv.Int64(msg["assetSkuId"])
return err stockId := gconv.Int64(msg["stockId"])
}
assetSkuId, err := bson.ObjectIDFromHex(gconv.String(msg["assetSkuId"]))
if err != nil {
return err
}
stockId := bson.ObjectID{}
if !g.IsEmpty(msg["stockId"]) {
stockId, err = bson.ObjectIDFromHex(gconv.String(msg["stockId"]))
if err != nil {
return err
}
}
userName := gconv.String(msg["userName"]) userName := gconv.String(msg["userName"])
tenantId := gconv.Float64(msg["tenantId"]) tenantId := gconv.Float64(msg["tenantId"])
stockCount := gconv.Int(msg["stockCount"]) stockCount := gconv.Int(msg["stockCount"])
@@ -219,9 +207,9 @@ func (s *stockManage) AddStock(ctx context.Context, msg map[string]interface{})
success, err := redis.Lock(ctx, fileLockKey, int64(60), func(ctx context.Context) error { success, err := redis.Lock(ctx, fileLockKey, int64(60), func(ctx context.Context) error {
if operationType == "add" { if operationType == "add" {
if stockMode == stock.StockModeBatch { if stockMode == stock.StockModeBatch {
if !stockId.IsZero() { if !g.IsEmpty(stockId) {
batch := stockDto.UpdateBatchReq{ batch := stockDto.UpdateBatchReq{
Id: &stockId, Id: stockId,
BatchQty: stockCount, BatchQty: stockCount,
AvailableQty: stockCount, AvailableQty: stockCount,
} }
@@ -230,8 +218,8 @@ func (s *stockManage) AddStock(ctx context.Context, msg map[string]interface{})
} }
} else { } else {
batch := stockDto.CreateBatchReq{ batch := stockDto.CreateBatchReq{
AssetId: &assetId, AssetId: assetId,
AssetSkuId: &assetSkuId, AssetSkuId: assetSkuId,
Status: stock.BatchStatusActive, Status: stock.BatchStatusActive,
Metadata: metadata, Metadata: metadata,
BatchNo: batchNo, BatchNo: batchNo,
@@ -251,14 +239,14 @@ func (s *stockManage) AddStock(ctx context.Context, msg map[string]interface{})
var stockInterfaces []interface{} var stockInterfaces []interface{}
for i := 0; i < stockCount; i++ { for i := 0; i < stockCount; i++ {
stockInterfaces = append(stockInterfaces, entity.StockDetails{ stockInterfaces = append(stockInterfaces, entity.StockDetails{
AssetId: &assetId, AssetId: assetId,
AssetSkuId: &assetSkuId, AssetSkuId: assetSkuId,
Status: stock.StockStatusAvailable, Status: stock.StockStatusAvailable,
Metadata: metadata, Metadata: metadata,
}) })
} }
// 批量插入数据库 // 批量插入数据库
if _, err = dao.StockDetails.BatchInsert(ctx, stockInterfaces); err != nil { if _, err := dao.StockDetails.BatchInsert(ctx, stockInterfaces); err != nil {
return err return err
} }
} }
@@ -268,7 +256,7 @@ func (s *stockManage) AddStock(ctx context.Context, msg map[string]interface{})
stockCount = 0 - stockCount stockCount = 0 - stockCount
// 更新批次 // 更新批次
batch := stockDto.UpdateBatchReq{ batch := stockDto.UpdateBatchReq{
Id: &stockId, Id: stockId,
BatchQty: stockCount, BatchQty: stockCount,
AvailableQty: stockCount, AvailableQty: stockCount,
} }
@@ -283,7 +271,7 @@ func (s *stockManage) AddStock(ctx context.Context, msg map[string]interface{})
for pageNum := int64(1); ; pageNum++ { for pageNum := int64(1); ; pageNum++ {
details, total, err := dao.StockDetails.List(ctx, details, total, err := dao.StockDetails.List(ctx,
&stockDto.ListStockDetailsReq{ &stockDto.ListStockDetailsReq{
AssetSkuId: &assetSkuId, AssetSkuId: assetSkuId,
Status: stock.StockStatusAvailable, Status: stock.StockStatusAvailable,
Page: &beans.Page{PageNum: pageNum, PageSize: pageSize}, Page: &beans.Page{PageNum: pageNum, PageSize: pageSize},
}) })
@@ -317,7 +305,8 @@ func (s *stockManage) AddStock(ctx context.Context, msg map[string]interface{})
stockCount = 0 - stockCount stockCount = 0 - stockCount
} }
} }
return assetDao.AssetSku.Update(ctx, &assetDto.UpdateAssetSkuReq{Id: &assetSkuId, Stock: stockCount}) _, err := assetDao.AssetSku.Update(ctx, &assetDto.UpdateAssetSkuReq{Id: assetSkuId, Stock: stockCount})
return err
}) })
if err != nil { if err != nil {
return err return err

View File

@@ -1,20 +1,17 @@
-----------2025-06-16 15:00:00-------------- -----------2025-06-16 15:00:00--------------
--------------------pgsql创建assets_category表语句--------------------------- --------------------pgsql创建assets_category表语句---------------------------
-- 分类主表 -- 分类主表
CREATE TABLE IF NOT EXISTS assets_category ( CREATE TABLE IF NOT EXISTS assets_category (
-- 基础字段 -- 基础字段
id BIGSERIAL PRIMARY KEY, id BIGINT PRIMARY KEY, -- 从BIGSERIAL改为BIGINT取消自增
creator VARCHAR(64) NOT NULL, creator VARCHAR(64) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updater VARCHAR(64) NOT NULL, updater VARCHAR(64) NOT NULL,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleter VARCHAR(64),
deleted_at timestamp(6), deleted_at timestamp(6),
-- 分类核心字段 -- 分类核心字段移除bid字段
bid VARCHAR(64) NOT NULL,
name VARCHAR(128) NOT NULL, name VARCHAR(128) NOT NULL,
parent_id VARCHAR(64) DEFAULT '', parent_id VARCHAR(64) DEFAULT '',
path VARCHAR(512) DEFAULT '', path VARCHAR(512) DEFAULT '',
@@ -23,27 +20,23 @@ CREATE TABLE IF NOT EXISTS assets_category (
sort INT NOT NULL DEFAULT 0, sort INT NOT NULL DEFAULT 0,
image VARCHAR(256) DEFAULT '', image VARCHAR(256) DEFAULT '',
attrs JSONB DEFAULT '[]'::JSONB, attrs JSONB DEFAULT '[]'::JSONB,
status SMALLINT NOT NULL DEFAULT 1, status SMALLINT NOT NULL DEFAULT 1
-- 唯一索引 & 普通索引
CONSTRAINT uk_category_id UNIQUE (bid)
); );
-- 为分类表添加索引PostgreSQL 索引单独创建)
-- 为分类表添加索引移除原uk_category_id唯一索引保留其他索引
CREATE INDEX idx_category_parent_id ON assets_category(parent_id); CREATE INDEX idx_category_parent_id ON assets_category(parent_id);
CREATE INDEX idx_category_level ON assets_category(level); CREATE INDEX idx_category_level ON assets_category(level);
CREATE INDEX idx_category_status ON assets_category(status); CREATE INDEX idx_category_status ON assets_category(status);
CREATE INDEX idx_category_is_leaf_node ON assets_category(is_leaf_node); CREATE INDEX idx_category_is_leaf_node ON assets_category(is_leaf_node);
-- 分类表字段注释 -- 分类表字段注释移除bid字段注释
COMMENT ON TABLE assets_category IS '商品/服务分类表'; COMMENT ON TABLE assets_category IS '商品/服务分类表';
COMMENT ON COLUMN assets_category.id IS '主键ID'; COMMENT ON COLUMN assets_category.id IS '主键ID(非自增)';
COMMENT ON COLUMN assets_category.creator IS '创建人'; COMMENT ON COLUMN assets_category.creator IS '创建人';
COMMENT ON COLUMN assets_category.created_at IS '创建时间'; COMMENT ON COLUMN assets_category.created_at IS '创建时间';
COMMENT ON COLUMN assets_category.updater IS '更新人'; COMMENT ON COLUMN assets_category.updater IS '更新人';
COMMENT ON COLUMN assets_category.updated_at IS '更新时间'; COMMENT ON COLUMN assets_category.updated_at IS '更新时间';
COMMENT ON COLUMN assets_category.deleter IS '删除人(软删)';
COMMENT ON COLUMN assets_category.deleted_at IS '删除时间(软删)'; COMMENT ON COLUMN assets_category.deleted_at IS '删除时间(软删)';
COMMENT ON COLUMN assets_category.bid IS '业务ID';
COMMENT ON COLUMN assets_category.name IS '分类名称'; COMMENT ON COLUMN assets_category.name IS '分类名称';
COMMENT ON COLUMN assets_category.parent_id IS '父分类ID为空表示根分类'; COMMENT ON COLUMN assets_category.parent_id IS '父分类ID为空表示根分类';
COMMENT ON COLUMN assets_category.path IS '分类路径,如:/root/parent/child'; COMMENT ON COLUMN assets_category.path IS '分类路径,如:/root/parent/child';
@@ -61,20 +54,18 @@ COMMENT ON COLUMN assets_category.status IS '状态1启用/0禁用';
-- 资产表asset -- 资产表asset
CREATE TABLE IF NOT EXISTS assets_asset ( CREATE TABLE IF NOT EXISTS assets_asset (
-- 嵌入基础字段(复用 SQLBaseDO 结构) -- 嵌入基础字段(复用 SQLBaseDO 结构)
id BIGSERIAL PRIMARY KEY, id BIGINT PRIMARY KEY, -- 从BIGSERIAL改为BIGINT取消自增
creator VARCHAR(64) NOT NULL, creator VARCHAR(64) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updater VARCHAR(64) NOT NULL, updater VARCHAR(64) NOT NULL,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleter VARCHAR(64),
deleted_at timestamp(6), deleted_at timestamp(6),
-- 基础信息字段 -- 基础信息字段移除bid字段
bid VARCHAR(64) NOT NULL,
name VARCHAR(128) NOT NULL, name VARCHAR(128) NOT NULL,
description TEXT DEFAULT '', description TEXT DEFAULT '',
type VARCHAR(32) NOT NULL, -- 资产类型physical实物/virtual虚拟/service服务 type VARCHAR(32) NOT NULL, -- 资产类型physical实物/virtual虚拟/service服务
category_id BIGINT NOT NULL, -- 分类ID对应分类表category_id实体中定义为uint64PG用BIGINT适配 category_id BIGINT NOT NULL, -- 分类ID对应category分类表id
category_path VARCHAR(512) DEFAULT '', category_path VARCHAR(512) DEFAULT '',
image_url VARCHAR(512) DEFAULT '', image_url VARCHAR(512) DEFAULT '',
images JSONB DEFAULT '[]'::JSONB, -- 图片列表字符串数组JSONB存储 images JSONB DEFAULT '[]'::JSONB, -- 图片列表字符串数组JSONB存储
@@ -93,13 +84,10 @@ CREATE TABLE IF NOT EXISTS assets_asset (
metadata JSONB, -- 扩展字段(动态元数据) metadata JSONB, -- 扩展字段(动态元数据)
-- 租户相关 -- 租户相关
tenant_module_type VARCHAR(64) DEFAULT '', tenant_module_type VARCHAR(64) DEFAULT ''
-- 唯一索引
CONSTRAINT uk_asset_id UNIQUE (bid)
); );
-- 为资产表添加索引(优化查询性能 -- 为资产表添加索引(移除原uk_asset_id唯一索引保留其他索引
CREATE INDEX idx_asset_category_id ON assets_asset(category_id); CREATE INDEX idx_asset_category_id ON assets_asset(category_id);
CREATE INDEX idx_asset_type ON assets_asset(type); CREATE INDEX idx_asset_type ON assets_asset(type);
CREATE INDEX idx_asset_status ON assets_asset(status); CREATE INDEX idx_asset_status ON assets_asset(status);
@@ -107,20 +95,18 @@ CREATE INDEX idx_asset_online_time ON assets_asset(online_time);
CREATE INDEX idx_asset_offline_time ON assets_asset(offline_time); CREATE INDEX idx_asset_offline_time ON assets_asset(offline_time);
CREATE INDEX idx_asset_tenant_module_type ON assets_asset(tenant_module_type); CREATE INDEX idx_asset_tenant_module_type ON assets_asset(tenant_module_type);
-- 为资产表添加注释(PostgreSQL 专属语法 -- 为资产表添加注释(移除bid字段注释更新id注释
COMMENT ON TABLE assets_asset IS '资产主表'; COMMENT ON TABLE assets_asset IS '资产主表';
COMMENT ON COLUMN assets_asset.id IS '主键ID'; COMMENT ON COLUMN assets_asset.id IS '主键ID(非自增)';
COMMENT ON COLUMN assets_asset.creator IS '创建人'; COMMENT ON COLUMN assets_asset.creator IS '创建人';
COMMENT ON COLUMN assets_asset.created_at IS '创建时间'; COMMENT ON COLUMN assets_asset.created_at IS '创建时间';
COMMENT ON COLUMN assets_asset.updater IS '更新人'; COMMENT ON COLUMN assets_asset.updater IS '更新人';
COMMENT ON COLUMN assets_asset.updated_at IS '更新时间'; COMMENT ON COLUMN assets_asset.updated_at IS '更新时间';
COMMENT ON COLUMN assets_asset.deleter IS '删除人(软删)';
COMMENT ON COLUMN assets_asset.deleted_at IS '删除时间(软删)'; COMMENT ON COLUMN assets_asset.deleted_at IS '删除时间(软删)';
COMMENT ON COLUMN assets_asset.bid IS '业务ID';
COMMENT ON COLUMN assets_asset.name IS '资产名称'; COMMENT ON COLUMN assets_asset.name IS '资产名称';
COMMENT ON COLUMN assets_asset.description IS '资产描述'; COMMENT ON COLUMN assets_asset.description IS '资产描述';
COMMENT ON COLUMN assets_asset.type IS '资产类型physical实物/virtual虚拟/service服务'; COMMENT ON COLUMN assets_asset.type IS '资产类型physical实物/virtual虚拟/service服务';
COMMENT ON COLUMN assets_asset.category_id IS '分类ID'; COMMENT ON COLUMN assets_asset.category_id IS '分类ID关联assets_category.id';
COMMENT ON COLUMN assets_asset.category_path IS '分类路径'; COMMENT ON COLUMN assets_asset.category_path IS '分类路径';
COMMENT ON COLUMN assets_asset.image_url IS '主图URL'; COMMENT ON COLUMN assets_asset.image_url IS '主图URL';
COMMENT ON COLUMN assets_asset.images IS '图片列表(JSONB)'; COMMENT ON COLUMN assets_asset.images IS '图片列表(JSONB)';