-
-
+
+
+
+ {/* 监控仪表盘替代原有仪表盘 */}
+
+
);
-}
\ No newline at end of file
+}
diff --git a/src/components/admin/monitoring-dashboard.tsx b/src/components/admin/monitoring-dashboard.tsx
new file mode 100644
index 0000000..1755239
--- /dev/null
+++ b/src/components/admin/monitoring-dashboard.tsx
@@ -0,0 +1,116 @@
+'use client';
+
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { useWebVitals } from "@/hooks/use-web-vitals";
+import { useEffect } from "react";
+
+interface MonitoringDashboardProps {
+ userCount: number;
+ problemCount: number;
+}
+
+export function MonitoringDashboard({
+ userCount,
+ problemCount
+}: MonitoringDashboardProps) {
+ const { vitals, loading } = useWebVitals();
+
+ // 添加日志输出性能指标读取结果(已注释)
+ useEffect(() => {
+ if (!loading) {
+ // console.log('[仪表盘] 当前显示指标:', {
+ // lcp: vitals.lcp ? `${vitals.lcp.value.toFixed(2)}秒(${vitals.lcp.rating})` : '未收集',
+ // fid: vitals.fid ? `${vitals.fid.value.toFixed(2)}毫秒(${vitals.fid.rating})` : '未收集',
+ // cls: vitals.cls ? `${vitals.cls.value.toFixed(2)}(${vitals.cls.rating})` : '未收集',
+ // fcp: vitals.fcp ? `${vitals.fcp.value.toFixed(2)}秒(${vitals.fcp.rating})` : '未收集'
+ // });
+ }
+ }, [loading, vitals]);
+
+ return (
+
+ {/* 用户统计 */}
+
+
+
+ 活跃用户
+
+
+
+
+ {userCount}
+
+ +20% 本月新增
+
+
+
+
+ {/* 题目统计 */}
+
+
+
+ 在线题目
+
+
+
+
+ {problemCount}
+
+ +15% 本周新增
+
+
+
+
+ {/* 性能指标卡片 */}
+
+
+ 性能指标
+
+
+
+ - LCP:
+ - {loading ? '加载中...' : vitals.lcp ? `${vitals.lcp.value.toFixed(2)} 秒(${vitals.lcp.rating})` : '暂无数据'}
+
+ - FID:
+ - {loading ? '加载中...' : vitals.fid ? `${vitals.fid.value.toFixed(2)} 毫秒(${vitals.fid.rating})` : '暂无数据'}
+
+ - CLS:
+ - {loading ? '加载中...' : vitals.cls ? `${vitals.cls.value.toFixed(2)}(${vitals.cls.rating})` : '暂无数据'}
+
+ - FCP:
+ - {loading ? '加载中...' : vitals.fcp ? `${vitals.fcp.value.toFixed(2)} 秒(${vitals.fcp.rating})` : '暂无数据'}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/admin/sidebar.tsx b/src/components/admin/sidebar.tsx
index e3f1db1..d0efd2b 100644
--- a/src/components/admin/sidebar.tsx
+++ b/src/components/admin/sidebar.tsx
@@ -1,13 +1,13 @@
"use client"
import { useSession } from "next-auth/react";
+import { usePathname } from "next/navigation";
+// 仅保留实际使用的组件导入
import {
- Sidebar,
SidebarContent,
SidebarFooter,
SidebarRail,
} from "@/components/ui/sidebar";
import { NavMain } from "@/components/nav-main";
-import { NavProjects } from "@/components/nav-projects";
import { NavUser } from "@/components/nav-user";
import {
Command,
@@ -15,6 +15,9 @@ import {
Settings2,
} from "lucide-react";
+// 添加缺失的AppSidebar导入
+import { AppSidebar as BaseAppSidebar } from "@/components/app-sidebar";
+
import { useEffect, useState } from "react";
import { PrismaClient } from "@prisma/client";
@@ -27,13 +30,6 @@ const teams = [
const adminData = {
- // teams: [
- // {
- // name: "Admin Team",
- // logo: GalleryVerticalEnd,
- // plan: "Enterprise",
- // },
- // ],
navMain: [
{
title: "Dashboard",
@@ -69,9 +65,10 @@ const adminData = {
]
};
-export const AdminSidebar = ({ ...props }: React.ComponentProps
) => {
+export function AdminSidebar() {
const { data: session } = useSession();
const [userAvatar, setUserAvatar] = useState("");
+ const pathname = usePathname();
useEffect(() => {
const fetchUserAvatar = async () => {
@@ -99,20 +96,48 @@ export const AdminSidebar = ({ ...props }: React.ComponentProps)
email: session?.user?.email || "admin@example.com",
avatar: userAvatar
};
-
+ const adminNavItems = adminData.navMain.map((item) => ({
+ ...item,
+ items: item.items.map((subItem) => ({
+ ...subItem,
+ active: subItem.url === pathname,
+ })),
+ }));
return (
-
+
{/**/}
{/* */}
{/**/}
-
-
+
+ {/* 添加监控菜单项 */}
+
-
+
);
-};
\ No newline at end of file
+}
diff --git a/src/hooks/use-web-vitals.ts b/src/hooks/use-web-vitals.ts
new file mode 100644
index 0000000..3c4be86
--- /dev/null
+++ b/src/hooks/use-web-vitals.ts
@@ -0,0 +1,80 @@
+'use client';
+
+import { useReportWebVitals } from 'next/web-vitals';
+import { useEffect, useState } from 'react';
+
+export interface WebVital {
+ value: number;
+ rating: 'good' | 'needs-improvement' | 'poor';
+}
+
+interface WebVitals {
+ lcp?: WebVital;
+ fid?: WebVital;
+ cls?: WebVital;
+ fcp?: WebVital;
+}
+
+export function useWebVitals() {
+ const [vitals, setVitals] = useState({
+ lcp: undefined,
+ fid: undefined,
+ cls: undefined,
+ fcp: undefined,
+ });
+ const [loading, setLoading] = useState(true);
+
+ // 添加详细日志记录指标接收(已注释)
+ useReportWebVitals((metric) => {
+ // console.log(`[Web Vitals] 接收指标: ${metric.name}`, {
+ // value: metric.value,
+ // rating: getRating(metric)
+ // });
+
+ setVitals((prev) => ({
+ ...prev,
+ [metric.name.toLowerCase()]: {
+ value: metric.value,
+ rating: getRating(metric),
+ },
+ }));
+ });
+
+ // 添加日志记录最终指标状态(已注释)
+ useEffect(() => {
+ if (!loading) {
+ // console.log('[Web Vitals] 当前完整指标:', {
+ // lcp: vitals.lcp?.value,
+ // fid: vitals.fid?.value,
+ // cls: vitals.cls?.value,
+ // fcp: vitals.fcp?.value
+ // });
+ }
+ }, [loading, vitals]);
+
+ // 使用useEffect处理加载状态
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ setLoading(false);
+ }, 2000);
+
+ return () => {
+ clearTimeout(timer);
+ };
+ }, []);
+
+ return { vitals, loading };
+}
+
+// 添加更具体的类型定义
+interface Metric {
+ name: string;
+ value: number;
+ rating: 'good' | 'needs-improvement' | 'poor';
+}
+
+function getRating(metric: Metric): 'good' | 'needs-improvement' | 'poor' {
+ if (metric.rating === 'good') return 'good';
+ if (metric.rating === 'needs-improvement') return 'needs-improvement';
+ return 'poor';
+}
\ No newline at end of file