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

@ -541,11 +541,14 @@ async def get_all_products(
has_img = bool(row[3] and row[3] != "[]" and row[3] != "null")
latest_record_map[row[0]] = (row[1], row[2], has_img, row[4])
# 🔧 当前人滞留时长:每个产品活跃任务(WIP/PENDING)最早接手时间 → 小时
# 🔧 当前人滞留时长:每个产品活跃任务(WIP/PENDING)最早接手时间 → 小时(排除非工作日)
active_duration_map: dict[uuid.UUID, float] = {}
if product_ids:
from sqlalchemy import func as sa_func
from app.core.time_utils import get_beijing_time, BEIJING_TZ
from app.core.time_utils import get_beijing_time, to_beijing, working_duration_hours
from app.models.holiday import Holiday
hres = await db.execute(select(Holiday.day))
holidays = {r[0] for r in hres}
start_stmt = (
select(
Task.product_id,
@ -563,11 +566,8 @@ async def get_all_products(
start = row[1]
if start is None:
continue
if start.tzinfo is None:
start = start.replace(tzinfo=BEIJING_TZ)
else:
start = start.astimezone(BEIJING_TZ)
active_duration_map[row[0]] = round((now - start).total_seconds() / 3600, 1)
start_bj = to_beijing(start) # 🚀 naive 按 UTC 转北京时间(修复多算8小时)
active_duration_map[row[0]] = working_duration_hours(start_bj, now, holidays)
return [
ProductResponse(