# 管理界面模块 from fastapi import APIRouter, Request, Depends, HTTPException, status from fastapi.responses import HTMLResponse, JSONResponse from fastapi.templating import Jinja2Templates from pydantic import BaseModel from typing import Dict, Any, List, Optional import psutil import asyncio from datetime import datetime from auth import get_current_active_user, User, Token, create_access_token from config import Config from proxy import opencode_proxy from version import get_version_info # 创建路由 admin_router = APIRouter(prefix="/admin", tags=["管理"]) # 模板配置(稍后创建模板文件) templates = Jinja2Templates(directory="templates") class SystemStatus(BaseModel): """系统状态模型""" cpu_percent: float memory_percent: float disk_percent: float opencode_status: Dict[str, Any] fastapi_status: str uptime: str version_info: Dict[str, Any] class LoginRequest(BaseModel): """登录请求模型""" username: str password: str class ServiceControl(BaseModel): """服务控制模型""" action: str # restart, start, stop async def get_system_info() -> Dict[str, Any]: """获取系统信息""" try: # CPU 使用率 cpu_percent = psutil.cpu_percent(interval=1) # 内存使用率 memory = psutil.virtual_memory() memory_percent = memory.percent # 磁盘使用率 disk = psutil.disk_usage('/') disk_percent = (disk.used / disk.total) * 100 # OpenCode 状态 opencode_info = await opencode_proxy.get_service_info() # 系统启动时间 boot_time = psutil.boot_time() uptime = datetime.now() - datetime.fromtimestamp(boot_time) uptime_str = str(uptime).split('.')[0] return { "cpu_percent": cpu_percent, "memory_percent": memory_percent, "disk_percent": disk_percent, "opencode_status": opencode_info, "fastapi_status": "healthy", "uptime": uptime_str } except Exception as e: return { "error": str(e), "cpu_percent": 0, "memory_percent": 0, "disk_percent": 0, "opencode_status": {"status": "unknown"}, "fastapi_status": "unknown", "uptime": "unknown" } @admin_router.get("/", response_class=HTMLResponse) async def admin_dashboard(request: Request): """管理仪表板主页""" # 检查是否有有效的令牌 token = request.cookies.get("access_token") if token: try: # 这里应该验证 token,为了简化先直接显示仪表板 return templates.TemplateResponse( "dashboard.html", { "request": request, "title": "管理仪表板" } ) except: pass # 没有有效令牌,重定向到登录页 return templates.TemplateResponse( "login.html", { "request": request, "title": "管理员登录" } ) @admin_router.get("/login", response_class=HTMLResponse) async def login_page(request: Request): """登录页面""" return templates.TemplateResponse( "login.html", { "request": request, "title": "管理员登录" } ) @admin_router.post("/login") async def login(login_data: LoginRequest): """处理登录""" if login_data.username != Config.ADMIN_USERNAME or login_data.password != Config.ADMIN_PASSWORD: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="用户名或密码错误" ) # 创建访问令牌 access_token_expires = datetime.timedelta(minutes=Config.JWT_EXPIRE_MINUTES) access_token = create_access_token( data={"sub": login_data.username}, expires_delta=access_token_expires ) return { "access_token": access_token, "token_type": "bearer", "expires_in": Config.JWT_EXPIRE_MINUTES * 60 } @admin_router.get("/dashboard", response_class=HTMLResponse) async def dashboard(request: Request, current_user: User = Depends(get_current_active_user)): """管理仪表板""" return templates.TemplateResponse( "dashboard.html", { "request": request, "title": "管理仪表板", "user": current_user } ) @admin_router.get("/api/system/status") async def get_system_status(current_user: User = Depends(get_current_active_user)) -> SystemStatus: """获取系统状态""" system_info = await get_system_info() version_info = get_version_info() return SystemStatus( cpu_percent=system_info.get("cpu_percent", 0), memory_percent=system_info.get("memory_percent", 0), disk_percent=system_info.get("disk_percent", 0), opencode_status=system_info.get("opencode_status", {}), fastapi_status=system_info.get("fastapi_status", "unknown"), uptime=system_info.get("uptime", "unknown"), version_info=version_info ) @admin_router.get("/api/version") async def get_version(current_user: User = Depends(get_current_active_user)) -> Dict[str, Any]: """获取版本信息""" return get_version_info() @admin_router.post("/api/service/control") async def control_service( control: ServiceControl, current_user: User = Depends(get_current_active_user) ): """服务控制""" # 这里应该实现实际的服务控制逻辑 # 目前返回模拟响应 if control.action == "restart": # TODO: 实现 OpenCode 服务重启 return {"status": "success", "message": "服务重启成功"} elif control.action == "status": status_info = await opencode_proxy.get_service_info() return {"status": "success", "data": status_info} else: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="不支持的操作" ) @admin_router.get("/api/logs") async def get_logs( lines: int = 100, current_user: User = Depends(get_current_active_user) ) -> Dict[str, Any]: """获取系统日志""" # TODO: 实现日志获取逻辑 return { "logs": [ f"{datetime.now().isoformat()} - [INFO] - 服务运行正常", f"{datetime.now().isoformat()} - [INFO] - OpenCode 服务已启动", ], "total_lines": 2 } @admin_router.post("/logout") async def logout(): """登出""" return {"message": "登出成功"}