- 双源确认样板库完整性: search接口与画图编辑器for_ht目录均为254条, 0遗漏 - 全量体检: 6套样板含7个畸形段(缺ps/pe)导致解析报错 前后端重放/算料统一加固过滤, 254样板0异常/1046窗格 - 报表统计模块(/chart): 近N天订单数金额按日柱图+8项总量+状态分布 - 样板库官方/我的样板双Tab(is_default过滤) - 使用指南接入帮助文章接口(种子8篇), seed分类树幂等修复 - 全接口回归18/18通过
54 lines
2.1 KiB
Python
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})
|