feat: graph-log-villages support dateFrom/dateTo + recent-village-logs endpoint

This commit is contained in:
2026-05-25 15:08:30 +08:00
parent 6cf6486172
commit 22555079f3

View File

@@ -633,7 +633,7 @@ const MonitoringServer = new Elysia({ prefix: "/api/monitoring" })
}
)
.get("/graph-log-villages", async ({ query, set }) => {
const { id, time } = query;
const { id, time, dateFrom, dateTo } = query;
try {
const village = await prisma.village.findUnique({
@@ -651,14 +651,20 @@ const MonitoringServer = new Elysia({ prefix: "/api/monitoring" })
const now = new Date();
let startDate: Date;
let endDate: Date = now;
const useCustomRange = !!(dateFrom && dateTo);
if (time === "daily") {
if (useCustomRange) {
startDate = new Date(dateFrom);
endDate = new Date(dateTo);
endDate.setHours(23, 59, 59, 999);
} else if (time === "daily") {
startDate = new Date();
startDate.setDate(now.getDate() - 13); // 14 hari
} else if (time === "monthly") {
startDate = new Date(now.getFullYear(), 0, 1); // awal tahun
} else if (time === "yearly") {
startDate = new Date(now.getFullYear() - 4, 0, 1); // 5 tahun terakhir (opsional)
startDate = new Date(now.getFullYear() - 4, 0, 1); // 5 tahun terakhir
} else {
startDate = new Date(0);
}
@@ -667,6 +673,7 @@ const MonitoringServer = new Elysia({ prefix: "/api/monitoring" })
where: {
createdAt: {
gte: startDate,
...(useCustomRange ? { lte: endDate } : {}),
},
User: {
idVillage: id,
@@ -682,21 +689,27 @@ const MonitoringServer = new Elysia({ prefix: "/api/monitoring" })
// =========================
const map: Record<string, number> = {};
// Tentukan format label berdasarkan range
const effectiveTime = useCustomRange ? (
// > 60 hari pakai monthly, selain itu daily
(endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24) > 60 ? 'monthly' : 'daily'
) : time;
dataLog.forEach((log) => {
const date = new Date(log.createdAt);
let label = "";
if (time === "daily") {
if (effectiveTime === "daily") {
label = date.toLocaleDateString("id-ID", {
day: "2-digit",
month: "short",
});
} else if (time === "monthly") {
} else if (effectiveTime === "monthly") {
label = date.toLocaleDateString("id-ID", {
month: "short",
year: "numeric",
});
} else if (time === "yearly") {
} else if (effectiveTime === "yearly") {
label = date.getFullYear().toString();
}
@@ -708,9 +721,13 @@ const MonitoringServer = new Elysia({ prefix: "/api/monitoring" })
// =========================
let result: any[] = [];
if (time === "daily") {
for (let i = 13; i >= 0; i--) {
const d = new Date();
if (effectiveTime === "daily") {
const days = useCustomRange
? Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24))
: 14;
for (let i = days - 1; i >= 0; i--) {
const d = new Date(endDate);
d.setDate(d.getDate() - i);
const label = d.toLocaleDateString("id-ID", {
@@ -723,41 +740,38 @@ const MonitoringServer = new Elysia({ prefix: "/api/monitoring" })
aktivitas: map[label] || 0,
});
}
} else if (time === "monthly") {
const year = now.getFullYear();
for (let m = 0; m <= 11; m++) {
const d = new Date(year, m, 1);
} else if (effectiveTime === "monthly") {
const s = new Date(startDate);
const e = new Date(endDate);
const months: string[] = [];
const label = d.toLocaleDateString("id-ID", {
const cursor = new Date(s.getFullYear(), s.getMonth(), 1);
while (cursor <= e) {
months.push(cursor.toLocaleDateString("id-ID", {
month: "short",
});
result.push({
label,
aktivitas: map[label] || 0,
});
year: "numeric",
}));
cursor.setMonth(cursor.getMonth() + 1);
}
} else if (time === "yearly") {
result = months.map((label) => ({
label,
aktivitas: map[label] || 0,
}));
} else if (effectiveTime === "yearly") {
const years = Object.keys(map).map(Number);
if (years.length === 0) {
const currentYear = new Date().getFullYear();
result = [
{ label: currentYear.toString(), aktivitas: 0 }
];
result = [{ label: currentYear.toString(), aktivitas: 0 }];
} else {
const minYear = Math.min(...years);
const maxYear = Math.max(...years);
result = [];
for (let y = minYear; y <= maxYear; y++) {
const label = y.toString();
result.push({
label,
aktivitas: map[label] || 0,
label: y.toString(),
aktivitas: map[y.toString()] || 0,
});
}
}
@@ -781,21 +795,81 @@ const MonitoringServer = new Elysia({ prefix: "/api/monitoring" })
{
query: t.Object({
id: t.String({ description: "ID desa" }),
time: t.Enum(
{
daily: "daily",
monthly: "monthly",
yearly: "yearly",
},
{
description: "Rentang waktu (daily = 14 hari, monthly = 1 tahun, yearly = per tahun)",
}
),
time: t.Optional(t.Enum(
{ daily: "daily", monthly: "monthly", yearly: "yearly" },
{ description: "Rentang waktu (daily = 14 hari, monthly = 1 tahun, yearly = per tahun). Default: daily" },
)),
dateFrom: t.Optional(t.String({ description: "Filter dari tanggal (YYYY-MM-DD). Mengabaikan time jika diisi bersama dateTo." })),
dateTo: t.Optional(t.String({ description: "Filter sampai tanggal (YYYY-MM-DD). Mengabaikan time jika diisi bersama dateFrom." })),
}),
detail: {
summary: "Graph Log Villages",
description:
"Mendapatkan data grafik log aktivitas desa berdasarkan rentang waktu (harian, bulanan, tahunan)",
"Mendapatkan data grafik log aktivitas desa berdasarkan rentang waktu (harian, bulanan, tahunan) atau custom date range.",
tags: ["detail-villages"],
},
}
)
.get("/recent-village-logs", async ({ query, set }) => {
const { id } = query;
try {
const village = await prisma.village.findUnique({
where: { id },
});
if (!village) {
set.status = 404;
return {
success: false,
message: "Desa tidak ditemukan",
data: null,
};
}
const logs = await prisma.userLog.findMany({
where: {
User: { idVillage: id },
},
select: {
createdAt: true,
action: true,
desc: true,
User: { select: { name: true } },
},
orderBy: { createdAt: 'desc' },
take: 10,
});
const result = logs.map((log) => ({
timestamp: log.createdAt,
userName: log.User.name,
action: log.action,
desc: log.desc,
}));
return {
success: true,
message: "Berhasil mendapatkan data",
data: result,
};
} catch (error) {
console.error("[recent-village-logs] error:", error);
set.status = 500;
return {
success: false,
message: "Terjadi kesalahan pada server",
data: null,
};
}
},
{
query: t.Object({
id: t.String({ description: "ID desa" }),
}),
detail: {
summary: "Recent Village Logs",
description: "Mendapatkan 10 log aktivitas terbaru di desa tertentu.",
tags: ["detail-villages"],
},
}