|
|
@@ -59,14 +59,14 @@ function getDefaultRange(type: number): [Dayjs, Dayjs] {
|
|
|
case 2: // 月报:过去 6 个月
|
|
|
return [today.subtract(5, "month").startOf("month"), today];
|
|
|
default: // 周报:过去 8 周
|
|
|
- return [today.subtract(7, "week").startOf("week"), today];
|
|
|
+ return [today.subtract(7, "week").startOf("isoWeek"), today];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Generates all period IDs covered by [start, end] for the given report type.
|
|
|
* - type 0 (daily): "YYYY-MM-DD"
|
|
|
- * - type 1 (weekly): "gggg-[W]ww"
|
|
|
+ * - type 1 (weekly): "GGGG-[W]WW" (ISO week year – ISO week number)
|
|
|
* - type 2 (monthly): "YYYY-MM"
|
|
|
*/
|
|
|
function generatePeriodIds(start: Dayjs, end: Dayjs, type: number): string[] {
|
|
|
@@ -78,10 +78,10 @@ function generatePeriodIds(start: Dayjs, end: Dayjs, type: number): string[] {
|
|
|
cur = cur.add(1, "day");
|
|
|
}
|
|
|
} else if (type === 1) {
|
|
|
- let cur = start.startOf("week");
|
|
|
+ let cur = start.startOf("isoWeek");
|
|
|
while (!cur.isAfter(end)) {
|
|
|
- const week = cur.week();
|
|
|
- const year = cur.weekYear();
|
|
|
+ const week = cur.isoWeek();
|
|
|
+ const year = cur.isoWeekYear();
|
|
|
ids.push(`${year}-W${String(week).padStart(2, "0")}`);
|
|
|
cur = cur.add(1, "week");
|
|
|
}
|
|
|
@@ -163,20 +163,23 @@ function fillPlaymateData(
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Given a natural-week ID like "2026-W10", returns the Sun–Sat date range string.
|
|
|
+ * Given an ISO-week ID like "2026-W10", returns the Mon–Sun date range string.
|
|
|
* Returns null for non-week IDs.
|
|
|
+ *
|
|
|
+ * ISO 8601: week 1 is the week containing the first Thursday of the year;
|
|
|
+ * Jan 4 always falls in ISO week 1, so startOf("isoWeek") on Jan 4 reliably
|
|
|
+ * gives the Monday of week 1.
|
|
|
*/
|
|
|
function getWeekDateRange(id: string): string | null {
|
|
|
const match = id.match(/^(\d{4})-W(\d{2})$/);
|
|
|
if (!match) return null;
|
|
|
const year = Number(match[1]);
|
|
|
const week = Number(match[2]);
|
|
|
- // Natural week: week 1 starts on the Sunday of the week containing Jan 1
|
|
|
- const sunday = dayjs(`${year}-01-01`)
|
|
|
- .startOf("week")
|
|
|
+ const monday = dayjs(`${year}-01-04`)
|
|
|
+ .startOf("isoWeek")
|
|
|
.add((week - 1) * 7, "day");
|
|
|
- const saturday = sunday.add(6, "day");
|
|
|
- return `${sunday.format("YYYY-MM-DD")} ~ ${saturday.format("YYYY-MM-DD")}`;
|
|
|
+ const sunday = monday.add(6, "day");
|
|
|
+ return `${monday.format("YYYY-MM-DD")} ~ ${sunday.format("YYYY-MM-DD")}`;
|
|
|
}
|
|
|
|
|
|
function renderPeriodId(id: string, showRaw: boolean): React.ReactNode {
|
|
|
@@ -229,9 +232,9 @@ const StatsDashboardPage: React.FC = () => {
|
|
|
let startDay = range[0];
|
|
|
let endDay = range[1];
|
|
|
if (reportType === 1) {
|
|
|
- // Natural week: Sunday (day=0) ~ Saturday (day=6)
|
|
|
- startDay = range[0].day(0);
|
|
|
- endDay = range[1].day(6);
|
|
|
+ // ISO week: Monday ~ Sunday
|
|
|
+ startDay = range[0].startOf("isoWeek");
|
|
|
+ endDay = range[1].startOf("isoWeek").add(6, "day");
|
|
|
} else if (reportType === 2) {
|
|
|
startDay = range[0].startOf("month");
|
|
|
endDay = range[1].endOf("month");
|
|
|
@@ -724,7 +727,7 @@ const StatsDashboardPage: React.FC = () => {
|
|
|
reportType === 0
|
|
|
? "YYYY-MM-DD"
|
|
|
: reportType === 1
|
|
|
- ? "gggg-[W]ww"
|
|
|
+ ? "GGGG-[W]WW"
|
|
|
: "YYYY-MM"
|
|
|
}
|
|
|
/>
|