Files
DP/Server/app/api/v1/checkin.py

232 lines
7.8 KiB
Python
Raw Permalink 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.
# -*- coding: utf-8 -*-
"""
签到接口
功能:每日签到、签到状态查询、签到日历
"""
from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel
from datetime import date, datetime, timedelta
from sqlalchemy.orm import Session
from sqlalchemy import func
from app.db import get_db
from app.models.user import User
from app.models.business import CheckInConfig, VipConfig, CheckInRecord, PointsHistory
from app.core.security import get_current_user
router = APIRouter()
# ==================== 签到功能 ====================
@router.post("/checkin/daily")
async def daily_checkin(db: Session = Depends(get_db), current_username: str = Depends(get_current_user)):
"""每日签到"""
# 1. 获取用户信息
user = db.query(User).filter(User.username == current_username).first()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
# 2. 检查今日是否已签到
today = date.today()
if user.last_check_in_date == today:
raise HTTPException(status_code=400, detail="今日已签到,明天再来吧")
# 3. 计算连续天数
consecutive_days = user.consecutive_check_in if user.consecutive_check_in else 0
total_days = user.total_check_in_days if user.total_check_in_days else 0
yesterday = today - timedelta(days=1)
if user.last_check_in_date == yesterday:
# 连续签到
consecutive_days += 1
else:
# 中断了,重新开始
consecutive_days = 1
total_days += 1
# 4. 从配置表获取奖励
reward_config = db.query(CheckInConfig)\
.filter(CheckInConfig.consecutive_days <= consecutive_days, CheckInConfig.enabled == True)\
.order_by(CheckInConfig.consecutive_days.desc())\
.first()
if not reward_config:
# 如果没有配置默认给10积分
base_points = 10
bonus_points = 0
total_points = 10
else:
base_points = reward_config.base_points
bonus_points = reward_config.bonus_points
total_points = reward_config.total_points
# 5. 应用VIP倍数
vip_multiplier = 1.0
if user.vip_type and user.vip_type in ['vip', 'svip']:
vip_config = db.query(VipConfig).filter(VipConfig.vip_type == user.vip_type).first()
if vip_config:
vip_multiplier = float(vip_config.points_multiplier)
points_earned = int(total_points * vip_multiplier)
current_points = user.points if user.points else 0
new_balance = current_points + points_earned
# 6. 更新用户数据
user.points = new_balance
user.total_check_in_days = total_days
user.consecutive_check_in = consecutive_days
user.last_check_in_date = today
# 7. 记录签到记录
checkin_record = CheckInRecord(
user_id=user.id,
username=current_username,
check_in_date=today,
points_earned=points_earned,
consecutive_days=consecutive_days,
vip_multiplier=vip_multiplier
)
db.add(checkin_record)
# 8. 记录积分历史
points_history = PointsHistory(
user_id=user.id,
username=current_username,
type='checkin',
amount=points_earned,
balance=new_balance,
description=f"每日签到奖励(连续{consecutive_days}天)"
)
db.add(points_history)
db.commit()
# 9. 返回结果
return {
"code": 200,
"data": {
"success": True,
"points_earned": points_earned,
"base_points": base_points,
"bonus_points": bonus_points,
"vip_multiplier": vip_multiplier,
"consecutive_days": consecutive_days,
"total_check_in_days": total_days,
"total_points": new_balance,
"message": f"签到成功!连续签到{consecutive_days}天,获得{points_earned}积分"
}
}
@router.get("/checkin/config")
async def get_checkin_config(db: Session = Depends(get_db)):
"""获取签到奖励配置(公开)"""
configs = db.query(CheckInConfig)\
.filter(CheckInConfig.enabled == True)\
.order_by(CheckInConfig.consecutive_days)\
.all()
result = []
for config in configs:
result.append({
"consecutive_days": config.consecutive_days,
"base_points": config.base_points,
"bonus_points": config.bonus_points,
"total_points": config.total_points
})
return {
"code": 200,
"data": result
}
@router.get("/checkin/status")
async def get_checkin_status(db: Session = Depends(get_db), current_username: str = Depends(get_current_user)):
"""获取签到状态"""
user = db.query(User).filter(User.username == current_username).first()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
today = date.today()
today_checked = (user.last_check_in_date == today)
return {
"code": 200,
"data": {
"today_checked": today_checked,
"consecutive_days": user.consecutive_check_in if user.consecutive_check_in else 0,
"total_days": user.total_check_in_days if user.total_check_in_days else 0,
"total_points": user.points if user.points else 0,
"last_check_in_date": user.last_check_in_date.isoformat() if user.last_check_in_date else None
}
}
@router.get("/checkin/calendar/{year}/{month}")
async def get_checkin_calendar(year: int, month: int, db: Session = Depends(get_db), current_username: str = Depends(get_current_user)):
"""获取签到日历"""
user = db.query(User).filter(User.username == current_username).first()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
# 使用 SQLAlchemy 提取日期部分
# 注意SQLite 和 MySQL 的日期函数不同
# 为了兼容性,这里我们查询该月范围内的所有记录,然后在 Python 中处理
import calendar
_, last_day = calendar.monthrange(year, month)
start_date = date(year, month, 1)
end_date = date(year, month, last_day)
records = db.query(CheckInRecord)\
.filter(
CheckInRecord.user_id == user.id,
CheckInRecord.check_in_date >= start_date,
CheckInRecord.check_in_date <= end_date
).all()
checked_dates = [record.check_in_date.day for record in records]
return {
"code": 200,
"data": {
"year": year,
"month": month,
"checked_dates": checked_dates
}
}
@router.get("/checkin/history")
async def get_checkin_history(page: int = 1, limit: int = 10, db: Session = Depends(get_db), current_username: str = Depends(get_current_user)):
"""签到记录"""
user = db.query(User).filter(User.username == current_username).first()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
offset = (page - 1) * limit
total = db.query(func.count(CheckInRecord.id)).filter(CheckInRecord.user_id == user.id).scalar()
records = db.query(CheckInRecord)\
.filter(CheckInRecord.user_id == user.id)\
.order_by(CheckInRecord.check_in_date.desc())\
.offset(offset)\
.limit(limit)\
.all()
result_records = []
for record in records:
result_records.append({
"check_in_date": record.check_in_date.isoformat(),
"points_earned": record.points_earned,
"consecutive_days": record.consecutive_days,
"created_at": record.created_at.isoformat() if record.created_at else None
})
return {
"code": 200,
"data": {
"total": total,
"records": result_records
}
}