refactor: 优化订单时间字段处理及数据库模型结构调整

- 将订单的PaidAt和CancelledAt从指针类型改为值类型
- 统一时间字段的判空逻辑,使用IsZero()替代nil检查
- 调整多个数据库模型结构,添加新字段并优化字段顺序
- 为活动奖励设置、用户邀请等表添加新字段
- 更新对应的DAO层代码以匹配模型变更
This commit is contained in:
邹方成 2025-12-23 23:37:59 +08:00
parent a7a0f639e1
commit 425e64daa5
19 changed files with 374 additions and 312 deletions

View File

@ -253,7 +253,7 @@ func (h *handler) ListPayOrders() core.HandlerFunc {
"actual_amount": o.ActualAmount, "actual_amount": o.ActualAmount,
"status": o.Status, "status": o.Status,
"paid_at": func() string { "paid_at": func() string {
if o.PaidAt != nil && !o.PaidAt.IsZero() { if !o.PaidAt.IsZero() {
return o.PaidAt.Format("2006-01-02 15:04:05") return o.PaidAt.Format("2006-01-02 15:04:05")
} }
return "" return ""
@ -585,7 +585,7 @@ func (h *handler) GetPayOrderDetail() core.HandlerFunc {
Status: order.Status, Status: order.Status,
ActualAmount: order.ActualAmount, ActualAmount: order.ActualAmount,
PaidAt: func() string { PaidAt: func() string {
if order.PaidAt != nil && !order.PaidAt.IsZero() { if !order.PaidAt.IsZero() {
return order.PaidAt.Format("2006-01-02 15:04:05") return order.PaidAt.Format("2006-01-02 15:04:05")
} }
return "" return ""

View File

@ -100,7 +100,7 @@ func (h *handler) ExportPayOrders() core.HandlerFunc {
r.AddCell().SetInt64(pu) r.AddCell().SetInt64(pu)
r.AddCell().SetInt64(couponApplied) r.AddCell().SetInt64(couponApplied)
r.AddCell().SetInt64(o.ActualAmount) r.AddCell().SetInt64(o.ActualAmount)
if o.PaidAt != nil { if !o.PaidAt.IsZero() {
r.AddCell().Value = o.PaidAt.Format("2006-01-02 15:04:05") r.AddCell().Value = o.PaidAt.Format("2006-01-02 15:04:05")
} else { } else {
r.AddCell().Value = "" r.AddCell().Value = ""

View File

@ -11,12 +11,13 @@ import (
) )
type createProductRequest struct { type createProductRequest struct {
Name string `json:"name" binding:"required"` Name string `json:"name" binding:"required"`
CategoryID int64 `json:"category_id" binding:"required"` CategoryID int64 `json:"category_id" binding:"required"`
ImagesJSON string `json:"images_json"` ImagesJSON string `json:"images_json"`
Price int64 `json:"price" binding:"required"` Price int64 `json:"price" binding:"required"`
Stock int64 `json:"stock" binding:"required"` Stock int64 `json:"stock" binding:"required"`
Status int32 `json:"status"` Status int32 `json:"status"`
Description string `json:"description"`
} }
type createProductResponse struct { type createProductResponse struct {
@ -46,7 +47,7 @@ func (h *handler) CreateProduct() core.HandlerFunc {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作")) ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
return return
} }
item, err := h.product.CreateProduct(ctx.RequestContext(), prodsvc.CreateProductInput{Name: req.Name, CategoryID: req.CategoryID, ImagesJSON: req.ImagesJSON, Price: req.Price, Stock: req.Stock, Status: req.Status}) item, err := h.product.CreateProduct(ctx.RequestContext(), prodsvc.CreateProductInput{Name: req.Name, CategoryID: req.CategoryID, ImagesJSON: req.ImagesJSON, Price: req.Price, Stock: req.Stock, Status: req.Status, Description: req.Description})
if err != nil { if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
return return
@ -58,12 +59,13 @@ func (h *handler) CreateProduct() core.HandlerFunc {
} }
type modifyProductRequest struct { type modifyProductRequest struct {
Name *string `json:"name"` Name *string `json:"name"`
CategoryID *int64 `json:"category_id"` CategoryID *int64 `json:"category_id"`
ImagesJSON *string `json:"images_json"` ImagesJSON *string `json:"images_json"`
Price *int64 `json:"price"` Price *int64 `json:"price"`
Stock *int64 `json:"stock"` Stock *int64 `json:"stock"`
Status *int32 `json:"status"` Status *int32 `json:"status"`
Description *string `json:"description"`
} }
// ModifyProduct 修改商品 // ModifyProduct 修改商品
@ -90,7 +92,7 @@ func (h *handler) ModifyProduct() core.HandlerFunc {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作")) ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
return return
} }
if err := h.product.ModifyProduct(ctx.RequestContext(), id, prodsvc.ModifyProductInput{Name: req.Name, CategoryID: req.CategoryID, ImagesJSON: req.ImagesJSON, Price: req.Price, Stock: req.Stock, Status: req.Status}); err != nil { if err := h.product.ModifyProduct(ctx.RequestContext(), id, prodsvc.ModifyProductInput{Name: req.Name, CategoryID: req.CategoryID, ImagesJSON: req.ImagesJSON, Price: req.Price, Stock: req.Stock, Status: req.Status, Description: req.Description}); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
return return
} }
@ -133,14 +135,15 @@ type listProductsRequest struct {
} }
type productItem struct { type productItem struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`
CategoryID int64 `json:"category_id"` CategoryID int64 `json:"category_id"`
ImagesJSON string `json:"images_json"` ImagesJSON string `json:"images_json"`
Price int64 `json:"price"` Price int64 `json:"price"`
Stock int64 `json:"stock"` Stock int64 `json:"stock"`
Sales int64 `json:"sales"` Sales int64 `json:"sales"`
Status int32 `json:"status"` Status int32 `json:"status"`
Description string `json:"description"`
} }
type listProductsResponse struct { type listProductsResponse struct {
Page int `json:"page"` Page int `json:"page"`
@ -181,7 +184,7 @@ func (h *handler) ListProducts() core.HandlerFunc {
res.Total = total res.Total = total
res.List = make([]productItem, len(items)) res.List = make([]productItem, len(items))
for i, it := range items { for i, it := range items {
res.List[i] = productItem{ID: it.ID, Name: it.Name, CategoryID: it.CategoryID, ImagesJSON: it.ImagesJSON, Price: it.Price, Stock: it.Stock, Sales: it.Sales, Status: it.Status} res.List[i] = productItem{ID: it.ID, Name: it.Name, CategoryID: it.CategoryID, ImagesJSON: it.ImagesJSON, Price: it.Price, Stock: it.Stock, Sales: it.Sales, Status: it.Status, Description: it.Description}
} }
ctx.Payload(res) ctx.Payload(res)
} }

View File

@ -141,7 +141,7 @@ func (h *handler) CancelOrder() core.HandlerFunc {
OrderID: order.ID, OrderID: order.ID,
OrderNo: order.OrderNo, OrderNo: order.OrderNo,
Status: order.Status, Status: order.Status,
CancelledAt: order.CancelledAt, CancelledAt: &order.CancelledAt,
}) })
} }
} }

View File

@ -55,6 +55,10 @@ func newActivities(db *gorm.DB, opts ...gen.DOOption) activities {
_activities.CommitmentStateVersion = field.NewInt32(tableName, "commitment_state_version") _activities.CommitmentStateVersion = field.NewInt32(tableName, "commitment_state_version")
_activities.CommitmentItemsRoot = field.NewBytes(tableName, "commitment_items_root") _activities.CommitmentItemsRoot = field.NewBytes(tableName, "commitment_items_root")
_activities.GameplayIntro = field.NewString(tableName, "gameplay_intro") _activities.GameplayIntro = field.NewString(tableName, "gameplay_intro")
_activities.DailySeed = field.NewString(tableName, "daily_seed")
_activities.DailySeedDate = field.NewString(tableName, "daily_seed_date")
_activities.LastDailySeed = field.NewString(tableName, "last_daily_seed")
_activities.LastDailySeedDate = field.NewString(tableName, "last_daily_seed_date")
_activities.fillFieldMap() _activities.fillFieldMap()
@ -94,6 +98,10 @@ type activities struct {
CommitmentStateVersion field.Int32 CommitmentStateVersion field.Int32
CommitmentItemsRoot field.Bytes CommitmentItemsRoot field.Bytes
GameplayIntro field.String // 玩法介绍 GameplayIntro field.String // 玩法介绍
DailySeed field.String
DailySeedDate field.String // 种子日期(YYYY-MM-DD)
LastDailySeed field.String // 昨日种子
LastDailySeedDate field.String // 昨日种子日期
fieldMap map[string]field.Expr fieldMap map[string]field.Expr
} }
@ -138,6 +146,10 @@ func (a *activities) updateTableName(table string) *activities {
a.CommitmentStateVersion = field.NewInt32(table, "commitment_state_version") a.CommitmentStateVersion = field.NewInt32(table, "commitment_state_version")
a.CommitmentItemsRoot = field.NewBytes(table, "commitment_items_root") a.CommitmentItemsRoot = field.NewBytes(table, "commitment_items_root")
a.GameplayIntro = field.NewString(table, "gameplay_intro") a.GameplayIntro = field.NewString(table, "gameplay_intro")
a.DailySeed = field.NewString(table, "daily_seed")
a.DailySeedDate = field.NewString(table, "daily_seed_date")
a.LastDailySeed = field.NewString(table, "last_daily_seed")
a.LastDailySeedDate = field.NewString(table, "last_daily_seed_date")
a.fillFieldMap() a.fillFieldMap()
@ -154,7 +166,7 @@ func (a *activities) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
} }
func (a *activities) fillFieldMap() { func (a *activities) fillFieldMap() {
a.fieldMap = make(map[string]field.Expr, 28) a.fieldMap = make(map[string]field.Expr, 32)
a.fieldMap["id"] = a.ID a.fieldMap["id"] = a.ID
a.fieldMap["created_at"] = a.CreatedAt a.fieldMap["created_at"] = a.CreatedAt
a.fieldMap["updated_at"] = a.UpdatedAt a.fieldMap["updated_at"] = a.UpdatedAt
@ -183,6 +195,10 @@ func (a *activities) fillFieldMap() {
a.fieldMap["commitment_state_version"] = a.CommitmentStateVersion a.fieldMap["commitment_state_version"] = a.CommitmentStateVersion
a.fieldMap["commitment_items_root"] = a.CommitmentItemsRoot a.fieldMap["commitment_items_root"] = a.CommitmentItemsRoot
a.fieldMap["gameplay_intro"] = a.GameplayIntro a.fieldMap["gameplay_intro"] = a.GameplayIntro
a.fieldMap["daily_seed"] = a.DailySeed
a.fieldMap["daily_seed_date"] = a.DailySeedDate
a.fieldMap["last_daily_seed"] = a.LastDailySeed
a.fieldMap["last_daily_seed_date"] = a.LastDailySeedDate
} }
func (a activities) clone(db *gorm.DB) activities { func (a activities) clone(db *gorm.DB) activities {

View File

@ -40,6 +40,7 @@ func newActivityRewardSettings(db *gorm.DB, opts ...gen.DOOption) activityReward
_activityRewardSettings.Sort = field.NewInt32(tableName, "sort") _activityRewardSettings.Sort = field.NewInt32(tableName, "sort")
_activityRewardSettings.IsBoss = field.NewInt32(tableName, "is_boss") _activityRewardSettings.IsBoss = field.NewInt32(tableName, "is_boss")
_activityRewardSettings.DeletedAt = field.NewField(tableName, "deleted_at") _activityRewardSettings.DeletedAt = field.NewField(tableName, "deleted_at")
_activityRewardSettings.MinScore = field.NewInt64(tableName, "min_score")
_activityRewardSettings.fillFieldMap() _activityRewardSettings.fillFieldMap()
@ -64,6 +65,7 @@ type activityRewardSettings struct {
Sort field.Int32 // 排序 Sort field.Int32 // 排序
IsBoss field.Int32 // Boss 1 是 0 不是 IsBoss field.Int32 // Boss 1 是 0 不是
DeletedAt field.Field DeletedAt field.Field
MinScore field.Int64 // 最低得分/碰数要求
fieldMap map[string]field.Expr fieldMap map[string]field.Expr
} }
@ -93,6 +95,7 @@ func (a *activityRewardSettings) updateTableName(table string) *activityRewardSe
a.Sort = field.NewInt32(table, "sort") a.Sort = field.NewInt32(table, "sort")
a.IsBoss = field.NewInt32(table, "is_boss") a.IsBoss = field.NewInt32(table, "is_boss")
a.DeletedAt = field.NewField(table, "deleted_at") a.DeletedAt = field.NewField(table, "deleted_at")
a.MinScore = field.NewInt64(table, "min_score")
a.fillFieldMap() a.fillFieldMap()
@ -109,7 +112,7 @@ func (a *activityRewardSettings) GetFieldByName(fieldName string) (field.OrderEx
} }
func (a *activityRewardSettings) fillFieldMap() { func (a *activityRewardSettings) fillFieldMap() {
a.fieldMap = make(map[string]field.Expr, 13) a.fieldMap = make(map[string]field.Expr, 14)
a.fieldMap["id"] = a.ID a.fieldMap["id"] = a.ID
a.fieldMap["created_at"] = a.CreatedAt a.fieldMap["created_at"] = a.CreatedAt
a.fieldMap["updated_at"] = a.UpdatedAt a.fieldMap["updated_at"] = a.UpdatedAt
@ -123,6 +126,7 @@ func (a *activityRewardSettings) fillFieldMap() {
a.fieldMap["sort"] = a.Sort a.fieldMap["sort"] = a.Sort
a.fieldMap["is_boss"] = a.IsBoss a.fieldMap["is_boss"] = a.IsBoss
a.fieldMap["deleted_at"] = a.DeletedAt a.fieldMap["deleted_at"] = a.DeletedAt
a.fieldMap["min_score"] = a.MinScore
} }
func (a activityRewardSettings) clone(db *gorm.DB) activityRewardSettings { func (a activityRewardSettings) clone(db *gorm.DB) activityRewardSettings {

View File

@ -44,6 +44,8 @@ func newOrders(db *gorm.DB, opts ...gen.DOOption) orders {
_orders.UserAddressID = field.NewInt64(tableName, "user_address_id") _orders.UserAddressID = field.NewInt64(tableName, "user_address_id")
_orders.IsConsumed = field.NewInt32(tableName, "is_consumed") _orders.IsConsumed = field.NewInt32(tableName, "is_consumed")
_orders.PointsLedgerID = field.NewInt64(tableName, "points_ledger_id") _orders.PointsLedgerID = field.NewInt64(tableName, "points_ledger_id")
_orders.CouponID = field.NewInt64(tableName, "coupon_id")
_orders.ItemCardID = field.NewInt64(tableName, "item_card_id")
_orders.Remark = field.NewString(tableName, "remark") _orders.Remark = field.NewString(tableName, "remark")
_orders.fillFieldMap() _orders.fillFieldMap()
@ -73,6 +75,8 @@ type orders struct {
UserAddressID field.Int64 // 收货地址IDuser_addresses.id UserAddressID field.Int64 // 收货地址IDuser_addresses.id
IsConsumed field.Int32 // 是否已履约/消耗(对虚拟资产) IsConsumed field.Int32 // 是否已履约/消耗(对虚拟资产)
PointsLedgerID field.Int64 // 积分扣减流水IDuser_points_ledger.id PointsLedgerID field.Int64 // 积分扣减流水IDuser_points_ledger.id
CouponID field.Int64 // 使用的优惠券ID
ItemCardID field.Int64 // 使用的道具卡ID
Remark field.String // 备注 Remark field.String // 备注
fieldMap map[string]field.Expr fieldMap map[string]field.Expr
@ -107,6 +111,8 @@ func (o *orders) updateTableName(table string) *orders {
o.UserAddressID = field.NewInt64(table, "user_address_id") o.UserAddressID = field.NewInt64(table, "user_address_id")
o.IsConsumed = field.NewInt32(table, "is_consumed") o.IsConsumed = field.NewInt32(table, "is_consumed")
o.PointsLedgerID = field.NewInt64(table, "points_ledger_id") o.PointsLedgerID = field.NewInt64(table, "points_ledger_id")
o.CouponID = field.NewInt64(table, "coupon_id")
o.ItemCardID = field.NewInt64(table, "item_card_id")
o.Remark = field.NewString(table, "remark") o.Remark = field.NewString(table, "remark")
o.fillFieldMap() o.fillFieldMap()
@ -124,7 +130,7 @@ func (o *orders) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
} }
func (o *orders) fillFieldMap() { func (o *orders) fillFieldMap() {
o.fieldMap = make(map[string]field.Expr, 18) o.fieldMap = make(map[string]field.Expr, 20)
o.fieldMap["id"] = o.ID o.fieldMap["id"] = o.ID
o.fieldMap["created_at"] = o.CreatedAt o.fieldMap["created_at"] = o.CreatedAt
o.fieldMap["updated_at"] = o.UpdatedAt o.fieldMap["updated_at"] = o.UpdatedAt
@ -142,6 +148,8 @@ func (o *orders) fillFieldMap() {
o.fieldMap["user_address_id"] = o.UserAddressID o.fieldMap["user_address_id"] = o.UserAddressID
o.fieldMap["is_consumed"] = o.IsConsumed o.fieldMap["is_consumed"] = o.IsConsumed
o.fieldMap["points_ledger_id"] = o.PointsLedgerID o.fieldMap["points_ledger_id"] = o.PointsLedgerID
o.fieldMap["coupon_id"] = o.CouponID
o.fieldMap["item_card_id"] = o.ItemCardID
o.fieldMap["remark"] = o.Remark o.fieldMap["remark"] = o.Remark
} }

View File

@ -38,6 +38,7 @@ func newProducts(db *gorm.DB, opts ...gen.DOOption) products {
_products.Sales = field.NewInt64(tableName, "sales") _products.Sales = field.NewInt64(tableName, "sales")
_products.Status = field.NewInt32(tableName, "status") _products.Status = field.NewInt32(tableName, "status")
_products.DeletedAt = field.NewField(tableName, "deleted_at") _products.DeletedAt = field.NewField(tableName, "deleted_at")
_products.Description = field.NewString(tableName, "description")
_products.fillFieldMap() _products.fillFieldMap()
@ -48,18 +49,19 @@ func newProducts(db *gorm.DB, opts ...gen.DOOption) products {
type products struct { type products struct {
productsDo productsDo
ALL field.Asterisk ALL field.Asterisk
ID field.Int64 // 主键ID ID field.Int64 // 主键ID
CreatedAt field.Time // 创建时间 CreatedAt field.Time // 创建时间
UpdatedAt field.Time // 更新时间 UpdatedAt field.Time // 更新时间
Name field.String // 商品名称 Name field.String // 商品名称
CategoryID field.Int64 // 单一主分类IDproduct_categories.id CategoryID field.Int64 // 单一主分类IDproduct_categories.id
ImagesJSON field.String // 商品图片JSON数组 ImagesJSON field.String // 商品图片JSON数组
Price field.Int64 // 商品售价(分) Price field.Int64 // 商品售价(分)
Stock field.Int64 // 可售库存 Stock field.Int64 // 可售库存
Sales field.Int64 // 已售数量 Sales field.Int64 // 已售数量
Status field.Int32 // 上下架状态1上架 2下架 Status field.Int32 // 上下架状态1上架 2下架
DeletedAt field.Field DeletedAt field.Field
Description field.String // 商品详情
fieldMap map[string]field.Expr fieldMap map[string]field.Expr
} }
@ -87,6 +89,7 @@ func (p *products) updateTableName(table string) *products {
p.Sales = field.NewInt64(table, "sales") p.Sales = field.NewInt64(table, "sales")
p.Status = field.NewInt32(table, "status") p.Status = field.NewInt32(table, "status")
p.DeletedAt = field.NewField(table, "deleted_at") p.DeletedAt = field.NewField(table, "deleted_at")
p.Description = field.NewString(table, "description")
p.fillFieldMap() p.fillFieldMap()
@ -103,7 +106,7 @@ func (p *products) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
} }
func (p *products) fillFieldMap() { func (p *products) fillFieldMap() {
p.fieldMap = make(map[string]field.Expr, 11) p.fieldMap = make(map[string]field.Expr, 12)
p.fieldMap["id"] = p.ID p.fieldMap["id"] = p.ID
p.fieldMap["created_at"] = p.CreatedAt p.fieldMap["created_at"] = p.CreatedAt
p.fieldMap["updated_at"] = p.UpdatedAt p.fieldMap["updated_at"] = p.UpdatedAt
@ -115,6 +118,7 @@ func (p *products) fillFieldMap() {
p.fieldMap["sales"] = p.Sales p.fieldMap["sales"] = p.Sales
p.fieldMap["status"] = p.Status p.fieldMap["status"] = p.Status
p.fieldMap["deleted_at"] = p.DeletedAt p.fieldMap["deleted_at"] = p.DeletedAt
p.fieldMap["description"] = p.Description
} }
func (p products) clone(db *gorm.DB) products { func (p products) clone(db *gorm.DB) products {

View File

@ -37,6 +37,7 @@ func newTaskCenterTaskTiers(db *gorm.DB, opts ...gen.DOOption) taskCenterTaskTie
_taskCenterTaskTiers.Priority = field.NewInt32(tableName, "priority") _taskCenterTaskTiers.Priority = field.NewInt32(tableName, "priority")
_taskCenterTaskTiers.CreatedAt = field.NewTime(tableName, "created_at") _taskCenterTaskTiers.CreatedAt = field.NewTime(tableName, "created_at")
_taskCenterTaskTiers.UpdatedAt = field.NewTime(tableName, "updated_at") _taskCenterTaskTiers.UpdatedAt = field.NewTime(tableName, "updated_at")
_taskCenterTaskTiers.ExtraParams = field.NewString(tableName, "extra_params")
_taskCenterTaskTiers.fillFieldMap() _taskCenterTaskTiers.fillFieldMap()
@ -47,17 +48,18 @@ func newTaskCenterTaskTiers(db *gorm.DB, opts ...gen.DOOption) taskCenterTaskTie
type taskCenterTaskTiers struct { type taskCenterTaskTiers struct {
taskCenterTaskTiersDo taskCenterTaskTiersDo
ALL field.Asterisk ALL field.Asterisk
ID field.Int64 // 主键ID ID field.Int64 // 主键ID
TaskID field.Int64 // 关联任务IDtask_center_tasks.id TaskID field.Int64 // 关联任务IDtask_center_tasks.id
Metric field.String // 指标first_order|order_count|invite_count Metric field.String // 指标first_order|order_count|invite_count
Operator field.String // 比较符:>= 或 == Operator field.String // 比较符:>= 或 ==
Threshold field.Int64 // 阈值(数量或布尔首单) Threshold field.Int64 // 阈值(数量或布尔首单)
Window field.String // 时间窗口activity_period|since_registration Window field.String // 时间窗口activity_period|since_registration
Repeatable field.Int32 // 是否每档一次0否 1是 Repeatable field.Int32 // 是否每档一次0否 1是
Priority field.Int32 // 匹配优先级(数值越小越先匹配) Priority field.Int32 // 匹配优先级(数值越小越先匹配)
CreatedAt field.Time // 创建时间 CreatedAt field.Time // 创建时间
UpdatedAt field.Time // 更新时间 UpdatedAt field.Time // 更新时间
ExtraParams field.String // 额外参数配置(如消费门槛)
fieldMap map[string]field.Expr fieldMap map[string]field.Expr
} }
@ -84,6 +86,7 @@ func (t *taskCenterTaskTiers) updateTableName(table string) *taskCenterTaskTiers
t.Priority = field.NewInt32(table, "priority") t.Priority = field.NewInt32(table, "priority")
t.CreatedAt = field.NewTime(table, "created_at") t.CreatedAt = field.NewTime(table, "created_at")
t.UpdatedAt = field.NewTime(table, "updated_at") t.UpdatedAt = field.NewTime(table, "updated_at")
t.ExtraParams = field.NewString(table, "extra_params")
t.fillFieldMap() t.fillFieldMap()
@ -100,7 +103,7 @@ func (t *taskCenterTaskTiers) GetFieldByName(fieldName string) (field.OrderExpr,
} }
func (t *taskCenterTaskTiers) fillFieldMap() { func (t *taskCenterTaskTiers) fillFieldMap() {
t.fieldMap = make(map[string]field.Expr, 10) t.fieldMap = make(map[string]field.Expr, 11)
t.fieldMap["id"] = t.ID t.fieldMap["id"] = t.ID
t.fieldMap["task_id"] = t.TaskID t.fieldMap["task_id"] = t.TaskID
t.fieldMap["metric"] = t.Metric t.fieldMap["metric"] = t.Metric
@ -111,6 +114,7 @@ func (t *taskCenterTaskTiers) fillFieldMap() {
t.fieldMap["priority"] = t.Priority t.fieldMap["priority"] = t.Priority
t.fieldMap["created_at"] = t.CreatedAt t.fieldMap["created_at"] = t.CreatedAt
t.fieldMap["updated_at"] = t.UpdatedAt t.fieldMap["updated_at"] = t.UpdatedAt
t.fieldMap["extra_params"] = t.ExtraParams
} }
func (t taskCenterTaskTiers) clone(db *gorm.DB) taskCenterTaskTiers { func (t taskCenterTaskTiers) clone(db *gorm.DB) taskCenterTaskTiers {

View File

@ -36,6 +36,8 @@ func newUserInvites(db *gorm.DB, opts ...gen.DOOption) userInvites {
_userInvites.CreatedAt = field.NewTime(tableName, "created_at") _userInvites.CreatedAt = field.NewTime(tableName, "created_at")
_userInvites.UpdatedAt = field.NewTime(tableName, "updated_at") _userInvites.UpdatedAt = field.NewTime(tableName, "updated_at")
_userInvites.DeletedAt = field.NewField(tableName, "deleted_at") _userInvites.DeletedAt = field.NewField(tableName, "deleted_at")
_userInvites.IsEffective = field.NewBool(tableName, "is_effective")
_userInvites.AccumulatedAmount = field.NewInt64(tableName, "accumulated_amount")
_userInvites.fillFieldMap() _userInvites.fillFieldMap()
@ -46,16 +48,18 @@ func newUserInvites(db *gorm.DB, opts ...gen.DOOption) userInvites {
type userInvites struct { type userInvites struct {
userInvitesDo userInvitesDo
ALL field.Asterisk ALL field.Asterisk
ID field.Int64 // 主键ID ID field.Int64 // 主键ID
InviterID field.Int64 // 邀请人用户ID InviterID field.Int64 // 邀请人用户ID
InviteeID field.Int64 // 被邀请用户ID InviteeID field.Int64 // 被邀请用户ID
InviteCode field.String // 邀请时使用的邀请码 InviteCode field.String // 邀请时使用的邀请码
RewardPoints field.Int64 // 发放的积分数量(用于审计) RewardPoints field.Int64 // 发放的积分数量(用于审计)
RewardedAt field.Time // 奖励发放时间 RewardedAt field.Time // 奖励发放时间
CreatedAt field.Time // 创建时间 CreatedAt field.Time // 创建时间
UpdatedAt field.Time // 更新时间 UpdatedAt field.Time // 更新时间
DeletedAt field.Field // 删除时间(软删) DeletedAt field.Field // 删除时间(软删)
IsEffective field.Bool // 是否为有效邀请
AccumulatedAmount field.Int64 // 被邀请人累计消费金额(分)
fieldMap map[string]field.Expr fieldMap map[string]field.Expr
} }
@ -81,6 +85,8 @@ func (u *userInvites) updateTableName(table string) *userInvites {
u.CreatedAt = field.NewTime(table, "created_at") u.CreatedAt = field.NewTime(table, "created_at")
u.UpdatedAt = field.NewTime(table, "updated_at") u.UpdatedAt = field.NewTime(table, "updated_at")
u.DeletedAt = field.NewField(table, "deleted_at") u.DeletedAt = field.NewField(table, "deleted_at")
u.IsEffective = field.NewBool(table, "is_effective")
u.AccumulatedAmount = field.NewInt64(table, "accumulated_amount")
u.fillFieldMap() u.fillFieldMap()
@ -97,7 +103,7 @@ func (u *userInvites) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
} }
func (u *userInvites) fillFieldMap() { func (u *userInvites) fillFieldMap() {
u.fieldMap = make(map[string]field.Expr, 9) u.fieldMap = make(map[string]field.Expr, 11)
u.fieldMap["id"] = u.ID u.fieldMap["id"] = u.ID
u.fieldMap["inviter_id"] = u.InviterID u.fieldMap["inviter_id"] = u.InviterID
u.fieldMap["invitee_id"] = u.InviteeID u.fieldMap["invitee_id"] = u.InviteeID
@ -107,6 +113,8 @@ func (u *userInvites) fillFieldMap() {
u.fieldMap["created_at"] = u.CreatedAt u.fieldMap["created_at"] = u.CreatedAt
u.fieldMap["updated_at"] = u.UpdatedAt u.fieldMap["updated_at"] = u.UpdatedAt
u.fieldMap["deleted_at"] = u.DeletedAt u.fieldMap["deleted_at"] = u.DeletedAt
u.fieldMap["is_effective"] = u.IsEffective
u.fieldMap["accumulated_amount"] = u.AccumulatedAmount
} }
func (u userInvites) clone(db *gorm.DB) userInvites { func (u userInvites) clone(db *gorm.DB) userInvites {

View File

@ -39,13 +39,13 @@ type Activities struct {
CommitmentAlgo string `gorm:"column:commitment_algo;default:commit-v1" json:"commitment_algo"` CommitmentAlgo string `gorm:"column:commitment_algo;default:commit-v1" json:"commitment_algo"`
CommitmentSeedMaster []byte `gorm:"column:commitment_seed_master" json:"commitment_seed_master"` CommitmentSeedMaster []byte `gorm:"column:commitment_seed_master" json:"commitment_seed_master"`
CommitmentSeedHash []byte `gorm:"column:commitment_seed_hash" json:"commitment_seed_hash"` CommitmentSeedHash []byte `gorm:"column:commitment_seed_hash" json:"commitment_seed_hash"`
DailySeed string `gorm:"column:daily_seed" json:"daily_seed"`
DailySeedDate string `gorm:"column:daily_seed_date" json:"daily_seed_date"`
LastDailySeed string `gorm:"column:last_daily_seed" json:"last_daily_seed"`
LastDailySeedDate string `gorm:"column:last_daily_seed_date" json:"last_daily_seed_date"`
CommitmentStateVersion int32 `gorm:"column:commitment_state_version" json:"commitment_state_version"` CommitmentStateVersion int32 `gorm:"column:commitment_state_version" json:"commitment_state_version"`
CommitmentItemsRoot []byte `gorm:"column:commitment_items_root" json:"commitment_items_root"` CommitmentItemsRoot []byte `gorm:"column:commitment_items_root" json:"commitment_items_root"`
GameplayIntro string `gorm:"column:gameplay_intro;comment:玩法介绍" json:"gameplay_intro"` // 玩法介绍 GameplayIntro string `gorm:"column:gameplay_intro;comment:玩法介绍" json:"gameplay_intro"` // 玩法介绍
DailySeed string `gorm:"column:daily_seed" json:"daily_seed"`
DailySeedDate string `gorm:"column:daily_seed_date;comment:种子日期(YYYY-MM-DD)" json:"daily_seed_date"` // 种子日期(YYYY-MM-DD)
LastDailySeed string `gorm:"column:last_daily_seed;comment:昨日种子" json:"last_daily_seed"` // 昨日种子
LastDailySeedDate string `gorm:"column:last_daily_seed_date;comment:昨日种子日期" json:"last_daily_seed_date"` // 昨日种子日期
} }
// TableName Activities's table name // TableName Activities's table name

View File

@ -26,8 +26,8 @@ type ActivityRewardSettings struct {
Level int32 `gorm:"column:level;not null;comment:奖级如1=S 2=A 3=B" json:"level"` // 奖级如1=S 2=A 3=B Level int32 `gorm:"column:level;not null;comment:奖级如1=S 2=A 3=B" json:"level"` // 奖级如1=S 2=A 3=B
Sort int32 `gorm:"column:sort;comment:排序" json:"sort"` // 排序 Sort int32 `gorm:"column:sort;comment:排序" json:"sort"` // 排序
IsBoss int32 `gorm:"column:is_boss;comment:Boss 1 是 0 不是" json:"is_boss"` // Boss 1 是 0 不是 IsBoss int32 `gorm:"column:is_boss;comment:Boss 1 是 0 不是" json:"is_boss"` // Boss 1 是 0 不是
MinScore int64 `gorm:"column:min_score;not null;default:0;comment:最低得分/碰数要求" json:"min_score"` // 最低得分/碰数要求
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at" json:"deleted_at"` DeletedAt gorm.DeletedAt `gorm:"column:deleted_at" json:"deleted_at"`
MinScore int64 `gorm:"column:min_score;not null;comment:最低得分/碰数要求" json:"min_score"` // 最低得分/碰数要求
} }
// TableName ActivityRewardSettings's table name // TableName ActivityRewardSettings's table name

View File

@ -12,26 +12,26 @@ const TableNameOrders = "orders"
// Orders 订单 // Orders 订单
type Orders struct { type Orders struct {
ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP(3);comment:创建时间" json:"created_at"` // 创建时间 CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP(3);comment:创建时间" json:"created_at"` // 创建时间
UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP(3);comment:更新时间" json:"updated_at"` // 更新时间 UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP(3);comment:更新时间" json:"updated_at"` // 更新时间
UserID int64 `gorm:"column:user_id;not null;comment:下单用户IDuser_members.id" json:"user_id"` // 下单用户IDuser_members.id UserID int64 `gorm:"column:user_id;not null;comment:下单用户IDuser_members.id" json:"user_id"` // 下单用户IDuser_members.id
OrderNo string `gorm:"column:order_no;not null;comment:业务订单号(唯一)" json:"order_no"` // 业务订单号(唯一) OrderNo string `gorm:"column:order_no;not null;comment:业务订单号(唯一)" json:"order_no"` // 业务订单号(唯一)
SourceType int32 `gorm:"column:source_type;not null;default:1;comment:来源1商城直购 2抽奖票据 3其他" json:"source_type"` // 来源1商城直购 2抽奖票据 3其他 SourceType int32 `gorm:"column:source_type;not null;default:1;comment:来源1商城直购 2抽奖票据 3其他" json:"source_type"` // 来源1商城直购 2抽奖票据 3其他
TotalAmount int64 `gorm:"column:total_amount;not null;comment:订单总金额(分)" json:"total_amount"` // 订单总金额(分) TotalAmount int64 `gorm:"column:total_amount;not null;comment:订单总金额(分)" json:"total_amount"` // 订单总金额(分)
DiscountAmount int64 `gorm:"column:discount_amount;not null;comment:优惠券抵扣金额(分)" json:"discount_amount"` // 优惠券抵扣金额(分) DiscountAmount int64 `gorm:"column:discount_amount;not null;comment:优惠券抵扣金额(分)" json:"discount_amount"` // 优惠券抵扣金额(分)
PointsAmount int64 `gorm:"column:points_amount;not null;comment:积分抵扣金额(分)" json:"points_amount"` // 积分抵扣金额(分) PointsAmount int64 `gorm:"column:points_amount;not null;comment:积分抵扣金额(分)" json:"points_amount"` // 积分抵扣金额(分)
ActualAmount int64 `gorm:"column:actual_amount;not null;comment:实际支付金额(分)" json:"actual_amount"` // 实际支付金额(分) ActualAmount int64 `gorm:"column:actual_amount;not null;comment:实际支付金额(分)" json:"actual_amount"` // 实际支付金额(分)
Status int32 `gorm:"column:status;not null;default:1;comment:订单状态1待支付 2已支付 3已取消 4已退款" json:"status"` // 订单状态1待支付 2已支付 3已取消 4已退款 Status int32 `gorm:"column:status;not null;default:1;comment:订单状态1待支付 2已支付 3已取消 4已退款" json:"status"` // 订单状态1待支付 2已支付 3已取消 4已退款
PayPreorderID int64 `gorm:"column:pay_preorder_id;comment:关联预支付单IDpayment_preorder.id" json:"pay_preorder_id"` // 关联预支付单IDpayment_preorder.id PayPreorderID int64 `gorm:"column:pay_preorder_id;comment:关联预支付单IDpayment_preorder.id" json:"pay_preorder_id"` // 关联预支付单IDpayment_preorder.id
PaidAt *time.Time `gorm:"column:paid_at;comment:支付完成时间" json:"paid_at"` // 支付完成时间 PaidAt time.Time `gorm:"column:paid_at;comment:支付完成时间" json:"paid_at"` // 支付完成时间
CancelledAt *time.Time `gorm:"column:cancelled_at;comment:取消时间" json:"cancelled_at"` // 取消时间 CancelledAt time.Time `gorm:"column:cancelled_at;comment:取消时间" json:"cancelled_at"` // 取消时间
UserAddressID int64 `gorm:"column:user_address_id;comment:收货地址IDuser_addresses.id" json:"user_address_id"` // 收货地址IDuser_addresses.id UserAddressID int64 `gorm:"column:user_address_id;comment:收货地址IDuser_addresses.id" json:"user_address_id"` // 收货地址IDuser_addresses.id
IsConsumed int32 `gorm:"column:is_consumed;not null;comment:是否已履约/消耗(对虚拟资产)" json:"is_consumed"` // 是否已履约/消耗(对虚拟资产) IsConsumed int32 `gorm:"column:is_consumed;not null;comment:是否已履约/消耗(对虚拟资产)" json:"is_consumed"` // 是否已履约/消耗(对虚拟资产)
PointsLedgerID int64 `gorm:"column:points_ledger_id;comment:积分扣减流水IDuser_points_ledger.id" json:"points_ledger_id"` // 积分扣减流水IDuser_points_ledger.id PointsLedgerID int64 `gorm:"column:points_ledger_id;comment:积分扣减流水IDuser_points_ledger.id" json:"points_ledger_id"` // 积分扣减流水IDuser_points_ledger.id
CouponID int64 `gorm:"column:coupon_id;comment:使用的优惠券ID" json:"coupon_id"` // 使用的优惠券ID CouponID int64 `gorm:"column:coupon_id;comment:使用的优惠券ID" json:"coupon_id"` // 使用的优惠券ID
ItemCardID int64 `gorm:"column:item_card_id;comment:使用的道具卡ID" json:"item_card_id"` // 使用的道具卡ID ItemCardID int64 `gorm:"column:item_card_id;comment:使用的道具卡ID" json:"item_card_id"` // 使用的道具卡ID
Remark string `gorm:"column:remark;comment:备注" json:"remark"` // 备注 Remark string `gorm:"column:remark;comment:备注" json:"remark"` // 备注
} }
// TableName Orders's table name // TableName Orders's table name

View File

@ -14,17 +14,18 @@ const TableNameProducts = "products"
// Products 商品 // Products 商品
type Products struct { type Products struct {
ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP(3);comment:创建时间" json:"created_at"` // 创建时间 CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP(3);comment:创建时间" json:"created_at"` // 创建时间
UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP(3);comment:更新时间" json:"updated_at"` // 更新时间 UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP(3);comment:更新时间" json:"updated_at"` // 更新时间
Name string `gorm:"column:name;not null;comment:商品名称" json:"name"` // 商品名称 Name string `gorm:"column:name;not null;comment:商品名称" json:"name"` // 商品名称
CategoryID int64 `gorm:"column:category_id;comment:单一主分类IDproduct_categories.id" json:"category_id"` // 单一主分类IDproduct_categories.id CategoryID int64 `gorm:"column:category_id;comment:单一主分类IDproduct_categories.id" json:"category_id"` // 单一主分类IDproduct_categories.id
ImagesJSON string `gorm:"column:images_json;comment:商品图片JSON数组" json:"images_json"` // 商品图片JSON数组 ImagesJSON string `gorm:"column:images_json;comment:商品图片JSON数组" json:"images_json"` // 商品图片JSON数组
Price int64 `gorm:"column:price;not null;comment:商品售价(分)" json:"price"` // 商品售价(分) Price int64 `gorm:"column:price;not null;comment:商品售价(分)" json:"price"` // 商品售价(分)
Stock int64 `gorm:"column:stock;not null;comment:可售库存" json:"stock"` // 可售库存 Stock int64 `gorm:"column:stock;not null;comment:可售库存" json:"stock"` // 可售库存
Sales int64 `gorm:"column:sales;not null;comment:已售数量" json:"sales"` // 已售数量 Sales int64 `gorm:"column:sales;not null;comment:已售数量" json:"sales"` // 已售数量
Status int32 `gorm:"column:status;not null;default:1;comment:上下架状态1上架 2下架" json:"status"` // 上下架状态1上架 2下架 Status int32 `gorm:"column:status;not null;default:1;comment:上下架状态1上架 2下架" json:"status"` // 上下架状态1上架 2下架
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at" json:"deleted_at"` DeletedAt gorm.DeletedAt `gorm:"column:deleted_at" json:"deleted_at"`
Description string `gorm:"column:description;comment:商品详情" json:"description"` // 商品详情
} }
// TableName Products's table name // TableName Products's table name

View File

@ -12,16 +12,17 @@ const TableNameTaskCenterTaskTiers = "task_center_task_tiers"
// TaskCenterTaskTiers 任务中心-档位配置 // TaskCenterTaskTiers 任务中心-档位配置
type TaskCenterTaskTiers struct { type TaskCenterTaskTiers struct {
ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID
TaskID int64 `gorm:"column:task_id;not null;comment:关联任务IDtask_center_tasks.id" json:"task_id"` // 关联任务IDtask_center_tasks.id TaskID int64 `gorm:"column:task_id;not null;comment:关联任务IDtask_center_tasks.id" json:"task_id"` // 关联任务IDtask_center_tasks.id
Metric string `gorm:"column:metric;not null;comment:指标first_order|order_count|invite_count" json:"metric"` // 指标first_order|order_count|invite_count Metric string `gorm:"column:metric;not null;comment:指标first_order|order_count|invite_count" json:"metric"` // 指标first_order|order_count|invite_count
Operator string `gorm:"column:operator;not null;comment:比较符:>= 或 ==" json:"operator"` // 比较符:>= 或 == Operator string `gorm:"column:operator;not null;comment:比较符:>= 或 ==" json:"operator"` // 比较符:>= 或 ==
Threshold int64 `gorm:"column:threshold;not null;comment:阈值(数量或布尔首单)" json:"threshold"` // 阈值(数量或布尔首单) Threshold int64 `gorm:"column:threshold;not null;comment:阈值(数量或布尔首单)" json:"threshold"` // 阈值(数量或布尔首单)
Window string `gorm:"column:window;not null;comment:时间窗口activity_period|since_registration" json:"window"` // 时间窗口activity_period|since_registration Window string `gorm:"column:window;not null;comment:时间窗口activity_period|since_registration" json:"window"` // 时间窗口activity_period|since_registration
Repeatable int32 `gorm:"column:repeatable;not null;default:1;comment:是否每档一次0否 1是" json:"repeatable"` // 是否每档一次0否 1是 Repeatable int32 `gorm:"column:repeatable;not null;default:1;comment:是否每档一次0否 1是" json:"repeatable"` // 是否每档一次0否 1是
Priority int32 `gorm:"column:priority;not null;comment:匹配优先级(数值越小越先匹配)" json:"priority"` // 匹配优先级(数值越小越先匹配) Priority int32 `gorm:"column:priority;not null;comment:匹配优先级(数值越小越先匹配)" json:"priority"` // 匹配优先级(数值越小越先匹配)
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间
ExtraParams string `gorm:"column:extra_params;comment:额外参数配置(如消费门槛)" json:"extra_params"` // 额外参数配置(如消费门槛)
} }
// TableName TaskCenterTaskTiers's table name // TableName TaskCenterTaskTiers's table name

View File

@ -14,17 +14,17 @@ const TableNameUserInvites = "user_invites"
// UserInvites 用户邀请关系表 // UserInvites 用户邀请关系表
type UserInvites struct { type UserInvites struct {
ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID
InviterID int64 `gorm:"column:inviter_id;not null;comment:邀请人用户ID" json:"inviter_id"` // 邀请人用户ID InviterID int64 `gorm:"column:inviter_id;not null;comment:邀请人用户ID" json:"inviter_id"` // 邀请人用户ID
InviteeID int64 `gorm:"column:invitee_id;not null;comment:被邀请用户ID" json:"invitee_id"` // 被邀请用户ID InviteeID int64 `gorm:"column:invitee_id;not null;comment:被邀请用户ID" json:"invitee_id"` // 被邀请用户ID
InviteCode string `gorm:"column:invite_code;not null;comment:邀请时使用的邀请码" json:"invite_code"` // 邀请时使用的邀请码 InviteCode string `gorm:"column:invite_code;not null;comment:邀请时使用的邀请码" json:"invite_code"` // 邀请时使用的邀请码
RewardPoints int64 `gorm:"column:reward_points;not null;comment:发放的积分数量(用于审计)" json:"reward_points"` // 发放的积分数量(用于审计) RewardPoints int64 `gorm:"column:reward_points;not null;comment:发放的积分数量(用于审计)" json:"reward_points"` // 发放的积分数量(用于审计)
IsEffective int32 `gorm:"column:is_effective;not null;default:0;comment:是否为有效邀请" json:"is_effective"` // 是否为有效邀请
AccumulatedAmount int64 `gorm:"column:accumulated_amount;not null;default:0;comment:被邀请人累计消费金额(分)" json:"accumulated_amount"` // 被邀请人累计消费金额(分)
RewardedAt time.Time `gorm:"column:rewarded_at;comment:奖励发放时间" json:"rewarded_at"` // 奖励发放时间 RewardedAt time.Time `gorm:"column:rewarded_at;comment:奖励发放时间" json:"rewarded_at"` // 奖励发放时间
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP(3);comment:创建时间" json:"created_at"` // 创建时间 CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP(3);comment:创建时间" json:"created_at"` // 创建时间
UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP(3);comment:更新时间" json:"updated_at"` // 更新时间 UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP(3);comment:更新时间" json:"updated_at"` // 更新时间
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;comment:删除时间(软删)" json:"deleted_at"` // 删除时间(软删) DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;comment:删除时间(软删)" json:"deleted_at"` // 删除时间(软删)
IsEffective bool `gorm:"column:is_effective;not null;comment:是否为有效邀请" json:"is_effective"` // 是否为有效邀请
AccumulatedAmount int64 `gorm:"column:accumulated_amount;not null;comment:被邀请人累计消费金额(分)" json:"accumulated_amount"` // 被邀请人累计消费金额(分)
} }
// TableName UserInvites's table name // TableName UserInvites's table name

View File

@ -1,16 +1,16 @@
package product package product
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"strings" "errors"
"time" "strings"
"errors" "time"
"bindbox-game/internal/pkg/logger" "bindbox-game/internal/pkg/logger"
"bindbox-game/internal/repository/mysql" "bindbox-game/internal/repository/mysql"
"bindbox-game/internal/repository/mysql/dao" "bindbox-game/internal/repository/mysql/dao"
"bindbox-game/internal/repository/mysql/model" "bindbox-game/internal/repository/mysql/model"
) )
type Service interface { type Service interface {
@ -22,22 +22,22 @@ type Service interface {
CreateProduct(ctx context.Context, in CreateProductInput) (*model.Products, error) CreateProduct(ctx context.Context, in CreateProductInput) (*model.Products, error)
ModifyProduct(ctx context.Context, id int64, in ModifyProductInput) error ModifyProduct(ctx context.Context, id int64, in ModifyProductInput) error
DeleteProduct(ctx context.Context, id int64) error DeleteProduct(ctx context.Context, id int64) error
ListProducts(ctx context.Context, in ListProductsInput) (items []*model.Products, total int64, err error) ListProducts(ctx context.Context, in ListProductsInput) (items []*model.Products, total int64, err error)
BatchUpdate(ctx context.Context, ids []int64, stock *int64, status *int32) (int64, error) BatchUpdate(ctx context.Context, ids []int64, stock *int64, status *int32) (int64, error)
ListForApp(ctx context.Context, in AppListInput) (items []AppListItem, total int64, err error) ListForApp(ctx context.Context, in AppListInput) (items []AppListItem, total int64, err error)
GetDetailForApp(ctx context.Context, id int64) (*AppDetail, error) GetDetailForApp(ctx context.Context, id int64) (*AppDetail, error)
} }
type service struct { type service struct {
logger logger.CustomLogger logger logger.CustomLogger
readDB *dao.Query readDB *dao.Query
writeDB *dao.Query writeDB *dao.Query
listCache map[string]cachedList listCache map[string]cachedList
detailCache map[int64]cachedDetail detailCache map[int64]cachedDetail
} }
func New(l logger.CustomLogger, db mysql.Repo) Service { func New(l logger.CustomLogger, db mysql.Repo) Service {
return &service{logger: l, readDB: dao.Use(db.GetDbR()), writeDB: dao.Use(db.GetDbW()), listCache: make(map[string]cachedList), detailCache: make(map[int64]cachedDetail)} return &service{logger: l, readDB: dao.Use(db.GetDbR()), writeDB: dao.Use(db.GetDbW()), listCache: make(map[string]cachedList), detailCache: make(map[int64]cachedDetail)}
} }
type CreateCategoryInput struct { type CreateCategoryInput struct {
@ -87,8 +87,8 @@ func (s *service) ModifyCategory(ctx context.Context, id int64, in ModifyCategor
} }
func (s *service) DeleteCategory(ctx context.Context, id int64) error { func (s *service) DeleteCategory(ctx context.Context, id int64) error {
_, err := s.writeDB.ProductCategories.WithContext(ctx).Where(s.writeDB.ProductCategories.ID.Eq(id)).Updates(map[string]any{"deleted_at": time.Now()}) _, err := s.writeDB.ProductCategories.WithContext(ctx).Where(s.writeDB.ProductCategories.ID.Eq(id)).Updates(map[string]any{"deleted_at": time.Now()})
return err return err
} }
func (s *service) ListCategories(ctx context.Context, in ListCategoriesInput) (items []*model.ProductCategories, total int64, err error) { func (s *service) ListCategories(ctx context.Context, in ListCategoriesInput) (items []*model.ProductCategories, total int64, err error) {
@ -114,21 +114,23 @@ func (s *service) ListCategories(ctx context.Context, in ListCategoriesInput) (i
} }
type CreateProductInput struct { type CreateProductInput struct {
Name string Name string
CategoryID int64 CategoryID int64
ImagesJSON string ImagesJSON string
Price int64 Price int64
Stock int64 Stock int64
Status int32 Status int32
Description string
} }
type ModifyProductInput struct { type ModifyProductInput struct {
Name *string Name *string
CategoryID *int64 CategoryID *int64
ImagesJSON *string ImagesJSON *string
Price *int64 Price *int64
Stock *int64 Stock *int64
Status *int32 Status *int32
Description *string
} }
type ListProductsInput struct { type ListProductsInput struct {
@ -140,40 +142,40 @@ type ListProductsInput struct {
} }
type AppListInput struct { type AppListInput struct {
CategoryID *int64 CategoryID *int64
PriceMin *int64 PriceMin *int64
PriceMax *int64 PriceMax *int64
SalesMin *int64 SalesMin *int64
InStock *bool InStock *bool
SortBy string SortBy string
Order string Order string
Page int Page int
PageSize int PageSize int
} }
type AppListItem struct { type AppListItem struct {
ID int64 ID int64
Name string Name string
MainImage string MainImage string
Price int64 Price int64
Sales int64 Sales int64
InStock bool InStock bool
} }
type AppDetail struct { type AppDetail struct {
ID int64 ID int64
Name string Name string
Album []string Album []string
Price int64 Price int64
Sales int64 Sales int64
Stock int64 Stock int64
Description string Description string
Service []string Service []string
Recommendations []AppListItem Recommendations []AppListItem
} }
func (s *service) CreateProduct(ctx context.Context, in CreateProductInput) (*model.Products, error) { func (s *service) CreateProduct(ctx context.Context, in CreateProductInput) (*model.Products, error) {
m := &model.Products{Name: in.Name, CategoryID: in.CategoryID, ImagesJSON: normalizeJSON(in.ImagesJSON), Price: in.Price, Stock: in.Stock, Status: in.Status} m := &model.Products{Name: in.Name, CategoryID: in.CategoryID, ImagesJSON: normalizeJSON(in.ImagesJSON), Price: in.Price, Stock: in.Stock, Status: in.Status, Description: in.Description}
if err := s.writeDB.Products.WithContext(ctx).Create(m); err != nil { if err := s.writeDB.Products.WithContext(ctx).Create(m); err != nil {
return nil, err return nil, err
} }
@ -201,6 +203,9 @@ func (s *service) ModifyProduct(ctx context.Context, id int64, in ModifyProductI
if in.Status != nil { if in.Status != nil {
set["status"] = *in.Status set["status"] = *in.Status
} }
if in.Description != nil {
set["description"] = *in.Description
}
if len(set) == 0 { if len(set) == 0 {
return nil return nil
} }
@ -209,8 +214,8 @@ func (s *service) ModifyProduct(ctx context.Context, id int64, in ModifyProductI
} }
func (s *service) DeleteProduct(ctx context.Context, id int64) error { func (s *service) DeleteProduct(ctx context.Context, id int64) error {
_, err := s.writeDB.Products.WithContext(ctx).Where(s.writeDB.Products.ID.Eq(id)).Updates(map[string]any{"deleted_at": time.Now()}) _, err := s.writeDB.Products.WithContext(ctx).Where(s.writeDB.Products.ID.Eq(id)).Updates(map[string]any{"deleted_at": time.Now()})
return err return err
} }
func (s *service) ListProducts(ctx context.Context, in ListProductsInput) (items []*model.Products, total int64, err error) { func (s *service) ListProducts(ctx context.Context, in ListProductsInput) (items []*model.Products, total int64, err error) {
@ -239,120 +244,120 @@ func (s *service) ListProducts(ctx context.Context, in ListProductsInput) (items
} }
func (s *service) ListForApp(ctx context.Context, in AppListInput) (items []AppListItem, total int64, err error) { func (s *service) ListForApp(ctx context.Context, in AppListInput) (items []AppListItem, total int64, err error) {
key := s.listKey(in) key := s.listKey(in)
if v, ok := s.listCache[key]; ok && time.Now().Before(v.expireAt) { if v, ok := s.listCache[key]; ok && time.Now().Before(v.expireAt) {
return v.items, v.total, nil return v.items, v.total, nil
} }
if in.Page <= 0 { if in.Page <= 0 {
in.Page = 1 in.Page = 1
} }
if in.PageSize <= 0 { if in.PageSize <= 0 {
in.PageSize = 20 in.PageSize = 20
} }
q := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.Status.Eq(1)) q := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.Status.Eq(1))
if in.CategoryID != nil { if in.CategoryID != nil {
q = q.Where(s.readDB.Products.CategoryID.Eq(*in.CategoryID)) q = q.Where(s.readDB.Products.CategoryID.Eq(*in.CategoryID))
} }
if in.PriceMin != nil { if in.PriceMin != nil {
q = q.Where(s.readDB.Products.Price.Gte(*in.PriceMin)) q = q.Where(s.readDB.Products.Price.Gte(*in.PriceMin))
} }
if in.PriceMax != nil { if in.PriceMax != nil {
q = q.Where(s.readDB.Products.Price.Lte(*in.PriceMax)) q = q.Where(s.readDB.Products.Price.Lte(*in.PriceMax))
} }
if in.SalesMin != nil { if in.SalesMin != nil {
q = q.Where(s.readDB.Products.Sales.Gte(*in.SalesMin)) q = q.Where(s.readDB.Products.Sales.Gte(*in.SalesMin))
} }
if in.InStock != nil && *in.InStock { if in.InStock != nil && *in.InStock {
q = q.Where(s.readDB.Products.Stock.Gt(0)) q = q.Where(s.readDB.Products.Stock.Gt(0))
} }
total, err = q.Count() total, err = q.Count()
if err != nil { if err != nil {
return return
} }
orderDesc := true orderDesc := true
if strings.ToLower(in.Order) == "asc" { if strings.ToLower(in.Order) == "asc" {
orderDesc = false orderDesc = false
} }
switch strings.ToLower(in.SortBy) { switch strings.ToLower(in.SortBy) {
case "price": case "price":
if orderDesc { if orderDesc {
q = q.Order(s.readDB.Products.Price.Desc()) q = q.Order(s.readDB.Products.Price.Desc())
} else { } else {
q = q.Order(s.readDB.Products.Price.Asc()) q = q.Order(s.readDB.Products.Price.Asc())
} }
case "createdat", "created_at": case "createdat", "created_at":
if orderDesc { if orderDesc {
q = q.Order(s.readDB.Products.CreatedAt.Desc()) q = q.Order(s.readDB.Products.CreatedAt.Desc())
} else { } else {
q = q.Order(s.readDB.Products.CreatedAt.Asc()) q = q.Order(s.readDB.Products.CreatedAt.Asc())
} }
default: default:
if orderDesc { if orderDesc {
q = q.Order(s.readDB.Products.Sales.Desc()) q = q.Order(s.readDB.Products.Sales.Desc())
} else { } else {
q = q.Order(s.readDB.Products.Sales.Asc()) q = q.Order(s.readDB.Products.Sales.Asc())
} }
} }
rows, err := q.Limit(in.PageSize).Offset((in.Page-1)*in.PageSize).Find() rows, err := q.Limit(in.PageSize).Offset((in.Page - 1) * in.PageSize).Find()
if err != nil { if err != nil {
return return
} }
items = make([]AppListItem, len(rows)) items = make([]AppListItem, len(rows))
for i, it := range rows { for i, it := range rows {
items[i] = AppListItem{ID: it.ID, Name: it.Name, MainImage: firstImage(it.ImagesJSON), Price: it.Price, Sales: it.Sales, InStock: it.Stock > 0} items[i] = AppListItem{ID: it.ID, Name: it.Name, MainImage: firstImage(it.ImagesJSON), Price: it.Price, Sales: it.Sales, InStock: it.Stock > 0}
} }
s.listCache[key] = cachedList{items: items, total: total, expireAt: time.Now().Add(30 * time.Second)} s.listCache[key] = cachedList{items: items, total: total, expireAt: time.Now().Add(30 * time.Second)}
return return
} }
func (s *service) GetDetailForApp(ctx context.Context, id int64) (*AppDetail, error) { func (s *service) GetDetailForApp(ctx context.Context, id int64) (*AppDetail, error) {
if v, ok := s.detailCache[id]; ok && time.Now().Before(v.expireAt) { if v, ok := s.detailCache[id]; ok && time.Now().Before(v.expireAt) {
return v.detail, nil return v.detail, nil
} }
p, err := s.readDB.Products.WithContext(ctx).Where(s.readDB.Products.ID.Eq(id)).Take() p, err := s.readDB.Products.WithContext(ctx).Where(s.readDB.Products.ID.Eq(id)).Take()
if err != nil { if err != nil {
return nil, err return nil, err
} }
if p.Status != 1 { if p.Status != 1 {
return nil, errors.New("PRODUCT_OFFSHELF") return nil, errors.New("PRODUCT_OFFSHELF")
} }
if p.Stock <= 0 { if p.Stock <= 0 {
return nil, errors.New("PRODUCT_OUT_OF_STOCK") return nil, errors.New("PRODUCT_OUT_OF_STOCK")
} }
album := splitImages(p.ImagesJSON) album := splitImages(p.ImagesJSON)
d := &AppDetail{ID: p.ID, Name: p.Name, Album: album, Price: p.Price, Sales: p.Sales, Stock: p.Stock, Description: "", Service: []string{}, Recommendations: []AppListItem{}} d := &AppDetail{ID: p.ID, Name: p.Name, Album: album, Price: p.Price, Sales: p.Sales, Stock: p.Stock, Description: p.Description, Service: []string{}, Recommendations: []AppListItem{}}
recQ := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.Status.Eq(1)).Where(s.readDB.Products.ID.Neq(p.ID)) recQ := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.Status.Eq(1)).Where(s.readDB.Products.ID.Neq(p.ID))
if p.CategoryID > 0 { if p.CategoryID > 0 {
recQ = recQ.Where(s.readDB.Products.CategoryID.Eq(p.CategoryID)) recQ = recQ.Where(s.readDB.Products.CategoryID.Eq(p.CategoryID))
} }
recs, _ := recQ.Order(s.readDB.Products.Sales.Desc()).Limit(6).Find() recs, _ := recQ.Order(s.readDB.Products.Sales.Desc()).Limit(6).Find()
for _, it := range recs { for _, it := range recs {
d.Recommendations = append(d.Recommendations, AppListItem{ID: it.ID, Name: it.Name, MainImage: firstImage(it.ImagesJSON), Price: it.Price, Sales: it.Sales, InStock: it.Stock > 0}) d.Recommendations = append(d.Recommendations, AppListItem{ID: it.ID, Name: it.Name, MainImage: firstImage(it.ImagesJSON), Price: it.Price, Sales: it.Sales, InStock: it.Stock > 0})
} }
s.detailCache[id] = cachedDetail{detail: d, expireAt: time.Now().Add(60 * time.Second)} s.detailCache[id] = cachedDetail{detail: d, expireAt: time.Now().Add(60 * time.Second)}
return d, nil return d, nil
} }
func (s *service) BatchUpdate(ctx context.Context, ids []int64, stock *int64, status *int32) (int64, error) { func (s *service) BatchUpdate(ctx context.Context, ids []int64, stock *int64, status *int32) (int64, error) {
if len(ids) == 0 { if len(ids) == 0 {
return 0, nil return 0, nil
} }
set := map[string]any{} set := map[string]any{}
if stock != nil { if stock != nil {
set["stock"] = *stock set["stock"] = *stock
} }
if status != nil { if status != nil {
set["status"] = *status set["status"] = *status
} }
if len(set) == 0 { if len(set) == 0 {
return 0, nil return 0, nil
} }
updater := s.writeDB.Products.WithContext(ctx).Where(s.writeDB.Products.ID.In(ids...)) updater := s.writeDB.Products.WithContext(ctx).Where(s.writeDB.Products.ID.In(ids...))
result, err := updater.Updates(set) result, err := updater.Updates(set)
if err != nil { if err != nil {
return 0, err return 0, err
} }
return result.RowsAffected, nil return result.RowsAffected, nil
} }
func normalizeJSON(s string) string { func normalizeJSON(s string) string {
@ -367,36 +372,37 @@ func normalizeJSON(s string) string {
} }
func (s *service) listKey(in AppListInput) string { func (s *service) listKey(in AppListInput) string {
b, _ := json.Marshal(in) b, _ := json.Marshal(in)
return string(b) return string(b)
} }
func splitImages(s string) []string { func splitImages(s string) []string {
var arr []string var arr []string
if strings.TrimSpace(s) == "" { if strings.TrimSpace(s) == "" {
return arr return arr
} }
var v []string var v []string
if json.Unmarshal([]byte(s), &v) != nil { if json.Unmarshal([]byte(s), &v) != nil {
return arr return arr
} }
return v return v
} }
func firstImage(s string) string { func firstImage(s string) string {
imgs := splitImages(s) imgs := splitImages(s)
if len(imgs) > 0 { if len(imgs) > 0 {
return imgs[0] return imgs[0]
} }
return "" return ""
} }
type cachedList struct { type cachedList struct {
items []AppListItem items []AppListItem
total int64 total int64
expireAt time.Time expireAt time.Time
} }
type cachedDetail struct { type cachedDetail struct {
detail *AppDetail detail *AppDetail
expireAt time.Time expireAt time.Time
} }

View File

@ -91,8 +91,8 @@ func (s *service) GrantReward(ctx context.Context, userID int64, req GrantReward
PointsAmount: 0, PointsAmount: 0,
ActualAmount: 0, ActualAmount: 0,
IsConsumed: 0, IsConsumed: 0,
PaidAt: &now, // 设置支付时间为当前时间 PaidAt: now, // 设置支付时间为当前时间
CancelledAt: &minValidTime, // 设置取消时间为最小有效时间避免MySQL错误 CancelledAt: minValidTime, // 设置取消时间为最小有效时间避免MySQL错误
Remark: req.Remark, Remark: req.Remark,
CreatedAt: now, CreatedAt: now,
UpdatedAt: now, UpdatedAt: now,

View File

@ -324,3 +324,10 @@
{"level":"info","time":"2025-12-23 20:10:39","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3} {"level":"info","time":"2025-12-23 20:10:39","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
{"level":"info","time":"2025-12-23 20:10:39","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0} {"level":"info","time":"2025-12-23 20:10:39","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}
{"level":"info","time":"2025-12-23 20:10:39","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4} {"level":"info","time":"2025-12-23 20:10:39","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
{"level":"info","time":"2025-12-23 23:32:14","caller":"logger/logger.go:309","msg":"Connected to Redis","domain":"mini-chat[fat]","addr":"118.25.13.43:8379"}
{"level":"info","time":"2025-12-23 23:32:14","caller":"logger/logger.go:309","msg":"Task center worker started","domain":"mini-chat[fat]"}
{"level":"info","time":"2025-12-23 23:32:14","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":4}
{"level":"info","time":"2025-12-23 23:32:14","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":1}
{"level":"info","time":"2025-12-23 23:32:14","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":2}
{"level":"info","time":"2025-12-23 23:32:14","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":3}
{"level":"info","time":"2025-12-23 23:32:14","caller":"logger/logger.go:309","msg":"Worker routine started","domain":"mini-chat[fat]","worker_id":0}