Compare commits

...

2 Commits

Author SHA1 Message Date
甲辰生产 25fc88f683 v1.2.52 - 修复前端版本号 2026-04-08 07:48:25 +08:00
甲辰生产 6de39e55ae v1.2.52 - 安全修复:统一版本号、CORS配置、SECRET_KEY、Stats性能优化 2026-04-08 07:48:25 +08:00
6 changed files with 113 additions and 61 deletions

View File

@ -1 +1 @@
1.2.41 VERSION=1.2.52

View File

@ -11,7 +11,9 @@ from app.core.database import SessionLocal
from app.models.models import User from app.models.models import User
# 配置 # 配置
SECRET_KEY = os.getenv("SECRET_KEY", "your-secret-key-change-in-production") SECRET_KEY = os.getenv("SECRET_KEY")
if not SECRET_KEY:
raise ValueError("SECRET_KEY environment variable is not set. Please configure it in production!")
ALGORITHM = "HS256" ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "10080")) # 7天 ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "10080")) # 7天

View File

@ -51,10 +51,11 @@ app = FastAPI(
# 设置全局错误处理器 # 设置全局错误处理器
setup_error_handlers(app) setup_error_handlers(app)
# CORS 配置 # CORS 配置 - 生产环境限制域名
ALLOWED_ORIGINS = os.getenv("ALLOWED_ORIGINS", "http://47.103.29.111,http://120.55.81.21,https://socoolbot.com").split(",")
app.add_middleware( app.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=["*"], # 生产环境应该限制域名 allow_origins=ALLOWED_ORIGINS, # 生产环境限制域名
allow_credentials=True, allow_credentials=True,
allow_methods=["*"], allow_methods=["*"],
allow_headers=["*"], allow_headers=["*"],

View File

@ -4,7 +4,8 @@ import uuid
import re import re
from typing import Optional, List from typing import Optional, List
from fastapi import APIRouter, Depends, HTTPException, status, Query, UploadFile, File from fastapi import APIRouter, Depends, HTTPException, status, Query, UploadFile, File
from sqlalchemy import func, text from sqlalchemy import func, text, case, nullsfirst
from sqlalchemy.dialects import postgresql as pg
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.core.database import get_db from app.core.database import get_db
from app.core.auth import get_current_user from app.core.auth import get_current_user
@ -275,68 +276,117 @@ def get_stats(
current_user: User = Depends(get_current_user), current_user: User = Depends(get_current_user),
db: Session = Depends(get_db) db: Session = Depends(get_db)
): ):
"""获取藏品统计""" """获取藏品统计 - 使用数据库聚合查询优化性能"""
# 获取所有藏品 from sqlalchemy import case
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()
# 总数 # 基础查询条件
total_count = len(all_collections) if current_user.role == "admin":
base_filter = True
user_filter = True
else:
base_filter = Collection.f99_91_user_id == current_user.f99_90_id
user_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 = db.query(
by_category = Counter(c.f01_03_category for c in all_collections).items() 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_packaging = db.query(
by_rarity = Counter(c.f02_13_rarity for c in all_collections if c.f02_13_rarity).items() Collection.f02_12_packaging,
by_version = Counter(c.f02_11_version for c in all_collections if c.f02_11_version).items() func.count(Collection.f99_90_id)
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() ).filter(base_filter, Collection.f02_12_packaging.isnot(None)).group_by(Collection.f02_12_packaging).all()
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()
# 总成本: SUM(cost_price + repair_fee + grading_fee) for ALL collections # 按稀有度统计
total_cost = sum( by_rarity = db.query(
(c.f05_40_cost_price or 0) + (c.f05_43_repair_fee or 0) + (c.f05_44_grading_fee or 0) Collection.f02_13_rarity,
for c in all_collections 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( by_version = db.query(
(c.f05_41_target_price or 0) - (c.f05_40_cost_price or 0) Collection.f02_11_version,
for c in all_collections func.count(Collection.f99_90_id)
if c.f05_41_target_price and c.f05_41_target_price > 0 ).filter(base_filter, Collection.f02_11_version.isnot(None)).group_by(Collection.f02_11_version).all()
)
# 已售商品:状态为 sold 且出售价 > 0 # 按评级公司统计
sold_collections = [ by_grading_company = db.query(
c for c in all_collections Collection.f03_21_grading_company,
if c.f01_04_status == 'sold' and c.f05_42_goal_price and c.f05_42_goal_price > 0 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( by_grading_score = db.query(
c.f05_42_goal_price or 0 Collection.f03_22_grading_score,
for c in sold_collections 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 已售商品 # 按特殊标记统计
# 单藏品总成本 = 成本价 + 修复费 + 评级费 by_special_mark = db.query(
total_profit = sum( Collection.f04_30_special_mark,
(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) func.count(Collection.f99_90_id)
for c in sold_collections ).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
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 = base_filter & (Collection.f01_04_status == 'sold') & (Collection.f05_42_goal_price > 0)
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
# 盈亏统计
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
return { return {
"totalCount": total_count, "totalCount": total_count,
@ -350,13 +400,12 @@ def get_stats(
"byGradingScore": [{"score": s, "count": n} for s, n in by_grading_score], "byGradingScore": [{"score": s, "count": n} for s, n in by_grading_score],
"bySpecialMark": [{"mark": m, "count": n} for m, n in by_special_mark], "bySpecialMark": [{"mark": m, "count": n} for m, n in by_special_mark],
"byNumberCategory": [{"numberCategory": n, "count": c} for n, c in by_number_category], "byNumberCategory": [{"numberCategory": n, "count": c} for n, c in by_number_category],
# 盈亏统计(只统计已售且有价格的藏品)
"byProfitLoss": [ "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": "profit", "label": "盈利", "count": profit_count},
{"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": "loss", "label": "亏损", "count": loss_count}
], ],
"totalCost": total_cost, "totalCost": cost_result,
"totalTarget": sum(c.f05_41_target_price or 0 for c in all_collections), "totalTarget": target_result,
"expectedProfit": expected_profit, "expectedProfit": expected_profit,
"totalRevenue": total_revenue, "totalRevenue": total_revenue,
"totalProfit": total_profit "totalProfit": total_profit

View File

@ -1 +1 @@
v1.2.41 VERSION=1.2.52

View File

@ -1,6 +1,6 @@
{ {
"name": "jiachenlong-frontend", "name": "jiachenlong-frontend",
"version": "1.2.12", "version": "1.2.52",
"private": true, "private": true,
"description": "甲辰藏品管理系统 - 移动端前端", "description": "甲辰藏品管理系统 - 移动端前端",
"scripts": { "scripts": {