252 lines
6.8 KiB
Go
252 lines
6.8 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
|
|
"36wisdom/biz/consts"
|
|
"36wisdom/biz/dao"
|
|
"36wisdom/biz/model/dto"
|
|
"36wisdom/biz/model/entity"
|
|
"36wisdom/common/auth"
|
|
)
|
|
|
|
type child struct{}
|
|
|
|
var Child = &child{}
|
|
|
|
// getChildOf 校验孩子归属当前家长并返回档案。
|
|
func getChildOf(ctx context.Context, parentUid, childId int64) (*entity.Child, error) {
|
|
rec, err := dao.Child.GetByPk(ctx, childId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if rec == nil || rec.ParentId != parentUid {
|
|
return nil, gerror.New("孩子档案不存在")
|
|
}
|
|
return rec, nil
|
|
}
|
|
|
|
// Create 新建孩子档案。
|
|
func (s *child) Create(ctx context.Context, req *dto.ChildCreateReq) (*dto.ChildCreateRes, error) {
|
|
id, err := dao.Child.InsertAndReturnId(ctx, g.Map{
|
|
"parent_id": auth.GetUid(ctx),
|
|
"nickname": req.Nickname,
|
|
"age_group": req.AgeGroup,
|
|
"status": consts.StatusEnabled,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &dto.ChildCreateRes{ChildId: id}, nil
|
|
}
|
|
|
|
// Update 更新孩子档案:仅本人名下档案可改,非空字段覆盖。
|
|
func (s *child) Update(ctx context.Context, req *dto.ChildUpdateReq) (*dto.ChildUpdateRes, error) {
|
|
rec, err := dao.Child.GetByPk(ctx, req.ChildId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if rec == nil || rec.ParentId != auth.GetUid(ctx) {
|
|
return nil, gerror.New("孩子档案不存在")
|
|
}
|
|
data := g.Map{}
|
|
if req.Nickname != "" {
|
|
data["nickname"] = req.Nickname
|
|
}
|
|
if req.Avatar != "" {
|
|
data["avatar"] = req.Avatar
|
|
}
|
|
if req.AgeGroup != "" {
|
|
data["age_group"] = req.AgeGroup
|
|
}
|
|
if req.DailyLimitMinutes > 0 {
|
|
data["daily_limit_minutes"] = req.DailyLimitMinutes
|
|
}
|
|
if len(data) == 0 {
|
|
return &dto.ChildUpdateRes{}, nil
|
|
}
|
|
if err = dao.Child.UpdateByPk(ctx, req.ChildId, data); err != nil {
|
|
return nil, err
|
|
}
|
|
return &dto.ChildUpdateRes{}, nil
|
|
}
|
|
|
|
// List 家长名下的孩子列表,perfect 数经 user_progress 批量汇总。
|
|
func (s *child) List(ctx context.Context, req *dto.ChildListReq) (*dto.ChildListRes, error) {
|
|
parentId := auth.GetUid(ctx)
|
|
recs, err := dao.Child.ListByParent(ctx, parentId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
items := make([]dto.ChildListItem, 0, len(recs))
|
|
if len(recs) == 0 {
|
|
return &dto.ChildListRes{List: items}, nil
|
|
}
|
|
|
|
childIds := make([]int64, 0, len(recs))
|
|
for _, r := range recs {
|
|
childIds = append(childIds, r.Id)
|
|
}
|
|
perfectMap, err := dao.UserProgress.CountPerfectByChildIds(ctx, childIds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, r := range recs {
|
|
perfect := perfectMap[r.Id]
|
|
level, title := LevelOf(perfect)
|
|
items = append(items, dto.ChildListItem{
|
|
ChildId: r.Id,
|
|
Nickname: r.Nickname,
|
|
Avatar: r.Avatar,
|
|
AgeGroup: r.AgeGroup,
|
|
Points: r.Points,
|
|
Level: level,
|
|
LevelTitle: title,
|
|
PerfectCount: perfect,
|
|
DailyLimitMinutes: r.DailyLimitMinutes,
|
|
})
|
|
}
|
|
return &dto.ChildListRes{List: items}, nil
|
|
}
|
|
|
|
// ---------- 后台管理 ----------
|
|
|
|
type adminChild struct{}
|
|
|
|
var AdminChild = &adminChild{}
|
|
|
|
// List 孩子列表(parent_id 可选筛),含完美数与成长等级。
|
|
func (s *adminChild) List(ctx context.Context, req *dto.AdminChildListReq) (*dto.AdminChildListRes, error) {
|
|
recs, err := dao.Child.ListAll(ctx, req.ParentId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
childIds := make([]int64, 0, len(recs))
|
|
for _, r := range recs {
|
|
childIds = append(childIds, r.Id)
|
|
}
|
|
perfects, err := perfectCounts(ctx, childIds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
items := make([]*dto.AdminChildItem, 0, len(recs))
|
|
for _, r := range recs {
|
|
item := childItemOf(r)
|
|
item.PerfectCount = perfects[r.Id]
|
|
item.Level, item.LevelTitle = LevelOf(item.PerfectCount)
|
|
items = append(items, item)
|
|
}
|
|
return &dto.AdminChildListRes{List: items}, nil
|
|
}
|
|
|
|
// childItemOf 孩子档案 → 管理项(完美数与成长等级由调用方补填)。
|
|
func childItemOf(r *entity.Child) *dto.AdminChildItem {
|
|
return &dto.AdminChildItem{
|
|
Id: r.Id, ParentId: r.ParentId,
|
|
Nickname: r.Nickname, Avatar: r.Avatar,
|
|
AgeGroup: r.AgeGroup, Points: r.Points,
|
|
DailyLimitMinutes: r.DailyLimitMinutes,
|
|
Status: r.Status, CreatedAt: timeString(r.CreatedAt),
|
|
}
|
|
}
|
|
|
|
// perfectCounts 各孩子完美通关数(复用前台统计)。
|
|
func perfectCounts(ctx context.Context, childIds []int64) (map[int64]int, error) {
|
|
return dao.UserProgress.CountPerfectByChildIds(ctx, childIds)
|
|
}
|
|
|
|
// childNicknames 批量孩子昵称,返回 id → 昵称。
|
|
func childNicknames(ctx context.Context, childIds []int64) (map[int64]string, error) {
|
|
m := make(map[int64]string, len(childIds))
|
|
childIds = uniqueInt64(childIds)
|
|
if len(childIds) == 0 {
|
|
return m, nil
|
|
}
|
|
recs, err := dao.Child.ListByIds(ctx, childIds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, r := range recs {
|
|
m[r.Id] = r.Nickname
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
// timeString 时间格式化(空值回退空串)。
|
|
func timeString(t *gtime.Time) string {
|
|
if t == nil {
|
|
return ""
|
|
}
|
|
return t.String()
|
|
}
|
|
|
|
// Detail 孩子详情:档案 + 全部闯关进度 + 汇总统计。
|
|
func (s *adminChild) Detail(ctx context.Context, req *dto.AdminChildDetailReq) (*dto.AdminChildDetailRes, error) {
|
|
child, err := dao.Child.GetByPk(ctx, req.ChildId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if child == nil {
|
|
return nil, gerror.New("孩子不存在")
|
|
}
|
|
recs, err := dao.UserProgress.ListByChild(ctx, req.ChildId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
levelIds := make([]int64, 0, len(recs))
|
|
for _, p := range recs {
|
|
levelIds = append(levelIds, p.LevelId)
|
|
}
|
|
levels, err := dao.Level.ListByIds(ctx, levelIds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
levelById := make(map[int64]*entity.Level, len(levels))
|
|
strategyIds := make([]int64, 0, len(levels))
|
|
for _, lv := range levels {
|
|
levelById[lv.Id] = lv
|
|
strategyIds = append(strategyIds, lv.StrategyId)
|
|
}
|
|
strategies, err := dao.Strategy.ListByIds(ctx, strategyIds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
strategyNames := make(map[int64]string, len(strategies))
|
|
for _, st := range strategies {
|
|
strategyNames[st.Id] = st.Name
|
|
}
|
|
|
|
item := childItemOf(child)
|
|
perfect, stars := 0, 0
|
|
for _, p := range recs {
|
|
if p.Perfect == 1 {
|
|
perfect++
|
|
}
|
|
stars += p.Stars
|
|
}
|
|
item.PerfectCount = perfect
|
|
detail := &dto.AdminChildDetailRes{
|
|
Child: item, Passed: len(recs), Perfect: perfect, Stars: stars,
|
|
Progress: make([]*dto.AdminProgressItem, 0, len(recs)),
|
|
}
|
|
for _, p := range recs {
|
|
title, sid := "", int64(0)
|
|
if lv := levelById[p.LevelId]; lv != nil {
|
|
title, sid = lv.Title, lv.StrategyId
|
|
}
|
|
detail.Progress = append(detail.Progress, &dto.AdminProgressItem{
|
|
LevelId: p.LevelId, LevelTitle: title,
|
|
StrategyId: sid, StrategyName: strategyNames[sid],
|
|
Stars: p.Stars, Perfect: p.Perfect == 1,
|
|
ContentVersion: p.ContentVersion, CompletedAt: timeString(p.CompletedAt),
|
|
})
|
|
}
|
|
return detail, nil
|
|
}
|