新功能(#74): 新增促销系统模型层

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
2026-05-26 22:11:02 -07:00
parent 5ebfe0a981
commit e61988d78f
14 changed files with 720 additions and 25 deletions
+106
View File
@@ -0,0 +1,106 @@
package subscribe_promo
import (
"context"
"errors"
"fmt"
"github.com/perfect-panel/server/pkg/cache"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
)
var _ Model = (*customSubscribePromoModel)(nil)
var cacheSubscribePromoIdPrefix = "cache:subscribe_promo:id:"
type (
Model interface {
subscribePromoModel
customSubscribePromoLogicModel
}
subscribePromoModel interface {
Insert(ctx context.Context, data *SubscribePromo, tx ...*gorm.DB) error
FindOne(ctx context.Context, id int64) (*SubscribePromo, error)
Update(ctx context.Context, data *SubscribePromo, tx ...*gorm.DB) error
Delete(ctx context.Context, id int64, tx ...*gorm.DB) error
Transaction(ctx context.Context, fn func(db *gorm.DB) error) error
}
customSubscribePromoModel struct {
*defaultSubscribePromoModel
}
defaultSubscribePromoModel struct {
cache.CachedConn
table string
}
)
func newSubscribePromoModel(db *gorm.DB, c *redis.Client) *defaultSubscribePromoModel {
return &defaultSubscribePromoModel{
CachedConn: cache.NewConn(db, c),
table: "`subscribe_promo`",
}
}
func (m *defaultSubscribePromoModel) getCacheKeys(data *SubscribePromo) []string {
if data == nil {
return []string{}
}
return []string{fmt.Sprintf("%s%v", cacheSubscribePromoIdPrefix, data.Id)}
}
func (m *defaultSubscribePromoModel) Insert(ctx context.Context, data *SubscribePromo, tx ...*gorm.DB) error {
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
if len(tx) > 0 {
conn = tx[0]
}
return conn.Create(data).Error
}, m.getCacheKeys(data)...)
}
func (m *defaultSubscribePromoModel) FindOne(ctx context.Context, id int64) (*SubscribePromo, error) {
key := fmt.Sprintf("%s%v", cacheSubscribePromoIdPrefix, id)
var resp SubscribePromo
err := m.QueryCtx(ctx, &resp, key, func(conn *gorm.DB, v interface{}) error {
return conn.Model(&SubscribePromo{}).Where("`id` = ?", id).First(v).Error
})
if err != nil {
return nil, err
}
return &resp, nil
}
func (m *defaultSubscribePromoModel) Update(ctx context.Context, data *SubscribePromo, tx ...*gorm.DB) error {
old, err := m.FindOne(ctx, data.Id)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
if len(tx) > 0 {
conn = tx[0]
}
return conn.Save(data).Error
}, m.getCacheKeys(old)...)
}
func (m *defaultSubscribePromoModel) Delete(ctx context.Context, id int64, tx ...*gorm.DB) error {
data, err := m.FindOne(ctx, id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
return err
}
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
if len(tx) > 0 {
conn = tx[0]
}
return conn.Delete(&SubscribePromo{}, id).Error
}, m.getCacheKeys(data)...)
}
func (m *defaultSubscribePromoModel) Transaction(ctx context.Context, fn func(db *gorm.DB) error) error {
return m.TransactCtx(ctx, fn)
}
+84
View File
@@ -0,0 +1,84 @@
package subscribe_promo
import (
"context"
"time"
"github.com/perfect-panel/server/internal/model/promo_rule"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
)
type RulePromo struct {
Id int64
SubscribeId int64
PromoRuleId int64
PromoPrice int64
RuleName string
RuleType string
Params promo_rule.JSONRawMessage
Priority int64
StartTime *time.Time
EndTime *time.Time
}
type customSubscribePromoLogicModel interface {
FindOneBySubscribeAndRule(ctx context.Context, subscribeId, promoRuleId int64) (*SubscribePromo, error)
FindBySubscribeId(ctx context.Context, subscribeId int64) ([]*SubscribePromo, error)
FindByPromoRuleId(ctx context.Context, promoRuleId int64) ([]*SubscribePromo, error)
QueryEnabledBySubscribeId(ctx context.Context, subscribeId int64) ([]*RulePromo, error)
}
func NewModel(conn *gorm.DB, c *redis.Client) Model {
return &customSubscribePromoModel{
defaultSubscribePromoModel: newSubscribePromoModel(conn, c),
}
}
func (m *customSubscribePromoModel) FindOneBySubscribeAndRule(ctx context.Context, subscribeId, promoRuleId int64) (*SubscribePromo, error) {
var resp SubscribePromo
err := m.QueryNoCacheCtx(ctx, &resp, func(conn *gorm.DB, v interface{}) error {
return conn.Model(&SubscribePromo{}).
Where("subscribe_id = ? AND promo_rule_id = ?", subscribeId, promoRuleId).
First(v).Error
})
if err != nil {
return nil, err
}
return &resp, nil
}
func (m *customSubscribePromoModel) FindBySubscribeId(ctx context.Context, subscribeId int64) ([]*SubscribePromo, error) {
var list []*SubscribePromo
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
return conn.Model(&SubscribePromo{}).
Where("subscribe_id = ?", subscribeId).
Order("id DESC").
Find(v).Error
})
return list, err
}
func (m *customSubscribePromoModel) FindByPromoRuleId(ctx context.Context, promoRuleId int64) ([]*SubscribePromo, error) {
var list []*SubscribePromo
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
return conn.Model(&SubscribePromo{}).
Where("promo_rule_id = ?", promoRuleId).
Order("id DESC").
Find(v).Error
})
return list, err
}
func (m *customSubscribePromoModel) QueryEnabledBySubscribeId(ctx context.Context, subscribeId int64) ([]*RulePromo, error) {
var list []*RulePromo
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
return conn.Table("subscribe_promo AS sp").
Select("sp.id, sp.subscribe_id, sp.promo_rule_id, sp.promo_price, pr.name AS rule_name, pr.type AS rule_type, pr.params, pr.priority, pr.start_time, pr.end_time").
Joins("JOIN promo_rule AS pr ON pr.id = sp.promo_rule_id AND pr.deleted_at IS NULL").
Where("sp.subscribe_id = ? AND pr.enabled = ?", subscribeId, true).
Order("pr.priority DESC, pr.id DESC").
Scan(v).Error
})
return list, err
}
@@ -0,0 +1,16 @@
package subscribe_promo
import "time"
type SubscribePromo struct {
Id int64 `gorm:"type:bigint unsigned;primaryKey"`
SubscribeId int64 `gorm:"type:bigint unsigned;not null;index:uk_subscribe_rule,unique,priority:1;comment:Subscribe Id"`
PromoRuleId int64 `gorm:"type:bigint unsigned;not null;index:uk_subscribe_rule,unique,priority:2;index:idx_promo_rule_id;comment:Promo Rule Id"`
PromoPrice int64 `gorm:"type:bigint;not null;default:0;comment:Promo Price"`
CreatedAt time.Time `gorm:"<-:create;comment:Create Time"`
UpdatedAt time.Time `gorm:"comment:Update Time"`
}
func (SubscribePromo) TableName() string {
return "subscribe_promo"
}