Files
36Wisdom/biz/dao/dao_user_progress.go
T
2026-08-14 16:11:10 +08:00

137 lines
4.6 KiB
Go

package dao
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"36wisdom/biz/consts"
"36wisdom/biz/model/entity"
"36wisdom/common"
)
type userProgressDao struct{ common.BaseDao }
var UserProgress = &userProgressDao{BaseDao: common.BaseDao{Table: consts.TableUserProgress}}
func (d *userProgressDao) Init(ctx context.Context) error {
_, err := g.DB().Exec(ctx, `
CREATE TABLE IF NOT EXISTS user_progress (
id INTEGER PRIMARY KEY AUTOINCREMENT,
child_id INTEGER NOT NULL,
level_id INTEGER NOT NULL,
stars INTEGER NOT NULL DEFAULT 0,
score INTEGER NOT NULL DEFAULT 0,
perfect INTEGER NOT NULL DEFAULT 0,
content_version INTEGER NOT NULL DEFAULT 1,
completed_at DATETIME,
UNIQUE(child_id, level_id)
);
CREATE INDEX IF NOT EXISTS idx_progress_level ON user_progress(level_id);`)
return err
}
// GetByChildLevel 孩子某关进度(不缓存);不存在返回 nil, nil。
func (d *userProgressDao) GetByChildLevel(ctx context.Context, childId, levelId int64) (*entity.UserProgress, error) {
return common.GetOne[entity.UserProgress](d.Model().Ctx(ctx).
Where("child_id", childId).Where("level_id", levelId))
}
// ListByChildLevelIds 孩子多关进度(不缓存)。
func (d *userProgressDao) ListByChildLevelIds(ctx context.Context, childId int64, levelIds []int64) ([]*entity.UserProgress, error) {
if len(levelIds) == 0 {
return []*entity.UserProgress{}, nil
}
return common.GetList[entity.UserProgress](d.Model().Ctx(ctx).
Where("child_id", childId).WhereIn("level_id", levelIds))
}
// ListByChild 孩子全部闯关进度(不缓存),按 level_id 升序。
func (d *userProgressDao) ListByChild(ctx context.Context, childId int64) ([]*entity.UserProgress, error) {
return common.GetList[entity.UserProgress](d.Model().Ctx(ctx).
Where("child_id", childId).Order("level_id ASC"))
}
// CountPerfectByChild 孩子完美通关关卡数。
func (d *userProgressDao) CountPerfectByChild(ctx context.Context, childId int64) (int, error) {
return d.Model().Ctx(ctx).Where("child_id", childId).Where("perfect", 1).Count()
}
// CountPerfectByChildIds 批量孩子的完美通关数(按 child_id 分组聚合)。
func (d *userProgressDao) CountPerfectByChildIds(ctx context.Context, childIds []int64) (map[int64]int, error) {
m := make(map[int64]int, len(childIds))
if len(childIds) == 0 {
return m, nil
}
recs, err := d.Model().Ctx(ctx).Fields("child_id", "COUNT(*) AS cnt").
Where("perfect", 1).WhereIn("child_id", childIds).Group("child_id").All()
if err != nil {
return nil, err
}
for _, r := range recs {
m[r["child_id"].Int64()] = r["cnt"].Int()
}
return m, nil
}
// ProgressStatsByLevel 关卡参与人数与完美通关数(单表聚合)。
func (d *userProgressDao) ProgressStatsByLevel(ctx context.Context, levelId int64) (players, perfectCount int, err error) {
rec, err := d.Model().Ctx(ctx).
Fields("COUNT(*) AS players, SUM(CASE WHEN perfect = 1 THEN 1 ELSE 0 END) AS perfect_cnt").
Where("level_id", levelId).One()
if err != nil {
return 0, 0, err
}
if rec.IsEmpty() {
return 0, 0, nil
}
return rec["players"].Int(), rec["perfect_cnt"].Int(), nil
}
// GetInTx 事务内读孩子某关进度;不存在返回 nil, nil。
func (d *userProgressDao) GetInTx(ctx context.Context, tx gdb.TX, childId, levelId int64) (*entity.UserProgress, error) {
rec, err := tx.Model(consts.TableUserProgress).Ctx(ctx).
Where("child_id", childId).Where("level_id", levelId).One()
if err != nil {
return nil, err
}
if rec.IsEmpty() {
return nil, nil
}
dst := &entity.UserProgress{}
if err = rec.Struct(dst); err != nil {
return nil, err
}
return dst, nil
}
// UpsertInTx 事务内合并写入进度:星星取历史最高、完美取并集;不存在则插入。
func (d *userProgressDao) UpsertInTx(ctx context.Context, tx gdb.TX, childId, levelId int64, stars, perfect, contentVersion int) error {
rec, err := tx.Model(consts.TableUserProgress).Ctx(ctx).
Where("child_id", childId).Where("level_id", levelId).One()
if err != nil {
return err
}
if stars < rec["stars"].Int() {
stars = rec["stars"].Int()
}
perfect = rec["perfect"].Int() | perfect
data := g.Map{
"stars": stars,
"perfect": perfect,
"content_version": contentVersion,
"completed_at": gtime.Now(),
}
if rec.IsEmpty() {
data["child_id"] = childId
data["level_id"] = levelId
_, err = tx.Model(consts.TableUserProgress).Ctx(ctx).Data(data).Insert()
} else {
_, err = tx.Model(consts.TableUserProgress).Ctx(ctx).Data(data).
Where("child_id", childId).Where("level_id", levelId).Update()
}
return err
}