From 1d0f412e4a8d18c5d91ca5b42cc1eb99f244f652 Mon Sep 17 00:00:00 2001 From: v6ole Date: Wed, 24 Jun 2026 17:22:05 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BA=AE=E7=81=AF=E8=A1=A8=E6=9D=83?= =?UTF-8?q?=E9=99=90=E6=8E=A7=E5=88=B6=20=E2=80=94=20=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=BB=8F=E7=90=86=E5=8F=AA=E7=9C=8B=E8=87=AA=E5=B7=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_light_board 新增 user_id/role 参数: - director/leader: 看全部经理 + 未分配客户 - manager: 只看自己, 不显示未分配客户 - API 层从 current_user 提取身份信息透传 --- backend/app/api/dashboard.py | 4 +- backend/app/services/light_board.py | 67 ++++++++++++++++++----------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/backend/app/api/dashboard.py b/backend/app/api/dashboard.py index d9981f9..147915b 100644 --- a/backend/app/api/dashboard.py +++ b/backend/app/api/dashboard.py @@ -60,6 +60,6 @@ async def light_board( current_user: dict = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): - """Get customer visit coverage matrix (light board). Director/leader only.""" + """Get customer visit coverage matrix. Managers see only themselves.""" ref = date.fromisoformat(reference_date) if reference_date else None - return await get_light_board(db, ref) + return await get_light_board(db, ref, uuid.UUID(current_user["user_id"]), current_user["role"]) diff --git a/backend/app/services/light_board.py b/backend/app/services/light_board.py index bbe684c..a93ebff 100644 --- a/backend/app/services/light_board.py +++ b/backend/app/services/light_board.py @@ -53,13 +53,26 @@ def classify(last_visit_date: date | None, ref: date) -> tuple[str, int]: return ("red", missed) -async def get_light_board(db: AsyncSession, reference_date: date | None = None) -> dict: - """Get per-manager customer visit coverage for the light board.""" +async def get_light_board( + db: AsyncSession, + reference_date: date | None = None, + user_id: UUID | None = None, + role: str = "manager", +) -> dict: + """Get per-manager customer visit coverage for the light board. + + Directors/leaders see all managers; managers see only themselves. + """ ref = reference_date or today_cst() - # ── All managers ── + # ── Managers (filtered by role) ── managers_result = await db.execute(select(User).where(User.role == "manager")) - managers = managers_result.scalars().all() + all_managers = managers_result.scalars().all() + # Filter: managers only see themselves + visible_managers = all_managers if role in ("director", "leader") else [ + m for m in all_managers if m.id == user_id + ] + manager_map: dict[UUID, dict] = { m.id: { "manager_id": str(m.id), @@ -71,7 +84,7 @@ async def get_light_board(db: AsyncSession, reference_date: date | None = None) "coverage_rate": 0.0, "customers": [], } - for m in managers + for m in visible_managers } # ── All customers with their last visit per manager ── @@ -153,28 +166,30 @@ async def get_light_board(db: AsyncSession, reference_date: date | None = None) manager_list = sorted(manager_map.values(), key=lambda m: m["coverage_rate"]) # ── Unassigned customers (no primary manager) ── - unassigned_rows = await db.execute( - select(Customer) - .outerjoin(CustomerAssignment, and_( - CustomerAssignment.customer_id == Customer.id, - CustomerAssignment.role == "primary", - )) - .where(CustomerAssignment.id == None) - .order_by(Customer.name) - ) + # Only visible to directors/leaders — not actionable for individual managers unassigned = [] - for c in unassigned_rows.scalars(): - unassigned.append({ - "customer_id": str(c.id), - "customer_name": c.name, - "industry": c.industry or "", - "in_use_services": c.in_use_services or "", - "monthly_fee": str(c.monthly_fee) if c.monthly_fee else "", - "last_visit_date": None, - "last_visit_method": "", - "status": "gray", - "consecutive_missed_months": 0, - }) + if role in ("director", "leader"): + unassigned_rows = await db.execute( + select(Customer) + .outerjoin(CustomerAssignment, and_( + CustomerAssignment.customer_id == Customer.id, + CustomerAssignment.role == "primary", + )) + .where(CustomerAssignment.id == None) + .order_by(Customer.name) + ) + for c in unassigned_rows.scalars(): + unassigned.append({ + "customer_id": str(c.id), + "customer_name": c.name, + "industry": c.industry or "", + "in_use_services": c.in_use_services or "", + "monthly_fee": str(c.monthly_fee) if c.monthly_fee else "", + "last_visit_date": None, + "last_visit_method": "", + "status": "gray", + "consecutive_missed_months": 0, + }) # ── Team summary ── all_total = sum(m["total_customers"] for m in manager_list)