fix(dashboard): trends per-company lines instead of meaningless average
This commit is contained in:
@@ -166,50 +166,52 @@ async def get_health_heatmap(
|
||||
|
||||
@router.get("/trends", response_model=ApiResponse[list[dict]])
|
||||
async def get_health_trends(
|
||||
company_id: str | None = Query(default=None, description="指定企业 ID,不传则汇总"),
|
||||
company_id: str | None = Query(default=None, description="指定企业 ID,不传则返回全部企业"),
|
||||
months: int = Query(default=6, ge=1, le=24, description="趋势月数"),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
user: User = Depends(get_current_user),
|
||||
):
|
||||
"""获取健康度趋势对比数据 — 按月汇总评分变化。
|
||||
"""获取健康度趋势数据 — 按企业分组,每家企业一条折线。
|
||||
|
||||
返回格式:[{ period, avg_score, company_count, dimension_avgs: { dimension: avg } }]
|
||||
返回格式:[{ company_id, company_name, data: [{ period, score }] }]
|
||||
"""
|
||||
query = (
|
||||
select(HealthScore)
|
||||
select(HealthScore, Company.name.label("company_name"))
|
||||
.join(Company, HealthScore.company_id == Company.id)
|
||||
.where(Company.tenant_id == user.tenant_id)
|
||||
)
|
||||
if company_id:
|
||||
query = query.where(HealthScore.company_id == company_id)
|
||||
|
||||
query = query.order_by(HealthScore.calculated_at.desc()).limit(months * 50)
|
||||
query = query.order_by(HealthScore.calculated_at.asc()).limit(months * 100)
|
||||
result = await db.execute(query)
|
||||
scores = result.scalars().all()
|
||||
|
||||
# 按月分组
|
||||
monthly: dict[str, list[HealthScore]] = {}
|
||||
for s in scores:
|
||||
period = s.calculated_at.strftime("%Y-%m")
|
||||
monthly.setdefault(period, []).append(s)
|
||||
# 按企业分组
|
||||
by_company: dict[str, dict[str, list]] = {}
|
||||
for row in result.all():
|
||||
score = row[0]
|
||||
cname = row[1]
|
||||
cid = str(score.company_id)
|
||||
if cid not in by_company:
|
||||
by_company[cid] = {"company_name": cname, "scores": []}
|
||||
by_company[cid]["scores"].append(score)
|
||||
|
||||
trends = []
|
||||
for period in sorted(monthly.keys()):
|
||||
month_scores = monthly[period]
|
||||
count = len(month_scores)
|
||||
avg_total = sum(s.total_score for s in month_scores) / count if count else 0
|
||||
|
||||
dim_avgs = {}
|
||||
for dim_key in _DIMENSION_KEYS:
|
||||
vals = [getattr(s, dim_key) for s in month_scores if getattr(s, dim_key) is not None]
|
||||
if vals:
|
||||
dim_avgs[dim_key] = round(sum(vals) / len(vals), 1)
|
||||
for cid, info in by_company.items():
|
||||
# 每月取最新一条
|
||||
monthly: dict[str, float] = {}
|
||||
for s in info["scores"]:
|
||||
period = s.calculated_at.strftime("%Y-%m")
|
||||
monthly[period] = s.total_score
|
||||
|
||||
data_points = [
|
||||
{"period": p, "score": round(v, 1)}
|
||||
for p, v in sorted(monthly.items())
|
||||
]
|
||||
trends.append({
|
||||
"period": period,
|
||||
"avg_score": round(avg_total, 1),
|
||||
"company_count": count,
|
||||
"dimension_avgs": dim_avgs,
|
||||
"company_id": cid,
|
||||
"company_name": info["company_name"],
|
||||
"data": data_points,
|
||||
})
|
||||
|
||||
return success(data=trends)
|
||||
|
||||
Reference in New Issue
Block a user