Merge pull request #1365 from Mai-with-u/dev

0.11.4
pull/1381/head
墨梓柒 2025-11-19 15:40:46 +08:00 committed by GitHub
commit 8f8adeacbb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 336 additions and 158 deletions

View File

@ -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

View File

@ -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

View File

@ -2,6 +2,5 @@ HOST=127.0.0.1
PORT=8000
# WebUI 配置
# WEBUI_ENABLED=true
# WEBUI_MODE=development # 开发模式(需手动启动前端: cd webui && npm run dev端口 7999
# WEBUI_MODE=production # 生产模式(需先构建前端: cd webui && npm run build
WEBUI_ENABLED=true
WEBUI_MODE=production # 生产模式

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,8 +5,8 @@
<link rel="icon" type="image/x-icon" href="/maimai.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MaiBot Dashboard</title>
<script type="module" crossorigin src="/assets/index-DYT0dd6E.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BjjI9czp.css">
<script type="module" crossorigin src="/assets/index-Tw768L2V.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BWXp50gY.css">
</head>
<body>
<div id="root"></div>