upd: api monitoring #29
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Village" ADD COLUMN "isDummy" BOOLEAN NOT NULL DEFAULT false;
|
||||
@@ -51,6 +51,7 @@ model Village {
|
||||
name String
|
||||
desc String @db.Text
|
||||
isActive Boolean @default(true)
|
||||
isDummy Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
Group Group[]
|
||||
|
||||
233
src/app/api/monitoring/[[...slug]]/route.ts
Normal file
233
src/app/api/monitoring/[[...slug]]/route.ts
Normal file
@@ -0,0 +1,233 @@
|
||||
import { prisma } from "@/module/_global";
|
||||
import cors from "@elysiajs/cors";
|
||||
import { swagger } from "@elysiajs/swagger";
|
||||
import Elysia from "elysia";
|
||||
import _ from "lodash";
|
||||
import moment from "moment";
|
||||
import "moment/locale/id";
|
||||
|
||||
// Gabungkan semua ke dalam satu instance server yang dipasang di /api/monitoring
|
||||
const MonitoringServer = new Elysia({ prefix: "/api/monitoring" })
|
||||
.use(cors({
|
||||
origin: "*",
|
||||
methods: ["GET", "POST", "OPTIONS"],
|
||||
}))
|
||||
.use(swagger({
|
||||
path: "/docs", // Karena prefix instance adalah /api/monitoring, maka ini akan diakses di /api/monitoring/docs
|
||||
documentation: {
|
||||
info: {
|
||||
title: "Des Plus - Monitoring API",
|
||||
version: "1.0.0",
|
||||
description: "API Khusus untuk kebutuhan Dashboard Monitoring",
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
.get(
|
||||
"/grid-overview",
|
||||
async ({ query, set }) => {
|
||||
try {
|
||||
const version = await prisma.setting.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
value: true
|
||||
}
|
||||
});
|
||||
|
||||
const result_version = Object.fromEntries(version.map(item => [item.id, item.value]));
|
||||
|
||||
const activity_today = await prisma.userLog.count({
|
||||
where: {
|
||||
createdAt: {
|
||||
gte: moment().subtract(1, 'days').toDate(),
|
||||
lte: moment().toDate(),
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const activity_yesterday = await prisma.userLog.count({
|
||||
where: {
|
||||
createdAt: {
|
||||
gte: moment().subtract(2, 'days').toDate(),
|
||||
lte: moment().subtract(1, 'days').toDate(),
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const activity_increase = (activity_today - activity_yesterday);
|
||||
const percentage_increase = (activity_increase / activity_yesterday) * 100
|
||||
|
||||
const total_village = await prisma.village.findMany({
|
||||
where: {
|
||||
isDummy: false
|
||||
}
|
||||
})
|
||||
|
||||
const total_village_active = total_village.filter((item) => item.isActive).length
|
||||
const total_village_inactive = total_village.filter((item) => !item.isActive).length
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Berhasil mendapatkan data",
|
||||
data: {
|
||||
version: result_version,
|
||||
activity: {
|
||||
today: activity_today,
|
||||
increase: _.isNaN(percentage_increase) ? 0 : percentage_increase.toFixed(2),
|
||||
},
|
||||
village: {
|
||||
active: total_village_active,
|
||||
inactive: total_village_inactive,
|
||||
},
|
||||
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("[overview] grid-overview error:", error);
|
||||
set.status = 500;
|
||||
return {
|
||||
success: false,
|
||||
message: "Terjadi kesalahan pada server",
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
summary: "Grid Overview",
|
||||
description: "Menu Overview - Mendapatkan daftar versi aplikasi.",
|
||||
tags: ["overview"],
|
||||
},
|
||||
}
|
||||
)
|
||||
.get(
|
||||
"/daily-activity",
|
||||
async ({ query, set }) => {
|
||||
try {
|
||||
// const data = await prisma.userLog.findMany({
|
||||
// where: {
|
||||
// User: {
|
||||
// Village: {
|
||||
// isDummy: false
|
||||
// }
|
||||
// },
|
||||
// createdAt: {
|
||||
// gte: moment().subtract(7, 'days').toDate(),
|
||||
// lte: moment().toDate(),
|
||||
// }
|
||||
// },
|
||||
// select: {
|
||||
// createdAt: true,
|
||||
// }
|
||||
// })
|
||||
|
||||
const data = await prisma.$queryRaw`
|
||||
SELECT
|
||||
DATE(ul."createdAt") AS tanggal,
|
||||
COUNT(*) AS total
|
||||
FROM "UserLog" ul
|
||||
JOIN "User" u ON ul."idUser" = u."id"
|
||||
JOIN "Village" v ON u."idVillage" = v."id"
|
||||
WHERE v."isDummy" = false
|
||||
AND ul."createdAt" >= NOW() - INTERVAL '7 days'
|
||||
GROUP BY tanggal
|
||||
ORDER BY tanggal;` as any[];
|
||||
|
||||
const result = [];
|
||||
|
||||
// ubah data ke map biar gampang lookup
|
||||
const map = data.reduce((acc: any, item: any) => {
|
||||
const key = moment(item.tanggal).format('YYYY-MM-DD');
|
||||
acc[key] = Number(item.total);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
// generate 7 hari terakhir
|
||||
for (let i = 6; i >= 0; i--) {
|
||||
const date = moment().subtract(i, 'days');
|
||||
|
||||
const key = date.format('YYYY-MM-DD');
|
||||
|
||||
result.push({
|
||||
date: date.format('DD MMM'),
|
||||
logs: map[key] || 0
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Berhasil mendapatkan data",
|
||||
data: result,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("[overview] daily-activity error:", error);
|
||||
set.status = 500;
|
||||
return {
|
||||
success: false,
|
||||
message: "Terjadi kesalahan pada server",
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
summary: "Daily Activity",
|
||||
description: "Menu Overview - Mendapatkan data grafik aktivitas harian semua desa.",
|
||||
tags: ["overview"],
|
||||
},
|
||||
}
|
||||
)
|
||||
.get(
|
||||
"/comparison-activity",
|
||||
async ({ query, set }) => {
|
||||
try {
|
||||
const data = await prisma.$queryRaw`
|
||||
SELECT
|
||||
v."name",
|
||||
COUNT(ul."id") AS total_logs
|
||||
FROM "UserLog" ul
|
||||
JOIN "User" u ON ul."idUser" = u."id"
|
||||
JOIN "Village" v ON u."idVillage" = v."id"
|
||||
WHERE v."isDummy" = false
|
||||
AND ul."createdAt" >= NOW() - INTERVAL '7 days'
|
||||
GROUP BY v."id", v."name"
|
||||
ORDER BY total_logs DESC;
|
||||
` as any[];
|
||||
|
||||
const result = data.map(item => ({
|
||||
village: item.name,
|
||||
activity: Number(item.total_logs)
|
||||
}));
|
||||
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Berhasil mendapatkan data",
|
||||
data: result,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("[overview] comparison-activity error:", error);
|
||||
set.status = 500;
|
||||
return {
|
||||
success: false,
|
||||
message: "Terjadi kesalahan pada server",
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
summary: "Comparison Activity",
|
||||
description: "Menu Overview - Mendapatkan data grafik perbandingan aktivitas desa selama 7 hari terakhir.",
|
||||
tags: ["overview"],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
;
|
||||
|
||||
|
||||
export const GET = MonitoringServer.handle;
|
||||
export const POST = MonitoringServer.handle;
|
||||
@@ -2,7 +2,7 @@ import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
return NextResponse.json({ success: true, version: "2.1.8", tahap: "beta", update: "-api untuk dashboard noc; -perbaikan otp" }, { status: 200 });
|
||||
return NextResponse.json({ success: true, version: "2.1.9", tahap: "beta", update: "-api untuk dashboard monitoring" }, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ success: false, version: "Gagal mendapatkan version, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 });
|
||||
|
||||
Reference in New Issue
Block a user