from typing import Optional, Literal from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from sqlalchemy import func, and_, extract from datetime import datetime, timedelta from decimal import Decimal from app.database import get_db from app.models import ( User, Employee, SecondaryAgent, ProductCategory, PerformanceRecord, CalculationResult ) from app.routers.auth import get_current_user router = APIRouter(prefix="/dashboard", tags=["数据看板"]) @router.get("/summary", response_model=dict) def get_dashboard_summary( db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """获取仪表盘汇总数据""" # 本月业绩总额 now = datetime.now() start_of_month = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0) monthly_performance = db.query( func.coalesce(func.sum(PerformanceRecord.amount), Decimal("0")) ).filter( PerformanceRecord.record_date >= start_of_month.date() ).scalar() # 员工收益总额(本月) monthly_income = db.query( func.coalesce(func.sum(CalculationResult.total_income), Decimal("0")) ).filter( CalculationResult.calc_year == now.year, CalculationResult.calc_month == now.month ).scalar() # 员工总数 employee_count = db.query(Employee).join(User).filter(User.status == 1).count() # 二级代理总数 agent_count = db.query(SecondaryAgent).join(User).filter(User.status == 1).count() # 产品分类数 category_count = db.query(ProductCategory).filter(ProductCategory.status == 1).count() return { "code": 200, "message": "success", "data": { "total_performance": str(monthly_performance), "total_income": str(monthly_income), "employee_count": employee_count, "agent_count": agent_count, "category_count": category_count } } @router.get("/chart", response_model=dict) def get_dashboard_chart( type: Literal["performance", "category"] = Query(..., description="图表类型"), months: int = Query(6, ge=1, le=12, description="显示月数"), db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """获取仪表盘图表数据""" if type == "performance": # 业绩趋势数据 end_date = datetime.now() data = [] for i in range(months - 1, -1, -1): month_date = end_date - timedelta(days=i * 30) start_of_month = month_date.replace(day=1, hour=0, minute=0, second=0, microsecond=0) if month_date.month == 12: end_of_month = month_date.replace(year=month_date.year + 1, month=1, day=1) else: end_of_month = month_date.replace(month=month_date.month + 1, day=1) amount = db.query( func.coalesce(func.sum(PerformanceRecord.amount), Decimal("0")) ).filter( PerformanceRecord.record_date >= start_of_month.date(), PerformanceRecord.record_date < end_of_month.date() ).scalar() data.append({ "month": month_date.strftime("%Y-%m"), "amount": float(amount) }) return { "code": 200, "message": "success", "data": data } elif type == "category": # 产品分类占比数据 results = db.query( ProductCategory.name, func.coalesce(func.sum(PerformanceRecord.amount), Decimal("0")).label("amount") ).outerjoin( PerformanceRecord, ProductCategory.id == PerformanceRecord.category_id ).filter( ProductCategory.status == 1 ).group_by(ProductCategory.id).all() data = [ {"name": name, "amount": float(amount)} for name, amount in results if amount > 0 ] return { "code": 200, "message": "success", "data": data } return { "code": 400, "message": "不支持的图表类型", "data": [] } @router.get("/recent-performance", response_model=dict) def get_recent_performance( limit: int = Query(5, ge=1, le=20), db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """获取最近业绩记录""" records = db.query(PerformanceRecord).order_by( PerformanceRecord.record_date.desc() ).limit(limit).all() data = [] for record in records: employee_name = None if record.employee_id: emp = db.query(Employee).filter(Employee.id == record.employee_id).first() if emp and emp.user: employee_name = emp.user.name category_name = None if record.category_id: cat = db.query(ProductCategory).filter(ProductCategory.id == record.category_id).first() if cat: category_name = cat.name data.append({ "id": record.id, "record_date": record.record_date.isoformat() if record.record_date else None, "employee_name": employee_name, "category_name": category_name, "amount": str(record.amount), "customer_name": record.customer_name, "order_no": record.order_no }) return { "code": 200, "message": "success", "data": data }