83 lines
3.2 KiB
Python
83 lines
3.2 KiB
Python
|
|
"""
|
||
|
|
仪表盘路由模块
|
||
|
|
|
||
|
|
提供进销存系统的仪表盘统计数据,包括:
|
||
|
|
- 基础数据统计(产品数、供应商数、客户数、仓库数)
|
||
|
|
- 库存统计(总库存量、库存总价值)
|
||
|
|
- 订单统计(待处理采购订单、待处理销售订单)
|
||
|
|
- 低库存产品预警(库存量低于最小库存的产品列表)
|
||
|
|
|
||
|
|
路由前缀: /api/dashboard
|
||
|
|
"""
|
||
|
|
from fastapi import APIRouter, Depends
|
||
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
|
from sqlalchemy import select, func
|
||
|
|
|
||
|
|
from database.database import get_db_session
|
||
|
|
from services.auth_service import get_current_active_user
|
||
|
|
from models.database import (
|
||
|
|
User, Product, Supplier, Customer, Warehouse,
|
||
|
|
Inventory, PurchaseOrder, SalesOrder
|
||
|
|
)
|
||
|
|
|
||
|
|
router = APIRouter(prefix="/dashboard", tags=["仪表盘"])
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("")
|
||
|
|
async def get_dashboard(
|
||
|
|
db_session: AsyncSession = Depends(get_db_session),
|
||
|
|
current_user: User = Depends(get_current_active_user)
|
||
|
|
):
|
||
|
|
material_count = await db_session.scalar(
|
||
|
|
select(func.count(Product.id)).where(Product.is_active == True, Product.item_type == "material")
|
||
|
|
) or 0
|
||
|
|
finished_product_count = await db_session.scalar(
|
||
|
|
select(func.count(Product.id)).where(Product.is_active == True, Product.item_type == "finished")
|
||
|
|
) or 0
|
||
|
|
supplier_count = await db_session.scalar(select(func.count(Supplier.id)).where(Supplier.is_active == True))
|
||
|
|
customer_count = await db_session.scalar(select(func.count(Customer.id)).where(Customer.is_active == True))
|
||
|
|
warehouse_count = await db_session.scalar(select(func.count(Warehouse.id)).where(Warehouse.is_active == True))
|
||
|
|
|
||
|
|
total_stock = await db_session.scalar(
|
||
|
|
select(func.sum(Inventory.quantity))
|
||
|
|
.join(Product, Inventory.product_id == Product.id)
|
||
|
|
.where(Product.item_type == "material")
|
||
|
|
) or 0
|
||
|
|
total_value = await db_session.scalar(
|
||
|
|
select(func.sum(Inventory.quantity * Product.cost_price))
|
||
|
|
.join(Product, Inventory.product_id == Product.id)
|
||
|
|
.where(Product.item_type == "material")
|
||
|
|
) or 0
|
||
|
|
|
||
|
|
pending_purchase = await db_session.scalar(
|
||
|
|
select(func.count(PurchaseOrder.id)).where(PurchaseOrder.status == "pending")
|
||
|
|
)
|
||
|
|
pending_sales = await db_session.scalar(
|
||
|
|
select(func.count(SalesOrder.id)).where(SalesOrder.status == "pending")
|
||
|
|
)
|
||
|
|
|
||
|
|
low_stock_products = await db_session.execute(
|
||
|
|
select(Product, Inventory)
|
||
|
|
.join(Inventory, Product.id == Inventory.product_id)
|
||
|
|
.where(Product.item_type == "material")
|
||
|
|
.where(Inventory.quantity <= Product.min_stock)
|
||
|
|
.limit(10)
|
||
|
|
)
|
||
|
|
low_stock = [
|
||
|
|
{"id": p.id, "name": p.name, "sku": p.sku, "quantity": i.quantity, "min_stock": p.min_stock}
|
||
|
|
for p, i in low_stock_products.all()
|
||
|
|
]
|
||
|
|
|
||
|
|
return {
|
||
|
|
"finished_product_count": finished_product_count,
|
||
|
|
"material_count": material_count,
|
||
|
|
"supplier_count": supplier_count,
|
||
|
|
"customer_count": customer_count,
|
||
|
|
"warehouse_count": warehouse_count,
|
||
|
|
"total_stock": total_stock,
|
||
|
|
"total_value": round(total_value, 2),
|
||
|
|
"pending_purchase": pending_purchase,
|
||
|
|
"pending_sales": pending_sales,
|
||
|
|
"low_stock_products": low_stock
|
||
|
|
}
|