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

324
app/crud/system_config.py Normal file
View File

@@ -0,0 +1,324 @@
"""
系统配置CRUD操作
"""
from typing import Optional, List, Dict, Any
from sqlalchemy import select, and_, or_, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.system_config import SystemConfig
import json
class SystemConfigCRUD:
"""系统配置CRUD类"""
async def get(self, db: AsyncSession, config_id: int) -> Optional[SystemConfig]:
"""
根据ID获取系统配置
Args:
db: 数据库会话
config_id: 配置ID
Returns:
SystemConfig对象或None
"""
result = await db.execute(
select(SystemConfig).where(SystemConfig.id == config_id)
)
return result.scalar_one_or_none()
async def get_by_key(self, db: AsyncSession, config_key: str) -> Optional[SystemConfig]:
"""
根据配置键获取系统配置
Args:
db: 数据库会话
config_key: 配置键
Returns:
SystemConfig对象或None
"""
result = await db.execute(
select(SystemConfig).where(SystemConfig.config_key == config_key)
)
return result.scalar_one_or_none()
async def get_multi(
self,
db: AsyncSession,
*,
skip: int = 0,
limit: int = 100,
keyword: Optional[str] = None,
category: Optional[str] = None,
is_active: Optional[bool] = None,
is_system: Optional[bool] = None
) -> tuple[List[SystemConfig], int]:
"""
获取系统配置列表
Args:
db: 数据库会话
skip: 跳过条数
limit: 返回条数
keyword: 搜索关键词
category: 配置分类
is_active: 是否启用
is_system: 是否系统配置
Returns:
(配置列表, 总数)
"""
# 构建查询条件
conditions = []
if keyword:
conditions.append(
or_(
SystemConfig.config_key.ilike(f"%{keyword}%"),
SystemConfig.config_name.ilike(f"%{keyword}%"),
SystemConfig.description.ilike(f"%{keyword}%")
)
)
if category:
conditions.append(SystemConfig.category == category)
if is_active is not None:
conditions.append(SystemConfig.is_active == is_active)
if is_system is not None:
conditions.append(SystemConfig.is_system == is_system)
# 查询总数
count_query = select(func.count(SystemConfig.id))
if conditions:
count_query = count_query.where(and_(*conditions))
total_result = await db.execute(count_query)
total = total_result.scalar() or 0
# 查询数据
query = select(SystemConfig)
if conditions:
query = query.where(and_(*conditions))
query = query.order_by(SystemConfig.category, SystemConfig.sort_order, SystemConfig.id)
query = query.offset(skip).limit(limit)
result = await db.execute(query)
items = result.scalars().all()
return list(items), total
async def get_by_category(
self,
db: AsyncSession,
category: str,
*,
is_active: bool = True
) -> List[SystemConfig]:
"""
根据分类获取配置列表
Args:
db: 数据库会话
category: 配置分类
is_active: 是否启用
Returns:
配置列表
"""
conditions = [SystemConfig.category == category]
if is_active:
conditions.append(SystemConfig.is_active == True)
result = await db.execute(
select(SystemConfig)
.where(and_(*conditions))
.order_by(SystemConfig.sort_order, SystemConfig.id)
)
return list(result.scalars().all())
async def get_categories(
self,
db: AsyncSession
) -> List[Dict[str, Any]]:
"""
获取所有配置分类及统计信息
Args:
db: 数据库会话
Returns:
分类列表
"""
result = await db.execute(
select(
SystemConfig.category,
func.count(SystemConfig.id).label('count')
)
.group_by(SystemConfig.category)
.order_by(SystemConfig.category)
)
categories = []
for row in result:
categories.append({
"category": row[0],
"count": row[1]
})
return categories
async def create(
self,
db: AsyncSession,
*,
obj_in: Dict[str, Any]
) -> SystemConfig:
"""
创建系统配置
Args:
db: 数据库会话
obj_in: 创建数据
Returns:
SystemConfig对象
"""
db_obj = SystemConfig(**obj_in)
db.add(db_obj)
await db.flush()
await db.refresh(db_obj)
return db_obj
async def update(
self,
db: AsyncSession,
*,
db_obj: SystemConfig,
obj_in: Dict[str, Any]
) -> SystemConfig:
"""
更新系统配置
Args:
db: 数据库会话
db_obj: 数据库对象
obj_in: 更新数据
Returns:
SystemConfig对象
"""
for field, value in obj_in.items():
if hasattr(db_obj, field):
setattr(db_obj, field, value)
await db.flush()
await db.refresh(db_obj)
return db_obj
async def batch_update(
self,
db: AsyncSession,
*,
configs: Dict[str, Any],
updater_id: Optional[int] = None
) -> List[SystemConfig]:
"""
批量更新配置
Args:
db: 数据库会话
configs: 配置键值对
updater_id: 更新人ID
Returns:
更新的配置列表
"""
updated_configs = []
for config_key, config_value in configs.items():
db_obj = await self.get_by_key(db, config_key)
if db_obj:
# 转换为字符串存储
if isinstance(config_value, (dict, list)):
config_value = json.dumps(config_value, ensure_ascii=False)
elif isinstance(config_value, bool):
config_value = str(config_value).lower()
else:
config_value = str(config_value)
db_obj.config_value = config_value
db_obj.updated_by = updater_id
updated_configs.append(db_obj)
await db.flush()
return updated_configs
async def delete(self, db: AsyncSession, *, config_id: int) -> Optional[SystemConfig]:
"""
删除系统配置
Args:
db: 数据库会话
config_id: 配置ID
Returns:
删除的SystemConfig对象或None
"""
obj = await self.get(db, config_id)
if obj:
# 系统配置不允许删除
if obj.is_system:
raise ValueError("系统配置不允许删除")
await db.delete(obj)
await db.flush()
return obj
async def get_value(
self,
db: AsyncSession,
config_key: str,
default: Any = None
) -> Any:
"""
获取配置值(自动转换类型)
Args:
db: 数据库会话
config_key: 配置键
default: 默认值
Returns:
配置值
"""
config = await self.get_by_key(db, config_key)
if not config or not config.is_active:
return default
value = config.config_value
# 根据类型转换
if config.value_type == "boolean":
return value.lower() in ("true", "1", "yes") if value else False
elif config.value_type == "number":
try:
return int(value) if value else 0
except ValueError:
try:
return float(value) if value else 0.0
except ValueError:
return 0
elif config.value_type == "json":
try:
return json.loads(value) if value else {}
except json.JSONDecodeError:
return {}
else:
return value
# 创建全局实例
system_config_crud = SystemConfigCRUD()