fix(时长): 所有时长计算排除非工作日 + 修复两处时区多算8小时

- get_wip_tasks/get_people_workload/get_people_history/product active_duration_hours/analytics 均改用 working_duration_hours
- 修复 get_wip_tasks 与 active_duration_hours 的 naive 时间误标北京时间 bug(DB实存UTC,原多算8小时)
- 每处读取 holidays 表排除配置的放假日期
This commit is contained in:
2026-08-28 15:08:10 +08:00
parent ad4b55dece
commit bad0941d67
3 changed files with 40 additions and 22 deletions

View File

@ -114,11 +114,12 @@ def _to_bj(dt: datetime | None) -> datetime | None:
return dt
def _duration_hours(start: datetime | None, end: datetime) -> float:
"""计算单台耗时(小时),无开始时间返回 0。"""
def _duration_hours(start: datetime | None, end: datetime, holidays: set = None) -> float:
"""计算单台耗时(工作小时,排除周末/节假日),无开始时间返回 0。"""
if not start:
return 0.0
return (end - start).total_seconds() / 3600
from app.core.time_utils import working_duration_hours
return working_duration_hours(start, end, holidays)
# ============================================================
@ -142,10 +143,15 @@ async def get_capability_profile(
Task, TASK_STATUS_WIP, TASK_STATUS_PENDING, TASK_STATUS_COMPLETED,
)
from app.models.product import Product
from app.models.holiday import Holiday
from app.core.time_utils import get_beijing_time
now = get_beijing_time()
# 读取节假日(排除非工作日)
hres = await db.execute(select(Holiday.day))
holidays = {r[0] for r in hres}
stmt = (
select(
Task.assignee_id, Task.status,
@ -196,7 +202,7 @@ async def get_capability_profile(
"hours": 0.0, "prio": 9,
"first_start": None, "last_completed": None,
})
entry["hours"] += _duration_hours(start, end)
entry["hours"] += _duration_hours(start, end, holidays)
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