Files
chat/backend/app/services/admin_service.py
T
2026-06-12 23:14:12 +08:00

190 lines
7.3 KiB
Python

"""管理后台服务"""
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()