Commit 4a83b87f by Ooh-Ao

projectId param dashboard

parent 78aa85f9
# myproject/controllers/admin_dashboard_controller.py
from datetime import date
from typing import Optional
from uuid import UUID
from sqlalchemy import select, func, extract, case
from sqlalchemy.ext.asyncio import AsyncSession
from ..models.project import Project
from ..models.member import Member
from ..models.project_member import ProjectMember
from ..models.equipment import Equipment
from ..models.project_equipment import ProjectEquipment
from ..models.borrow_transaction import BorrowTransaction
......@@ -14,85 +19,134 @@ from ..schemas.admin_dashboard_schema import (
async def get_admin_dashboard(
db: AsyncSession,
start_date: date,
end_date: date
end_date: date,
project_id: Optional[UUID] = None
):
# 1) Summary Cards
total_members = await db.scalar(select(func.count()).select_from(Member))
prev_members = await db.scalar(
select(func.count()).select_from(Member)
.where(Member.createdAt.between(start_date.replace(year=start_date.year-1), start_date))
)
total_projects = await db.scalar(select(func.count()).select_from(Project))
prev_projects = await db.scalar(
select(func.count()).select_from(Project)
.where(Project.createdAt.between(start_date.replace(year=start_date.year-1), start_date))
)
total_equips = await db.scalar(select(func.count()).select_from(Equipment))
prev_equips = await db.scalar(
select(func.count()).select_from(Equipment)
.where(Equipment.createdAt.between(start_date.replace(year=start_date.year-1), start_date))
)
# --- 1) SUMMARY CARDS ---
if project_id:
# สมาชิกในโปรเจ็กต์
total_members = await db.scalar(
select(func.count()).select_from(ProjectMember)
.where(ProjectMember.projectId == project_id)
)
prev_members = 0
# โครงการเดียว
total_projects = 1
prev_projects = 0
# อุปกรณ์ในโครงการ (นับ distinct equipment)
total_equips = await db.scalar(
select(func.count()).select_from(ProjectEquipment)
.where(ProjectEquipment.projectId == project_id)
)
prev_equips = 0
else:
total_members = await db.scalar(select(func.count()).select_from(Member))
prev_members = await db.scalar(
select(func.count()).select_from(Member)
.where(Member.createdAt.between(start_date.replace(year=start_date.year-1), start_date))
)
total_projects = await db.scalar(select(func.count()).select_from(Project))
prev_projects = await db.scalar(
select(func.count()).select_from(Project)
.where(Project.createdAt.between(start_date.replace(year=start_date.year-1), start_date))
)
total_equips = await db.scalar(select(func.count()).select_from(Equipment))
prev_equips = await db.scalar(
select(func.count()).select_from(Equipment)
.where(Equipment.createdAt.between(start_date.replace(year=start_date.year-1), start_date))
)
summary = [
SummaryCard(label="จำนวนผู้ใช้งานทั้งหมด",
value=total_members,
change=(total_members - prev_members) / prev_members * 100 if prev_members else 0),
SummaryCard(label="จำนวนโครงการทั้งหมด",
value=total_projects,
change=(total_projects - prev_projects) / prev_projects * 100 if prev_projects else 0),
SummaryCard(label="จำนวนอุปกรณ์ทั้งหมด",
value=total_equips,
change=(total_equips - prev_equips) / prev_equips * 100 if prev_equips else 0),
SummaryCard(
label="จำนวนผู้ใช้งาน",
value=total_members,
change=(total_members - prev_members) / prev_members * 100 if prev_members else 0
),
SummaryCard(
label="จำนวนโครงการ",
value=total_projects,
change=(total_projects - prev_projects) / prev_projects * 100 if prev_projects else 0
),
SummaryCard(
label="จำนวนอุปกรณ์",
value=total_equips,
change=(total_equips - prev_equips) / prev_equips * 100 if prev_equips else 0
),
]
# 2) Monthly Trends (bar chart) ยืม vs คืน
# Helper: build a SQLAlchemy filter for this project
def pe_filter(q):
return q.where(ProjectEquipment.projectId == project_id) if project_id else q
def bt_filter(q):
if project_id:
# borrowTransaction.pe_id in those of this project
q = q.where(BorrowTransaction.peId.in_(
select(ProjectEquipment.peId).where(ProjectEquipment.projectId == project_id)
))
return q
# --- 2) MONTHLY TRENDS ---
stmt = (
select(
extract('month', BorrowTransaction.created_at).label('m'),
func.sum(case((BorrowTransaction.status != 'returned', 1), else_=0)).label('borrowed'),
func.sum(case((BorrowTransaction.status == 'returned', 1), else_=0)).label('returned'),
func.sum(
case((BorrowTransaction.status != 'returned', 1), else_=0)
).label('borrowed'),
func.sum(
case((BorrowTransaction.status == 'returned', 1), else_=0)
).label('returned'),
)
.where(BorrowTransaction.created_at.between(start_date, end_date))
.group_by('m')
.order_by('m')
)
stmt = bt_filter(stmt)
stmt = stmt.group_by('m').order_by('m')
rows = (await db.execute(stmt)).all()
monthly_trends = [
TrendItem(period=date(1900, int(m), 1).strftime('%b'),
borrowed=int(b), returned=int(r))
TrendItem(
period=date(1900, int(m), 1).strftime('%b'),
borrowed=int(b), returned=int(r)
)
for m, b, r in rows
]
# 3) Equipment Distribution (pie chart)
stmt2 = (
select(
Equipment.equipmentName,
func.coalesce(func.sum(ProjectEquipment.quantity_in_project), 0).label('count')
)
.join(ProjectEquipment, Equipment.equipmentId == ProjectEquipment.equipmentId)
.group_by(Equipment.equipmentName)
)
# --- 3) EQUIPMENT DISTRIBUTION ---
stmt2 = select(
Equipment.equipmentName,
func.coalesce(func.sum(ProjectEquipment.quantity_in_project), 0).label('count')
).join(ProjectEquipment, Equipment.equipmentId == ProjectEquipment.equipmentId)
stmt2 = pe_filter(stmt2).group_by(Equipment.equipmentName)
rows2 = (await db.execute(stmt2)).all()
equipment_distribution = [
PieSlice(category=name, count=int(cnt))
for name, cnt in rows2
]
# 4) Borrow/Return Line (line chart)
# --- 4) BORROW/RETURN LINE ---
stmt3 = (
select(
extract('month', BorrowTransaction.created_at).label('m'),
func.sum(case((BorrowTransaction.status != 'returned', 1), else_=0)).label('borrowed'),
func.sum(case((BorrowTransaction.status == 'returned', 1), else_=0)).label('returned'),
func.sum(
case((BorrowTransaction.status != 'returned', 1), else_=0)
).label('borrowed'),
func.sum(
case((BorrowTransaction.status == 'returned', 1), else_=0)
).label('returned'),
)
.where(BorrowTransaction.created_at.between(start_date, end_date))
.group_by('m')
.order_by('m')
)
stmt3 = bt_filter(stmt3).group_by('m').order_by('m')
rows3 = (await db.execute(stmt3)).all()
borrow_return_line = [
TrendItem(period=date(1900, int(m), 1).strftime('%b'),
borrowed=int(b), returned=int(r))
TrendItem(
period=date(1900, int(m), 1).strftime('%b'),
borrowed=int(b), returned=int(r)
)
for m, b, r in rows3
]
......
......@@ -3,24 +3,24 @@ from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession
from datetime import date, timedelta
from typing import Optional
from uuid import UUID
from ..config.database import get_db
from ..controllers.admin_dashboard_controller import get_admin_dashboard
from ..schemas.admin_dashboard_schema import AdminDashboardResponse
router = APIRouter(prefix="/admin/dashboard", tags=["AdminDashboard"])
@router.get("", response_model=AdminDashboardResponse)
async def admin_dashboard(
start_date: Optional[date] = Query(None, description="YYYY-MM-DD"),
end_date: Optional[date] = Query(None, description="YYYY-MM-DD"),
project_id: Optional[UUID] = Query(None, description="Filter by project ID"),
db: AsyncSession = Depends(get_db)
):
# กำหนด default ช่วง 1 ปีย้อนหลังถ้าไม่ส่งมา
if not end_date:
end_date = date.today()
if not start_date:
start_date = end_date - timedelta(days=365)
return await get_admin_dashboard(db, start_date, end_date)
return await get_admin_dashboard(db, start_date, end_date, project_id)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment