135 lines
3.3 KiB
Go
135 lines
3.3 KiB
Go
package web
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"daili/internal/domain"
|
|
"daili/internal/store"
|
|
)
|
|
|
|
type screenDay struct {
|
|
Date string
|
|
Day int
|
|
InMonth bool
|
|
IsToday bool
|
|
IsPast bool
|
|
Due int
|
|
Heat int
|
|
}
|
|
|
|
type screenData struct {
|
|
Stats *store.Stats
|
|
MonthTitle string
|
|
Year, Month int
|
|
Weeks [][]screenDay
|
|
Weekdays []string
|
|
Top []SubView
|
|
DueToday []SubView
|
|
TodayList []SubView
|
|
Recent []store.Adjustment
|
|
TodayTasks int
|
|
TodayDone int
|
|
Refresh int
|
|
Version string
|
|
}
|
|
|
|
func (s *Server) handleScreen(w http.ResponseWriter, r *http.Request) {
|
|
today := domain.Today()
|
|
warn := s.warnDays()
|
|
stats, err := s.db.ScreenStats(today, warn)
|
|
if err != nil {
|
|
http.Error(w, "读取大屏数据失败", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
data := &screenData{
|
|
Stats: stats,
|
|
MonthTitle: fmt.Sprintf("%d 年 %d 月", today.Year(), int(today.Month())),
|
|
Year: today.Year(),
|
|
Month: int(today.Month()),
|
|
Weekdays: []string{"一", "二", "三", "四", "五", "六", "日"},
|
|
Top: subViews(stats.Top, today, warn),
|
|
DueToday: subViews(stats.DueTodaySubs, today, warn),
|
|
Refresh: s.screenRefresh(),
|
|
Version: s.cfg.Version,
|
|
}
|
|
if len(data.DueToday) > 6 {
|
|
data.DueToday = data.DueToday[:6]
|
|
}
|
|
|
|
// 本月热力
|
|
monthStart := domain.MonthStart(today.Year(), today.Month())
|
|
monthEnd := domain.MonthEnd(today.Year(), today.Month())
|
|
gridStart := domain.AddDays(monthStart, -domain.WeekdayIndex(monthStart))
|
|
weeks := (domain.WeekdayIndex(monthStart) + monthEnd.Day() + 6) / 7
|
|
for wi := 0; wi < weeks; wi++ {
|
|
week := make([]screenDay, 0, 7)
|
|
for di := 0; di < 7; di++ {
|
|
d := domain.AddDays(gridStart, wi*7+di)
|
|
ds := domain.Date(d)
|
|
due := stats.Heat[ds]
|
|
week = append(week, screenDay{
|
|
Date: ds,
|
|
Day: d.Day(),
|
|
InMonth: d.Month() == today.Month(),
|
|
IsToday: ds == domain.Date(today),
|
|
IsPast: d.Before(today),
|
|
Due: due,
|
|
Heat: heatLevel(due),
|
|
})
|
|
}
|
|
data.Weeks = append(data.Weeks, week)
|
|
}
|
|
|
|
if adj, err := s.db.RecentAdjustments(6); err == nil {
|
|
data.Recent = adj
|
|
}
|
|
list, done := s.todayTaskList(today)
|
|
data.TodayTasks = len(list)
|
|
data.TodayDone = done
|
|
data.TodayList = subViews(list, today, warn)
|
|
|
|
p := s.newPage(r, "大屏", "screen")
|
|
p.D = data
|
|
s.render(w, r, "screen", p)
|
|
}
|
|
|
|
// todayTaskList 返回今天应服务的订阅与已完成数量。
|
|
func (s *Server) todayTaskList(today time.Time) ([]store.Subscription, int) {
|
|
ts := domain.Date(today)
|
|
subs, err := s.db.CalendarSubs(ts, ts)
|
|
if err != nil {
|
|
return nil, 0
|
|
}
|
|
ids := make([]int64, 0, len(subs))
|
|
for _, sub := range subs {
|
|
ids = append(ids, sub.ID)
|
|
}
|
|
pauses, _ := s.db.PausesForSubs(ids)
|
|
checkins, _ := s.db.CheckinsBetween(ts, ts)
|
|
warn := s.warnDays()
|
|
out := []store.Subscription{}
|
|
done := 0
|
|
for _, sub := range subs {
|
|
if sub.Status == domain.StatusClosed {
|
|
continue
|
|
}
|
|
if sub.StartDate > ts || sub.EndDate == "" || sub.EndDate < ts {
|
|
continue
|
|
}
|
|
cs := calSub{sub: sub, pauses: pauses[sub.ID], hasEnd: true, eval: sub.Eval(today, warn)}
|
|
if sub.Unit == domain.UnitCount && cs.eval.RemainingCount <= 0 {
|
|
continue
|
|
}
|
|
if cs.pausedOn(ts) {
|
|
continue
|
|
}
|
|
out = append(out, sub)
|
|
if ci, ok := checkins[sub.ID][ts]; ok && ci.Status == "done" {
|
|
done++
|
|
}
|
|
}
|
|
return out, done
|
|
}
|