Files
meijiaka-zy/python-api/app/crud/point_transaction.py
T
小鱼开发 04e467e433 feat(points): 积分系统收尾 + 充值弹窗改造 + 命名统一
后端:
- 微信回调 db.commit 失败仍返回 SUCCESS,避免无限重试
- recharge() 加 order_id 幂等保护,防重复充值
- time_expire 使用北京时间(UTC+8),修复时区 bug
- 充值档位后端配置化(points-config.yaml + /recharge-options API)
- 代码审查 20 项修复(认证加固、扣费顺序、错误响应、状态同步等)

前端:
- 充值弹窗:自动轮询 + 【我已支付】手动兜底
- 二维码倒计时显示,过期后遮罩 + 刷新按钮
- 充值档位从后端动态加载
- 去掉 select/qrcode 弹窗标题,金额红色突出显示
- 全项目命名统一(视频生成/压制成片/配音合成/声音复刻等)
- Modal 关闭按钮独立于 title 显示
2026-05-09 21:29:35 +08:00

101 lines
3.1 KiB
Python

"""
积分流水 CRUD
=============
只增不改,用于审计和对账。
"""
from datetime import datetime
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.crud.base import CRUDBase
from app.models.point_transaction import PointTransaction
class PointTransactionCRUD(CRUDBase[PointTransaction]):
"""积分流水数据访问对象"""
def __init__(self) -> None:
super().__init__(PointTransaction)
async def get_by_user_id(
self,
db: AsyncSession,
*,
user_id: str,
skip: int = 0,
limit: int = 50,
tx_type: str | None = None,
category: str | None = None,
start_time: datetime | None = None,
end_time: datetime | None = None,
) -> list[PointTransaction]:
"""根据用户 ID 获取流水记录(支持筛选和分页,按时间倒序)"""
stmt = select(PointTransaction).where(PointTransaction.user_id == user_id)
if tx_type:
stmt = stmt.where(PointTransaction.type == tx_type)
if category:
stmt = stmt.where(PointTransaction.category == category)
if start_time:
stmt = stmt.where(PointTransaction.created_at >= start_time)
if end_time:
stmt = stmt.where(PointTransaction.created_at <= end_time)
stmt = stmt.order_by(PointTransaction.created_at.desc()).offset(skip).limit(limit)
result = await db.execute(stmt)
return list(result.scalars().all())
async def count_by_user_id(
self,
db: AsyncSession,
*,
user_id: str,
tx_type: str | None = None,
category: str | None = None,
start_time: datetime | None = None,
end_time: datetime | None = None,
) -> int:
"""根据筛选条件统计流水记录总数"""
from sqlalchemy import func
stmt = select(func.count(PointTransaction.id)).where(PointTransaction.user_id == user_id)
if tx_type:
stmt = stmt.where(PointTransaction.type == tx_type)
if category:
stmt = stmt.where(PointTransaction.category == category)
if start_time:
stmt = stmt.where(PointTransaction.created_at >= start_time)
if end_time:
stmt = stmt.where(PointTransaction.created_at <= end_time)
result = await db.execute(stmt)
return result.scalar() or 0
async def get_by_source(
self,
db: AsyncSession,
*,
user_id: str,
source_type: str,
source_id: str,
) -> list[PointTransaction]:
"""根据消费来源查询流水(用于查询某次 AI 调用的扣费记录)"""
result = await db.execute(
select(PointTransaction)
.where(
PointTransaction.user_id == user_id,
PointTransaction.source_type == source_type,
PointTransaction.source_id == source_id,
)
.order_by(PointTransaction.created_at.desc())
)
return list(result.scalars().all())
# 导出实例
point_transaction = PointTransactionCRUD()