- 修复前端路由守卫:未登录时不显示提示,直接跳转登录页 - 修复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>
325 lines
8.5 KiB
Python
325 lines
8.5 KiB
Python
"""
|
|
系统配置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()
|