Files
tianpu-ems/backend/app/api/v1/carbon.py
Du Wenbo f53a610a19 Initial commit: Tianpu Zero-Carbon EMS Platform
Full-stack energy management system for Tianpu Daxing campus.
- Frontend: React 19 + TypeScript + Ant Design + ECharts
- Backend: FastAPI + SQLAlchemy + PostgreSQL/TimescaleDB
- Features: PV monitoring, heat pump management, carbon tracking, alarms, reports

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 13:36:06 +08:00

75 lines
3.0 KiB
Python

from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, and_, text
from app.core.database import get_db
from app.core.deps import get_current_user
from app.models.carbon import CarbonEmission, EmissionFactor
from app.models.user import User
router = APIRouter(prefix="/carbon", tags=["碳排放管理"])
@router.get("/overview")
async def carbon_overview(db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)):
"""碳排放总览"""
now = datetime.now(timezone.utc)
today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
year_start = now.replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
async def sum_carbon(start, end):
r = await db.execute(
select(func.sum(CarbonEmission.emission), func.sum(CarbonEmission.reduction))
.where(and_(CarbonEmission.date >= start, CarbonEmission.date < end))
)
row = r.first()
return {"emission": row[0] or 0, "reduction": row[1] or 0}
today = await sum_carbon(today_start, now)
month = await sum_carbon(month_start, now)
year = await sum_carbon(year_start, now)
# 各scope分布
scope_q = await db.execute(
select(CarbonEmission.scope, func.sum(CarbonEmission.emission))
.where(CarbonEmission.date >= year_start)
.group_by(CarbonEmission.scope)
)
by_scope = {row[0]: round(row[1], 2) for row in scope_q.all()}
return {
"today": {"emission": round(today["emission"], 2), "reduction": round(today["reduction"], 2)},
"month": {"emission": round(month["emission"], 2), "reduction": round(month["reduction"], 2)},
"year": {"emission": round(year["emission"], 2), "reduction": round(year["reduction"], 2)},
"by_scope": by_scope,
}
@router.get("/trend")
async def carbon_trend(
days: int = Query(30, ge=1, le=365),
db: AsyncSession = Depends(get_db),
user: User = Depends(get_current_user),
):
"""碳排放趋势"""
start = datetime.now(timezone.utc) - timedelta(days=days)
result = await db.execute(
select(
func.date_trunc('day', CarbonEmission.date).label('day'),
func.sum(CarbonEmission.emission),
func.sum(CarbonEmission.reduction),
).where(CarbonEmission.date >= start)
.group_by(text('day')).order_by(text('day'))
)
return [{"date": str(r[0]), "emission": round(r[1], 2), "reduction": round(r[2], 2)} for r in result.all()]
@router.get("/factors")
async def list_factors(db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)):
result = await db.execute(select(EmissionFactor).order_by(EmissionFactor.id))
return [{
"id": f.id, "name": f.name, "energy_type": f.energy_type, "factor": f.factor,
"unit": f.unit, "scope": f.scope, "region": f.region, "source": f.source,
} for f in result.scalars().all()]