GoalMetric
This commit is contained in:
@@ -33,12 +33,15 @@ public class ActivitySummary extends AbstractActivity implements ReadonlyEntity
|
||||
@Transient
|
||||
private @Nullable Map<String, String> valuesForSummary;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
public ActivitySummary() {
|
||||
// hibernate
|
||||
}
|
||||
|
||||
@PostLoad
|
||||
void populateValuesForSummary() {
|
||||
final Map<String, String> map = new HashMap<>();
|
||||
if (distanceM != null) {
|
||||
map.put("distanceM", String.valueOf(distanceM));
|
||||
}
|
||||
map.put("distanceM", String.valueOf(distanceM));
|
||||
if (trainingLoad != null) {
|
||||
map.put("trainingLoad", String.valueOf(trainingLoad));
|
||||
}
|
||||
@@ -50,9 +53,4 @@ public class ActivitySummary extends AbstractActivity implements ReadonlyEntity
|
||||
}
|
||||
valuesForSummary = map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
public ActivitySummary() {
|
||||
// hibernate
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,15 +62,14 @@ public class DashboardService {
|
||||
final Map<Long, List<ActivityStreamPoint>> weekActivityStreams =
|
||||
resolveWeekActivityStreams(activitySummaries, selectedWeekMonday);
|
||||
|
||||
final LocalDate weekMonday = selectedWeekMonday;
|
||||
final int calendarYear = weekMonday.getYear();
|
||||
final int calendarMonth = weekMonday.getMonthValue();
|
||||
final int calendarYear = selectedWeekMonday.getYear();
|
||||
final int calendarMonth = selectedWeekMonday.getMonthValue();
|
||||
final List<GoalMetricTotals> metricTotals = java.util.Arrays.stream(GoalMetricEnum.values())
|
||||
.map(metric -> new GoalMetricTotals(
|
||||
metric,
|
||||
goalMetricPeriodTotalService.getWeeklyTotal(athleteId, metric, year, calendarWeek),
|
||||
goalMetricPeriodTotalService.getMonthlyTotal(athleteId, metric, calendarYear, calendarMonth),
|
||||
goalMetricPeriodTotalService.getYearlyTotal(athleteId, metric, calendarYear)
|
||||
goalMetricPeriodTotalService.getMonthlyTotalForWeek(athleteId, metric, year, calendarWeek, calendarYear, calendarMonth),
|
||||
goalMetricPeriodTotalService.getYearlyTotalForWeek(athleteId, metric, year, calendarWeek, calendarYear)
|
||||
))
|
||||
.toList();
|
||||
|
||||
|
||||
@@ -63,6 +63,48 @@ public class GoalMetricPeriodTotalDAO extends AbstractDAO<GoalMetricPeriodTotal>
|
||||
return result != null ? result : 0.0;
|
||||
}
|
||||
|
||||
public double sumByWeekAndMonth(
|
||||
final long athleteId,
|
||||
final GoalMetricEnum metric,
|
||||
final int isoWeekYear,
|
||||
final int calendarWeek,
|
||||
final int year,
|
||||
final int month) {
|
||||
final CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
final CriteriaQuery<Double> cq = cb.createQuery(Double.class);
|
||||
final Root<GoalMetricPeriodTotal> root = cq.from(GoalMetricPeriodTotal.class);
|
||||
cq.select(cb.sum(root.get(GoalMetricPeriodTotal_.aggregatedValue))).where(
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.athleteId), athleteId),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.metric), metric),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.isoWeekYear), isoWeekYear),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.calendarWeek), calendarWeek),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.year), year),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.month), month)
|
||||
);
|
||||
final Double result = em.createQuery(cq).getSingleResult();
|
||||
return result != null ? result : 0.0;
|
||||
}
|
||||
|
||||
public double sumByWeekAndYear(
|
||||
final long athleteId,
|
||||
final GoalMetricEnum metric,
|
||||
final int isoWeekYear,
|
||||
final int calendarWeek,
|
||||
final int year) {
|
||||
final CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
final CriteriaQuery<Double> cq = cb.createQuery(Double.class);
|
||||
final Root<GoalMetricPeriodTotal> root = cq.from(GoalMetricPeriodTotal.class);
|
||||
cq.select(cb.sum(root.get(GoalMetricPeriodTotal_.aggregatedValue))).where(
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.athleteId), athleteId),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.metric), metric),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.isoWeekYear), isoWeekYear),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.calendarWeek), calendarWeek),
|
||||
cb.equal(root.get(GoalMetricPeriodTotal_.year), year)
|
||||
);
|
||||
final Double result = em.createQuery(cq).getSingleResult();
|
||||
return result != null ? result : 0.0;
|
||||
}
|
||||
|
||||
public double sumByMonth(final long athleteId, final GoalMetricEnum metric, final int year, final int month) {
|
||||
final CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
final CriteriaQuery<Double> cq = cb.createQuery(Double.class);
|
||||
|
||||
@@ -34,7 +34,6 @@ public class GoalMetricPeriodTotalService extends AbstractService<GoalMetricPeri
|
||||
return goalMetricPeriodTotalDAO;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void recalculateIncremental(final long athleteId) {
|
||||
for (final GoalMetricEnum metric : GoalMetricEnum.values()) {
|
||||
recalculateMetricIncremental(athleteId, metric);
|
||||
@@ -53,29 +52,34 @@ public class GoalMetricPeriodTotalService extends AbstractService<GoalMetricPeri
|
||||
}
|
||||
|
||||
for (final IntervalsActivity activity : activities) {
|
||||
final LocalDate date = activity.getStartTime().atZone(ZoneOffset.UTC).toLocalDate();
|
||||
final int year = date.getYear();
|
||||
final int month = date.getMonthValue();
|
||||
final int calendarWeek = date.get(WeekFields.ISO.weekOfWeekBasedYear());
|
||||
final int isoWeekYear = date.get(WeekFields.ISO.weekBasedYear());
|
||||
final double value = intervalsActivityService.extractMetricValue(activity, metric);
|
||||
recalculateMetric4Activity(athleteId, metric, activity);
|
||||
}
|
||||
}
|
||||
|
||||
final GoalMetricPeriodTotal existing = goalMetricPeriodTotalDAO.findByKey(athleteId, metric, year, month, calendarWeek);
|
||||
if (existing != null) {
|
||||
existing.setAggregatedValue(existing.getAggregatedValue() + value);
|
||||
existing.setLastActivityId(activity.getId());
|
||||
} else {
|
||||
final GoalMetricPeriodTotal row = new GoalMetricPeriodTotal();
|
||||
row.setAthleteId(athleteId);
|
||||
row.setMetric(metric);
|
||||
row.setYear(year);
|
||||
row.setMonth(month);
|
||||
row.setCalendarWeek(calendarWeek);
|
||||
row.setIsoWeekYear(isoWeekYear);
|
||||
row.setAggregatedValue(value);
|
||||
row.setLastActivityId(activity.getId());
|
||||
insert(row);
|
||||
}
|
||||
@Transactional
|
||||
public void recalculateMetric4Activity(final long athleteId, final GoalMetricEnum metric, final IntervalsActivity activity) {
|
||||
final LocalDate date = activity.getStartTime().atZone(ZoneOffset.UTC).toLocalDate();
|
||||
final int year = date.getYear();
|
||||
final int month = date.getMonthValue();
|
||||
final int calendarWeek = date.get(WeekFields.ISO.weekOfWeekBasedYear());
|
||||
final int isoWeekYear = date.get(WeekFields.ISO.weekBasedYear());
|
||||
final double value = intervalsActivityService.extractMetricValue(activity, metric);
|
||||
|
||||
final GoalMetricPeriodTotal existing = goalMetricPeriodTotalDAO.findByKey(athleteId, metric, year, month, calendarWeek);
|
||||
if (existing != null) {
|
||||
existing.setAggregatedValue(existing.getAggregatedValue() + value);
|
||||
existing.setLastActivityId(activity.getId());
|
||||
} else {
|
||||
final GoalMetricPeriodTotal row = new GoalMetricPeriodTotal();
|
||||
row.setAthleteId(athleteId);
|
||||
row.setMetric(metric);
|
||||
row.setYear(year);
|
||||
row.setMonth(month);
|
||||
row.setCalendarWeek(calendarWeek);
|
||||
row.setIsoWeekYear(isoWeekYear);
|
||||
row.setAggregatedValue(value);
|
||||
row.setLastActivityId(activity.getId());
|
||||
insert(row);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +88,27 @@ public class GoalMetricPeriodTotalService extends AbstractService<GoalMetricPeri
|
||||
return goalMetricPeriodTotalDAO.sumByWeek(athleteId, metric, isoWeekYear, calendarWeek);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public double getMonthlyTotalForWeek(
|
||||
final long athleteId,
|
||||
final GoalMetricEnum metric,
|
||||
final int isoWeekYear,
|
||||
final int calendarWeek,
|
||||
final int year,
|
||||
final int month) {
|
||||
return goalMetricPeriodTotalDAO.sumByWeekAndMonth(athleteId, metric, isoWeekYear, calendarWeek, year, month);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public double getYearlyTotalForWeek(
|
||||
final long athleteId,
|
||||
final GoalMetricEnum metric,
|
||||
final int isoWeekYear,
|
||||
final int calendarWeek,
|
||||
final int year) {
|
||||
return goalMetricPeriodTotalDAO.sumByWeekAndYear(athleteId, metric, isoWeekYear, calendarWeek, year);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public double getMonthlyTotal(final long athleteId, final GoalMetricEnum metric, final int year, final int month) {
|
||||
return goalMetricPeriodTotalDAO.sumByMonth(athleteId, metric, year, month);
|
||||
|
||||
@@ -18,7 +18,7 @@ import {useDashboardGetDashboard} from '@/api/hooks'
|
||||
import type {ActivitySummaryDo} from '@/types/ActivitySummaryDo'
|
||||
import type {GoalDo} from '@/types/GoalDo'
|
||||
import type {GoalMetricEnum} from '@/types/GoalMetricEnum'
|
||||
import type {GoalMetricPeriodTotalDo} from '@/types/GoalMetricPeriodTotalDo'
|
||||
import type {GoalMetricTotalsDo} from '@/types/GoalMetricTotalsDo'
|
||||
import type {GoalPeriodEnum} from '@/types/GoalPeriodEnum'
|
||||
import {formatDistance, formatDuration, sportIcon, summaryNum} from '@/utils/activity'
|
||||
import {ActivityOverviewCard} from '@/components/dashboard/ActivityOverviewCard'
|
||||
@@ -70,17 +70,13 @@ function formatGoalValue(metric: Metric, value: number): string {
|
||||
type Actuals = Record<Metric, number>
|
||||
|
||||
function buildActualsFromTotals(
|
||||
totals: GoalMetricPeriodTotalDo[],
|
||||
totals: GoalMetricTotalsDo[],
|
||||
period: GoalPeriodEnum,
|
||||
year: number,
|
||||
calendarWeek: number,
|
||||
): Actuals {
|
||||
const relevant = totals.filter(
|
||||
(t) => t.period === period && t.year === year && t.calendarWeek === calendarWeek,
|
||||
)
|
||||
const result: Actuals = {DISTANCE: 0, TSS: 0, ELEVATION: 0, TIME: 0}
|
||||
for (const t of relevant) {
|
||||
result[t.metric] = t.metric === 'DISTANCE' ? t.aggregatedValue / 1000 : t.aggregatedValue
|
||||
for (const t of totals) {
|
||||
const raw = period === 'WEEKLY' ? t.weeklyTotal : period === 'MONTHLY' ? t.monthlyTotal : t.yearlyTotal
|
||||
result[t.metric] = t.metric === 'DISTANCE' ? raw / 1000 : raw
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -428,7 +424,7 @@ export function Dashboard({athleteId}: { athleteId: number }) {
|
||||
const {data: dashboardData, isLoading} = useDashboardGetDashboard(athleteId, week, year)
|
||||
const activities = dashboardData?.activities ?? []
|
||||
const goals = dashboardData?.goals ?? []
|
||||
const goalMetricPeriodTotals = dashboardData?.goalMetricPeriodTotals ?? []
|
||||
const goalMetricTotals = dashboardData?.goalMetricTotals ?? []
|
||||
const weekActivityMapStreams = dashboardData?.weekActivityMapStreams ?? {}
|
||||
const weekActivityStreams = dashboardData?.weekActivityStreams ?? {}
|
||||
|
||||
@@ -446,9 +442,9 @@ export function Dashboard({athleteId}: { athleteId: number }) {
|
||||
const wEnd = endOfISOWeek(wStart)
|
||||
const weekDays = eachDayOfInterval({start: wStart, end: wEnd})
|
||||
|
||||
const weekActuals = buildActualsFromTotals(goalMetricPeriodTotals, 'WEEKLY', year, week)
|
||||
const monthActuals = buildActualsFromTotals(goalMetricPeriodTotals, 'MONTHLY', year, week)
|
||||
const yearActuals = buildActualsFromTotals(goalMetricPeriodTotals, 'YEARLY', year, week)
|
||||
const weekActuals = buildActualsFromTotals(goalMetricTotals, 'WEEKLY')
|
||||
const monthActuals = buildActualsFromTotals(goalMetricTotals, 'MONTHLY')
|
||||
const yearActuals = buildActualsFromTotals(goalMetricTotals, 'YEARLY')
|
||||
|
||||
const weeklyGoals = goals.filter((g) => g.period === 'WEEKLY')
|
||||
const monthlyGoals = goals.filter((g) => g.period === 'MONTHLY')
|
||||
|
||||
Reference in New Issue
Block a user