xiangqinxiaochengxu/backend/app/services/admin_service.py

264 lines
8.3 KiB
Python
Raw Normal View History

2026-04-17 10:49:14 +08:00
from datetime import datetime
from sqlalchemy import or_, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.admin import Admin
from app.models.match import Match
from app.models.system_config import SystemConfig
from app.models.user import User
from app.schemas.admin import AdminAuditRequest, AdminBanRequest, AdminCreateRequest
from app.utils.security import create_access_token, hash_password, verify_password
async def admin_login(session: AsyncSession, username: str, password: str) -> dict:
result = await session.execute(select(Admin).where(Admin.username == username, Admin.is_active == 1))
admin = result.scalar_one_or_none()
if admin is None or not verify_password(password, admin.password_hash):
raise ValueError("账号或密码错误")
admin.last_login = datetime.now()
session.add(admin)
await session.commit()
token = create_access_token({"admin_id": admin.id, "role": admin.role})
return {
"access_token": token,
"token_type": "bearer",
"admin_id": admin.id,
"username": admin.username,
"role": admin.role,
}
async def list_admin_accounts(session: AsyncSession) -> list[Admin]:
result = await session.execute(select(Admin).order_by(Admin.created_at.asc()))
return result.scalars().all()
async def create_admin_account(session: AsyncSession, payload: AdminCreateRequest) -> Admin:
exists = await session.execute(select(Admin).where(Admin.username == payload.username))
if exists.scalar_one_or_none() is not None:
raise ValueError("管理员用户名已存在")
admin = Admin(
username=payload.username,
password_hash=hash_password(payload.password),
role=payload.role,
is_active=1,
)
session.add(admin)
await session.commit()
await session.refresh(admin)
return admin
async def update_admin_status(session: AsyncSession, admin_id: int, is_active: int) -> Admin | None:
admin = await session.get(Admin, admin_id)
if admin is None:
return None
admin.is_active = is_active
session.add(admin)
await session.commit()
await session.refresh(admin)
return admin
async def reset_admin_password(session: AsyncSession, admin_id: int, password: str) -> Admin | None:
admin = await session.get(Admin, admin_id)
if admin is None:
return None
admin.password_hash = hash_password(password)
session.add(admin)
await session.commit()
await session.refresh(admin)
return admin
async def list_users(
session: AsyncSession,
*,
keyword: str | None = None,
audit_status: int | None = None,
gender: int | None = None,
only_pending: bool = False,
) -> list[User]:
stmt = select(User)
if only_pending:
stmt = stmt.where(User.audit_status == 1)
if audit_status is not None:
stmt = stmt.where(User.audit_status == audit_status)
if gender is not None:
stmt = stmt.where(User.gender == gender)
if keyword:
like_keyword = f"%{keyword}%"
stmt = stmt.where(or_(User.nickname.like(like_keyword), User.real_name.like(like_keyword)))
stmt = stmt.order_by(User.updated_at.asc())
result = await session.execute(stmt)
return result.scalars().all()
async def audit_user(
session: AsyncSession,
user_id: int,
admin_id: int,
payload: AdminAuditRequest,
) -> User | None:
user = await session.get(User, user_id)
if user is None:
return None
if payload.audit_status not in {2, 3}:
raise ValueError("审核状态仅支持通过或驳回")
if payload.audit_status == 3 and not payload.audit_remark:
raise ValueError("驳回时必须填写原因")
user.audit_status = payload.audit_status
user.audit_remark = payload.audit_remark
user.audit_time = datetime.now()
user.auditor_id = admin_id
session.add(user)
await session.commit()
await session.refresh(user)
return user
async def get_user_detail(session: AsyncSession, user_id: int) -> User | None:
return await session.get(User, user_id)
async def ban_user(session: AsyncSession, user_id: int, payload: AdminBanRequest) -> User | None:
user = await session.get(User, user_id)
if user is None:
return None
user.is_active = payload.is_active
user.ban_reason = payload.ban_reason if payload.is_active == 0 else None
session.add(user)
await session.commit()
await session.refresh(user)
return user
async def list_admin_matches(
session: AsyncSession,
*,
user_id: int | None = None,
start_date: datetime | None = None,
end_date: datetime | None = None,
) -> list[dict]:
stmt = select(Match)
if user_id is not None:
stmt = stmt.where(or_(Match.user_a_id == user_id, Match.user_b_id == user_id))
if start_date is not None:
stmt = stmt.where(Match.matched_at >= start_date)
if end_date is not None:
stmt = stmt.where(Match.matched_at < end_date)
result = await session.execute(stmt.order_by(Match.matched_at.desc()))
matches = result.scalars().all()
data = []
for item in matches:
user_a = await session.get(User, item.user_a_id)
user_b = await session.get(User, item.user_b_id)
data.append(
{
"match_id": item.id,
"matched_at": item.matched_at.isoformat() if item.matched_at else None,
"match_score": float(item.match_score) if item.match_score is not None else None,
"match_type": item.match_type,
"user_a": {
"id": user_a.id if user_a else item.user_a_id,
"nickname": user_a.nickname if user_a else None,
},
"user_b": {
"id": user_b.id if user_b else item.user_b_id,
"nickname": user_b.nickname if user_b else None,
},
}
)
return data
DEFAULT_SYSTEM_CONFIGS = {
"ai_weights": {
"age": 0.20,
"hobbies": 0.18,
"values": 0.18,
"education": 0.14,
"activity": 0.12,
"location": 0.10,
"height": 0.08,
},
"daily_recommend_limit": 10,
"matches_per_activity_limit": 3,
2026-05-16 19:01:44 +08:00
"api_base_url": "https://ghxiangqin.com/api/v1",
2026-04-17 10:49:14 +08:00
"customer_service_wechat": "service_wechat_001",
}
async def get_system_configs(session: AsyncSession) -> dict:
result = await session.execute(select(SystemConfig))
items = result.scalars().all()
if not items:
for key, value in DEFAULT_SYSTEM_CONFIGS.items():
session.add(
SystemConfig(config_key=key, config_value=json_dumps(value), description=f"default {key}")
)
await session.commit()
result = await session.execute(select(SystemConfig))
items = result.scalars().all()
configs = {}
for item in items:
configs[item.config_key] = json_loads(item.config_value)
return configs
async def update_system_configs(session: AsyncSession, configs: dict) -> dict:
result = await session.execute(select(SystemConfig))
items = {item.config_key: item for item in result.scalars().all()}
for key, value in configs.items():
if key in items:
items[key].config_value = json_dumps(value)
session.add(items[key])
else:
session.add(SystemConfig(config_key=key, config_value=json_dumps(value), description=f"custom {key}"))
await session.commit()
return await get_system_configs(session)
async def get_system_config_value(session: AsyncSession, key: str, default=None):
result = await session.execute(select(SystemConfig).where(SystemConfig.config_key == key))
item = result.scalar_one_or_none()
if item is None:
return default
try:
return json_loads(item.config_value)
except Exception:
return default
async def get_system_config_value(session: AsyncSession, key: str, default=None):
result = await session.execute(select(SystemConfig).where(SystemConfig.config_key == key))
item = result.scalar_one_or_none()
if item is None:
return default
try:
return json_loads(item.config_value)
except Exception:
return default
def json_dumps(value) -> str:
import json
return json.dumps(value, ensure_ascii=False)
def json_loads(value: str):
import json
return json.loads(value)