From 83b10945c86eaa146e2a33102f2cc31e3eb373dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=B1=BC=E5=BC=80=E5=8F=91?= Date: Sat, 16 May 2026 09:46:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(points):=20=E6=96=B0=E5=A2=9E=E4=BB=8A?= =?UTF-8?q?=E6=97=A5=E6=B6=88=E8=80=97=E6=8E=A5=E5=8F=A3=20+=20=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E4=B8=AD=E5=BF=83=E5=AD=97=E4=BD=93=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后端: - CRUD 新增 sum_consumed_today() 方法,统计用户今日消费积分总和 - API 新增 GET /points/today-consumed 路由 前端: - 个人中心积分数字从 40px 改为 32px - 今日消耗从本地计算改为调用后端接口 --- python-api/app/api/v1/points.py | 12 ++++++++++++ python-api/app/crud/point_transaction.py | 24 ++++++++++++++++++++++-- tauri-app/src/api/modules/points.ts | 9 +++++++++ tauri-app/src/pages/Profile/Profile.tsx | 24 +++++++++--------------- 4 files changed, 52 insertions(+), 17 deletions(-) diff --git a/python-api/app/api/v1/points.py b/python-api/app/api/v1/points.py index 544a19f..965615a 100644 --- a/python-api/app/api/v1/points.py +++ b/python-api/app/api/v1/points.py @@ -497,6 +497,18 @@ async def get_points_rules( +# ── 今日消费统计 ────────────────────────────────────── + +@router.get("/today-consumed", response_model=ApiResponse[dict]) +async def get_today_consumed( + db: AsyncSession = Depends(get_db), + current_user: User = Depends(get_current_user), +): + """获取当前用户今日消费积分总额""" + total = await point_transaction.sum_consumed_today(db, user_id=current_user.id) + return success_response(data={"total": total}) + + # ── 直接消费扣费(前端/Rust 层调用)─────────────────── @router.post("/consume", response_model=ApiResponse[dict]) diff --git a/python-api/app/crud/point_transaction.py b/python-api/app/crud/point_transaction.py index 2e6e7db..623b7cc 100644 --- a/python-api/app/crud/point_transaction.py +++ b/python-api/app/crud/point_transaction.py @@ -5,9 +5,9 @@ 只增不改,用于审计和对账。 """ -from datetime import datetime +from datetime import datetime, time -from sqlalchemy import select +from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.crud.base import CRUDBase @@ -101,6 +101,26 @@ class PointTransactionCRUD(CRUDBase[PointTransaction]): ) return list(result.scalars().all()) + async def sum_consumed_today( + self, + db: AsyncSession, + *, + user_id: str, + ) -> int: + """统计用户今日消费积分总和""" + now = datetime.now() + start_of_day = datetime.combine(now.date(), time.min) + stmt = ( + select(func.coalesce(func.sum(PointTransaction.amount), 0)) + .where( + PointTransaction.user_id == user_id, + PointTransaction.type == "consume", + PointTransaction.created_at >= start_of_day, + ) + ) + result = await db.execute(stmt) + return result.scalar() or 0 + # 导出实例 point_transaction = PointTransactionCRUD() diff --git a/tauri-app/src/api/modules/points.ts b/tauri-app/src/api/modules/points.ts index 10045e3..98f3282 100644 --- a/tauri-app/src/api/modules/points.ts +++ b/tauri-app/src/api/modules/points.ts @@ -165,6 +165,15 @@ export const pointsApi = { ); }, + /** + * GET /points/today-consumed + * + * 获取今日消费积分总额。 + */ + getTodayConsumed: async (): Promise<{ total: number }> => { + return client.get<{ total: number }>('/points/today-consumed'); + }, + /** * 直接消费积分(前端/Rust 层业务扣费) * POST /points/consume diff --git a/tauri-app/src/pages/Profile/Profile.tsx b/tauri-app/src/pages/Profile/Profile.tsx index 77e4828..161993d 100644 --- a/tauri-app/src/pages/Profile/Profile.tsx +++ b/tauri-app/src/pages/Profile/Profile.tsx @@ -44,6 +44,7 @@ export default function Profile() { const [user, setUser] = useState(null); const [balance, setBalance] = useState(null); const [recentTx, setRecentTx] = useState([]); + const [todayConsumed, setTodayConsumed] = useState(0); const [loading, setLoading] = useState(true); const [showRechargeModal, setShowRechargeModal] = useState(false); @@ -66,10 +67,12 @@ export default function Profile() { } if (balanceData) {setBalance(balanceData);} - const txData = await pointsApi - .getTransactions({ page: 1, pageSize: 10 }) - .catch(() => null); + const [txData, todayData] = await Promise.all([ + pointsApi.getTransactions({ page: 1, pageSize: 10 }).catch(() => null), + pointsApi.getTodayConsumed().catch(() => null), + ]); if (txData) {setRecentTx(txData.items);} + if (todayData) {setTodayConsumed(todayData.total);} } catch (e) { console.error('[Profile] 加载数据失败:', e); } finally { @@ -212,7 +215,7 @@ export default function Profile() {
剩余积分
-
+
{balance?.balance ?? 0}
@@ -220,17 +223,8 @@ export default function Profile() {
今日消耗
-
- {(() => { - const todayStr = new Date().toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' }).replace(/\//g, '-'); - return recentTx - .filter(tx => { - if (tx.type !== 'consume') return false; - const txDate = new Date(tx.createdAt).toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' }).replace(/\//g, '-'); - return txDate === todayStr; - }) - .reduce((sum, tx) => sum + tx.amount, 0); - })()} +
+ {todayConsumed}