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:
address: ":3003"
name: "assets"
workerId: 1
#logPath: "resource/log/server"
logStdout: true
errorStack: true

View File

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

View File

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

View File

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

View File

@@ -19,92 +19,79 @@ type assetDao struct {
// Insert 插入资产
func (d *assetDao) Insert(ctx context.Context, req *dto.CreateAssetReq) (id int64, err error) {
var result entity.Asset
if err = gconv.Struct(req, &result); err != nil {
var res *entity.Asset
if err = gconv.Struct(req, &res); err != nil {
return
}
return gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).Data(&result).InsertAndGetId()
}
// 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
r, err := gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).Data(&res).Insert()
if err != nil {
return
}
return r.LastInsertId()
}
// Update 更新资产
func (d *assetDao) Update(ctx context.Context, req *dto.UpdateAssetReq) (err error) {
data := g.Map{
"name": req.Name,
"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,
func (d *assetDao) Update(ctx context.Context, req *dto.UpdateAssetReq) (rows int64, err error) {
r, err := gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).OmitEmpty().Where(entity.AssetCol.Id, req.Id).Update()
if err != nil {
return
}
_, err = gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).Where("id", req.Id).Update(data)
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
// Delete 删除资产-根据id进行假删
func (d *assetDao) Delete(ctx context.Context, req *dto.DeleteAssetReq) (rows int64, err error) {
r, err := gfdb.DB(ctx).Model(ctx, public.AssetCollection).Where(entity.AssetCol.Id, req.Id).Delete()
if err != nil {
return
}
return r.RowsAffected()
}
// GetOneById 通过ID获取单个资产内部使用uint64
func (d *assetDao) GetOneById(ctx context.Context, id uint64) (res *entity.Asset, err error) {
err = gfdb.DB(ctx).Model(ctx, public.AssetCollection).Ctx(ctx).Where("id", id).Scan(&res)
// 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
}
// Count 获取资产数量
func (d *assetDao) Count(ctx context.Context, req *dto.ListAssetReq) (count int64, err error) {
m := d.buildListFilter(ctx, req)
c, err := m.Count()
return int64(c), err
func (d *assetDao) Count(ctx context.Context, req *dto.ListAssetReq) (count int, err error) {
return d.buildListFilter(ctx, req).Count()
}
// List 获取资产列表
func (d *assetDao) List(ctx context.Context, req *dto.ListAssetReq) (res []entity.Asset, total int, err error) {
m := d.buildListFilter(ctx, req)
func (d *assetDao) List(ctx context.Context, req *dto.ListAssetReq, fields ...string) (res []entity.Asset, total int, err error) {
model := d.buildListFilter(ctx, req)
model.Fields(fields)
model.OrderDesc(entity.AssetCol.CreatedAt)
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
}
// buildListFilter 构建列表查询的过滤条件
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)
if !g.IsEmpty(req.Name) {
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)
model := gfdb.DB(ctx).Model(ctx, public.AssetCollection).Model
if !g.IsEmpty(req.Keyword) {
model.WhereLike(entity.AssetCol.Name, "%"+req.Keyword+"%")
}
if !g.IsEmpty(req.CategoryPath) {
m = m.WhereLike("category_path", req.CategoryPath+"%")
model.WhereLike(entity.AssetCol.CategoryPath, req.CategoryPath+"%")
}
if !g.IsEmpty(req.Keyword) {
m = m.WhereLike("name", "%"+req.Keyword+"%")
}
return m
model.Where(entity.AssetCol.Name, req.Name)
model.Where(entity.AssetCol.Type, req.Type)
model.Where(entity.AssetCol.CategoryId, req.CategoryId)
model.Where(entity.AssetCol.Status, req.Status)
model.OmitEmptyWhere()
return model
}

View File

@@ -6,11 +6,10 @@ import (
"assets/model/entity/asset"
"context"
"gitea.com/red-future/common/beans"
"gitea.com/red-future/common/db/mongo"
"gitea.com/red-future/common/utils"
"gitea.com/red-future/common/db/gfdb"
"github.com/gogf/gf/v2/database/gdb"
"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)
@@ -19,112 +18,94 @@ type assetSku struct {
}
// Insert 插入SKU
func (d *assetSku) Insert(ctx context.Context, req *dto.CreateAssetSkuReq) (ids []any, err error) {
var result *entity.AssetSku
if err = utils.Struct(req, &result); err != nil {
func (d *assetSku) Insert(ctx context.Context, req *dto.CreateAssetSkuReq) (id int64, err error) {
var res *entity.AssetSku
if err = gconv.Struct(req, &res); err != nil {
return
}
ids, err = mongo.DB().Insert(ctx, []interface{}{&result}, public.AssetSkuCollection)
return
}
// Update 更新SKU
func (d *assetSku) Update(ctx context.Context, req *dto.UpdateAssetSkuReq) (err error) {
buildUpdateData, err := mongo.BuildUpdateData(ctx, req)
r, err := gfdb.DB(ctx).Model(ctx, public.AssetSkuCollection).Ctx(ctx).Data(&res).Insert()
if err != nil {
return
}
filter := bson.M{"_id": req.Id}
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
return r.LastInsertId()
}
// DeleteFake 删除SKU-根据id进行假删
func (d *assetSku) DeleteFake(ctx context.Context, req *dto.DeleteAssetSkuReq) (err error) {
filter := bson.M{"_id": req.Id}
_, err = mongo.DB().DeleteSoft(ctx, filter, public.AssetSkuCollection)
return
// Update 更新SKU
func (d *assetSku) Update(ctx context.Context, req *dto.UpdateAssetSkuReq) (rows int64, err error) {
r, err := gfdb.DB(ctx).Model(ctx, public.AssetSkuCollection).Ctx(ctx).OmitEmpty().Where(entity.AssetCol.Id, req.Id).Update()
if err != nil {
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
func (d *assetSku) GetOne(ctx context.Context, req *dto.GetAssetSkuReq, noTenantId bool) (res *entity.AssetSku, err error) {
filter := bson.M{"_id": req.Id}
if noTenantId {
err = mongo.DB().NoTenantId().FindOne(ctx, filter, &res, public.AssetSkuCollection)
} else {
err = mongo.DB().FindOne(ctx, filter, &res, public.AssetSkuCollection)
func (d *assetSku) GetOne(ctx context.Context, req *dto.GetAssetSkuReq, fields ...string) (res *entity.AssetSku, err error) {
r, err := gfdb.DB(ctx).Model(ctx, public.AssetSkuCollection).Ctx(ctx).Where(entity.AssetCol.Id, req.Id).Fields(fields).One()
if err != nil {
return
}
err = r.Struct(&res)
return
}
// GetListByAssetIdExcludeCurrentSku 根据资产ID获取SKU列表并且排除当前SKU
func (d *assetSku) GetListByAssetIdExcludeCurrentSku(ctx context.Context, assetId *bson.ObjectID, req *dto.ListAssetSkuReq) (res []entity.AssetSku, total int64, err error) {
filter := bson.M{"assetId": assetId, "_id": bson.M{"$ne": req.Id}}
total, err = mongo.DB().Find(ctx, filter, &res, public.AssetSkuCollection, req.Page, req.OrderBy)
func (d *assetSku) GetListByAssetIdExcludeCurrentSku(ctx context.Context, assetId int64, req *dto.ListAssetSkuReq, fields ...string) (res []entity.AssetSku, total int, err error) {
model := gfdb.DB(ctx).Model(ctx, public.AssetSkuCollection)
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
}
// List 获取SKU列表
func (d *assetSku) List(ctx context.Context, req *dto.ListAssetSkuReq, noTenantId bool) (res []entity.AssetSku, total int64, err error) {
// 构建查询过滤条件
filter, err := d.buildListFilter(ctx, req)
func (d *assetSku) List(ctx context.Context, req *dto.ListAssetSkuReq, fields ...string) (res []entity.AssetSku, total int, err error) {
model := 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 {
return
}
// 排序处理
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)
}
err = r.Structs(&res)
return
}
// buildListFilter 构建列表查询的过滤条件
func (d *assetSku) buildListFilter(ctx context.Context, req *dto.ListAssetSkuReq) (filter bson.M, err error) {
_ = ctx
filter = bson.M{}
if !g.IsEmpty(req.AssetId) {
filter["assetId"] = req.AssetId
}
if !g.IsEmpty(req.Status) {
filter["status"] = req.Status
func (d *assetSku) buildListFilter(ctx context.Context, req *dto.ListAssetSkuReq) *gdb.Model {
model := gfdb.DB(ctx).Model(ctx, public.AssetSkuCollection).Model
if !g.IsEmpty(req.Keyword) {
model.WhereLike(entity.AssetCol.Name, "%"+req.Keyword+"%")
model.WhereOrLike(entity.AssetSkuCol.SkuName, "%"+req.Keyword+"%")
}
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) {
orConditions := bson.A{
bson.M{"skuName": bson.M{"$regex": req.Keyword, "$options": "i"}},
bson.M{"assetName": bson.M{"$regex": req.Keyword, "$options": "i"}},
}
filter["$or"] = orConditions
}
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
model.Where(entity.AssetSkuCol.Id, req.Id)
model.Where(entity.AssetSkuCol.Status, req.Status)
model.WhereGT(entity.AssetSkuCol.Price, req.MinPrice)
model.WhereLT(entity.AssetSkuCol.Price, req.MaxPrice)
model.OmitEmptyWhere()
return model
}

View File

@@ -8,10 +8,8 @@ import (
"gitea.com/red-future/common/db/gfdb"
"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/util/gconv"
)
var Category = new(category)
@@ -20,63 +18,65 @@ type category struct {
}
// 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 {
return
}
res.Bid = guid.S()
_, err = gfdb.DB(ctx).Model(ctx, public.CategoryCollection).Insert(&res)
return res, nil
r, err := gfdb.DB(ctx).Model(ctx, public.CategoryCollection).Insert(&res)
if err != nil {
return
}
return r.LastInsertId()
}
// Update 更新分类
func (d *category) Update(ctx context.Context, req *dto.UpdateCategoryReq) (err error) {
model := gfdb.DB(ctx).Model(ctx, public.CategoryCollection).Data(gconv.Map(&req)).OmitEmpty()
if !g.IsEmpty(req.Bid) {
model.Where("bid", req.Bid)
func (d *category) Update(ctx context.Context, req *dto.UpdateCategoryReq) (rows int64, err error) {
r, err := gfdb.DB(ctx).Model(ctx, public.CategoryCollection).Data(&req).OmitEmpty().Where(entity.CategoryCol.Id, req.Id).Update()
if err != nil {
return
}
if !g.IsEmpty(req.Id) {
model.Where("id", req.Id)
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
}
_, err = model.Update()
return
return r.RowsAffected()
}
// GetOne 获取单个分类
func (d *category) GetOne(ctx context.Context, req *dto.GetCategoryReq, fields ...string) (category *entity.Category, err error) {
model := gfdb.DB(ctx).Model(ctx, public.CategoryCollection)
if !g.IsEmpty(req.Bid) {
model.Where(entity.CategoryCol.Bid, req.Bid)
func (d *category) GetOne(ctx context.Context, req *dto.GetCategoryReq, fields ...string) (res *entity.Category, err error) {
r, err := gfdb.DB(ctx).Model(ctx, public.CategoryCollection).Where(entity.CategoryCol.Id, req.Id).Fields(fields).One()
if err != nil {
return
}
if !g.IsEmpty(req.Id) {
model.Where(entity.CategoryCol.Id, req.Id)
}
res, err := model.Fields(fields).One()
err = res.Struct(&category)
return
}
// 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()
err = r.Struct(&res)
return
}
// Count 根据条件统计分类数量
func (d *category) Count(ctx context.Context, req *dto.ListCategoryReq) (count int64, err error) {
m := d.buildListFilter(ctx, req)
c, err := m.Count()
return int64(c), err
func (d *category) Count(ctx context.Context, req *dto.ListCategoryReq) (count int, err error) {
return d.buildListFilter(ctx, req).Count()
}
// List 获取分类列表
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.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)
err = gconv.Structs(r.List(), &res)
if err != nil {
return
}
err = r.Structs(&res)
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.Status, req.Status)
model.OrderAsc(entity.CategoryCol.Sort)
model.OrderDesc(entity.CategoryCol.CreatedAt)
model.OmitEmptyWhere()
return model
}

View File

@@ -39,7 +39,7 @@ func (d *stockDetails) DeleteManyByIds(ctx context.Context, allStockIds []*bson.
}
// 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["assetSkuId"] = assetSkuId

View File

@@ -5,32 +5,28 @@ import (
"assets/consts/stock"
"assets/model/config"
enumDto "assets/model/dto/enum"
entity "assets/model/entity/asset"
"time"
"gitea.com/red-future/common/beans"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"go.mongodb.org/mongo-driver/v2/bson"
)
// CreateAssetReq 创建资产请求
type CreateAssetReq struct {
g.Meta `path:"/createAsset" method:"post" tags:"资产管理" summary:"创建资产" dc:"创建新的资产"`
// 基础信息
Name string `json:"name" v:"required" dc:"资产名称"`
Description string `json:"description" dc:"资产描述"`
Type consts.AssetType `json:"type" v:"required" dc:"资产类型physical实物/virtual虚拟/service服务"`
CategoryId uint64 `json:"categoryId" v:"required" dc:"分类ID"`
CategoryPath string `json:"categoryPath" dc:"分类路径"`
ImageURL string `json:"imageUrl" dc:"主图URL"`
Images []string `json:"images" dc:"图片列表"`
Status *consts.AssetStatus `json:"status" dc:"状态1/0" d:"1"`
UnlimitedStock bool `json:"unlimitedStock" dc:"是否无库存限制"`
StockMode stock.StockMode `json:"stockMode" dc:"库存管理模式1-明细模式 2-批次模式" d:"2"`
// 上线和下线时间配置(由定时任务处理资产状态)
OnlineTime *time.Time `json:"onlineTime,omitempty" dc:"线时间格式2006-01-02 15:04:05"`
OfflineTime *time.Time `json:"offlineTime,omitempty" dc:"下线时间格式2006-01-02 15:04:05"`
Name string `json:"name" v:"required" dc:"资产名称"`
Description string `json:"description" dc:"资产描述"`
Type consts.AssetType `json:"type" v:"required" dc:"资产类型physical实物/virtual虚拟/service服务"`
CategoryId int64 `json:"categoryId" v:"required" dc:"分类ID"`
CategoryPath string `json:"categoryPath" dc:"分类路径"`
ImageURL string `json:"imageUrl" dc:"主图URL"`
Images []string `json:"images" dc:"图片列表"`
Status consts.AssetStatusType `json:"status" dc:"状态1/0" d:"1"`
UnlimitedStock bool `json:"unlimitedStock" dc:"是否无库存限制"`
StockMode stock.StockMode `json:"stockMode" dc:"库存管理模式1-明细模式 2-批次模式" d:"2"`
OnlineTime *gtime.Time `json:"onlineTime,omitempty" dc:"上线时间格式2006-01-02 15:04:05"`
OfflineTime *gtime.Time `json:"offlineTime,omitempty" dc:"线时间格式2006-01-02 15:04:05"`
// 类型专用配置 - 实物资产配置
PhysicalAssetConfig *config.PhysicalAssetConfig `json:"physicalAssetConfig"`
// 类型专用配置 - 服务资产配置
@@ -45,86 +41,83 @@ type CreateAssetReq struct {
// CreateAssetRes 创建资产响应
type CreateAssetRes struct {
Id uint64 `json:"id" dc:"资产ID"`
Id int64 `json:"id" dc:"资产ID"`
}
// ListAssetReq 获取资产列表请求
type ListAssetReq struct {
g.Meta `path:"/listAssets" method:"get" tags:"资产管理" summary:"获取资产列表" dc:"分页查询资产列表,支持多条件筛选"`
*beans.Page
OrderBy []beans.OrderBy `json:"orderBy" dc:"排序规则"`
Name string `json:"name" dc:"资产名称"`
Type consts.AssetType `json:"type" dc:"资产类型"`
CategoryId string `json:"categoryId" dc:"分类ID"`
CategoryPath string `json:"categoryPath" dc:"分类路径"`
Status *consts.AssetStatus `json:"status" dc:"状态"`
Keyword string `json:"keyword" dc:"关键词搜索"`
Name string `json:"name" dc:"资产名称"`
Type consts.AssetType `json:"type" dc:"资产类型"`
CategoryId int64 `json:"categoryId" dc:"分类ID"`
CategoryPath string `json:"categoryPath" dc:"分类路径"`
Status consts.AssetStatusType `json:"status" dc:"状态"`
TenantModuleType beans.TenantModuleType `json:"tenantModuleType" dc:"租户模块类型"`
Keyword string `json:"keyword" dc:"关键词搜索"`
}
// ListAssetRes 获取资产列表响应
type ListAssetRes struct {
List []AssetListItem `json:"list" dc:"资产列表"`
Total int `json:"total" dc:"总数"`
List []AssetItem `json:"list" dc:"资产列表"`
Total int `json:"total" dc:"总数"`
}
type AssetListItem struct {
// 基础信息
Id uint64 `json:"id"` // 资产ID
Name string `json:"name"` // 资产名称
Type consts.AssetType `json:"type"` // 资产类型physical实物/virtual虚拟/service服务
TypeName string `json:"typeName"` // 资产类型physical实物/virtual虚拟/service服务
CategoryId uint64 `json:"categoryId"` // 分类ID
UnlimitedStock bool `json:"unlimitedStock"` // 是否无库存限制
Status *consts.AssetStatus `json:"status"` // 资产状态active启用/inactive停用
BasePrice int `json:"basePrice"` // 基础价格(分为单位)
OnlineTime *gtime.Time `json:"onlineTime,omitempty"` // 线时间
OfflineTime *gtime.Time `json:"offlineTime,omitempty"` // 下线时间
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" dc:"更新时间"`
type AssetItem struct {
Id int64 `json:"id"` // 资产ID
Name string `json:"name"` // 资产名称
Type consts.AssetType `json:"type"` // 资产类型physical实物/virtual虚拟/service服务
TypeName string `json:"typeName"` // 资产类型physical实物/virtual虚拟/service服务
CategoryId int64 `json:"categoryId"` // 分类ID
UnlimitedStock bool `json:"unlimitedStock"` // 是否无库存限制
Status consts.AssetStatusType `json:"status"` // 资产状态active启用/inactive停用
BasePrice int `json:"basePrice"` // 基础价格(分为单位)
OnlineTime *gtime.Time `json:"onlineTime,omitempty"` // 上线时间
OfflineTime *gtime.Time `json:"offlineTime,omitempty"` // 线时间
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" dc:"更新时间"`
}
// GetAssetReq 获取资产详情请求
type GetAssetReq struct {
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 获取资产详情响应
type GetAssetRes struct {
*entity.Asset
*AssetItem
CategoryName string `json:"categoryName" dc:"分类名称"`
ImgAddressPrefix string `json:"imgAddressPrefix"`
}
// GetAssetAndSkuReq 获取资产和Sku详情请求
type GetAssetAndSkuReq struct {
g.Meta `path:"/getAssetAndSku" method:"get" tags:"资产管理" summary:"获取资产和SKU详情" dc:"获取资产和SKU详情"`
AssetId *bson.ObjectID `json:"assetId" v:"required" dc:"资产ID"`
g.Meta `path:"/getAssetAndSku" method:"get" tags:"资产管理" summary:"获取资产和SKU详情" dc:"获取资产和SKU详情"`
Id int64 `json:"id" v:"required" dc:"资产ID"`
}
// GetAssetAndSkuRes 获取资产详情响应
type GetAssetAndSkuRes struct {
*entity.Asset
Skus []entity.AssetSku `json:"skus" dc:"SKU列表"`
*AssetItem
Skus []AssetSkuItem `json:"skus" dc:"SKU列表"`
TenantModuleType []enumDto.KeyValue `json:"tenantModuleType" dc:"租户模块类型"`
ImgAddressPrefix string `json:"imgAddressPrefix"`
}
// UpdateAssetReq 更新资产请求
type UpdateAssetReq struct {
g.Meta `path:"/updateAsset" method:"put" tags:"资产管理" summary:"更新资产" dc:"更新资产信息"`
Id *bson.ObjectID `json:"id" v:"required" dc:"资产ID"`
// 基础信息
Name string `json:"name" dc:"资产名称"`
Description string `json:"description" dc:"资产描述"`
Type consts.AssetType `json:"type" dc:"资产类型physical实物/virtual虚拟/service服务"`
CategoryId *bson.ObjectID `json:"categoryId" dc:"分类ID"`
ImageURL string `json:"imageUrl" dc:"主图URL"`
Images []string `json:"images" dc:"图片列表"`
Status *consts.AssetStatus `json:"status,omitempty" dc:"状态1/0"`
// 上线和下线时间配置(由定时任务处理资产状态)
OnlineTime *time.Time `json:"onlineTime,omitempty" dc:"上线时间格式2006-01-02 15:04:05"`
OfflineTime *time.Time `json:"offlineTime,omitempty" dc:"下线时间格式2006-01-02 15:04:05"`
g.Meta `path:"/updateAsset" method:"put" tags:"资产管理" summary:"更新资产" dc:"更新资产信息"`
Id int64 `json:"id" v:"required" dc:"资产ID"`
Name string `json:"name" dc:"资产名称"`
Description string `json:"description" dc:"资产描述"`
Type consts.AssetType `json:"type" dc:"资产类型physical实物/virtual虚拟/service服务"`
CategoryId int64 `json:"categoryId" dc:"分类ID"`
ImageURL string `json:"imageUrl" dc:"主图URL"`
Images []string `json:"images" dc:"图片列表"`
Status consts.AssetStatusType `json:"status,omitempty" dc:"状态1/0"`
OnlineTime *gtime.Time `json:"onlineTime,omitempty" dc:"上线时间格式2006-01-02 15:04:05"`
OfflineTime *gtime.Time `json:"offlineTime,omitempty" dc:"下线时间格式2006-01-02 15:04:05"`
// 类型专用配置 - 实物资产配置
PhysicalAssetConfig *config.PhysicalAssetConfig `json:"physicalAssetConfig"`
// 类型专用配置 - 服务资产配置
@@ -138,12 +131,12 @@ type UpdateAssetReq struct {
// UpdateAssetStatusReq 更新资产状态请求
type UpdateAssetStatusReq struct {
g.Meta `path:"/updateAssetStatus" method:"put" tags:"资产管理" summary:"更新资产状态" dc:"更新资产状态"`
Id *bson.ObjectID `json:"id" v:"required" dc:"资产ID"`
Status *consts.AssetStatus `json:"status" v:"required|in:1,0" dc:"状态1启用/0停用"`
Id int64 `json:"id" v:"required" dc:"资产ID"`
Status consts.AssetStatusType `json:"status" v:"required|in:1,0" dc:"状态1启用/0停用"`
}
// DeleteAssetReq 删除资产请求
type DeleteAssetReq struct {
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"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"go.mongodb.org/mongo-driver/v2/bson"
)
// CreateAssetSkuReq 创建SKU请求
type CreateAssetSkuReq struct {
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:"关联资产名称"`
SkuName string `json:"skuName" v:"required" dc:"SKU名称"`
SpecsCount int `json:"specsCount" v:"required|min:1" dc:"规格数量"`
@@ -24,24 +23,24 @@ type CreateAssetSkuReq struct {
ImageURL string `json:"imageUrl" v:"required" dc:"SKU主图"`
Price int `json:"price" 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:"是否无库存限制"`
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:"分类路径"`
TenantModuleType beans.TenantModuleType `json:"tenantModuleType" dc:"租户模块类型"`
}
// CreateAssetSkuRes 创建SKU响应
type CreateAssetSkuRes struct {
Id *bson.ObjectID `json:"id" dc:"SKU ID"`
Id int64 `json:"id" dc:"SKU ID"`
}
// UpdateAssetSkuReq 更新SKU请求
type UpdateAssetSkuReq struct {
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名称"`
SpecsCount int `json:"specsCount" dc:"规格数量"`
SpecsUnit *entity.SpecsUnitKeyValue `json:"specsUnit" dc:"规格单位"`
@@ -50,36 +49,36 @@ type UpdateAssetSkuReq struct {
Price int `json:"price" dc:"价格(分为单位)"`
Sort int `json:"sort" dc:"排序"`
Stock int `json:"stock" dc:"库存数量"`
Status *consts.AssetSkuStatus `json:"status" dc:"状态"`
Status consts.AssetSkuStatusType `json:"status" dc:"状态"`
}
// DeleteAssetSkuReq 删除SKU请求
type DeleteAssetSkuReq struct {
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详情请求
type GetAssetSkuModuleReq struct {
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详情响应
type GetAssetSkuModuleRes struct {
AssetId *bson.ObjectID `json:"assetId"`
ExpireAt *gtime.Time `json:"expireAt"`
AssetId int64 `json:"assetId"`
ExpireAt *gtime.Time `json:"expireAt"`
}
// GetAssetSkuReq 获取SKU详情请求
type GetAssetSkuReq struct {
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详情响应
type GetAssetSkuRes struct {
*entity.AssetSku
*AssetSkuItem
ImgAddressPrefix string `json:"imgAddressPrefix"`
}
@@ -87,25 +86,24 @@ type GetAssetSkuRes struct {
type ListAssetSkuReq struct {
g.Meta `path:"/listAssetSkus" method:"get" tags:"SKU管理" summary:"获取SKU列表" dc:"分页查询SKU列表支持多条件筛选"`
*beans.Page
OrderBy []beans.OrderBy `json:"orderBy" dc:"排序规则"`
Id *bson.ObjectID `json:"id" dc:"SKU ID"`
AssetId *bson.ObjectID `json:"assetId" v:"required" dc:"资产ID"`
Status *consts.AssetSkuStatus `json:"status" dc:"状态"`
Keyword string `json:"keyword" dc:"关键词搜索"`
MinPrice int `json:"minPrice" dc:"最价格"`
MaxPrice int `json:"maxPrice" dc:"最高价格"`
CategoryPath string `json:"categoryPath" dc:"分类路径"`
Id int64 `json:"id" dc:"SKU ID"`
AssetId int64 `json:"assetId" v:"required" dc:"资产ID"`
Status consts.AssetSkuStatusType `json:"status" dc:"状态"`
Keyword string `json:"keyword" dc:"关键词搜索"`
MinPrice int `json:"minPrice" dc:"最低价格"`
MaxPrice int `json:"maxPrice" dc:"最价格"`
CategoryPath string `json:"categoryPath" dc:"分类路径"`
}
// ListAssetSkuRes 获取SKU列表响应
type ListAssetSkuRes struct {
List []*AssetSkuListResItem `json:"list" dc:"SKU列表"`
Total int64 `json:"total" dc:"总数"`
List []AssetSkuItem `json:"list" dc:"SKU列表"`
Total int `json:"total" dc:"总数"`
}
type AssetSkuListResItem struct {
Id *bson.ObjectID `json:"id"` // SKU ID
AssetId *bson.ObjectID `json:"assetId"`
type AssetSkuItem struct {
Id int64 `json:"id"` // SKU ID
AssetId int64 `json:"assetId"`
AssetName string `json:"assetName"` // 资产名称
SkuName string `json:"skuName"` // SKU名称
SpecsCount int `json:"specsCount"` // 规格数量
@@ -115,7 +113,7 @@ type AssetSkuListResItem struct {
UnlimitedStock bool `json:"unlimitedStock"` // 是否无库存限制
Stock int `json:"stock"` // 库存数量
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-批次模式
CreatedAt *gtime.Time `json:"createdAt"` // 创建时间
UpdatedAt *gtime.Time `json:"updatedAt"` // 更新时间

View File

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

View File

@@ -2,6 +2,7 @@ package dto
import (
"assets/consts/asset"
"github.com/gogf/gf/v2/frame/g"
)
@@ -39,7 +40,7 @@ type GetSpecsUnitRes struct {
// GetTenantModuleTypeReq 获取租户模块类型请求
type GetTenantModuleTypeReq struct {
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 获取租户模块类型响应

View File

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

View File

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

View File

@@ -11,8 +11,8 @@ import (
type StockOperationReq struct {
g.Meta `path:"/stockOperation" method:"post" tags:"库存管理" summary:"库存操作(创建/修改)" dc:"库存操作(创建/修改)"`
AssetSkuId *bson.ObjectID `json:"assetSkuId" v:"required" dc:"关联资产SKU ID"`
Stock int `json:"stock" v:"required|min:1" dc:"库存数量"`
AssetSkuId int64 `json:"assetSkuId" v:"required" dc:"关联资产SKU ID"`
Stock int `json:"stock" v:"required|min:1" dc:"库存数量"`
// 批次模式专用字段
BatchNo string `json:"batchNo" dc:"批次号(批次模式必填)"`
ProductionDate *gtime.Time `json:"productionDate" dc:"生产日期(批次模式,格式:2006-01-02)"`
@@ -22,8 +22,8 @@ type StockOperationReq struct {
// StockPublishMessage 库存发布消息
type StockPublishMessage struct {
AssetId string `json:"assetId"`
AssetSkuId string `json:"assetSkuId"`
AssetId int64 `json:"assetId"`
AssetSkuId int64 `json:"assetSkuId"`
TenantId interface{} `json:"tenantId"`
UserName interface{} `json:"userName"`
StockCount int `json:"stockCount"`
@@ -41,7 +41,7 @@ type StockPublishMessage struct {
type GetStockFormFieldsReq struct {
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 获取库存表单字段响应

View File

@@ -5,30 +5,74 @@ import (
"assets/consts/stock"
"gitea.com/red-future/common/beans"
"github.com/gogf/gf/v2/encoding/gjson"
"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 资产实体
type Asset struct {
beans.SQLBaseDO `orm:",inherit"` // 嵌入基础字段Id, Creator, CreatedAt, Updater, UpdatedAt, IsDeleted
beans.SQLBaseDO `orm:",inherit"`
// 基础信息
Name string `orm:"name" json:"name" description:"资产名称"`
Description string `orm:"description" json:"description" description:"资产描述"`
Type consts.AssetType `orm:"type" json:"type" description:"资产类型physical实物/virtual虚拟/service服务"`
CategoryId uint64 `orm:"category_id" json:"categoryId" description:"分类ID"`
CategoryPath string `orm:"category_path" json:"categoryPath" description:"分类路径"`
ImageURL string `orm:"image_url" json:"imageUrl" description:"主图URL"`
Images []string `orm:"images" json:"images" description:"图片列表(JSONB)"`
Status *consts.AssetStatus `orm:"status" json:"status" description:"资产状态1启用/0停用"`
BasePrice int `orm:"base_price" json:"basePrice" description:"基础价格(分为单位)"`
Currency string `orm:"currency" json:"currency" description:"货币单位默认CNY"`
UnlimitedStock bool `orm:"unlimited_stock" json:"unlimitedStock" description:"是否无库存限制"`
StockMode stock.StockMode `orm:"stock_mode" json:"stockMode" description:"库存管理模式1-明细模式 2-批次模式"`
// 上线和下线时间配置(由定时任务处理资产状态)
OnlineTime *gtime.Time `orm:"online_time" json:"onlineTime,omitempty" description:"线时间"`
OfflineTime *gtime.Time `orm:"offline_time" json:"offlineTime,omitempty" description:"下线时间"`
Name string `orm:"name" json:"name" description:"资产名称"`
Description string `orm:"description" json:"description" description:"资产描述"`
Type consts.AssetType `orm:"type" json:"type" description:"资产类型physical实物/virtual虚拟/service服务"`
CategoryId int64 `orm:"category_id" json:"categoryId" description:"分类ID"`
CategoryPath string `orm:"category_path" json:"categoryPath" description:"分类路径"`
ImageURL string `orm:"image_url" json:"imageUrl" description:"主图URL"`
Images []string `orm:"images" json:"images" description:"图片列表(JSONB)"`
Status consts.AssetStatusType `orm:"status" json:"status" description:"资产状态1启用/0停用"`
BasePrice int `orm:"base_price" json:"basePrice" description:"基础价格(分为单位)"`
Currency string `orm:"currency" json:"currency" description:"货币单位默认CNY"`
UnlimitedStock bool `orm:"unlimited_stock" json:"unlimitedStock" description:"是否无库存限制"`
StockMode stock.StockMode `orm:"stock_mode" json:"stockMode" description:"库存管理模式1-明细模式 2-批次模式"`
OnlineTime *gtime.Time `orm:"online_time" json:"onlineTime,omitempty" description:"上线时间"` // 上线和下线时间配置(由定时任务处理资产状态)
OfflineTime *gtime.Time `orm:"offline_time" json:"offlineTime,omitempty" description:"线时间"` // 上线和下线时间配置(由定时任务处理资产状态)
// 类型专用配置 - 实物资产配置(JSONB)
PhysicalAssetConfig *gjson.Json `orm:"physical_asset_config" json:"physicalAssetConfig" description:"实物资产配置(JSONB)"`
@@ -37,7 +81,7 @@ type Asset struct {
// 类型专用配置 - 虚拟资产配置(JSONB)
VirtualAssetConfig *gjson.Json `orm:"virtual_asset_config" json:"virtualAssetConfig" description:"虚拟资产配置(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 (
consts "assets/consts/asset"
"assets/consts/public"
"assets/consts/stock"
"assets/model/config"
"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实体
type AssetSku struct {
beans.MongoBaseDO `bson:",inline"` // 嵌入基础字段Id, Creator, CreatedAt, Updater, UpdatedAt, TenantId, IsDeleted
AssetId *bson.ObjectID `bson:"assetId" json:"assetId"` // 关联资产ID
AssetName string `bson:"assetName" json:"assetName"` // 资产名称
SkuName string `bson:"skuName" json:"skuName"` // SKU名称
ImageURL string `bson:"imageUrl,omitempty" json:"imageUrl"` // SKU主图
SpecValues []map[string]interface{} `bson:"specValues" json:"specValues"` // 规格值:{"颜色":"红色","尺寸":"L","时长":"1个月","平台":"抖音"}
Price int `bson:"price" json:"price"` // 价格(分为单位)
UnlimitedStock bool `bson:"unlimitedStock" json:"unlimitedStock"` // 是否无库存限制
Stock int `bson:"stock" json:"stock"` // 库存数量
SpecsCount int `bson:"specsCount" json:"specsCount"` // 规格数量
SpecsUnit *SpecsUnitKeyValue `bson:"specsUnit" json:"specsUnit"` // 规格单位
Sort int `bson:"sort" json:"sort"` // 排序
Status *consts.AssetSkuStatus `bson:"status" json:"status"` // 状态active/inactive/disabled
StockMode stock.StockMode `bson:"stockMode" json:"stockMode"` // 库存管理模式1-明细模式 2-批次模式
CategoryId *bson.ObjectID `bson:"categoryId" json:"categoryId"` // 分类ID
CategoryPath string `bson:"categoryPath" json:"categoryPath"` // 分类路径
CapacityUnitType stock.CapacityUnitType `bson:"capacityUnitType" json:"capacityUnitType"` // 容量单位类型
Capacity config.Capacity `bson:"capacity" json:"capacity"` //容量
TenantModuleType beans.TenantModuleType `bson:"tenantModuleType" json:"tenantModuleType"`
beans.SQLBaseDO `orm:",inherit"`
AssetId int64 `orm:"asset_id" json:"assetId"` // 关联资产ID
AssetName string `orm:"asset_name" json:"assetName"` // 资产名称
SkuName string `orm:"sku_name" json:"skuName"` // SKU名称
ImageURL string `orm:"image_url,omitempty" json:"imageUrl"` // SKU主图
SpecValues []gjson.Json `orm:"spec_values" json:"specValues"` // 规格值:{"颜色":"红色","尺寸":"L","时长":"1个月","平台":"抖音"}
Price int `orm:"price" json:"price"` // 价格(分为单位)
UnlimitedStock bool `orm:"unlimited_stock" json:"unlimitedStock"` // 是否无库存限制
Stock int `orm:"stock" json:"stock"` // 库存数量
SpecsCount int `orm:"specs_count" json:"specsCount"` // 规格数量
SpecsUnit *gjson.Json `orm:"specs_unit" json:"specsUnit"` // 规格单位 SpecsUnitKeyValue
Sort int `orm:"sort" json:"sort"` // 排序
Status consts.AssetSkuStatusType `orm:"status" json:"status"` // 状态active/inactive/disabled
StockMode stock.StockMode `orm:"stock_mode" json:"stockMode"` // 库存管理模式1-明细模式 2-批次模式
CategoryId int64 `orm:"category_id" json:"categoryId"` // 分类ID
CategoryPath string `orm:"category_path" json:"categoryPath"` // 分类路径
CapacityUnitType stock.CapacityUnitType `orm:"capacity_unit_type" json:"capacityUnitType"` // 容量单位类型
Capacity config.Capacity `orm:"capacity" json:"capacity"` // 容量
TenantModuleType beans.TenantModuleType `orm:"tenant_module_type" json:"tenantModuleType"` // 租户模块类型
}
type SpecsUnitKeyValue struct {
Key string `bson:"key" json:"key"` // 对应原有常量值
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"
"gitea.com/red-future/common/beans"
"github.com/gogf/gf/v2/encoding/gjson"
)
type categoryCol struct {
@@ -26,7 +25,7 @@ var CategoryCol = categoryCol{
ParentId: "parent_id",
Path: "path",
Level: "level",
IsLeafNode: "isLeaf_node",
IsLeafNode: "is_leaf_node",
Sort: "sort",
Image: "image",
Attrs: "attrs",
@@ -35,15 +34,16 @@ var CategoryCol = categoryCol{
// Category 分类实体
type Category struct {
beans.SQLBaseDO `orm:",inherit"` // 嵌入基础字段Id, Creator, CreatedAt, Updater, UpdatedAt, IsDeleted
Name string `orm:"name" json:"name"` // 分类名称
ParentId string `orm:"parent_id" json:"parentId"` // 父分类ID为空表示根分类
Path string `orm:"path" json:"path"` // 分类路径,如:/root/parent/child
Level int `orm:"level" json:"level"` // 分类层级
IsLeafNode bool `orm:"isLeaf_node" json:"isLeafNode"` // 是叶子节点
Sort int `orm:"sort" json:"sort"` // 排序
Image string `orm:"image" json:"image"` // 分类图片
Attrs []gjson.Json `orm:"attrs" json:"attrs,omitempty"` // 分类属性
beans.SQLBaseDO `orm:",inherit"`
Name string `orm:"name" json:"name"` // 分类名称
ParentId int64 `orm:"parent_id" json:"parentId"` // 父分类ID为空表示根分类
Path string `orm:"path" json:"path"` // 分类路径,如:/root/parent/child
Level int `orm:"level" json:"level"` // 分类层级
IsLeafNode *bool `orm:"is_leaf_node" json:"isLeafNode"` // 是叶子节点
Sort int `orm:"sort" json:"sort"` // 排序
Image string `orm:"image" json:"image"` // 分类图片
Status consts.CategoryStatusType `orm:"status" json:"status"` // 状态1启用/0禁用
Attrs []CategoryAttr `orm:"attrs" json:"attrs,omitempty"` // 分类属性 CategoryAttr
// 使用场景说明:
// 1. 商品分类属性:为该分类下的商品定义标准化的属性模板,如服装分类可定义尺寸、颜色、材质等属性
// 2. 服务分类属性:为服务类目定义特性参数,如咨询服务可定义服务时长、服务方式、专业领域等
@@ -51,20 +51,18 @@ type Category struct {
// 4. 搜索筛选:基于分类属性进行商品筛选和搜索,提升用户体验
// 5. 数据标准化:确保同一分类下的商品具有统一的属性结构,便于数据管理
// 支持的属性类型:文本(text)、数字(number)、日期(date)、单选(select)、多选(multi_select)、布尔(boolean)、图片(image)
Status consts.CategoryStatusType `orm:"status" json:"status"` // 状态1启用/0禁用
}
// CategoryAttr 分类属性
// 用于定义分类下商品或服务的标准化属性模板,确保同类商品属性统一
// Attrs 用于定义分类下商品或服务的标准化属性模板,确保同类商品属性统一
type CategoryAttr struct {
Name string `json:"name"` // 属性名称,如:尺寸、颜色、品牌等
Type string `json:"type"` // 属性类型text文本/number数字/date日期/select选择/multi_select多选/boolean布尔/image图片
DictType string `json:"dictType"` // 字典类型如果是select/multi_select类型时有效
Required bool `json:"required"` // 是否必填true表示商品发布时必须填写此属性
Options []FieldOption `json:"options"` // 选项配置JSON字符串格式用于select/multi_select类型的可选值列表
// 示例:'{"options":[{"label":"红色","value":"red"},{"label":"蓝色","value":"blue"}]}'
Description string `json:"description"` // 属性描述,向用户说明此属性的具体含义和填写要求
Sort int `json:"sort"` // 排序权重,数值越小排序越靠前,用于属性在界面的显示顺序
Name string `json:"name"` // 属性名称,如:尺寸、颜色、品牌等
Type string `json:"type"` // 属性类型text文本/number数字/date日期/select选择/multi_select多选/boolean布尔/image图片
DictType string `json:"dictType"` // 字典类型如果是select/multi_select类型时有效
Required bool `json:"required"` // 是否必填true表示商品发布时必须填写此属性
Options []FieldOption `json:"options"` // 选项配置JSON字符串格式用于select/multi_select类型的可选值列表 // 示例:'{"options":[{"label":"红色","value":"red"},{"label":"蓝色","value":"blue"}]}'
Description string `json:"description"` // 属性描述,向用户说明此属性的具体含义和填写要求
Sort int `json:"sort"` // 排序权重,数值越小排序越靠前,用于属性在界面的显示顺序
}
// FieldOption 字段选项

View File

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

View File

@@ -3,18 +3,19 @@ package service
import (
"assets/consts/stock"
dao "assets/dao/asset"
"assets/dao/base"
dto "assets/model/dto/asset"
enumDto "assets/model/dto/enum"
entity "assets/model/entity/asset"
service "assets/service/enum"
"context"
"errors"
"fmt"
"gitea.com/red-future/common/http"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
"gitea.com/red-future/common/beans"
"gitea.com/red-future/common/minio"
"gitea.com/red-future/common/utils"
)
type asset struct{}
@@ -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 {
return
}
if !isSuperAdmin {
req.StockMode = stock.StockModeDetail
//var getUserInfo beans.User
//getUserInfo, err = utils.GetUserInfo(ctx)
//if err != nil {
// return
//}
//var get *gvar.Var
//get, err = message.GetRedisClientTest("test").Get(ctx, fmt.Sprintf("module_tenant:tenantId-%v", getUserInfo.TenantId))
//if err != nil {
// return
//}
//if !g.IsEmpty(get.String()) {
// list := new(beans.ModuleTenant)
// if err = json.Unmarshal(get.Bytes(), &list); err != nil {
// return
// }
// req.TenantModuleType = list.TenantModuleType
//} else {
// moduleTenantRes := new(beans.ModuleTenant)
// err = message.CallRPC(ctx, "moduleService.AddRedisByTenantId", map[string]interface{}{"tenantId": getUserInfo.TenantId}, moduleTenantRes)
// if err != nil {
// return
// }
// if !g.IsEmpty(moduleTenantRes.TenantModuleType) {
// req.TenantModuleType = moduleTenantRes.TenantModuleType
// } else {
// return nil, errors.New("您未开通此模块,请开通后再使用")
// }
//}
} else {
req.TenantModuleType = beans.TenantModuleTypePlatform
}
@@ -87,7 +58,7 @@ func (s *asset) Create(ctx context.Context, req *dto.CreateAssetReq) (res *dto.C
return
}
res = &dto.CreateAssetRes{
Id: gconv.Uint64(id),
Id: id,
}
return
}
@@ -98,79 +69,88 @@ func (s *asset) List(ctx context.Context, req *dto.ListAssetReq) (res *dto.ListA
if err != nil {
return
}
user, err := utils.GetUserInfo(ctx)
if err != nil {
return
}
fmt.Println(user)
res = &dto.ListAssetRes{
Total: total,
}
err = utils.Struct(assetList, &res.List)
err = gconv.Struct(assetList, &res.List)
return
}
// GetOne 获取单个资产
func (s *asset) GetOne(ctx context.Context, req *dto.GetAssetReq) (res *dto.GetAssetRes, err error) {
assetOne, err := dao.Asset.GetOne(ctx, req)
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 {
return
}
// TODO: CategoryId类型不匹配需要同步修改category为uint64
// getCategoryRes, err := dao.Category.GetOne(ctx, &dto.GetCategoryReq{
// Id: assetOne.CategoryId,
// })
// if err != nil {
// return
// }
return &dto.GetAssetRes{
Asset: assetOne,
CategoryName: "", // getCategoryRes.Name,
AssetItem: assetListItem,
CategoryName: getCategoryRes.Name,
ImgAddressPrefix: minio.GetFileAddressPrefix(ctx),
}, nil
}
// GetAssetAndSku 获取资产和Sku详情
func (s *asset) GetAssetAndSku(ctx context.Context, req *dto.GetAssetAndSkuReq) (res *dto.GetAssetAndSkuRes, err error) {
// 跳过租户ID过滤获取资产
// TODO: AssetId 类型不匹配bson.ObjectID 需要转换为 uint64
// 使用 SkipTenantId 跳过租户ID过滤
assetOne, err := dao.Asset.GetOneById(base.SkipTenantId(ctx), 0)
_ = req.AssetId
var updateReq *dto.GetAssetReq
if err = gconv.Struct(req, &updateReq); err != nil {
return
}
assetOne, err := dao.Asset.GetOne(ctx, updateReq)
if err != nil {
return
}
// TODO: AssetId类型不匹配需要适配
// moduleType, err := service.Enum.GetTenantModuleType(ctx, &enumDto.GetTenantModuleTypeReq{AssetId: req.AssetId.Hex()})
// if err != nil {
// return
// }
// TODO: AssetId类型不匹配需要同步修改AssetSku为uint64
// skus, _, err := dao.AssetSku.List(ctx, &dto.ListAssetSkuReq{AssetId: req.AssetId}, true)
// if err != nil {
// return
// }
var assetListItem *dto.AssetItem
if err = gconv.Struct(assetOne, assetListItem); err != nil {
return
}
moduleType, err := service.Enum.GetTenantModuleType(ctx, &enumDto.GetTenantModuleTypeReq{AssetId: assetOne.Id})
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{
Asset: assetOne,
Skus: nil, // skus,
TenantModuleType: nil, // moduleType.Options,
AssetItem: assetListItem,
Skus: assetSkuListResItem,
TenantModuleType: moduleType.Options,
ImgAddressPrefix: minio.GetFileAddressPrefix(ctx),
}, nil
}
// Update 更新资产
func (s *asset) Update(ctx context.Context, req *dto.UpdateAssetReq) error {
return dao.Asset.Update(ctx, req)
func (s *asset) Update(ctx context.Context, req *dto.UpdateAssetReq) (err error) {
_, err = dao.Asset.Update(ctx, req)
return
}
// UpdateStatus 更新资产状态
func (s *asset) UpdateStatus(ctx context.Context, req *dto.UpdateAssetStatusReq) (err error) {
var updateReq *dto.UpdateAssetReq
err = utils.Struct(req, &updateReq)
return dao.Asset.Update(ctx, updateReq)
if err = gconv.Struct(req, &updateReq); err != nil {
return err
}
_, err = dao.Asset.Update(ctx, updateReq)
return
}
// Delete 删除资产
func (s *asset) Delete(ctx context.Context, req *dto.DeleteAssetReq) error {
return dao.Asset.DeleteFake(ctx, req)
func (s *asset) Delete(ctx context.Context, req *dto.DeleteAssetReq) (err error) {
_, err = dao.Asset.Delete(ctx, req)
return
}

View File

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

View File

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

View File

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

View File

@@ -1,20 +1,17 @@
-----------2025-06-16 15:00:00--------------
--------------------pgsql创建assets_category表语句---------------------------
-- 分类主表
CREATE TABLE IF NOT EXISTS assets_category (
-- 基础字段
id BIGSERIAL PRIMARY KEY,
id BIGINT PRIMARY KEY, -- 从BIGSERIAL改为BIGINT取消自增
creator VARCHAR(64) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updater VARCHAR(64) NOT NULL,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleter VARCHAR(64),
deleted_at timestamp(6),
-- 分类核心字段
bid VARCHAR(64) NOT NULL,
-- 分类核心字段移除bid字段
name VARCHAR(128) NOT NULL,
parent_id VARCHAR(64) DEFAULT '',
path VARCHAR(512) DEFAULT '',
@@ -23,27 +20,23 @@ CREATE TABLE IF NOT EXISTS assets_category (
sort INT NOT NULL DEFAULT 0,
image VARCHAR(256) DEFAULT '',
attrs JSONB DEFAULT '[]'::JSONB,
status SMALLINT NOT NULL DEFAULT 1,
-- 唯一索引 & 普通索引
CONSTRAINT uk_category_id UNIQUE (bid)
status SMALLINT NOT NULL DEFAULT 1
);
-- 为分类表添加索引PostgreSQL 索引单独创建)
-- 为分类表添加索引移除原uk_category_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_status ON assets_category(status);
CREATE INDEX idx_category_is_leaf_node ON assets_category(is_leaf_node);
-- 分类表字段注释
-- 分类表字段注释移除bid字段注释
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.created_at IS '创建时间';
COMMENT ON COLUMN assets_category.updater 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.bid IS '业务ID';
COMMENT ON COLUMN assets_category.name IS '分类名称';
COMMENT ON COLUMN assets_category.parent_id IS '父分类ID为空表示根分类';
COMMENT ON COLUMN assets_category.path IS '分类路径,如:/root/parent/child';
@@ -61,20 +54,18 @@ COMMENT ON COLUMN assets_category.status IS '状态1启用/0禁用';
-- 资产表asset
CREATE TABLE IF NOT EXISTS assets_asset (
-- 嵌入基础字段(复用 SQLBaseDO 结构)
id BIGSERIAL PRIMARY KEY,
id BIGINT PRIMARY KEY, -- 从BIGSERIAL改为BIGINT取消自增
creator VARCHAR(64) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updater VARCHAR(64) NOT NULL,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleter VARCHAR(64),
deleted_at timestamp(6),
-- 基础信息字段
bid VARCHAR(64) NOT NULL,
-- 基础信息字段移除bid字段
name VARCHAR(128) NOT NULL,
description TEXT DEFAULT '',
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 '',
image_url VARCHAR(512) DEFAULT '',
images JSONB DEFAULT '[]'::JSONB, -- 图片列表字符串数组JSONB存储
@@ -93,13 +84,10 @@ CREATE TABLE IF NOT EXISTS assets_asset (
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_type ON assets_asset(type);
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_tenant_module_type ON assets_asset(tenant_module_type);
-- 为资产表添加注释(PostgreSQL 专属语法
-- 为资产表添加注释(移除bid字段注释更新id注释
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.created_at IS '创建时间';
COMMENT ON COLUMN assets_asset.updater 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.bid IS '业务ID';
COMMENT ON COLUMN assets_asset.name IS '资产名称';
COMMENT ON COLUMN assets_asset.description IS '资产描述';
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.image_url IS '主图URL';
COMMENT ON COLUMN assets_asset.images IS '图片列表(JSONB)';