From 907473b18c6f97187379e99fd69c0375aa049ea2 Mon Sep 17 00:00:00 2001 From: duxingchen Date: Fri, 28 Aug 2026 15:38:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=95=88=E8=83=BD=E5=88=86=E6=9E=90):=20?= =?UTF-8?q?=E4=BA=BA=E5=91=98=E8=A7=86=E5=9B=BE=E4=B9=9F=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=87=AA=E7=84=B6=E5=A4=A9/=E5=B7=A5=E4=BD=9C=E6=97=A5?= =?UTF-8?q?=E8=80=97=E6=97=B6=E5=88=87=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - capability 接口加 mode 参数,natural 用自然小时、workdays 用工作小时 - 人员视图柱状图随顶部按钮切换,排除休息日的耗时 - 切换按钮自动重新请求 capability 与 flow --- backend/app/api/v1/endpoints/analytics.py | 3 ++- backend/app/services/analytics_service.py | 10 +++++++--- frontend/src/pages/admin/AnalyticsDashboard.tsx | 3 ++- frontend/src/services/analyticsApi.ts | 2 ++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/backend/app/api/v1/endpoints/analytics.py b/backend/app/api/v1/endpoints/analytics.py index 2e06f37..24a917c 100644 --- a/backend/app/api/v1/endpoints/analytics.py +++ b/backend/app/api/v1/endpoints/analytics.py @@ -21,6 +21,7 @@ async def capability_profile( spec_models: str | None = Query(None, description="规格型号,逗号分隔(可选)"), since: str | None = Query(None, description="起始日期 ISO"), until: str | None = Query(None, description="截止日期 ISO"), + mode: str = Query("workdays", description="耗时口径: workdays(工作小时,默认) / natural(自然小时)"), db: AsyncSession = Depends(get_db), ): """个人能力图谱 — X 轴=设备身份证,分组柱状图(单台设备总耗时)。""" @@ -30,7 +31,7 @@ async def capability_profile( specs = [s.strip() for s in spec_models.split(",") if s.strip()] if spec_models else None return await get_capability_profile( db, assignee_ids=ids, spec_models=specs, - since=since_dt, until=until_dt, + since=since_dt, until=until_dt, mode=mode, ) diff --git a/backend/app/services/analytics_service.py b/backend/app/services/analytics_service.py index 46a7832..c7e218f 100644 --- a/backend/app/services/analytics_service.py +++ b/backend/app/services/analytics_service.py @@ -116,10 +116,13 @@ def _to_bj(dt: datetime | None) -> datetime | None: return dt -def _duration_hours(start: datetime | None, end: datetime, holidays: set = None) -> float: - """计算单台耗时(工作小时,排除周末/节假日),无开始时间返回 0。""" +def _duration_hours(start: datetime | None, end: datetime, holidays: set = None, mode: str = "workdays") -> float: + """计算单台耗时(小时),无开始时间返回 0。 + mode=workdays: 排除周末/节假日的工作小时;mode=natural: 自然小时。""" if not start: return 0.0 + if mode == "natural": + return (end - start).total_seconds() / 3600 from app.core.time_utils import working_duration_hours return working_duration_hours(start, end, holidays) @@ -134,6 +137,7 @@ async def get_capability_profile( spec_models: list[str] | None = None, since: datetime | None = None, until: datetime | None = None, + mode: str = "workdays", ) -> CapabilityResponse: """ 个人能力图谱(单机颗粒度):X 轴 = 设备身份证,每个负责人一条柱状 series。 @@ -204,7 +208,7 @@ async def get_capability_profile( "hours": 0.0, "prio": 9, "first_start": None, "last_completed": None, }) - entry["hours"] += _duration_hours(start, end, holidays) + entry["hours"] += _duration_hours(start, end, holidays, mode) if start and (entry["first_start"] is None or start < entry["first_start"]): entry["first_start"] = start completed_dt = _to_bj(row[4]) if row[4] else None diff --git a/frontend/src/pages/admin/AnalyticsDashboard.tsx b/frontend/src/pages/admin/AnalyticsDashboard.tsx index c3c16a5..eeb0c6a 100644 --- a/frontend/src/pages/admin/AnalyticsDashboard.tsx +++ b/frontend/src/pages/admin/AnalyticsDashboard.tsx @@ -120,8 +120,9 @@ export default function AnalyticsDashboard() { q.since = range[0].startOf("day").toISOString(); q.until = range[1].endOf("day").toISOString(); } + q.mode = totalDaysMode; // 自然天 / 工作日,控制人员视图耗时口径 return q; - }, [assigneeIds, specModels, range]); + }, [assigneeIds, specModels, range, totalDaysMode]); const buildFlowQuery = useCallback((): FlowQuery => { const q: FlowQuery = {}; diff --git a/frontend/src/services/analyticsApi.ts b/frontend/src/services/analyticsApi.ts index f4e0150..0f07b28 100644 --- a/frontend/src/services/analyticsApi.ts +++ b/frontend/src/services/analyticsApi.ts @@ -98,6 +98,7 @@ export interface CapabilityQuery { spec_models?: string[]; since?: string; until?: string; + mode?: "natural" | "workdays"; } export interface FlowQuery { @@ -116,6 +117,7 @@ export async function fetchCapabilityProfile(query: CapabilityQuery): Promise("/analytics/capability", { params }); return data; }