perf: reduce dashboard api call
This commit is contained in:
1 parent
090ad2e51f
commit
cd479cadcc
17 files changed
+160
-213
No files matched your search
@@ -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
|
||||
);
|
||||
});
|
||||
@@ -4,4 +4,4 @@ export * from "./agents";
|
||||
export * from "./users";
|
||||
export * from "./status";
|
||||
export * from "./notifications";
|
||||
export * from "./migrate";
|
||||
export * from "./dashboard";
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3,4 +3,4 @@ export * from './db';
|
||||
export * from './monitor';
|
||||
export * from './notification';
|
||||
export * from './user';
|
||||
|
||||
export * from './status';
|
||||
@@ -0,0 +1,9 @@
|
||||
// 状态页配置接口定义
|
||||
export interface StatusPageConfig {
|
||||
id?: number;
|
||||
user_id: number;
|
||||
title: string;
|
||||
description: string;
|
||||
logo_url: string;
|
||||
custom_css: string;
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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,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";
|
||||
|
||||
/**
|
||||
* 状态页相关的数据库操作
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
Reference in new issue
Block a user