feat(效能分析): 人员视图也支持自然天/工作日耗时切换

- capability 接口加 mode 参数,natural 用自然小时、workdays 用工作小时
- 人员视图柱状图随顶部按钮切换,排除休息日的耗时
- 切换按钮自动重新请求 capability 与 flow
This commit is contained in:
2026-08-28 15:38:32 +08:00
parent 4447a1f52d
commit 907473b18c
4 changed files with 13 additions and 5 deletions

View File

@ -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,
)

View File

@ -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