perf: reduce dashboard api call

This commit is contained in:
zaunist committed 2025-04-27 22:14:38 +08:00
1 parent 090ad2e51f
commit cd479cadcc
17 files changed
+160 -213

No files matched your search

+16
View File
@@ -0,0 +1,16 @@
import { Hono } from "hono";
import { Bindings } from "../models/db";
import { getDashboardData } from "../services/DashboardService";
export const dashboard = new Hono<{ Bindings: Bindings }>();
// 获取仪表盘数据
dashboard.get("/", async (c) => {
const result = await getDashboardData(c.env.DB);
return c.json(
{
monitors: result.monitors,
agents: result.agents,
},
200
);
});
+1 -1
View File
@@ -4,4 +4,4 @@ export * from "./agents";
export * from "./users";
export * from "./status";
export * from "./notifications";
export * from "./migrate";
export * from "./dashboard";
-23
View File
@@ -1,23 +0,0 @@
import { Hono } from "hono";
import { Bindings } from "../models/db";
import { runMigrations } from "../migrations/migration";
export const migrate = new Hono<{ Bindings: Bindings }>();
// 获取所有监控
migrate.get("/", async (c) => {
try {
// 调用服务层获取监控列表
const result = await runMigrations(c.env);
return c.json(
{
success: true,
message: "迁移成功",
result: result,
},
200
);
} catch (error) {
console.error("迁移失败:", error);
return c.json({ success: false, message: "迁移失败" }, 500);
}
});
+1 -1
View File
@@ -11,7 +11,7 @@ notifications.get("/", async (c) => {
const db = c.env.DB;
const userId = c.get("jwtPayload").id;
const config = await NotificationService.getNotificationConfig(db, userId);
const config = await NotificationService.getNotificationConfig(db);
return c.json({
success: true,
+1 -2
View File
@@ -32,8 +32,7 @@ app.route("/api/agents", api.agents);
app.route("/api/users", api.users);
app.route("/api/status", api.status);
app.route("/api/notifications", api.notifications);
app.route("/api/migrate", api.migrate);
app.route("/api/dashboard", api.dashboard);
// 数据库状态标志,用于记录数据库初始化状态
let dbInitialized = false;
+12
View File
@@ -14,6 +14,18 @@ export interface D1PreparedStatement {
raw<T = unknown>(): Promise<T[]>;
}
// 定义操作结果的元数据类型
export interface DbResultMeta {
changes?: number;
[key: string]: any;
}
// 扩展D1Result meta属性的类型
export interface D1Meta {
last_row_id?: number;
changes?: number;
}
export interface D1Result<T = unknown> {
results?: T[];
success: boolean;
+1 -1
View File
@@ -3,4 +3,4 @@ export * from './db';
export * from './monitor';
export * from './notification';
export * from './user';
export * from './status';
+9
View File
@@ -0,0 +1,9 @@
// 状态页配置接口定义
export interface StatusPageConfig {
id?: number;
user_id: number;
title: string;
description: string;
logo_url: string;
custom_css: string;
}
+56 -72
View File
@@ -1,11 +1,9 @@
import { Bindings } from "../models/db";
import { Monitor, MonitorStatusHistory } from "../models/monitor";
// 定义操作结果的元数据类型
interface DbResultMeta {
changes?: number;
[key: string]: any;
}
import {
Bindings,
Monitor,
MonitorStatusHistory,
DbResultMeta,
} from "../models";
/**
* 监控相关的数据库操作
@@ -393,83 +391,69 @@ export async function deleteMonitor(db: Bindings["DB"], id: number) {
}
/**
* 获取所有监控(根据用户角色过滤)
* 获取所有监控
* @param db 数据库连接
* @param userId 用户ID
* @param userRole 用户角色
* @returns 监控列表和操作结果
*/
export async function getAllMonitors(
db: Bindings["DB"],
userId: number,
userRole: string
) {
try {
// 根据用户角色过滤监控
let result;
if (userRole === "admin") {
result = await db
.prepare("SELECT * FROM monitors ORDER BY created_at DESC")
.all<Monitor>();
} else {
result = await db
.prepare(
"SELECT * FROM monitors WHERE created_by = ? ORDER BY created_at DESC"
)
.bind(userId)
.all<Monitor>();
}
export async function getAllMonitors(db: Bindings["DB"]) {
// 根据用户角色过滤监控
let result;
result = await db
.prepare("SELECT * FROM monitors ORDER BY created_at DESC")
.all<Monitor>();
// 解析所有监控的 headers 字段
if (result.results && result.results.length > 0) {
result.results.forEach((monitor) => {
if (typeof monitor.headers === "string") {
try {
monitor.headers = JSON.parse(monitor.headers);
} catch (e) {
monitor.headers = {};
}
// 解析所有监控的 headers 字段
if (result.results && result.results.length > 0) {
result.results.forEach((monitor) => {
if (typeof monitor.headers === "string") {
try {
monitor.headers = JSON.parse(monitor.headers);
} catch (e) {
monitor.headers = {};
}
});
}
});
// 获取所有监控的历史状态数据
const monitorsWithHistory = await Promise.all(
result.results.map(async (monitor) => {
const historyResult = await db
.prepare(
`SELECT * FROM monitor_status_history
// 获取所有监控的历史状态数据
const monitorsWithHistory = await Promise.all(
result.results.map(async (monitor) => {
const historyResult = await db
.prepare(
`SELECT * FROM monitor_status_history
WHERE monitor_id = ?
ORDER BY timestamp ASC`
)
.bind(monitor.id)
.all<MonitorStatusHistory>();
)
.bind(monitor.id)
.all<MonitorStatusHistory>();
return {
...monitor,
history: historyResult.results || [],
};
})
);
return {
success: true,
monitors: monitorsWithHistory,
status: 200,
};
}
return {
...monitor,
history: historyResult.results || [],
};
})
);
return {
success: true,
monitors: result.results || [],
monitors: monitorsWithHistory,
status: 200,
};
} catch (error) {
console.error("获取监控列表错误:", error);
return {
success: false,
message: "获取监控列表失败",
error: error instanceof Error ? error.message : String(error),
status: 500,
};
}
return {
success: true,
monitors: result.results || [],
status: 200,
};
}
/**
* 获取所有监控(不包含历史状态数据)
* @param db 数据库连接
* @returns 监控列表和操作结果
*/
export async function getAllMonitorsWithoutHistory(db: Bindings["DB"]) {
return await db
.prepare("SELECT * FROM monitors ORDER BY created_at DESC")
.all<Monitor>();
}
+3 -9
View File
@@ -1,17 +1,12 @@
import { D1Database } from "../models/db";
import {
NotificationChannel,
NotificationTemplate,
NotificationSettings,
NotificationHistory,
NotificationConfig,
} from "../models/notification";
// 扩展D1Result meta属性的类型
interface D1Meta {
last_row_id?: number;
changes?: number;
}
D1Meta,
D1Database,
} from "../models";
// 获取所有通知渠道
export const getNotificationChannels = async (
@@ -485,7 +480,6 @@ export const getNotificationHistory = async (
// 获取完整的通知配置(用于前端)
export const getNotificationConfig = async (
db: D1Database,
userId: number
): Promise<NotificationConfig> => {
// 获取所有渠道
const channels = await getNotificationChannels(db);
+1 -55
View File
@@ -1,58 +1,4 @@
import { MonitorStatusHistory, Bindings } from "../models";
// 状态页配置接口定义
export interface StatusPageConfig {
id?: number;
user_id: number;
title: string;
description: string;
logo_url: string;
custom_css: string;
}
// 监控项接口
export interface Monitor {
id: number;
name: string;
url: string;
method: string;
interval: number;
timeout: number;
expected_status: number;
headers: string;
body: string;
created_by: number;
active: boolean;
status: string;
uptime: number;
response_time: number;
last_checked?: string;
created_at: string;
updated_at: string;
history?: MonitorStatusHistory[];
}
// 客户端接口
export interface Agent {
id: number;
name: string;
token: string;
created_by: number;
created_at: string;
updated_at: string;
status?: string;
cpu_usage?: number;
memory_total?: number;
memory_used?: number;
disk_total?: number;
disk_used?: number;
network_rx?: number;
network_tx?: number;
hostname?: string;
ip_addresses?: string;
os?: string;
version?: string;
}
import { StatusPageConfig, Agent, Bindings } from "../models";
/**
* 状态页相关的数据库操作
+23
View File
@@ -0,0 +1,23 @@
import { Bindings } from "../models";
import * as repositories from "../repositories";
export async function getDashboardData(db: Bindings["DB"]) {
const monitors = await repositories.getAllMonitorsWithoutHistory(db);
const agents = await repositories.getAllAgents(db);
if (monitors.results && monitors.results.length > 0) {
monitors.results.forEach((monitor) => {
if (typeof monitor.headers === "string") {
try {
monitor.headers = JSON.parse(monitor.headers);
} catch (e) {
monitor.headers = {};
}
}
});
}
return {
monitors: monitors.results,
agents: agents.results,
};
}
+1 -2
View File
@@ -166,9 +166,8 @@ export async function deleteNotificationTemplate(
// 通知设置相关服务,获取所有的通知设置
export async function getNotificationConfig(
db: D1Database,
userId: number
): Promise<models.NotificationConfig> {
return await repositories.getNotificationConfig(db, userId);
return await repositories.getNotificationConfig(db);
}
export async function createOrUpdateSettings(
+13 -38
View File
@@ -7,10 +7,8 @@ import {
GlobeIcon,
ExclamationTriangleIcon,
} from "@radix-ui/react-icons";
import { getAllMonitors } from "../services/api/monitors";
import { Monitor } from "../types/monitors";
import { getAllAgents } from "../services/api/agents";
import { Agent } from "../types/agents";
import { Monitor, Agent } from "../types";
import { getDashboardData } from "../services/api/dashboard";
import StatusSummaryCard from "../components/StatusSummaryCard";
import "../styles/components.css";
import { useTranslation } from "react-i18next";
@@ -24,50 +22,27 @@ const Dashboard = () => {
// 获取所有数据
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
// 同时获取监控和客户端数据
const [monitorsResponse, agentsResponse] = await Promise.all([
getAllMonitors(),
getAllAgents(),
]);
// 处理监控数据
if (monitorsResponse.success && monitorsResponse.monitors) {
setMonitors(monitorsResponse.monitors);
} else {
console.error("获取监控数据失败:", monitorsResponse.message);
}
// 处理客户端数据
if (agentsResponse.success && agentsResponse.agents) {
console.log("获取到客户端列表:", agentsResponse.agents);
setAgents(agentsResponse.agents);
} else {
console.error("获取客户端数据失败:", agentsResponse.message);
}
} catch (err) {
console.error("获取数据错误:", err);
setError(t("common.error"));
} finally {
setLoading(false);
}
};
fetchData();
// 设置定时器,每分钟刷新一次数据
const intervalId = setInterval(() => {
console.log("Dashboard: 自动刷新数据...");
fetchData();
}, 60000); // 60000ms = 1分钟
}, 180000); // 180000ms = 3分钟
// 组件卸载时清除定时器
return () => clearInterval(intervalId);
}, [t]);
const fetchData = async () => {
setLoading(true);
const [dashboardResponse] = await Promise.all([getDashboardData()]);
if (dashboardResponse) {
setMonitors(dashboardResponse.monitors);
setAgents(dashboardResponse.agents);
}
setLoading(false);
};
// 加载中显示
if (loading) {
return (
+11
View File
@@ -0,0 +1,11 @@
import api from "./index";
import { Monitor, Agent } from "../../types";
// 获取仪表盘数据
export const getDashboardData = async (): Promise<{
monitors: Monitor[];
agents: Agent[];
}> => {
const response = await api.get("/api/dashboard");
return response.data;
};
+2 -9
View File
@@ -1,16 +1,9 @@
import { User } from "./users";
/**
* 认证相关类型定义
*/
export interface User {
id: number;
username: string;
email?: string;
role?: string;
created_at?: string;
updated_at?: string;
}
export interface LoginRequest {
username: string;
password: string;
+9
View File
@@ -0,0 +1,9 @@
export * from "./monitors";
export * from "./agents";
export * from "./auth";
export * from "./users";
export * from "./status";
export * from "./components";
export * from "./language";
export * from "./notification";
export * from "./routes";