From 425e64daa54536a53e6b5740e4d7a3c7bbe461b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=96=B9=E6=88=90?= Date: Tue, 23 Dec 2025 23:37:59 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E6=97=B6=E9=97=B4=E5=AD=97=E6=AE=B5=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=8F=8A=E6=95=B0=E6=8D=AE=E5=BA=93=E6=A8=A1=E5=9E=8B=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将订单的PaidAt和CancelledAt从指针类型改为值类型 - 统一时间字段的判空逻辑,使用IsZero()替代nil检查 - 调整多个数据库模型结构,添加新字段并优化字段顺序 - 为活动奖励设置、用户邀请等表添加新字段 - 更新对应的DAO层代码以匹配模型变更 --- internal/api/admin/pay_orders_admin.go | 4 +- internal/api/admin/pay_orders_export.go | 2 +- internal/api/admin/product_create.go | 49 +-- internal/api/user/orders_app.go | 2 +- .../repository/mysql/dao/activities.gen.go | 18 +- .../mysql/dao/activity_reward_settings.gen.go | 6 +- internal/repository/mysql/dao/orders.gen.go | 10 +- internal/repository/mysql/dao/products.gen.go | 30 +- .../mysql/dao/task_center_task_tiers.gen.go | 28 +- .../repository/mysql/dao/user_invites.gen.go | 30 +- .../repository/mysql/model/activities.gen.go | 8 +- .../model/activity_reward_settings.gen.go | 2 +- internal/repository/mysql/model/orders.gen.go | 40 +- .../repository/mysql/model/products.gen.go | 23 +- .../mysql/model/task_center_task_tiers.gen.go | 21 +- .../mysql/model/user_invites.gen.go | 18 +- internal/service/product/product.go | 384 +++++++++--------- internal/service/user/reward_grant.go | 4 +- logs/mini-chat-access.log | 7 + 19 files changed, 374 insertions(+), 312 deletions(-) diff --git a/internal/api/admin/pay_orders_admin.go b/internal/api/admin/pay_orders_admin.go index 952d754..68fa9f8 100644 --- a/internal/api/admin/pay_orders_admin.go +++ b/internal/api/admin/pay_orders_admin.go @@ -253,7 +253,7 @@ func (h *handler) ListPayOrders() core.HandlerFunc { "actual_amount": o.ActualAmount, "status": o.Status, "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 "" @@ -585,7 +585,7 @@ func (h *handler) GetPayOrderDetail() core.HandlerFunc { Status: order.Status, ActualAmount: order.ActualAmount, 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 "" diff --git a/internal/api/admin/pay_orders_export.go b/internal/api/admin/pay_orders_export.go index 4df86f8..f39186a 100644 --- a/internal/api/admin/pay_orders_export.go +++ b/internal/api/admin/pay_orders_export.go @@ -100,7 +100,7 @@ func (h *handler) ExportPayOrders() core.HandlerFunc { r.AddCell().SetInt64(pu) r.AddCell().SetInt64(couponApplied) 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") } else { r.AddCell().Value = "" diff --git a/internal/api/admin/product_create.go b/internal/api/admin/product_create.go index a889123..9b44207 100644 --- a/internal/api/admin/product_create.go +++ b/internal/api/admin/product_create.go @@ -11,12 +11,13 @@ import ( ) type createProductRequest struct { - Name string `json:"name" binding:"required"` - CategoryID int64 `json:"category_id" binding:"required"` - ImagesJSON string `json:"images_json"` - Price int64 `json:"price" binding:"required"` - Stock int64 `json:"stock" binding:"required"` - Status int32 `json:"status"` + Name string `json:"name" binding:"required"` + CategoryID int64 `json:"category_id" binding:"required"` + ImagesJSON string `json:"images_json"` + Price int64 `json:"price" binding:"required"` + Stock int64 `json:"stock" binding:"required"` + Status int32 `json:"status"` + Description string `json:"description"` } type createProductResponse struct { @@ -46,7 +47,7 @@ func (h *handler) CreateProduct() core.HandlerFunc { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作")) 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 { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) return @@ -58,12 +59,13 @@ func (h *handler) CreateProduct() core.HandlerFunc { } type modifyProductRequest struct { - Name *string `json:"name"` - CategoryID *int64 `json:"category_id"` - ImagesJSON *string `json:"images_json"` - Price *int64 `json:"price"` - Stock *int64 `json:"stock"` - Status *int32 `json:"status"` + Name *string `json:"name"` + CategoryID *int64 `json:"category_id"` + ImagesJSON *string `json:"images_json"` + Price *int64 `json:"price"` + Stock *int64 `json:"stock"` + Status *int32 `json:"status"` + Description *string `json:"description"` } // ModifyProduct 修改商品 @@ -90,7 +92,7 @@ func (h *handler) ModifyProduct() core.HandlerFunc { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作")) 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())) return } @@ -133,14 +135,15 @@ type listProductsRequest struct { } type productItem struct { - ID int64 `json:"id"` - Name string `json:"name"` - CategoryID int64 `json:"category_id"` - ImagesJSON string `json:"images_json"` - Price int64 `json:"price"` - Stock int64 `json:"stock"` - Sales int64 `json:"sales"` - Status int32 `json:"status"` + ID int64 `json:"id"` + Name string `json:"name"` + CategoryID int64 `json:"category_id"` + ImagesJSON string `json:"images_json"` + Price int64 `json:"price"` + Stock int64 `json:"stock"` + Sales int64 `json:"sales"` + Status int32 `json:"status"` + Description string `json:"description"` } type listProductsResponse struct { Page int `json:"page"` @@ -181,7 +184,7 @@ func (h *handler) ListProducts() core.HandlerFunc { res.Total = total res.List = make([]productItem, len(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) } diff --git a/internal/api/user/orders_app.go b/internal/api/user/orders_app.go index 85e15f0..0a90644 100644 --- a/internal/api/user/orders_app.go +++ b/internal/api/user/orders_app.go @@ -141,7 +141,7 @@ func (h *handler) CancelOrder() core.HandlerFunc { OrderID: order.ID, OrderNo: order.OrderNo, Status: order.Status, - CancelledAt: order.CancelledAt, + CancelledAt: &order.CancelledAt, }) } } diff --git a/internal/repository/mysql/dao/activities.gen.go b/internal/repository/mysql/dao/activities.gen.go index c1280da..4282af4 100644 --- a/internal/repository/mysql/dao/activities.gen.go +++ b/internal/repository/mysql/dao/activities.gen.go @@ -55,6 +55,10 @@ func newActivities(db *gorm.DB, opts ...gen.DOOption) activities { _activities.CommitmentStateVersion = field.NewInt32(tableName, "commitment_state_version") _activities.CommitmentItemsRoot = field.NewBytes(tableName, "commitment_items_root") _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() @@ -94,6 +98,10 @@ type activities struct { CommitmentStateVersion field.Int32 CommitmentItemsRoot field.Bytes GameplayIntro field.String // 玩法介绍 + DailySeed field.String + DailySeedDate field.String // 种子日期(YYYY-MM-DD) + LastDailySeed field.String // 昨日种子 + LastDailySeedDate field.String // 昨日种子日期 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.CommitmentItemsRoot = field.NewBytes(table, "commitment_items_root") 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() @@ -154,7 +166,7 @@ func (a *activities) GetFieldByName(fieldName string) (field.OrderExpr, bool) { } 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["created_at"] = a.CreatedAt a.fieldMap["updated_at"] = a.UpdatedAt @@ -183,6 +195,10 @@ func (a *activities) fillFieldMap() { a.fieldMap["commitment_state_version"] = a.CommitmentStateVersion a.fieldMap["commitment_items_root"] = a.CommitmentItemsRoot 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 { diff --git a/internal/repository/mysql/dao/activity_reward_settings.gen.go b/internal/repository/mysql/dao/activity_reward_settings.gen.go index 9c3efcb..27320ba 100644 --- a/internal/repository/mysql/dao/activity_reward_settings.gen.go +++ b/internal/repository/mysql/dao/activity_reward_settings.gen.go @@ -40,6 +40,7 @@ func newActivityRewardSettings(db *gorm.DB, opts ...gen.DOOption) activityReward _activityRewardSettings.Sort = field.NewInt32(tableName, "sort") _activityRewardSettings.IsBoss = field.NewInt32(tableName, "is_boss") _activityRewardSettings.DeletedAt = field.NewField(tableName, "deleted_at") + _activityRewardSettings.MinScore = field.NewInt64(tableName, "min_score") _activityRewardSettings.fillFieldMap() @@ -64,6 +65,7 @@ type activityRewardSettings struct { Sort field.Int32 // 排序 IsBoss field.Int32 // Boss 1 是 0 不是 DeletedAt field.Field + MinScore field.Int64 // 最低得分/碰数要求 fieldMap map[string]field.Expr } @@ -93,6 +95,7 @@ func (a *activityRewardSettings) updateTableName(table string) *activityRewardSe a.Sort = field.NewInt32(table, "sort") a.IsBoss = field.NewInt32(table, "is_boss") a.DeletedAt = field.NewField(table, "deleted_at") + a.MinScore = field.NewInt64(table, "min_score") a.fillFieldMap() @@ -109,7 +112,7 @@ func (a *activityRewardSettings) GetFieldByName(fieldName string) (field.OrderEx } 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["created_at"] = a.CreatedAt a.fieldMap["updated_at"] = a.UpdatedAt @@ -123,6 +126,7 @@ func (a *activityRewardSettings) fillFieldMap() { a.fieldMap["sort"] = a.Sort a.fieldMap["is_boss"] = a.IsBoss a.fieldMap["deleted_at"] = a.DeletedAt + a.fieldMap["min_score"] = a.MinScore } func (a activityRewardSettings) clone(db *gorm.DB) activityRewardSettings { diff --git a/internal/repository/mysql/dao/orders.gen.go b/internal/repository/mysql/dao/orders.gen.go index 0813955..4bf9ec1 100644 --- a/internal/repository/mysql/dao/orders.gen.go +++ b/internal/repository/mysql/dao/orders.gen.go @@ -44,6 +44,8 @@ func newOrders(db *gorm.DB, opts ...gen.DOOption) orders { _orders.UserAddressID = field.NewInt64(tableName, "user_address_id") _orders.IsConsumed = field.NewInt32(tableName, "is_consumed") _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.fillFieldMap() @@ -73,6 +75,8 @@ type orders struct { UserAddressID field.Int64 // 收货地址ID(user_addresses.id) IsConsumed field.Int32 // 是否已履约/消耗(对虚拟资产) PointsLedgerID field.Int64 // 积分扣减流水ID(user_points_ledger.id) + CouponID field.Int64 // 使用的优惠券ID + ItemCardID field.Int64 // 使用的道具卡ID Remark field.String // 备注 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.IsConsumed = field.NewInt32(table, "is_consumed") 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.fillFieldMap() @@ -124,7 +130,7 @@ func (o *orders) GetFieldByName(fieldName string) (field.OrderExpr, bool) { } 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["created_at"] = o.CreatedAt o.fieldMap["updated_at"] = o.UpdatedAt @@ -142,6 +148,8 @@ func (o *orders) fillFieldMap() { o.fieldMap["user_address_id"] = o.UserAddressID o.fieldMap["is_consumed"] = o.IsConsumed 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 } diff --git a/internal/repository/mysql/dao/products.gen.go b/internal/repository/mysql/dao/products.gen.go index 00367dd..f1361f9 100644 --- a/internal/repository/mysql/dao/products.gen.go +++ b/internal/repository/mysql/dao/products.gen.go @@ -38,6 +38,7 @@ func newProducts(db *gorm.DB, opts ...gen.DOOption) products { _products.Sales = field.NewInt64(tableName, "sales") _products.Status = field.NewInt32(tableName, "status") _products.DeletedAt = field.NewField(tableName, "deleted_at") + _products.Description = field.NewString(tableName, "description") _products.fillFieldMap() @@ -48,18 +49,19 @@ func newProducts(db *gorm.DB, opts ...gen.DOOption) products { type products struct { productsDo - ALL field.Asterisk - ID field.Int64 // 主键ID - CreatedAt field.Time // 创建时间 - UpdatedAt field.Time // 更新时间 - Name field.String // 商品名称 - CategoryID field.Int64 // 单一主分类ID(product_categories.id) - ImagesJSON field.String // 商品图片JSON(数组) - Price field.Int64 // 商品售价(分) - Stock field.Int64 // 可售库存 - Sales field.Int64 // 已售数量 - Status field.Int32 // 上下架状态:1上架 2下架 - DeletedAt field.Field + ALL field.Asterisk + ID field.Int64 // 主键ID + CreatedAt field.Time // 创建时间 + UpdatedAt field.Time // 更新时间 + Name field.String // 商品名称 + CategoryID field.Int64 // 单一主分类ID(product_categories.id) + ImagesJSON field.String // 商品图片JSON(数组) + Price field.Int64 // 商品售价(分) + Stock field.Int64 // 可售库存 + Sales field.Int64 // 已售数量 + Status field.Int32 // 上下架状态:1上架 2下架 + DeletedAt field.Field + Description field.String // 商品详情 fieldMap map[string]field.Expr } @@ -87,6 +89,7 @@ func (p *products) updateTableName(table string) *products { p.Sales = field.NewInt64(table, "sales") p.Status = field.NewInt32(table, "status") p.DeletedAt = field.NewField(table, "deleted_at") + p.Description = field.NewString(table, "description") p.fillFieldMap() @@ -103,7 +106,7 @@ func (p *products) GetFieldByName(fieldName string) (field.OrderExpr, bool) { } 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["created_at"] = p.CreatedAt p.fieldMap["updated_at"] = p.UpdatedAt @@ -115,6 +118,7 @@ func (p *products) fillFieldMap() { p.fieldMap["sales"] = p.Sales p.fieldMap["status"] = p.Status p.fieldMap["deleted_at"] = p.DeletedAt + p.fieldMap["description"] = p.Description } func (p products) clone(db *gorm.DB) products { diff --git a/internal/repository/mysql/dao/task_center_task_tiers.gen.go b/internal/repository/mysql/dao/task_center_task_tiers.gen.go index 560f7fe..cc3ceb4 100644 --- a/internal/repository/mysql/dao/task_center_task_tiers.gen.go +++ b/internal/repository/mysql/dao/task_center_task_tiers.gen.go @@ -37,6 +37,7 @@ func newTaskCenterTaskTiers(db *gorm.DB, opts ...gen.DOOption) taskCenterTaskTie _taskCenterTaskTiers.Priority = field.NewInt32(tableName, "priority") _taskCenterTaskTiers.CreatedAt = field.NewTime(tableName, "created_at") _taskCenterTaskTiers.UpdatedAt = field.NewTime(tableName, "updated_at") + _taskCenterTaskTiers.ExtraParams = field.NewString(tableName, "extra_params") _taskCenterTaskTiers.fillFieldMap() @@ -47,17 +48,18 @@ func newTaskCenterTaskTiers(db *gorm.DB, opts ...gen.DOOption) taskCenterTaskTie type taskCenterTaskTiers struct { taskCenterTaskTiersDo - ALL field.Asterisk - ID field.Int64 // 主键ID - TaskID field.Int64 // 关联任务ID(task_center_tasks.id) - Metric field.String // 指标:first_order|order_count|invite_count - Operator field.String // 比较符:>= 或 == - Threshold field.Int64 // 阈值(数量或布尔首单) - Window field.String // 时间窗口:activity_period|since_registration - Repeatable field.Int32 // 是否每档一次:0否 1是 - Priority field.Int32 // 匹配优先级(数值越小越先匹配) - CreatedAt field.Time // 创建时间 - UpdatedAt field.Time // 更新时间 + ALL field.Asterisk + ID field.Int64 // 主键ID + TaskID field.Int64 // 关联任务ID(task_center_tasks.id) + Metric field.String // 指标:first_order|order_count|invite_count + Operator field.String // 比较符:>= 或 == + Threshold field.Int64 // 阈值(数量或布尔首单) + Window field.String // 时间窗口:activity_period|since_registration + Repeatable field.Int32 // 是否每档一次:0否 1是 + Priority field.Int32 // 匹配优先级(数值越小越先匹配) + CreatedAt field.Time // 创建时间 + UpdatedAt field.Time // 更新时间 + ExtraParams field.String // 额外参数配置(如消费门槛) fieldMap map[string]field.Expr } @@ -84,6 +86,7 @@ func (t *taskCenterTaskTiers) updateTableName(table string) *taskCenterTaskTiers t.Priority = field.NewInt32(table, "priority") t.CreatedAt = field.NewTime(table, "created_at") t.UpdatedAt = field.NewTime(table, "updated_at") + t.ExtraParams = field.NewString(table, "extra_params") t.fillFieldMap() @@ -100,7 +103,7 @@ func (t *taskCenterTaskTiers) GetFieldByName(fieldName string) (field.OrderExpr, } 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["task_id"] = t.TaskID t.fieldMap["metric"] = t.Metric @@ -111,6 +114,7 @@ func (t *taskCenterTaskTiers) fillFieldMap() { t.fieldMap["priority"] = t.Priority t.fieldMap["created_at"] = t.CreatedAt t.fieldMap["updated_at"] = t.UpdatedAt + t.fieldMap["extra_params"] = t.ExtraParams } func (t taskCenterTaskTiers) clone(db *gorm.DB) taskCenterTaskTiers { diff --git a/internal/repository/mysql/dao/user_invites.gen.go b/internal/repository/mysql/dao/user_invites.gen.go index e4fe94a..11d15de 100644 --- a/internal/repository/mysql/dao/user_invites.gen.go +++ b/internal/repository/mysql/dao/user_invites.gen.go @@ -36,6 +36,8 @@ func newUserInvites(db *gorm.DB, opts ...gen.DOOption) userInvites { _userInvites.CreatedAt = field.NewTime(tableName, "created_at") _userInvites.UpdatedAt = field.NewTime(tableName, "updated_at") _userInvites.DeletedAt = field.NewField(tableName, "deleted_at") + _userInvites.IsEffective = field.NewBool(tableName, "is_effective") + _userInvites.AccumulatedAmount = field.NewInt64(tableName, "accumulated_amount") _userInvites.fillFieldMap() @@ -46,16 +48,18 @@ func newUserInvites(db *gorm.DB, opts ...gen.DOOption) userInvites { type userInvites struct { userInvitesDo - ALL field.Asterisk - ID field.Int64 // 主键ID - InviterID field.Int64 // 邀请人用户ID - InviteeID field.Int64 // 被邀请用户ID - InviteCode field.String // 邀请时使用的邀请码 - RewardPoints field.Int64 // 发放的积分数量(用于审计) - RewardedAt field.Time // 奖励发放时间 - CreatedAt field.Time // 创建时间 - UpdatedAt field.Time // 更新时间 - DeletedAt field.Field // 删除时间(软删) + ALL field.Asterisk + ID field.Int64 // 主键ID + InviterID field.Int64 // 邀请人用户ID + InviteeID field.Int64 // 被邀请用户ID + InviteCode field.String // 邀请时使用的邀请码 + RewardPoints field.Int64 // 发放的积分数量(用于审计) + RewardedAt field.Time // 奖励发放时间 + CreatedAt field.Time // 创建时间 + UpdatedAt field.Time // 更新时间 + DeletedAt field.Field // 删除时间(软删) + IsEffective field.Bool // 是否为有效邀请 + AccumulatedAmount field.Int64 // 被邀请人累计消费金额(分) fieldMap map[string]field.Expr } @@ -81,6 +85,8 @@ func (u *userInvites) updateTableName(table string) *userInvites { u.CreatedAt = field.NewTime(table, "created_at") u.UpdatedAt = field.NewTime(table, "updated_at") u.DeletedAt = field.NewField(table, "deleted_at") + u.IsEffective = field.NewBool(table, "is_effective") + u.AccumulatedAmount = field.NewInt64(table, "accumulated_amount") u.fillFieldMap() @@ -97,7 +103,7 @@ func (u *userInvites) GetFieldByName(fieldName string) (field.OrderExpr, bool) { } 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["inviter_id"] = u.InviterID u.fieldMap["invitee_id"] = u.InviteeID @@ -107,6 +113,8 @@ func (u *userInvites) fillFieldMap() { u.fieldMap["created_at"] = u.CreatedAt u.fieldMap["updated_at"] = u.UpdatedAt 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 { diff --git a/internal/repository/mysql/model/activities.gen.go b/internal/repository/mysql/model/activities.gen.go index baf131b..46d48d0 100644 --- a/internal/repository/mysql/model/activities.gen.go +++ b/internal/repository/mysql/model/activities.gen.go @@ -39,13 +39,13 @@ type Activities struct { CommitmentAlgo string `gorm:"column:commitment_algo;default:commit-v1" json:"commitment_algo"` CommitmentSeedMaster []byte `gorm:"column:commitment_seed_master" json:"commitment_seed_master"` 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"` CommitmentItemsRoot []byte `gorm:"column:commitment_items_root" json:"commitment_items_root"` 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 diff --git a/internal/repository/mysql/model/activity_reward_settings.gen.go b/internal/repository/mysql/model/activity_reward_settings.gen.go index a8559bc..388ac00 100644 --- a/internal/repository/mysql/model/activity_reward_settings.gen.go +++ b/internal/repository/mysql/model/activity_reward_settings.gen.go @@ -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) Sort int32 `gorm:"column:sort;comment:排序" json:"sort"` // 排序 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"` + MinScore int64 `gorm:"column:min_score;not null;comment:最低得分/碰数要求" json:"min_score"` // 最低得分/碰数要求 } // TableName ActivityRewardSettings's table name diff --git a/internal/repository/mysql/model/orders.gen.go b/internal/repository/mysql/model/orders.gen.go index fa2bbd2..d0a2e71 100644 --- a/internal/repository/mysql/model/orders.gen.go +++ b/internal/repository/mysql/model/orders.gen.go @@ -12,26 +12,26 @@ const TableNameOrders = "orders" // Orders 订单 type Orders struct { - 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"` // 创建时间 - 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:下单用户ID(user_members.id)" json:"user_id"` // 下单用户ID(user_members.id) - 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其他 - TotalAmount int64 `gorm:"column:total_amount;not null;comment:订单总金额(分)" json:"total_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"` // 积分抵扣金额(分) - 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已退款 - PayPreorderID int64 `gorm:"column:pay_preorder_id;comment:关联预支付单ID(payment_preorder.id)" json:"pay_preorder_id"` // 关联预支付单ID(payment_preorder.id) - PaidAt *time.Time `gorm:"column:paid_at;comment:支付完成时间" json:"paid_at"` // 支付完成时间 - CancelledAt *time.Time `gorm:"column:cancelled_at;comment:取消时间" json:"cancelled_at"` // 取消时间 - UserAddressID int64 `gorm:"column:user_address_id;comment:收货地址ID(user_addresses.id)" json:"user_address_id"` // 收货地址ID(user_addresses.id) - IsConsumed int32 `gorm:"column:is_consumed;not null;comment:是否已履约/消耗(对虚拟资产)" json:"is_consumed"` // 是否已履约/消耗(对虚拟资产) - PointsLedgerID int64 `gorm:"column:points_ledger_id;comment:积分扣减流水ID(user_points_ledger.id)" json:"points_ledger_id"` // 积分扣减流水ID(user_points_ledger.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 - Remark string `gorm:"column:remark;comment:备注" json:"remark"` // 备注 + 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"` // 创建时间 + 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:下单用户ID(user_members.id)" json:"user_id"` // 下单用户ID(user_members.id) + 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其他 + TotalAmount int64 `gorm:"column:total_amount;not null;comment:订单总金额(分)" json:"total_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"` // 积分抵扣金额(分) + 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已退款 + PayPreorderID int64 `gorm:"column:pay_preorder_id;comment:关联预支付单ID(payment_preorder.id)" json:"pay_preorder_id"` // 关联预支付单ID(payment_preorder.id) + PaidAt time.Time `gorm:"column:paid_at;comment:支付完成时间" json:"paid_at"` // 支付完成时间 + CancelledAt time.Time `gorm:"column:cancelled_at;comment:取消时间" json:"cancelled_at"` // 取消时间 + UserAddressID int64 `gorm:"column:user_address_id;comment:收货地址ID(user_addresses.id)" json:"user_address_id"` // 收货地址ID(user_addresses.id) + IsConsumed int32 `gorm:"column:is_consumed;not null;comment:是否已履约/消耗(对虚拟资产)" json:"is_consumed"` // 是否已履约/消耗(对虚拟资产) + PointsLedgerID int64 `gorm:"column:points_ledger_id;comment:积分扣减流水ID(user_points_ledger.id)" json:"points_ledger_id"` // 积分扣减流水ID(user_points_ledger.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 + Remark string `gorm:"column:remark;comment:备注" json:"remark"` // 备注 } // TableName Orders's table name diff --git a/internal/repository/mysql/model/products.gen.go b/internal/repository/mysql/model/products.gen.go index d1d7f93..40ece20 100644 --- a/internal/repository/mysql/model/products.gen.go +++ b/internal/repository/mysql/model/products.gen.go @@ -14,17 +14,18 @@ const TableNameProducts = "products" // Products 商品 type Products struct { - 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"` // 创建时间 - 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"` // 商品名称 - CategoryID int64 `gorm:"column:category_id;comment:单一主分类ID(product_categories.id)" json:"category_id"` // 单一主分类ID(product_categories.id) - ImagesJSON string `gorm:"column:images_json;comment:商品图片JSON(数组)" json:"images_json"` // 商品图片JSON(数组) - Price int64 `gorm:"column:price;not null;comment:商品售价(分)" json:"price"` // 商品售价(分) - Stock int64 `gorm:"column:stock;not null;comment:可售库存" json:"stock"` // 可售库存 - 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下架 - DeletedAt gorm.DeletedAt `gorm:"column:deleted_at" json:"deleted_at"` + 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"` // 创建时间 + 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"` // 商品名称 + CategoryID int64 `gorm:"column:category_id;comment:单一主分类ID(product_categories.id)" json:"category_id"` // 单一主分类ID(product_categories.id) + ImagesJSON string `gorm:"column:images_json;comment:商品图片JSON(数组)" json:"images_json"` // 商品图片JSON(数组) + Price int64 `gorm:"column:price;not null;comment:商品售价(分)" json:"price"` // 商品售价(分) + Stock int64 `gorm:"column:stock;not null;comment:可售库存" json:"stock"` // 可售库存 + 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下架 + DeletedAt gorm.DeletedAt `gorm:"column:deleted_at" json:"deleted_at"` + Description string `gorm:"column:description;comment:商品详情" json:"description"` // 商品详情 } // TableName Products's table name diff --git a/internal/repository/mysql/model/task_center_task_tiers.gen.go b/internal/repository/mysql/model/task_center_task_tiers.gen.go index 6e02a23..306798d 100644 --- a/internal/repository/mysql/model/task_center_task_tiers.gen.go +++ b/internal/repository/mysql/model/task_center_task_tiers.gen.go @@ -12,16 +12,17 @@ const TableNameTaskCenterTaskTiers = "task_center_task_tiers" // TaskCenterTaskTiers 任务中心-档位配置 type TaskCenterTaskTiers struct { - ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID - TaskID int64 `gorm:"column:task_id;not null;comment:关联任务ID(task_center_tasks.id)" json:"task_id"` // 关联任务ID(task_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 - Operator string `gorm:"column:operator;not null;comment:比较符:>= 或 ==" json:"operator"` // 比较符:>= 或 == - 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 - 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"` // 匹配优先级(数值越小越先匹配) - 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"` // 更新时间 + ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID + TaskID int64 `gorm:"column:task_id;not null;comment:关联任务ID(task_center_tasks.id)" json:"task_id"` // 关联任务ID(task_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 + Operator string `gorm:"column:operator;not null;comment:比较符:>= 或 ==" json:"operator"` // 比较符:>= 或 == + 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 + 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"` // 匹配优先级(数值越小越先匹配) + 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"` // 更新时间 + ExtraParams string `gorm:"column:extra_params;comment:额外参数配置(如消费门槛)" json:"extra_params"` // 额外参数配置(如消费门槛) } // TableName TaskCenterTaskTiers's table name diff --git a/internal/repository/mysql/model/user_invites.gen.go b/internal/repository/mysql/model/user_invites.gen.go index 47cd1cc..3974dda 100644 --- a/internal/repository/mysql/model/user_invites.gen.go +++ b/internal/repository/mysql/model/user_invites.gen.go @@ -14,17 +14,17 @@ const TableNameUserInvites = "user_invites" // UserInvites 用户邀请关系表 type UserInvites struct { - 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 - 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"` // 邀请时使用的邀请码 + 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 + 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"` // 邀请时使用的邀请码 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"` // 奖励发放时间 - 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"` // 更新时间 - DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;comment:删除时间(软删)" json:"deleted_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"` // 更新时间 + 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 diff --git a/internal/service/product/product.go b/internal/service/product/product.go index f52ef85..8e3d036 100644 --- a/internal/service/product/product.go +++ b/internal/service/product/product.go @@ -1,16 +1,16 @@ package product import ( - "context" - "encoding/json" - "strings" - "time" - "errors" + "context" + "encoding/json" + "errors" + "strings" + "time" - "bindbox-game/internal/pkg/logger" - "bindbox-game/internal/repository/mysql" - "bindbox-game/internal/repository/mysql/dao" - "bindbox-game/internal/repository/mysql/model" + "bindbox-game/internal/pkg/logger" + "bindbox-game/internal/repository/mysql" + "bindbox-game/internal/repository/mysql/dao" + "bindbox-game/internal/repository/mysql/model" ) type Service interface { @@ -22,22 +22,22 @@ type Service interface { CreateProduct(ctx context.Context, in CreateProductInput) (*model.Products, error) ModifyProduct(ctx context.Context, id int64, in ModifyProductInput) error DeleteProduct(ctx context.Context, id int64) 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) - ListForApp(ctx context.Context, in AppListInput) (items []AppListItem, total int64, err error) - GetDetailForApp(ctx context.Context, id int64) (*AppDetail, 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) + ListForApp(ctx context.Context, in AppListInput) (items []AppListItem, total int64, err error) + GetDetailForApp(ctx context.Context, id int64) (*AppDetail, error) } type service struct { - logger logger.CustomLogger - readDB *dao.Query - writeDB *dao.Query - listCache map[string]cachedList - detailCache map[int64]cachedDetail + logger logger.CustomLogger + readDB *dao.Query + writeDB *dao.Query + listCache map[string]cachedList + detailCache map[int64]cachedDetail } 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 { @@ -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 { - _, err := s.writeDB.ProductCategories.WithContext(ctx).Where(s.writeDB.ProductCategories.ID.Eq(id)).Updates(map[string]any{"deleted_at": time.Now()}) - return err + _, err := s.writeDB.ProductCategories.WithContext(ctx).Where(s.writeDB.ProductCategories.ID.Eq(id)).Updates(map[string]any{"deleted_at": time.Now()}) + return err } 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 { - Name string - CategoryID int64 - ImagesJSON string - Price int64 - Stock int64 - Status int32 + Name string + CategoryID int64 + ImagesJSON string + Price int64 + Stock int64 + Status int32 + Description string } type ModifyProductInput struct { - Name *string - CategoryID *int64 - ImagesJSON *string - Price *int64 - Stock *int64 - Status *int32 + Name *string + CategoryID *int64 + ImagesJSON *string + Price *int64 + Stock *int64 + Status *int32 + Description *string } type ListProductsInput struct { @@ -140,40 +142,40 @@ type ListProductsInput struct { } type AppListInput struct { - CategoryID *int64 - PriceMin *int64 - PriceMax *int64 - SalesMin *int64 - InStock *bool - SortBy string - Order string - Page int - PageSize int + CategoryID *int64 + PriceMin *int64 + PriceMax *int64 + SalesMin *int64 + InStock *bool + SortBy string + Order string + Page int + PageSize int } type AppListItem struct { - ID int64 - Name string - MainImage string - Price int64 - Sales int64 - InStock bool + ID int64 + Name string + MainImage string + Price int64 + Sales int64 + InStock bool } type AppDetail struct { - ID int64 - Name string - Album []string - Price int64 - Sales int64 - Stock int64 - Description string - Service []string - Recommendations []AppListItem + ID int64 + Name string + Album []string + Price int64 + Sales int64 + Stock int64 + Description string + Service []string + Recommendations []AppListItem } 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 { return nil, err } @@ -201,6 +203,9 @@ func (s *service) ModifyProduct(ctx context.Context, id int64, in ModifyProductI if in.Status != nil { set["status"] = *in.Status } + if in.Description != nil { + set["description"] = *in.Description + } if len(set) == 0 { 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 { - _, err := s.writeDB.Products.WithContext(ctx).Where(s.writeDB.Products.ID.Eq(id)).Updates(map[string]any{"deleted_at": time.Now()}) - return err + _, err := s.writeDB.Products.WithContext(ctx).Where(s.writeDB.Products.ID.Eq(id)).Updates(map[string]any{"deleted_at": time.Now()}) + return err } 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) { - key := s.listKey(in) - if v, ok := s.listCache[key]; ok && time.Now().Before(v.expireAt) { - return v.items, v.total, nil - } - if in.Page <= 0 { - in.Page = 1 - } - if in.PageSize <= 0 { - in.PageSize = 20 - } - q := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.Status.Eq(1)) - if in.CategoryID != nil { - q = q.Where(s.readDB.Products.CategoryID.Eq(*in.CategoryID)) - } - if in.PriceMin != nil { - q = q.Where(s.readDB.Products.Price.Gte(*in.PriceMin)) - } - if in.PriceMax != nil { - q = q.Where(s.readDB.Products.Price.Lte(*in.PriceMax)) - } - if in.SalesMin != nil { - q = q.Where(s.readDB.Products.Sales.Gte(*in.SalesMin)) - } - if in.InStock != nil && *in.InStock { - q = q.Where(s.readDB.Products.Stock.Gt(0)) - } - total, err = q.Count() - if err != nil { - return - } - orderDesc := true - if strings.ToLower(in.Order) == "asc" { - orderDesc = false - } - switch strings.ToLower(in.SortBy) { - case "price": - if orderDesc { - q = q.Order(s.readDB.Products.Price.Desc()) - } else { - q = q.Order(s.readDB.Products.Price.Asc()) - } - case "createdat", "created_at": - if orderDesc { - q = q.Order(s.readDB.Products.CreatedAt.Desc()) - } else { - q = q.Order(s.readDB.Products.CreatedAt.Asc()) - } - default: - if orderDesc { - q = q.Order(s.readDB.Products.Sales.Desc()) - } else { - q = q.Order(s.readDB.Products.Sales.Asc()) - } - } - rows, err := q.Limit(in.PageSize).Offset((in.Page-1)*in.PageSize).Find() - if err != nil { - return - } - items = make([]AppListItem, len(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} - } - s.listCache[key] = cachedList{items: items, total: total, expireAt: time.Now().Add(30 * time.Second)} - return + key := s.listKey(in) + if v, ok := s.listCache[key]; ok && time.Now().Before(v.expireAt) { + return v.items, v.total, nil + } + if in.Page <= 0 { + in.Page = 1 + } + if in.PageSize <= 0 { + in.PageSize = 20 + } + q := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.Status.Eq(1)) + if in.CategoryID != nil { + q = q.Where(s.readDB.Products.CategoryID.Eq(*in.CategoryID)) + } + if in.PriceMin != nil { + q = q.Where(s.readDB.Products.Price.Gte(*in.PriceMin)) + } + if in.PriceMax != nil { + q = q.Where(s.readDB.Products.Price.Lte(*in.PriceMax)) + } + if in.SalesMin != nil { + q = q.Where(s.readDB.Products.Sales.Gte(*in.SalesMin)) + } + if in.InStock != nil && *in.InStock { + q = q.Where(s.readDB.Products.Stock.Gt(0)) + } + total, err = q.Count() + if err != nil { + return + } + orderDesc := true + if strings.ToLower(in.Order) == "asc" { + orderDesc = false + } + switch strings.ToLower(in.SortBy) { + case "price": + if orderDesc { + q = q.Order(s.readDB.Products.Price.Desc()) + } else { + q = q.Order(s.readDB.Products.Price.Asc()) + } + case "createdat", "created_at": + if orderDesc { + q = q.Order(s.readDB.Products.CreatedAt.Desc()) + } else { + q = q.Order(s.readDB.Products.CreatedAt.Asc()) + } + default: + if orderDesc { + q = q.Order(s.readDB.Products.Sales.Desc()) + } else { + q = q.Order(s.readDB.Products.Sales.Asc()) + } + } + rows, err := q.Limit(in.PageSize).Offset((in.Page - 1) * in.PageSize).Find() + if err != nil { + return + } + items = make([]AppListItem, len(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} + } + s.listCache[key] = cachedList{items: items, total: total, expireAt: time.Now().Add(30 * time.Second)} + return } func (s *service) GetDetailForApp(ctx context.Context, id int64) (*AppDetail, error) { - if v, ok := s.detailCache[id]; ok && time.Now().Before(v.expireAt) { - return v.detail, nil - } - p, err := s.readDB.Products.WithContext(ctx).Where(s.readDB.Products.ID.Eq(id)).Take() - if err != nil { - return nil, err - } - if p.Status != 1 { - return nil, errors.New("PRODUCT_OFFSHELF") - } - if p.Stock <= 0 { - return nil, errors.New("PRODUCT_OUT_OF_STOCK") - } - 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{}} - 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 { - recQ = recQ.Where(s.readDB.Products.CategoryID.Eq(p.CategoryID)) - } - recs, _ := recQ.Order(s.readDB.Products.Sales.Desc()).Limit(6).Find() - 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}) - } - s.detailCache[id] = cachedDetail{detail: d, expireAt: time.Now().Add(60 * time.Second)} - return d, nil + if v, ok := s.detailCache[id]; ok && time.Now().Before(v.expireAt) { + return v.detail, nil + } + p, err := s.readDB.Products.WithContext(ctx).Where(s.readDB.Products.ID.Eq(id)).Take() + if err != nil { + return nil, err + } + if p.Status != 1 { + return nil, errors.New("PRODUCT_OFFSHELF") + } + if p.Stock <= 0 { + return nil, errors.New("PRODUCT_OUT_OF_STOCK") + } + album := splitImages(p.ImagesJSON) + 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)) + if p.CategoryID > 0 { + recQ = recQ.Where(s.readDB.Products.CategoryID.Eq(p.CategoryID)) + } + recs, _ := recQ.Order(s.readDB.Products.Sales.Desc()).Limit(6).Find() + 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}) + } + s.detailCache[id] = cachedDetail{detail: d, expireAt: time.Now().Add(60 * time.Second)} + return d, nil } func (s *service) BatchUpdate(ctx context.Context, ids []int64, stock *int64, status *int32) (int64, error) { - if len(ids) == 0 { - return 0, nil - } - set := map[string]any{} - if stock != nil { - set["stock"] = *stock - } - if status != nil { - set["status"] = *status - } - if len(set) == 0 { - return 0, nil - } - updater := s.writeDB.Products.WithContext(ctx).Where(s.writeDB.Products.ID.In(ids...)) - result, err := updater.Updates(set) - if err != nil { - return 0, err - } - return result.RowsAffected, nil + if len(ids) == 0 { + return 0, nil + } + set := map[string]any{} + if stock != nil { + set["stock"] = *stock + } + if status != nil { + set["status"] = *status + } + if len(set) == 0 { + return 0, nil + } + updater := s.writeDB.Products.WithContext(ctx).Where(s.writeDB.Products.ID.In(ids...)) + result, err := updater.Updates(set) + if err != nil { + return 0, err + } + return result.RowsAffected, nil } func normalizeJSON(s string) string { @@ -367,36 +372,37 @@ func normalizeJSON(s string) string { } func (s *service) listKey(in AppListInput) string { - b, _ := json.Marshal(in) - return string(b) + b, _ := json.Marshal(in) + return string(b) } func splitImages(s string) []string { - var arr []string - if strings.TrimSpace(s) == "" { - return arr - } - var v []string - if json.Unmarshal([]byte(s), &v) != nil { - return arr - } - return v + var arr []string + if strings.TrimSpace(s) == "" { + return arr + } + var v []string + if json.Unmarshal([]byte(s), &v) != nil { + return arr + } + return v } func firstImage(s string) string { - imgs := splitImages(s) - if len(imgs) > 0 { - return imgs[0] - } - return "" + imgs := splitImages(s) + if len(imgs) > 0 { + return imgs[0] + } + return "" } + type cachedList struct { - items []AppListItem - total int64 - expireAt time.Time + items []AppListItem + total int64 + expireAt time.Time } type cachedDetail struct { - detail *AppDetail - expireAt time.Time + detail *AppDetail + expireAt time.Time } diff --git a/internal/service/user/reward_grant.go b/internal/service/user/reward_grant.go index d1864ac..a97baf9 100644 --- a/internal/service/user/reward_grant.go +++ b/internal/service/user/reward_grant.go @@ -91,8 +91,8 @@ func (s *service) GrantReward(ctx context.Context, userID int64, req GrantReward PointsAmount: 0, ActualAmount: 0, IsConsumed: 0, - PaidAt: &now, // 设置支付时间为当前时间 - CancelledAt: &minValidTime, // 设置取消时间为最小有效时间,避免MySQL错误 + PaidAt: now, // 设置支付时间为当前时间 + CancelledAt: minValidTime, // 设置取消时间为最小有效时间,避免MySQL错误 Remark: req.Remark, CreatedAt: now, UpdatedAt: now, diff --git a/logs/mini-chat-access.log b/logs/mini-chat-access.log index f999e18..748bdf8 100644 --- a/logs/mini-chat-access.log +++ b/logs/mini-chat-access.log @@ -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":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 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}