diff --git a/VERSION b/VERSION index daba2a9..fdd481e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.70 +VERSION=1.2.71 diff --git a/backend/VERSION b/backend/VERSION index daba2a9..7468c0e 100644 --- a/backend/VERSION +++ b/backend/VERSION @@ -1 +1 @@ -1.2.70 +1.2.71 diff --git a/backend/app/routers/collections.py b/backend/app/routers/collections.py index 7fbf85a..45ccc9b 100644 --- a/backend/app/routers/collections.py +++ b/backend/app/routers/collections.py @@ -276,68 +276,132 @@ def get_stats( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): - """获取藏品统计""" - # 获取所有藏品 - if current_user.role == "admin": - all_collections = db.query(Collection).all() - else: - all_collections = db.query(Collection).filter( - Collection.f99_91_user_id == current_user.f99_90_id - ).all() + """获取藏品统计 - 使用数据库聚合查询优化性能""" + from sqlalchemy import case, func + from sqlalchemy.sql import expression - # 总数 - total_count = len(all_collections) + # 基础过滤条件 + if current_user.role == "admin": + base_filter = True + else: + base_filter = Collection.f99_91_user_id == current_user.f99_90_id + + # 总数 - 使用 COUNT + total_count = db.query(func.count(Collection.f99_90_id)).filter(base_filter).scalar() or 0 # 按分类统计 - from collections import Counter - by_category = Counter(c.f01_03_category for c in all_collections).items() + by_category = db.query( + Collection.f01_03_category, + func.count(Collection.f99_90_id) + ).filter(base_filter).group_by(Collection.f01_03_category).all() # 按状态统计 - by_status = Counter(c.f01_04_status for c in all_collections).items() + by_status = db.query( + Collection.f01_04_status, + func.count(Collection.f99_90_id) + ).filter(base_filter).group_by(Collection.f01_04_status).all() # 按是否评级统计 - by_graded = Counter(c.f03_20_is_graded for c in all_collections).items() + by_graded = db.query( + Collection.f03_20_is_graded, + func.count(Collection.f99_90_id) + ).filter(base_filter).group_by(Collection.f03_20_is_graded).all() - # 新增:8 个分布统计 - by_packaging = Counter(c.f02_12_packaging for c in all_collections if c.f02_12_packaging).items() - by_rarity = Counter(c.f02_13_rarity for c in all_collections if c.f02_13_rarity).items() - by_version = Counter(c.f02_11_version for c in all_collections if c.f02_11_version).items() - by_grading_company = Counter(c.f03_21_grading_company for c in all_collections if c.f03_20_is_graded and c.f03_21_grading_company).items() - by_grading_score = Counter(c.f03_22_grading_score for c in all_collections if c.f03_20_is_graded and c.f03_22_grading_score).items() - by_special_mark = Counter(c.f04_30_special_mark for c in all_collections if c.f04_30_special_mark).items() - by_number_category = Counter(c.f02_14_number_category for c in all_collections if c.f02_14_number_category).items() + # 按包装统计 + by_packaging = db.query( + Collection.f02_12_packaging, + func.count(Collection.f99_90_id) + ).filter(base_filter, Collection.f02_12_packaging.isnot(None)).group_by(Collection.f02_12_packaging).all() - # 总成本: SUM(cost_price + repair_fee + grading_fee) for ALL collections - total_cost = sum( - (c.f05_40_cost_price or 0) + (c.f05_43_repair_fee or 0) + (c.f05_44_grading_fee or 0) - for c in all_collections - ) + # 按稀有度统计 + by_rarity = db.query( + Collection.f02_13_rarity, + func.count(Collection.f99_90_id) + ).filter(base_filter, Collection.f02_13_rarity.isnot(None)).group_by(Collection.f02_13_rarity).all() - # 预期利润: SUM(target_price - cost_price) for collections with target_price > 0 - expected_profit = sum( - (c.f05_41_target_price or 0) - (c.f05_40_cost_price or 0) - for c in all_collections - if c.f05_41_target_price and c.f05_41_target_price > 0 - ) + # 按版本统计 + by_version = db.query( + Collection.f02_11_version, + func.count(Collection.f99_90_id) + ).filter(base_filter, Collection.f02_11_version.isnot(None)).group_by(Collection.f02_11_version).all() - # 已售商品:状态为 sold 且出售价 > 0 - sold_collections = [ - c for c in all_collections - if c.f01_04_status == 'sold' and c.f05_42_goal_price and c.f05_42_goal_price > 0 - ] + # 按评级公司统计 + by_grading_company = db.query( + Collection.f03_21_grading_company, + func.count(Collection.f99_90_id) + ).filter(base_filter, Collection.f03_20_is_graded == True, Collection.f03_21_grading_company.isnot(None)).group_by(Collection.f03_21_grading_company).all() - # 总收入:SUM(出售价) for 已售商品(售价>0) - total_revenue = sum( - c.f05_42_goal_price or 0 - for c in sold_collections - ) + # 按评级分数统计 + by_grading_score = db.query( + Collection.f03_22_grading_score, + func.count(Collection.f99_90_id) + ).filter(base_filter, Collection.f03_20_is_graded == True, Collection.f03_22_grading_score.isnot(None)).group_by(Collection.f03_22_grading_score).all() - # 总利润(已实现利润):SUM(出售价 - 成本价 - 修复费 - 评级费) for 已售商品 - # 单藏品总成本 = 成本价 + 修复费 + 评级费 - total_profit = sum( - (c.f05_42_goal_price or 0) - (c.f05_40_cost_price or 0) - (c.f05_43_repair_fee or 0) - (c.f05_44_grading_fee or 0) - for c in sold_collections - ) + # 按特殊标记统计 + by_special_mark = db.query( + Collection.f04_30_special_mark, + func.count(Collection.f99_90_id) + ).filter(base_filter, Collection.f04_30_special_mark.isnot(None)).group_by(Collection.f04_30_special_mark).all() + + # 按号码分类统计 + by_number_category = db.query( + Collection.f02_14_number_category, + func.count(Collection.f99_90_id) + ).filter(base_filter, Collection.f02_14_number_category.isnot(None)).group_by(Collection.f02_14_number_category).all() + + # 财务统计 - 使用数据库 SUM + # 总成本 = SUM(cost_price + repair_fee + grading_fee) + cost_result = db.query( + func.coalesce(func.sum( + func.coalesce(Collection.f05_40_cost_price, 0) + + func.coalesce(Collection.f05_43_repair_fee, 0) + + func.coalesce(Collection.f05_44_grading_fee, 0) + ), 0) + ).filter(base_filter).scalar() or 0 + + # 预期利润 = SUM(target_price - cost_price) where target_price > 0 + target_result = db.query( + func.coalesce(func.sum( + func.coalesce(Collection.f05_41_target_price, 0) - + func.coalesce(Collection.f05_40_cost_price, 0) + ), 0) + ).filter(base_filter, Collection.f05_41_target_price > 0).scalar() or 0 + + expected_profit = target_result + + # 已售商品过滤条件 + sold_filter = base_filter & (Collection.f01_04_status == 'sold') & (Collection.f05_42_goal_price > 0) + + # 总收入 + total_revenue = db.query( + func.coalesce(func.sum(Collection.f05_42_goal_price), 0) + ).filter(sold_filter).scalar() or 0 + + # 总利润 = SUM(goal_price - cost_price - repair_fee - grading_fee) + total_profit = db.query( + func.coalesce(func.sum( + func.coalesce(Collection.f05_42_goal_price, 0) - + func.coalesce(Collection.f05_40_cost_price, 0) - + func.coalesce(Collection.f05_43_repair_fee, 0) - + func.coalesce(Collection.f05_44_grading_fee, 0) + ), 0) + ).filter(sold_filter).scalar() or 0 + + # 盈亏统计 + profit_count = db.query(func.count(Collection.f99_90_id)).filter( + sold_filter, + Collection.f05_42_goal_price > Collection.f05_40_cost_price + ).scalar() or 0 + + loss_count = db.query(func.count(Collection.f99_90_id)).filter( + sold_filter, + Collection.f05_42_goal_price <= Collection.f05_40_cost_price + ).scalar() or 0 + + # 目标总价 + total_target = db.query( + func.coalesce(func.sum(func.coalesce(Collection.f05_41_target_price, 0)), 0) + ).filter(base_filter).scalar() or 0 return { "totalCount": total_count, @@ -351,16 +415,15 @@ def get_stats( "byGradingScore": [{"score": s, "count": n} for s, n in by_grading_score], "bySpecialMark": [{"mark": m, "count": n} for m, n in by_special_mark], "byNumberCategory": [{"numberCategory": n, "count": c} for n, c in by_number_category], - # 盈亏统计(只统计已售且有价格的藏品) "byProfitLoss": [ - {"type": "profit", "label": "盈利", "count": sum(1 for c in sold_collections if c.f05_42_goal_price and c.f05_40_cost_price and c.f05_42_goal_price > c.f05_40_cost_price)}, - {"type": "loss", "label": "亏损", "count": sum(1 for c in sold_collections if c.f05_42_goal_price and c.f05_40_cost_price and c.f05_42_goal_price <= c.f05_40_cost_price)} + {"type": "profit", "label": "盈利", "count": profit_count}, + {"type": "loss", "label": "亏损", "count": loss_count} ], - "totalCost": total_cost, - "totalTarget": sum(c.f05_41_target_price or 0 for c in all_collections), - "expectedProfit": expected_profit, - "totalRevenue": total_revenue, - "totalProfit": total_profit + "totalCost": float(cost_result), + "totalTarget": float(total_target), + "expectedProfit": float(expected_profit), + "totalRevenue": float(total_revenue), + "totalProfit": float(total_profit) } diff --git a/config/VERSION b/config/VERSION index fb1488c..fdd481e 100644 --- a/config/VERSION +++ b/config/VERSION @@ -1 +1 @@ -VERSION=1.2.70 +VERSION=1.2.71 diff --git a/frontend/package.json b/frontend/package.json index 91579d5..c6552ce 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "jiachenlong-frontend", - "version": "1.2.70", + "version": "1.2.71", "private": true, "description": "甲辰藏品管理系统 - 移动端前端", "scripts": {