From 74f9beb2316e653b0920b5908bea381624f1a99d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A2=A8=E6=A2=93=E6=9F=92?= <1787882683@qq.com> Date: Wed, 19 Nov 2025 14:59:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E9=A6=96=E6=AC=A1?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E6=94=AF=E6=8C=81=E8=8E=B7=E5=8F=96=E3=80=81?= =?UTF-8?q?=E6=A0=87=E8=AE=B0=E5=AE=8C=E6=88=90=E5=92=8C=E9=87=8D=E7=BD=AE?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/webui/routes.py | 125 +++++++++++++++++++++++++++++++++++++ src/webui/token_manager.py | 50 ++++++++++++++- 2 files changed, 174 insertions(+), 1 deletion(-) diff --git a/src/webui/routes.py b/src/webui/routes.py index a3397e83..b52dede6 100644 --- a/src/webui/routes.py +++ b/src/webui/routes.py @@ -62,6 +62,24 @@ class TokenRegenerateResponse(BaseModel): message: str = Field(..., description="生成结果消息") +class FirstSetupStatusResponse(BaseModel): + """首次配置状态响应""" + is_first_setup: bool = Field(..., description="是否为首次配置") + message: str = Field(..., description="状态消息") + + +class CompleteSetupResponse(BaseModel): + """完成配置响应""" + success: bool = Field(..., description="是否成功") + message: str = Field(..., description="结果消息") + + +class ResetSetupResponse(BaseModel): + """重置配置响应""" + success: bool = Field(..., description="是否成功") + message: str = Field(..., description="结果消息") + + @router.get("/health") async def health_check(): """健康检查""" @@ -174,3 +192,110 @@ async def regenerate_token(authorization: Optional[str] = Header(None)): logger.error(f"Token 重新生成失败: {e}") raise HTTPException(status_code=500, detail="Token 重新生成失败") from e + +@router.get("/setup/status", response_model=FirstSetupStatusResponse) +async def get_setup_status(authorization: Optional[str] = Header(None)): + """ + 获取首次配置状态 + + Args: + authorization: Authorization header (Bearer token) + + Returns: + 首次配置状态 + """ + try: + # 验证 token + if not authorization or not authorization.startswith("Bearer "): + raise HTTPException(status_code=401, detail="未提供有效的认证信息") + + current_token = authorization.replace("Bearer ", "") + token_manager = get_token_manager() + + if not token_manager.verify_token(current_token): + raise HTTPException(status_code=401, detail="Token 无效") + + # 检查是否为首次配置 + is_first = token_manager.is_first_setup() + + return FirstSetupStatusResponse( + is_first_setup=is_first, + message="首次配置" if is_first else "已完成配置" + ) + except HTTPException: + raise + except Exception as e: + logger.error(f"获取配置状态失败: {e}") + raise HTTPException(status_code=500, detail="获取配置状态失败") from e + + +@router.post("/setup/complete", response_model=CompleteSetupResponse) +async def complete_setup(authorization: Optional[str] = Header(None)): + """ + 标记首次配置完成 + + Args: + authorization: Authorization header (Bearer token) + + Returns: + 完成结果 + """ + try: + # 验证 token + if not authorization or not authorization.startswith("Bearer "): + raise HTTPException(status_code=401, detail="未提供有效的认证信息") + + current_token = authorization.replace("Bearer ", "") + token_manager = get_token_manager() + + if not token_manager.verify_token(current_token): + raise HTTPException(status_code=401, detail="Token 无效") + + # 标记配置完成 + success = token_manager.mark_setup_completed() + + return CompleteSetupResponse( + success=success, + message="配置已完成" if success else "标记失败" + ) + except HTTPException: + raise + except Exception as e: + logger.error(f"标记配置完成失败: {e}") + raise HTTPException(status_code=500, detail="标记配置完成失败") from e + + +@router.post("/setup/reset", response_model=ResetSetupResponse) +async def reset_setup(authorization: Optional[str] = Header(None)): + """ + 重置首次配置状态,允许重新进入配置向导 + + Args: + authorization: Authorization header (Bearer token) + + Returns: + 重置结果 + """ + try: + # 验证 token + if not authorization or not authorization.startswith("Bearer "): + raise HTTPException(status_code=401, detail="未提供有效的认证信息") + + current_token = authorization.replace("Bearer ", "") + token_manager = get_token_manager() + + if not token_manager.verify_token(current_token): + raise HTTPException(status_code=401, detail="Token 无效") + + # 重置配置状态 + success = token_manager.reset_setup_status() + + return ResetSetupResponse( + success=success, + message="配置状态已重置" if success else "重置失败" + ) + except HTTPException: + raise + except Exception as e: + logger.error(f"重置配置状态失败: {e}") + raise HTTPException(status_code=500, detail="重置配置状态失败") from e diff --git a/src/webui/token_manager.py b/src/webui/token_manager.py index 2b606b84..7ab16d75 100644 --- a/src/webui/token_manager.py +++ b/src/webui/token_manager.py @@ -79,7 +79,8 @@ class TokenManager: config = { "access_token": token, "created_at": self._get_current_timestamp(), - "updated_at": self._get_current_timestamp() + "updated_at": self._get_current_timestamp(), + "first_setup_completed": False # 标记首次配置未完成 } self._save_config(config) @@ -231,6 +232,53 @@ class TokenManager: return True, "Token 格式正确" + def is_first_setup(self) -> bool: + """ + 检查是否为首次配置 + + Returns: + bool: 是否为首次配置 + """ + config = self._load_config() + return not config.get("first_setup_completed", False) + + def mark_setup_completed(self) -> bool: + """ + 标记首次配置已完成 + + Returns: + bool: 是否标记成功 + """ + try: + config = self._load_config() + config["first_setup_completed"] = True + config["setup_completed_at"] = self._get_current_timestamp() + self._save_config(config) + logger.info("首次配置已标记为完成") + return True + except Exception as e: + logger.error(f"标记首次配置完成失败: {e}") + return False + + def reset_setup_status(self) -> bool: + """ + 重置首次配置状态,允许重新进入配置向导 + + Returns: + bool: 是否重置成功 + """ + try: + config = self._load_config() + config["first_setup_completed"] = False + if "setup_completed_at" in config: + del config["setup_completed_at"] + self._save_config(config) + logger.info("首次配置状态已重置") + return True + except Exception as e: + logger.error(f"重置首次配置状态失败: {e}") + return False + # 全局单例 _token_manager_instance: Optional[TokenManager] = None