baoxiang/backend/app/services/system_service.py
2025-12-16 19:03:48 +08:00

515 lines
18 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
系统配置服务 - 增强版
"""
from sqlalchemy.orm import Session
from sqlalchemy import and_, func
from typing import Dict, Any, List, Optional
from ..models.system import SystemConfig, ConfigType, ConfigCategory
from ..schemas.system import (
SystemConfigCreate,
SystemConfigUpdate,
SystemConfigResponse,
SystemConfigGroup,
SystemConfigSummary
)
class SystemService:
"""系统配置服务"""
# 配置分类显示名称映射
CATEGORY_NAMES = {
ConfigCategory.GAME_ECONOMY: "游戏经济配置",
ConfigCategory.GAME_LOGIC: "游戏逻辑配置",
ConfigCategory.SYSTEM_OPERATIONS: "系统运维配置",
ConfigCategory.UI_DISPLAY: "界面显示配置",
}
# 配置分类描述映射
CATEGORY_DESCRIPTIONS = {
ConfigCategory.GAME_ECONOMY: "游戏经济相关配置,如奖励、低保、抽水比例等",
ConfigCategory.GAME_LOGIC: "游戏逻辑相关配置,如倒计时、活跃宝箱数等",
ConfigCategory.SYSTEM_OPERATIONS: "系统运维相关配置如分页、WebSocket等",
ConfigCategory.UI_DISPLAY: "界面显示相关配置",
}
@staticmethod
def get_config(db: Session, key: str) -> Optional[SystemConfig]:
"""
根据键获取配置
"""
return db.query(SystemConfig).filter(SystemConfig.config_key == key).first()
@staticmethod
def get_all_configs(db: Session) -> List[SystemConfig]:
"""
获取所有配置
"""
return db.query(SystemConfig).order_by(
SystemConfig.category,
SystemConfig.display_order,
SystemConfig.config_key
).all()
@staticmethod
def get_configs_by_category(db: Session, category: ConfigCategory) -> List[SystemConfig]:
"""
根据分类获取配置
"""
return db.query(SystemConfig).filter(
SystemConfig.category == category
).order_by(
SystemConfig.display_order,
SystemConfig.config_key
).all()
@staticmethod
def get_config_groups(db: Session) -> List[SystemConfigGroup]:
"""
获取配置分组
"""
configs = SystemService.get_all_configs(db)
groups = {}
for config in configs:
category = config.category
if category not in groups:
groups[category] = []
groups[category].append(config)
result = []
for category, configs in groups.items():
result.append(
SystemConfigGroup(
category=category,
category_name=SystemService.CATEGORY_NAMES.get(category, str(category)),
category_description=SystemService.CATEGORY_DESCRIPTIONS.get(category, ""),
configs=[SystemConfigResponse.model_validate(c) for c in configs]
)
)
return result
@staticmethod
def create_config(db: Session, config_data: SystemConfigCreate) -> SystemConfig:
"""
创建配置
"""
# 检查键是否已存在
existing_config = db.query(SystemConfig).filter(
SystemConfig.config_key == config_data.config_key
).first()
if existing_config:
raise ValueError("配置键已存在")
db_config = SystemConfig(
config_key=config_data.config_key,
config_value=config_data.config_value,
config_type=config_data.config_type,
category=config_data.category,
description=config_data.description,
is_editable=config_data.is_editable,
is_public=config_data.is_public,
display_order=config_data.display_order,
)
db.add(db_config)
db.commit()
db.refresh(db_config)
return db_config
@staticmethod
def update_config(db: Session, key: str, config_data: SystemConfigUpdate) -> Optional[SystemConfig]:
"""
更新配置
"""
db_config = SystemService.get_config(db, key)
if not db_config:
return None
if not db_config.is_editable:
raise ValueError("该配置项不可编辑")
update_data = config_data.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(db_config, field, value)
db.commit()
db.refresh(db_config)
return db_config
@staticmethod
def delete_config(db: Session, key: str) -> bool:
"""
删除配置
"""
db_config = SystemService.get_config(db, key)
if not db_config:
return False
if not db_config.is_editable:
raise ValueError("该配置项不可删除")
db.delete(db_config)
db.commit()
return True
@staticmethod
def batch_update_configs(db: Session, configs: Dict[str, str]) -> List[SystemConfig]:
"""
批量更新配置
"""
updated_configs = []
for key, value in configs.items():
config = SystemService.update_config(db, key, SystemConfigUpdate(config_value=value))
if config:
updated_configs.append(config)
return updated_configs
@staticmethod
def get_config_summary(db: Session) -> SystemConfigSummary:
"""
获取配置概览
"""
total_configs = db.query(SystemConfig).count()
editable_configs = db.query(SystemConfig).filter(SystemConfig.is_editable == True).count()
public_configs = db.query(SystemConfig).filter(SystemConfig.is_public == True).count()
# 统计各分类的配置数量
category_counts = {}
for category in ConfigCategory:
count = db.query(SystemConfig).filter(SystemConfig.category == category).count()
category_counts[category.value] = count
return SystemConfigSummary(
total_configs=total_configs,
editable_configs=editable_configs,
public_configs=public_configs,
category_counts=category_counts
)
@staticmethod
def get_public_configs(db: Session) -> Dict[str, str]:
"""
获取公开配置(供前端使用)
"""
configs = db.query(SystemConfig).filter(SystemConfig.is_public == True).all()
return {c.config_key: c.config_value for c in configs}
@staticmethod
def get_typed_value(config: SystemConfig) -> Any:
"""
根据配置类型获取正确类型的值
"""
if config.config_type == ConfigType.NUMBER:
try:
return float(config.config_value) if '.' in config.config_value else int(config.config_value)
except ValueError:
return config.config_value
elif config.config_type == ConfigType.BOOLEAN:
return config.config_value.lower() in ('true', '1', 'yes', 'on')
elif config.config_type == ConfigType.JSON:
import json
try:
return json.loads(config.config_value)
except json.JSONDecodeError:
return config.config_value
else:
return config.config_value
@staticmethod
def initialize_default_configs(db: Session):
"""
初始化默认系统配置
"""
from ..models.system import ConfigType, ConfigCategory
# 检查是否已有配置
existing_count = db.query(SystemConfig).count()
if existing_count > 0:
print(f"系统已有 {existing_count} 个配置项,跳过初始化")
return
# 游戏经济配置
game_economy_configs = [
{
"config_key": "GAME_NEW_USER_REWARD",
"config_value": "100000",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_ECONOMY,
"description": "新用户注册奖励(分)",
"is_editable": True,
"is_public": False,
"display_order": 1,
},
{
"config_key": "GAME_DAILY_ALLOWANCE",
"config_value": "5000",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_ECONOMY,
"description": "每日低保(分)",
"is_editable": True,
"is_public": False,
"display_order": 2,
},
{
"config_key": "GAME_ALLOWANCE_THRESHOLD",
"config_value": "1000",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_ECONOMY,
"description": "低保门槛(分)",
"is_editable": True,
"is_public": False,
"display_order": 3,
},
{
"config_key": "GAME_HOUSE_EDGE",
"config_value": "0.10",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_ECONOMY,
"description": "总抽水比例",
"is_editable": True,
"is_public": False,
"display_order": 4,
},
{
"config_key": "GAME_STREAMER_SHARE",
"config_value": "0.05",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_ECONOMY,
"description": "主播分润比例",
"is_editable": True,
"is_public": False,
"display_order": 5,
},
{
"config_key": "GAME_PLATFORM_SHARE",
"config_value": "0.05",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_ECONOMY,
"description": "平台分润比例",
"is_editable": True,
"is_public": False,
"display_order": 6,
},
{
"config_key": "GAME_DAILY_CHECKIN_REWARD",
"config_value": "1000",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_ECONOMY,
"description": "每日签到奖励(分)",
"is_editable": True,
"is_public": False,
"display_order": 7,
},
{
"config_key": "BALANCE_ZERO_REWARD_AMOUNT",
"config_value": "10000",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_ECONOMY,
"description": "余额清零自动发放金额(分)",
"is_editable": True,
"is_public": False,
"display_order": 8,
},
{
"config_key": "ALLOWANCE_RESET_TIME",
"config_value": "00:00",
"config_type": ConfigType.STRING,
"category": ConfigCategory.GAME_ECONOMY,
"description": "低保每日刷新时间(HH:MM格式)",
"is_editable": True,
"is_public": False,
"display_order": 9,
},
]
# 游戏逻辑配置
game_logic_configs = [
{
"config_key": "GAME_DEFAULT_COUNTDOWN",
"config_value": "300",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_LOGIC,
"description": "默认倒计时(秒)",
"is_editable": True,
"is_public": False,
"display_order": 1,
},
{
"config_key": "GAME_MIN_COUNTDOWN",
"config_value": "10",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_LOGIC,
"description": "最小倒计时(秒)",
"is_editable": True,
"is_public": False,
"display_order": 2,
},
{
"config_key": "GAME_MAX_COUNTDOWN",
"config_value": "3600",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_LOGIC,
"description": "最大倒计时(秒)",
"is_editable": True,
"is_public": False,
"display_order": 3,
},
{
"config_key": "GAME_DEFAULT_MAX_ACTIVE_CHESTS",
"config_value": "10",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_LOGIC,
"description": "默认最大活跃宝箱数",
"is_editable": True,
"is_public": False,
"display_order": 4,
},
{
"config_key": "GAME_MIN_COMMISSION_RATE",
"config_value": "0.0",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_LOGIC,
"description": "最小主播抽成(%)",
"is_editable": True,
"is_public": False,
"display_order": 5,
},
{
"config_key": "GAME_MAX_COMMISSION_RATE",
"config_value": "100.0",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_LOGIC,
"description": "最大主播抽成(%)",
"is_editable": True,
"is_public": False,
"display_order": 6,
},
{
"config_key": "GAME_DEFAULT_COMMISSION_RATE",
"config_value": "5.0",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.GAME_LOGIC,
"description": "默认主播抽成(%)",
"is_editable": True,
"is_public": False,
"display_order": 7,
},
]
# 系统运维配置
system_operations_configs = [
{
"config_key": "PAGINATION_DEFAULT_PAGE_SIZE",
"config_value": "20",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.SYSTEM_OPERATIONS,
"description": "默认分页大小",
"is_editable": True,
"is_public": False,
"display_order": 1,
},
{
"config_key": "PAGINATION_ADMIN_PAGE_SIZE",
"config_value": "20",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.SYSTEM_OPERATIONS,
"description": "管理员页面分页大小",
"is_editable": True,
"is_public": False,
"display_order": 2,
},
{
"config_key": "PAGINATION_ANNOUNCEMENT_PAGE_SIZE",
"config_value": "10",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.SYSTEM_OPERATIONS,
"description": "公告页面分页大小",
"is_editable": True,
"is_public": False,
"display_order": 3,
},
{
"config_key": "WS_BROADCAST_INTERVAL",
"config_value": "200",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.SYSTEM_OPERATIONS,
"description": "WebSocket广播间隔(毫秒)",
"is_editable": True,
"is_public": False,
"display_order": 4,
},
{
"config_key": "WS_HEARTBEAT_INTERVAL",
"config_value": "30",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.SYSTEM_OPERATIONS,
"description": "WebSocket心跳间隔(秒)",
"is_editable": True,
"is_public": False,
"display_order": 5,
},
{
"config_key": "WS_CONNECTION_TIMEOUT",
"config_value": "60",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.SYSTEM_OPERATIONS,
"description": "WebSocket连接超时(秒)",
"is_editable": True,
"is_public": False,
"display_order": 6,
},
]
# 界面显示配置
ui_display_configs = [
{
"config_key": "ANNOUNCEMENT_DEFAULT_PRIORITY",
"config_value": "0",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.UI_DISPLAY,
"description": "公告默认优先级",
"is_editable": True,
"is_public": False,
"display_order": 1,
},
{
"config_key": "ANNOUNCEMENT_MAX_PRIORITY",
"config_value": "100",
"config_type": ConfigType.NUMBER,
"category": ConfigCategory.UI_DISPLAY,
"description": "公告最大优先级",
"is_editable": True,
"is_public": False,
"display_order": 2,
},
]
# 合并所有配置
all_configs = (
game_economy_configs +
game_logic_configs +
system_operations_configs +
ui_display_configs
)
# 创建配置项
created_count = 0
for config_data in all_configs:
try:
# 检查配置是否已存在
existing = db.query(SystemConfig).filter(
SystemConfig.config_key == config_data["config_key"]
).first()
if not existing:
db_config = SystemConfig(**config_data)
db.add(db_config)
created_count += 1
except Exception as e:
print(f"创建配置 {config_data['config_key']} 失败: {e}")
db.commit()
print(f"成功初始化 {created_count} 个默认配置项")