From 79ce79b92c9537f006955466cb04369a3c6928c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B2=E8=BE=B0=E7=94=9F=E4=BA=A7?= Date: Wed, 8 Apr 2026 14:39:10 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=81=A2=E5=A4=8Dcollections.py?= =?UTF-8?q?=E5=B9=B6=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/routers/collections.py | 197 ++++++++++++----------------- 1 file changed, 79 insertions(+), 118 deletions(-) diff --git a/backend/app/routers/collections.py b/backend/app/routers/collections.py index 704ec2b..8479da6 100644 --- a/backend/app/routers/collections.py +++ b/backend/app/routers/collections.py @@ -64,30 +64,25 @@ def to_camel_case(data: dict) -> dict: # 编码生成函数 def generate_code(version: str, user_id: str, db: Session) -> str: - """自动生成藏品编号 - 按用户独立编码,使用行锁防止并发冲突""" + """自动生成藏品编号 - 按用户独立编码""" import re - from sqlalchemy import text - # 使用 FOR UPDATE 行锁防止并发冲突 - result = db.execute( - text(""" - SELECT f01_02_code FROM collections - WHERE f99_91_user_id = :user_id - AND f01_02_code IS NOT NULL - AND f01_02_code ~ '^\\d{4,5}$' - ORDER BY f01_02_code::int DESC - LIMIT 1 - FOR UPDATE - """), - {"user_id": user_id} - ).fetchone() + # 查询当前用户的非空编码(不与其他用户混算) + user_codes = db.query(Collection.f01_02_code).filter( + Collection.f01_02_code.isnot(None), + Collection.f99_91_user_id == user_id + ).all() max_num = 0 - if result and result[0]: - try: - max_num = int(result[0]) - except (ValueError, TypeError): - pass + for (code,) in user_codes: + # 处理纯数字编码(支持4位和5位) + if re.match(r'^\d{4,5}$', code): + try: + num = int(code) + if num > max_num: + max_num = num + except (ValueError, TypeError): + pass # 当前用户最大号 +1 next_num = max_num + 1 @@ -138,6 +133,10 @@ def get_collections( from sqlalchemy.orm import joinedload # 管理员默认查看全库,普通用户只看自己 + if current_user is None: + return {"error": "Unauthorized", "totalCount": 0} + + # 获取所有藏品 if current_user.role == "admin": # 联表查询获取用户名 query = db.query(Collection, User.f01_01_name.label('owner_name')).join( @@ -207,7 +206,11 @@ def get_collections( data_list = [] for item in data: # 处理联表查询结果 - if current_user.role == "admin": + if current_user is None: + return {"error": "Unauthorized", "totalCount": 0} + + # 获取所有藏品 + if current_user.role == "admin": collection_item, owner_name = item else: collection_item = item @@ -281,110 +284,72 @@ def get_stats( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): - """获取藏品统计 - 使用数据库聚合查询优化性能""" - from sqlalchemy import func, case + """获取藏品统计""" + # 获取所有藏品 + if current_user is None: + return {"error": "Unauthorized", "totalCount": 0} - # 基础查询条件 - 检查用户是否登录 - if current_user is None or not hasattr(current_user, 'role'): - base_filter = False # 未登录用户不能查看任何藏品 + # 获取所有藏品 + if current_user.role == "admin": + all_collections = db.query(Collection).all() else: - base_filter = True if current_user.role == "admin" else Collection.f99_91_user_id == current_user.f99_90_id + all_collections = db.query(Collection).filter( + Collection.f99_91_user_id == current_user.f99_90_id + ).all() # 总数 - total_count = db.query(func.count(Collection.f99_90_id)).filter(base_filter).scalar() or 0 + total_count = len(all_collections) # 按分类统计 - by_category = db.query( - Collection.f01_03_category, - func.count(Collection.f99_90_id) - ).filter(base_filter).group_by(Collection.f01_03_category).all() + from collections import Counter + by_category = Counter(c.f01_03_category 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_status = Counter(c.f01_04_status 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() + by_graded = Counter(c.f03_20_is_graded for c in all_collections).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() + # 新增: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_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(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_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() + # 预期利润: 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_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() + # 已售商品:状态为 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_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 已售商品(售价>0) + total_revenue = sum( + c.f05_42_goal_price 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() - - # 总成本 - cost_result = db.query( - func.sum( - (Collection.f05_40_cost_price or 0) + - (Collection.f05_43_repair_fee or 0) + - (Collection.f05_44_grading_fee or 0) - ) - ).filter(base_filter).scalar() or 0 - - # 预期利润 - target_result = db.query( - func.sum(Collection.f05_41_target_price) - ).filter(base_filter, Collection.f05_41_target_price > 0).scalar() or 0 - - expected_profit = target_result - cost_result - - # 已售商品统计 - sold_filter = (Collection.f01_04_status == 'sold') & (Collection.f05_42_goal_price > 0) - if current_user.role != "admin": - sold_filter = sold_filter & (Collection.f99_91_user_id == current_user.f99_90_id) - - total_revenue = db.query(func.sum(Collection.f05_42_goal_price)).filter(sold_filter).scalar() or 0 - - # 总利润 - total_profit = db.query( - func.sum( - (Collection.f05_42_goal_price or 0) - - (Collection.f05_40_cost_price or 0) - - (Collection.f05_43_repair_fee or 0) - - (Collection.f05_44_grading_fee or 0) - ) - ).filter(sold_filter).scalar() or 0 + # 总利润(已实现利润):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 + ) return { "totalCount": total_count, @@ -398,17 +363,13 @@ 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": db.query(func.count(Collection.f99_90_id)).filter( - sold_filter, Collection.f05_42_goal_price > Collection.f05_40_cost_price - ).scalar() or 0}, - {"type": "loss", "label": "亏损", "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} + {"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)} ], - "totalCost": cost_result, - "totalTarget": target_result, + "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