Files
小鱼开发 c6eba97b43 feat(points): 积分消耗系统全链路集成
后端:
- 简化积分服务: 删除 freeze/settle/refund, 保留 consume/recharge/expire
- 计费配置化: config/points-config.yaml 驱动 fixed/duration/free 三种模式
- TTS 时长探测: app/utils/audio_utils.py (httpx + mutagen 纯 Python)
- Python 层扣费: script(5)/polish(1)/title(1)/voice_clone(200)/tts(按秒)/video(按秒)
- 字幕 free_services: caption/auto_align 不扣费
- 新增 POST /points/consume 端点(402余额预检)
- 新增 check_balance + /points/cost 返回 sufficient/balance/required
- 新增 expire_batches 定时回收, 接入 scheduler main(每5分钟)
- 删除废弃 tts_handler.py
- Alembic 迁移: 删除 frozen/total_refunded 字段
- 同步 requirements.lock 添加 mutagen

前端:
- Rust/IPC 层扣费: compose(5)/subtitle_burn(2)/cover_design(2)
- 字幕打轴改异步: 走 scheduler subtitle handler
- 对口型传 duration: VideoGeneration 传 actualDuration
- 创建 pointStore: 全局余额 + fetchBalance + 充值弹窗控制
- 402 欠费弹 RechargeModal: VideoGeneration/SubtitleBurning/CoverDesign
- 修复 VoiceDubbing.tsx 类型错误 (alignResult never)
- 同步 PointBalance 类型(删除 frozen/available/totalRefunded)

Refs: 积分消耗集成收尾
2026-05-09 15:42:54 +08:00

55 lines
1.2 KiB
Python

"""
积分批次表
==========
每笔充值产生一个批次,记录初始积分、剩余积分、过期时间。
消费时按过期时间升序扣减(FIFO,先充先用)。
"""
import uuid
from datetime import datetime
from sqlalchemy import DateTime, String
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column
from app.models.base import BaseModelBigInt
class PointBatch(BaseModelBigInt):
"""积分批次"""
__tablename__ = "mjk_point_batches"
user_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
nullable=False,
comment="用户 ID",
)
amount: Mapped[int] = mapped_column(
default=0,
nullable=False,
comment="初始积分",
)
remaining: Mapped[int] = mapped_column(
default=0,
nullable=False,
comment="剩余可用积分",
)
expired_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
nullable=False,
comment="过期时间(created_at + 180 天)",
)
source: Mapped[str] = mapped_column(
String(32),
default="wxpay",
nullable=False,
comment="来源:wxpay / invite / gift / compensation",
)