186 lines
5.4 KiB
Python
186 lines
5.4 KiB
Python
"""质检任务负责人 CRUD"""
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import Dict, List, Optional, Set
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.db_collation import eq_unicode
|
|
from app.core.utils import generate_uuid
|
|
from app.models.models import BizQcTaskAssignee, SysUser
|
|
|
|
|
|
def _active_users_in_tenant(
|
|
db: Session, user_ids: List[str], tenant_no: str
|
|
) -> Set[str]:
|
|
ids = [x.strip() for x in user_ids if (x or "").strip()]
|
|
if not ids:
|
|
return set()
|
|
rows = (
|
|
db.query(SysUser.id)
|
|
.filter(
|
|
SysUser.id.in_(ids),
|
|
SysUser.tenant_no == tenant_no,
|
|
SysUser.del_flag == 0,
|
|
SysUser.status == "1",
|
|
)
|
|
.all()
|
|
)
|
|
return {r[0] for r in rows}
|
|
|
|
|
|
def validate_assignee_user_ids(
|
|
db: Session, user_ids: List[str], tenant_no: str
|
|
) -> List[str]:
|
|
"""去重并校验用户有效,返回有序列表。"""
|
|
seen: Set[str] = set()
|
|
ordered: List[str] = []
|
|
for uid in user_ids:
|
|
u = (uid or "").strip()
|
|
if not u or u in seen:
|
|
continue
|
|
seen.add(u)
|
|
ordered.append(u)
|
|
if not ordered:
|
|
raise ValueError("请至少指定一名负责人")
|
|
valid = _active_users_in_tenant(db, ordered, tenant_no)
|
|
invalid = [u for u in ordered if u not in valid]
|
|
if invalid:
|
|
raise ValueError("存在无效或已停用的负责人用户")
|
|
return ordered
|
|
|
|
|
|
def sync_assignees_for_task(
|
|
db: Session,
|
|
task_id: str,
|
|
user_ids: List[str],
|
|
*,
|
|
tenant_no: str,
|
|
operator_id: Optional[str] = None,
|
|
create_dept_id: str = "",
|
|
) -> None:
|
|
"""全量替换任务负责人(软删旧记录 + 插入新记录)。"""
|
|
normalized = validate_assignee_user_ids(db, user_ids, tenant_no)
|
|
now = datetime.now()
|
|
existing = (
|
|
db.query(BizQcTaskAssignee)
|
|
.filter(
|
|
BizQcTaskAssignee.task_id == task_id,
|
|
BizQcTaskAssignee.tenant_no == tenant_no,
|
|
BizQcTaskAssignee.del_flag == 0,
|
|
)
|
|
.all()
|
|
)
|
|
keep_ids = set(normalized)
|
|
for row in existing:
|
|
if row.user_id not in keep_ids:
|
|
row.del_flag = 1
|
|
row.update_by = operator_id
|
|
row.update_time = now
|
|
db.add(row)
|
|
existing_map = {r.user_id: r for r in existing if r.del_flag == 0}
|
|
for idx, uid in enumerate(normalized):
|
|
if uid in existing_map:
|
|
row = existing_map[uid]
|
|
row.order_num = idx + 1
|
|
row.update_by = operator_id
|
|
row.update_time = now
|
|
db.add(row)
|
|
continue
|
|
db.add(
|
|
BizQcTaskAssignee(
|
|
id=generate_uuid(),
|
|
task_id=task_id,
|
|
user_id=uid,
|
|
tenant_no=tenant_no,
|
|
order_num=idx + 1,
|
|
create_by=operator_id,
|
|
create_dept_id=create_dept_id or "",
|
|
create_time=now,
|
|
update_by=operator_id,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
)
|
|
|
|
|
|
def soft_delete_assignees_by_task_ids(
|
|
db: Session, task_ids: List[str], tenant_no: str
|
|
) -> None:
|
|
if not task_ids:
|
|
return
|
|
now = datetime.now()
|
|
rows = (
|
|
db.query(BizQcTaskAssignee)
|
|
.filter(
|
|
BizQcTaskAssignee.task_id.in_(task_ids),
|
|
BizQcTaskAssignee.tenant_no == tenant_no,
|
|
BizQcTaskAssignee.del_flag == 0,
|
|
)
|
|
.all()
|
|
)
|
|
for row in rows:
|
|
row.del_flag = 1
|
|
row.update_time = now
|
|
db.add(row)
|
|
|
|
|
|
def list_assignees_by_task_ids(
|
|
db: Session, task_ids: List[str], tenant_no: str
|
|
) -> Dict[str, List[Dict[str, str]]]:
|
|
if not task_ids:
|
|
return {}
|
|
rows = (
|
|
db.query(BizQcTaskAssignee, SysUser)
|
|
.outerjoin(SysUser, eq_unicode(SysUser.id, BizQcTaskAssignee.user_id))
|
|
.filter(
|
|
BizQcTaskAssignee.task_id.in_(task_ids),
|
|
BizQcTaskAssignee.tenant_no == tenant_no,
|
|
BizQcTaskAssignee.del_flag == 0,
|
|
)
|
|
.order_by(BizQcTaskAssignee.order_num.asc(), BizQcTaskAssignee.create_time.asc())
|
|
.all()
|
|
)
|
|
out: Dict[str, List[Dict[str, str]]] = {}
|
|
for assignee, user in rows:
|
|
out.setdefault(assignee.task_id, []).append(
|
|
{
|
|
"userId": assignee.user_id,
|
|
"userName": (user.nick_name or user.user_no or assignee.user_id)
|
|
if user
|
|
else assignee.user_id,
|
|
}
|
|
)
|
|
return out
|
|
|
|
|
|
def is_user_assignee(db: Session, task_id: str, user_id: str, tenant_no: str) -> bool:
|
|
if not task_id or not user_id:
|
|
return False
|
|
row = (
|
|
db.query(BizQcTaskAssignee.id)
|
|
.filter(
|
|
BizQcTaskAssignee.task_id == task_id,
|
|
BizQcTaskAssignee.user_id == user_id,
|
|
BizQcTaskAssignee.tenant_no == tenant_no,
|
|
BizQcTaskAssignee.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
return row is not None
|
|
|
|
|
|
def enrich_tasks_with_assignees(
|
|
db: Session, items: List[dict], tenant_no: str
|
|
) -> List[dict]:
|
|
if not items:
|
|
return items
|
|
task_ids = [t.get("id") for t in items if t.get("id")]
|
|
mapping = list_assignees_by_task_ids(db, task_ids, tenant_no)
|
|
for item in items:
|
|
rows = mapping.get(item.get("id") or "", [])
|
|
item["assigneeUserIds"] = [r["userId"] for r in rows]
|
|
item["assigneeUserNames"] = "、".join(r["userName"] for r in rows if r.get("userName"))
|
|
return items
|