fix: 修复多个关键问题

- 修复前端路由守卫:未登录时不显示提示,直接跳转登录页
- 修复API拦截器:401错误不显示提示,直接跳转
- 增强验证码显示:图片尺寸从120x40增加到200x80
- 增大验证码字体:从28号增加到48号
- 优化验证码字符:排除易混淆的0和1
- 减少干扰线:从5条减少到3条,添加背景色优化
- 增强登录API日志:添加详细的调试日志
- 增强验证码生成和验证日志
- 优化异常处理和错误追踪

影响文件:
- src/router/index.ts
- src/api/request.ts
- app/services/auth_service.py
- app/api/v1/auth.py
- app/schemas/user.py

测试状态:
- 前端构建通过
- 后端语法检查通过
- 验证码显示效果优化完成

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-01-25 00:26:21 +08:00
commit e71181f0a3
150 changed files with 39549 additions and 0 deletions

View File

@@ -0,0 +1,298 @@
"""
系统配置服务层
"""
from typing import Optional, List, Dict, Any
from sqlalchemy.ext.asyncio import AsyncSession
from app.crud.system_config import system_config_crud
from app.schemas.system_config import SystemConfigCreate, SystemConfigUpdate
import json
class SystemConfigService:
"""系统配置服务类"""
async def get_config(self, db: AsyncSession, config_id: int) -> Optional[Dict[str, Any]]:
"""
获取配置详情
Args:
db: 数据库会话
config_id: 配置ID
Returns:
配置信息
"""
config = await system_config_crud.get(db, config_id)
if not config:
return None
return {
"id": config.id,
"config_key": config.config_key,
"config_name": config.config_name,
"config_value": config.config_value,
"value_type": config.value_type,
"category": config.category,
"description": config.description,
"is_system": config.is_system,
"is_encrypted": config.is_encrypted,
"validation_rule": config.validation_rule,
"options": config.options,
"default_value": config.default_value,
"sort_order": config.sort_order,
"is_active": config.is_active,
"created_at": config.created_at,
"updated_at": config.updated_at,
"updated_by": config.updated_by,
}
async def get_config_by_key(
self,
db: AsyncSession,
config_key: str,
default: Any = None
) -> Any:
"""
根据键获取配置值
Args:
db: 数据库会话
config_key: 配置键
default: 默认值
Returns:
配置值
"""
return await system_config_crud.get_value(db, config_key, default)
async def get_configs(
self,
db: AsyncSession,
*,
skip: int = 0,
limit: int = 20,
keyword: Optional[str] = None,
category: Optional[str] = None,
is_active: Optional[bool] = None,
is_system: Optional[bool] = None
) -> Dict[str, Any]:
"""
获取配置列表
Args:
db: 数据库会话
skip: 跳过条数
limit: 返回条数
keyword: 搜索关键词
category: 配置分类
is_active: 是否启用
is_system: 是否系统配置
Returns:
配置列表和总数
"""
items, total = await system_config_crud.get_multi(
db,
skip=skip,
limit=limit,
keyword=keyword,
category=category,
is_active=is_active,
is_system=is_system
)
return {
"items": [
{
"id": item.id,
"config_key": item.config_key,
"config_name": item.config_name,
"config_value": item.config_value,
"value_type": item.value_type,
"category": item.category,
"description": item.description,
"is_system": item.is_system,
"is_encrypted": item.is_encrypted,
"options": item.options,
"default_value": item.default_value,
"sort_order": item.sort_order,
"is_active": item.is_active,
"created_at": item.created_at,
"updated_at": item.updated_at,
}
for item in items
],
"total": total
}
async def get_configs_by_category(
self,
db: AsyncSession,
category: str,
is_active: bool = True
) -> List[Dict[str, Any]]:
"""
根据分类获取配置
Args:
db: 数据库会话
category: 配置分类
is_active: 是否启用
Returns:
配置列表
"""
items = await system_config_crud.get_by_category(db, category, is_active=is_active)
return [
{
"config_key": item.config_key,
"config_name": item.config_name,
"config_value": item.config_value,
"value_type": item.value_type,
"description": item.description,
}
for item in items
]
async def get_categories(self, db: AsyncSession) -> List[Dict[str, Any]]:
"""
获取所有配置分类
Args:
db: 数据库会话
Returns:
分类列表
"""
return await system_config_crud.get_categories(db)
async def create_config(
self,
db: AsyncSession,
obj_in: SystemConfigCreate,
creator_id: Optional[int] = None
) -> Dict[str, Any]:
"""
创建配置
Args:
db: 数据库会话
obj_in: 创建数据
creator_id: 创建人ID
Returns:
创建的配置信息
"""
# 检查键是否已存在
existing = await system_config_crud.get_by_key(db, obj_in.config_key)
if existing:
raise ValueError(f"配置键 {obj_in.config_key} 已存在")
# 转换为字典
obj_in_data = obj_in.model_dump()
# 处理复杂类型
if obj_in.options:
obj_in_data["options"] = json.loads(obj_in.options.model_dump_json()) if isinstance(obj_in.options, dict) else obj_in.options
config = await system_config_crud.create(db, obj_in=obj_in_data)
return {
"id": config.id,
"config_key": config.config_key,
"config_name": config.config_name,
"category": config.category,
}
async def update_config(
self,
db: AsyncSession,
config_id: int,
obj_in: SystemConfigUpdate,
updater_id: Optional[int] = None
) -> Dict[str, Any]:
"""
更新配置
Args:
db: 数据库会话
config_id: 配置ID
obj_in: 更新数据
updater_id: 更新人ID
Returns:
更新的配置信息
"""
config = await system_config_crud.get(db, config_id)
if not config:
raise ValueError("配置不存在")
# 系统配置不允许修改某些字段
if config.is_system:
if obj_in.config_key and obj_in.config_key != config.config_key:
raise ValueError("系统配置不允许修改配置键")
if obj_in.value_type and obj_in.value_type != config.value_type:
raise ValueError("系统配置不允许修改值类型")
if obj_in.category and obj_in.category != config.category:
raise ValueError("系统配置不允许修改分类")
# 转换为字典过滤None值
update_data = obj_in.model_dump(exclude_unset=True)
# 处理复杂类型
if update_data.get("options"):
update_data["options"] = json.loads(update_data["options"].model_dump_json()) if isinstance(update_data["options"], dict) else update_data["options"]
update_data["updated_by"] = updater_id
config = await system_config_crud.update(db, db_obj=config, obj_in=update_data)
return {
"id": config.id,
"config_key": config.config_key,
"config_name": config.config_name,
"config_value": config.config_value,
}
async def batch_update_configs(
self,
db: AsyncSession,
configs: Dict[str, Any],
updater_id: Optional[int] = None
) -> Dict[str, Any]:
"""
批量更新配置
Args:
db: 数据库会话
configs: 配置键值对
updater_id: 更新人ID
Returns:
更新结果
"""
updated = await system_config_crud.batch_update(
db,
configs=configs,
updater_id=updater_id
)
return {
"count": len(updated),
"configs": [item.config_key for item in updated]
}
async def delete_config(self, db: AsyncSession, config_id: int) -> None:
"""
删除配置
Args:
db: 数据库会话
config_id: 配置ID
"""
await system_config_crud.delete(db, config_id=config_id)
# 创建全局实例
system_config_service = SystemConfigService()