Files
menchuang/src/huamenchuang/api/reports.py
T
HHY 453decf2e4 feat: v0.9 样板数据完整性验证/解析加固/报表统计
- 双源确认样板库完整性: search接口与画图编辑器for_ht目录均为254条, 0遗漏
- 全量体检: 6套样板含7个畸形段(缺ps/pe)导致解析报错
  前后端重放/算料统一加固过滤, 254样板0异常/1046窗格
- 报表统计模块(/chart): 近N天订单数金额按日柱图+8项总量+状态分布
- 样板库官方/我的样板双Tab(is_default过滤)
- 使用指南接入帮助文章接口(种子8篇), seed分类树幂等修复
- 全接口回归18/18通过
2026-09-20 12:27:19 -07:00

54 lines
2.1 KiB
Python

"""报表统计路由(对齐原站 /chart 报表)。"""
from datetime import datetime, timedelta
from fastapi import APIRouter
from sqlalchemy import func, select
from huamenchuang.core.deps import CurrentUser, DbSession
from huamenchuang.core.response import ok
from huamenchuang.models.business import AfterSale, MeasureOrder, Quotation
from huamenchuang.models.contract import Contract, Customer
from huamenchuang.models.order import Order
router = APIRouter(prefix="/reports", tags=["报表"])
@router.get("/summary")
async def summary(user: CurrentUser, db: DbSession, days: int = 14):
"""经营汇总:近 N 天订单数/金额按日 + 各实体总数。"""
since = datetime.utcnow() - timedelta(days=days)
cid = user.company_id
# 按日订单数与金额
day_rows = (await db.execute(
select(func.date(Order.created_at), func.count(), func.sum(Order.money))
.where(Order.company_id == cid, Order.created_at >= since)
.group_by(func.date(Order.created_at))
)).all()
by_day = [{"date": str(d), "count": c, "money": float(m or 0)} for d, c, m in day_rows]
async def count(model, extra=None):
conds = [model.company_id == cid]
if extra is not None:
conds.append(extra)
return (await db.execute(select(func.count()).select_from(model).where(*conds))).scalar_one()
totals = {
"orders": await count(Order),
"intentions": await count(Order, Order.status == 0),
"finished": await count(Order, Order.status == 3),
"quotations": await count(Quotation),
"customers": await count(Customer),
"contracts": await count(Contract),
"measures": await count(MeasureOrder),
"after_sales": await count(AfterSale, AfterSale.status != 2),
}
# 订单状态分布
status_rows = (await db.execute(
select(Order.status, func.count()).where(Order.company_id == cid).group_by(Order.status)
)).all()
status_dist = [{"status": s, "count": c} for s, c in status_rows]
return ok(data={"by_day": by_day, "totals": totals, "status_dist": status_dist, "days": days})