diff --git a/backend/app/services/dashboard_service.py b/backend/app/services/dashboard_service.py index 62c57fa..2b6a8ea 100644 --- a/backend/app/services/dashboard_service.py +++ b/backend/app/services/dashboard_service.py @@ -483,29 +483,29 @@ async def get_user_operations( since: datetime | None = None, until: datetime | None = None, ) -> list[UserOperation]: - """上帝视角 — 统计**全部人员**的操作次数(按时段过滤 task_logs)。 + """上帝视角 — 统计**全部人员**的操作次数(按时段过滤)。 返回所有 IRIS 部门人员(该时段无操作的计 0),并追加有操作记录但不在 人员清单中的账号(如历史/已离职)。 - 操作口径: - - 接收: action_type='receive' - - 转交: action_type='complete'(完工并移交下一道工序) - - 上传备注: action_type='record'(工人手动追加的进度记录) + 操作口径(均不修改数据库): + - 接收: task_logs.action_type='receive'(按操作人) + - 转交: task_logs.action_type='complete'(按操作人) + - 上传备注: task_records 按**任务负责人**归因(排除系统自动生成的 + 以 '[' 开头的备注,如 "[接收] 操作员已确认接收"),历史数据可回溯 """ from app.models.task_log import TaskLog + from app.models.task import Task, TaskRecord from app.core.mom_database import MomSessionLocal - from sqlalchemy import text + from sqlalchemy import text, or_ - # ── 1. 统计 task_logs 操作次数(按 operator_id 聚合)── + # ── 1. 接收 / 转交(task_logs 按 operator_id 聚合)── rcv = func.count().filter(TaskLog.action_type == "receive") cpl = func.count().filter(TaskLog.action_type == "complete") - rcd = func.count().filter(TaskLog.action_type == "record") - stmt = ( - select(TaskLog.operator_id, rcv.label("receive"), cpl.label("complete"), rcd.label("record")) + select(TaskLog.operator_id, rcv.label("receive"), cpl.label("complete")) .where( - TaskLog.action_type.in_(["receive", "complete", "record"]), + TaskLog.action_type.in_(["receive", "complete"]), TaskLog.operator_id.isnot(None), ) .group_by(TaskLog.operator_id) @@ -514,11 +514,27 @@ async def get_user_operations( stmt = stmt.where(TaskLog.created_at >= since) if until: stmt = stmt.where(TaskLog.created_at <= until) + op_rows = (await db.execute(stmt)).all() + op_map = {r[0]: (r[1] or 0, r[2] or 0) for r in op_rows} - result = await db.execute(stmt) - op_map = {r[0]: (r[1] or 0, r[2] or 0, r[3] or 0) for r in result.all()} + # ── 2. 上传备注(task_records 按任务 assignee 归因,排除系统自动备注)── + rcd_stmt = ( + select(Task.assignee_id, func.count(TaskRecord.id)) + .join(Task, TaskRecord.task_id == Task.id) + .where( + Task.assignee_id.isnot(None), + or_(TaskRecord.remark.is_(None), ~TaskRecord.remark.like("[%")), + ) + .group_by(Task.assignee_id) + ) + if since: + rcd_stmt = rcd_stmt.where(TaskRecord.created_at >= since) + if until: + rcd_stmt = rcd_stmt.where(TaskRecord.created_at <= until) + rcd_rows = (await db.execute(rcd_stmt)).all() + record_map = {r[0]: r[1] or 0 for r in rcd_rows} - # ── 2. 获取全部 MOM 用户清单(IRIS 部门)── + # ── 3. 获取全部 MOM 用户清单(IRIS 部门)── users: list[dict] = [] try: dbm = MomSessionLocal() @@ -540,19 +556,19 @@ async def get_user_operations( except Exception: users = [] - # ── 3. 合并:所有人员 + 有操作但不在清单的账号 ── + # ── 4. 合并:所有人员 + 有操作但不在清单的账号 ── merged: dict[str, dict] = {} for u in users: merged[u["username"]] = {"name": u["full_name"], "rcv": 0, "cpl": 0, "rcd": 0} - for uid, (r, c, rd) in op_map.items(): - if uid in merged: - merged[uid]["rcv"] = r - merged[uid]["cpl"] = c - merged[uid]["rcd"] = rd - else: - merged[uid] = {"name": uid, "rcv": r, "cpl": c, "rcd": rd} + for uid in set(op_map.keys()) | set(record_map.keys()): + if uid not in merged: + merged[uid] = {"name": uid, "rcv": 0, "cpl": 0, "rcd": 0} + r, c = op_map.get(uid, (0, 0)) + merged[uid]["rcv"] = r + merged[uid]["cpl"] = c + merged[uid]["rcd"] = record_map.get(uid, 0) - # ── 4. 组装 + 排序(总次数降序,无操作的排在最后)── + # ── 5. 组装 + 排序(总次数降序,无操作的排在最后)── items: list[UserOperation] = [] for uid, v in merged.items(): items.append(UserOperation( diff --git a/backend/app/services/task_service.py b/backend/app/services/task_service.py index 51b53c9..06d662b 100644 --- a/backend/app/services/task_service.py +++ b/backend/app/services/task_service.py @@ -1049,16 +1049,6 @@ async def add_task_record( db.add(record) await db.flush() - # 🔧 操作日志:记录一次「上传备注」操作(供人员操作统计) - if current_user: - from app.models.task_log import TaskLog - db.add(TaskLog( - task_id=task_id, - operator_id=current_user.get("username") or current_user.get("sub") or "", - action_type="record", - remark=f"上传备注: {(data.remark or '')[:100]}", - )) - # 🚀 留言通知:给任务当前负责人发送提醒(不给自己发) if ( current_user