spark-server/internal/module/energy/logic/calendar.go
DESKTOP-L8OUL9F\gfl0034 753c276496 feat: PopAdmin 拉取管理、签到能量 API 与图片 150KiB 硬上限
管理端按用户查询开启通讯录/相册/媒体拉取;服务端写入路径自动压图;新增 /v1/sign 与 /v1/energy。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-02 12:44:06 +08:00

147 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package logic
import (
"context"
"time"
"spark-server/internal/module/energy/entity"
"spark-server/internal/pkg/errs"
)
// DayStatus is one calendar cell for the sign-in page.
type DayStatus struct {
Day int64 `json:"day"`
SignInStatus string `json:"sign_in_status"`
RewardPoint int `json:"reward_point"`
IsDouble bool `json:"is_double"`
IsSurprise bool `json:"is_surprise"`
VideoDouble bool `json:"video_double"`
}
// CalendarView matches the legacy SignInBean shape used by the Android page.
type CalendarView struct {
ContinueDays int `json:"continue_days"`
StartDate int64 `json:"start_date"`
NeedDays int `json:"need_days"`
RewardPoint int `json:"reward_point"`
TodaySignStatus string `json:"today_sign_status"`
TotalRewardPoint int64 `json:"total_reward_point"`
DrawPrizeStatus int `json:"draw_prize_status"`
Energy int64 `json:"energy"`
StatusList []DayStatus `json:"status_list"`
}
// Calendar returns month status for year/month (1–12). year=0 uses current year.
func (s *Service) Calendar(ctx context.Context, userID int64, year, month int) (*CalendarView, error) {
if !s.ready() || userID <= 0 {
return nil, errs.ErrUnauthorized
}
now := s.now()
if year <= 0 {
year = now.Year()
}
if month < 1 || month > 12 {
month = int(now.Month())
}
first := time.Date(year, time.Month(month), 1, 0, 0, 0, 0, s.loc)
last := first.AddDate(0, 1, -1)
fromDay, toDay := dayKeyOf(first), dayKeyOf(last)
today := dayKeyOf(now)
records, err := s.repo.ListSignsInRange(ctx, userID, fromDay, toDay)
if err != nil {
return nil, err
}
byDay := map[int]*entity.SignRecord{}
for _, r := range records {
byDay[r.DayKey] = r
}
streak, start := s.computeStreak(ctx, userID, today)
need := entity.DefaultNeedDays - (streak % entity.DefaultNeedDays)
if need == entity.DefaultNeedDays && streak > 0 && streak%entity.DefaultNeedDays == 0 {
need = entity.DefaultNeedDays
}
if streak == 0 {
need = entity.DefaultNeedDays
}
nextReward := entity.CycleRewards(streak + 1)
wallet, err := s.repo.EnsureWallet(ctx, userID)
if err != nil {
return nil, err
}
list := make([]DayStatus, 0, last.Day())
todayStatus := entity.StatusUnsigned
for d := 1; d <= last.Day(); d++ {
day := year*10000 + month*100 + d
st := DayStatus{
Day: int64(day),
RewardPoint: entity.CycleRewards(1),
}
if rec, ok := byDay[day]; ok {
if rec.Kind == entity.KindMakeup {
st.SignInStatus = entity.StatusMakeupDone
} else {
st.SignInStatus = entity.StatusSigned
}
st.RewardPoint = rec.Reward
} else if day == today {
st.SignInStatus = entity.StatusUnsigned
st.RewardPoint = nextReward
} else if day < today {
st.SignInStatus = entity.StatusCanMakeup
st.RewardPoint = entity.CycleRewards(1)
} else {
// Future days: not yet signed (client treats as empty slot).
st.SignInStatus = entity.StatusUnsigned
st.RewardPoint = entity.CycleRewards(1)
}
if day == today {
todayStatus = st.SignInStatus
if todayStatus == entity.StatusUnsigned {
st.RewardPoint = nextReward
}
}
list = append(list, st)
}
return &CalendarView{
ContinueDays: streak,
StartDate: int64(start),
NeedDays: need,
RewardPoint: nextReward,
TodaySignStatus: todayStatus,
TotalRewardPoint: wallet.Energy,
DrawPrizeStatus: 0,
Energy: wallet.Energy,
StatusList: list,
}, nil
}
func (s *Service) computeStreak(ctx context.Context, userID int64, today int) (streak int, start int) {
recent, err := s.repo.ListRecentSigns(ctx, userID, 60)
if err != nil || len(recent) == 0 {
return 0, 0
}
have := map[int]bool{}
for _, r := range recent {
have[r.DayKey] = true
}
cursor := today
if !have[today] {
cursor = addDays(today, -1)
}
if !have[cursor] {
return 0, 0
}
start = cursor
for have[cursor] {
streak++
start = cursor
cursor = addDays(cursor, -1)
}
return streak, start
}