"""管理后台服务""" import uuid from datetime import datetime, timezone from sqlalchemy import select, func, delete from sqlalchemy.ext.asyncio import AsyncSession from app.config import settings from app.models.user import User from app.models.message import Message from app.models.conversation import Conversation from app.models.system_config import SystemConfig from app.utils.security import verify_password, hash_password, create_access_token class AdminService: def __init__(self, db: AsyncSession = None): self.db = db async def init_system_config(self): """初始化系统默认配置""" if not self.db: return defaults = { "platform_name": "青叶", "announcement": "", "max_upload_size_mb": "10", "allow_registration": "true", "admin_password_hash": hash_password(settings.ADMIN_PASSWORD), } for key, value in defaults.items(): result = await self.db.execute( select(SystemConfig).where(SystemConfig.key == key) ) if not result.scalars().first(): self.db.add(SystemConfig(id=str(uuid.uuid4()), key=key, value=value)) async def login(self, password: str) -> str | None: """管理员登录(仅密码)""" result = await self.db.execute( select(SystemConfig).where(SystemConfig.key == "admin_password_hash") ) config = result.scalars().first() if not config: return None if not verify_password(password, config.value): return None # 生成管理员 Token token = create_access_token({ "sub": "admin", "username": "admin", "is_admin": True, }) return token async def get_dashboard_stats(self) -> dict: """获取仪表盘统计数据""" total_users = await self.db.execute(select(func.count(User.id))) online_users = await self.db.execute( select(func.count(User.id)).where(User.status == "online") ) total_messages = await self.db.execute(select(func.count(Message.id))) total_conversations = await self.db.execute(select(func.count(Conversation.id))) today = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0) today_messages = await self.db.execute( select(func.count(Message.id)).where(Message.created_at >= today) ) seven_days_ago = datetime.utcnow() - __import__("datetime").timedelta(days=7) new_users_7d = await self.db.execute( select(func.count(User.id)).where(User.created_at >= seven_days_ago) ) return { "total_users": total_users.scalar() or 0, "online_users": online_users.scalar() or 0, "total_messages": total_messages.scalar() or 0, "today_messages": today_messages.scalar() or 0, "total_conversations": total_conversations.scalar() or 0, "new_users_7d": new_users_7d.scalar() or 0, } async def get_trend_data(self, metric: str, days: int = 7) -> list[dict]: """获取趋势数据""" from sqlalchemy import cast, Date trends = [] for i in range(days - 1, -1, -1): day = (datetime.utcnow() - __import__("datetime").timedelta(days=i)).date() day_start = datetime.combine(day, __import__("datetime").time.min) day_end = datetime.combine(day, __import__("datetime").time.max) if metric == "online": # 简化:使用当前在线数 count = await self.db.execute( select(func.count(User.id)).where(User.status == "online") ) value = count.scalar() or 0 elif metric == "messages": count = await self.db.execute( select(func.count(Message.id)).where( Message.created_at >= day_start, Message.created_at <= day_end, ) ) value = count.scalar() or 0 elif metric == "registrations": count = await self.db.execute( select(func.count(User.id)).where( User.created_at >= day_start, User.created_at <= day_end, ) ) value = count.scalar() or 0 else: value = 0 trends.append({"date": day.isoformat(), "value": value}) return trends async def get_users_list(self, page: int = 1, page_size: int = 20, search: str | None = None, status: str | None = None) -> dict: """获取用户列表(管理后台)""" query = select(User) count_query = select(func.count(User.id)) if search: query = query.where(User.username.ilike(f"%{search}%")) count_query = count_query.where(User.username.ilike(f"%{search}%")) if status == "online": query = query.where(User.status == "online") count_query = count_query.where(User.status == "online") elif status == "banned": query = query.where(User.is_banned == True) count_query = count_query.where(User.is_banned == True) total = (await self.db.execute(count_query)).scalar() or 0 result = await self.db.execute( query.order_by(User.created_at.desc()) .offset((page - 1) * page_size) .limit(page_size) ) users = [] for u in result.scalars().all(): users.append({ "id": u.id, "username": u.username, "email": u.email, "avatar_url": u.avatar_url, "status": u.status, "is_banned": u.is_banned, "banned_reason": u.banned_reason, "last_seen_at": u.last_seen_at, "created_at": u.created_at, }) return {"items": users, "total": total, "page": page, "page_size": page_size} async def ban_user(self, user_id: str, is_banned: bool, reason: str | None = None): """封禁/解封用户""" result = await self.db.execute(select(User).where(User.id == user_id)) user = result.scalars().first() if not user: raise ValueError("用户不存在") user.is_banned = is_banned user.banned_reason = reason if is_banned else None async def delete_user(self, user_id: str): """删除用户""" await self.db.execute(delete(User).where(User.id == user_id)) async def get_all_configs(self) -> list[dict]: """获取所有系统配置""" result = await self.db.execute(select(SystemConfig)) return [{"key": c.key, "value": c.value} for c in result.scalars().all()] async def update_configs(self, configs: dict[str, str]): """更新系统配置""" for key, value in configs.items(): result = await self.db.execute( select(SystemConfig).where(SystemConfig.key == key) ) config = result.scalars().first() if config: config.value = value config.updated_at = datetime.utcnow()