提交
This commit is contained in:
1 parent
66609c0e21
commit
0b50eff3d8
93 files changed
+40172
-30060
No files matched your search
+1
-1
@@ -1 +1 @@
|
||||
32839
|
||||
78910
|
||||
@@ -429,7 +429,7 @@ class StorageFacilityCreateBody(BaseModel):
|
||||
|
||||
parent_id: str = Field("0", alias="parentId")
|
||||
node_name: str = Field(..., alias="nodeName")
|
||||
node_code: str = Field(..., alias="nodeCode", min_length=1, max_length=32)
|
||||
node_code: str = Field("", alias="nodeCode", max_length=32)
|
||||
node_type: Optional[str] = Field(None, alias="nodeType")
|
||||
is_leaf: Optional[int] = Field(0, alias="isLeaf")
|
||||
order_num: Optional[int] = Field(0, alias="orderNum")
|
||||
@@ -440,7 +440,7 @@ class StorageFacilityUpdateBody(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
node_name: Optional[str] = Field(None, alias="nodeName")
|
||||
node_code: Optional[str] = Field(None, alias="nodeCode", min_length=1, max_length=32)
|
||||
node_code: Optional[str] = Field(None, alias="nodeCode", max_length=32)
|
||||
node_type: Optional[str] = Field(None, alias="nodeType")
|
||||
is_leaf: Optional[int] = Field(None, alias="isLeaf")
|
||||
order_num: Optional[int] = Field(None, alias="orderNum")
|
||||
@@ -553,6 +553,7 @@ class StorageSlotCreateBody(BaseModel):
|
||||
slot_code: Optional[str] = Field(None, alias="slotCode")
|
||||
slot_status: Optional[str] = Field(None, alias="slotStatus")
|
||||
order_num: Optional[int] = Field(0, alias="orderNum")
|
||||
at_row_num: Optional[int] = Field(None, alias="atRowNum", ge=1)
|
||||
remark: Optional[str] = None
|
||||
|
||||
|
||||
@@ -692,6 +693,7 @@ async def create_storage_slot(
|
||||
order_num=body.order_num,
|
||||
remark=body.remark,
|
||||
user_id=user.get("user_id"),
|
||||
at_row_num=body.at_row_num,
|
||||
)
|
||||
return success_response(storage_facility_svc._slot_to_dict_for_row(db, obj), message="创建成功")
|
||||
except ValueError as e:
|
||||
@@ -774,7 +776,9 @@ async def delete_storage_slot(
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
storage_facility_svc.soft_delete_slot(db, slot_id, tenant_no=tenant_no)
|
||||
storage_facility_svc.soft_delete_slot(
|
||||
db, slot_id, tenant_no=tenant_no, user_id=user.get("user_id")
|
||||
)
|
||||
return success_response(None, message="删除成功")
|
||||
except ValueError as e:
|
||||
return error_response(400, str(e))
|
||||
|
||||
@@ -55,6 +55,7 @@ from app.schemas.production_task import (
|
||||
ProductionTaskStatusUpdate,
|
||||
ProductionTaskForwardBody,
|
||||
ProductionTaskAssigneeUpdate,
|
||||
ProductionTaskStepDispatchBody,
|
||||
TaskStepAdd,
|
||||
TaskStepUpdate,
|
||||
TaskStepMaterialItem,
|
||||
@@ -102,11 +103,35 @@ def _assert_production_task_write_access(
|
||||
if scope == "mine":
|
||||
if role != SUPER_ADMIN_ROLE and "production:my-task:list" not in codes:
|
||||
raise PermissionError("无菜单访问权限")
|
||||
production_task_svc.assert_task_assignee(db, task_id, user_id, tenant_no)
|
||||
production_task_svc.assert_task_step_assignee_or_legacy(
|
||||
db, task_id, user_id, tenant_no
|
||||
)
|
||||
elif role != SUPER_ADMIN_ROLE and "production:work-order:list" not in codes:
|
||||
raise PermissionError("无菜单访问权限")
|
||||
|
||||
|
||||
def _assert_production_task_step_write_access(
|
||||
db: Session,
|
||||
user: dict,
|
||||
step_id: str,
|
||||
tenant_no: str,
|
||||
operate_scope: Optional[str],
|
||||
) -> None:
|
||||
scope = (operate_scope or "manage").strip().lower()
|
||||
user_id = _get_current_user_id(user)
|
||||
role = user.get("role")
|
||||
codes = get_user_menu_codes(db, user_id) if role != SUPER_ADMIN_ROLE else set()
|
||||
manage = scope != "mine"
|
||||
if not manage:
|
||||
if role != SUPER_ADMIN_ROLE and "production:my-task:list" not in codes:
|
||||
raise PermissionError("无菜单访问权限")
|
||||
elif role != SUPER_ADMIN_ROLE and "production:work-order:list" not in codes:
|
||||
raise PermissionError("无菜单访问权限")
|
||||
production_task_svc.assert_step_assignee_for_write(
|
||||
db, step_id, user_id, tenant_no, manage=manage
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. 耗材
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -1840,7 +1865,7 @@ async def list_production_work_order_cell_product_options(
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
items = qc_work_order_svc.list_cell_product_options_for_production_work_order(
|
||||
items = qc_work_order_svc.list_step_output_dispatch_options_for_production_work_order(
|
||||
db, production_work_order_id=wo_id, tenant_no=tenant_no
|
||||
)
|
||||
return success_response(items)
|
||||
@@ -1860,8 +1885,7 @@ async def create_qc_work_order_from_production_api(
|
||||
wo = qc_work_order_svc.create_qc_work_order_from_production(
|
||||
db,
|
||||
production_work_order_id=wo_id,
|
||||
cell_product_id=body.cell_product_id,
|
||||
production_task_id=body.production_task_id,
|
||||
production_step_output_id=body.production_step_output_id,
|
||||
remark=body.remark or "",
|
||||
tenant_no=tenant_no,
|
||||
user_id=user.get("user_id"),
|
||||
@@ -2026,6 +2050,40 @@ async def reassign_production_task_api(
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.put("/production-tasks/{task_id}/steps/dispatch")
|
||||
async def dispatch_production_task_steps_api(
|
||||
task_id: str,
|
||||
body: ProductionTaskStepDispatchBody,
|
||||
operateScope: Optional[str] = Query(None, alias="operateScope"),
|
||||
user: dict = Depends(require_any_menu_code("production:my-task:list", "production:work-order:list")),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
_assert_production_task_write_access(db, user, task_id, tenant_no, operateScope)
|
||||
payload = [
|
||||
{
|
||||
"step_id": it.step_id,
|
||||
"assignee_user_ids": it.assignee_user_ids,
|
||||
"planned_start_time": it.planned_start_time,
|
||||
}
|
||||
for it in body.steps
|
||||
]
|
||||
detail = production_task_svc.dispatch_task_steps(
|
||||
db,
|
||||
task_id,
|
||||
tenant_no=tenant_no,
|
||||
steps_payload=payload,
|
||||
operator_id=user.get("user_id"),
|
||||
create_dept_id=user.get("dept_id", ""),
|
||||
)
|
||||
db.commit()
|
||||
return success_response(detail, message="步骤派发成功")
|
||||
except ValueError as e:
|
||||
db.rollback()
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.get("/production-tasks/{task_id}")
|
||||
async def get_production_task_detail(
|
||||
task_id: str,
|
||||
@@ -2132,6 +2190,7 @@ async def update_production_task_step(
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
_assert_production_task_write_access(db, user, task_id, tenant_no, operateScope)
|
||||
_assert_production_task_step_write_access(db, user, step_id, tenant_no, operateScope)
|
||||
data = body.model_dump(exclude_unset=True, by_alias=False)
|
||||
step = production_task_svc.update_task_step(
|
||||
db, step_id, tenant_no, user.get("user_id"), data,
|
||||
@@ -2154,6 +2213,7 @@ async def delete_production_task_step(
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
_assert_production_task_write_access(db, user, task_id, tenant_no, operateScope)
|
||||
_assert_production_task_step_write_access(db, user, step_id, tenant_no, operateScope)
|
||||
production_task_svc.delete_task_step(db, step_id, tenant_no, user.get("user_id"))
|
||||
return success_response(None, message="删除成功")
|
||||
except PermissionError as e:
|
||||
@@ -2191,6 +2251,7 @@ async def copy_production_task_step(
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
_assert_production_task_write_access(db, user, task_id, tenant_no, operateScope)
|
||||
_assert_production_task_step_write_access(db, user, step_id, tenant_no, operateScope)
|
||||
step_data = production_task_svc.copy_task_step(
|
||||
db,
|
||||
step_id=step_id,
|
||||
@@ -2216,6 +2277,7 @@ async def replace_task_step_reagents(
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
_assert_production_task_write_access(db, user, task_id, tenant_no, operateScope)
|
||||
_assert_production_task_step_write_access(db, user, step_id, tenant_no, operateScope)
|
||||
items_data = []
|
||||
for it in body:
|
||||
d = it.model_dump(by_alias=False)
|
||||
@@ -2250,6 +2312,7 @@ async def replace_task_step_consumables(
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
_assert_production_task_write_access(db, user, task_id, tenant_no, operateScope)
|
||||
_assert_production_task_step_write_access(db, user, step_id, tenant_no, operateScope)
|
||||
items_data = []
|
||||
for it in body:
|
||||
d = it.model_dump(by_alias=False)
|
||||
@@ -2284,6 +2347,7 @@ async def replace_task_step_configured_reagents(
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
_assert_production_task_write_access(db, user, task_id, tenant_no, operateScope)
|
||||
_assert_production_task_step_write_access(db, user, step_id, tenant_no, operateScope)
|
||||
items_data = []
|
||||
for it in body:
|
||||
d = it.model_dump(by_alias=False)
|
||||
@@ -2319,6 +2383,7 @@ async def replace_task_step_data_collections(
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
_assert_production_task_write_access(db, user, task_id, tenant_no, operateScope)
|
||||
_assert_production_task_step_write_access(db, user, step_id, tenant_no, operateScope)
|
||||
items_data = [it.model_dump(by_alias=False) for it in body]
|
||||
production_task_svc.replace_step_data_collections(db, step_id, tenant_no, user.get("user_id"), items_data)
|
||||
return success_response(None, message="更新成功")
|
||||
@@ -2340,6 +2405,7 @@ async def replace_task_step_outputs(
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
_assert_production_task_write_access(db, user, task_id, tenant_no, operateScope)
|
||||
_assert_production_task_step_write_access(db, user, step_id, tenant_no, operateScope)
|
||||
items_data = [it.model_dump(by_alias=False) for it in body]
|
||||
production_task_svc.replace_step_outputs(db, step_id, tenant_no, user.get("user_id"), items_data)
|
||||
return success_response(None, message="更新成功")
|
||||
|
||||
@@ -12,6 +12,7 @@ from app.core.utils import generate_uuid
|
||||
from app.crud.equipment_snapshot import parse_equipment_ids, resolve_equipment_list_snapshot
|
||||
from app.models.models import (
|
||||
BizProcess,
|
||||
BizProcessCategory,
|
||||
BizProcessConsumable,
|
||||
BizProcessDataCollection,
|
||||
BizProcessOutput,
|
||||
@@ -124,7 +125,18 @@ def list_processes(
|
||||
page_size = min(max(1, page_size), 100)
|
||||
rows = (
|
||||
_filtered()
|
||||
.order_by(BizProcess.create_time.desc())
|
||||
.outerjoin(
|
||||
BizProcessCategory,
|
||||
and_(
|
||||
BizProcess.category_id == BizProcessCategory.id,
|
||||
BizProcessCategory.del_flag == 0,
|
||||
),
|
||||
)
|
||||
.order_by(
|
||||
BizProcessCategory.category_name.is_(None),
|
||||
BizProcessCategory.category_name.asc(),
|
||||
BizProcess.create_time.desc(),
|
||||
)
|
||||
.offset((page - 1) * page_size)
|
||||
.limit(page_size)
|
||||
.all()
|
||||
|
||||
@@ -11,6 +11,7 @@ from sqlalchemy.orm import Session
|
||||
from app.core.utils import generate_uuid
|
||||
from app.crud.equipment_snapshot import parse_equipment_ids, resolve_equipment_list_snapshot
|
||||
from app.models.models import (
|
||||
BizCellProductType,
|
||||
BizProcess,
|
||||
BizProcessReagent,
|
||||
BizProcessConsumable,
|
||||
@@ -145,8 +146,16 @@ def list_routes(db: Session, *, page: int = 1, page_size: int = 10,
|
||||
page_size = min(max(1, page_size), 100)
|
||||
rows = (
|
||||
_filtered()
|
||||
.outerjoin(
|
||||
BizCellProductType,
|
||||
and_(
|
||||
BizProcessRoute.product_type_id == BizCellProductType.id,
|
||||
BizCellProductType.del_flag == 0,
|
||||
),
|
||||
)
|
||||
.order_by(
|
||||
func.coalesce(BizProcessRoute.order_num, 999999).asc(),
|
||||
BizCellProductType.product_type_name.is_(None),
|
||||
BizCellProductType.product_type_name.asc(),
|
||||
BizProcessRoute.create_time.desc(),
|
||||
)
|
||||
.offset((page - 1) * page_size)
|
||||
|
||||
@@ -29,6 +29,7 @@ from app.models.models import (
|
||||
BizProductionTaskInput,
|
||||
BizProductionTaskOutput,
|
||||
BizProductionTaskStep,
|
||||
BizProductionTaskStepAssignee,
|
||||
BizProductionTaskStepConsumable,
|
||||
BizProductionTaskStepConfiguredReagent,
|
||||
BizProductionTaskStepDataCollection,
|
||||
@@ -305,8 +306,14 @@ def _step_to_dict(s: BizProductionTaskStep) -> Dict[str, Any]:
|
||||
"actualDuration": s.actual_duration or "",
|
||||
"sopIds": s.sop_ids or "",
|
||||
"stepStatus": s.step_status or "dzx",
|
||||
"plannedStartTime": _fmt_dt(getattr(s, "planned_start_time", None)),
|
||||
"startedTime": _fmt_dt(s.started_time),
|
||||
"completedTime": _fmt_dt(s.completed_time),
|
||||
"completedBy": getattr(s, "completed_by", None) or "",
|
||||
"completedByName": "",
|
||||
"assigneeUserIds": [],
|
||||
"assigneeNames": [],
|
||||
"assignees": [],
|
||||
"remark": s.remark or "",
|
||||
}
|
||||
|
||||
@@ -684,12 +691,54 @@ def get_production_task_row(
|
||||
def assert_task_assignee(
|
||||
db: Session, task_id: str, user_id: str, tenant_no: str
|
||||
) -> BizProductionTask:
|
||||
"""Deprecated:优先使用 assert_task_step_assignee_or_legacy。"""
|
||||
return assert_task_step_assignee_or_legacy(db, task_id, user_id, tenant_no)
|
||||
|
||||
|
||||
def assert_task_step_assignee_or_legacy(
|
||||
db: Session, task_id: str, user_id: str, tenant_no: str
|
||||
) -> BizProductionTask:
|
||||
from app.crud import production_task_step_assignee as step_assignee_svc
|
||||
|
||||
task = get_production_task_row(db, task_id, tenant_no)
|
||||
if not task:
|
||||
raise ValueError("任务不存在")
|
||||
if (task.current_assignee_user_id or "") != (user_id or ""):
|
||||
raise PermissionError("非当前任务负责人,无权操作")
|
||||
return task
|
||||
if step_assignee_svc.user_is_any_step_assignee_of_task(db, task_id, user_id, tenant_no):
|
||||
return task
|
||||
if (task.current_assignee_user_id or "") == (user_id or ""):
|
||||
return task
|
||||
raise PermissionError("非任务步骤负责人,无权操作")
|
||||
|
||||
|
||||
def assert_step_assignee_for_write(
|
||||
db: Session,
|
||||
step_id: str,
|
||||
user_id: str,
|
||||
tenant_no: str,
|
||||
*,
|
||||
manage: bool = False,
|
||||
) -> BizProductionTaskStep:
|
||||
if manage:
|
||||
step = db.query(BizProductionTaskStep).filter(
|
||||
BizProductionTaskStep.id == step_id,
|
||||
BizProductionTaskStep.tenant_no == tenant_no,
|
||||
BizProductionTaskStep.del_flag == 0,
|
||||
).first()
|
||||
if not step:
|
||||
raise ValueError("步骤不存在")
|
||||
return step
|
||||
from app.crud import production_task_step_assignee as step_assignee_svc
|
||||
|
||||
step = db.query(BizProductionTaskStep).filter(
|
||||
BizProductionTaskStep.id == step_id,
|
||||
BizProductionTaskStep.tenant_no == tenant_no,
|
||||
BizProductionTaskStep.del_flag == 0,
|
||||
).first()
|
||||
if not step:
|
||||
raise ValueError("步骤不存在")
|
||||
if not step_assignee_svc.user_is_step_assignee(db, step_id, user_id, tenant_no):
|
||||
raise PermissionError("非当前步骤负责人,无权操作")
|
||||
return step
|
||||
|
||||
|
||||
def _record_task_handover(
|
||||
@@ -842,7 +891,9 @@ def create_production_task(
|
||||
task_type = "outbound"
|
||||
|
||||
assignee_raw = (data.get("assignee_user_id") or data.get("assigneeUserId") or "").strip()
|
||||
assignee_user_id = _validate_assignee_user_id(db, assignee_raw, tenant_no)
|
||||
assignee_user_id = None
|
||||
if assignee_raw:
|
||||
assignee_user_id = _validate_assignee_user_id(db, assignee_raw, tenant_no)
|
||||
|
||||
task_no = _generate_task_no(db, tenant_no)
|
||||
now = datetime.now()
|
||||
@@ -891,6 +942,71 @@ def create_production_task(
|
||||
return task
|
||||
|
||||
|
||||
def dispatch_task_steps(
|
||||
db: Session,
|
||||
task_id: str,
|
||||
*,
|
||||
tenant_no: str,
|
||||
steps_payload: List[Dict[str, Any]],
|
||||
operator_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
) -> Dict[str, Any]:
|
||||
from app.crud import production_task_step_assignee as step_assignee_svc
|
||||
|
||||
task = get_production_task_row(db, task_id, tenant_no)
|
||||
if not task:
|
||||
raise ValueError("任务不存在")
|
||||
if not steps_payload:
|
||||
raise ValueError("请至少指定一个步骤的负责人")
|
||||
|
||||
step_rows = {
|
||||
s.id: s
|
||||
for s in db.query(BizProductionTaskStep).filter(
|
||||
BizProductionTaskStep.task_id == task_id,
|
||||
BizProductionTaskStep.tenant_no == tenant_no,
|
||||
BizProductionTaskStep.del_flag == 0,
|
||||
).all()
|
||||
}
|
||||
|
||||
for item in steps_payload:
|
||||
sid = (item.get("step_id") or item.get("stepId") or "").strip()
|
||||
if sid not in step_rows:
|
||||
raise ValueError(f"步骤不存在或不属于该任务: {sid}")
|
||||
user_ids = item.get("assignee_user_ids") or item.get("assigneeUserIds") or []
|
||||
step_assignee_svc.sync_assignees_for_step(
|
||||
db,
|
||||
sid,
|
||||
user_ids,
|
||||
tenant_no=tenant_no,
|
||||
operator_id=operator_id,
|
||||
create_dept_id=create_dept_id,
|
||||
)
|
||||
step = step_rows[sid]
|
||||
if "planned_start_time" in item or "plannedStartTime" in item:
|
||||
pst = item.get("planned_start_time")
|
||||
if pst is None and "plannedStartTime" in item:
|
||||
pst = item.get("plannedStartTime")
|
||||
if pst is None or pst == "":
|
||||
step.planned_start_time = None
|
||||
else:
|
||||
if isinstance(pst, datetime):
|
||||
step.planned_start_time = pst
|
||||
else:
|
||||
parsed = parse_datetime(str(pst).strip())
|
||||
if parsed is None:
|
||||
raise ValueError("计划开始时间格式无效")
|
||||
step.planned_start_time = parsed
|
||||
step.update_by = operator_id
|
||||
step.update_time = datetime.now()
|
||||
db.add(step)
|
||||
|
||||
db.flush()
|
||||
detail = get_production_task_detail(db, task_id, tenant_no)
|
||||
if not detail:
|
||||
raise ValueError("任务不存在")
|
||||
return detail
|
||||
|
||||
|
||||
def list_production_tasks(
|
||||
db: Session, *, tenant_no: str,
|
||||
page: int = 1, page_size: int = 10,
|
||||
@@ -901,6 +1017,7 @@ def list_production_tasks(
|
||||
started_time_start: Optional[str] = None,
|
||||
started_time_end: Optional[str] = None,
|
||||
current_assignee_user_id: Optional[str] = None,
|
||||
step_assignee_user_id: Optional[str] = None,
|
||||
mine_history_user_id: Optional[str] = None,
|
||||
work_order_type: Optional[str] = None,
|
||||
reception_source: Optional[str] = None,
|
||||
@@ -954,6 +1071,29 @@ def list_production_tasks(
|
||||
ca_uid = (current_assignee_user_id or "").strip()
|
||||
if ca_uid:
|
||||
q = q.filter(BizProductionTask.current_assignee_user_id == ca_uid)
|
||||
sa_uid = (step_assignee_user_id or "").strip()
|
||||
if sa_uid:
|
||||
step_task_ids = (
|
||||
db.query(BizProductionTaskStep.task_id)
|
||||
.join(
|
||||
BizProductionTaskStepAssignee,
|
||||
BizProductionTaskStepAssignee.step_id == BizProductionTaskStep.id,
|
||||
)
|
||||
.filter(
|
||||
BizProductionTaskStepAssignee.user_id == sa_uid,
|
||||
BizProductionTaskStepAssignee.tenant_no == tenant_no,
|
||||
BizProductionTaskStepAssignee.del_flag == 0,
|
||||
BizProductionTaskStep.del_flag == 0,
|
||||
)
|
||||
.distinct()
|
||||
.subquery()
|
||||
)
|
||||
q = q.filter(
|
||||
or_(
|
||||
BizProductionTask.id.in_(step_task_ids),
|
||||
BizProductionTask.current_assignee_user_id == sa_uid,
|
||||
)
|
||||
)
|
||||
mh_uid = (mine_history_user_id or "").strip()
|
||||
if mh_uid:
|
||||
handover_task_ids = (
|
||||
@@ -1252,7 +1392,7 @@ def list_mine_production_tasks(
|
||||
page_size=page_size,
|
||||
keyword=keyword,
|
||||
task_status=task_status,
|
||||
current_assignee_user_id=uid,
|
||||
step_assignee_user_id=uid,
|
||||
work_order_type=work_order_type,
|
||||
reception_source=reception_source,
|
||||
biz_type=biz_type,
|
||||
@@ -1350,6 +1490,11 @@ def get_production_task_detail(db: Session, task_id: str, tenant_no: str) -> Opt
|
||||
sd["dataCollections"] = [_step_data_collection_to_dict(d) for d in data_collections]
|
||||
step_list.append(sd)
|
||||
|
||||
from app.crud.production_task_step_assignee import enrich_step_assignees, enrich_step_completed_by_names
|
||||
|
||||
enrich_step_assignees(db, step_list, tenant_no=tenant_no)
|
||||
enrich_step_completed_by_names(db, step_list)
|
||||
|
||||
inputs = db.query(BizProductionTaskInput).filter(
|
||||
and_(BizProductionTaskInput.task_id == task_id, BizProductionTaskInput.del_flag == 0)
|
||||
).order_by(BizProductionTaskInput.order_num.asc(), BizProductionTaskInput.create_time.asc()).all()
|
||||
@@ -1729,11 +1874,18 @@ def update_task_step(
|
||||
step.equipment_ids = eids
|
||||
step.equipment_name = enames
|
||||
if data.get("started_time"):
|
||||
from dateutil.parser import parse as _parse_dt
|
||||
step.started_time = _parse_dt(data["started_time"])
|
||||
parsed = parse_datetime(str(data["started_time"]).strip())
|
||||
if parsed is None:
|
||||
raise ValueError("开始时间格式无效")
|
||||
step.started_time = parsed
|
||||
if data.get("completed_time"):
|
||||
from dateutil.parser import parse as _parse_dt
|
||||
step.completed_time = _parse_dt(data["completed_time"])
|
||||
parsed = parse_datetime(str(data["completed_time"]).strip())
|
||||
if parsed is None:
|
||||
raise ValueError("完成时间格式无效")
|
||||
step.completed_time = parsed
|
||||
new_status = (data.get("step_status") or "").strip()
|
||||
if new_status == "ywc" and user_id:
|
||||
step.completed_by = user_id
|
||||
step.update_by = user_id
|
||||
step.update_time = datetime.now()
|
||||
db.add(step)
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
"""生产任务步骤负责人 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 BizProductionTaskStep, BizProductionTaskStepAssignee, 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_step(
|
||||
db: Session,
|
||||
step_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(BizProductionTaskStepAssignee)
|
||||
.filter(
|
||||
BizProductionTaskStepAssignee.step_id == step_id,
|
||||
BizProductionTaskStepAssignee.tenant_no == tenant_no,
|
||||
BizProductionTaskStepAssignee.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(
|
||||
BizProductionTaskStepAssignee(
|
||||
id=generate_uuid(),
|
||||
step_id=step_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 enrich_step_assignees(
|
||||
db: Session, steps: List[Dict], *, tenant_no: str
|
||||
) -> None:
|
||||
"""批量填充 assigneeUserIds / assigneeNames / assignees。"""
|
||||
step_ids = [s["id"] for s in steps if s.get("id")]
|
||||
if not step_ids:
|
||||
return
|
||||
rows = (
|
||||
db.query(BizProductionTaskStepAssignee, SysUser)
|
||||
.outerjoin(SysUser, eq_unicode(SysUser.id, BizProductionTaskStepAssignee.user_id))
|
||||
.filter(
|
||||
BizProductionTaskStepAssignee.step_id.in_(step_ids),
|
||||
BizProductionTaskStepAssignee.tenant_no == tenant_no,
|
||||
BizProductionTaskStepAssignee.del_flag == 0,
|
||||
)
|
||||
.order_by(
|
||||
BizProductionTaskStepAssignee.order_num.asc(),
|
||||
BizProductionTaskStepAssignee.create_time.asc(),
|
||||
)
|
||||
.all()
|
||||
)
|
||||
by_step: Dict[str, List] = {}
|
||||
for assignee, user in rows:
|
||||
by_step.setdefault(assignee.step_id, []).append((assignee, user))
|
||||
for step in steps:
|
||||
pairs = by_step.get(step["id"], [])
|
||||
step["assigneeUserIds"] = [a.user_id for a, _ in pairs]
|
||||
step["assigneeNames"] = [
|
||||
f"{(u.nick_name or u.user_name or '')}({u.user_no or ''})".strip()
|
||||
for _, u in pairs
|
||||
if u
|
||||
]
|
||||
step["assignees"] = [
|
||||
{
|
||||
"userId": a.user_id,
|
||||
"nickName": (u.nick_name or u.user_name or "") if u else "",
|
||||
"userNo": (u.user_no or "") if u else "",
|
||||
}
|
||||
for a, u in pairs
|
||||
]
|
||||
|
||||
|
||||
def enrich_step_completed_by_names(db: Session, steps: List[Dict]) -> None:
|
||||
uids = list({(s.get("completedBy") or "").strip() for s in steps if (s.get("completedBy") or "").strip()})
|
||||
if not uids:
|
||||
return
|
||||
users = {
|
||||
u.id: u
|
||||
for u in db.query(SysUser).filter(SysUser.id.in_(uids), SysUser.del_flag == 0).all()
|
||||
}
|
||||
for step in steps:
|
||||
uid = (step.get("completedBy") or "").strip()
|
||||
if not uid:
|
||||
step["completedByName"] = ""
|
||||
continue
|
||||
u = users.get(uid)
|
||||
step["completedByName"] = (
|
||||
f"{(u.nick_name or u.user_name or '')}({u.user_no or ''})".strip() if u else uid
|
||||
)
|
||||
|
||||
|
||||
def user_is_step_assignee(
|
||||
db: Session, step_id: str, user_id: str, tenant_no: str
|
||||
) -> bool:
|
||||
uid = (user_id or "").strip()
|
||||
if not uid:
|
||||
return False
|
||||
row = (
|
||||
db.query(BizProductionTaskStepAssignee.id)
|
||||
.filter(
|
||||
BizProductionTaskStepAssignee.step_id == step_id,
|
||||
BizProductionTaskStepAssignee.user_id == uid,
|
||||
BizProductionTaskStepAssignee.tenant_no == tenant_no,
|
||||
BizProductionTaskStepAssignee.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
return row is not None
|
||||
|
||||
|
||||
def user_is_any_step_assignee_of_task(
|
||||
db: Session, task_id: str, user_id: str, tenant_no: str
|
||||
) -> bool:
|
||||
uid = (user_id or "").strip()
|
||||
if not uid:
|
||||
return False
|
||||
row = (
|
||||
db.query(BizProductionTaskStepAssignee.id)
|
||||
.join(
|
||||
BizProductionTaskStep,
|
||||
BizProductionTaskStep.id == BizProductionTaskStepAssignee.step_id,
|
||||
)
|
||||
.filter(
|
||||
BizProductionTaskStep.task_id == task_id,
|
||||
BizProductionTaskStep.del_flag == 0,
|
||||
BizProductionTaskStepAssignee.user_id == uid,
|
||||
BizProductionTaskStepAssignee.tenant_no == tenant_no,
|
||||
BizProductionTaskStepAssignee.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
return row is not None
|
||||
@@ -519,9 +519,9 @@ def get_task_detail(db: Session, row_id: str, tenant_no: str) -> Dict[str, Any]:
|
||||
out = _task_row_to_dict(t, wo, db, tenant_no)
|
||||
out = _enrich_tasks_reception_fields(db, [out])[0]
|
||||
out = assignee_svc.enrich_tasks_with_assignees(db, [out], tenant_no)[0]
|
||||
from app.crud.qc_work_order import _enrich_work_order_cell_products
|
||||
from app.crud.qc_work_order import _enrich_work_order_qc_targets
|
||||
|
||||
out = _enrich_work_order_cell_products(db, tenant_no, [out])[0]
|
||||
out = _enrich_work_order_qc_targets(db, tenant_no, [out])[0]
|
||||
if (out.get("qcBizType") or "") != "temporary":
|
||||
resolved_reception_id = _resolve_reception_id_for_work_order_detail(db, wo, tenant_no)
|
||||
reception_detail = (
|
||||
|
||||
+235
-116
@@ -33,8 +33,10 @@ from app.models.models import (
|
||||
BizPilotPatient,
|
||||
BizProtocolSample,
|
||||
BizProductionTask,
|
||||
BizProductionTaskOutput,
|
||||
BizProductionTaskStep,
|
||||
BizProductionTaskStepOutput,
|
||||
BizProductionWorkOrder,
|
||||
BizOutputType,
|
||||
BizQcLabTestItem,
|
||||
BizQcTask,
|
||||
BizQcThirdPartyItem,
|
||||
@@ -65,6 +67,7 @@ _TRIGGER_SOURCE_LABELS = {
|
||||
}
|
||||
_ACCEPT_CONCLUSION_LABELS = {"js": "接收", "bj": "拒收"}
|
||||
_WORK_ORDER_STATUS_LABELS = {"dpz": "待配置", "ypz": "已配置", "ywc": "已完成", "yzf": "已作废"}
|
||||
_VALID_QC_DISPATCH_OUTPUT_TYPE_NAME = "有效物"
|
||||
_VALID_QC_WORK_ORDER_STATUSES = frozenset(_WORK_ORDER_STATUS_LABELS.keys())
|
||||
_TASK_TYPE_LABELS = {"sysz": "实验室自检", "dsfjc": "第三方检测"}
|
||||
_TASK_STATUS_LABELS = {"dzx": "待执行", "jxz": "进行中", "ywc": "已完成"}
|
||||
@@ -199,6 +202,52 @@ def _enrich_work_order_cell_products(
|
||||
return items
|
||||
|
||||
|
||||
def _enrich_work_order_step_outputs(
|
||||
db: Session, tenant_no: str, items: List[Dict[str, Any]]
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""步骤产出物触发的质检:无细胞产品时用工单条码/名称展示质检对象。"""
|
||||
if not items:
|
||||
return items
|
||||
step_output_ids = list(
|
||||
{
|
||||
x.get("productionStepOutputId")
|
||||
for x in items
|
||||
if (x.get("productionStepOutputId") or "").strip()
|
||||
and not (x.get("cellProductId") or "").strip()
|
||||
}
|
||||
)
|
||||
if not step_output_ids:
|
||||
return items
|
||||
rows = (
|
||||
db.query(BizProductionTaskStepOutput)
|
||||
.filter(
|
||||
BizProductionTaskStepOutput.id.in_(step_output_ids),
|
||||
BizProductionTaskStepOutput.tenant_no == tenant_no,
|
||||
BizProductionTaskStepOutput.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
row_map = {r.id: r for r in rows}
|
||||
for item in items:
|
||||
if (item.get("cellProductId") or "").strip():
|
||||
continue
|
||||
so = row_map.get(item.get("productionStepOutputId") or "")
|
||||
if not so:
|
||||
continue
|
||||
if not (item.get("cellProductCode") or "").strip():
|
||||
item["cellProductCode"] = (so.output_barcode or "").strip()
|
||||
if not (item.get("cellProductName") or "").strip():
|
||||
item["cellProductName"] = (so.output_name or "").strip()
|
||||
return items
|
||||
|
||||
|
||||
def _enrich_work_order_qc_targets(
|
||||
db: Session, tenant_no: str, items: List[Dict[str, Any]]
|
||||
) -> List[Dict[str, Any]]:
|
||||
items = _enrich_work_order_cell_products(db, tenant_no, items)
|
||||
return _enrich_work_order_step_outputs(db, tenant_no, items)
|
||||
|
||||
|
||||
def _enrich_outbound_work_orders(
|
||||
db: Session, tenant_no: str, items: List[Dict[str, Any]]
|
||||
) -> List[Dict[str, Any]]:
|
||||
@@ -710,6 +759,7 @@ def _wo_to_dict(
|
||||
"productionWorkOrderId": getattr(wo, "production_work_order_id", None) or "",
|
||||
"productionWorkOrderNo": "",
|
||||
"productionTaskId": getattr(wo, "production_task_id", None) or "",
|
||||
"productionStepOutputId": getattr(wo, "production_step_output_id", None) or "",
|
||||
"receptionTime": "",
|
||||
"handlerName": "",
|
||||
"sampleTypeName": "",
|
||||
@@ -846,12 +896,42 @@ def create_work_order_from_reception(
|
||||
return wo
|
||||
|
||||
|
||||
def _valid_qc_dispatch_output_type_ids(db: Session, tenant_no: str) -> set:
|
||||
rows = (
|
||||
db.query(BizOutputType)
|
||||
.filter(
|
||||
BizOutputType.tenant_no == tenant_no,
|
||||
BizOutputType.del_flag == 0,
|
||||
BizOutputType.type_name == _VALID_QC_DISPATCH_OUTPUT_TYPE_NAME,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
return {r.id for r in rows}
|
||||
|
||||
|
||||
def _resolve_cell_product_id_by_barcode(
|
||||
db: Session, barcode: Optional[str], tenant_no: str
|
||||
) -> Optional[str]:
|
||||
code = (barcode or "").strip()
|
||||
if not code:
|
||||
return None
|
||||
cp = (
|
||||
db.query(BizCellProduct)
|
||||
.filter(
|
||||
BizCellProduct.product_code == code,
|
||||
BizCellProduct.tenant_no == tenant_no,
|
||||
BizCellProduct.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
return cp.id if cp else None
|
||||
|
||||
|
||||
def create_qc_work_order_from_production(
|
||||
db: Session,
|
||||
*,
|
||||
production_work_order_id: str,
|
||||
cell_product_id: str,
|
||||
production_task_id: Optional[str] = None,
|
||||
production_step_output_id: str,
|
||||
remark: str = "",
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
@@ -878,28 +958,76 @@ def create_qc_work_order_from_production(
|
||||
if status not in ("jxz", "ywc"):
|
||||
raise ValueError("仅进行中或已完成的生产工单可派发质检")
|
||||
|
||||
cp_id = _validate_cell_product_id(db, cell_product_id, tenant_no)
|
||||
options = list_cell_product_options_for_production_work_order(
|
||||
step_output_id = (production_step_output_id or "").strip()
|
||||
if not step_output_id:
|
||||
raise ValueError("请选择步骤产出物")
|
||||
|
||||
options = list_step_output_dispatch_options_for_production_work_order(
|
||||
db, production_work_order_id=production_work_order_id, tenant_no=tenant_no
|
||||
)
|
||||
option_ids = {o["id"] for o in options}
|
||||
if cp_id not in option_ids:
|
||||
raise ValueError("所选细胞产品不在该生产工单的产出列表中")
|
||||
option_map = {o["id"]: o for o in options}
|
||||
selected = option_map.get(step_output_id)
|
||||
if not selected:
|
||||
raise ValueError("所选步骤产出物不在该生产工单的可派发列表中")
|
||||
|
||||
task_id = (production_task_id or "").strip() or None
|
||||
if task_id:
|
||||
task = (
|
||||
db.query(BizProductionTask)
|
||||
.filter(
|
||||
BizProductionTask.id == task_id,
|
||||
BizProductionTask.work_order_id == pwo.id,
|
||||
BizProductionTask.tenant_no == tenant_no,
|
||||
BizProductionTask.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
step_output = (
|
||||
db.query(BizProductionTaskStepOutput)
|
||||
.filter(
|
||||
BizProductionTaskStepOutput.id == step_output_id,
|
||||
BizProductionTaskStepOutput.tenant_no == tenant_no,
|
||||
BizProductionTaskStepOutput.del_flag == 0,
|
||||
)
|
||||
if not task:
|
||||
raise ValueError("关联生产任务不存在")
|
||||
.first()
|
||||
)
|
||||
if not step_output:
|
||||
raise ValueError("步骤产出物不存在")
|
||||
|
||||
step = (
|
||||
db.query(BizProductionTaskStep)
|
||||
.filter(
|
||||
BizProductionTaskStep.id == step_output.step_id,
|
||||
BizProductionTaskStep.tenant_no == tenant_no,
|
||||
BizProductionTaskStep.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if not step:
|
||||
raise ValueError("关联工艺步骤不存在")
|
||||
|
||||
task = (
|
||||
db.query(BizProductionTask)
|
||||
.filter(
|
||||
BizProductionTask.id == step.task_id,
|
||||
BizProductionTask.work_order_id == pwo.id,
|
||||
BizProductionTask.tenant_no == tenant_no,
|
||||
BizProductionTask.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if not task:
|
||||
raise ValueError("关联生产任务不存在")
|
||||
|
||||
cp_id = _resolve_cell_product_id_by_barcode(db, step_output.output_barcode, tenant_no)
|
||||
task_id = task.id
|
||||
|
||||
common_fields = dict(
|
||||
trigger_source="production",
|
||||
cell_product_id=cp_id,
|
||||
production_work_order_id=pwo.id,
|
||||
production_task_id=task_id,
|
||||
production_step_output_id=step_output_id,
|
||||
work_order_status="dpz",
|
||||
has_lab="0",
|
||||
has_third_party="0",
|
||||
tenant_no=tenant_no,
|
||||
remark=(remark or "").strip() or None,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id or "",
|
||||
update_by=user_id,
|
||||
create_time=datetime.now(),
|
||||
update_time=datetime.now(),
|
||||
del_flag=0,
|
||||
)
|
||||
|
||||
if wo_type == "outbound":
|
||||
schedule_id = (getattr(pwo, "infusion_schedule_id", None) or "").strip()
|
||||
@@ -921,21 +1049,7 @@ def create_qc_work_order_from_production(
|
||||
qc_biz_type="outbound",
|
||||
biz_type=biz_type,
|
||||
infusion_schedule_id=schedule_id,
|
||||
trigger_source="production",
|
||||
cell_product_id=cp_id,
|
||||
production_work_order_id=pwo.id,
|
||||
production_task_id=task_id,
|
||||
work_order_status="dpz",
|
||||
has_lab="0",
|
||||
has_third_party="0",
|
||||
tenant_no=tenant_no,
|
||||
remark=(remark or "").strip() or None,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id or "",
|
||||
update_by=user_id,
|
||||
create_time=datetime.now(),
|
||||
update_time=datetime.now(),
|
||||
del_flag=0,
|
||||
**common_fields,
|
||||
)
|
||||
elif wo_type == "temporary":
|
||||
wo = BizQcWorkOrder(
|
||||
@@ -949,29 +1063,13 @@ def create_qc_work_order_from_production(
|
||||
sample_code=None,
|
||||
reception_source=None,
|
||||
qc_biz_type="temporary",
|
||||
trigger_source="production",
|
||||
cell_product_id=cp_id,
|
||||
production_work_order_id=pwo.id,
|
||||
production_task_id=task_id,
|
||||
work_order_status="dpz",
|
||||
has_lab="0",
|
||||
has_third_party="0",
|
||||
tenant_no=tenant_no,
|
||||
remark=(remark or "").strip() or None,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id or "",
|
||||
update_by=user_id,
|
||||
create_time=datetime.now(),
|
||||
update_time=datetime.now(),
|
||||
del_flag=0,
|
||||
**common_fields,
|
||||
)
|
||||
else:
|
||||
wo = BizQcWorkOrder(
|
||||
id=generate_uuid(),
|
||||
work_order_no=_gen_daily_no(db, tenant_no, "ZJ"),
|
||||
work_order_type="inbound",
|
||||
# 生产过程触发不写入 reception_id,避免与 uk_qc_wo_reception(reception_id,del_flag) 冲突;
|
||||
# 样本关联仍通过 sample_code / protocol_sample_id 等快照字段。
|
||||
reception_id=None,
|
||||
protocol_sample_id=pwo.protocol_sample_id,
|
||||
collection_protocol_id=pwo.collection_protocol_id,
|
||||
@@ -979,34 +1077,20 @@ def create_qc_work_order_from_production(
|
||||
sample_code=pwo.sample_code or None,
|
||||
reception_source=getattr(pwo, "reception_source", "cell_storage") or "cell_storage",
|
||||
qc_biz_type="inbound",
|
||||
trigger_source="production",
|
||||
cell_product_id=cp_id,
|
||||
production_work_order_id=pwo.id,
|
||||
production_task_id=task_id,
|
||||
work_order_status="dpz",
|
||||
has_lab="0",
|
||||
has_third_party="0",
|
||||
tenant_no=tenant_no,
|
||||
remark=(remark or "").strip() or None,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id or "",
|
||||
update_by=user_id,
|
||||
create_time=datetime.now(),
|
||||
update_time=datetime.now(),
|
||||
del_flag=0,
|
||||
**common_fields,
|
||||
)
|
||||
db.add(wo)
|
||||
db.flush()
|
||||
return wo
|
||||
|
||||
|
||||
def list_cell_product_options_for_production_work_order(
|
||||
def list_step_output_dispatch_options_for_production_work_order(
|
||||
db: Session,
|
||||
*,
|
||||
production_work_order_id: str,
|
||||
tenant_no: str,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""汇总生产工单下任务产出中的细胞产品(去重)。"""
|
||||
"""汇总生产工单下可派发的步骤产出物:类型为有效物且有条码。"""
|
||||
pwo = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(
|
||||
@@ -1019,6 +1103,10 @@ def list_cell_product_options_for_production_work_order(
|
||||
if not pwo:
|
||||
raise ValueError("生产工单不存在")
|
||||
|
||||
valid_type_ids = _valid_qc_dispatch_output_type_ids(db, tenant_no)
|
||||
if not valid_type_ids:
|
||||
return []
|
||||
|
||||
tasks = (
|
||||
db.query(BizProductionTask)
|
||||
.filter(
|
||||
@@ -1033,60 +1121,91 @@ def list_cell_product_options_for_production_work_order(
|
||||
|
||||
task_map = {t.id: t for t in tasks}
|
||||
task_ids = list(task_map.keys())
|
||||
outputs = (
|
||||
db.query(BizProductionTaskOutput)
|
||||
steps = (
|
||||
db.query(BizProductionTaskStep)
|
||||
.filter(
|
||||
BizProductionTaskOutput.task_id.in_(task_ids),
|
||||
BizProductionTaskOutput.tenant_no == tenant_no,
|
||||
BizProductionTaskOutput.del_flag == 0,
|
||||
BizProductionTaskOutput.cell_product_id.isnot(None),
|
||||
BizProductionTaskOutput.cell_product_id != "",
|
||||
BizProductionTaskStep.task_id.in_(task_ids),
|
||||
BizProductionTaskStep.tenant_no == tenant_no,
|
||||
BizProductionTaskStep.del_flag == 0,
|
||||
)
|
||||
.order_by(BizProductionTaskOutput.order_num.asc(), BizProductionTaskOutput.create_time.asc())
|
||||
.all()
|
||||
)
|
||||
seen: set[str] = set()
|
||||
items: List[Dict[str, Any]] = []
|
||||
for out in outputs:
|
||||
cp_id = (out.cell_product_id or "").strip()
|
||||
if not cp_id or cp_id in seen:
|
||||
continue
|
||||
seen.add(cp_id)
|
||||
task = task_map.get(out.task_id)
|
||||
items.append(
|
||||
{
|
||||
"id": cp_id,
|
||||
"cellProductId": cp_id,
|
||||
"taskId": out.task_id,
|
||||
"taskNo": task.task_no if task else "",
|
||||
}
|
||||
)
|
||||
|
||||
if not items:
|
||||
if not steps:
|
||||
return []
|
||||
|
||||
cp_ids = [i["id"] for i in items]
|
||||
products = (
|
||||
db.query(BizCellProduct)
|
||||
step_map = {s.id: s for s in steps}
|
||||
step_ids = list(step_map.keys())
|
||||
type_rows = (
|
||||
db.query(BizOutputType)
|
||||
.filter(
|
||||
BizCellProduct.id.in_(cp_ids),
|
||||
BizCellProduct.tenant_no == tenant_no,
|
||||
BizCellProduct.del_flag == 0,
|
||||
BizOutputType.id.in_(list(valid_type_ids)),
|
||||
BizOutputType.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
product_dicts = _cp_enrich(db, tenant_no, [_cp_row_to_dict(p) for p in products])
|
||||
product_map = {d["id"]: d for d in product_dicts}
|
||||
for item in items:
|
||||
cp = product_map.get(item["id"]) or {}
|
||||
item["productCode"] = cp.get("productCode", "")
|
||||
item["productName"] = cp.get("productName", "")
|
||||
item["productTypeName"] = cp.get("productTypeName", "")
|
||||
item["passage"] = cp.get("passage", "")
|
||||
item["storageSlotName"] = cp.get("storageSlotName", "")
|
||||
type_name_map = {t.id: t.type_name or "" for t in type_rows}
|
||||
|
||||
outputs = (
|
||||
db.query(BizProductionTaskStepOutput)
|
||||
.filter(
|
||||
BizProductionTaskStepOutput.step_id.in_(step_ids),
|
||||
BizProductionTaskStepOutput.tenant_no == tenant_no,
|
||||
BizProductionTaskStepOutput.del_flag == 0,
|
||||
BizProductionTaskStepOutput.output_type_id.in_(list(valid_type_ids)),
|
||||
)
|
||||
.order_by(
|
||||
BizProductionTaskStepOutput.order_num.asc(),
|
||||
BizProductionTaskStepOutput.create_time.asc(),
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
items: List[Dict[str, Any]] = []
|
||||
for out in outputs:
|
||||
barcode = (out.output_barcode or "").strip()
|
||||
if not barcode:
|
||||
continue
|
||||
step = step_map.get(out.step_id)
|
||||
if not step:
|
||||
continue
|
||||
task = task_map.get(step.task_id)
|
||||
if not task:
|
||||
continue
|
||||
type_id = (out.output_type_id or "").strip()
|
||||
cell_product_id = _resolve_cell_product_id_by_barcode(db, barcode, tenant_no)
|
||||
items.append(
|
||||
{
|
||||
"id": out.id,
|
||||
"stepOutputId": out.id,
|
||||
"taskId": task.id,
|
||||
"taskNo": task.task_no or "",
|
||||
"taskName": task.task_name or "",
|
||||
"stepId": step.id,
|
||||
"processName": step.process_name or "",
|
||||
"outputTypeId": type_id,
|
||||
"outputTypeName": type_name_map.get(type_id, _VALID_QC_DISPATCH_OUTPUT_TYPE_NAME),
|
||||
"outputName": (out.output_name or "").strip(),
|
||||
"outputBarcode": barcode,
|
||||
"cellProductId": cell_product_id or "",
|
||||
}
|
||||
)
|
||||
return items
|
||||
|
||||
|
||||
def list_cell_product_options_for_production_work_order(
|
||||
db: Session,
|
||||
*,
|
||||
production_work_order_id: str,
|
||||
tenant_no: str,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""兼容旧接口名:返回步骤产出物派发选项。"""
|
||||
return list_step_output_dispatch_options_for_production_work_order(
|
||||
db,
|
||||
production_work_order_id=production_work_order_id,
|
||||
tenant_no=tenant_no,
|
||||
)
|
||||
|
||||
|
||||
def list_work_orders(
|
||||
db: Session,
|
||||
*,
|
||||
@@ -1201,7 +1320,7 @@ def list_work_orders(
|
||||
items = [_wo_to_dict(x) for x in rows]
|
||||
items = _enrich_work_order_list_items(db, items)
|
||||
if tenant_no:
|
||||
items = _enrich_work_order_cell_products(db, tenant_no, items)
|
||||
items = _enrich_work_order_qc_targets(db, tenant_no, items)
|
||||
items = _enrich_production_work_order_refs(db, items)
|
||||
items = _enrich_outbound_work_orders(db, tenant_no, items)
|
||||
items = enrich_work_order_fee_summaries(db, items, tenant_no)
|
||||
@@ -1355,7 +1474,7 @@ def _process_qc_info_items_from_wos(
|
||||
return []
|
||||
items = [_qc_info_item(db, wo, tenant_no) for wo in wos]
|
||||
items = _enrich_work_order_list_items(db, items)
|
||||
items = _enrich_work_order_cell_products(db, tenant_no, items)
|
||||
items = _enrich_work_order_qc_targets(db, tenant_no, items)
|
||||
items = _enrich_production_work_order_refs(db, items)
|
||||
return items
|
||||
|
||||
@@ -1535,7 +1654,7 @@ def get_work_order_detail(
|
||||
out = _wo_to_dict(wo)
|
||||
enriched_list = _enrich_work_order_list_items(db, [out])
|
||||
if tenant_no:
|
||||
enriched_list = _enrich_work_order_cell_products(db, tenant_no, enriched_list)
|
||||
enriched_list = _enrich_work_order_qc_targets(db, tenant_no, enriched_list)
|
||||
enriched = enriched_list[0]
|
||||
out.update(
|
||||
{
|
||||
@@ -2253,7 +2372,7 @@ def list_temp_qc_work_orders(
|
||||
)
|
||||
items = [_wo_to_dict(x) for x in rows]
|
||||
if tenant_no:
|
||||
items = _enrich_work_order_cell_products(db, tenant_no, items)
|
||||
items = _enrich_work_order_qc_targets(db, tenant_no, items)
|
||||
return items, int(total)
|
||||
|
||||
|
||||
@@ -2277,7 +2396,7 @@ def get_temp_qc_work_order_detail(
|
||||
if not wo:
|
||||
return None
|
||||
out = _wo_to_dict(wo)
|
||||
enriched_list = _enrich_work_order_cell_products(db, tenant_no, [out])
|
||||
enriched_list = _enrich_work_order_qc_targets(db, tenant_no, [out])
|
||||
out = enriched_list[0]
|
||||
out["labItems"] = _temp_lab_lines(db, wo.id)
|
||||
out["thirdPartyItems"] = _temp_third_lines(db, wo.id)
|
||||
|
||||
@@ -15,6 +15,8 @@ from app.services.storage_facility_code import (
|
||||
build_full_slot_code,
|
||||
cascade_refresh_slot_name_snapshots_for_nodes,
|
||||
cascade_refresh_slot_name_snapshots_for_slots,
|
||||
decode_slot_layout_order,
|
||||
encode_slot_layout_order,
|
||||
load_facility_map,
|
||||
validate_node_code,
|
||||
)
|
||||
@@ -385,10 +387,21 @@ def create_slot(
|
||||
order_num: Optional[int] = None,
|
||||
remark: Optional[str] = None,
|
||||
user_id: Optional[str] = None,
|
||||
at_row_num: Optional[int] = None,
|
||||
) -> BizStorageFacilitySlot:
|
||||
fid = (facility_node_id or "").strip()
|
||||
if not fid:
|
||||
raise ValueError("所属设施节点不能为空")
|
||||
if at_row_num is not None:
|
||||
return insert_slot_at_row_end(
|
||||
db,
|
||||
facility_node_id=fid,
|
||||
row_num=at_row_num,
|
||||
slot_status=slot_status,
|
||||
tenant_no=tenant_no,
|
||||
remark=remark,
|
||||
user_id=user_id,
|
||||
)
|
||||
obj = BizStorageFacilitySlot(
|
||||
id=generate_uuid(),
|
||||
facility_node_id=fid,
|
||||
@@ -410,6 +423,58 @@ def create_slot(
|
||||
return obj
|
||||
|
||||
|
||||
def insert_slot_at_row_end(
|
||||
db: Session,
|
||||
*,
|
||||
facility_node_id: str,
|
||||
row_num: int,
|
||||
slot_status: Optional[str] = None,
|
||||
tenant_no: str = "zkxw",
|
||||
remark: Optional[str] = None,
|
||||
user_id: Optional[str] = None,
|
||||
) -> BizStorageFacilitySlot:
|
||||
fid = (facility_node_id or "").strip()
|
||||
row = int(row_num)
|
||||
if row < 1:
|
||||
raise ValueError("行号参数不合法")
|
||||
|
||||
node = db.query(BizStorageFacility).filter(
|
||||
and_(BizStorageFacility.id == fid, BizStorageFacility.del_flag == 0)
|
||||
).first()
|
||||
if not node:
|
||||
raise ValueError("所属设施节点不存在")
|
||||
if not node.is_leaf:
|
||||
raise ValueError("只能为叶子节点创建格子")
|
||||
|
||||
max_col = 0
|
||||
for slot in _list_facility_slots(db, fid, tenant_no):
|
||||
slot_row, slot_col = _resolve_slot_layout_position(slot)
|
||||
if slot_row == row:
|
||||
max_col = max(max_col, slot_col)
|
||||
_ensure_slot_layout_order(slot, user_id=user_id)
|
||||
|
||||
now = datetime.now()
|
||||
obj = BizStorageFacilitySlot(
|
||||
id=generate_uuid(),
|
||||
facility_node_id=fid,
|
||||
slot_code=None,
|
||||
slot_status=(slot_status or "空").strip() or "空",
|
||||
tenant_no=tenant_no,
|
||||
order_num=encode_slot_layout_order(row, max_col + 1),
|
||||
remark=(remark or "").strip() or None,
|
||||
create_by=user_id,
|
||||
create_dept_id="",
|
||||
create_time=now,
|
||||
update_by=user_id,
|
||||
update_time=now,
|
||||
del_flag=0,
|
||||
)
|
||||
db.add(obj)
|
||||
db.commit()
|
||||
db.refresh(obj)
|
||||
return obj
|
||||
|
||||
|
||||
def update_slot(
|
||||
db: Session,
|
||||
slot_id: str,
|
||||
@@ -446,12 +511,13 @@ def update_slot(
|
||||
return obj
|
||||
|
||||
|
||||
def soft_delete_slot(db: Session, slot_id: str, tenant_no: Optional[str] = None) -> None:
|
||||
def soft_delete_slot(db: Session, slot_id: str, tenant_no: Optional[str] = None, user_id: Optional[str] = None) -> None:
|
||||
obj = get_slot(db, slot_id, tenant_no=tenant_no)
|
||||
if not obj:
|
||||
raise ValueError("存储设施小格不存在")
|
||||
obj.del_flag = 1
|
||||
obj.update_time = datetime.now()
|
||||
obj.update_by = user_id
|
||||
db.add(obj)
|
||||
db.commit()
|
||||
|
||||
@@ -488,6 +554,59 @@ def clear_slots_by_facility_node(
|
||||
return int(updated or 0)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Slot layout & sequential code helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _resolve_slot_layout_position(slot: BizStorageFacilitySlot) -> tuple[int, int]:
|
||||
order = int(slot.order_num or 0)
|
||||
row, col = decode_slot_layout_order(order)
|
||||
if row > 0:
|
||||
return row, col
|
||||
match = re.match(r"^(.*?)(\d+)-(\d+)$", (slot.slot_code or "").strip())
|
||||
if match:
|
||||
return int(match.group(2)), int(match.group(3))
|
||||
return 0, 0
|
||||
|
||||
|
||||
def _ensure_slot_layout_order(
|
||||
slot: BizStorageFacilitySlot,
|
||||
*,
|
||||
user_id: Optional[str] = None,
|
||||
) -> tuple[int, int]:
|
||||
row, col = _resolve_slot_layout_position(slot)
|
||||
if row > 0:
|
||||
expected = encode_slot_layout_order(row, col)
|
||||
if int(slot.order_num or 0) != expected:
|
||||
slot.order_num = expected
|
||||
if user_id:
|
||||
slot.update_by = user_id
|
||||
slot.update_time = datetime.now()
|
||||
return row, col
|
||||
return 0, 0
|
||||
|
||||
|
||||
def _list_facility_slots(
|
||||
db: Session,
|
||||
facility_node_id: str,
|
||||
tenant_no: str,
|
||||
) -> List[BizStorageFacilitySlot]:
|
||||
return (
|
||||
db.query(BizStorageFacilitySlot)
|
||||
.filter(
|
||||
BizStorageFacilitySlot.facility_node_id == facility_node_id,
|
||||
BizStorageFacilitySlot.del_flag == 0,
|
||||
BizStorageFacilitySlot.tenant_no == tenant_no,
|
||||
)
|
||||
.order_by(
|
||||
BizStorageFacilitySlot.order_num.asc(),
|
||||
BizStorageFacilitySlot.create_time.asc(),
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def batch_create_slots(
|
||||
db: Session,
|
||||
*,
|
||||
@@ -513,17 +632,17 @@ def batch_create_slots(
|
||||
raise ValueError("只能为叶子节点创建格子")
|
||||
now = datetime.now()
|
||||
slots: List[BizStorageFacilitySlot] = []
|
||||
seq = 0
|
||||
for r in range(1, rows + 1):
|
||||
for c in range(1, cols + 1):
|
||||
code = f"{r}-{c}"
|
||||
order = (r - 1) * cols + c
|
||||
seq += 1
|
||||
obj = BizStorageFacilitySlot(
|
||||
id=generate_uuid(),
|
||||
facility_node_id=fid,
|
||||
slot_code=code,
|
||||
slot_code=str(seq),
|
||||
slot_status="空",
|
||||
tenant_no=tenant_no,
|
||||
order_num=order,
|
||||
order_num=encode_slot_layout_order(r, c),
|
||||
remark=None,
|
||||
create_by=user_id,
|
||||
create_dept_id="",
|
||||
@@ -570,30 +689,19 @@ def insert_row_and_shift_slots(
|
||||
if not node.is_leaf:
|
||||
raise ValueError("只能为叶子节点新增格子行")
|
||||
|
||||
row_code_pattern = re.compile(r"^(.*?)(\d+)-(\d+)$")
|
||||
slots = db.query(BizStorageFacilitySlot).filter(
|
||||
and_(
|
||||
BizStorageFacilitySlot.facility_node_id == fid,
|
||||
BizStorageFacilitySlot.del_flag == 0,
|
||||
BizStorageFacilitySlot.tenant_no == tenant_no,
|
||||
)
|
||||
).all()
|
||||
slots = _list_facility_slots(db, fid, tenant_no)
|
||||
|
||||
now = datetime.now()
|
||||
shifted_count = 0
|
||||
affected_slot_ids: List[str] = []
|
||||
for slot in slots:
|
||||
match = row_code_pattern.match((slot.slot_code or "").strip())
|
||||
if not match:
|
||||
row_no, col_no = _ensure_slot_layout_order(slot, user_id=user_id)
|
||||
if row_no <= 0:
|
||||
continue
|
||||
_prefix, row_no_raw, col_no_raw = match.groups()
|
||||
row_no = int(row_no_raw)
|
||||
if row_no > after_row_num:
|
||||
slot.slot_code = f"{row_no + 1}-{int(col_no_raw)}"
|
||||
slot.order_num = encode_slot_layout_order(row_no + 1, col_no)
|
||||
slot.update_by = user_id
|
||||
slot.update_time = now
|
||||
shifted_count += 1
|
||||
affected_slot_ids.append(slot.id)
|
||||
|
||||
insert_row_num = after_row_num + 1
|
||||
created_slots: List[BizStorageFacilitySlot] = []
|
||||
@@ -602,10 +710,10 @@ def insert_row_and_shift_slots(
|
||||
BizStorageFacilitySlot(
|
||||
id=generate_uuid(),
|
||||
facility_node_id=fid,
|
||||
slot_code=f"{insert_row_num}-{col}",
|
||||
slot_code=None,
|
||||
slot_status="空",
|
||||
tenant_no=tenant_no,
|
||||
order_num=0,
|
||||
order_num=encode_slot_layout_order(insert_row_num, col),
|
||||
remark=None,
|
||||
create_by=user_id,
|
||||
create_dept_id="",
|
||||
@@ -617,8 +725,5 @@ def insert_row_and_shift_slots(
|
||||
)
|
||||
if created_slots:
|
||||
db.add_all(created_slots)
|
||||
affected_slot_ids.extend(s.id for s in created_slots)
|
||||
if affected_slot_ids:
|
||||
cascade_refresh_slot_name_snapshots_for_slots(db, affected_slot_ids, tenant_no)
|
||||
db.commit()
|
||||
return {"shiftedCount": shifted_count, "createdCount": len(created_slots)}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_production_task_py", "label": "production_task.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L1"}, {"id": "crud_production_task_require_requisition_for_catalog_material", "label": "_require_requisition_for_catalog_material()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L49"}, {"id": "crud_production_task_production_conclusion_label", "label": "_production_conclusion_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L101"}, {"id": "crud_production_task_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L108"}, {"id": "crud_production_task_normalize_date_bound", "label": "_normalize_date_bound()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L112"}, {"id": "crud_production_task_enrich_outbound_task_items", "label": "_enrich_outbound_task_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L119"}, {"id": "crud_production_task_generate_task_no", "label": "_generate_task_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L253"}, {"id": "crud_production_task_task_to_dict", "label": "_task_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L267"}, {"id": "crud_production_task_step_to_dict", "label": "_step_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L294"}, {"id": "crud_production_task_step_reagent_to_dict", "label": "_step_reagent_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L321"}, {"id": "crud_production_task_step_configured_reagent_to_dict", "label": "_step_configured_reagent_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L338"}, {"id": "crud_production_task_step_consumable_to_dict", "label": "_step_consumable_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L354"}, {"id": "crud_production_task_step_output_to_dict", "label": "_step_output_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L371"}, {"id": "crud_production_task_step_data_collection_to_dict", "label": "_step_data_collection_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L383"}, {"id": "crud_production_task_task_input_to_dict", "label": "_task_input_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L395"}, {"id": "crud_production_task_task_output_to_dict", "label": "_task_output_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L417"}, {"id": "crud_production_task_soft_delete_sub", "label": "_soft_delete_sub()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L442"}, {"id": "crud_production_task_resolve_sub_table_order_num", "label": "_resolve_sub_table_order_num()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L455"}, {"id": "crud_production_task_step_sub_tables_to_dict", "label": "_step_sub_tables_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L464"}, {"id": "crud_production_task_clone_step_reagents", "label": "_clone_step_reagents()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L490"}, {"id": "crud_production_task_clone_step_consumables", "label": "_clone_step_consumables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L513"}, {"id": "crud_production_task_clone_step_outputs", "label": "_clone_step_outputs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L536"}, Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_process_py", "label": "process.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L1"}, {"id": "crud_process_reagent_row_to_dict", "label": "_reagent_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L25"}, {"id": "crud_process_consumable_row_to_dict", "label": "_consumable_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L40"}, {"id": "crud_process_output_row_to_dict", "label": "_output_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L54"}, {"id": "crud_process_data_collection_row_to_dict", "label": "_data_collection_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L66"}, {"id": "crud_process_row_to_dict", "label": "_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L77"}, {"id": "crud_process_list_processes", "label": "list_processes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L96"}, {"id": "crud_process_list_all_processes", "label": "list_all_processes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L147"}, {"id": "crud_process_get_process", "label": "get_process()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L156"}, {"id": "crud_process_get_process_detail", "label": "get_process_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L164"}, {"id": "crud_process_process_code_exists", "label": "process_code_exists()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L204"}, {"id": "crud_process_create_sub_reagent", "label": "_create_sub_reagent()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L213"}, {"id": "crud_process_create_sub_consumable", "label": "_create_sub_consumable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L236"}, {"id": "crud_process_create_sub_output", "label": "_create_sub_output()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L259"}, {"id": "crud_process_sub_item_with_order", "label": "_sub_item_with_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L279"}, {"id": "crud_process_create_sub_data_collection", "label": "_create_sub_data_collection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L286"}, {"id": "crud_process_create_process", "label": "create_process()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L305"}, {"id": "crud_process_soft_delete_sub_records", "label": "_soft_delete_sub_records()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L372"}, {"id": "crud_process_update_process", "label": "update_process()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L384"}, {"id": "crud_process_soft_delete_process", "label": "soft_delete_process()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L461"}, {"id": "crud_process_total_pages", "label": "total_pages()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L478"}, {"id": "crud_process_rationale_1", "label": "\u5de5\u827a\u5e93 CRUD\uff08biz_process + biz_process_reagent/consumable/output\uff09", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L1"}, {"id": "crud_process_rationale_280", "label": "\u4fdd\u5b58\u5b50\u8868\u65f6\u6309\u5217\u8868\u4e0b\u6807\u5199\u5165 order_num\uff0c\u907f\u514d\u540c\u6279 create_time \u5bfc\u81f4\u67e5\u8be2\u987a\u5e8f\u6f02\u79fb\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py", "source_location": "L280"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_processLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_process_route_py", "label": "process_route.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L1"}, {"id": "crud_process_route_route_row_to_dict", "label": "_route_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L33"}, {"id": "crud_process_route_step_row_to_dict", "label": "_step_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L49"}, {"id": "crud_process_route_step_reagent_row_to_dict", "label": "_step_reagent_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L67"}, {"id": "crud_process_route_step_consumable_row_to_dict", "label": "_step_consumable_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L82"}, {"id": "crud_process_route_step_output_row_to_dict", "label": "_step_output_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L97"}, {"id": "crud_process_route_step_data_collection_row_to_dict", "label": "_step_data_collection_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L109"}, {"id": "crud_process_route_list_routes", "label": "list_routes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L124"}, {"id": "crud_process_route_get_route", "label": "get_route()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L168"}, {"id": "crud_process_route_get_route_detail", "label": "get_route_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L174"}, {"id": "crud_process_route_create_route", "label": "create_route()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L212"}, {"id": "crud_process_route_update_route", "label": "update_route()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L243"}, {"id": "crud_process_route_set_current_route", "label": "set_current_route()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L259"}, {"id": "crud_process_route_soft_delete_sub_records", "label": "_soft_delete_sub_records()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L285"}, {"id": "crud_process_route_create_step_reagent", "label": "_create_step_reagent()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L295"}, {"id": "crud_process_route_create_step_consumable", "label": "_create_step_consumable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L311"}, {"id": "crud_process_route_create_step_output", "label": "_create_step_output()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L327"}, {"id": "crud_process_route_create_step_data_collection", "label": "_create_step_data_collection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L340"}, {"id": "crud_process_route_add_step", "label": "add_step()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L356"}, {"id": "crud_process_route_update_step", "label": "update_step()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L432"}, {"id": "crud_process_route_reorder_steps", "label": "reorder_steps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L457"}, {"id": "crud_process_route_copy_step", "label": "copy_step()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L471"}, {"id": "crud_process_route_soft_delete_step", "label": "soft_delete_step()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py", "source_location": "L576"}, {"id": "crud_process_route_soft_delete_routLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_production_task_py", "label": "production_task.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L1"}, {"id": "crud_production_task_require_requisition_for_catalog_material", "label": "_require_requisition_for_catalog_material()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L49"}, {"id": "crud_production_task_production_conclusion_label", "label": "_production_conclusion_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L101"}, {"id": "crud_production_task_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L108"}, {"id": "crud_production_task_normalize_date_bound", "label": "_normalize_date_bound()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L112"}, {"id": "crud_production_task_enrich_outbound_task_items", "label": "_enrich_outbound_task_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L119"}, {"id": "crud_production_task_generate_task_no", "label": "_generate_task_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L253"}, {"id": "crud_production_task_task_to_dict", "label": "_task_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L267"}, {"id": "crud_production_task_step_to_dict", "label": "_step_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L294"}, {"id": "crud_production_task_step_reagent_to_dict", "label": "_step_reagent_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L321"}, {"id": "crud_production_task_step_configured_reagent_to_dict", "label": "_step_configured_reagent_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L338"}, {"id": "crud_production_task_step_consumable_to_dict", "label": "_step_consumable_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L354"}, {"id": "crud_production_task_step_output_to_dict", "label": "_step_output_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L371"}, {"id": "crud_production_task_step_data_collection_to_dict", "label": "_step_data_collection_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L383"}, {"id": "crud_production_task_task_input_to_dict", "label": "_task_input_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L395"}, {"id": "crud_production_task_task_output_to_dict", "label": "_task_output_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L417"}, {"id": "crud_production_task_soft_delete_sub", "label": "_soft_delete_sub()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L442"}, {"id": "crud_production_task_resolve_sub_table_order_num", "label": "_resolve_sub_table_order_num()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L455"}, {"id": "crud_production_task_step_sub_tables_to_dict", "label": "_step_sub_tables_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L464"}, {"id": "crud_production_task_clone_step_reagents", "label": "_clone_step_reagents()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L490"}, {"id": "crud_production_task_clone_step_consumables", "label": "_clone_step_consumables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L513"}, {"id": "crud_production_task_clone_step_outputs", "label": "_clone_step_outputs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py", "source_location": "L536"}, Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_services_storage_facility_code_py", "label": "storage_facility_code.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L1"}, {"id": "services_storage_facility_code_encode_slot_layout_order", "label": "encode_slot_layout_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L19"}, {"id": "services_storage_facility_code_decode_slot_layout_order", "label": "decode_slot_layout_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L30"}, {"id": "services_storage_facility_code_validate_node_code", "label": "validate_node_code()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L38"}, {"id": "services_storage_facility_code_assert_sibling_node_code_unique", "label": "assert_sibling_node_code_unique()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L47"}, {"id": "services_storage_facility_code_build_node_code_path", "label": "build_node_code_path()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L71"}, {"id": "services_storage_facility_code_build_full_slot_code", "label": "build_full_slot_code()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L96"}, {"id": "services_storage_facility_code_load_facility_map", "label": "load_facility_map()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L108"}, {"id": "services_storage_facility_code_collect_slot_ids_under_nodes", "label": "collect_slot_ids_under_nodes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L120"}, {"id": "services_storage_facility_code_refresh_outbound_release_cell_slot_names", "label": "refresh_outbound_release_cell_slot_names()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L163"}, {"id": "services_storage_facility_code_cascade_refresh_slot_name_snapshots_for_slots", "label": "cascade_refresh_slot_name_snapshots_for_slots()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L208"}, {"id": "services_storage_facility_code_cascade_refresh_slot_name_snapshots_for_nodes", "label": "cascade_refresh_slot_name_snapshots_for_nodes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L237"}, {"id": "services_storage_facility_code_rationale_1", "label": "\u5e93\u4f4d\u8282\u70b9\u7f16\u53f7\u8def\u5f84\u4e0e\u50a8\u7269\u683c\u5b8c\u6574\u7f16\u53f7\u8ba1\u7b97\u3001\u5feb\u7167\u7ea7\u8054\u5237\u65b0\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L1"}, {"id": "services_storage_facility_code_rationale_20", "label": "\u5c06\u8d27\u67b6\u884c\u5217\u4f4d\u7f6e\u7f16\u7801\u4e3a order_num\uff08row*1000+col\uff09\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L20"}, {"id": "services_storage_facility_code_rationale_31", "label": "\u89e3\u6790 order_num \u4e2d\u7684\u884c\u5217\u4f4d\u7f6e\uff1b\u975e\u5e03\u5c40\u7f16\u7801\u65f6\u8fd4\u56de (0, order)\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L31"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_services_storage_facility_code_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_services_storage_facility_code_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_services_storage_facility_code_py", "target": "sqlalchemy_orm", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/worLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_work_order_py", "label": "qc_work_order.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L1"}, {"id": "crud_qc_work_order_resolve_outbound_biz_type_for_schedule", "label": "resolve_outbound_biz_type_for_schedule()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L89"}, {"id": "crud_qc_work_order_dec", "label": "_dec()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L130"}, {"id": "crud_qc_work_order_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L136"}, {"id": "crud_qc_work_order_normalize_date_bound", "label": "_normalize_date_bound()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L140"}, {"id": "crud_qc_work_order_reception_source_label", "label": "_reception_source_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L147"}, {"id": "crud_qc_work_order_qc_biz_type_label", "label": "_qc_biz_type_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L152"}, {"id": "crud_qc_work_order_work_order_qc_biz_type", "label": "_work_order_qc_biz_type()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L157"}, {"id": "crud_qc_work_order_validate_cell_product_id", "label": "_validate_cell_product_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L164"}, {"id": "crud_qc_work_order_enrich_work_order_cell_products", "label": "_enrich_work_order_cell_products()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L176"}, {"id": "crud_qc_work_order_enrich_work_order_step_outputs", "label": "_enrich_work_order_step_outputs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L205"}, {"id": "crud_qc_work_order_enrich_work_order_qc_targets", "label": "_enrich_work_order_qc_targets()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L244"}, {"id": "crud_qc_work_order_enrich_outbound_work_orders", "label": "_enrich_outbound_work_orders()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L251"}, {"id": "crud_qc_work_order_outbound_qc_work_order_ids_by_keyword", "label": "_outbound_qc_work_order_ids_by_keyword()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L372"}, {"id": "crud_qc_work_order_accept_conclusion_label", "label": "_accept_conclusion_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L419"}, {"id": "crud_qc_work_order_load_sample_type_name_map", "label": "_load_sample_type_name_map()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L424"}, {"id": "crud_qc_work_order_effective_reception_source", "label": "_effective_reception_source()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L436"}, {"id": "crud_qc_work_order_effective_donation_sample_id", "label": "_effective_donation_sample_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L445"}, {"id": "crud_qc_work_order_effective_protocol_sample_id", "label": "_effective_protocol_sample_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L454"}, {"id": "crud_qc_work_order_sample_type_name_for_item", "label": "_sample_type_name_for_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L462"}, {"id": "crud_qc_work_order_sample_type_name_for_reception", "label": "_sample_type_name_for_reception()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L480"}, {"id": "crud_qc_work_order_enrich_work_order_list_items", "label": "_enrich_work_order_list_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/bLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_task_py", "label": "production_task.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L1"}, {"id": "schemas_production_task_productiontaskcreate", "label": "ProductionTaskCreate", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L6"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "schemas_production_task_productiontaskforwardbody", "label": "ProductionTaskForwardBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L17"}, {"id": "schemas_production_task_productiontaskassigneeupdate", "label": "ProductionTaskAssigneeUpdate", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L23"}, {"id": "schemas_production_task_productiontasklistquery", "label": "ProductionTaskListQuery", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L29"}, {"id": "schemas_production_task_productiontaskupdate", "label": "ProductionTaskUpdate", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L38"}, {"id": "schemas_production_task_productiontaskstatusupdate", "label": "ProductionTaskStatusUpdate", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L45"}, {"id": "schemas_production_task_taskstepadd", "label": "TaskStepAdd", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L52"}, {"id": "schemas_production_task_taskstepupdate", "label": "TaskStepUpdate", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L63"}, {"id": "schemas_production_task_taskstepmaterialitem", "label": "TaskStepMaterialItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L73"}, {"id": "schemas_production_task_taskstepoutputitem", "label": "TaskStepOutputItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L88"}, {"id": "schemas_production_task_taskstepdatacollectionitem", "label": "TaskStepDataCollectionItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L95"}, {"id": "schemas_production_task_taskinputitem", "label": "TaskInputItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L102"}, {"id": "schemas_production_task_taskoutputitem", "label": "TaskOutputItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L111"}, {"id": "schemas_production_task_taskstepreorderbody", "label": "TaskStepReorderBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L139"}, {"id": "schemas_production_task_productiontaskstepdispatchitem", "label": "ProductionTaskStepDispatchItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L145"}, {"id": "schemas_production_task_productiontaskstepdispatchbody", "label": "ProductionTaskStepDispatchBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L152"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_task_py", "target": "pydantic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_task_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_task_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_task_py", "targeLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_storage_facility_py", "label": "storage_facility.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L1"}, {"id": "crud_storage_facility_row_to_dict", "label": "_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L30"}, {"id": "crud_storage_facility_list_all_facilities", "label": "list_all_facilities()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L46"}, {"id": "crud_storage_facility_get_facility", "label": "get_facility()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L69"}, {"id": "crud_storage_facility_get_children", "label": "get_children()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L78"}, {"id": "crud_storage_facility_collect_descendant_ids", "label": "collect_descendant_ids()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L94"}, {"id": "crud_storage_facility_create_facility", "label": "create_facility()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L107"}, {"id": "crud_storage_facility_update_facility", "label": "update_facility()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L151"}, {"id": "crud_storage_facility_soft_delete_facility", "label": "soft_delete_facility()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L209"}, {"id": "crud_storage_facility_slot_to_dict", "label": "_slot_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L235"}, {"id": "crud_storage_facility_list_slots", "label": "list_slots()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L258"}, {"id": "crud_storage_facility_is_slot_available_row", "label": "_is_slot_available_row()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L277"}, {"id": "crud_storage_facility_slot_select_display_name", "label": "_slot_select_display_name()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L283"}, {"id": "crud_storage_facility_list_slot_select_options", "label": "list_slot_select_options()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L289"}, {"id": "crud_storage_facility_get_slot", "label": "get_slot()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L366"}, {"id": "crud_storage_facility_slot_to_dict_for_row", "label": "_slot_to_dict_for_row()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L375"}, {"id": "crud_storage_facility_create_slot", "label": "create_slot()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L380"}, {"id": "crud_storage_facility_insert_slot_at_row_end", "label": "insert_slot_at_row_end()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L426"}, {"id": "crud_storage_facility_update_slot", "label": "update_slot()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L478"}, {"id": "crud_storage_facility_soft_delete_slot", "label": "soft_delete_slot()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L514"}, {"id": "crud_storage_facility_clear_slots_by_facility_node", "label": "clear_slots_by_facility_node()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L525"}, {"id": "crud_storage_facility_resolve_slot_layout_position", "label": "_resolve_slot_layout_position()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py", "source_location": "L562"}, {"id": "crud_storage_facility_ensure_slot_layout_order", "label": "_ensure_slot_layout_order()", "file_type": "code", "source_file": "Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_operations_py", "label": "operations.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L1"}, {"id": "api_operations_get_tenant_no", "label": "_get_tenant_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L24"}, {"id": "api_operations_cleanroomcreatebody", "label": "CleanRoomCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L39"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "api_operations_cleanroomupdatebody", "label": "CleanRoomUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L52"}, {"id": "api_operations_list_clean_rooms", "label": "list_clean_rooms()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L66"}, {"id": "api_operations_create_clean_room", "label": "create_clean_room()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L91"}, {"id": "api_operations_update_clean_room", "label": "update_clean_room()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L117"}, {"id": "api_operations_delete_clean_room", "label": "delete_clean_room()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L146"}, {"id": "api_operations_accesslogcreatebody", "label": "AccessLogCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L164"}, {"id": "api_operations_accesslogupdatebody", "label": "AccessLogUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L178"}, {"id": "api_operations_parse_optional_dt", "label": "_parse_optional_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L191"}, {"id": "api_operations_list_access_logs", "label": "list_access_logs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L198"}, {"id": "api_operations_create_access_log", "label": "create_access_log()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L227"}, {"id": "api_operations_update_access_log", "label": "update_access_log()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L254"}, {"id": "api_operations_delete_access_log", "label": "delete_access_log()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L283"}, {"id": "api_operations_uvdisinfectlogcreatebody", "label": "UvDisinfectLogCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L301"}, {"id": "api_operations_uvdisinfectlogupdatebody", "label": "UvDisinfectLogUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L313"}, {"id": "api_operations_list_uv_disinfect_logs", "label": "list_uv_disinfect_logs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L325"}, {"id": "api_operations_create_uv_disinfect_log", "label": "create_uv_disinfect_log()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L356"}, {"id": "api_operations_update_uv_disinfect_log", "label": "update_uv_disinfect_log()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L381"}, {"id": "api_operations_delete_uv_disinfect_log", "label": "delete_uv_disinfect_log()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L409"}, {"id": "api_operations_storagefacilitycreatebody", "label": "StorageFacilityCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L427"}, {"id": "api_operations_storagefacilityupdatebody", "label": "StorageFacilityUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py", "source_location": "L439"}, {"id": "api_operations_list_storage_facilities", "labelLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_production_py", "label": "production.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L1"}, {"id": "api_production_legacy_material_write_gone", "label": "_legacy_material_write_gone()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L75"}, {"id": "api_production_get_tenant_no", "label": "_get_tenant_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L79"}, {"id": "api_production_get_current_user_id", "label": "_get_current_user_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L87"}, {"id": "api_production_assert_production_task_write_access", "label": "_assert_production_task_write_access()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L91"}, {"id": "api_production_consumablecreatebody", "label": "ConsumableCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L115"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "api_production_consumableupdatebody", "label": "ConsumableUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L129"}, {"id": "api_production_list_consumables", "label": "list_consumables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L144"}, {"id": "api_production_list_all_consumables", "label": "list_all_consumables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L158"}, {"id": "api_production_create_consumable", "label": "create_consumable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L168"}, {"id": "api_production_update_consumable", "label": "update_consumable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L177"}, {"id": "api_production_delete_consumable", "label": "delete_consumable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L187"}, {"id": "api_production_stockinbody", "label": "StockInBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L195"}, {"id": "api_production_stockoutbody", "label": "StockOutBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L201"}, {"id": "api_production_batchstockinitem", "label": "BatchStockInItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L209"}, {"id": "api_production_batchstockinbody", "label": "BatchStockInBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L216"}, {"id": "api_production_batchstockoutitem", "label": "BatchStockOutItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L222"}, {"id": "api_production_batchstockoutbody", "label": "BatchStockOutBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L228"}, {"id": "api_production_consumable_stock_in", "label": "consumable_stock_in()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L237"}, {"id": "api_production_consumable_stock_out", "label": "consumable_stock_out()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L259"}, {"id": "api_production_consumable_batch_stock_in", "label": "consumable_batch_stock_in()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L283"}, {"id": "api_production_consumable_batch_stock_out", "label": "consumable_batch_stock_out()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L301"}, {"id": "api_production_list_consumable_stock_logs", "label": "list_consumable_stock_logs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L320"}, {"id": "api_production_list_all_consumable_stock_logs", "labLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_models_models_py", "label": "models.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L1"}, {"id": "models_models_userrole", "label": "UserRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L10"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_models_sysuser", "label": "SysUser", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L22"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_models_sysrole", "label": "SysRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L48"}, {"id": "models_models_sysuserrole", "label": "SysUserRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L68"}, {"id": "models_models_sysrolemenu", "label": "SysRoleMenu", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L87"}, {"id": "models_models_sysroledatascopedetail", "label": "SysRoleDataScopeDetail", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L106"}, {"id": "models_models_sysmenu", "label": "SysMenu", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L126"}, {"id": "models_models_sysdept", "label": "SysDept", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L152"}, {"id": "models_models_systenant", "label": "SysTenant", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L175"}, {"id": "models_models_syssite", "label": "SysSite", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L195"}, {"id": "models_models_syspost", "label": "SysPost", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L221"}, {"id": "models_models_sysuserpost", "label": "SysUserPost", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L241"}, {"id": "models_models_bizitemunit", "label": "BizItemUnit", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L260"}, {"id": "models_models_bizexpresscompany", "label": "BizExpressCompany", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L279"}, {"id": "models_models_bizcustomer", "label": "BizCustomer", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L299"}, {"id": "models_models_bizcellsampletype", "label": "BizCellSampleType", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L322"}, {"id": "models_models_bizcollectionregion", "label": "BizCollectionRegion", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L345"}, {"id": "models_models_bizcollectionhospital", "label": "BizCollectionHospital", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L363"}, {"id": "models_models_bizcollectionprotocolno", "label": "BizCollectionProtocolNo", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L382"}, {"id": "models_models_bizbiznosequence", "label": "BizBizNoSequence", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L404"}, {"id": "models_models_bizsamplecode", "label": "BizSampleCode", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L424"}, {"id": "models_models_sysdicttype", "label": "SysDictType", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L452"}, {"id": "models_models_sysethnic", "label": "SysEthnic", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L471"}, {"id": "models_models_sysdictdata", "label": "SysDictData", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location"Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_production_task_step_assignee_py", "label": "production_task_step_assignee.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L1"}, {"id": "crud_production_task_step_assignee_active_users_in_tenant", "label": "_active_users_in_tenant()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L14"}, {"id": "crud_production_task_step_assignee_validate_assignee_user_ids", "label": "validate_assignee_user_ids()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L33"}, {"id": "crud_production_task_step_assignee_sync_assignees_for_step", "label": "sync_assignees_for_step()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L54"}, {"id": "crud_production_task_step_assignee_enrich_step_assignees", "label": "enrich_step_assignees()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L108"}, {"id": "crud_production_task_step_assignee_enrich_step_completed_by_names", "label": "enrich_step_completed_by_names()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L150"}, {"id": "crud_production_task_step_assignee_user_is_step_assignee", "label": "user_is_step_assignee()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L169"}, {"id": "crud_production_task_step_assignee_user_is_any_step_assignee_of_task", "label": "user_is_any_step_assignee_of_task()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L188"}, {"id": "crud_production_task_step_assignee_rationale_63", "label": "\u5168\u91cf\u66ff\u6362\u6b65\u9aa4\u8d1f\u8d23\u4eba\uff08\u8f6f\u5220\u65e7\u8bb0\u5f55 + \u63d2\u5165\u65b0\u8bb0\u5f55\uff09\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L63"}, {"id": "crud_production_task_step_assignee_rationale_111", "label": "\u6279\u91cf\u586b\u5145 assigneeUserIds / assigneeNames / assignees\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L111"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_production_task_step_assignee_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_production_task_step_assignee_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_production_task_step_assignee_py", "target": "sqlalchemy_orm", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L7", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_production_task_step_assignee_py", "target": "app_core_db_collation", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_production_task_step_assignee_py", "target": "app_core_utils", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L10", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_production_task_step_assignee_py", "target": "app_models_models", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py", "source_location": "L11", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_production_task_step_assignee_py", "target": "crud_production_task_step_assignee_active_users_in_tenant", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/cLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_production_py", "label": "production.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L1"}, {"id": "api_production_legacy_material_write_gone", "label": "_legacy_material_write_gone()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L76"}, {"id": "api_production_get_tenant_no", "label": "_get_tenant_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L80"}, {"id": "api_production_get_current_user_id", "label": "_get_current_user_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L88"}, {"id": "api_production_assert_production_task_write_access", "label": "_assert_production_task_write_access()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L92"}, {"id": "api_production_assert_production_task_step_write_access", "label": "_assert_production_task_step_write_access()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L113"}, {"id": "api_production_consumablecreatebody", "label": "ConsumableCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L140"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "api_production_consumableupdatebody", "label": "ConsumableUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L154"}, {"id": "api_production_list_consumables", "label": "list_consumables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L169"}, {"id": "api_production_list_all_consumables", "label": "list_all_consumables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L183"}, {"id": "api_production_create_consumable", "label": "create_consumable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L193"}, {"id": "api_production_update_consumable", "label": "update_consumable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L202"}, {"id": "api_production_delete_consumable", "label": "delete_consumable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L212"}, {"id": "api_production_stockinbody", "label": "StockInBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L220"}, {"id": "api_production_stockoutbody", "label": "StockOutBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L226"}, {"id": "api_production_batchstockinitem", "label": "BatchStockInItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L234"}, {"id": "api_production_batchstockinbody", "label": "BatchStockInBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L241"}, {"id": "api_production_batchstockoutitem", "label": "BatchStockOutItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L247"}, {"id": "api_production_batchstockoutbody", "label": "BatchStockOutBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L253"}, {"id": "api_production_consumable_stock_in", "label": "consumable_stock_in()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L262"}, {"id": "api_production_consumable_stock_out", "label": "consumable_stock_out()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L284"}, {"id": "api_production_consumable_batch_stock_in", "label": "consumable_batch_stock_in()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L308"}, {"id": "api_production_consumable_batch_stock_out", "label": "consumable_batch_stock_out()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L326"}, {"id": "api_production_list_conLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_production_py", "label": "production.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L1"}, {"id": "api_production_legacy_material_write_gone", "label": "_legacy_material_write_gone()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L76"}, {"id": "api_production_get_tenant_no", "label": "_get_tenant_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L80"}, {"id": "api_production_get_current_user_id", "label": "_get_current_user_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L88"}, {"id": "api_production_assert_production_task_write_access", "label": "_assert_production_task_write_access()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L92"}, {"id": "api_production_assert_production_task_step_write_access", "label": "_assert_production_task_step_write_access()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L113"}, {"id": "api_production_consumablecreatebody", "label": "ConsumableCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L140"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "api_production_consumableupdatebody", "label": "ConsumableUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L154"}, {"id": "api_production_list_consumables", "label": "list_consumables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L169"}, {"id": "api_production_list_all_consumables", "label": "list_all_consumables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L183"}, {"id": "api_production_create_consumable", "label": "create_consumable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L193"}, {"id": "api_production_update_consumable", "label": "update_consumable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L202"}, {"id": "api_production_delete_consumable", "label": "delete_consumable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L212"}, {"id": "api_production_stockinbody", "label": "StockInBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L220"}, {"id": "api_production_stockoutbody", "label": "StockOutBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L226"}, {"id": "api_production_batchstockinitem", "label": "BatchStockInItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L234"}, {"id": "api_production_batchstockinbody", "label": "BatchStockInBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L241"}, {"id": "api_production_batchstockoutitem", "label": "BatchStockOutItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L247"}, {"id": "api_production_batchstockoutbody", "label": "BatchStockOutBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L253"}, {"id": "api_production_consumable_stock_in", "label": "consumable_stock_in()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L262"}, {"id": "api_production_consumable_stock_out", "label": "consumable_stock_out()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L284"}, {"id": "api_production_consumable_batch_stock_in", "label": "consumable_batch_stock_in()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L308"}, {"id": "api_production_consumable_batch_stock_out", "label": "consumable_batch_stock_out()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L326"}, {"id": "api_production_list_conLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_models_models_py", "label": "models.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L1"}, {"id": "models_models_userrole", "label": "UserRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L10"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_models_sysuser", "label": "SysUser", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L22"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_models_sysrole", "label": "SysRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L48"}, {"id": "models_models_sysuserrole", "label": "SysUserRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L68"}, {"id": "models_models_sysrolemenu", "label": "SysRoleMenu", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L87"}, {"id": "models_models_sysroledatascopedetail", "label": "SysRoleDataScopeDetail", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L106"}, {"id": "models_models_sysmenu", "label": "SysMenu", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L126"}, {"id": "models_models_sysdept", "label": "SysDept", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L152"}, {"id": "models_models_systenant", "label": "SysTenant", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L175"}, {"id": "models_models_syssite", "label": "SysSite", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L195"}, {"id": "models_models_syspost", "label": "SysPost", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L221"}, {"id": "models_models_sysuserpost", "label": "SysUserPost", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L241"}, {"id": "models_models_bizitemunit", "label": "BizItemUnit", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L260"}, {"id": "models_models_bizexpresscompany", "label": "BizExpressCompany", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L279"}, {"id": "models_models_bizcustomer", "label": "BizCustomer", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L299"}, {"id": "models_models_bizcellsampletype", "label": "BizCellSampleType", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L322"}, {"id": "models_models_bizcollectionregion", "label": "BizCollectionRegion", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L345"}, {"id": "models_models_bizcollectionhospital", "label": "BizCollectionHospital", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L363"}, {"id": "models_models_bizcollectionprotocolno", "label": "BizCollectionProtocolNo", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L382"}, {"id": "models_models_bizbiznosequence", "label": "BizBizNoSequence", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L404"}, {"id": "models_models_bizsamplecode", "label": "BizSampleCode", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L424"}, {"id": "models_models_sysdicttype", "label": "SysDictType", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L452"}, {"id": "models_models_sysethnic", "label": "SysEthnic", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L471"}, {"id": "models_models_sysdictdata", "label": "SysDictData", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location"Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_work_order_py", "label": "qc_work_order.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L1"}, {"id": "schemas_qc_work_order_outboundqcdetailapplication", "label": "OutboundQcDetailApplication", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L5"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "schemas_qc_work_order_outboundqcdetailpatient", "label": "OutboundQcDetailPatient", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L14"}, {"id": "schemas_qc_work_order_outboundqcdetailinfusionplan", "label": "OutboundQcDetailInfusionPlan", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L28"}, {"id": "schemas_qc_work_order_outboundqcdetailinfusionschedule", "label": "OutboundQcDetailInfusionSchedule", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L39"}, {"id": "schemas_qc_work_order_outboundqcdetailproduct", "label": "OutboundQcDetailProduct", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L51"}, {"id": "schemas_qc_work_order_outboundqcdetailresponse", "label": "OutboundQcDetailResponse", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L64"}, {"id": "schemas_qc_work_order_qcworkordercreatebody", "label": "QcWorkOrderCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L76"}, {"id": "schemas_qc_work_order_productionqcworkordercreatebody", "label": "ProductionQcWorkOrderCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L89"}, {"id": "schemas_qc_work_order_qcworkorderupdatebody", "label": "QcWorkOrderUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L99"}, {"id": "schemas_qc_work_order_rationale_100", "label": "\u7f16\u8f91\u8d28\u68c0\u5de5\u5355\uff08\u5165\u5e93/\u51fa\u5e93\u53ef\u6539\u5907\u6ce8\u4e0e\u72b6\u6001\uff1b\u4e34\u65f6\u53ef\u542b\u8d28\u68c0\u5bf9\u8c61\uff09", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L100"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_work_order_py", "target": "pydantic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_work_order_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_work_order_py", "target": "schemas_qc_work_order_outboundqcdetailapplication", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L5", "weight": 1.0}, {"source": "schemas_qc_work_order_outboundqcdetailapplication", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_work_order_py", "target": "schemas_qc_work_order_outboundqcdetailpatient", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L14", "weight": 1.0}, {"source": "schemas_qc_work_order_outboundqcdetailpatient", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L14", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_work_order_py", "target": "schemas_qc_work_order_outboundqcdetailinfusionplan", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L28", "weight": 1.0}, {"source": "schemas_qc_work_order_outboundqcdetailinfusionplan", "target": "bLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_py", "label": "qc_task.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L1"}, {"id": "crud_qc_task_dec", "label": "_dec()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L36"}, {"id": "crud_qc_task_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L42"}, {"id": "crud_qc_task_gen_task_no", "label": "_gen_task_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L46"}, {"id": "crud_qc_task_conclusion_label", "label": "_conclusion_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L59"}, {"id": "crud_qc_task_task_to_dict", "label": "_task_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L64"}, {"id": "crud_qc_task_task_work_order_context", "label": "_task_work_order_context()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L97"}, {"id": "crud_qc_task_enrich_tasks_reception_fields", "label": "_enrich_tasks_reception_fields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L134"}, {"id": "crud_qc_task_task_row_to_dict", "label": "_task_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L242"}, {"id": "crud_qc_task_create_task_for_line", "label": "create_task_for_line()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L253"}, {"id": "crud_qc_task_list_tasks", "label": "list_tasks()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L298"}, {"id": "crud_qc_task_list_mine_tasks", "label": "list_mine_tasks()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L379"}, {"id": "crud_qc_task_assert_task_assignee", "label": "assert_task_assignee()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L470"}, {"id": "crud_qc_task_list_tasks_by_work_order", "label": "list_tasks_by_work_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L477"}, {"id": "crud_qc_task_get_task", "label": "get_task()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L495"}, {"id": "crud_qc_task_get_task_detail", "label": "get_task_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L504"}, {"id": "crud_qc_task_start_task", "label": "start_task()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L537"}, {"id": "crud_qc_task_set_task_remark", "label": "_set_task_remark()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L554"}, {"id": "crud_qc_task_complete_task", "label": "complete_task()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L558"}, {"id": "crud_qc_task_apply_task_result", "label": "apply_task_result()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L602"}, {"id": "crud_qc_task_update_task_attachments", "label": "update_task_attachments()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L654"}, {"id": "crud_qc_task_create_qc_task_manual", "label": "create_qc_task_manual()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L684"}, {"id": "crud_qc_task_delete_qc_task", "label": "delete_qc_task()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L733"}, {"id": "crud_qc_task_rationale_613", "label": "\u4fdd\u5b58\u68c0\u6d4b\u7ed3\u679c\u4e0e\u7ed3\u8bba\uff1b\u4efb\u52a1\u672a\u5b8c\u6210\u65f6\u987a\u5e26\u6807\u8bb0\u4e3a\u5df2\u5b8c\u6210\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L613"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_taLine truncated
|
||||
@@ -1355,6 +1355,7 @@ class BizQcWorkOrder(Base):
|
||||
cell_product_id = Column(String(64), nullable=True, comment="质检对象-细胞产品ID")
|
||||
production_work_order_id = Column(String(64), nullable=True, comment="关联生产工单ID(生产过程触发时)")
|
||||
production_task_id = Column(String(64), nullable=True, comment="关联生产任务ID(可选)")
|
||||
production_step_output_id = Column(String(64), nullable=True, comment="关联生产任务步骤产出物ID(生产过程触发时)")
|
||||
work_order_status = Column(String(16), nullable=False, default="dpz", comment="工单状态")
|
||||
has_lab = Column(String(1), nullable=False, default="0", comment="含实验室自检")
|
||||
has_third_party = Column(String(1), nullable=False, default="0", comment="含第三方检测")
|
||||
@@ -2739,8 +2740,10 @@ class BizProductionTaskStep(Base):
|
||||
actual_duration = Column(String(100), nullable=True, comment="实际耗时")
|
||||
sop_ids = Column(String(1000), nullable=True, comment="关联SOP文档id(逗号分隔)")
|
||||
step_status = Column(String(16), nullable=True, default="dzx", comment="步骤状态 dzx待执行 jxz执行中 ywc已完成")
|
||||
planned_start_time = Column(DateTime, nullable=True, comment="计划开始时间")
|
||||
started_time = Column(DateTime, nullable=True, comment="开始时间")
|
||||
completed_time = Column(DateTime, nullable=True, comment="完成时间")
|
||||
completed_by = Column(String(64), nullable=True, comment="完成步骤的用户ID")
|
||||
tenant_no = Column(String(64), nullable=False, default="zkxw", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号")
|
||||
remark = Column(String(512), nullable=True, comment="备注")
|
||||
@@ -2752,6 +2755,25 @@ class BizProductionTaskStep(Base):
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
|
||||
|
||||
class BizProductionTaskStepAssignee(Base):
|
||||
"""生产任务步骤负责人 biz_production_task_step_assignee"""
|
||||
|
||||
__tablename__ = "biz_production_task_step_assignee"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键")
|
||||
step_id = Column(String(64), nullable=False, comment="生产任务步骤ID")
|
||||
user_id = Column(String(64), nullable=False, comment="负责人用户ID")
|
||||
tenant_no = Column(String(64), nullable=False, default="zkxw", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, default=0, comment="展示顺序")
|
||||
remark = Column(String(512), nullable=True, comment="备注")
|
||||
create_by = Column(String(64), nullable=True, comment="创建人id")
|
||||
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
|
||||
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
|
||||
update_by = Column(String(64), nullable=True, comment="更新人id")
|
||||
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
|
||||
|
||||
class BizProductionTaskStepReagent(Base):
|
||||
"""生产任务步骤试剂 biz_production_task_step_reagent"""
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from datetime import datetime
|
||||
class ProductionTaskCreate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
work_order_id: str
|
||||
assignee_user_id: str = Field(..., alias="assigneeUserId")
|
||||
assignee_user_id: Optional[str] = Field(None, alias="assigneeUserId")
|
||||
task_type: Optional[str] = 'cell_storage'
|
||||
task_name: Optional[str] = None
|
||||
route_id: Optional[str] = None
|
||||
@@ -140,3 +140,15 @@ class TaskStepReorderBody(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
task_id: str = Field(..., alias="taskId")
|
||||
step_ids: List[str] = Field(..., alias="stepIds")
|
||||
|
||||
|
||||
class ProductionTaskStepDispatchItem(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
step_id: str = Field(..., alias="stepId")
|
||||
assignee_user_ids: List[str] = Field(..., alias="assigneeUserIds", min_length=1)
|
||||
planned_start_time: Optional[datetime] = Field(None, alias="plannedStartTime")
|
||||
|
||||
|
||||
class ProductionTaskStepDispatchBody(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
steps: List[ProductionTaskStepDispatchItem] = Field(..., min_length=1)
|
||||
@@ -90,8 +90,9 @@ class ProductionQcWorkOrderCreateBody(BaseModel):
|
||||
"""生产过程派发质检工单"""
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
cell_product_id: str = Field(..., alias="cellProductId", description="细胞产品ID")
|
||||
production_task_id: Optional[str] = Field(None, alias="productionTaskId", description="关联生产任务ID(可选)")
|
||||
production_step_output_id: str = Field(
|
||||
..., alias="productionStepOutputId", description="步骤产出物ID"
|
||||
)
|
||||
remark: Optional[str] = Field(None, description="备注")
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""库位节点编号路径与储物格完整编号计算、快照级联刷新。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
@@ -14,15 +13,32 @@ from app.models.models import (
|
||||
BizStorageFacilitySlot,
|
||||
)
|
||||
|
||||
_NODE_CODE_PATTERN = re.compile(r"^[A-Za-z0-9]+$")
|
||||
SLOT_LAYOUT_ROW_STRIDE = 1000
|
||||
|
||||
|
||||
def encode_slot_layout_order(row: int, col: int) -> int:
|
||||
"""将货架行列位置编码为 order_num(row*1000+col)。"""
|
||||
row_i = int(row)
|
||||
col_i = int(col)
|
||||
if row_i < 1 or col_i < 1:
|
||||
raise ValueError("行列序号必须从 1 开始")
|
||||
if col_i >= SLOT_LAYOUT_ROW_STRIDE:
|
||||
raise ValueError(f"列数不能超过 {SLOT_LAYOUT_ROW_STRIDE - 1}")
|
||||
return row_i * SLOT_LAYOUT_ROW_STRIDE + col_i
|
||||
|
||||
|
||||
def decode_slot_layout_order(order_num: int) -> tuple[int, int]:
|
||||
"""解析 order_num 中的行列位置;非布局编码时返回 (0, order)。"""
|
||||
order = int(order_num or 0)
|
||||
if order >= SLOT_LAYOUT_ROW_STRIDE:
|
||||
return order // SLOT_LAYOUT_ROW_STRIDE, order % SLOT_LAYOUT_ROW_STRIDE
|
||||
return 0, order
|
||||
|
||||
|
||||
def validate_node_code(node_code: str) -> str:
|
||||
code = (node_code or "").strip()
|
||||
if not code:
|
||||
raise ValueError("节点编号不能为空")
|
||||
if not _NODE_CODE_PATTERN.match(code):
|
||||
raise ValueError("节点编号只能包含字母和数字,不能包含连字符")
|
||||
return ""
|
||||
if len(code) > 32:
|
||||
raise ValueError("节点编号长度不能超过 32 个字符")
|
||||
return code
|
||||
@@ -38,6 +54,8 @@ def assert_sibling_node_code_unique(
|
||||
) -> None:
|
||||
pid = (parent_id or "0").strip() or "0"
|
||||
code = validate_node_code(node_code)
|
||||
if not code:
|
||||
return
|
||||
q = db.query(BizStorageFacility).filter(
|
||||
BizStorageFacility.parent_id == pid,
|
||||
BizStorageFacility.node_code == code,
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+13623
-10634
File diff suppressed because it is too large.
Load diff
@@ -1,11 +1,11 @@
|
||||
# Graph Report - app (2026-06-24)
|
||||
# Graph Report - app (2026-06-25)
|
||||
|
||||
## Corpus Check
|
||||
- Large corpus: 210 files · ~249,301 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
|
||||
- Large corpus: 211 files · ~251,177 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
|
||||
|
||||
## Summary
|
||||
- 4251 nodes · 22373 edges · 53 communities detected
|
||||
- Extraction: 33% EXTRACTED · 67% INFERRED · 0% AMBIGUOUS · INFERRED: 15072 edges (avg confidence: 0.6)
|
||||
- 4285 nodes · 22669 edges · 43 communities detected
|
||||
- Extraction: 32% EXTRACTED · 68% INFERRED · 0% AMBIGUOUS · INFERRED: 15304 edges (avg confidence: 0.59)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
@@ -46,108 +46,98 @@
|
||||
- [[_COMMUNITY_Community 34|Community 34]]
|
||||
- [[_COMMUNITY_Community 35|Community 35]]
|
||||
- [[_COMMUNITY_Community 36|Community 36]]
|
||||
- [[_COMMUNITY_Community 37|Community 37]]
|
||||
- [[_COMMUNITY_Community 38|Community 38]]
|
||||
- [[_COMMUNITY_Community 39|Community 39]]
|
||||
- [[_COMMUNITY_Community 40|Community 40]]
|
||||
- [[_COMMUNITY_Community 41|Community 41]]
|
||||
- [[_COMMUNITY_Community 42|Community 42]]
|
||||
- [[_COMMUNITY_Community 43|Community 43]]
|
||||
- [[_COMMUNITY_Community 44|Community 44]]
|
||||
- [[_COMMUNITY_Community 45|Community 45]]
|
||||
- [[_COMMUNITY_Community 46|Community 46]]
|
||||
- [[_COMMUNITY_Community 49|Community 49]]
|
||||
- [[_COMMUNITY_Community 50|Community 50]]
|
||||
- [[_COMMUNITY_Community 51|Community 51]]
|
||||
- [[_COMMUNITY_Community 52|Community 52]]
|
||||
- [[_COMMUNITY_Community 53|Community 53]]
|
||||
- [[_COMMUNITY_Community 54|Community 54]]
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `success_response()` - 652 edges
|
||||
2. `error_response()` - 538 edges
|
||||
3. `SysUser` - 458 edges
|
||||
4. `BizProductionMaterialUsage` - 298 edges
|
||||
5. `BizProductionMaterial` - 297 edges
|
||||
6. `BizQcTaskResult` - 296 edges
|
||||
7. `BizQcMaterialUsage` - 295 edges
|
||||
8. `BizQcMaterial` - 286 edges
|
||||
9. `BizProductionMaterialStockBatch` - 285 edges
|
||||
10. `BizMaterialUsage` - 282 edges
|
||||
1. `success_response()` - 653 edges
|
||||
2. `error_response()` - 539 edges
|
||||
3. `SysUser` - 462 edges
|
||||
4. `BizProductionMaterial` - 300 edges
|
||||
5. `BizProductionMaterialUsage` - 300 edges
|
||||
6. `BizQcTaskResult` - 299 edges
|
||||
7. `BizQcMaterialUsage` - 297 edges
|
||||
8. `BizQcMaterial` - 288 edges
|
||||
9. `BizProductionMaterialStockBatch` - 287 edges
|
||||
10. `BizMaterialUsage` - 284 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `统一记录 API 请求/响应出入参的中间件` --uses--> `SysApiRequestLog` [INFERRED]
|
||||
core/api_request_log_middleware.py → models/models.py
|
||||
- `get_menu_list()` --calls--> `success_response()` [INFERRED]
|
||||
api/menu.py → core/response.py
|
||||
- `list_my_qc_material_usages()` --calls--> `strip_row_fields()` [INFERRED]
|
||||
api/qc.py → core/menu_guard.py
|
||||
- `中试服务申请单管理 API(申请单、患者信息、输注方案、输注计划、出库联动)` --uses--> `SysUser` [INFERRED]
|
||||
api/pilot_application.py → models/models.py
|
||||
- `中试服务交付管理 API(交付信息、交付物料、交付方式)` --uses--> `SysUser` [INFERRED]
|
||||
api/pilot_delivery.py → models/models.py
|
||||
- `保留匹配节点及其全部上级,供关键词检索后仍能正确组树。` --uses--> `SysDept` [INFERRED]
|
||||
crud/dept.py → models/models.py
|
||||
- `中试服务体检管理 API(体检信息、预约项目、实际项目)` --uses--> `SysUser` [INFERRED]
|
||||
api/pilot_checkup.py → models/models.py
|
||||
|
||||
## Communities
|
||||
|
||||
### Community 0 - "Community 0"
|
||||
Cohesion: 0.01
|
||||
Nodes (804): attachment_download_url(), create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post() (+796 more)
|
||||
Nodes (862): attachment_download_url(), create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post() (+854 more)
|
||||
|
||||
### Community 1 - "Community 1"
|
||||
Cohesion: 0.01
|
||||
Nodes (609): AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody, DictTypeUpdateBody, ExpressCompanyCreateBody (+601 more)
|
||||
Nodes (605): AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody, DictTypeUpdateBody, ExpressCompanyCreateBody (+597 more)
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.06
|
||||
Nodes (519): 细胞存储 — 采集协议单 / 审核 / 财务确认 / 分期预警 API, If mother info exists but no customerId, create a customer record and link it., 保险公司及险种价格管理 API(保险公司 + 开票信息 + 险种价格), 审批意见:前端传 commentText,兼容 comment。, TaskActionBody, Base, 细胞产品 CRUD(biz_cell_product), 解析任务样本投入物,返回祖先链单段(样本终止节点)。 (+511 more)
|
||||
Cohesion: 0.01
|
||||
Nodes (432): generate_uuid(), ApiRequestLogCRUD, delete(), get_multi_with_filters(), create_cell_sample_type(), get_cell_sample_type(), list_cell_sample_types(), 细胞样本类型 CRUD(biz_cell_sample_type) (+424 more)
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.01
|
||||
Nodes (312): _normalize_date_bound(), _persist_protocol_sub_resources(), list_ethnics_for_select(), apply_data_scope(), _get_child_dept_ids(), get_user_dept_id(), _resolve_user_role_scopes(), format_date() (+304 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (367): 环境检测 — 检测项维护 + 登记管理 API, 保险公司及险种价格管理 API(保险公司 + 开票信息 + 险种价格), AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, ExhibitionAppointmentCreateBody, ExhibitionAppointmentUpdateBody (+359 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.01
|
||||
Nodes (288): generate_uuid(), create_cell_sample_type(), get_cell_sample_type(), list_cell_sample_types(), 细胞样本类型 CRUD(biz_cell_sample_type), _row_to_dict(), soft_delete_cell_sample_type(), type_code_exists() (+280 more)
|
||||
Nodes (300): _normalize_date_bound(), _persist_protocol_sub_resources(), list_ethnics_for_select(), apply_data_scope(), _get_child_dept_ids(), get_user_dept_id(), _resolve_user_role_scopes(), format_date() (+292 more)
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.02
|
||||
Nodes (214): batch_discard(), batch_options(), _batch_row_to_dict(), batch_stock_in(), batch_stock_out(), _create_batch_and_usage(), delete_batch(), _discard_batch() (+206 more)
|
||||
Cohesion: 0.07
|
||||
Nodes (231): CellSampleTypeCreateBody, CellSampleTypeUpdateBody, CollectionRegionCreateBody, CollectionRegionUpdateBody, CustomerCreateBody, CustomerUpdateBody, HospitalCreateBody, HospitalUpdateBody (+223 more)
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.02
|
||||
Nodes (116): get_designer_data(), _error_json(), lifespan(), 数据库异常:返回 JSON 并保留 CORS 头,避免浏览器只报跨域错误, 未捕获异常:统一 JSON 500,确保跨域场景下仍有 Access-Control-Allow-Origin, sqlalchemy_exception_handler(), unhandled_exception_handler(), BaseHTTPMiddleware (+108 more)
|
||||
Nodes (191): eq_unicode(), like_unicode(), MySQL 字符串比较/模糊匹配时统一排序规则,避免 Illegal mix of collations。, 跨表字符串等值比较(JOIN / WHERE)时统一为 utf8mb4_unicode_ci。, 将列显式设为 utf8mb4_unicode_ci。, unicode_ci(), batch_review(), _dec() (+183 more)
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.02
|
||||
Nodes (165): api_save_application(), get_protocol_nos_used_in_protocols(), create_dict_type(), dict_type_code_exists(), get_dict_type(), list_dict_types(), 字典类型 CRUD(sys_dict_type), _row_to_dict() (+157 more)
|
||||
Nodes (167): _code_exists(), create_material(), _dec(), _fmt_dt(), get_material(), get_material_entity(), get_my_usages(), _is_enabled_status() (+159 more)
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.03
|
||||
Nodes (164): eq_unicode(), like_unicode(), MySQL 字符串比较/模糊匹配时统一排序规则,避免 Illegal mix of collations。, 跨表字符串等值比较(JOIN / WHERE)时统一为 utf8mb4_unicode_ci。, 将列显式设为 utf8mb4_unicode_ci。, unicode_ci(), batch_review(), _dec() (+156 more)
|
||||
Cohesion: 0.02
|
||||
Nodes (110): get_designer_data(), _error_json(), 数据库异常:返回 JSON 并保留 CORS 头,避免浏览器只报跨域错误, 未捕获异常:统一 JSON 500,确保跨域场景下仍有 Access-Control-Allow-Origin, sqlalchemy_exception_handler(), unhandled_exception_handler(), BaseHTTPMiddleware, parse_admin_request_json() (+102 more)
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.05
|
||||
Nodes (93): AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, ExhibitionAppointmentCreateBody, ExhibitionAppointmentUpdateBody, OccupancyCreateBody, 运营支撑 API(洁净室、进出记录、仓储设施、储位、展厅预约) (+85 more)
|
||||
Cohesion: 0.02
|
||||
Nodes (135): get_role_menus(), list_storage_slots(), get_protocol_nos_used_in_protocols(), create_dict_type(), dict_type_code_exists(), get_dict_type(), list_dict_types(), 字典类型 CRUD(sys_dict_type) (+127 more)
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.05
|
||||
Nodes (75): batch_delete_research_donations(), change_donation_status(), convert_from_storage(), convert_to_storage(), create_research_donation(), delete_research_donation(), _get_current_user_id(), get_research_donation_detail() (+67 more)
|
||||
Cohesion: 0.04
|
||||
Nodes (75): list_roles_for_select(), _avatar_url_field(), _build_current_user_payload(), _build_user_info_payload(), change_current_user_password(), get_current_user_profile(), _jwt_user_payload(), logout() (+67 more)
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.36
|
||||
Nodes (67): BatchStockInBody, BatchStockInItem, BatchStockOutBody, BatchStockOutItem, ConsumableCreateBody, ConsumablePackCreateBody, ConsumablePackUpdateBody, ConsumableUpdateBody (+59 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (60): batch_delete_research_donations(), change_donation_status(), convert_from_storage(), convert_to_storage(), create_research_donation(), delete_research_donation(), _get_current_user_id(), get_research_donation_detail() (+52 more)
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.06
|
||||
Nodes (52): _avatar_url_field(), _build_user_info_payload(), _jwt_user_payload(), logout(), 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/zkxw.sql 基线), Web 端登录用 RSA 公钥(PKCS#1 v1.5,与 JSEncrypt 一致), Web 端登录:账号为 sys_user.user_no,密码为 sys_user.password(bcrypt)。, 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。 (+44 more)
|
||||
Cohesion: 0.07
|
||||
Nodes (57): _ancestor_link_from_cell_product_input(), _ancestor_sample_chain_link(), _apply_cell_product_status_change(), _build_ancestor_chain(), _build_descendant_chain(), _build_facility_path_label(), build_split_product_codes(), create_cell_product() (+49 more)
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.08
|
||||
Nodes (53): get_next_cell_product_code(), _ancestor_link_from_cell_product_input(), _ancestor_sample_chain_link(), _apply_cell_product_status_change(), _build_ancestor_chain(), _build_descendant_chain(), _build_facility_path_label(), build_split_product_codes() (+45 more)
|
||||
Nodes (58): api_save_application(), auto_generate_schedules(), complete_application(), create_application(), create_basic_experiment_sale_schedules(), create_infusion_plan(), create_schedule(), _create_schedule_products() (+50 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.11
|
||||
Nodes (36): batch_create_sterilize_logs(), batch_create_wash_logs(), batch_discard_garments(), batch_soft_delete_garments(), _count_map(), create_garment(), create_sterilize_log(), create_wash_log() (+28 more)
|
||||
Nodes (35): batch_create_sterilize_logs(), batch_create_wash_logs(), batch_discard_garments(), batch_soft_delete_garments(), _count_map(), create_garment(), create_sterilize_log(), create_wash_log() (+27 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.12
|
||||
@@ -158,189 +148,147 @@ Cohesion: 0.19
|
||||
Nodes (27): _amount_for_row(), _batch_map(), deduct_for_task(), _deduct_task_usage_legacy_batch(), _display_remark(), _fmt_date_val(), _linked_qc_task_no_map(), list_linked_task_usages() (+19 more)
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
Cohesion: 0.16
|
||||
Nodes (19): get_by_schedule(), get_method(), _get_tenant_no(), list_by_application(), list_materials(), 中试服务交付管理 API(交付信息、交付物料、交付方式), soft_delete(), create_delivery() (+11 more)
|
||||
Cohesion: 0.15
|
||||
Nodes (17): create_customer(), get_customer(), id_card_taken(), list_customers(), 客户 CRUD(biz_customer), _row_to_dict(), soft_delete_customer(), update_customer() (+9 more)
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
Cohesion: 0.18
|
||||
Nodes (18): company_code_exists(), create_company(), get_company(), list_companies(), list_company_options(), _row_to_dict(), soft_delete_company(), update_company() (+10 more)
|
||||
Cohesion: 0.15
|
||||
Nodes (18): delete_hospital(), create_collection_region(), create_hospital(), get_collection_region(), get_hospital(), list_hospitals(), soft_delete_collection_region(), soft_delete_hospital() (+10 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.2
|
||||
Nodes (19): _code_exists(), create_material(), _dec(), _fmt_dt(), get_material(), get_material_entity(), get_my_usages(), _is_enabled_status() (+11 more)
|
||||
Cohesion: 0.22
|
||||
Nodes (14): batch_generate_sample_codes(), batch_issue_sample_codes(), batch_revoke_sample_codes(), create_sample_code(), get_sample_code(), list_sample_codes(), _parse_issued_time(), 样本编码池 CRUD(biz_sample_code) (+6 more)
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
Cohesion: 0.26
|
||||
Nodes (12): batch_issue_sample_codes(), batch_revoke_sample_codes(), create_sample_code(), get_sample_code(), list_sample_codes(), _parse_issued_time(), 样本编码池 CRUD(biz_sample_code), _resolve_issued_user_display_name() (+4 more)
|
||||
|
||||
### Community 21 - "Community 21"
|
||||
Cohesion: 0.23
|
||||
Nodes (12): create_collection_region(), create_hospital(), get_collection_region(), get_hospital(), _hospital_to_dict(), list_hospitals(), 按医院名称模糊检索,返回医院及所属采集地区信息。, search_hospitals_by_keyword() (+4 more)
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
Cohesion: 0.24
|
||||
Nodes (9): 微信消息通知服务 支持微信小程序模板消息推送 使用方式: from app.core.wechat_message import Wech, 发送模板消息 Args: openid: 用户openid templ, send_delivery_notice(), send_delivery_warning(), send_order_status(), send_payment_success(), send_refund_result(), send_urge_notification() (+1 more)
|
||||
|
||||
### Community 21 - "Community 21"
|
||||
Cohesion: 0.23
|
||||
Nodes (12): Config, ProductBase, ProductCategoryBase, ProductCategoryCreate, ProductCategoryResponse, ProductCreate, ProductResponse, ProductUnitBase (+4 more)
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
Cohesion: 0.24
|
||||
Nodes (12): appointment_no_exists(), create_exhibition_appointment(), _format_visit_date(), _generate_appointment_no(), get_exhibition_appointment(), list_exhibition_appointments(), 展览预约 CRUD(biz_exhibition_appointment), 生成预约编号:YYYYMMDD + 6位序号(如 20260515000001) (+4 more)
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.31
|
||||
Nodes (11): create_equipment(), _dec(), equipment_code_exists(), equipment_is_referenced(), get_equipment(), list_equipments(), _norm_status(), _parse_date() (+3 more)
|
||||
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.27
|
||||
Nodes (11): create_consumable_pack(), get_consumable_pack(), get_pack_detail(), _item_row_to_dict(), list_all_packs(), list_consumable_packs(), pack_code_exists(), 耗材包 CRUD(biz_consumable_pack + biz_consumable_pack_item) (+3 more)
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
Cohesion: 0.24
|
||||
Nodes (11): deduct_for_step(), _display_remark(), list_stock_logs(), _parse_receiver_purpose_from_remark(), 试剂变动记录 CRUD(biz_reagent_stock_log), 撤销步骤此前 step_save 扣减,便于重新填报。, 扣减试剂库存并生成变动记录。调用方控制事务,本函数不 commit。, _resolve_receiver_purpose() (+3 more)
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.32
|
||||
Nodes (11): create_env_detect_record(), _generate_record_no(), get_env_detect_record(), _join_csv(), list_env_detect_records(), _resolve_inspector_snapshots(), _resolve_item_snapshot(), _row_to_dict() (+3 more)
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
Cohesion: 0.24
|
||||
Nodes (11): deduct_for_step(), _display_remark(), list_stock_logs(), _parse_receiver_purpose_from_remark(), 耗材变动记录 CRUD(biz_consumable_stock_log), 撤销步骤此前 step_save 扣减,便于重新填报。, 扣减耗材库存并生成变动记录。调用方控制事务,本函数不 commit。, _resolve_receiver_purpose() (+3 more)
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.27
|
||||
Nodes (11): _build_tree(), _cascade_soft_delete(), _collect_with_ancestors(), create_dept(), get_dept(), list_depts(), list_depts_tree(), 保留匹配节点及其全部上级,供关键词检索后仍能正确组树。 (+3 more)
|
||||
|
||||
### Community 29 - "Community 29"
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.24
|
||||
Nodes (11): deduct_for_step(), _display_remark(), list_stock_logs(), _parse_receiver_purpose_from_remark(), 试剂变动记录 CRUD(biz_reagent_stock_log), 撤销步骤此前 step_save 扣减,便于重新填报。, 扣减试剂库存并生成变动记录。调用方控制事务,本函数不 commit。, _resolve_receiver_purpose() (+3 more)
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
Cohesion: 0.32
|
||||
Nodes (11): create_env_detect_record(), _generate_record_no(), get_env_detect_record(), _join_csv(), list_env_detect_records(), _resolve_inspector_snapshots(), _resolve_item_snapshot(), _row_to_dict() (+3 more)
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.24
|
||||
Nodes (11): deduct_for_step(), _display_remark(), list_stock_logs(), _parse_receiver_purpose_from_remark(), 耗材变动记录 CRUD(biz_consumable_stock_log), 撤销步骤此前 step_save 扣减,便于重新填报。, 扣减耗材库存并生成变动记录。调用方控制事务,本函数不 commit。, _resolve_receiver_purpose() (+3 more)
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
Cohesion: 0.29
|
||||
Nodes (9): _build_tree(), _cascade_soft_delete(), create_menu(), get_menu(), list_menus(), list_menus_tree(), _row_to_dict(), soft_delete_menu() (+1 more)
|
||||
|
||||
### Community 30 - "Community 30"
|
||||
Cohesion: 0.27
|
||||
Nodes (8): create_customer(), get_customer(), id_card_taken(), list_customers(), 客户 CRUD(biz_customer), _row_to_dict(), soft_delete_customer(), update_customer()
|
||||
|
||||
### Community 31 - "Community 31"
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): create_express_company(), express_code_exists(), get_express_company(), list_express_companies(), 快递公司 CRUD(biz_express_company), _row_to_dict(), soft_delete_express_company(), update_express_company()
|
||||
Nodes (8): create_sop_document(), get_sop_document(), list_sop_documents(), SOP文档 CRUD(biz_sop_document), _row_to_dict(), soft_delete_sop_document(), sop_code_exists(), update_sop_document()
|
||||
|
||||
### Community 32 - "Community 32"
|
||||
### Community 29 - "Community 29"
|
||||
Cohesion: 0.38
|
||||
Nodes (9): create_check_item(), get_check_item(), item_code_exists(), list_active_check_items(), list_check_items(), _order_query(), _row_to_dict(), soft_delete_check_item() (+1 more)
|
||||
|
||||
### Community 33 - "Community 33"
|
||||
Cohesion: 0.38
|
||||
Nodes (9): create_env_detect_item(), get_env_detect_item(), item_code_exists(), list_active_env_detect_items(), list_env_detect_items(), _order_query(), _row_to_dict(), soft_delete_env_detect_item() (+1 more)
|
||||
|
||||
### Community 34 - "Community 34"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): category_code_exists(), create_process_category(), get_process_category(), list_process_categories(), 工艺工序分类 CRUD(biz_process_category), _row_to_dict(), soft_delete_process_category(), update_process_category()
|
||||
|
||||
### Community 35 - "Community 35"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): create_item_unit(), get_item_unit(), list_item_units(), 物品单位 CRUD(biz_item_unit), _row_to_dict(), soft_delete_item_unit(), unit_code_exists(), update_item_unit()
|
||||
|
||||
### Community 36 - "Community 36"
|
||||
### Community 30 - "Community 30"
|
||||
Cohesion: 0.22
|
||||
Nodes (8): 菜单 code 权限守卫(V0.3:通过 sys_user_role → sys_role_menu → sys_menu.perms), 运营端角色守卫:admin / super_admin 可访问。, 接口菜单权限守卫(已统一放行 menuCode 校验,仅保留运营端登录)。, 接口菜单权限守卫(已统一放行 menuCode 校验,仅保留运营端登录)。, require_admin_or_super_admin(), require_any_menu_code(), require_menu_code(), strip_row_fields()
|
||||
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.36
|
||||
Nodes (7): create_post(), get_post(), list_posts(), post_code_exists(), _row_to_dict(), soft_delete_post(), update_post()
|
||||
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.36
|
||||
Nodes (7): create_tenant(), get_tenant(), list_tenants(), _row_to_dict(), soft_delete_tenant(), tenant_no_exists(), update_tenant()
|
||||
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 0.36
|
||||
Nodes (7): create_site(), get_site(), list_sites(), _row_to_dict(), site_code_exists(), soft_delete_site(), update_site()
|
||||
|
||||
### Community 40 - "Community 40"
|
||||
### Community 31 - "Community 31"
|
||||
Cohesion: 0.29
|
||||
Nodes (2): BaseModel, SoftDeleteModel
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
### Community 32 - "Community 32"
|
||||
Cohesion: 0.38
|
||||
Nodes (6): derive_legacy_status_from_three(), derive_three_status_from_legacy(), 阶段A兼容:从旧 status 推导三字段。 约束:旧 status 本身混合了支付/配送/订单生命周期,因此只能尽力推断; 若业务侧已有更精确, 阶段A兼容:从三字段反推旧 status(用于旧前端/旧筛选参数兼容)。, ThreeStatus, _to_decimal()
|
||||
|
||||
### Community 42 - "Community 42"
|
||||
### Community 33 - "Community 33"
|
||||
Cohesion: 0.5
|
||||
Nodes (3): BaseSettings, Config, Settings
|
||||
|
||||
### Community 43 - "Community 43"
|
||||
### Community 34 - "Community 34"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): _auto_fill_create_dept_id(), ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID
|
||||
|
||||
### Community 44 - "Community 44"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): get_menu_list(), 运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,5 个一级菜单分组)
|
||||
|
||||
### Community 45 - "Community 45"
|
||||
### Community 35 - "Community 35"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传
|
||||
|
||||
### Community 46 - "Community 46"
|
||||
### Community 36 - "Community 36"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)
|
||||
|
||||
### Community 49 - "Community 49"
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送订单状态通知 Args: openid: 用户openid ord
|
||||
|
||||
### Community 50 - "Community 50"
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送支付成功通知 Args: openid: 用户openid ord
|
||||
|
||||
### Community 51 - "Community 51"
|
||||
### Community 41 - "Community 41"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送配送通知 Args: openid: 配送员openid task
|
||||
|
||||
### Community 52 - "Community 52"
|
||||
### Community 42 - "Community 42"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送配送时效预警 Args: openid: 配送员openid ta
|
||||
|
||||
### Community 53 - "Community 53"
|
||||
### Community 43 - "Community 43"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送退款结果通知 Args: openid: 用户openid ord
|
||||
|
||||
### Community 54 - "Community 54"
|
||||
### Community 44 - "Community 44"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送催单通知给配送员 Args: deliver_openid: 配送员openid
|
||||
|
||||
## Knowledge Gaps
|
||||
- **129 isolated node(s):** `刷新会话 TTL(refreshToken 续期;已登录用户每次 API 校验通过后滑动续期)`, `写入 refreshToken(用于 one-time 使用/吊销)`, `根据 token 获取当前用户(包含 Redis 会话校验;会话滑动续期)`, `登录凭据 RSA 解密(与前端 JSEncrypt PKCS#1 v1.5 兼容)。`, `加载 RSA 密钥对:优先环境变量,否则使用内置固定默认密钥。` (+124 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **Thin community `Community 40`** (8 nodes): `BaseModel`, `.to_dict()`, `get_active()`, `base.py`, `SoftDeleteModel`, `.restore()`, `.soft_delete()`, `__tablename__()`
|
||||
- **Thin community `Community 31`** (8 nodes): `BaseModel`, `.to_dict()`, `get_active()`, `base.py`, `SoftDeleteModel`, `.restore()`, `.soft_delete()`, `__tablename__()`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 43`** (4 nodes): `_auto_fill_create_dept_id()`, `get_db()`, `database.py`, `ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID`
|
||||
- **Thin community `Community 34`** (4 nodes): `_auto_fill_create_dept_id()`, `get_db()`, `database.py`, `ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 44`** (3 nodes): `get_menu_list()`, `menu.py`, `运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,5 个一级菜单分组)`
|
||||
- **Thin community `Community 35`** (2 nodes): `context.py`, `请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 45`** (2 nodes): `context.py`, `请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传`
|
||||
- **Thin community `Community 36`** (2 nodes): `__init__.py`, `API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 46`** (2 nodes): `__init__.py`, `API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)`
|
||||
- **Thin community `Community 39`** (1 nodes): `发送订单状态通知 Args: openid: 用户openid ord`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 49`** (1 nodes): `发送订单状态通知 Args: openid: 用户openid ord`
|
||||
- **Thin community `Community 40`** (1 nodes): `发送支付成功通知 Args: openid: 用户openid ord`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 50`** (1 nodes): `发送支付成功通知 Args: openid: 用户openid ord`
|
||||
- **Thin community `Community 41`** (1 nodes): `发送配送通知 Args: openid: 配送员openid task`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 51`** (1 nodes): `发送配送通知 Args: openid: 配送员openid task`
|
||||
- **Thin community `Community 42`** (1 nodes): `发送配送时效预警 Args: openid: 配送员openid ta`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 52`** (1 nodes): `发送配送时效预警 Args: openid: 配送员openid ta`
|
||||
- **Thin community `Community 43`** (1 nodes): `发送退款结果通知 Args: openid: 用户openid ord`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 53`** (1 nodes): `发送退款结果通知 Args: openid: 用户openid ord`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 54`** (1 nodes): `发送催单通知给配送员 Args: deliver_openid: 配送员openid`
|
||||
- **Thin community `Community 44`** (1 nodes): `发送催单通知给配送员 Args: deliver_openid: 配送员openid`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `SysUser` connect `Community 1` to `Community 0`, `Community 2`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 17`, `Community 20`, `Community 25`, `Community 27`?**
|
||||
_High betweenness centrality (0.108) - this node is a cross-community bridge._
|
||||
- **Why does `success_response()` connect `Community 0` to `Community 1`, `Community 3`, `Community 6`, `Community 7`, `Community 10`, `Community 12`, `Community 44`, `Community 13`, `Community 17`?**
|
||||
_High betweenness centrality (0.068) - this node is a cross-community bridge._
|
||||
- **Why does `generate_uuid()` connect `Community 4` to `Community 0`, `Community 1`, `Community 2`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 12`, `Community 13`, `Community 14`, `Community 16`, `Community 18`, `Community 19`, `Community 20`, `Community 21`, `Community 23`, `Community 24`, `Community 25`, `Community 26`, `Community 27`, `Community 28`, `Community 29`, `Community 30`, `Community 31`, `Community 32`, `Community 33`, `Community 34`, `Community 35`, `Community 37`, `Community 38`, `Community 39`?**
|
||||
_High betweenness centrality (0.060) - this node is a cross-community bridge._
|
||||
- **Are the 703 inferred relationships involving `str` (e.g. with `unhandled_exception_handler()` and `get_current_user_by_token()`) actually correct?**
|
||||
_`str` has 703 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 651 inferred relationships involving `success_response()` (e.g. with `list_storage_release_reviews()` and `get_storage_release_review_detail()`) actually correct?**
|
||||
_`success_response()` has 651 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 537 inferred relationships involving `error_response()` (e.g. with `_json_error_response()` and `list_storage_release_reviews()`) actually correct?**
|
||||
_`error_response()` has 537 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 456 inferred relationships involving `SysUser` (e.g. with `数据权限过滤(V0.3:基于角色 data_scope 的查询级行级过滤) data_scope 值: 1 = 全部数据 2 = 本部门数据 3` and `从 SysUser 读取用户的 dept_id。`) actually correct?**
|
||||
_`SysUser` has 456 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Why does `SysUser` connect `Community 1` to `Community 0`, `Community 2`, `Community 3`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 9`, `Community 10`, `Community 11`, `Community 19`, `Community 24`, `Community 26`?**
|
||||
_High betweenness centrality (0.141) - this node is a cross-community bridge._
|
||||
- **Why does `generate_uuid()` connect `Community 2` to `Community 0`, `Community 3`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 14`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 22`, `Community 23`, `Community 24`, `Community 25`, `Community 26`, `Community 27`, `Community 28`, `Community 29`?**
|
||||
_High betweenness centrality (0.076) - this node is a cross-community bridge._
|
||||
- **Why does `success_response()` connect `Community 0` to `Community 1`, `Community 4`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 13`, `Community 18`?**
|
||||
_High betweenness centrality (0.061) - this node is a cross-community bridge._
|
||||
- **Are the 707 inferred relationships involving `str` (e.g. with `unhandled_exception_handler()` and `get_current_user_by_token()`) actually correct?**
|
||||
_`str` has 707 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 652 inferred relationships involving `success_response()` (e.g. with `list_storage_release_reviews()` and `get_storage_release_review_detail()`) actually correct?**
|
||||
_`success_response()` has 652 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 538 inferred relationships involving `error_response()` (e.g. with `_json_error_response()` and `list_storage_release_reviews()`) actually correct?**
|
||||
_`error_response()` has 538 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 460 inferred relationships involving `SysUser` (e.g. with `数据权限过滤(V0.3:基于角色 data_scope 的查询级行级过滤) data_scope 值: 1 = 全部数据 2 = 本部门数据 3` and `从 SysUser 读取用户的 dept_id。`) actually correct?**
|
||||
_`SysUser` has 460 INFERRED edges - model-reasoned connections that need verification._
|
||||
@@ -57,12 +57,12 @@
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">4251 nodes · 22373 edges · 59 communities</div>
|
||||
<div id="stats">4285 nodes · 22669 edges · 49 communities</div>
|
||||
</div>
|
||||
<script>
|
||||
const RAW_NODES = [{"id": "init_py", "label": "__init__.py", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 47, "community_name": "Community 47", "source_file": "__init__.py", "file_type": "code", "degree": 0}, {"id": "main_py", "label": "main.py", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "main.py", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 7}, {"id": "app_main_lifespan", "label": "lifespan()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "lifespan()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_error_json", "label": "_error_json()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "_error_json()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 3}, {"id": "app_main_sqlalchemy_exception_handler", "label": "sqlalchemy_exception_handler()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "sqlalchemy_exception_handler()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_unhandled_exception_handler", "label": "unhandled_exception_handler()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "unhandled_exception_handler()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 5}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "_mask_secret()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_root", "label": "root()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "root()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_health_check", "label": "health_check()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "health_check()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_rationale_81", "label": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "app_main_rationale_92", "label": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "tasks_init_py", "label": "__init__.py", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 6, "community_name": "Community 6", "source_file": "tasks/__init__.py", "file_type": "code", "degLine truncated
|
||||
const RAW_EDGES = [{"from": "main_py", "to": "app_main_lifespan", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_error_json", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_sqlalchemy_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_unhandled_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_mask_secret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_root", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_health_check", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_lifespan", "to": "core_login_crypto_ensure_initialized", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_init_scheduled_tasks", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_shutdown_scheduler", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_error_json", "to": "app_main_sqlalchemy_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_error_json", "to": "app_main_unhandled_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "app_main_rationale_81", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "app_main_rationale_92", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_unhandled_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "str", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tasks_init_py", "to": "tasks_init_init_scheduled_tasks", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tasks_init_py", "to": "tasks_init_shutdown_scheduler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_redis_session_enabled", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_redis_client", "labeLine truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 835}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 648}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 525}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 355}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 317}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 228}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 186}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 181}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 174}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 98}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 88}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 74}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 61}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 56}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 39}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 31}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 28}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 22}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 20}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 20}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 14}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 14}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 13}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 13}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 13}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 12}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 12}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 12}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 12}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 11}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 11}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 10}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 10}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 10}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 10}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 10}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 9}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 9}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 9}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 9}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 8}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 7}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 4}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 4}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 3}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 2}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 2}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 1}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 1}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 1}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 1}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 1}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 1}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 1}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 1}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 1}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 1}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 1}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 1}];
|
||||
const RAW_NODES = [{"id": "init_py", "label": "__init__.py", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 37, "community_name": "Community 37", "source_file": "__init__.py", "file_type": "code", "degree": 0}, {"id": "main_py", "label": "main.py", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "main.py", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 7}, {"id": "app_main_lifespan", "label": "lifespan()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "lifespan()", "community": 10, "community_name": "Community 10", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_error_json", "label": "_error_json()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "_error_json()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 3}, {"id": "app_main_sqlalchemy_exception_handler", "label": "sqlalchemy_exception_handler()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "sqlalchemy_exception_handler()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_unhandled_exception_handler", "label": "unhandled_exception_handler()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "unhandled_exception_handler()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 5}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "_mask_secret()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_root", "label": "root()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "root()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_health_check", "label": "health_check()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "health_check()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_rationale_81", "label": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "app_main_rationale_92", "label": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "tasks_init_py", "label": "__init__.py", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 10, "community_name": "Community 10", "source_file": "tasks/__init__.py", "file_type": "code", Line truncated
|
||||
const RAW_EDGES = [{"from": "main_py", "to": "app_main_lifespan", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_error_json", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_sqlalchemy_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_unhandled_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_mask_secret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_root", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_health_check", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_lifespan", "to": "core_login_crypto_ensure_initialized", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_init_scheduled_tasks", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_shutdown_scheduler", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_error_json", "to": "app_main_sqlalchemy_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_error_json", "to": "app_main_unhandled_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "app_main_rationale_81", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "app_main_rationale_92", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_unhandled_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "str", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tasks_init_py", "to": "tasks_init_init_scheduled_tasks", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tasks_init_py", "to": "tasks_init_shutdown_scheduler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_redis_session_enabled", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_redis_client", "labeLine truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 899}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 648}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 488}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 372}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 344}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 233}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 202}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 179}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 177}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 151}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 86}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 64}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 61}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 60}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 38}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 31}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 28}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 21}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 21}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 16}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 13}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 13}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 13}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 12}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 12}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 12}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 12}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 11}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 10}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 10}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 9}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 8}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 7}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 4}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 4}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 2}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 2}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 1}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 1}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 1}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 1}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 1}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 1}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 1}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 1}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 1}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 1}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 1}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 1}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 0}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 0}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 0}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 0}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 0}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 0}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 0}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 0}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 0}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 0}];
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
|
||||
+19461
-15603
File diff suppressed because it is too large.
Load diff
@@ -28,7 +28,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/material.py": 1781427174.243315,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/production_material.py": 1781427178.0074935,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/qc_param.py": 1779022399.0175831,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py": 1781747637.7400184,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py": 1782351467.7127345,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/cleanroom_garment.py": 1781347080.6165943,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/__init__.py": 1781344070.5899634,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py": 1780458012.8329656,
|
||||
@@ -50,7 +50,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/product_parameter_value.py": 1778578258.0980055,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/product_review_media.py": 1778578258.0986822,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/product_parameter.py": 1778578258.0977957,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py": 1781524096.5898407,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_task.py": 1782351474.1300344,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/product_detail_media.py": 1778578258.0973988,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/product_banner.py": 1778578258.097102,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/region.py": 1778578258.099429,
|
||||
@@ -64,7 +64,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/category_parameter.py": 1778578258.0944862,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/common.py": 1778578258.094703,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/unit.py": 1778578258.0996897,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py": 1781245309.0806582,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py": 1782350310.733416,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/outbound_release_material.py": 1779827058.9935315,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/product.py": 1778578258.0968297,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/workflow.py": 1778633845.5937889,
|
||||
@@ -74,8 +74,8 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/leave.py": 1778666088.7680702,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py": 1781536745.221194,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/equipment.py": 1781524075.5310335,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py": 1781589822.2906754,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py": 1781524077.6406052,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py": 1782350322.6331227,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py": 1782289879.5489628,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/sample_code.py": 1780479191.5382729,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_result.py": 1779331731.6720955,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/outbound_release_review.py": 1781603141.940902,
|
||||
@@ -97,7 +97,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/material_usage.py": 1781427187.4456425,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_material_usage.py": 1781513732.7796721,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/sop_document.py": 1779265721.9928973,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py": 1781583485.3504221,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py": 1782360197.8427687,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_third_party_item.py": 1779265661.482352,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/reagent.py": 1779512669.9847593,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py": 1782195334.7812605,
|
||||
@@ -119,6 +119,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/role.py": 1779265616.3701816,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_material_stock_batch.py": 1781690315.173275,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/material_stock_check.py": 1781427194.5434632,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task_step_assignee.py": 1782351472.9662378,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py": 1781590614.9654794,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py": 1781233180.3766735,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation_sample_collection.py": 1781063441.5812025,
|
||||
@@ -137,11 +138,11 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/env_detect_item.py": 1781145689.9525824,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_category.py": 1779265700.0606413,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/item_unit.py": 1779265653.7504313,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py": 1781698777.252274,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py": 1782350337.3184292,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/outbound_handover_inventory.py": 1781598316.476379,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/env_detect_record.py": 1781145773.959546,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/outbound_release_material.py": 1781612877.0137436,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py": 1781524075.6578302,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py": 1782289878.7772164,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/pilot_service.py": 1781599314.0124536,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/customer.py": 1779686149.7508218,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/workflow.py": 1779265993.677624,
|
||||
@@ -152,7 +153,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_material.py": 1779284415.64655,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol_no.py": 1779882001.753651,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/outbound_handover.py": 1780455574.0993364,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py": 1781435014.6878881,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_facility.py": 1782290554.4607918,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/sample_reception_lab_code.py": 1780462849.099601,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_sample_type.py": 1781747645.1762104,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/pilot_outbound_status_sync.py": 1781595840.6955194,
|
||||
@@ -184,7 +185,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/pre_transit_sample.py": 1782204426.7965167,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py": 1780326875.7886882,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/research_donation_sample_collection.py": 1780457788.2998126,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py": 1781435016.699977,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py": 1782290496.6424515,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py": 1781749943.5843754,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/pilot_delivery.py": 1779655584.820777,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/admin.py": 1782268401.1532724,
|
||||
@@ -197,13 +198,13 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py": 1780325524.907156,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_reception.py": 1781535825.750677,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/insurance_company.py": 1781410837.9443986,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py": 1781605168.6365004,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py": 1782362266.599568,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/protocol_sample_collection.py": 1780457788.2093296,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/leave.py": 1779266168.8693042,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/clinical_payment.py": 1781750841.074568,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/workflow_callback.py": 1778727966.7277644,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py": 1781337818.5442588,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py": 1781348051.133351,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/storage_facility_code.py": 1782289322.2116506,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/workflow_engine.py": 1778634664.6293883,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/web_auth_roles.py": 1782122624.7941194,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/protocol_payment_installment.py": 1781432208.0765035,
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
-- 生产过程派发质检:支持仅关联步骤产出物(无细胞产品时也可派发)
|
||||
ALTER TABLE `biz_qc_work_order`
|
||||
ADD COLUMN `production_step_output_id` varchar(64) DEFAULT NULL
|
||||
COMMENT '关联生产任务步骤产出物ID(生产过程触发时)'
|
||||
AFTER `production_task_id`;
|
||||
|
||||
CREATE INDEX `idx_qc_wo_prod_step_output` ON `biz_qc_work_order` (`production_step_output_id`, `del_flag`);
|
||||
@@ -0,0 +1,30 @@
|
||||
-- 可选:将仍有 task.current_assignee_user_id 且无步骤负责人的旧任务回填到全部步骤
|
||||
--
|
||||
-- 注意:MySQL 5.7 在 INSERT...SELECT 中 UUID() 可能整批只计算一次,导致主键重复。
|
||||
-- 此处用 SHA2(step_id) 生成确定性主键,每步唯一,且可重复执行(已存在则跳过)。
|
||||
|
||||
INSERT INTO `biz_production_task_step_assignee` (
|
||||
`id`, `step_id`, `user_id`, `tenant_no`, `order_num`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
|
||||
)
|
||||
SELECT
|
||||
LOWER(SHA2(CONCAT('step-assignee-backfill:', s.id), 256)),
|
||||
s.id,
|
||||
t.current_assignee_user_id,
|
||||
s.tenant_no,
|
||||
0,
|
||||
t.create_by,
|
||||
IFNULL(t.create_dept_id, ''),
|
||||
NOW(),
|
||||
t.update_by,
|
||||
NOW(),
|
||||
0
|
||||
FROM `biz_production_task` t
|
||||
JOIN `biz_production_task_step` s ON s.task_id = t.id AND s.del_flag = 0
|
||||
WHERE t.del_flag = 0
|
||||
AND t.current_assignee_user_id IS NOT NULL
|
||||
AND TRIM(t.current_assignee_user_id) <> ''
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM `biz_production_task_step_assignee` a
|
||||
WHERE a.step_id = s.id AND a.del_flag = 0
|
||||
);
|
||||
@@ -0,0 +1,26 @@
|
||||
-- 生产任务 · 工艺步骤级派发
|
||||
-- 步骤计划开始时间、完成人 + 步骤负责人关联表
|
||||
|
||||
ALTER TABLE `biz_production_task_step`
|
||||
ADD COLUMN `planned_start_time` datetime DEFAULT NULL COMMENT '计划开始时间' AFTER `step_status`;
|
||||
|
||||
ALTER TABLE `biz_production_task_step`
|
||||
ADD COLUMN `completed_by` varchar(64) DEFAULT NULL COMMENT '完成步骤的用户ID' AFTER `completed_time`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `biz_production_task_step_assignee` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键',
|
||||
`step_id` varchar(64) NOT NULL COMMENT '生产任务步骤ID',
|
||||
`user_id` varchar(64) NOT NULL COMMENT '负责人用户ID',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
|
||||
`order_num` int DEFAULT 0 COMMENT '展示顺序',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人id',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
|
||||
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人id',
|
||||
`update_time` datetime NOT NULL COMMENT '更新时间',
|
||||
`del_flag` tinyint NOT NULL DEFAULT 0 COMMENT '删除标记',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_step_assignee_step` (`step_id`),
|
||||
KEY `idx_step_assignee_user` (`user_id`, `tenant_no`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生产任务步骤负责人';
|
||||
+33
-1
@@ -3522,8 +3522,10 @@ CREATE TABLE `biz_production_task_step` (
|
||||
`actual_duration` varchar(100) DEFAULT NULL COMMENT '实际耗时',
|
||||
`sop_ids` varchar(1000) DEFAULT NULL COMMENT 'SOP文档ID(逗号分隔)',
|
||||
`step_status` varchar(16) NOT NULL DEFAULT 'dzx' COMMENT '状态(dzx待执行/jxz进行中/ywc已完成)',
|
||||
`planned_start_time` datetime DEFAULT NULL COMMENT '计划开始时间',
|
||||
`started_time` datetime DEFAULT NULL COMMENT '开始时间',
|
||||
`completed_time` datetime DEFAULT NULL COMMENT '完成时间',
|
||||
`completed_by` varchar(64) DEFAULT NULL COMMENT '完成步骤的用户ID',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
@@ -3538,12 +3540,40 @@ CREATE TABLE `biz_production_task_step` (
|
||||
KEY `idx_pts_tenant` (`tenant_no`,`del_flag`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生产任务工艺步骤';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for biz_production_task_step_assignee
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `biz_production_task_step_assignee`;
|
||||
CREATE TABLE `biz_production_task_step_assignee` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键',
|
||||
`step_id` varchar(64) NOT NULL COMMENT '生产任务步骤ID',
|
||||
`user_id` varchar(64) NOT NULL COMMENT '负责人用户ID',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT '0' COMMENT '展示顺序',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人id',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
|
||||
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人id',
|
||||
`update_time` datetime NOT NULL COMMENT '更新时间',
|
||||
`del_flag` tinyint(4) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_step_assignee_step` (`step_id`),
|
||||
KEY `idx_step_assignee_user` (`user_id`,`tenant_no`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生产任务步骤负责人';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of biz_production_task_step
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of biz_production_task_step_assignee
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for biz_production_task_step_configured_reagent
|
||||
-- ----------------------------
|
||||
@@ -4647,6 +4677,7 @@ CREATE TABLE `biz_qc_work_order` (
|
||||
`cell_product_id` varchar(64) DEFAULT NULL COMMENT '质检对象-细胞产品ID',
|
||||
`production_work_order_id` varchar(64) DEFAULT NULL COMMENT '关联生产工单ID(生产过程触发时)',
|
||||
`production_task_id` varchar(64) DEFAULT NULL COMMENT '关联生产任务ID(可选)',
|
||||
`production_step_output_id` varchar(64) DEFAULT NULL COMMENT '关联生产任务步骤产出物ID(生产过程触发时)',
|
||||
`work_order_status` varchar(16) NOT NULL DEFAULT 'dpz' COMMENT 'dpz待配置 ypz已配置 ywc已完成',
|
||||
`has_lab` char(1) NOT NULL DEFAULT '0' COMMENT '含实验室自检',
|
||||
`has_third_party` char(1) NOT NULL DEFAULT '0' COMMENT '含第三方检测',
|
||||
@@ -4666,7 +4697,8 @@ CREATE TABLE `biz_qc_work_order` (
|
||||
UNIQUE KEY `uk_qc_wo_reception` (`reception_id`,`del_flag`),
|
||||
KEY `idx_qc_wo_tenant_status` (`tenant_no`,`work_order_status`,`del_flag`),
|
||||
KEY `idx_qc_wo_sample_trigger` (`tenant_no`,`sample_code`,`trigger_source`,`del_flag`),
|
||||
KEY `idx_qc_wo_prod_wo` (`production_work_order_id`,`del_flag`)
|
||||
KEY `idx_qc_wo_prod_wo` (`production_work_order_id`,`del_flag`),
|
||||
KEY `idx_qc_wo_prod_step_output` (`production_step_output_id`,`del_flag`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='质检工单';
|
||||
|
||||
-- ----------------------------
|
||||
|
||||
@@ -0,0 +1,926 @@
|
||||
# 生产任务 · 工艺步骤级派发 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 将生产任务派发粒度从「整条任务 + 单一负责人」改为「工艺步骤 + 多人负责人 + 计划开始时间」;「我的生产任务」按步骤负责人过滤;执行弹窗内仅可操作派给自己的步骤。
|
||||
|
||||
**Architecture:** 新增 `biz_production_task_step_assignee`(对齐 `biz_qc_task_assignee`);步骤表增加 `planned_start_time`、`completed_by`;`PUT /production-tasks/{id}/steps/dispatch` 批量 sync 负责人;mine 鉴权从 `assert_task_assignee` 改为「任务级任一步 assignee OR 步骤级 assignee」+ 步骤写操作 `assert_step_assignee`;前端新增 `DispatchStepDialog.vue`,移除任务级负责人表单,隐藏任务转发/改派入口。
|
||||
|
||||
**Tech Stack:** MySQL 5.7 · FastAPI · SQLAlchemy · Pydantic v2 · Vue 3 · Element Plus · pnpm
|
||||
|
||||
**Design Spec:** `docs/superpowers/specs/2026-06-25-production-step-dispatch-design.md`
|
||||
|
||||
---
|
||||
|
||||
## File Map
|
||||
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `docs/sql/migrations/2026-06-25-production-step-dispatch.sql` | 步骤字段 + assignee 表 |
|
||||
| `docs/sql/migrations/2026-06-25-production-step-dispatch-backfill.sql` | 可选:旧任务 task assignee → 全步骤 assignee |
|
||||
| `docs/sql/zkxw.sql` | 同步 DDL |
|
||||
| `backend/app/models/models.py` | `BizProductionTaskStep` 新列 + `BizProductionTaskStepAssignee` |
|
||||
| `backend/app/models/__init__.py` | export 新模型 |
|
||||
| `backend/app/crud/production_task_step_assignee.py` | **新建** sync / enrich / validate |
|
||||
| `backend/app/crud/production_task.py` | mine 过滤、dispatch、assert、completed_by、create 去 assignee 必填 |
|
||||
| `backend/app/schemas/production_task.py` | `ProductionTaskStepDispatchBody`;Create 去必填 assignee |
|
||||
| `backend/app/api/production.py` | `PUT steps/dispatch`;`_assert_*` 改造 |
|
||||
| `web-admin/src/api/production-task.ts` | `fetchDispatchProductionTaskSteps`;create 去 assigneeUserId |
|
||||
| `web-admin/src/views/production/production-work-order/DispatchStepDialog.vue` | **新建** 步骤派发表格弹窗 |
|
||||
| `web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue` | 移除任务负责人;B 入口打开步骤派发 |
|
||||
| `web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue` | 步骤派发按钮;隐藏转发/改派;展示步骤负责人 |
|
||||
| `web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue` | mine 步骤过滤 + 只读样式 |
|
||||
| `web-admin/src/views/production/production-work-order/StepDetailPanel.vue` | `canEditStep` 控制按钮 |
|
||||
| `web-admin/src/views/production/production-work-order/useTaskStepEditor.ts` | `canEditStep` / 完成写 completed_by 透传 |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: 数据库迁移
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/sql/migrations/2026-06-25-production-step-dispatch.sql`
|
||||
- Create: `docs/sql/migrations/2026-06-25-production-step-dispatch-backfill.sql`
|
||||
- Modify: `docs/sql/zkxw.sql`(`biz_production_task_step` 与新建表片段)
|
||||
|
||||
- [ ] **Step 1: 编写主 migration**
|
||||
|
||||
```sql
|
||||
-- docs/sql/migrations/2026-06-25-production-step-dispatch.sql
|
||||
|
||||
ALTER TABLE `biz_production_task_step`
|
||||
ADD COLUMN `planned_start_time` datetime DEFAULT NULL COMMENT '计划开始时间' AFTER `step_status`;
|
||||
|
||||
ALTER TABLE `biz_production_task_step`
|
||||
ADD COLUMN `completed_by` varchar(64) DEFAULT NULL COMMENT '完成步骤的用户ID' AFTER `completed_time`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `biz_production_task_step_assignee` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键',
|
||||
`step_id` varchar(64) NOT NULL COMMENT '生产任务步骤ID',
|
||||
`user_id` varchar(64) NOT NULL COMMENT '负责人用户ID',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
|
||||
`order_num` int DEFAULT 0 COMMENT '展示顺序',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人id',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
|
||||
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人id',
|
||||
`update_time` datetime NOT NULL COMMENT '更新时间',
|
||||
`del_flag` tinyint NOT NULL DEFAULT 0 COMMENT '删除标记',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_step_assignee_step` (`step_id`),
|
||||
KEY `idx_step_assignee_user` (`user_id`, `tenant_no`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生产任务步骤负责人';
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 编写可选 backfill(旧数据兼容)**
|
||||
|
||||
```sql
|
||||
-- docs/sql/migrations/2026-06-25-production-step-dispatch-backfill.sql
|
||||
-- 将仍有 task.current_assignee_user_id 且无步骤负责人的任务,回填到全部步骤
|
||||
|
||||
INSERT INTO biz_production_task_step_assignee (
|
||||
id, step_id, user_id, tenant_no, order_num,
|
||||
create_by, create_dept_id, create_time, update_by, update_time, del_flag
|
||||
)
|
||||
SELECT
|
||||
REPLACE(UUID(), '-', ''),
|
||||
s.id,
|
||||
t.current_assignee_user_id,
|
||||
s.tenant_no,
|
||||
0,
|
||||
t.create_by,
|
||||
IFNULL(t.create_dept_id, ''),
|
||||
NOW(),
|
||||
t.update_by,
|
||||
NOW(),
|
||||
0
|
||||
FROM biz_production_task t
|
||||
JOIN biz_production_task_step s ON s.task_id = t.id AND s.del_flag = 0
|
||||
WHERE t.del_flag = 0
|
||||
AND t.current_assignee_user_id IS NOT NULL
|
||||
AND TRIM(t.current_assignee_user_id) <> ''
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM biz_production_task_step_assignee a
|
||||
WHERE a.step_id = s.id AND a.del_flag = 0
|
||||
);
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 在开发/测试库执行主 migration**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mysql -u ... -p ... zkxw < docs/sql/migrations/2026-06-25-production-step-dispatch.sql
|
||||
```
|
||||
|
||||
Expected: 两列新增成功;`biz_production_task_step_assignee` 表存在。
|
||||
|
||||
- [ ] **Step 4: 同步 `docs/sql/zkxw.sql` 对应 DDL**
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Backend 模型
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/models/models.py`
|
||||
- Modify: `backend/app/models/__init__.py`
|
||||
|
||||
- [ ] **Step 1: 扩展 `BizProductionTaskStep`**
|
||||
|
||||
在 `step_status` 后、`started_time` 前增加:
|
||||
|
||||
```python
|
||||
planned_start_time = Column(DateTime, nullable=True, comment="计划开始时间")
|
||||
```
|
||||
|
||||
在 `completed_time` 后增加:
|
||||
|
||||
```python
|
||||
completed_by = Column(String(64), nullable=True, comment="完成步骤的用户ID")
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 新增 `BizProductionTaskStepAssignee`**
|
||||
|
||||
放在 `BizProductionTaskStep` 附近,字段对齐 migration SQL(参照 `BizQcTaskAssignee`)。
|
||||
|
||||
- [ ] **Step 3: 注册 export**
|
||||
|
||||
`backend/app/models/__init__.py`:
|
||||
|
||||
```python
|
||||
from app.models.models import (
|
||||
# ...
|
||||
BizProductionTaskStepAssignee,
|
||||
)
|
||||
__all__ = [
|
||||
# ...
|
||||
"BizProductionTaskStepAssignee",
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: Backend Schema
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/schemas/production_task.py`
|
||||
|
||||
- [ ] **Step 1: 创建任务 body 去掉 assignee 必填**
|
||||
|
||||
```python
|
||||
class ProductionTaskCreate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
work_order_id: str
|
||||
assignee_user_id: Optional[str] = Field(None, alias="assigneeUserId") # deprecated,可选
|
||||
task_type: Optional[str] = 'cell_storage'
|
||||
task_name: Optional[str] = None
|
||||
route_id: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
remark: Optional[str] = None
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 新增步骤派发 body**
|
||||
|
||||
```python
|
||||
class ProductionTaskStepDispatchItem(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
step_id: str = Field(..., alias="stepId")
|
||||
assignee_user_ids: List[str] = Field(..., alias="assigneeUserIds", min_length=1)
|
||||
planned_start_time: Optional[datetime] = Field(None, alias="plannedStartTime")
|
||||
|
||||
|
||||
class ProductionTaskStepDispatchBody(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
steps: List[ProductionTaskStepDispatchItem] = Field(..., min_length=1)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: 步骤负责人 CRUD 模块
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/crud/production_task_step_assignee.py`
|
||||
|
||||
- [ ] **Step 1: 创建模块(复制 QC 模式并改表名)**
|
||||
|
||||
```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 BizProductionTaskStepAssignee, SysUser
|
||||
|
||||
# validate_assignee_user_ids — 与 qc_task_assignee.validate_assignee_user_ids 相同逻辑
|
||||
|
||||
|
||||
def sync_assignees_for_step(
|
||||
db: Session,
|
||||
step_id: str,
|
||||
user_ids: List[str],
|
||||
*,
|
||||
tenant_no: str,
|
||||
operator_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
) -> None:
|
||||
"""全量替换步骤负责人(软删旧 + 插入新)。"""
|
||||
# 实现同 qc_task_assignee.sync_assignees_for_task,表换 BizProductionTaskStepAssignee,FK 换 step_id
|
||||
|
||||
|
||||
def enrich_step_assignees(
|
||||
db: Session, steps: List[Dict], *, tenant_no: str
|
||||
) -> None:
|
||||
"""批量填充 assigneeUserIds / assigneeNames / assignees。"""
|
||||
step_ids = [s["id"] for s in steps if s.get("id")]
|
||||
if not step_ids:
|
||||
return
|
||||
rows = (
|
||||
db.query(BizProductionTaskStepAssignee, SysUser)
|
||||
.outerjoin(SysUser, eq_unicode(SysUser.id, BizProductionTaskStepAssignee.user_id))
|
||||
.filter(
|
||||
BizProductionTaskStepAssignee.step_id.in_(step_ids),
|
||||
BizProductionTaskStepAssignee.tenant_no == tenant_no,
|
||||
BizProductionTaskStepAssignee.del_flag == 0,
|
||||
)
|
||||
.order_by(BizProductionTaskStepAssignee.order_num.asc())
|
||||
.all()
|
||||
)
|
||||
by_step: Dict[str, List] = {}
|
||||
for assignee, user in rows:
|
||||
by_step.setdefault(assignee.step_id, []).append((assignee, user))
|
||||
for step in steps:
|
||||
pairs = by_step.get(step["id"], [])
|
||||
step["assigneeUserIds"] = [a.user_id for a, _ in pairs]
|
||||
step["assigneeNames"] = [
|
||||
f"{(u.nick_name or u.user_name or '')}({u.user_no or ''})".strip()
|
||||
for _, u in pairs if u
|
||||
]
|
||||
step["assignees"] = [
|
||||
{
|
||||
"userId": a.user_id,
|
||||
"nickName": (u.nick_name or u.user_name or "") if u else "",
|
||||
"userNo": (u.user_no or "") if u else "",
|
||||
}
|
||||
for a, u in pairs
|
||||
]
|
||||
|
||||
|
||||
def user_is_step_assignee(
|
||||
db: Session, step_id: str, user_id: str, tenant_no: str
|
||||
) -> bool:
|
||||
uid = (user_id or "").strip()
|
||||
if not uid:
|
||||
return False
|
||||
return (
|
||||
db.query(BizProductionTaskStepAssignee.id)
|
||||
.filter(
|
||||
BizProductionTaskStepAssignee.step_id == step_id,
|
||||
BizProductionTaskStepAssignee.user_id == uid,
|
||||
BizProductionTaskStepAssignee.tenant_no == tenant_no,
|
||||
BizProductionTaskStepAssignee.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
is not None
|
||||
)
|
||||
|
||||
|
||||
def user_is_any_step_assignee_of_task(
|
||||
db: Session, task_id: str, user_id: str, tenant_no: str
|
||||
) -> bool:
|
||||
from app.models.models import BizProductionTaskStep
|
||||
|
||||
uid = (user_id or "").strip()
|
||||
if not uid:
|
||||
return False
|
||||
return (
|
||||
db.query(BizProductionTaskStepAssignee.id)
|
||||
.join(
|
||||
BizProductionTaskStep,
|
||||
BizProductionTaskStep.id == BizProductionTaskStepAssignee.step_id,
|
||||
)
|
||||
.filter(
|
||||
BizProductionTaskStep.task_id == task_id,
|
||||
BizProductionTaskStep.del_flag == 0,
|
||||
BizProductionTaskStepAssignee.user_id == uid,
|
||||
BizProductionTaskStepAssignee.tenant_no == tenant_no,
|
||||
BizProductionTaskStepAssignee.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
is not None
|
||||
)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 本地 import smoke test**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd backend && source venv/bin/activate
|
||||
python -c "from app.crud import production_task_step_assignee; print('ok')"
|
||||
```
|
||||
|
||||
Expected: `ok`
|
||||
|
||||
---
|
||||
|
||||
## Task 5: production_task.py — 步骤 dict、派发、mine 过滤
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/crud/production_task.py`
|
||||
|
||||
- [ ] **Step 1: 扩展 `_step_to_dict`**
|
||||
|
||||
```python
|
||||
def _step_to_dict(s: BizProductionTaskStep) -> Dict[str, Any]:
|
||||
return {
|
||||
# ... existing fields ...
|
||||
"stepStatus": s.step_status or "dzx",
|
||||
"plannedStartTime": _fmt_dt(getattr(s, "planned_start_time", None)),
|
||||
"startedTime": _fmt_dt(s.started_time),
|
||||
"completedTime": _fmt_dt(s.completed_time),
|
||||
"completedBy": getattr(s, "completed_by", None) or "",
|
||||
"completedByName": "",
|
||||
"assigneeUserIds": [],
|
||||
"assigneeNames": [],
|
||||
"assignees": [],
|
||||
"remark": s.remark or "",
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: `create_production_task` 去掉 assignee 必填**
|
||||
|
||||
删除或注释:
|
||||
|
||||
```python
|
||||
assignee_raw = (data.get("assignee_user_id") or data.get("assigneeUserId") or "").strip()
|
||||
assignee_user_id = _validate_assignee_user_id(db, assignee_raw, tenant_no)
|
||||
```
|
||||
|
||||
改为:
|
||||
|
||||
```python
|
||||
assignee_raw = (data.get("assignee_user_id") or data.get("assigneeUserId") or "").strip()
|
||||
assignee_user_id = assignee_raw.strip() or None
|
||||
if assignee_raw.strip():
|
||||
assignee_user_id = _validate_assignee_user_id(db, assignee_raw, tenant_no)
|
||||
```
|
||||
|
||||
创建任务时:
|
||||
|
||||
```python
|
||||
current_assignee_user_id=assignee_user_id, # 可为 NULL
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 新增 `dispatch_task_steps`**
|
||||
|
||||
```python
|
||||
def dispatch_task_steps(
|
||||
db: Session,
|
||||
task_id: str,
|
||||
*,
|
||||
tenant_no: str,
|
||||
steps_payload: List[Dict[str, Any]],
|
||||
operator_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
) -> Dict[str, Any]:
|
||||
from app.crud import production_task_step_assignee as step_assignee_svc
|
||||
|
||||
task = get_production_task_row(db, task_id, tenant_no)
|
||||
if not task:
|
||||
raise ValueError("任务不存在")
|
||||
if not steps_payload:
|
||||
raise ValueError("请至少指定一个步骤的负责人")
|
||||
|
||||
step_rows = {
|
||||
s.id: s
|
||||
for s in db.query(BizProductionTaskStep).filter(
|
||||
BizProductionTaskStep.task_id == task_id,
|
||||
BizProductionTaskStep.tenant_no == tenant_no,
|
||||
BizProductionTaskStep.del_flag == 0,
|
||||
).all()
|
||||
}
|
||||
|
||||
for item in steps_payload:
|
||||
sid = (item.get("step_id") or item.get("stepId") or "").strip()
|
||||
if sid not in step_rows:
|
||||
raise ValueError(f"步骤不存在或不属于该任务: {sid}")
|
||||
user_ids = item.get("assignee_user_ids") or item.get("assigneeUserIds") or []
|
||||
step_assignee_svc.sync_assignees_for_step(
|
||||
db, sid, user_ids,
|
||||
tenant_no=tenant_no,
|
||||
operator_id=operator_id,
|
||||
create_dept_id=create_dept_id,
|
||||
)
|
||||
step = step_rows[sid]
|
||||
pst = item.get("planned_start_time") or item.get("plannedStartTime")
|
||||
if pst is None and "plannedStartTime" in item and item.get("plannedStartTime") is None:
|
||||
step.planned_start_time = None
|
||||
elif pst:
|
||||
from dateutil.parser import parse as _parse_dt
|
||||
step.planned_start_time = _parse_dt(str(pst)) if not isinstance(pst, datetime) else pst
|
||||
step.update_by = operator_id
|
||||
step.update_time = datetime.now()
|
||||
db.add(step)
|
||||
|
||||
db.flush()
|
||||
detail = get_production_task_detail(db, task_id, tenant_no)
|
||||
if not detail:
|
||||
raise ValueError("任务不存在")
|
||||
return detail
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 改造 `list_production_tasks` mine 过滤**
|
||||
|
||||
新增参数 `step_assignee_user_id: Optional[str] = None`。
|
||||
|
||||
在 `current_assignee_user_id` 过滤块 **之后** 增加:
|
||||
|
||||
```python
|
||||
sa_uid = (step_assignee_user_id or "").strip()
|
||||
if sa_uid:
|
||||
step_task_ids = (
|
||||
db.query(BizProductionTaskStep.task_id)
|
||||
.join(
|
||||
BizProductionTaskStepAssignee,
|
||||
BizProductionTaskStepAssignee.step_id == BizProductionTaskStep.id,
|
||||
)
|
||||
.filter(
|
||||
BizProductionTaskStepAssignee.user_id == sa_uid,
|
||||
BizProductionTaskStepAssignee.tenant_no == tenant_no,
|
||||
BizProductionTaskStepAssignee.del_flag == 0,
|
||||
BizProductionTaskStep.del_flag == 0,
|
||||
BizProductionTask.del_flag == 0,
|
||||
)
|
||||
.distinct()
|
||||
.subquery()
|
||||
)
|
||||
q = q.filter(
|
||||
or_(
|
||||
BizProductionTask.id.in_(step_task_ids),
|
||||
BizProductionTask.current_assignee_user_id == sa_uid, # 旧数据 fallback
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 改造 `list_mine_production_tasks`**
|
||||
|
||||
`scope=current` 时调用:
|
||||
|
||||
```python
|
||||
return list_production_tasks(
|
||||
# ...
|
||||
step_assignee_user_id=uid,
|
||||
current_assignee_user_id=None, # 不再仅用 task 级
|
||||
# ...
|
||||
)
|
||||
```
|
||||
|
||||
保留 `current_assignee_user_id=uid` 作为 OR 条件已在 Step 4 合并;或直接只传 `step_assignee_user_id=uid` 并在 SQL 内 OR task assignee fallback。
|
||||
|
||||
- [ ] **Step 6: 新增 assert 函数**
|
||||
|
||||
```python
|
||||
def assert_task_step_assignee_or_legacy(
|
||||
db: Session, task_id: str, user_id: str, tenant_no: str
|
||||
) -> BizProductionTask:
|
||||
from app.crud import production_task_step_assignee as step_assignee_svc
|
||||
|
||||
task = get_production_task_row(db, task_id, tenant_no)
|
||||
if not task:
|
||||
raise ValueError("任务不存在")
|
||||
if step_assignee_svc.user_is_any_step_assignee_of_task(db, task_id, user_id, tenant_no):
|
||||
return task
|
||||
if (task.current_assignee_user_id or "") == (user_id or ""):
|
||||
return task
|
||||
raise PermissionError("非任务步骤负责人,无权操作")
|
||||
|
||||
|
||||
def assert_step_assignee_for_write(
|
||||
db: Session,
|
||||
step_id: str,
|
||||
user_id: str,
|
||||
tenant_no: str,
|
||||
*,
|
||||
manage: bool = False,
|
||||
) -> BizProductionTaskStep:
|
||||
if manage:
|
||||
step = db.query(BizProductionTaskStep).filter(
|
||||
BizProductionTaskStep.id == step_id,
|
||||
BizProductionTaskStep.tenant_no == tenant_no,
|
||||
BizProductionTaskStep.del_flag == 0,
|
||||
).first()
|
||||
if not step:
|
||||
raise ValueError("步骤不存在")
|
||||
return step
|
||||
from app.crud import production_task_step_assignee as step_assignee_svc
|
||||
step = db.query(BizProductionTaskStep).filter(
|
||||
BizProductionTaskStep.id == step_id,
|
||||
BizProductionTaskStep.tenant_no == tenant_no,
|
||||
BizProductionTaskStep.del_flag == 0,
|
||||
).first()
|
||||
if not step:
|
||||
raise ValueError("步骤不存在")
|
||||
if not step_assignee_svc.user_is_step_assignee(db, step_id, user_id, tenant_no):
|
||||
raise PermissionError("非当前步骤负责人,无权操作")
|
||||
return step
|
||||
```
|
||||
|
||||
- [ ] **Step 7: `update_task_step` 写 `completed_by`**
|
||||
|
||||
当 `data.get("step_status") == "ywc"` 且 `user_id` 存在:
|
||||
|
||||
```python
|
||||
step.completed_by = user_id
|
||||
```
|
||||
|
||||
- [ ] **Step 8: `get_production_task_detail` enrich 步骤 assignee**
|
||||
|
||||
加载 steps 后调用:
|
||||
|
||||
```python
|
||||
from app.crud.production_task_step_assignee import enrich_step_assignees
|
||||
enrich_step_assignees(db, steps, tenant_no=tenant_no)
|
||||
# 可选:_enrich_completed_by_names
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 6: API 路由与鉴权
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/api/production.py`
|
||||
|
||||
- [ ] **Step 1: 改造 `_assert_production_task_write_access`**
|
||||
|
||||
```python
|
||||
def _assert_production_task_write_access(
|
||||
db: Session,
|
||||
user: dict,
|
||||
task_id: str,
|
||||
tenant_no: str,
|
||||
operate_scope: Optional[str],
|
||||
) -> None:
|
||||
scope = (operate_scope or "manage").strip().lower()
|
||||
user_id = _get_current_user_id(user)
|
||||
role = user.get("role")
|
||||
codes = get_user_menu_codes(db, user_id) if role != SUPER_ADMIN_ROLE else set()
|
||||
if scope == "mine":
|
||||
if role != SUPER_ADMIN_ROLE and "production:my-task:list" not in codes:
|
||||
raise PermissionError("无菜单访问权限")
|
||||
production_task_svc.assert_task_step_assignee_or_legacy(
|
||||
db, task_id, user_id, tenant_no
|
||||
)
|
||||
elif role != SUPER_ADMIN_ROLE and "production:work-order:list" not in codes:
|
||||
raise PermissionError("无菜单访问权限")
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 新增步骤写鉴权 helper**
|
||||
|
||||
```python
|
||||
def _assert_production_task_step_write_access(
|
||||
db: Session,
|
||||
user: dict,
|
||||
step_id: str,
|
||||
tenant_no: str,
|
||||
operate_scope: Optional[str],
|
||||
) -> None:
|
||||
scope = (operate_scope or "manage").strip().lower()
|
||||
user_id = _get_current_user_id(user)
|
||||
role = user.get("role")
|
||||
codes = get_user_menu_codes(db, user_id) if role != SUPER_ADMIN_ROLE else set()
|
||||
manage = scope != "mine"
|
||||
if not manage:
|
||||
if role != SUPER_ADMIN_ROLE and "production:my-task:list" not in codes:
|
||||
raise PermissionError("无菜单访问权限")
|
||||
elif role != SUPER_ADMIN_ROLE and "production:work-order:list" not in codes:
|
||||
raise PermissionError("无菜单访问权限")
|
||||
production_task_svc.assert_step_assignee_for_write(
|
||||
db, step_id, user_id, tenant_no, manage=manage
|
||||
)
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 注册 `PUT /production-tasks/{task_id}/steps/dispatch`**
|
||||
|
||||
```python
|
||||
@router.put("/production-tasks/{task_id}/steps/dispatch")
|
||||
async def dispatch_production_task_steps_api(
|
||||
task_id: str,
|
||||
body: ProductionTaskStepDispatchBody,
|
||||
user: dict = Depends(require_menu_code("production:work-order:list")),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
payload = [
|
||||
{
|
||||
"step_id": it.step_id,
|
||||
"assignee_user_ids": it.assignee_user_ids,
|
||||
"planned_start_time": it.planned_start_time,
|
||||
}
|
||||
for it in body.steps
|
||||
]
|
||||
detail = production_task_svc.dispatch_task_steps(
|
||||
db,
|
||||
task_id,
|
||||
tenant_no=tenant_no,
|
||||
steps_payload=payload,
|
||||
operator_id=user.get("user_id"),
|
||||
create_dept_id=user.get("dept_id", ""),
|
||||
)
|
||||
db.commit()
|
||||
return success_response(detail, message="步骤派发成功")
|
||||
except ValueError as e:
|
||||
db.rollback()
|
||||
return error_response(400, str(e))
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 步骤写接口增加 step 级鉴权**
|
||||
|
||||
在以下 handler **内** `_assert_production_task_write_access` 之后追加 `_assert_production_task_step_write_access`:
|
||||
|
||||
- `update_production_task_step`
|
||||
- `replace_task_step_reagents`
|
||||
- `replace_task_step_consumables`
|
||||
- `replace_task_step_configured_reagents`
|
||||
- `replace_task_step_data_collections`
|
||||
- `replace_task_step_outputs`
|
||||
- `delete_production_task_step`
|
||||
- `copy_production_task_step`
|
||||
|
||||
示例(`update_production_task_step`):
|
||||
|
||||
```python
|
||||
_assert_production_task_write_access(db, user, task_id, tenant_no, operateScope)
|
||||
_assert_production_task_step_write_access(db, user, step_id, tenant_no, operateScope)
|
||||
```
|
||||
|
||||
任务级 inputs/outputs/attachments/status 仍只用 task 级 assert(D10:任一步 assignee 即可)。
|
||||
|
||||
- [ ] **Step 5: Swagger 手动验证**
|
||||
|
||||
Run backend,在 `/docs` 测试:
|
||||
|
||||
1. `PUT .../steps/dispatch` 返回 steps 含 `assigneeUserIds`
|
||||
2. `GET .../production-tasks/mine?scope=current` 仅 assignee 可见
|
||||
|
||||
---
|
||||
|
||||
## Task 7: Frontend API
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/api/production-task.ts`
|
||||
|
||||
- [ ] **Step 1: 新增 dispatch API**
|
||||
|
||||
```typescript
|
||||
export function fetchDispatchProductionTaskSteps(
|
||||
taskId: string,
|
||||
data: {
|
||||
steps: Array<{
|
||||
stepId: string
|
||||
assigneeUserIds: string[]
|
||||
plannedStartTime?: string | null
|
||||
}>
|
||||
}
|
||||
) {
|
||||
return request.put<any>({
|
||||
url: `/web/admin/production-tasks/${taskId}/steps/dispatch`,
|
||||
data
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 确认 create 不再传 assigneeUserId**
|
||||
|
||||
`DispatchTaskDialog.vue` 将在 Task 9 移除该字段。
|
||||
|
||||
---
|
||||
|
||||
## Task 8: DispatchStepDialog.vue(新建)
|
||||
|
||||
**Files:**
|
||||
- Create: `web-admin/src/views/production/production-work-order/DispatchStepDialog.vue`
|
||||
|
||||
- [ ] **Step 1: 实现弹窗骨架**
|
||||
|
||||
要点:
|
||||
|
||||
- Props: `visible`, `taskId`, `taskName?`
|
||||
- 打开时 `fetchProductionTaskDetail(taskId)` 加载 `steps`
|
||||
- 表格列:序号、`processName`、负责人多选(remote `fetchUserList`)、计划开始时间
|
||||
- 本地 state:`rows: { stepId, processName, assigneeUserIds, plannedStartTime, userOptions }[]`
|
||||
- 提交:过滤 `assigneeUserIds.length >= 1` 的行,调用 `fetchDispatchProductionTaskSteps`
|
||||
- 校验:至少 1 行有负责人
|
||||
- UI:`dialog-form-layout`、`label-position="top"`、footer Close/Check 图标
|
||||
|
||||
- [ ] **Step 2: 回显已有 assignee**
|
||||
|
||||
detail.steps 中若已有 `assigneeUserIds` / `plannedStartTime`,填入表单。
|
||||
|
||||
---
|
||||
|
||||
## Task 9: DispatchTaskDialog.vue 改造
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue`
|
||||
|
||||
- [ ] **Step 1: 移除任务级负责人**
|
||||
|
||||
删除表单项 `assigneeUserId`、`rules.assigneeUserId`、`form.assigneeUserId` 及 create payload 中的 `assigneeUserId`。
|
||||
|
||||
- [ ] **Step 2: B 入口 — 创建后打开步骤派发**
|
||||
|
||||
在 `handleCreateTask` 成功、`enterEditPhase` 之后:
|
||||
|
||||
```typescript
|
||||
emit('open-step-dispatch', { taskId, taskName: form.taskName })
|
||||
```
|
||||
|
||||
或由父组件监听 `@success` 并根据是否选了 `routeId` 打开 `DispatchStepDialog`。
|
||||
|
||||
推荐:Dialog 内 `emit('needStepDispatch', taskId)`,父组件 `WorkOrderTaskSubList` / `index.vue` 统一挂载 `DispatchStepDialog`。
|
||||
|
||||
- [ ] **Step 3: 若选了 route 且步骤已克隆**
|
||||
|
||||
创建成功 + `expectSteps` 为 true 时,关闭编辑阶段或保留编辑的同时弹出步骤派发(产品:B 入口)。
|
||||
|
||||
---
|
||||
|
||||
## Task 10: WorkOrderTaskSubList.vue 改造
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue`
|
||||
|
||||
- [ ] **Step 1: 挂载 DispatchStepDialog**
|
||||
|
||||
```vue
|
||||
<DispatchStepDialog
|
||||
v-model:visible="stepDispatchVisible"
|
||||
:task-id="stepDispatchTaskId"
|
||||
:task-name="stepDispatchTaskName"
|
||||
@success="handleTaskMutationSuccess"
|
||||
/>
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 管理视角增加「步骤派发」按钮**
|
||||
|
||||
在 `!isMineMode` 且任务非 `yzf` 时显示;文案:无 assignee 时「步骤派发」,否则「调整派发」。
|
||||
|
||||
判断:任一步 `assigneeUserIds?.length` 或后端返回 `hasStepDispatch`。
|
||||
|
||||
- [ ] **Step 3: 隐藏 deprecated 转发/改派**
|
||||
|
||||
删除或 `v-if="false"`:
|
||||
|
||||
- 下拉「转发任务」「改派负责人」
|
||||
- `ForwardTaskDialog` 引用可保留文件但不挂载
|
||||
|
||||
- [ ] **Step 4: 任务卡片 meta 展示步骤负责人摘要**
|
||||
|
||||
在任务名下方增加 muted 文本,例如:`步骤负责人:张三、李四(细胞培养 09:00)` — 取前 2 步或折叠展示。
|
||||
|
||||
---
|
||||
|
||||
## Task 11: 执行弹窗 — 步骤权限与只读
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/views/production/production-work-order/useTaskStepEditor.ts`
|
||||
- Modify: `web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue`
|
||||
- Modify: `web-admin/src/views/production/production-work-order/StepDetailPanel.vue`
|
||||
|
||||
- [ ] **Step 1: useTaskStepEditor 增加 canEditStep**
|
||||
|
||||
```typescript
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
function canEditStep(step: Record<string, any> | null | undefined): boolean {
|
||||
if (!step) return false
|
||||
if (operateScope.value !== 'mine') return true
|
||||
const uid = userStore.info?.id || userStore.userId || ''
|
||||
const ids: string[] = step.assigneeUserIds || []
|
||||
return ids.includes(uid)
|
||||
}
|
||||
|
||||
function visibleStepsForMine(steps: Record<string, any>[]) {
|
||||
if (operateScope.value !== 'mine') return steps
|
||||
return steps.filter((s) => (s.assigneeUserIds || []).length > 0)
|
||||
}
|
||||
```
|
||||
|
||||
导出 `canEditStep`、`visibleStepsForMine`(或 computed `displayStepList`)。
|
||||
|
||||
- [ ] **Step 2: TaskExecutionDialog 步骤列表**
|
||||
|
||||
- mine:`v-for="element in editor.displayStepList"`(仅已派步骤)
|
||||
- 对 `!canEditStep(element)` 的步骤加 class `is-readonly`(降低 opacity,禁用 drag)
|
||||
- 任务级「转发任务」按钮移除
|
||||
|
||||
- [ ] **Step 3: StepDetailPanel 按钮**
|
||||
|
||||
```vue
|
||||
<el-button
|
||||
v-if="editor.mode.value === 'execution' && editor.canEditStep(editor.selectedStep.value)"
|
||||
...
|
||||
/>
|
||||
```
|
||||
|
||||
保存 / 开始 / 完成均加 `canEditStep` 条件;只读时仅展示内容。
|
||||
|
||||
- [ ] **Step 4: 步骤写操作前端 guard(可选双保险)**
|
||||
|
||||
`handleStartStep` / `handleCompleteStep` 开头:
|
||||
|
||||
```typescript
|
||||
if (!canEditStep(step)) {
|
||||
ElMessage.warning('非当前步骤负责人,无法操作')
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 12: 字段一致性与图谱
|
||||
|
||||
**Files:**
|
||||
- Run: `backend/scripts/check_field_consistency.py`(若涉及 CRUD 字段变更)
|
||||
- Run: `./scripts/update-graph.sh backend frontend`
|
||||
|
||||
- [ ] **Step 1: 字段一致性检查**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd backend && source venv/bin/activate
|
||||
python scripts/check_field_consistency.py
|
||||
```
|
||||
|
||||
Expected: 无 production_task step 相关新增不一致;若有 `_row_to_dict` 变更则修复 schema/前端。
|
||||
|
||||
- [ ] **Step 2: 更新知识图谱**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
./scripts/update-graph.sh backend
|
||||
./scripts/update-graph.sh frontend
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 13: 手工测试清单
|
||||
|
||||
- [ ] **B 入口**:生产工单 → 派发任务 → 选工艺路线 → 创建 → 步骤派发 → 用户 A/B 在「我的生产任务」见工单,执行时仅各自步骤可操作,其他只读。
|
||||
|
||||
- [ ] **A 入口**:无路线创建 → 手工加 3 步 → 步骤派发 → 同上。
|
||||
|
||||
- [ ] **一步多人**:A、B 同为步骤 1 负责人;A 完成步骤 1 后 B 见只读已完成。
|
||||
|
||||
- [ ] **同人多步**:步骤 1、2 均派给 A;A 两步均可操作。
|
||||
|
||||
- [ ] **计划开始时间**:卡片/派发弹窗展示;未到时间仍可执行。
|
||||
|
||||
- [ ] **未派步骤**:mine 执行弹窗不显示该步;manage 可见可操作。
|
||||
|
||||
- [ ] **改派**:manage 调整派发后,旧 assignee mine 列表消失(若无其他步骤),新 assignee 出现。
|
||||
|
||||
- [ ] **旧数据 backfill**(若执行 backfill SQL):原 task assignee 仍能在 mine 看到任务。
|
||||
|
||||
- [ ] **回归**:任务输入/产出/完成整单、派发质检工单链路不受影响。
|
||||
|
||||
---
|
||||
|
||||
## Spec Coverage Self-Review
|
||||
|
||||
| Spec 要求 | 对应 Task |
|
||||
|-----------|-----------|
|
||||
| D1 工单+任务列表 | Task 5 mine 过滤不变外层结构 |
|
||||
| D2 其他步骤只读 | Task 11 |
|
||||
| D3 一步多人任一完成 | Task 5 Step 7 completed_by |
|
||||
| D4 计划开始时间不阻断 | Task 8/11 无前端时间校验 |
|
||||
| D5 A+B 双入口 | Task 8/9/10 |
|
||||
| D6 未派步骤仅 manage | Task 11 visibleStepsForMine |
|
||||
| D7 方案 1 数据模型 | Task 1–4 |
|
||||
| D8 任务 assignee 非必填 | Task 3/5 |
|
||||
| D9 转发 deprecated | Task 10 |
|
||||
| D10 任务 I/O 任一步 assignee | Task 6 task 级 assert |
|
||||
| D11 mine 不可改派 | Task 6 dispatch 仅 work-order 权限 |
|
||||
|
||||
无 TBD 占位;类型命名 `assigneeUserIds` / `plannedStartTime` 前后端一致。
|
||||
|
||||
---
|
||||
|
||||
## 建议实施顺序
|
||||
|
||||
```
|
||||
Task 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10 → 11 → 12 → 13
|
||||
└─ backend 可联调 ─┘ └─ frontend ─────────────┘
|
||||
```
|
||||
|
||||
Backend Task 1–6 完成后即可用 Swagger 验证 mine 过滤与 dispatch;Frontend Task 7–11 依赖后端 API。
|
||||
@@ -0,0 +1,86 @@
|
||||
# 编辑生产任务 · 步骤详情内派发字段 — 设计
|
||||
|
||||
> 日期: 2026-06-25
|
||||
> 状态: **已评审,可实施**
|
||||
> 依赖: `2026-06-25-production-step-dispatch-design.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景
|
||||
|
||||
【编辑生产任务】(`DispatchTaskDialog` 阶段二)使用三栏编辑器 + `StepDetailPanel`。步骤负责人与计划开始时间仅能通过独立弹窗 `DispatchStepDialog` 配置,步骤详情无展示与编辑入口,导致:
|
||||
|
||||
- 已派发数据在 API 中存在,右侧详情不可见;
|
||||
- 工艺库新增步骤无法设置负责人与时间;
|
||||
- 改派需切换弹窗,体验割裂。
|
||||
|
||||
## 2. 决策
|
||||
|
||||
| 项 | 决策 |
|
||||
|----|------|
|
||||
| 方案 | **A**:在 `StepDetailPanel` 增加负责人 + 计划开始时间 |
|
||||
| 关闭校验 | **宽松**:关闭编辑弹窗时不强制每步均有负责人 |
|
||||
| 保存策略 | **A1**:并入步骤「保存」按钮(`handleManualSave`) |
|
||||
| 批量改派 | 保留 `DispatchStepDialog` 作批量入口 |
|
||||
|
||||
## 3. UI
|
||||
|
||||
### 3.1 展示条件
|
||||
|
||||
- `canEditStepDispatch()` 且 `!readonly`:可编辑控件(编辑工艺 / 任务执行,manage 与 mine 均可)
|
||||
- 只读「任务详情」:展示文本 Tag / 时间,不可改
|
||||
|
||||
### 3.2 任务执行弹窗
|
||||
|
||||
- manage 与 **mine** 均在步骤详情可配置负责人与时间(保存时调 `steps/dispatch`,带 `operateScope`)
|
||||
- mine 对未派发的新步骤:任务内任一步负责人可配置并保存
|
||||
|
||||
### 3.3 控件(对齐 `DispatchStepDialog`)
|
||||
|
||||
| 字段 | 控件 |
|
||||
|------|------|
|
||||
| 负责人 | `el-select` multiple + remote 用户搜索,`nickName(userNo)` |
|
||||
| 计划开始时间 | `el-date-picker` datetime,`value-format="YYYY-MM-DDTHH:mm:00"`,可清空 |
|
||||
|
||||
置于步骤详情 `form-grid-4` 内(与工序名称等同区),label `label-position="top"`。
|
||||
|
||||
### 3.4 提示
|
||||
|
||||
- 无负责人时:字段下 muted 提示「未派发;保存工艺后可在本处或「步骤派发」中指定负责人」
|
||||
|
||||
## 4. 数据与保存
|
||||
|
||||
### 4.1 加载
|
||||
|
||||
- 任务详情 steps 已含 `assigneeUserIds`、`assignees`、`plannedStartTime`
|
||||
- `normalizeStepSubTables` 补全 `assigneeUserIds`(来自 `assignees`),并记录快照 `_snapshotAssigneeUserIds`、`_snapshotPlannedStartTime` 用于脏检测
|
||||
|
||||
### 4.2 保存
|
||||
|
||||
- `handleManualSave` 在 `saveStepBasic` 等之后调用 `saveStepDispatch()`
|
||||
- 仅当 `stepDispatchChanged(step)` 时调用 `PUT steps/dispatch`(单步 payload)
|
||||
- 允许 `assigneeUserIds` 为空(清空负责人);`plannedStartTime` 传 `null` 表示清空
|
||||
- 成功后更新快照,避免重复提交
|
||||
|
||||
### 4.3 关闭弹窗
|
||||
|
||||
- **不校验**全步骤是否已派发;未派步骤仍仅 manage 可见(沿用步骤派发设计 §1.2)
|
||||
|
||||
## 5. 文件
|
||||
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `StepDetailPanel.vue` | 负责人、计划开始时间表单项 |
|
||||
| `useTaskStepEditor.ts` | 用户搜索、`saveStepDispatch`、快照脏检测、并入 `handleManualSave` |
|
||||
| `DispatchTaskDialog.vue` | 打开编辑时预加载用户列表(可选) |
|
||||
|
||||
## 6. 测试要点
|
||||
|
||||
1. 编辑工艺:已派发步骤在详情可见负责人与时间。
|
||||
2. 修改负责人/时间后点「保存」,mine 列表与步骤派发弹窗数据一致。
|
||||
3. 工艺库新增步骤:选中后可在详情设置并保存。
|
||||
4. 清空负责人或计划时间后保存,DB 与再次打开一致。
|
||||
5. 仅改工序名称未改派发字段时,保存不触发 dispatch API。
|
||||
6. 关闭编辑弹窗:部分步骤未派发仍可关闭。
|
||||
7. 工单页 · 任务执行(manage):工艺库新增步骤可在详情设负责人/时间并保存。
|
||||
8. 我的生产任务 · 执行(mine):可编辑负责人/时间并保存(需为任务步骤负责人;未派发新步可由任务内负责人配置)。
|
||||
@@ -0,0 +1,324 @@
|
||||
# 生产任务 · 工艺步骤级派发 — 需求分析与设计
|
||||
|
||||
> 日期: 2026-06-25
|
||||
> 状态: **已评审,可实施**
|
||||
> 范围: web-admin + backend(生产工单派发、任务执行、我的生产任务)
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
### 1.1 现状
|
||||
|
||||
| 项 | 现状 |
|
||||
|----|------|
|
||||
| 派发粒度 | `DispatchTaskDialog.vue` 创建 **整条生产任务** 时指定 **单一任务负责人**(`biz_production_task.current_assignee_user_id`) |
|
||||
| 步骤模型 | `biz_production_task_step` 有工序与执行状态(`dzx/jxz/ywc`),**无负责人、无计划开始时间** |
|
||||
| 我的生产任务 | 按 `current_assignee_user_id = 当前用户` 过滤任务 |
|
||||
| 任务执行 | `TaskExecutionDialog.vue`:当前负责人对 **全部步骤** 可操作 |
|
||||
| 类似实现 | 质检任务 **`biz_qc_task_assignee`**:每检测项多人负责,**任一可完成** |
|
||||
|
||||
### 1.2 客户需求(原文摘要)
|
||||
|
||||
1. **派发按工艺步骤**,而非整条生产任务整体派发。
|
||||
2. **列表仍按工单 + 生产任务展示**;展开/进入执行后,**仅派给自己的步骤可操作**,其他步骤 **只读可见**。
|
||||
3. 一个工艺步骤可 **同时派给多人**;**任一负责人** 可开始/完成该步骤。
|
||||
4. 每个步骤派发时可设置 **计划开始时间**(展示/排序,**不限制**提前执行)。
|
||||
5. 同一生产任务内,**多个步骤可派给同一人**。
|
||||
6. 支持 **创建时一并派发(B)** 与 **工艺配置后单独派发(A)** 两种入口。
|
||||
7. 已派给 A 的步骤,**可改派** 给其他人(更新负责人列表)。
|
||||
8. **未指定负责人的步骤**:仅管理员在 **生产工单页** 可见可操作;**不出现在** 任何人的「我的生产任务」。
|
||||
|
||||
---
|
||||
|
||||
## 2. 产品决策
|
||||
|
||||
| # | 问题 | 决策 | 状态 |
|
||||
|---|------|------|------|
|
||||
| D1 | 「我的生产任务」列表粒度? | **工单 + 任务卡片**(非步骤级平铺列表) | ✅ |
|
||||
| D2 | 未派给自己的步骤如何展示? | **只读可见**(可见完整工艺链路与状态,不可操作) | ✅ |
|
||||
| D3 | 一步多人时的完成语义? | **任一负责人可独立完成**(与质检任务一致;`completed_by` 记实际操作人) | ✅ |
|
||||
| D4 | 计划开始时间含义? | **仅展示/排序**,不阻断执行 | ✅ |
|
||||
| D5 | 派发入口? | **A + B 均支持**,共用同一套步骤派发能力 | ✅ |
|
||||
| D6 | 未派步骤可见性? | **仅管理员**(工单页 `operateScope=manage`);mine 不可见 | ✅ |
|
||||
| D7 | 数据模型方案? | **方案 1**:`biz_production_task_step_assignee` + 步骤 `planned_start_time` | ✅ |
|
||||
| D8 | 任务级负责人字段? | 创建时 **不再必填**;「我的生产任务」改按 **步骤负责人** 过滤 | ✅ |
|
||||
| D9 | 任务级「转发」? | **保留代码但标记 deprecated**;协作改由 **步骤改派** 完成 | ✅ |
|
||||
| D10 | 原材料/产出/纸质文档? | **任一步骤负责人** 在 mine 视角均可编辑(与步骤协作一致) | ✅ |
|
||||
| D11 | mine 端能否自行改派? | **否**;改派仅 **工单管理页**(`operateScope=manage`) | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## 3. 业务流程(目标态)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 生产工单 · 派发生产任务 │
|
||||
│ 阶段一:任务名称、工艺路线(可选)、描述 — 【移除任务级负责人】 │
|
||||
│ 阶段二:编辑工艺步骤(现有三栏编辑器) │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│ 若选了工艺路线(B) │ 未选路线 / 后补步骤(A)
|
||||
▼ ▼
|
||||
┌────────────────────────────┐ ┌────────────────────────────┐
|
||||
│ 创建后立即打开「步骤派发」 │ │ 任务卡片 · 「步骤派发」 │
|
||||
│ 每步:多人 + 计划开始时间 │ │ 同上 │
|
||||
└────────────────────────────┘ └────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 我的生产任务 · 工单 + 任务卡片 │
|
||||
│ 过滤:当前用户是 ≥1 个步骤的负责人 │
|
||||
│ 展开 → 进入执行:自己的步骤可操作;其他步骤只读;未派步骤 mine 不可见 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
管理员工单页 · 步骤改派
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ sync 步骤负责人列表 + 更新 planned_start_time │
|
||||
│ dzx/jxz:改派后新负责人可操作;ywc:仅影响可见性,不 reopen 步骤 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 数据模型
|
||||
|
||||
### 4.1 新增 / 变更
|
||||
|
||||
**步骤表扩展** `biz_production_task_step`:
|
||||
|
||||
```sql
|
||||
ALTER TABLE biz_production_task_step
|
||||
ADD COLUMN planned_start_time datetime DEFAULT NULL COMMENT '计划开始时间' AFTER step_status;
|
||||
|
||||
ALTER TABLE biz_production_task_step
|
||||
ADD COLUMN completed_by varchar(64) DEFAULT NULL COMMENT '完成步骤的用户ID' AFTER completed_time;
|
||||
```
|
||||
|
||||
**步骤负责人关联表** `biz_production_task_step_assignee`(对齐 `biz_qc_task_assignee`):
|
||||
|
||||
```sql
|
||||
CREATE TABLE biz_production_task_step_assignee (
|
||||
id varchar(64) NOT NULL COMMENT '主键',
|
||||
step_id varchar(64) NOT NULL COMMENT '生产任务步骤ID',
|
||||
user_id varchar(64) NOT NULL COMMENT '负责人用户ID',
|
||||
tenant_no varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
|
||||
order_num int DEFAULT 0 COMMENT '展示顺序',
|
||||
remark varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
create_by varchar(64) DEFAULT NULL COMMENT '创建人id',
|
||||
create_dept_id varchar(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
|
||||
create_time datetime NOT NULL COMMENT '创建时间',
|
||||
update_by varchar(64) DEFAULT NULL COMMENT '更新人id',
|
||||
update_time datetime NOT NULL COMMENT '更新时间',
|
||||
del_flag tinyint NOT NULL DEFAULT 0 COMMENT '删除标记',
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_step_assignee_step (step_id),
|
||||
KEY idx_step_assignee_user (user_id, tenant_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生产任务步骤负责人';
|
||||
```
|
||||
|
||||
### 4.2 任务级字段(兼容)
|
||||
|
||||
| 字段 | 处理 |
|
||||
|------|------|
|
||||
| `biz_production_task.current_assignee_user_id` | **保留列**;新创建任务可为 NULL;API 创建 body **移除 assigneeUserId 必填** |
|
||||
| `biz_production_task_handover` | **保留**;UI 不再主推「任务转发」,文档标注 deprecated |
|
||||
|
||||
### 4.3 历史数据迁移(可选脚本)
|
||||
|
||||
- 若旧任务 `current_assignee_user_id` 非空且无步骤负责人:可将该用户写入 **全部现有步骤** 的 assignee(一次性迁移),保证旧任务仍在「我的生产任务」可见。
|
||||
- 无 assignee 且无步骤负责人的旧任务:行为与「未派步骤」一致,仅 manage 可见。
|
||||
|
||||
---
|
||||
|
||||
## 5. API 设计
|
||||
|
||||
### 5.1 步骤派发(批量)
|
||||
|
||||
```
|
||||
PUT /api/web/admin/production-tasks/{taskId}/steps/dispatch
|
||||
```
|
||||
|
||||
**Body**(camelCase 与现有约定一致):
|
||||
|
||||
```json
|
||||
{
|
||||
"steps": [
|
||||
{
|
||||
"stepId": "uuid",
|
||||
"assigneeUserIds": ["u1", "u2"],
|
||||
"plannedStartTime": "2026-06-25T09:00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**规则:**
|
||||
|
||||
- 至少 **1 个 step** 在请求中且 `assigneeUserIds.length >= 1`(允许部分步骤暂不派)。
|
||||
- 未出现在请求中的步骤:**不修改** 其负责人与时间。
|
||||
- 出现的步骤:**全量 sync** 负责人(软删旧 + 插入新,复用 `qc_task_assignee.sync_assignees` 模式)。
|
||||
- `plannedStartTime` 可选;传 null 表示清空。
|
||||
- 权限:`production:work-order:list`(manage);mine 端 **403**。
|
||||
|
||||
**响应:** 任务详情(含 steps、assignees、plannedStartTime、assigneeNames)。
|
||||
|
||||
### 5.2 创建生产任务
|
||||
|
||||
```
|
||||
POST /api/web/admin/production-tasks
|
||||
```
|
||||
|
||||
- **移除** `assigneeUserId` 必填校验。
|
||||
- 可选扩展:同 body 内嵌 `stepDispatch` 数组(B 入口一次提交);或创建成功后前端再调 §5.1。
|
||||
|
||||
### 5.3 我的生产任务列表
|
||||
|
||||
```
|
||||
GET /api/web/admin/production-tasks/mine
|
||||
```
|
||||
|
||||
**过滤逻辑变更:**
|
||||
|
||||
- **current**:存在 `biz_production_task_step_assignee.user_id = 当前用户` 且 `del_flag=0` 的 **至少一个步骤** 的任务。
|
||||
- **history**(若保留):曾出现在步骤 assignee 但当前已不在任一步 assignee 列表的任务(可选首版简化:与 current 合并或暂不实现 history 变更)。
|
||||
|
||||
> 首版:**替换** 原 `current_assignee_user_id = 我` 为主过滤条件;history 沿用 handover 逻辑仅作兼容,不作为步骤协作主路径。
|
||||
|
||||
### 5.4 步骤写操作鉴权
|
||||
|
||||
| 操作 | mine | manage |
|
||||
|------|------|--------|
|
||||
| 开始/完成/保存 **已派给自己** 的步骤 | ✅ | ✅ |
|
||||
| 操作 **未派给自己** 的步骤 | ❌ 只读 | ✅ |
|
||||
| 操作 **未派任何人** 的步骤 | ❌ 不可见 | ✅ |
|
||||
| 编辑任务输入/产出/附件 | ✅ 若本人是任一步 assignee | ✅ |
|
||||
| 步骤派发/改派 | ❌ | ✅ |
|
||||
|
||||
实现:在 `production_task` CRUD 增加 `assert_step_assignee(step_id, user_id)`;manage 路径跳过。
|
||||
|
||||
### 5.5 任务详情 / 列表 enrichment
|
||||
|
||||
- `_task_to_dict` / 步骤 `_step_to_dict` 增加:
|
||||
- `assigneeUserIds: string[]`
|
||||
- `assigneeNames: string[]`(或 `assignees: {userId, nickName, userNo}[]`)
|
||||
- `plannedStartTime`
|
||||
- `completedBy` / `completedByName`
|
||||
- 列表接口批量 `_enrich_step_assignees`(对齐 QC `_enrich_assignee_names`)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 前端设计
|
||||
|
||||
### 6.1 新增组件
|
||||
|
||||
| 组件 | 职责 |
|
||||
|------|------|
|
||||
| `DispatchStepDialog.vue` | 步骤派发表格:工序名、负责人多选、计划开始时间;提交 §5.1 |
|
||||
|
||||
### 6.2 改造组件
|
||||
|
||||
| 组件 | 变更 |
|
||||
|------|------|
|
||||
| `DispatchTaskDialog.vue` | **移除** 任务级「负责人」表单项与校验;选工艺路线且创建成功后 **可选打开** `DispatchStepDialog`(B) |
|
||||
| `WorkOrderTaskSubList.vue` | 管理视角:任务卡片 meta 展示各步负责人 Tag + 计划开始时间;按钮「步骤派发 / 调整派发」 |
|
||||
| `TaskExecutionDialog.vue` | mine:`canEditStep(step)` = 当前用户在 step.assigneeUserIds;否则只读;未派步骤不渲染或 manage 才显示 |
|
||||
| `StepDetailPanel.vue` | 禁用开始/完成/保存按钮当 `!canEditStep` |
|
||||
| `useTaskStepEditor.ts` | 传入 `operateScope`;步骤操作前校验 assignee |
|
||||
| `production-task.ts` | 新增 `fetchDispatchProductionTaskSteps`;创建 body 去掉 assigneeUserId |
|
||||
| `production-mine-task-groups.ts` | mine 列表依赖后端新过滤(前端无需按 task assignee 过滤) |
|
||||
|
||||
### 6.3 步骤派发表格 UI
|
||||
|
||||
| 列 | 控件 |
|
||||
|----|------|
|
||||
| 序号 / 工序名称 | 只读 |
|
||||
| 负责人 | `el-select multiple filterable remote`,展示 `nickName(userNo)`,≥1 |
|
||||
| 计划开始时间 | `el-date-picker type="datetime"`,可选 |
|
||||
|
||||
- 弹窗:`dialog-form-layout`,`label-position="top"`。
|
||||
- 底栏:取消 / 确定(Close / Check 图标)。
|
||||
|
||||
### 6.4 执行弹窗 · 步骤列表视觉
|
||||
|
||||
- **可操作步骤**:现有高亮样式(`is-active`)。
|
||||
- **只读步骤**:降低 opacity 或 `readonly` class;隐藏开始/完成/保存;保留状态 Tag。
|
||||
- **未派步骤(mine)**:不展示(manage 正常展示并可操作)。
|
||||
|
||||
### 6.5 Deprecated UI
|
||||
|
||||
- 任务级「转发」「改派」按钮:管理页 **隐藏或替换** 为「步骤派发」;API 保留不删。
|
||||
|
||||
---
|
||||
|
||||
## 7. 改派规则
|
||||
|
||||
| 步骤状态 | 改负责人 | 改计划开始时间 | 步骤是否 reopen |
|
||||
|----------|----------|----------------|-----------------|
|
||||
| `dzx` | ✅ | ✅ | — |
|
||||
| `jxz` | ✅ | ✅ | 否,新负责人接手进行中步骤 |
|
||||
| `ywc` | ✅(仅影响 mine 可见性) | ✅ | **否** |
|
||||
|
||||
---
|
||||
|
||||
## 8. 任务 / 工单状态联动
|
||||
|
||||
- **任务状态**(`dpz/jxz/ywc`)逻辑 **不变**:仍由步骤聚合 + 现有 `sync_production_work_order_status_from_tasks` 驱动。
|
||||
- **未派步骤** 不参与 mine 过滤;manage 仍可执行未派步骤(管理员兜底)。
|
||||
|
||||
---
|
||||
|
||||
## 9. 权限与菜单
|
||||
|
||||
| 能力 | menuCode |
|
||||
|------|----------|
|
||||
| 生产工单(manage、步骤派发) | `production:work-order:list` |
|
||||
| 我的生产任务 | `production:my-task:list` |
|
||||
|
||||
无需新增菜单;步骤派发挂在工单页任务操作区。
|
||||
|
||||
---
|
||||
|
||||
## 10. 测试要点
|
||||
|
||||
1. B 入口:选路线 → 创建 → 步骤派发 → 各 assignee 在 mine 见任务,仅自己步骤可操作。
|
||||
2. A 入口:无路线创建 → 手工加步骤 → 步骤派发 → 同上。
|
||||
3. 一步多人:A、B 均可见任务;A 完成后 B 见只读已完成。
|
||||
4. 同人多步:mine 展开见多个可操作步骤。
|
||||
5. 计划开始时间:列表/卡片展示;未到时间仍可执行。
|
||||
6. 未派步骤:mine 不可见;manage 可见可操作。
|
||||
7. 改派:`dzx/jxz/ywc` 按 §7;mine 不可改派。
|
||||
8. 旧任务兼容(若跑迁移脚本):原 task assignee 仍可见。
|
||||
|
||||
---
|
||||
|
||||
## 11. 文件清单(实施参考)
|
||||
|
||||
| 层 | 文件 |
|
||||
|----|------|
|
||||
| SQL | `docs/sql/migrations/2026-06-25-production-step-dispatch.sql`,同步 `docs/sql/zkxw.sql` |
|
||||
| Backend Model | `backend/app/models/models.py` — `BizProductionTaskStepAssignee` + 步骤新字段 |
|
||||
| Backend CRUD | `backend/app/crud/production_task_step_assignee.py`(新建,对齐 qc_task_assignee) |
|
||||
| Backend CRUD | `backend/app/crud/production_task.py` — mine 过滤、step assert、complete 写 completed_by |
|
||||
| Backend Schema | `backend/app/schemas/production_task.py` — DispatchStepsBody |
|
||||
| Backend API | `backend/app/api/production.py` — PUT steps/dispatch;调整 create/mine |
|
||||
| Frontend API | `web-admin/src/api/production-task.ts` |
|
||||
| Frontend | `DispatchStepDialog.vue`(新建) |
|
||||
| Frontend | `DispatchTaskDialog.vue`, `WorkOrderTaskSubList.vue`, `TaskExecutionDialog.vue`, `StepDetailPanel.vue`, `useTaskStepEditor.ts` |
|
||||
|
||||
---
|
||||
|
||||
## 12. 与 OpenSpec / 既有 spec 关系
|
||||
|
||||
- supersede 部分:`2026-06-13-production-task-assignee-my-tasks-design.md` 中 **任务级单一负责人 + 任务转发** 产品路径;本 spec 以 **步骤级多人 + 步骤改派** 为准。
|
||||
- 对齐 `api-conventions`:租户隔离、软删除、`operateScope=mine|manage`。
|
||||
- 对齐 `ui-conventions`:Fresh Mint 弹窗、按钮图标、Tag 展示负责人。
|
||||
|
||||
---
|
||||
|
||||
## 13. 版本记录
|
||||
|
||||
| 日期 | 说明 |
|
||||
|------|------|
|
||||
| 2026-06-25 | 初稿:步骤级派发方案 1,产品决策 D1–D11 已确认 |
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,11 +1,11 @@
|
||||
# Graph Report - src (2026-06-24)
|
||||
# Graph Report - src (2026-06-25)
|
||||
|
||||
## Corpus Check
|
||||
- Large corpus: 791 files · ~527,792 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
|
||||
- Large corpus: 792 files · ~529,390 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
|
||||
|
||||
## Summary
|
||||
- 2609 nodes · 3608 edges · 57 communities detected
|
||||
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 782 edges (avg confidence: 0.8)
|
||||
- 2624 nodes · 3636 edges · 53 communities detected
|
||||
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 785 edges (avg confidence: 0.8)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
@@ -50,22 +50,18 @@
|
||||
- [[_COMMUNITY_Community 39|Community 39]]
|
||||
- [[_COMMUNITY_Community 40|Community 40]]
|
||||
- [[_COMMUNITY_Community 41|Community 41]]
|
||||
- [[_COMMUNITY_Community 42|Community 42]]
|
||||
- [[_COMMUNITY_Community 44|Community 44]]
|
||||
- [[_COMMUNITY_Community 45|Community 45]]
|
||||
- [[_COMMUNITY_Community 46|Community 46]]
|
||||
- [[_COMMUNITY_Community 48|Community 48]]
|
||||
- [[_COMMUNITY_Community 49|Community 49]]
|
||||
- [[_COMMUNITY_Community 50|Community 50]]
|
||||
- [[_COMMUNITY_Community 51|Community 51]]
|
||||
- [[_COMMUNITY_Community 52|Community 52]]
|
||||
- [[_COMMUNITY_Community 53|Community 53]]
|
||||
- [[_COMMUNITY_Community 54|Community 54]]
|
||||
- [[_COMMUNITY_Community 55|Community 55]]
|
||||
- [[_COMMUNITY_Community 56|Community 56]]
|
||||
- [[_COMMUNITY_Community 57|Community 57]]
|
||||
- [[_COMMUNITY_Community 60|Community 60]]
|
||||
- [[_COMMUNITY_Community 61|Community 61]]
|
||||
- [[_COMMUNITY_Community 62|Community 62]]
|
||||
- [[_COMMUNITY_Community 67|Community 67]]
|
||||
- [[_COMMUNITY_Community 69|Community 69]]
|
||||
- [[_COMMUNITY_Community 58|Community 58]]
|
||||
- [[_COMMUNITY_Community 63|Community 63]]
|
||||
- [[_COMMUNITY_Community 65|Community 65]]
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `get()` - 268 edges
|
||||
@@ -76,8 +72,8 @@
|
||||
6. `handleDynamicRoutes()` - 16 edges
|
||||
7. `withFullscreenLoading()` - 15 edges
|
||||
8. `VersionManager` - 15 edges
|
||||
9. `set()` - 15 edges
|
||||
10. `TableCache` - 14 edges
|
||||
9. `scopeQuery()` - 15 edges
|
||||
10. `set()` - 15 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `buildInboundMetaFields()` --calls--> `push()` [INFERRED]
|
||||
@@ -95,15 +91,15 @@
|
||||
|
||||
### Community 0 - "Community 0"
|
||||
Cohesion: 0.01
|
||||
Nodes (142): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchChannelAccount(), fetchChannelAgreementPrices(), fetchChannelAgreements() (+134 more)
|
||||
Nodes (134): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchChannelAccount(), fetchChannelAgreementPrices(), fetchChannelAgreements() (+126 more)
|
||||
|
||||
### Community 1 - "Community 1"
|
||||
Cohesion: 0.02
|
||||
Nodes (42): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllConsumableStockLogs(), fetchAllEquipments(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents() (+34 more)
|
||||
Cohesion: 0.03
|
||||
Nodes (70): fetchCellSampleTypeList(), fetchCheckupInstitutionInvoices(), fetchCheckupInstitutionList(), fetchCheckupInstitutionProjects(), fetchCreateCellSampleType(), fetchCreateCheckupInstitution(), fetchCreateCheckupInstitutionInvoice(), fetchCreateCheckupInstitutionProject() (+62 more)
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.03
|
||||
Nodes (76): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchPilotCheckupDetail(), markPilotCheckupChecked(), savePilotCheckup(), savePilotCheckupActualItems() (+68 more)
|
||||
Cohesion: 0.02
|
||||
Nodes (42): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllConsumableStockLogs(), fetchAllEquipments(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents() (+34 more)
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.03
|
||||
@@ -114,28 +110,28 @@ Cohesion: 0.03
|
||||
Nodes (44): handleBlur(), handleFocus(), handleInput(), formatAmount(), formatAmount(), formatProtocolAmount(), fmtMoney(), buildBaseFields() (+36 more)
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.03
|
||||
Nodes (52): fetchCheckupInstitutionInvoices(), fetchCheckupInstitutionList(), fetchCheckupInstitutionProjects(), fetchCreateCheckupInstitution(), fetchCreateCheckupInstitutionInvoice(), fetchCreateCheckupInstitutionProject(), fetchUpdateCheckupInstitution(), fetchUpdateCheckupInstitutionInvoice() (+44 more)
|
||||
Cohesion: 0.04
|
||||
Nodes (72): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchPilotCheckupDetail(), markPilotCheckupChecked(), savePilotCheckup(), savePilotCheckupActualItems() (+64 more)
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.04
|
||||
Nodes (61): fetchUploadAttachment(), reload(), handleReportUpload(), handleReportUpload(), walk(), handleMenuJump(), openExternalLink(), async() (+53 more)
|
||||
Nodes (53): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), updateInfusionScheduleStatus(), fetchProductionTaskList(), handleAdd(), handleDelete() (+45 more)
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.04
|
||||
Nodes (51): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), updateInfusionScheduleStatus(), fetchProductionTaskList(), handleDelete(), handleDropdownCommand() (+43 more)
|
||||
Cohesion: 0.05
|
||||
Nodes (57): fetchUploadAttachment(), FireworkSystem, handleReportUpload(), handleReportUpload(), walk(), async(), handleAttachmentChange(), push() (+49 more)
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.04
|
||||
Nodes (41): fetchMyProductionTasks(), fetchMyQcTaskList(), fetchQcTaskDetail(), fetchQcTaskList(), for(), set(), annotateForkEdges(), chainApiToElements() (+33 more)
|
||||
Nodes (42): fetchMyProductionTasks(), fetchMyQcTaskList(), fetchQcTaskDetail(), fetchQcTaskList(), for(), set(), annotateForkEdges(), chainApiToElements() (+34 more)
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.04
|
||||
Nodes (40): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchRoleOptions(), fetchUpdateMenu(), collectIds(), buildInboundBasicSection(), buildInboundCellStorageViewSections() (+32 more)
|
||||
Nodes (44): fetchFullmoonTodoList(), fetchUpdateFullmoonTodoInsurance(), fetchCollectionProtocolAuditList(), fetchCollectionProtocolDetail(), fetchCollectionProtocolList(), fetchCreateProtocolInvoiceRequest(), fetchInvoiceEligiblePayments(), fetchPaymentDetailList() (+36 more)
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.04
|
||||
Nodes (43): fetchFullmoonTodoList(), fetchUpdateFullmoonTodoInsurance(), fetchCollectionProtocolAuditList(), fetchCollectionProtocolDetail(), fetchCollectionProtocolList(), fetchCreateProtocolInvoiceRequest(), fetchInvoiceEligiblePayments(), fetchPaymentDetailList() (+35 more)
|
||||
Nodes (37): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchRoleOptions(), fetchUpdateMenu(), collectIds(), buildInboundBasicSection(), buildInboundCellStorageViewSections() (+29 more)
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.04
|
||||
@@ -146,77 +142,77 @@ Cohesion: 0.05
|
||||
Nodes (34): fetchClinicalPaymentDetail(), fetchClinicalPayments(), fetchClinicalReceiptConfirmed(), fetchClinicalReceiptPending(), fetchClinicalRefundConfirmed(), fetchClinicalRefundPending(), fetchOrderAdjusts(), fetchOrderDetail() (+26 more)
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.05
|
||||
Nodes (31): fetchDeleteQcMaterialBatch(), fetchQcMaterialBatchList(), fetchQcMaterialBatchOptions(), fetchQcMaterialList(), fetchQcMaterialOptions(), fetchUpdateQcMaterialBatch(), fetchMarkQcMaterialUsageFullyUsed(), fetchMyQcMaterialUsageList() (+23 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.06
|
||||
Nodes (11): fetchGetLatestUpgradeLog(), getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, getSystemStorage(), getSysVersion(), StorageKeyManager, StorageCompatibilityManager (+3 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.05
|
||||
Nodes (26): fetchDeleteQcMaterialBatch(), fetchQcMaterialBatchList(), fetchQcMaterialBatchOptions(), fetchQcMaterialList(), fetchQcMaterialOptions(), fetchUpdateQcMaterialBatch(), fetchMarkQcMaterialUsageFullyUsed(), financeAttachmentsToUrlString() (+18 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.06
|
||||
Nodes (25): useSettingsHandlers(), useSettingsPanel(), useSettingsState(), RoutePermissionValidator, useCeremony(), useTheme(), walk(), themeAnimation() (+17 more)
|
||||
Cohesion: 0.05
|
||||
Nodes (30): useSettingsHandlers(), useSettingsPanel(), useSettingsState(), RoutePermissionValidator, useCeremony(), useTheme(), collectAllPostBindDeptIds(), collectPostBindDeptSubtreeIds() (+22 more)
|
||||
|
||||
### Community 16 - "Community 16"
|
||||
Cohesion: 0.07
|
||||
Nodes (33): fetchUserList(), fetchAddTaskStep(), fetchCopyTaskStep(), fetchDeleteTaskStep(), fetchForwardProductionTask(), fetchProductionTaskDetail(), fetchReassignProductionTask(), fetchReorderTaskSteps() (+25 more)
|
||||
Cohesion: 0.06
|
||||
Nodes (36): fetchUserList(), fetchAddTaskStep(), fetchCopyTaskStep(), fetchDeleteTaskStep(), fetchDispatchProductionTaskSteps(), fetchForwardProductionTask(), fetchProductionTaskDetail(), fetchReassignProductionTask() (+28 more)
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
Cohesion: 0.04
|
||||
Nodes (21): fetchAvailableMaterialBatches(), fetchMyProductionMaterialConsumptions(), fetchMyProductionMaterialUsageList(), fetchProductionMaterialBatchList(), fetchProductionMaterialBatchOptions(), fetchProductionMaterialConsumptions(), fetchProductionMaterialFormula(), fetchProductionMaterialLinkedStepUsages() (+13 more)
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
Cohesion: 0.1
|
||||
Nodes (2): WebSocketClient, TableCache
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.08
|
||||
Nodes (32): toLogin(), base64ToBytes(), bytesToBase64(), decryptJson(), deriveKey(), encryptJson(), fromBase64Url(), hexToBytes() (+24 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
### Community 20 - "Community 20"
|
||||
Cohesion: 0.08
|
||||
Nodes (27): fetchUserOptions(), fetchSampleReceptionCheckItemList(), fetchSampleReceptionCheckItemsActive(), fetchAllocateLabStorageCodes(), fetchSampleReceptionBySampleCode(), fetchSampleReceptionDetail(), fetchSampleReceptionPendingList(), fetchSampleReceptionReceivedList() (+19 more)
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
### Community 21 - "Community 21"
|
||||
Cohesion: 0.08
|
||||
Nodes (20): maskIdCard(), buildBasicExperimentApplicationFields(), buildDefaultApplicationFields(), buildOutboundPilotContextSections(), applicationStatusLabel(), applicationStatusTagType(), cellProductStatusLabel(), cellProductStatusTagType() (+12 more)
|
||||
|
||||
### Community 21 - "Community 21"
|
||||
Cohesion: 0.09
|
||||
Nodes (28): completePilotApplication(), deletePilotApplication(), fetchPilotApplicationList(), startPilotApplication(), voidPilotApplication(), clearTableSelection(), handleBatchComplete(), handleBatchStart() (+20 more)
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
Cohesion: 0.07
|
||||
Nodes (17): fetchEthnicList(), applyDonationBundleToForm(), createEmptyTransport(), ensureEthnicOptionInList(), handleOpenForAdd(), loadEthnicOptions(), normalizeSampleRow(), resetForm() (+9 more)
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.09
|
||||
Nodes (27): completePilotApplication(), deletePilotApplication(), fetchPilotApplicationList(), startPilotApplication(), voidPilotApplication(), handleBatchComplete(), handleBatchStart(), handleBatchVoid() (+19 more)
|
||||
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.07
|
||||
Nodes (16): fetchDeleteMaterialBatch(), fetchMaterialBatchList(), fetchMaterialBatchOptions(), fetchMaterialList(), fetchMaterialOptions(), fetchUpdateMaterialBatch(), fetchMaterialUsageList(), fetchMyMaterialUsageList() (+8 more)
|
||||
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.1
|
||||
Nodes (28): fetchCellProductSpecList(), fetchCellProductTypeList(), fetchMaxPassageProductSeq(), handleAdd(), resetForm(), applyProductCodeToLines(), calcExpiryFromFreeze(), createEmptyProductLine() (+20 more)
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
Cohesion: 0.08
|
||||
Nodes (12): fetchCreateProductionWorkOrder(), fetchProductionWorkOrderCellProductOptions(), fetchProductionWorkOrderDetail(), fetchProductionWorkOrderList(), fetchProductionWorkOrderQcDispatchOptions(), reload(), handleMenuJump(), openExternalLink() (+4 more)
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.11
|
||||
Nodes (21): fetchGetMenuCodes(), fetchGetUserInfo(), fetchLogin(), fetchRefreshToken(), fetchUpdateProfile(), fetchUploadProfileAvatar(), fetchUserInfo(), buildWebEncryptedLoginBody() (+13 more)
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
### Community 27 - "Community 27"
|
||||
Cohesion: 0.12
|
||||
Nodes (24): fetchCellProductSpecList(), fetchCellProductTypeList(), applyProductCodeToLines(), calcExpiryFromFreeze(), createEmptyProductLine(), createQuantityValue(), getLineStorageSlotOptions(), getOtherLineStorageSlotIds() (+16 more)
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.12
|
||||
Nodes (15): addCopyButton(), highlightCode(), insertLineNumbers(), isBlockProcessed(), markBlockAsProcessed(), processBlock(), setupHighlightDirective(), setupRippleDirective() (+7 more)
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
Cohesion: 0.13
|
||||
Nodes (18): fetchCellSampleTypeList(), fetchCreateCellSampleType(), fetchDeleteCellSampleType(), fetchUpdateCellSampleType(), handleAdd(), handleDelete(), handleDropdownCommand(), handleEdit() (+10 more)
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
### Community 29 - "Community 29"
|
||||
Cohesion: 0.11
|
||||
Nodes (11): fetchOutboundReleaseMaterial(), fetchOutboundReleaseReviewDetail(), fetchOutboundReleaseReviewList(), fetchReleaseReviewList(), handleReset(), handleSearch(), handleToggleSelect(), loadData() (+3 more)
|
||||
|
||||
### Community 29 - "Community 29"
|
||||
### Community 30 - "Community 30"
|
||||
Cohesion: 0.16
|
||||
Nodes (13): handleChineseDatetimePaste(), parseChineseDatetimeText(), isMaternalBloodEmpty(), matchCellSampleType(), normalizeLine(), parseDatetime(), parseDeliveryMode(), parseDonationStandardImportText() (+5 more)
|
||||
|
||||
### Community 30 - "Community 30"
|
||||
Cohesion: 0.12
|
||||
Nodes (12): fetchApproveTask(), fetchBusinessAllTasks(), fetchCompletedTasks(), fetchDesignerData(), fetchInstanceDetail(), fetchMyInstances(), fetchPendingTasks(), fetchProcessDefList() (+4 more)
|
||||
|
||||
### Community 31 - "Community 31"
|
||||
Cohesion: 0.16
|
||||
Nodes (14): fetchCreateEnvDetectItem(), fetchDeleteEnvDetectItem(), fetchEnvDetectItemDetail(), fetchEnvDetectItemList(), fetchEnvDetectItemsActive(), fetchUpdateEnvDetectItem(), handleAdd(), handleBatchDelete() (+6 more)
|
||||
@@ -238,132 +234,108 @@ Cohesion: 0.19
|
||||
Nodes (6): fetchServiceOrderTxnList(), handleReset(), handleSearch(), handleTabChange(), loadData(), switchTab()
|
||||
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.15
|
||||
Nodes (4): fetchNextDonationSampleCode(), fetchResearchDonationAuditList(), fetchResearchDonationDetail(), fetchResearchDonationList()
|
||||
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.18
|
||||
Nodes (3): normalizeStepSubTables(), parseEquipmentIds(), syncEquipmentNamesFromOptions()
|
||||
|
||||
### Community 38 - "Community 38"
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 0.24
|
||||
Nodes (6): buildInboundMetaFields(), getCardMetaConfig(), getCardMetaConfigForLegacyTab(), parseReceptionTime(), receptionOver24HoursLabel(), receptionOver24HoursTagType()
|
||||
|
||||
### Community 39 - "Community 39"
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 0.42
|
||||
Nodes (9): buildPaymentFlowSteps(), dash(), formatAmount(), hasFinanceReceipt(), hasFinanceRefund(), hasReceiptSubmit(), hasRefundSubmit(), receiptSubmitTime() (+1 more)
|
||||
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 0.2
|
||||
Nodes (3): fetchProductionWorkOrderCellProductOptions(), fetchProductionWorkOrderDetail(), fetchProductionWorkOrderList()
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
Cohesion: 0.25
|
||||
Nodes (2): handleTouchEnd(), setTransition()
|
||||
|
||||
### Community 42 - "Community 42"
|
||||
Cohesion: 0.28
|
||||
Nodes (1): FireworkSystem
|
||||
|
||||
### Community 45 - "Community 45"
|
||||
### Community 44 - "Community 44"
|
||||
Cohesion: 0.39
|
||||
Nodes (6): isIgnorableScriptError(), normalizeErrorMessage(), registerPromiseErrorHandler(), registerResourceErrorHandler(), scriptErrorHandler(), setupErrorHandle()
|
||||
|
||||
### Community 46 - "Community 46"
|
||||
### Community 45 - "Community 45"
|
||||
Cohesion: 0.36
|
||||
Nodes (1): TableHeightCalculator
|
||||
|
||||
### Community 49 - "Community 49"
|
||||
### Community 48 - "Community 48"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): logApiCryptoBootInfo(), maskSecret()
|
||||
|
||||
### Community 50 - "Community 50"
|
||||
### Community 49 - "Community 49"
|
||||
Cohesion: 0.29
|
||||
Nodes (2): fetchLeaveDetail(), fetchLeaveList()
|
||||
|
||||
### Community 51 - "Community 51"
|
||||
### Community 50 - "Community 50"
|
||||
Cohesion: 0.47
|
||||
Nodes (3): isPaymentDueWithinWarnWindow(), parsePaymentDueYmd(), startOfLocalDay()
|
||||
|
||||
### Community 53 - "Community 53"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcThirdPartyCompanyList(), fetchQcThirdPartyCompanyOptions()
|
||||
|
||||
### Community 54 - "Community 54"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcLabTestItemList(), fetchQcLabTestItemsActive()
|
||||
|
||||
### Community 55 - "Community 55"
|
||||
### Community 52 - "Community 52"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): formatProtocolDocDeleteConfirm(), formatProtocolDocSubject()
|
||||
|
||||
### Community 56 - "Community 56"
|
||||
### Community 53 - "Community 53"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): focusInput(), handleKeydown()
|
||||
|
||||
### Community 57 - "Community 57"
|
||||
### Community 54 - "Community 54"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): if(), logSidebarMenu()
|
||||
|
||||
### Community 60 - "Community 60"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): fetchStorageEntrySmsList()
|
||||
|
||||
### Community 61 - "Community 61"
|
||||
### Community 57 - "Community 57"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): fetchSampleSmsNotificationList()
|
||||
|
||||
### Community 62 - "Community 62"
|
||||
### Community 58 - "Community 58"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): fetchQcSmsList()
|
||||
|
||||
### Community 67 - "Community 67"
|
||||
### Community 63 - "Community 63"
|
||||
Cohesion: 1.0
|
||||
Nodes (2): getSettingDefaults(), resetToDefaults()
|
||||
|
||||
### Community 69 - "Community 69"
|
||||
### Community 65 - "Community 65"
|
||||
Cohesion: 1.0
|
||||
Nodes (2): copyTextToClipboard(), copyTextWithFallback()
|
||||
|
||||
## Knowledge Gaps
|
||||
- **Thin community `Community 17`** (42 nodes): `WebSocketClient`, `.calculateReconnectDelay()`, `.clearAllTimers()`, `.clearConnectionTimers()`, `.clearTimer()`, `.close()`, `.closeCurrentSocketForReconnect()`, `.connect()`, `.connectionStatusText()`, `.constructor()`, `.destroyInstance()`, `.flushMessageQueue()`, `.getInstance()`, `.getReadyStateText()`, `.handleClose()`, `.handleConnectionTimeout()`, `.handleError()`, `.handleMessage()`, `.handleOpen()`, `.init()`, `.isWebSocketConnected()`, `.reconnect()`, `.resetHeartbeat()`, `.send()`, `.startHeartbeat()`, `.startPing()`, `TableCache`, `.cleanupExpired()`, `.clear()`, `.clearByTags()`, `.clearCurrentSearch()`, `.clearPagination()`, `.constructor()`, `.evictLRU()`, `.generateKey()`, `.generateTags()`, `.get()`, `.getStats()`, `.log()`, `.set()`, `index.ts`, `tableCache.ts`
|
||||
- **Thin community `Community 18`** (42 nodes): `WebSocketClient`, `.calculateReconnectDelay()`, `.clearAllTimers()`, `.clearConnectionTimers()`, `.clearTimer()`, `.close()`, `.closeCurrentSocketForReconnect()`, `.connect()`, `.connectionStatusText()`, `.constructor()`, `.destroyInstance()`, `.flushMessageQueue()`, `.getInstance()`, `.getReadyStateText()`, `.handleClose()`, `.handleConnectionTimeout()`, `.handleError()`, `.handleMessage()`, `.handleOpen()`, `.init()`, `.isWebSocketConnected()`, `.reconnect()`, `.resetHeartbeat()`, `.send()`, `.startHeartbeat()`, `.startPing()`, `TableCache`, `.cleanupExpired()`, `.clear()`, `.clearByTags()`, `.clearCurrentSearch()`, `.clearPagination()`, `.constructor()`, `.evictLRU()`, `.generateKey()`, `.generateTags()`, `.get()`, `.getStats()`, `.log()`, `.set()`, `index.ts`, `tableCache.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 41`** (9 nodes): `cleanupEventListeners()`, `handleTouchEnd()`, `handleTouchMove()`, `handleTouchStart()`, `handleWheelScroll()`, `if()`, `setTransition()`, `setupEventListeners()`, `index.vue`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 42`** (9 nodes): `FireworkSystem`, `.constructor()`, `.createFirework()`, `.createParticle()`, `.getAvailableParticle()`, `.initializePool()`, `.preloadAllImages()`, `.preloadImage()`, `index.vue`
|
||||
- **Thin community `Community 45`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 46`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
|
||||
- **Thin community `Community 48`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 49`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
|
||||
- **Thin community `Community 49`** (7 nodes): `fetchCreateLeave()`, `fetchDeleteLeave()`, `fetchLeaveDetail()`, `fetchLeaveList()`, `fetchSubmitLeave()`, `fetchUpdateLeave()`, `leave.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 50`** (7 nodes): `fetchCreateLeave()`, `fetchDeleteLeave()`, `fetchLeaveDetail()`, `fetchLeaveList()`, `fetchSubmitLeave()`, `fetchUpdateLeave()`, `leave.ts`
|
||||
- **Thin community `Community 52`** (5 nodes): `formatProtocolDocBatchDeleteConfirm()`, `formatProtocolDocDeleteConfirm()`, `formatProtocolDocSubject()`, `getProtocolDocTypeLabel()`, `protocol-doc-label.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 53`** (6 nodes): `fetchCreateQcThirdPartyCompany()`, `fetchDeleteQcThirdPartyCompany()`, `fetchQcThirdPartyCompanyList()`, `fetchQcThirdPartyCompanyOptions()`, `fetchUpdateQcThirdPartyCompany()`, `qc-third-party-company.ts`
|
||||
- **Thin community `Community 53`** (5 nodes): `focusInput()`, `handleKeydown()`, `if()`, `search()`, `index.vue`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 54`** (6 nodes): `fetchCreateQcLabTestItem()`, `fetchDeleteQcLabTestItem()`, `fetchQcLabTestItemList()`, `fetchQcLabTestItemsActive()`, `fetchUpdateQcLabTestItem()`, `qc-lab-test-item.ts`
|
||||
- **Thin community `Community 54`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 55`** (5 nodes): `formatProtocolDocBatchDeleteConfirm()`, `formatProtocolDocDeleteConfirm()`, `formatProtocolDocSubject()`, `getProtocolDocTypeLabel()`, `protocol-doc-label.ts`
|
||||
- **Thin community `Community 57`** (4 nodes): `fetchGenerateSms()`, `fetchSampleSmsNotificationList()`, `fetchToggleSmsNotified()`, `sample-sms-notification.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 56`** (5 nodes): `focusInput()`, `handleKeydown()`, `if()`, `search()`, `index.vue`
|
||||
- **Thin community `Community 58`** (4 nodes): `fetchGenerateQcSms()`, `fetchQcSmsList()`, `fetchToggleQcSmsNotified()`, `qc-sms-notification.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 57`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
|
||||
- **Thin community `Community 63`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 60`** (4 nodes): `fetchGenerateStorageEntrySms()`, `fetchStorageEntrySmsList()`, `fetchToggleStorageEntrySmsNotified()`, `storage-entry-sms-notification.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 61`** (4 nodes): `fetchGenerateSms()`, `fetchSampleSmsNotificationList()`, `fetchToggleSmsNotified()`, `sample-sms-notification.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 62`** (4 nodes): `fetchGenerateQcSms()`, `fetchQcSmsList()`, `fetchToggleQcSmsNotified()`, `qc-sms-notification.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 67`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 69`** (3 nodes): `copyTextToClipboard()`, `copyTextWithFallback()`, `copy-text.ts`
|
||||
- **Thin community `Community 65`** (3 nodes): `copyTextToClipboard()`, `copyTextWithFallback()`, `copy-text.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 12`, `Community 13`, `Community 14`, `Community 15`, `Community 16`, `Community 19`, `Community 21`, `Community 22`, `Community 23`, `Community 24`, `Community 25`, `Community 27`, `Community 28`, `Community 30`, `Community 31`, `Community 35`, `Community 40`, `Community 50`, `Community 53`, `Community 54`, `Community 60`, `Community 61`, `Community 62`?**
|
||||
_High betweenness centrality (0.367) - this node is a cross-community bridge._
|
||||
- **Why does `push()` connect `Community 6` to `Community 0`, `Community 1`, `Community 2`, `Community 4`, `Community 5`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 13`, `Community 15`, `Community 16`, `Community 17`, `Community 18`, `Community 20`, `Community 21`, `Community 22`, `Community 24`, `Community 38`, `Community 42`?**
|
||||
_High betweenness centrality (0.172) - this node is a cross-community bridge._
|
||||
- **Why does `handleDynamicRoutes()` connect `Community 3` to `Community 25`, `Community 15`?**
|
||||
_High betweenness centrality (0.036) - this node is a cross-community bridge._
|
||||
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 12`, `Community 13`, `Community 14`, `Community 15`, `Community 16`, `Community 17`, `Community 20`, `Community 22`, `Community 23`, `Community 24`, `Community 25`, `Community 26`, `Community 27`, `Community 29`, `Community 31`, `Community 35`, `Community 37`, `Community 49`, `Community 57`, `Community 58`?**
|
||||
_High betweenness centrality (0.322) - this node is a cross-community bridge._
|
||||
- **Why does `push()` connect `Community 7` to `Community 0`, `Community 1`, `Community 2`, `Community 4`, `Community 5`, `Community 6`, `Community 8`, `Community 9`, `Community 10`, `Community 14`, `Community 15`, `Community 16`, `Community 18`, `Community 19`, `Community 21`, `Community 22`, `Community 23`, `Community 25`, `Community 27`, `Community 39`?**
|
||||
_High betweenness centrality (0.154) - this node is a cross-community bridge._
|
||||
- **Why does `handleDynamicRoutes()` connect `Community 3` to `Community 26`, `Community 15`?**
|
||||
_High betweenness centrality (0.031) - this node is a cross-community bridge._
|
||||
- **Are the 267 inferred relationships involving `get()` (e.g. with `buildNodeCodePathFromFlat()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
|
||||
_`get()` has 267 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 63 inferred relationships involving `push()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `formatDetectMethods()`) actually correct?**
|
||||
|
||||
@@ -57,12 +57,12 @@
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">2609 nodes · 3608 edges · 324 communities</div>
|
||||
<div id="stats">2624 nodes · 3636 edges · 318 communities</div>
|
||||
</div>
|
||||
<script>
|
||||
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 49, "community_name": "Community 49", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 49, "community_name": "Community 49", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 49, "community_name": "Community 49", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 49, "community_name": "Community 49", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 49, "community_name": "Community 49", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 49, "community_name": "Community 49", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 107, "community_name": "Community 107", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 108, "community_name": "Community 108", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 26, "community_name": "Community 26", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 26, "community_name": "Community 26", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 26, "community_name": "Community 26", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 26, "community_name": "Community 26", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 26, "community_name": "Community 26", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_setuprolesdirective",Line truncated
|
||||
const RAW_EDGES = [{"from": "app_vue", "to": "src_app_refreshbuttonautoicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "src_app_refreshpaneltitleicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "main_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "utils_sys_console_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_masksecret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_logapicryptobootinfo", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "src_main_masksecret", "to": "src_main_logapicryptobootinfo", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_ts", "to": "directives_index_setupglobdirectives", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_setupglobdirectives", "to": "core_auth_setupauthdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "core_roles_setuprolesdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_highlight_setuphighlightdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_ripple_setuprippledirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_core_roles_ts", "to": "core_roles_checkrolepermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_setuprolesdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_roles_checkrolepermission", "to": "core_roles_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_checkauthpermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_setupauthdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_checkauthpermission", "to": "core_auth_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_ripple_ts", "to": "business_ripple_setuprippledirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_highlightcode", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_insertlinenumbers", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_addcopybutton", "label": "contains", "title": "contains [EXTRACTED]", "dLine truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 404}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 104}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 98}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 95}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 91}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 90}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 83}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 83}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 74}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 71}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 68}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 62}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 61}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 55}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 54}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 46}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 45}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 42}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 40}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 39}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 38}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 35}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 35}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 33}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 32}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 29}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 22}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 22}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 22}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 19}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 19}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 19}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 17}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 16}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 14}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 14}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 13}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 12}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 11}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 10}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 10}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 9}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 9}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 9}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 9}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 8}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 8}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 8}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 8}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 7}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 7}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 6}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 6}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 6}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 6}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 5}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 5}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 4}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 4}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 4}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 4}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 4}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 4}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 4}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 4}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 4}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 4}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 3}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 3}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 3}, {"cid": 70, "color": "#4E79A7", "label": "Community 70", "coLine truncated
|
||||
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 48, "community_name": "Community 48", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 48, "community_name": "Community 48", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 48, "community_name": "Community 48", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 48, "community_name": "Community 48", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 48, "community_name": "Community 48", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 48, "community_name": "Community 48", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 103, "community_name": "Community 103", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 104, "community_name": "Community 104", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 28, "community_name": "Community 28", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 28, "community_name": "Community 28", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 28, "community_name": "Community 28", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 28, "community_name": "Community 28", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 28, "community_name": "Community 28", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_setuprolesdirective",Line truncated
|
||||
const RAW_EDGES = [{"from": "app_vue", "to": "src_app_refreshbuttonautoicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "src_app_refreshpaneltitleicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "main_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "utils_sys_console_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_masksecret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_logapicryptobootinfo", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "src_main_masksecret", "to": "src_main_logapicryptobootinfo", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_ts", "to": "directives_index_setupglobdirectives", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_setupglobdirectives", "to": "core_auth_setupauthdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "core_roles_setuprolesdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_highlight_setuphighlightdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_ripple_setuprippledirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_core_roles_ts", "to": "core_roles_checkrolepermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_setuprolesdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_roles_checkrolepermission", "to": "core_roles_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_checkauthpermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_setupauthdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_checkauthpermission", "to": "core_auth_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_ripple_ts", "to": "business_ripple_setuprippledirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_highlightcode", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_insertlinenumbers", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_addcopybutton", "label": "contains", "title": "contains [EXTRACTED]", "dLine truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 382}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 112}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 104}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 95}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 91}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 89}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 86}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 81}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 76}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 69}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 66}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 62}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 61}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 60}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 55}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 53}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 50}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 48}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 42}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 40}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 39}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 38}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 35}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 34}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 33}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 29}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 29}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 28}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 22}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 22}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 19}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 19}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 17}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 16}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 14}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 14}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 13}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 13}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 12}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 11}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 10}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 9}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 9}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 9}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 8}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 8}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 8}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 8}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 7}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 7}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 6}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 6}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 5}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 5}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 4}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 4}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 4}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 4}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 4}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 4}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 4}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 4}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 4}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 3}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 3}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 3}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 3}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 3}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 3}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 3}, {"cid": 70, "color": "#4E79A7", "label": "Community 70", "cLine truncated
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/common/index.ts": 1781272556.3597305,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/directive/directive.d.ts": 1781272556.3601494,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/api/api.d.ts": 1781272556.3606477,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1782268511.5967362,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1782268506.0513382,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1782361730.3874717,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1782361721.5556824,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/store/index.ts": 1781272556.364766,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/router/index.ts": 1781272556.3652694,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/locales/index.ts": 1781272556.3657222,
|
||||
@@ -41,7 +41,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/enums/formEnum.ts": 1781272556.3778555,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/enums/appEnum.ts": 1781272556.3784597,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/patch-el-select-filterable.ts": 1781272556.3791182,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts": 1781534662.3091736,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts": 1782289322.9593837,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-tabs.ts": 1781600464.3251936,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-doc-label.ts": 1781272556.3840382,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/user-avatar.ts": 1781403605.517818,
|
||||
@@ -54,7 +54,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-mine-task-groups.ts": 1781608059.9990764,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-labels.ts": 1781272556.3878465,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts": 1781765815.259271,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts": 1781696893.3885784,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts": 1782358030.9320872,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/fetch-paged-list.ts": 1781272556.3903377,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/sort-order.ts": 1781272556.3913012,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/outbound-qc-pilot-view-sections.ts": 1781566346.7618802,
|
||||
@@ -241,7 +241,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/storage-release-review.ts": 1781536765.5084789,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-material.ts": 1781510846.4290047,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/workflow.ts": 1781272556.6579714,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts": 1781696883.6649792,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts": 1782350330.2414439,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task-result.ts": 1781272556.6589992,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/protocol-sample-collection.ts": 1781272556.659353,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/material-usage.ts": 1781517319.838243,
|
||||
@@ -262,7 +262,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts": 1781581101.6134424,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-item-param.ts": 1781272556.6680455,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/env-detect-item.ts": 1781272556.668322,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts": 1781583227.9475071,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts": 1782362264.303446,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-material-stock-check.ts": 1781424012.5471919,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-material-usage.ts": 1781424013.8349903,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-material.ts": 1781690334.9639037,
|
||||
@@ -271,7 +271,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/material.ts": 1781346022.817811,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/sample-reception.ts": 1781496419.5874305,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/auth.ts": 1782122651.4628098,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts": 1781698779.261544,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts": 1782350342.5611486,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/auth/login/index.vue": 1781272556.6735966,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/refund-confirm/index.vue": 1781272556.6742516,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/my-material-usage/index.vue": 1781518736.690082,
|
||||
@@ -306,7 +306,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/outside/Iframe.vue": 1781272556.7246568,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/demo/index.vue": 1781272556.7266567,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/clean-room/index.vue": 1781585388.6729288,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/storage-facility/index.vue": 1781594230.0853102,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/storage-facility/index.vue": 1782290524.010253,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/exhibition-appointment/index.vue": 1781600464.861937,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/audit/index.vue": 1781600355.3898988,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/sample-info/index.vue": 1781518738.227001,
|
||||
@@ -356,22 +356,23 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/sop/index.vue": 1781585388.69546,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-task/index.vue": 1781272556.812188,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/reagent/index.vue": 1781563767.359068,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue": 1781592903.601546,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts": 1781588526.441707,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue": 1781528130.4755712,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue": 1782351718.6351538,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts": 1782362265.837388,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue": 1782362266.614523,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/CompleteProductionTaskDialog.vue": 1781563767.3525257,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskInputEnhancedTable.vue": 1781585388.6972075,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue": 1781607677.069648,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue": 1782359900.6139107,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/SampleReceptionDialog.vue": 1781599793.4040868,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue": 1781588551.0654483,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue": 1782351614.9751787,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue": 1781577178.2471955,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputList.vue": 1781585388.699347,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue": 1781593091.2341514,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue": 1782361064.4509723,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskPaperAttachmentsPanel.vue": 1781530960.805927,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue": 1781585388.7005522,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue": 1782351634.8770185,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputProductDialog.vue": 1781605192.0421948,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue": 1781699025.1827943,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue": 1782358112.4315796,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ForwardTaskDialog.vue": 1781563767.3550124,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchStepDialog.vue": 1782351544.529724,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/tabs/OutboundPilotTab.vue": 1781583381.1088736,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/tabs/ProductionWorkOrderTabPanel.vue": 1781583376.390064,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/tabs/InboundCellStorageTab.vue": 1781583380.9191706,
|
||||
|
||||
@@ -69,6 +69,24 @@ export function fetchReassignProductionTask(
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchDispatchProductionTaskSteps(
|
||||
taskId: string,
|
||||
data: {
|
||||
steps: Array<{
|
||||
stepId: string
|
||||
assigneeUserIds: string[]
|
||||
plannedStartTime?: string | null
|
||||
}>
|
||||
},
|
||||
operateScope?: ProductionTaskOperateScope
|
||||
) {
|
||||
return request.put<any>({
|
||||
url: `/web/admin/production-tasks/${taskId}/steps/dispatch`,
|
||||
data,
|
||||
params: scopeQuery(operateScope)
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchProductionTaskDetail(id: string) {
|
||||
return request.get<any>({ url: `/web/admin/production-tasks/${id}` })
|
||||
}
|
||||
|
||||
@@ -150,27 +150,38 @@ export function fetchDeleteProductionWorkOrder(id: string) {
|
||||
return request.del({ url: `/web/admin/production-work-orders/${id}` })
|
||||
}
|
||||
|
||||
export interface ProductionCellProductOption {
|
||||
export interface ProductionQcDispatchOption {
|
||||
id: string
|
||||
cellProductId?: string
|
||||
productCode?: string
|
||||
productName?: string
|
||||
productTypeName?: string
|
||||
passage?: string
|
||||
storageSlotName?: string
|
||||
stepOutputId?: string
|
||||
taskId?: string
|
||||
taskNo?: string
|
||||
taskName?: string
|
||||
stepId?: string
|
||||
processName?: string
|
||||
outputTypeId?: string
|
||||
outputTypeName?: string
|
||||
outputName?: string
|
||||
outputBarcode?: string
|
||||
cellProductId?: string
|
||||
}
|
||||
|
||||
export function fetchProductionWorkOrderCellProductOptions(workOrderId: string) {
|
||||
return request.get<ProductionCellProductOption[]>({
|
||||
/** @deprecated 使用 ProductionQcDispatchOption */
|
||||
export type ProductionCellProductOption = ProductionQcDispatchOption
|
||||
|
||||
export function fetchProductionWorkOrderQcDispatchOptions(workOrderId: string) {
|
||||
return request.get<ProductionQcDispatchOption[]>({
|
||||
url: `/web/admin/production-work-orders/${workOrderId}/cell-product-options`
|
||||
})
|
||||
}
|
||||
|
||||
/** @deprecated 使用 fetchProductionWorkOrderQcDispatchOptions */
|
||||
export function fetchProductionWorkOrderCellProductOptions(workOrderId: string) {
|
||||
return fetchProductionWorkOrderQcDispatchOptions(workOrderId)
|
||||
}
|
||||
|
||||
export function fetchCreateQcFromProduction(
|
||||
workOrderId: string,
|
||||
data: { cellProductId: string; productionTaskId?: string; remark?: string }
|
||||
data: { productionStepOutputId: string; remark?: string }
|
||||
) {
|
||||
return request.post({
|
||||
url: `/web/admin/production-work-orders/${workOrderId}/qc-work-orders`,
|
||||
|
||||
@@ -138,6 +138,7 @@ export type QcWorkOrder = {
|
||||
productionWorkOrderId?: string
|
||||
productionWorkOrderNo?: string
|
||||
productionTaskId?: string
|
||||
productionStepOutputId?: string
|
||||
protocolStatus?: string
|
||||
protocolStatusLabel?: string
|
||||
paymentSummary?: QcProtocolPaymentSummary | null
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "label": "useTaskStepEditor.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L1"}, {"id": "production_work_order_usetaskstepeditor_parsetaskattachmentsfromurls", "label": "parseTaskAttachmentsFromUrls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L43"}, {"id": "production_work_order_usetaskstepeditor_toapiflag", "label": "toApiFlag()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L53"}, {"id": "production_work_order_usetaskstepeditor_fromapiflag", "label": "fromApiFlag()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L57"}, {"id": "production_work_order_usetaskstepeditor_normalizestepsubtables", "label": "normalizeStepSubTables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L60"}, {"id": "production_work_order_usetaskstepeditor_parseordernum", "label": "parseOrderNum()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L77"}, {"id": "production_work_order_usetaskstepeditor_usetaskstepeditor", "label": "useTaskStepEditor()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L84"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_task", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L18", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L27", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L28", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_sample_reception", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L29", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_equipment_select", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L30", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_process_material_ui", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L31", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_taskexecutiondialog_vue", "label": "TaskExecutionDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "label": "DispatchQcWorkOrderDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L114", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L115", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L116", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_task", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L117", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L118", "weight": 1.0}], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_task_ts", "label": "production-task.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L1"}, {"id": "api_production_task_scopequery", "label": "scopeQuery()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L5"}, {"id": "api_production_task_fetchcreateproductiontask", "label": "fetchCreateProductionTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L9"}, {"id": "api_production_task_fetchproductiontasklist", "label": "fetchProductionTaskList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L13"}, {"id": "api_production_task_fetchmyproductiontasks", "label": "fetchMyProductionTasks()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L31"}, {"id": "api_production_task_fetchforwardproductiontask", "label": "fetchForwardProductionTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L50"}, {"id": "api_production_task_fetchreassignproductiontask", "label": "fetchReassignProductionTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L62"}, {"id": "api_production_task_fetchdispatchproductiontasksteps", "label": "fetchDispatchProductionTaskSteps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L72"}, {"id": "api_production_task_fetchproductiontaskdetail", "label": "fetchProductionTaskDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L88"}, {"id": "api_production_task_fetchupdateproductiontask", "label": "fetchUpdateProductionTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L92"}, {"id": "api_production_task_fetchupdateproductiontaskstatus", "label": "fetchUpdateProductionTaskStatus()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L96"}, {"id": "api_production_task_fetchdeleteproductiontask", "label": "fetchDeleteProductionTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L108"}, {"id": "api_production_task_fetchaddtaskstep", "label": "fetchAddTaskStep()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L112"}, {"id": "api_production_task_fetchupdatetaskstep", "label": "fetchUpdateTaskStep()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L124"}, {"id": "api_production_task_fetchdeletetaskstep", "label": "fetchDeleteTaskStep()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L137"}, {"id": "api_production_task_fetchreplacestepreagents", "label": "fetchReplaceStepReagents()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L148"}, {"id": "api_production_task_fetchreplacestepconsumables", "label": "fetchReplaceStepConsumables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L161"}, {"id": "api_production_task_fetchreplacestepconfiguredreagents", "label": "fetchReplaceStepConfiguredReagents()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L174"}, {"id": "api_production_task_fetchreplacestepdatacollection", "label": "fetchReplaceStepDataCollection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L187"}, {"id": "api_production_task_fetchsettaskinputs", "label": "fetchSetTaskInputs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L200"}, {"id": "api_production_task_fetchsettaskoutputs", "label": "fetchSetTaskOutputs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L212"}, {"id": "api_production_task_fetchreordertasksteps", "label": "fetchReorderTaskSteps()", "file_type": "code", "source_file": "/Users/wuzilong/Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "label": "production-work-order.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L1"}, {"id": "api_production_work_order_fetchproductionworkorderlist", "label": "fetchProductionWorkOrderList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L83"}, {"id": "api_production_work_order_fetchproductionworkorderdetail", "label": "fetchProductionWorkOrderDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L105"}, {"id": "api_production_work_order_fetchcompleteproductionworkorder", "label": "fetchCompleteProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L109"}, {"id": "api_production_work_order_fetchcreateproductionworkorder", "label": "fetchCreateProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L113"}, {"id": "api_production_work_order_fetchconfigureproductionworkorder", "label": "fetchConfigureProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L126"}, {"id": "api_production_work_order_fetchupdateproductionworkorder", "label": "fetchUpdateProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L142"}, {"id": "api_production_work_order_fetchdeleteproductionworkorder", "label": "fetchDeleteProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L149"}, {"id": "api_production_work_order_fetchproductionworkorderqcdispatchoptions", "label": "fetchProductionWorkOrderQcDispatchOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L171"}, {"id": "api_production_work_order_fetchproductionworkordercellproductoptions", "label": "fetchProductionWorkOrderCellProductOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L178"}, {"id": "api_production_work_order_fetchcreateqcfromproduction", "label": "fetchCreateQcFromProduction()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L182"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_http", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "api_production_work_order_fetchproductionworkorderlist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L83", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "api_production_work_order_fetchproductionworkorderdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L105", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "api_production_work_order_fetchcompleteproductionworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L109", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "api_production_work_order_fetchcreateproductionworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L113", "weight": 1.0}, {"source": "users_wuzilong_Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_productionworkordercardlist_vue", "label": "ProductionWorkOrderCardList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchstepdialog_vue", "label": "DispatchStepDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchStepDialog.vue", "source_location": "L1"}, {"id": "production_work_order_dispatchstepdialog_mergeduseroptions", "label": "mergedUserOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchStepDialog.vue", "source_location": "L115"}, {"id": "production_work_order_dispatchstepdialog_remotesearchusers", "label": "remoteSearchUsers()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchStepDialog.vue", "source_location": "L122"}, {"id": "production_work_order_dispatchstepdialog_onuserselectvisible", "label": "onUserSelectVisible()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchStepDialog.vue", "source_location": "L139"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchstepdialog_vue", "target": "production_work_order_dispatchstepdialog_mergeduseroptions", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchStepDialog.vue", "source_location": "L115", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchstepdialog_vue", "target": "production_work_order_dispatchstepdialog_remotesearchusers", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchStepDialog.vue", "source_location": "L122", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchstepdialog_vue", "target": "production_work_order_dispatchstepdialog_onuserselectvisible", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchStepDialog.vue", "source_location": "L139", "weight": 1.0}, {"source": "production_work_order_dispatchstepdialog_onuserselectvisible", "target": "production_work_order_dispatchstepdialog_remotesearchusers", "relation": "calls", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchStepDialog.vue", "source_location": "L140", "weight": 1.0}], "raw_calls": [{"caller_nid": "production_work_order_dispatchstepdialog_mergeduseroptions", "callee": "values", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchStepDialog.vue", "source_location": "L119"}, {"caller_nid": "production_work_order_dispatchstepdialog_remotesearchusers", "callee": "fetchUserList", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchStepDialog.vue", "source_location": "L125"}, {"caller_nid": "production_work_order_dispatchstepdialog_remotesearchusers", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchStepDialog.vue", "source_location": "L128"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "label": "useTaskStepEditor.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L1"}, {"id": "production_work_order_usetaskstepeditor_parsetaskattachmentsfromurls", "label": "parseTaskAttachmentsFromUrls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L45"}, {"id": "production_work_order_usetaskstepeditor_toapiflag", "label": "toApiFlag()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L55"}, {"id": "production_work_order_usetaskstepeditor_fromapiflag", "label": "fromApiFlag()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L59"}, {"id": "production_work_order_usetaskstepeditor_normalizestepsubtables", "label": "normalizeStepSubTables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L62"}, {"id": "production_work_order_usetaskstepeditor_parseordernum", "label": "parseOrderNum()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L90"}, {"id": "production_work_order_usetaskstepeditor_usetaskstepeditor", "label": "useTaskStepEditor()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L97"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_task", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L19", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L20", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L29", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L30", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_sample_reception", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L31", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_equipment_select", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L32", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "label": "StepDetailPanel.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L1"}, {"id": "production_work_order_stepdetailpanel_for", "label": "for()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L990"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "target": "production_work_order_stepdetailpanel_for", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L990", "weight": 1.0}], "raw_calls": [{"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "push", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L992"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "decodeURIComponent", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L995"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "pop", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L995"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "split", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L995"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L995"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_productionworkordercardlist_vue", "label": "ProductionWorkOrderCardList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "label": "DispatchTaskDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L1"}, {"id": "production_work_order_dispatchtaskdialog_resolvecreatedtaskid", "label": "resolveCreatedTaskId()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L264"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "vue_draggable_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L208", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_task", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L209", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_production_labels", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L210", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L211", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L212", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L213", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L214", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "production_work_order_dispatchtaskdialog_resolvecreatedtaskid", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L264", "weight": 1.0}], "raw_calls": [{"caller_nid": "production_work_order_dispatchtaskdialog_resolvecreatedtaskid", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L266"}, {"caller_nid": "production_work_order_dispatchtaskdialog_resolvecreatedtaskid", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L266"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "label": "StepDetailPanel.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L1"}, {"id": "production_work_order_stepdetailpanel_for", "label": "for()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L912"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "target": "production_work_order_stepdetailpanel_for", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L912", "weight": 1.0}], "raw_calls": [{"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "push", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L914"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "decodeURIComponent", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L917"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "pop", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L917"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "split", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L917"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L917"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "label": "DispatchQcWorkOrderDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L109", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L110", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L111", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L112", "weight": 1.0}], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L1"}, {"id": "production_work_order_index_refreshactivetab", "label": "refreshActiveTab()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L148"}, {"id": "production_work_order_index_handletabchange", "label": "handleTabChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L153"}, {"id": "production_work_order_index_handleaddtemporary", "label": "handleAddTemporary()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L164"}, {"id": "production_work_order_index_submitadd", "label": "submitAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L169"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L111", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L112", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L113", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L114", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_production_work_order_tabs", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L121", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_tabs_productionworkordertabpanel_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L126", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L127", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchstepdialog_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L128", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L129", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_vieLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_workordertasksublist_vue", "label": "WorkOrderTaskSubList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L1"}, {"id": "production_work_order_workordertasksublist_iscurrentassignee", "label": "isCurrentAssignee()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L270"}, {"id": "production_work_order_workordertasksublist_isminehistoryrow", "label": "isMineHistoryRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L278"}, {"id": "production_work_order_workordertasksublist_canenterexecution", "label": "canEnterExecution()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L284"}, {"id": "production_work_order_workordertasksublist_canforwardtask", "label": "canForwardTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L291"}, {"id": "production_work_order_workordertasksublist_canreassigntask", "label": "canReassignTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L295"}, {"id": "production_work_order_workordertasksublist_candispatchsteps", "label": "canDispatchSteps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L299"}, {"id": "production_work_order_workordertasksublist_canedittask", "label": "canEditTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L304"}, {"id": "production_work_order_workordertasksublist_candeletetask", "label": "canDeleteTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L310"}, {"id": "production_work_order_workordertasksublist_hasmoretaskactions", "label": "hasMoreTaskActions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L315"}, {"id": "production_work_order_workordertasksublist_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L320"}, {"id": "production_work_order_workordertasksublist_handletaskmutationsuccess", "label": "handleTaskMutationSuccess()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L352"}, {"id": "production_work_order_workordertasksublist_handledispatch", "label": "handleDispatch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L359"}, {"id": "production_work_order_workordertasksublist_handleneedstepdispatch", "label": "handleNeedStepDispatch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L373"}, {"id": "production_work_order_workordertasksublist_openstepdispatch", "label": "openStepDispatch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L379"}, {"id": "production_work_order_workordertasksublist_handleenterexecution", "label": "handleEnterExecution()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L390"}, {"id": "production_work_order_workordertasksublist_handleviewdetail", "label": "handleViewDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L397"}, {"id": "production_work_order_workordertasksublist_handledropdowncommand", "label": "handleDropdownCommand()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-adLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_operations_storage_facility_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/storage-facility/index.vue", "source_location": "L1"}, {"id": "storage_facility_index_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/storage-facility/index.vue", "source_location": "L945"}, {"id": "storage_facility_index_push", "label": "push()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/storage-facility/index.vue", "source_location": "L948"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_operations_storage_facility_index_vue", "target": "storage_facility_index_if", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/storage-facility/index.vue", "source_location": "L945", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_operations_storage_facility_index_vue", "target": "storage_facility_index_push", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/storage-facility/index.vue", "source_location": "L948", "weight": 1.0}], "raw_calls": [{"caller_nid": "storage_facility_index_if", "callee": "set", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/storage-facility/index.vue", "source_location": "L946"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "label": "DispatchTaskDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L1"}, {"id": "production_work_order_dispatchtaskdialog_resolvecreatedtaskid", "label": "resolveCreatedTaskId()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L264"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "vue_draggable_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L208", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_task", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L209", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_production_labels", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L210", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L211", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L212", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L213", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L214", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "production_work_order_dispatchtaskdialog_resolvecreatedtaskid", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L264", "weight": 1.0}], "raw_calls": [{"caller_nid": "production_work_order_dispatchtaskdialog_resolvecreatedtaskid", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L266"}, {"caller_nid": "production_work_order_dispatchtaskdialog_resolvecreatedtaskid", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L266"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "label": "qc-work-order.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L1"}, {"id": "api_qc_work_order_fetchqcworkorderlist", "label": "fetchQcWorkOrderList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L181"}, {"id": "api_qc_work_order_fetchqcworkorderdetail", "label": "fetchQcWorkOrderDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L201"}, {"id": "api_qc_work_order_fetchconfigureqcworkorder", "label": "fetchConfigureQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L207"}, {"id": "api_qc_work_order_fetchcreateqcworkorder", "label": "fetchCreateQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L224"}, {"id": "api_qc_work_order_fetchupdateqcworkorder", "label": "fetchUpdateQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L239"}, {"id": "api_qc_work_order_fetchdeleteqcworkorder", "label": "fetchDeleteQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L249"}, {"id": "api_qc_work_order_fetchoutboundqcdetail", "label": "fetchOutboundQcDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L322"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_http", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchqcworkorderlist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L181", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchqcworkorderdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L201", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchconfigureqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L207", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchcreateqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L224", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchupdateqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L239", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchdeleteqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L249", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchoutboundqcdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L322", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_qc_work_order_fetchqcworkorderlist", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L195"}, {"caller_nid": "api_qc_work_order_fetchqcworkorderdetail", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L202"}, {"caller_nid": "api_qc_work_order_fetchconfigureqcworkorder", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L218"}, {"caller_nid": "api_qc_work_order_fetchcreateqcworkoLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "label": "useTaskStepEditor.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L1"}, {"id": "production_work_order_usetaskstepeditor_parsetaskattachmentsfromurls", "label": "parseTaskAttachmentsFromUrls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L45"}, {"id": "production_work_order_usetaskstepeditor_toapiflag", "label": "toApiFlag()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L55"}, {"id": "production_work_order_usetaskstepeditor_fromapiflag", "label": "fromApiFlag()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L59"}, {"id": "production_work_order_usetaskstepeditor_normalizestepsubtables", "label": "normalizeStepSubTables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L62"}, {"id": "production_work_order_usetaskstepeditor_parseordernum", "label": "parseOrderNum()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L90"}, {"id": "production_work_order_usetaskstepeditor_usetaskstepeditor", "label": "useTaskStepEditor()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L97"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_task", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L19", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L20", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L29", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L30", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_sample_reception", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L31", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_equipment_select", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L32", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_productionworkordercardlist_vue", "label": "ProductionWorkOrderCardList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "label": "StepDetailPanel.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L1"}, {"id": "production_work_order_stepdetailpanel_for", "label": "for()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L987"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "target": "production_work_order_stepdetailpanel_for", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L987", "weight": 1.0}], "raw_calls": [{"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "push", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L989"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "decodeURIComponent", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L992"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "pop", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L992"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "split", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L992"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L992"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "label": "useTaskStepEditor.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L1"}, {"id": "production_work_order_usetaskstepeditor_parsetaskattachmentsfromurls", "label": "parseTaskAttachmentsFromUrls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L45"}, {"id": "production_work_order_usetaskstepeditor_toapiflag", "label": "toApiFlag()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L55"}, {"id": "production_work_order_usetaskstepeditor_fromapiflag", "label": "fromApiFlag()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L59"}, {"id": "production_work_order_usetaskstepeditor_normalizestepsubtables", "label": "normalizeStepSubTables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L62"}, {"id": "production_work_order_usetaskstepeditor_parseordernum", "label": "parseOrderNum()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L90"}, {"id": "production_work_order_usetaskstepeditor_usetaskstepeditor", "label": "useTaskStepEditor()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L97"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_task", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L19", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L20", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L29", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L30", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_sample_reception", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L31", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_equipment_select", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts", "source_location": "L32", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "label": "DispatchTaskDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L1"}, {"id": "production_work_order_dispatchtaskdialog_resolvecreatedtaskid", "label": "resolveCreatedTaskId()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L264"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "vue_draggable_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L208", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_task", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L209", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_production_labels", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L210", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L211", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L212", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_usetaskstepeditor", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L213", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L214", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchtaskdialog_vue", "target": "production_work_order_dispatchtaskdialog_resolvecreatedtaskid", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L264", "weight": 1.0}], "raw_calls": [{"caller_nid": "production_work_order_dispatchtaskdialog_resolvecreatedtaskid", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L266"}, {"caller_nid": "production_work_order_dispatchtaskdialog_resolvecreatedtaskid", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue", "source_location": "L266"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_production_work_order_card_meta_ts", "label": "production-work-order-card-meta.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L1"}, {"id": "utils_production_work_order_card_meta_formatoutboundschedulesortno", "label": "formatOutboundScheduleSortNo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L40"}, {"id": "utils_production_work_order_card_meta_formatoutboundscheduletotalcount", "label": "formatOutboundScheduleTotalCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L46"}, {"id": "utils_production_work_order_card_meta_parsereceptiontime", "label": "parseReceptionTime()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L52"}, {"id": "utils_production_work_order_card_meta_receptionover24hourslabel", "label": "receptionOver24HoursLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L59"}, {"id": "utils_production_work_order_card_meta_receptionover24hourstagtype", "label": "receptionOver24HoursTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L66"}, {"id": "utils_production_work_order_card_meta_protocolstatuslabelfortab", "label": "protocolStatusLabelForTab()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L73"}, {"id": "utils_production_work_order_card_meta_protocolstatustagtypefortab", "label": "protocolStatusTagTypeForTab()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L82"}, {"id": "utils_production_work_order_card_meta_buildinboundmetafields", "label": "buildInboundMetaFields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L91"}, {"id": "utils_production_work_order_card_meta_getcardmetaconfig", "label": "getCardMetaConfig()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L263"}, {"id": "utils_production_work_order_card_meta_getcardmetaconfigforlegacytab", "label": "getCardMetaConfigForLegacyTab()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L267"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_production_work_order_card_meta_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_production_work_order_card_meta_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_labels", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_production_work_order_card_meta_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_production_work_order_card_meta_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_production_work_order_card_meta_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_production_work_order_tabs", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts", "source_location": "L10", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_storage_slot_options_ts", "label": "storage-slot-options.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L1"}, {"id": "utils_storage_slot_options_getstoragefacilityordernum", "label": "getStorageFacilityOrderNum()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L16"}, {"id": "utils_storage_slot_options_getstorageslotordernum", "label": "getStorageSlotOrderNum()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L22"}, {"id": "utils_storage_slot_options_decodeslotlayoutorder", "label": "decodeSlotLayoutOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L31"}, {"id": "utils_storage_slot_options_parselegacyrowcolslotcode", "label": "parseLegacyRowColSlotCode()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L40"}, {"id": "utils_storage_slot_options_parsestorageslotcode", "label": "parseStorageSlotCode()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L47"}, {"id": "utils_storage_slot_options_buildnodecodepathfromflat", "label": "buildNodeCodePathFromFlat()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L54"}, {"id": "utils_storage_slot_options_buildfullslotcodefromflat", "label": "buildFullSlotCodeFromFlat()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L78"}, {"id": "utils_storage_slot_options_comparestoragefacilityslots", "label": "compareStorageFacilitySlots()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L90"}, {"id": "utils_storage_slot_options_sortstoragefacilityslots", "label": "sortStorageFacilitySlots()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L118"}, {"id": "utils_storage_slot_options_isstorageslotavailable", "label": "isStorageSlotAvailable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L122"}, {"id": "utils_storage_slot_options_collectleaffacilitynodesintreeorder", "label": "collectLeafFacilityNodesInTreeOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L131"}, {"id": "utils_storage_slot_options_mapslotstoselectoptions", "label": "mapSlotsToSelectOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L183"}, {"id": "utils_storage_slot_options_loadstorageslotselectoptions", "label": "loadStorageSlotSelectOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L211"}, {"id": "utils_storage_slot_options_remotesearchstorageslotselectoptions", "label": "remoteSearchStorageSlotSelectOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L249"}, {"id": "utils_storage_slot_options_ensurestorageslotsinoptions", "label": "ensureStorageSlotsInOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L274"}, {"id": "utils_storage_slot_options_filterstorageslotselectoptions", "label": "filterStorageSlotSelectOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L293"}, {"id": "utils_storage_slot_options_validateuniquestorageslotids", "label": "validateUniqueStorageSlotIds()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L307"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_storage_slot_options_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_tree_path", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_storage_slot_options_ts", "target": "users_wuzilong_work_00code_Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_task_ts", "label": "production-task.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L1"}, {"id": "api_production_task_scopequery", "label": "scopeQuery()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L5"}, {"id": "api_production_task_fetchcreateproductiontask", "label": "fetchCreateProductionTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L9"}, {"id": "api_production_task_fetchproductiontasklist", "label": "fetchProductionTaskList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L13"}, {"id": "api_production_task_fetchmyproductiontasks", "label": "fetchMyProductionTasks()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L31"}, {"id": "api_production_task_fetchforwardproductiontask", "label": "fetchForwardProductionTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L50"}, {"id": "api_production_task_fetchreassignproductiontask", "label": "fetchReassignProductionTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L62"}, {"id": "api_production_task_fetchdispatchproductiontasksteps", "label": "fetchDispatchProductionTaskSteps()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L72"}, {"id": "api_production_task_fetchproductiontaskdetail", "label": "fetchProductionTaskDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L90"}, {"id": "api_production_task_fetchupdateproductiontask", "label": "fetchUpdateProductionTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L94"}, {"id": "api_production_task_fetchupdateproductiontaskstatus", "label": "fetchUpdateProductionTaskStatus()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L98"}, {"id": "api_production_task_fetchdeleteproductiontask", "label": "fetchDeleteProductionTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L110"}, {"id": "api_production_task_fetchaddtaskstep", "label": "fetchAddTaskStep()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L114"}, {"id": "api_production_task_fetchupdatetaskstep", "label": "fetchUpdateTaskStep()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L126"}, {"id": "api_production_task_fetchdeletetaskstep", "label": "fetchDeleteTaskStep()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L139"}, {"id": "api_production_task_fetchreplacestepreagents", "label": "fetchReplaceStepReagents()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L150"}, {"id": "api_production_task_fetchreplacestepconsumables", "label": "fetchReplaceStepConsumables()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L163"}, {"id": "api_production_task_fetchreplacestepconfiguredreagents", "label": "fetchReplaceStepConfiguredReagents()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L176"}, {"id": "api_production_task_fetchreplacestepdatacollection", "label": "fetchReplaceStepDataCollection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L189"}, {"id": "api_production_task_fetchsettaskinputs", "label": "fetchSetTaskInputs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L202"}, {"id": "api_production_task_fetchsettaskoutputs", "label": "fetchSetTaskOutputs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts", "source_location": "L214"}, {"id": "api_production_task_fetchreordertasksteps", "label": "fetchReorderTaskSteps()", "file_type": "code", "source_file": "/Users/wuzilong/Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "label": "StepDetailPanel.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L1"}, {"id": "production_work_order_stepdetailpanel_for", "label": "for()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L987"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "target": "production_work_order_stepdetailpanel_for", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L987", "weight": 1.0}], "raw_calls": [{"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "push", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L989"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "decodeURIComponent", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L992"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "pop", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L992"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "split", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L992"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L992"}]}
|
||||
@@ -89,10 +89,7 @@ function protocolStatusTagTypeForTab(
|
||||
}
|
||||
|
||||
function buildInboundMetaFields(tabKey: ProductionWorkOrderTabKey): CardMetaField[] {
|
||||
const fields: CardMetaField[] = [
|
||||
{ label: '样本编码', getValue: (row) => row.sampleCode || '—' },
|
||||
{ label: '实验室入库编码', getValue: (row) => row.labStorageCode || '—' }
|
||||
]
|
||||
const fields: CardMetaField[] = []
|
||||
if (tabKey === 'inbound_cell_storage') {
|
||||
fields.push({
|
||||
label: '来源类型',
|
||||
@@ -120,6 +117,9 @@ function buildInboundMetaFields(tabKey: ProductionWorkOrderTabKey): CardMetaFiel
|
||||
},
|
||||
{ label: '接收时间', getValue: (row) => row.receptionTime || '—' },
|
||||
{ label: '创建时间', getValue: (row) => row.createTime || '—' },
|
||||
{ label: '工单号', getValue: (row) => row.workOrderNo || '—' },
|
||||
{ label: '样本编码', getValue: (row) => row.sampleCode || '—' },
|
||||
{ label: '实验室入库编码', getValue: (row) => row.labStorageCode || '—' },
|
||||
{
|
||||
label: '备注',
|
||||
getValue: (row) => row.remark || '—',
|
||||
|
||||
@@ -25,11 +25,29 @@ export function getStorageSlotOrderNum(slot: Record<string, unknown>): number {
|
||||
return Number.isFinite(parsed) ? parsed : 0
|
||||
}
|
||||
|
||||
/** 解析 slotCode「{prefix}{row}-{col}」 */
|
||||
export function parseStorageSlotCode(code: string): { row: number; col: number } | null {
|
||||
/** 货架布局 order_num 步长(row * STRIDE + col) */
|
||||
export const SLOT_LAYOUT_ROW_STRIDE = 1000
|
||||
|
||||
export function decodeSlotLayoutOrder(orderNum: number): { row: number; col: number } {
|
||||
const order = Number(orderNum) || 0
|
||||
if (order >= SLOT_LAYOUT_ROW_STRIDE) {
|
||||
return { row: Math.trunc(order / SLOT_LAYOUT_ROW_STRIDE), col: order % SLOT_LAYOUT_ROW_STRIDE }
|
||||
}
|
||||
return { row: 0, col: order }
|
||||
}
|
||||
|
||||
/** 解析旧版 slotCode「{prefix}{row}-{col}」;纯数字序号返回 null */
|
||||
export function parseLegacyRowColSlotCode(code: string): { row: number; col: number; prefix: string } | null {
|
||||
const match = (code || '').trim().match(/^(.*?)(\d+)-(\d+)$/)
|
||||
if (!match) return null
|
||||
return { row: parseInt(match[2], 10), col: parseInt(match[3], 10) }
|
||||
return { prefix: match[1], row: parseInt(match[2], 10), col: parseInt(match[3], 10) }
|
||||
}
|
||||
|
||||
/** @deprecated 兼容旧调用;新数据请用 decodeSlotLayoutOrder + 序号 slotCode */
|
||||
export function parseStorageSlotCode(code: string): { row: number; col: number } | null {
|
||||
const legacy = parseLegacyRowColSlotCode(code)
|
||||
if (legacy) return { row: legacy.row, col: legacy.col }
|
||||
return null
|
||||
}
|
||||
|
||||
/** 从根到节点的 node_code 路径,用 `-` 连接 */
|
||||
@@ -68,17 +86,25 @@ export function buildFullSlotCodeFromFlat(
|
||||
return local || path
|
||||
}
|
||||
|
||||
/** 盒内格位:order_num → 行 → 列 → 编码 */
|
||||
/** 盒内格位:order_num → 布局行列 → 序号 */
|
||||
export function compareStorageFacilitySlots(
|
||||
a: Record<string, unknown>,
|
||||
b: Record<string, unknown>
|
||||
): number {
|
||||
const orderDiff = getStorageSlotOrderNum(a) - getStorageSlotOrderNum(b)
|
||||
if (orderDiff !== 0) return orderDiff
|
||||
const oa = getStorageSlotOrderNum(a)
|
||||
const ob = getStorageSlotOrderNum(b)
|
||||
if (oa >= SLOT_LAYOUT_ROW_STRIDE && ob >= SLOT_LAYOUT_ROW_STRIDE) {
|
||||
const da = decodeSlotLayoutOrder(oa)
|
||||
const db = decodeSlotLayoutOrder(ob)
|
||||
if (da.row !== db.row) return da.row - db.row
|
||||
if (da.col !== db.col) return da.col - db.col
|
||||
}
|
||||
const codeA = String(a.slotCode ?? a.slot_code ?? '')
|
||||
const codeB = String(b.slotCode ?? b.slot_code ?? '')
|
||||
const pa = parseStorageSlotCode(codeA)
|
||||
const pb = parseStorageSlotCode(codeB)
|
||||
const pa = parseLegacyRowColSlotCode(codeA)
|
||||
const pb = parseLegacyRowColSlotCode(codeB)
|
||||
if (pa && pb) {
|
||||
if (pa.row !== pb.row) return pa.row - pb.row
|
||||
if (pa.col !== pb.col) return pa.col - pb.col
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
<div class="shelf-cells">
|
||||
<div
|
||||
class="shelf-cell shelf-cell--add"
|
||||
title="在此行前面增加格子"
|
||||
title="在此行末尾增加格子"
|
||||
@click="handleAddSlotInRow(ri)"
|
||||
>
|
||||
<span class="add-icon">+</span>
|
||||
@@ -215,11 +215,11 @@
|
||||
<el-form-item label="节点名称" prop="nodeName">
|
||||
<el-input v-model="nodeFormData.nodeName" placeholder="请输入节点名称" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="nodeCode">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
节点编号<span class="form-label-tip">单段字母或数字,不含连字符</span>
|
||||
节点编号<span class="form-label-tip">可选</span>
|
||||
</template>
|
||||
<el-input v-model="nodeFormData.nodeCode" placeholder="如 1、03、A" />
|
||||
<el-input v-model="nodeFormData.nodeCode" placeholder="可不填" />
|
||||
</el-form-item>
|
||||
<el-form-item label="节点类型">
|
||||
<el-select v-model="nodeFormData.nodeType" placeholder="请选择节点类型">
|
||||
@@ -278,15 +278,17 @@
|
||||
<el-form
|
||||
ref="slotFormRef"
|
||||
:model="slotFormData"
|
||||
:rules="slotFormRules"
|
||||
label-position="top"
|
||||
class="storage-dialog-form"
|
||||
scroll-to-error
|
||||
:scroll-into-view-options="{ behavior: 'smooth', block: 'center' }"
|
||||
>
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="本地编码(行-列)" prop="slotCode">
|
||||
<el-input v-model="slotFormData.slotCode" placeholder="如 1-3" />
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
本地编码(序号)<span class="form-label-tip">可选</span>
|
||||
</template>
|
||||
<el-input v-model="slotFormData.slotCode" placeholder="可不填" />
|
||||
</el-form-item>
|
||||
<el-form-item label="格子状态">
|
||||
<el-select v-model="slotFormData.slotStatus" placeholder="请选择状态">
|
||||
@@ -357,9 +359,9 @@
|
||||
将生成 <strong>{{ batchForm.rows * batchForm.cols }}</strong> 个格子({{
|
||||
batchForm.rows
|
||||
}}
|
||||
行 × {{ batchForm.cols }} 列)
|
||||
行 × {{ batchForm.cols }} 列),本地序号从 <strong>1</strong> 起依次编号
|
||||
<template v-if="batchPreviewCode">
|
||||
,示例编号:<strong>{{ batchPreviewCode }}</strong>
|
||||
,示例完整编号:<strong>{{ batchPreviewCode }}</strong>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -625,22 +627,24 @@
|
||||
<el-form
|
||||
ref="occupancySlotFormRef"
|
||||
:model="occupancySlotFormData"
|
||||
:rules="occupancySlotFormRules"
|
||||
label-position="top"
|
||||
class="storage-dialog-form"
|
||||
scroll-to-error
|
||||
:scroll-into-view-options="{ behavior: 'smooth', block: 'center' }"
|
||||
>
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="完整编号" class="form-col-span-2">
|
||||
<div class="form-grid-3">
|
||||
<el-form-item label="完整编号">
|
||||
<el-input
|
||||
:model-value="currentSlot?.fullSlotCode || '—'"
|
||||
readonly
|
||||
placeholder="保存后自动生成"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="本地编码(行-列)" prop="slotCode">
|
||||
<el-input v-model="occupancySlotFormData.slotCode" placeholder="如 1-3" />
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
本地编码(序号)<span class="form-label-tip">可选</span>
|
||||
</template>
|
||||
<el-input v-model="occupancySlotFormData.slotCode" placeholder="可不填" />
|
||||
</el-form-item>
|
||||
<el-form-item label="格子状态">
|
||||
<el-select v-model="occupancySlotFormData.slotStatus" placeholder="请选择状态">
|
||||
@@ -734,7 +738,13 @@
|
||||
fetchRemoveOccupancy
|
||||
} from '@/api/admin'
|
||||
import { buildTreePathLabelFromFlat } from '@/utils/tree-path'
|
||||
import { buildNodeCodePathFromFlat } from '@/utils/storage-slot-options'
|
||||
import {
|
||||
buildNodeCodePathFromFlat,
|
||||
decodeSlotLayoutOrder,
|
||||
getStorageSlotOrderNum,
|
||||
parseLegacyRowColSlotCode,
|
||||
SLOT_LAYOUT_ROW_STRIDE
|
||||
} from '@/utils/storage-slot-options'
|
||||
|
||||
defineOptions({ name: 'StorageFacility' })
|
||||
|
||||
@@ -877,7 +887,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 货架行计算(按 slotCode 中的行号分组) ====================
|
||||
// ==================== 货架行计算(按 order_num 布局分组) ====================
|
||||
const batchForm = reactive({
|
||||
rows: 4,
|
||||
cols: 6
|
||||
@@ -886,23 +896,51 @@
|
||||
const batchPreviewCode = computed(() => {
|
||||
if (!selectedNode.value?.id) return ''
|
||||
const path = buildNodeCodePathFromFlat(selectedNode.value.id, flatList.value)
|
||||
if (!path) return ''
|
||||
return `${path}-1-1`
|
||||
const total = Number(batchForm.rows) * Number(batchForm.cols)
|
||||
const local = total <= 1 ? '1' : `1…${total}`
|
||||
return path ? `${path}-${local}` : local
|
||||
})
|
||||
|
||||
/** 解析 slotCode "{prefix}{row}-{col}" 格式,提取行号和列号 */
|
||||
const parseSlotCode = (code: string): { prefix: string; row: number; col: number } | null => {
|
||||
const match = code.match(/^(.*?)(\d+)-(\d+)$/)
|
||||
if (!match) return null
|
||||
return { prefix: match[1], row: parseInt(match[2], 10), col: parseInt(match[3], 10) }
|
||||
}
|
||||
const sortSlotsForShelf = (slots: any[]) =>
|
||||
[...slots].sort((a, b) => {
|
||||
const oa = getStorageSlotOrderNum(a)
|
||||
const ob = getStorageSlotOrderNum(b)
|
||||
if (oa !== ob) return oa - ob
|
||||
const na = parseInt(String(a.slotCode || ''), 10) || 0
|
||||
const nb = parseInt(String(b.slotCode || ''), 10) || 0
|
||||
return na - nb
|
||||
})
|
||||
|
||||
const shelfRows = computed(() => {
|
||||
const sorted = sortSlotsForShelf(slotList.value)
|
||||
const hasLayoutOrder = sorted.some((slot) => getStorageSlotOrderNum(slot) >= SLOT_LAYOUT_ROW_STRIDE)
|
||||
|
||||
if (hasLayoutOrder) {
|
||||
const rowMap = new Map<number, any[]>()
|
||||
for (const slot of sorted) {
|
||||
const { row } = decodeSlotLayoutOrder(getStorageSlotOrderNum(slot))
|
||||
if (!rowMap.has(row)) rowMap.set(row, [])
|
||||
rowMap.get(row)!.push(slot)
|
||||
}
|
||||
return [...rowMap.entries()]
|
||||
.sort(([a], [b]) => a - b)
|
||||
.map(([rowNum, cells], index) => ({
|
||||
label: String(index + 1),
|
||||
rowNum,
|
||||
prefix: '',
|
||||
cells: cells.sort(
|
||||
(a, b) =>
|
||||
decodeSlotLayoutOrder(getStorageSlotOrderNum(a)).col -
|
||||
decodeSlotLayoutOrder(getStorageSlotOrderNum(b)).col
|
||||
)
|
||||
}))
|
||||
}
|
||||
|
||||
// 兼容旧版「行-列」本地编码
|
||||
const rowMap = new Map<number, { prefix: string; cells: any[] }>()
|
||||
const ungrouped: any[] = []
|
||||
|
||||
for (const slot of slotList.value) {
|
||||
const parsed = parseSlotCode(slot.slotCode || '')
|
||||
for (const slot of sorted) {
|
||||
const parsed = parseLegacyRowColSlotCode(slot.slotCode || '')
|
||||
if (parsed) {
|
||||
if (!rowMap.has(parsed.row)) {
|
||||
rowMap.set(parsed.row, { prefix: parsed.prefix, cells: [] })
|
||||
@@ -913,14 +951,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 按行号排序,每个行内按列号排序
|
||||
const result: { label: string; cells: any[]; rowNum: number; prefix: string }[] = []
|
||||
const sortedEntries = [...rowMap.entries()].sort(([a], [b]) => a - b)
|
||||
|
||||
for (const [rowNum, data] of sortedEntries) {
|
||||
for (const [rowNum, data] of [...rowMap.entries()].sort(([a], [b]) => a - b)) {
|
||||
data.cells.sort((a, b) => {
|
||||
const pa = parseSlotCode(a.slotCode || '')
|
||||
const pb = parseSlotCode(b.slotCode || '')
|
||||
const pa = parseLegacyRowColSlotCode(a.slotCode || '')
|
||||
const pb = parseLegacyRowColSlotCode(b.slotCode || '')
|
||||
return (pa?.col ?? 0) - (pb?.col ?? 0)
|
||||
})
|
||||
result.push({
|
||||
@@ -931,7 +966,6 @@
|
||||
})
|
||||
}
|
||||
|
||||
// 无法解析编码的格子归入末尾
|
||||
if (ungrouped.length > 0) {
|
||||
result.push({
|
||||
label: String(result.length + 1),
|
||||
@@ -962,22 +996,8 @@
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const validateNodeCode = (_rule: unknown, value: string, callback: (err?: Error) => void) => {
|
||||
const v = (value || '').trim()
|
||||
if (!v) {
|
||||
callback(new Error('请输入节点编号'))
|
||||
return
|
||||
}
|
||||
if (!/^[A-Za-z0-9]+$/.test(v)) {
|
||||
callback(new Error('编号只能包含字母和数字,不能含连字符'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
const nodeFormRules = {
|
||||
nodeName: [{ required: true, message: '请输入节点名称', trigger: 'blur' }],
|
||||
nodeCode: [{ required: true, validator: validateNodeCode, trigger: 'blur' }]
|
||||
nodeName: [{ required: true, message: '请输入节点名称', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
const handleAddRoot = () => {
|
||||
@@ -1106,10 +1126,6 @@
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const slotFormRules = {
|
||||
slotCode: [{ required: true, message: '请输入格子编码', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
const handleEditSlot = (row: any) => {
|
||||
isSlotEdit.value = true
|
||||
slotDialogTitle.value = '编辑格子'
|
||||
@@ -1218,25 +1234,17 @@
|
||||
// ==================== 单独新增行/格子 ====================
|
||||
const addSlotLoading = ref(false)
|
||||
|
||||
/** 在指定行前面追加一个格子 */
|
||||
/** 在指定行末尾追加一个格子 */
|
||||
const handleAddSlotInRow = async (rowIndex: number) => {
|
||||
if (!selectedNode.value?.id || addSlotLoading.value) return
|
||||
const row = shelfRows.value[rowIndex]
|
||||
if (!row) return
|
||||
|
||||
// 计算该行下一个列号
|
||||
let nextCol = 1
|
||||
for (const cell of row.cells) {
|
||||
const parsed = parseSlotCode(cell.slotCode || '')
|
||||
if (parsed && parsed.col >= nextCol) nextCol = parsed.col + 1
|
||||
}
|
||||
|
||||
const slotCode = `${row.rowNum}-${nextCol}`
|
||||
addSlotLoading.value = true
|
||||
try {
|
||||
await fetchCreateStorageSlot({
|
||||
facilityNodeId: selectedNode.value.id,
|
||||
slotCode,
|
||||
atRowNum: row.rowNum,
|
||||
slotStatus: '空'
|
||||
})
|
||||
ElMessage.success('新增格子成功')
|
||||
@@ -1356,9 +1364,6 @@
|
||||
slotStatus: '空',
|
||||
remark: ''
|
||||
})
|
||||
const occupancySlotFormRules = {
|
||||
slotCode: [{ required: true, message: '请输入格子编码', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
const handleOccupancySlotSave = async () => {
|
||||
await occupancySlotFormRef.value?.validate?.()
|
||||
|
||||
+93
-28
@@ -30,23 +30,55 @@
|
||||
v-loading="optionsLoading"
|
||||
>
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="细胞产品" prop="cellProductId" class="form-col-span-2">
|
||||
<el-form-item label="生产任务" prop="taskId" class="form-col-span-2">
|
||||
<el-select
|
||||
v-model="form.cellProductId"
|
||||
placeholder="请选择细胞产品"
|
||||
v-model="form.taskId"
|
||||
placeholder="请选择生产任务"
|
||||
filterable
|
||||
style="width: 100%"
|
||||
:disabled="!productOptions.length"
|
||||
:disabled="!productionTasks.length"
|
||||
@change="handleTaskChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in productOptions"
|
||||
v-for="opt in taskOptions"
|
||||
:key="opt.taskId"
|
||||
:label="formatTaskOptionLabel(opt)"
|
||||
:value="opt.taskId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="步骤产出物" prop="stepOutputId" class="form-col-span-2">
|
||||
<template #label
|
||||
>步骤产出物<span class="form-label-tip">类型为有效物且已填写条码</span></template
|
||||
>
|
||||
<el-select
|
||||
v-model="form.stepOutputId"
|
||||
placeholder="请选择步骤产出物"
|
||||
filterable
|
||||
style="width: 100%"
|
||||
:disabled="!form.taskId || !filteredOutputOptions.length"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in filteredOutputOptions"
|
||||
:key="opt.id"
|
||||
:label="formatProductOptionLabel(opt)"
|
||||
:label="formatStepOutputOptionLabel(opt)"
|
||||
:value="opt.id"
|
||||
/>
|
||||
</el-select>
|
||||
<p v-if="!optionsLoading && !productOptions.length" class="hint-muted">
|
||||
暂无产出细胞产品,请先完成生产任务并录入输出。
|
||||
<p v-if="!optionsLoading && !productionTasks.length" class="hint-muted">
|
||||
该生产工单下暂无生产任务,请先派发生产任务。
|
||||
</p>
|
||||
<p
|
||||
v-else-if="!optionsLoading && productionTasks.length && !dispatchOptions.length"
|
||||
class="hint-muted"
|
||||
>
|
||||
暂无可派发产出物,请先在生产任务执行中录入类型为「有效物」且含条码的步骤产出。
|
||||
</p>
|
||||
<p
|
||||
v-else-if="!optionsLoading && form.taskId && !filteredOutputOptions.length"
|
||||
class="hint-muted"
|
||||
>
|
||||
该任务下暂无符合条件的步骤产出物。
|
||||
</p>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" class="form-col-span-2">
|
||||
@@ -69,7 +101,6 @@
|
||||
class="btn-main"
|
||||
type="primary"
|
||||
:loading="submitting"
|
||||
:disabled="!productOptions.length"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
<el-icon><Check /></el-icon>确定
|
||||
@@ -83,13 +114,20 @@
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Close, Check } from '@element-plus/icons-vue'
|
||||
import { fetchProductionTaskList } from '@/api/production-task'
|
||||
import {
|
||||
fetchProductionWorkOrderCellProductOptions,
|
||||
fetchProductionWorkOrderQcDispatchOptions,
|
||||
fetchCreateQcFromProduction,
|
||||
type ProductionWorkOrderItem,
|
||||
type ProductionCellProductOption
|
||||
type ProductionQcDispatchOption
|
||||
} from '@/api/production-work-order'
|
||||
|
||||
interface ProductionTaskOption {
|
||||
taskId: string
|
||||
taskNo?: string
|
||||
taskName?: string
|
||||
}
|
||||
|
||||
defineOptions({ name: 'DispatchQcWorkOrderDialog' })
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -108,41 +146,70 @@
|
||||
})
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const form = reactive({ cellProductId: '', remark: '' })
|
||||
const form = reactive({ taskId: '', stepOutputId: '', remark: '' })
|
||||
const rules: FormRules = {
|
||||
cellProductId: [{ required: true, message: '请选择细胞产品', trigger: 'change' }]
|
||||
taskId: [{ required: true, message: '请选择生产任务', trigger: 'change' }],
|
||||
stepOutputId: [{ required: true, message: '请选择步骤产出物', trigger: 'change' }]
|
||||
}
|
||||
const productOptions = ref<ProductionCellProductOption[]>([])
|
||||
const dispatchOptions = ref<ProductionQcDispatchOption[]>([])
|
||||
const productionTasks = ref<ProductionTaskOption[]>([])
|
||||
const optionsLoading = ref(false)
|
||||
const submitting = ref(false)
|
||||
|
||||
function formatProductOptionLabel(opt: ProductionCellProductOption) {
|
||||
const taskOptions = computed(() => productionTasks.value)
|
||||
|
||||
const filteredOutputOptions = computed(() =>
|
||||
dispatchOptions.value.filter((opt) => opt.taskId === form.taskId)
|
||||
)
|
||||
|
||||
function formatTaskOptionLabel(opt: ProductionTaskOption) {
|
||||
const parts = [opt.taskNo, opt.taskName].filter(Boolean)
|
||||
return parts.join(' · ') || opt.taskId || '—'
|
||||
}
|
||||
|
||||
function formatStepOutputOptionLabel(opt: ProductionQcDispatchOption) {
|
||||
const parts = [
|
||||
opt.productCode,
|
||||
opt.productName,
|
||||
opt.productTypeName ? `(${opt.productTypeName})` : '',
|
||||
opt.passage ? `P${opt.passage}` : '',
|
||||
opt.storageSlotName ? `@${opt.storageSlotName}` : ''
|
||||
opt.processName,
|
||||
opt.outputName,
|
||||
opt.outputBarcode ? `条码 ${opt.outputBarcode}` : ''
|
||||
].filter(Boolean)
|
||||
const base = parts.join(' ') || opt.id
|
||||
return opt.taskNo ? `${base} · ${opt.taskNo}` : base
|
||||
return parts.join(' · ') || opt.id
|
||||
}
|
||||
|
||||
function handleTaskChange() {
|
||||
form.stepOutputId = ''
|
||||
formRef.value?.clearValidate(['stepOutputId'])
|
||||
}
|
||||
|
||||
async function loadOptions() {
|
||||
if (!props.workOrderRow?.id) {
|
||||
productOptions.value = []
|
||||
dispatchOptions.value = []
|
||||
productionTasks.value = []
|
||||
return
|
||||
}
|
||||
optionsLoading.value = true
|
||||
try {
|
||||
productOptions.value = (await fetchProductionWorkOrderCellProductOptions(props.workOrderRow.id)) || []
|
||||
const [dispatchRes, tasksRes] = await Promise.all([
|
||||
fetchProductionWorkOrderQcDispatchOptions(props.workOrderRow.id),
|
||||
fetchProductionTaskList({ workOrderId: props.workOrderRow.id, pageSize: 100 })
|
||||
])
|
||||
dispatchOptions.value = dispatchRes || []
|
||||
productionTasks.value = (tasksRes?.list || []).map((task: Record<string, any>) => ({
|
||||
taskId: task.id,
|
||||
taskNo: task.taskNo,
|
||||
taskName: task.taskName
|
||||
}))
|
||||
if (productionTasks.value.length === 1) {
|
||||
form.taskId = productionTasks.value[0].taskId
|
||||
}
|
||||
} finally {
|
||||
optionsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
form.cellProductId = ''
|
||||
form.taskId = ''
|
||||
form.stepOutputId = ''
|
||||
form.remark = ''
|
||||
formRef.value?.clearValidate()
|
||||
}
|
||||
@@ -157,10 +224,8 @@
|
||||
await formRef.value?.validate()
|
||||
submitting.value = true
|
||||
try {
|
||||
const selected = productOptions.value.find((o) => o.id === form.cellProductId)
|
||||
await fetchCreateQcFromProduction(props.workOrderRow.id, {
|
||||
cellProductId: form.cellProductId,
|
||||
productionTaskId: selected?.taskId,
|
||||
productionStepOutputId: form.stepOutputId,
|
||||
remark: form.remark || undefined
|
||||
})
|
||||
ElMessage.success(
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
<!-- 生产任务 · 工艺步骤派发 / 调整派发 -->
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
width="860px"
|
||||
class="dialog-form-layout dispatch-step-dialog"
|
||||
align-center
|
||||
modal-class="protocol-dialog-mask"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose"
|
||||
>
|
||||
<p v-if="taskName" class="dispatch-step-dialog__task-name">任务:{{ taskName }}</p>
|
||||
<el-table v-loading="loading" :data="rows" stripe class="list-table dispatch-step-table">
|
||||
<el-table-column label="序号" min-width="64" align="center">
|
||||
<template #default="{ $index }">{{ $index + 1 }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="processName" label="工序名称" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="负责人" min-width="220">
|
||||
<template #default="{ row }">
|
||||
<el-select
|
||||
v-model="row.assigneeUserIds"
|
||||
multiple
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
placeholder="选择负责人"
|
||||
style="width: 100%"
|
||||
:loading="userLoading"
|
||||
:remote-method="remoteSearchUsers"
|
||||
@visible-change="onUserSelectVisible"
|
||||
>
|
||||
<el-option
|
||||
v-for="u in mergedUserOptions(row)"
|
||||
:key="u.id"
|
||||
:label="`${u.nickName}(${u.userNo})`"
|
||||
:value="u.id"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="计划开始时间" min-width="200">
|
||||
<template #default="{ row }">
|
||||
<el-date-picker
|
||||
v-model="row.plannedStartTime"
|
||||
type="datetime"
|
||||
placeholder="可选"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
value-format="YYYY-MM-DDTHH:mm:00"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<p class="form-label-tip dispatch-step-dialog__hint">至少为一个步骤指定负责人;未派发的步骤仅管理员可见。</p>
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>取消
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" :loading="submitting" @click="handleSubmit">
|
||||
<el-icon><Check /></el-icon>确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Close, Check } from '@element-plus/icons-vue'
|
||||
import { fetchUserList } from '@/api/admin'
|
||||
import { fetchProductionTaskDetail, fetchDispatchProductionTaskSteps } from '@/api/production-task'
|
||||
|
||||
defineOptions({ name: 'DispatchStepDialog' })
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean
|
||||
taskId: string
|
||||
taskName?: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', val: boolean): void
|
||||
(e: 'success'): void
|
||||
}>()
|
||||
|
||||
const dialogVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: (val) => emit('update:visible', val)
|
||||
})
|
||||
|
||||
const dialogTitle = computed(() => (hasAnyAssignee.value ? '调整步骤派发' : '步骤派发'))
|
||||
|
||||
const loading = ref(false)
|
||||
const submitting = ref(false)
|
||||
const userLoading = ref(false)
|
||||
const userOptions = ref<Api.User.UserItem[]>([])
|
||||
|
||||
type StepDispatchRow = {
|
||||
stepId: string
|
||||
processName: string
|
||||
assigneeUserIds: string[]
|
||||
plannedStartTime: string | null
|
||||
presetUsers: Api.User.UserItem[]
|
||||
}
|
||||
|
||||
const rows = ref<StepDispatchRow[]>([])
|
||||
const hasAnyAssignee = ref(false)
|
||||
|
||||
function mergedUserOptions(row: StepDispatchRow) {
|
||||
const map = new Map<string, Api.User.UserItem>()
|
||||
for (const u of userOptions.value) map.set(u.id, u)
|
||||
for (const u of row.presetUsers) map.set(u.id, u)
|
||||
return [...map.values()]
|
||||
}
|
||||
|
||||
async function remoteSearchUsers(query: string) {
|
||||
userLoading.value = true
|
||||
try {
|
||||
const res = await fetchUserList({
|
||||
page: 1,
|
||||
pageSize: 50,
|
||||
keyword: query?.trim() || undefined,
|
||||
status: '1'
|
||||
})
|
||||
userOptions.value = res.list || []
|
||||
} catch {
|
||||
userOptions.value = []
|
||||
} finally {
|
||||
userLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onUserSelectVisible(visible: boolean) {
|
||||
if (visible) void remoteSearchUsers('')
|
||||
}
|
||||
|
||||
async function loadSteps() {
|
||||
if (!props.taskId) {
|
||||
rows.value = []
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
const detail = await fetchProductionTaskDetail(props.taskId)
|
||||
const steps = (detail?.steps || []) as Record<string, any>[]
|
||||
hasAnyAssignee.value = steps.some((s) => (s.assigneeUserIds || []).length > 0)
|
||||
rows.value = steps.map((s) => ({
|
||||
stepId: s.id,
|
||||
processName: s.processName || '未命名步骤',
|
||||
assigneeUserIds: [...(s.assigneeUserIds || [])],
|
||||
plannedStartTime: s.plannedStartTime || null,
|
||||
presetUsers: (s.assignees || []).map((a: Record<string, any>) => ({
|
||||
id: a.userId,
|
||||
nickName: a.nickName,
|
||||
userNo: a.userNo
|
||||
})) as Api.User.UserItem[]
|
||||
}))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
dialogVisible.value = false
|
||||
rows.value = []
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!props.taskId) return
|
||||
const payload = rows.value
|
||||
.filter((r) => r.assigneeUserIds.length > 0)
|
||||
.map((r) => ({
|
||||
stepId: r.stepId,
|
||||
assigneeUserIds: r.assigneeUserIds,
|
||||
plannedStartTime: r.plannedStartTime
|
||||
}))
|
||||
if (!payload.length) {
|
||||
ElMessage.warning('请至少为一个步骤指定负责人')
|
||||
return
|
||||
}
|
||||
submitting.value = true
|
||||
try {
|
||||
await fetchDispatchProductionTaskSteps(props.taskId, { steps: payload })
|
||||
ElMessage.success('步骤派发成功')
|
||||
emit('success')
|
||||
handleClose()
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
if (val) {
|
||||
void remoteSearchUsers('')
|
||||
void loadSteps()
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dispatch-step-dialog__task-name {
|
||||
margin: 0 0 12px;
|
||||
font-size: 14px;
|
||||
color: var(--mint-text-muted, #64748b);
|
||||
}
|
||||
|
||||
.dispatch-step-dialog__hint {
|
||||
display: block;
|
||||
margin-top: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -33,27 +33,6 @@
|
||||
<el-form-item label="任务名称" prop="taskName" class="form-col-span-2">
|
||||
<el-input v-model="form.taskName" placeholder="请输入任务名称" maxlength="200" />
|
||||
</el-form-item>
|
||||
<el-form-item label="负责人" prop="assigneeUserId" class="form-col-span-2">
|
||||
<el-select
|
||||
v-model="form.assigneeUserId"
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
clearable
|
||||
placeholder="输入姓名检索负责人"
|
||||
style="width: 100%"
|
||||
:loading="userLoading"
|
||||
:remote-method="remoteSearchUsers"
|
||||
@visible-change="onUserSelectVisible"
|
||||
>
|
||||
<el-option
|
||||
v-for="u in userOptions"
|
||||
:key="u.id"
|
||||
:label="`${u.nickName}(${u.userNo})`"
|
||||
:value="u.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="工艺路线" class="form-col-span-2">
|
||||
<template #label
|
||||
>工艺路线<span class="form-label-tip">可选,不选则从零创建工艺过程</span></template
|
||||
@@ -228,7 +207,6 @@
|
||||
import { Rank, Plus, CopyDocument, Delete, Close, Check } from '@element-plus/icons-vue'
|
||||
import { VueDraggable as draggable } from 'vue-draggable-plus'
|
||||
import { fetchCreateProductionTask } from '@/api/production-task'
|
||||
import { fetchUserList } from '@/api/admin'
|
||||
import { productionTaskTypeForWorkOrder } from '@/utils/production-labels'
|
||||
import { fetchProcessRouteList } from '@/api/production'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
@@ -247,6 +225,7 @@
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', val: boolean): void
|
||||
(e: 'success'): void
|
||||
(e: 'needStepDispatch', payload: { taskId: string; taskName: string }): void
|
||||
}>()
|
||||
|
||||
const dialogVisible = computed({
|
||||
@@ -260,19 +239,15 @@
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const routeOptions = ref<any[]>([])
|
||||
const userOptions = ref<Api.User.UserItem[]>([])
|
||||
const userLoading = ref(false)
|
||||
const routeLoading = ref(false)
|
||||
const form = reactive({
|
||||
taskName: '',
|
||||
assigneeUserId: '',
|
||||
routeId: '',
|
||||
description: '',
|
||||
remark: ''
|
||||
})
|
||||
const rules: FormRules = {
|
||||
taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
|
||||
assigneeUserId: [{ required: true, message: '请选择负责人', trigger: 'change' }]
|
||||
taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
const editor = useTaskStepEditor()
|
||||
@@ -297,27 +272,6 @@
|
||||
return editor.initEditor(taskId, options)
|
||||
}
|
||||
|
||||
async function remoteSearchUsers(query: string) {
|
||||
userLoading.value = true
|
||||
try {
|
||||
const res = await fetchUserList({
|
||||
page: 1,
|
||||
pageSize: 50,
|
||||
keyword: query?.trim() || undefined,
|
||||
status: '1'
|
||||
})
|
||||
userOptions.value = res.list || []
|
||||
} catch {
|
||||
userOptions.value = []
|
||||
} finally {
|
||||
userLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onUserSelectVisible(visible: boolean) {
|
||||
if (visible) void remoteSearchUsers('')
|
||||
}
|
||||
|
||||
async function remoteSearchRoutes(query: string) {
|
||||
routeLoading.value = true
|
||||
try {
|
||||
@@ -344,7 +298,6 @@
|
||||
phase.value = 'form'
|
||||
createdTaskName.value = ''
|
||||
form.taskName = ''
|
||||
form.assigneeUserId = ''
|
||||
form.routeId = ''
|
||||
form.description = ''
|
||||
form.remark = ''
|
||||
@@ -361,7 +314,6 @@
|
||||
work_order_id: props.workOrderRow.id,
|
||||
task_type: productionTaskTypeForWorkOrder(props.workOrderRow.workOrderType),
|
||||
task_name: form.taskName,
|
||||
assigneeUserId: form.assigneeUserId,
|
||||
route_id: form.routeId,
|
||||
description: form.description || undefined,
|
||||
remark: form.remark || undefined
|
||||
@@ -379,6 +331,9 @@
|
||||
} else {
|
||||
ElMessage.success('任务已创建,可编辑步骤')
|
||||
}
|
||||
if (expectSteps && stepCount > 0) {
|
||||
emit('needStepDispatch', { taskId, taskName: form.taskName })
|
||||
}
|
||||
emit('success')
|
||||
} catch {
|
||||
/* global error handling */
|
||||
@@ -399,7 +354,6 @@
|
||||
// 新建任务:走阶段一表单(已在编辑阶段时不重置,避免生成任务后被 watch 打回表单)
|
||||
phase.value = 'form'
|
||||
form.taskName = ''
|
||||
form.assigneeUserId = ''
|
||||
form.routeId = ''
|
||||
form.description = ''
|
||||
form.remark = ''
|
||||
@@ -410,7 +364,7 @@
|
||||
form.taskName = `${props.workOrderRow.workOrderNo}任务`
|
||||
}
|
||||
void remoteSearchRoutes('')
|
||||
void remoteSearchUsers('')
|
||||
void editor.remoteSearchStepAssigneeUsers('')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+89
-18
@@ -14,7 +14,7 @@
|
||||
@change="(val) => handleCardSelect(row, Boolean(val))"
|
||||
/>
|
||||
<span class="production-work-order-card__index">{{ cardIndex(idx) }}</span>
|
||||
<span class="production-work-order-card__no">{{ row.workOrderNo || '—' }}</span>
|
||||
<span class="production-work-order-card__no">{{ cardTitleLabel(row) }}</span>
|
||||
<el-tag :type="productionWoStatusTag(row.workOrderStatus).type" size="small">
|
||||
{{ productionWoStatusTag(row.workOrderStatus).label }}
|
||||
</el-tag>
|
||||
@@ -174,18 +174,38 @@
|
||||
</section>
|
||||
</div>
|
||||
</header>
|
||||
<QcWorkOrderProtocolPaymentPanel
|
||||
v-if="showProtocolFeeSummary(row)"
|
||||
:summary="row.paymentSummary"
|
||||
compact
|
||||
class="production-work-order-card__fee-in-head"
|
||||
/>
|
||||
<QcWorkOrderFeeSummaryBar
|
||||
v-if="showOutboundFeeSummary(row)"
|
||||
variant="basic-experiment"
|
||||
:fee-summary="row.feeSummary"
|
||||
class="production-work-order-card__fee-in-head"
|
||||
/>
|
||||
<template v-if="hasFeeInfo(row)">
|
||||
<div
|
||||
v-if="isMineMode && !isFeeExpanded(row.id)"
|
||||
class="production-work-order-card__fee-toggle-bar"
|
||||
>
|
||||
<el-button class="btn-ghost" @click="toggleFeeExpand(row.id)">
|
||||
<el-icon><ArrowDown /></el-icon>展开费用
|
||||
</el-button>
|
||||
</div>
|
||||
<template v-if="!isMineMode || isFeeExpanded(row.id)">
|
||||
<QcWorkOrderProtocolPaymentPanel
|
||||
v-if="showProtocolFeeSummary(row)"
|
||||
:summary="row.paymentSummary"
|
||||
compact
|
||||
class="production-work-order-card__fee-in-head"
|
||||
/>
|
||||
<QcWorkOrderFeeSummaryBar
|
||||
v-if="showOutboundFeeSummary(row)"
|
||||
variant="basic-experiment"
|
||||
:fee-summary="row.feeSummary"
|
||||
class="production-work-order-card__fee-in-head"
|
||||
/>
|
||||
</template>
|
||||
<div
|
||||
v-if="isMineMode && isFeeExpanded(row.id)"
|
||||
class="production-work-order-card__fee-toggle-bar production-work-order-card__fee-toggle-bar--after-fee"
|
||||
>
|
||||
<el-button class="btn-ghost" @click="toggleFeeExpand(row.id)">
|
||||
<el-icon><ArrowUp /></el-icon>收起
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<section class="production-work-order-card__tasks">
|
||||
<WorkOrderTaskSubList
|
||||
embedded
|
||||
@@ -218,8 +238,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { View, Position, Document, Check, More, EditPen, Delete } from '@element-plus/icons-vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { View, Position, Document, Check, More, EditPen, Delete, ArrowDown, ArrowUp } from '@element-plus/icons-vue'
|
||||
import type { ProductionWorkOrderItem } from '@/api/production-work-order'
|
||||
import type { OutboundQcDetailProduct } from '@/api/qc-work-order'
|
||||
import type { ProductionWorkOrderCardMetaConfig } from '@/utils/production-work-order-card-meta'
|
||||
@@ -256,12 +276,42 @@
|
||||
|
||||
const isMineMode = computed(() => props.pageMode === 'mine')
|
||||
|
||||
const expandedFeeIds = ref<Set<string>>(new Set())
|
||||
|
||||
function isFeeExpanded(id: string) {
|
||||
return expandedFeeIds.value.has(id)
|
||||
}
|
||||
|
||||
function toggleFeeExpand(id: string) {
|
||||
const next = new Set(expandedFeeIds.value)
|
||||
if (next.has(id)) {
|
||||
next.delete(id)
|
||||
} else {
|
||||
next.add(id)
|
||||
}
|
||||
expandedFeeIds.value = next
|
||||
}
|
||||
|
||||
const cardMeta = computed(
|
||||
() =>
|
||||
props.cardMetaConfig ??
|
||||
getCardMetaConfigForLegacyTab(props.activeTypeTab || 'inbound')
|
||||
)
|
||||
|
||||
const INBOUND_SAMPLE_TITLE_TAB_KEYS = new Set([
|
||||
'inbound_cell_storage',
|
||||
'inbound_research_donation'
|
||||
])
|
||||
|
||||
function cardTitleLabel(row: ProductionWorkOrderItem) {
|
||||
if (INBOUND_SAMPLE_TITLE_TAB_KEYS.has(cardMeta.value.tabKey)) {
|
||||
const lab = (row.labStorageCode || '').trim() || '—'
|
||||
const sample = (row.sampleCode || '').trim() || '—'
|
||||
return `${lab} - ${sample}`
|
||||
}
|
||||
return row.workOrderNo || '—'
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
view: [row: ProductionWorkOrderItem]
|
||||
dispatch: [row: ProductionWorkOrderItem]
|
||||
@@ -293,6 +343,10 @@
|
||||
return cardMeta.value.showOutboundFeeSummary && !!row.feeSummary
|
||||
}
|
||||
|
||||
function hasFeeInfo(row: ProductionWorkOrderItem) {
|
||||
return showProtocolFeeSummary(row) || showOutboundFeeSummary(row)
|
||||
}
|
||||
|
||||
function cellProducts(row: ProductionWorkOrderItem): OutboundQcDetailProduct[] {
|
||||
return row.products?.length ? row.products : []
|
||||
}
|
||||
@@ -331,9 +385,9 @@
|
||||
|
||||
function dispatchQcTooltip(row: ProductionWorkOrderItem) {
|
||||
if (!cardMeta.value.allowDispatchQc) return ''
|
||||
if (row.workOrderStatus === 'dpz') return '请先派发并完成生产任务,录入输出细胞产品后再派发质检'
|
||||
if (row.workOrderStatus === 'dpz') return '请先派发生产任务,并在步骤中录入有效物产出及条码后再派发质检'
|
||||
if (row.workOrderStatus === 'yzf') return '已作废工单不可派发质检'
|
||||
return '请先完成生产任务并录入输出细胞产品'
|
||||
return '请先在生产任务步骤中录入类型为有效物且含条码的产出物'
|
||||
}
|
||||
|
||||
function canComplete(row: ProductionWorkOrderItem) {
|
||||
@@ -447,12 +501,28 @@
|
||||
|
||||
.production-work-order-card__no {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.production-work-order-card__fee-toggle-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
border-top: 1px solid #e2e8f0;
|
||||
background: #fff;
|
||||
|
||||
&--after-fee {
|
||||
border-top: none;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
}
|
||||
|
||||
.production-work-order-card__meta {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
@@ -476,6 +546,7 @@
|
||||
dd {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
color: #334155;
|
||||
word-break: break-word;
|
||||
|
||||
@@ -13,7 +13,11 @@
|
||||
{{ editor.stepStatusTag(editor.selectedStep.value.stepStatus || 'dzx').label }}
|
||||
</el-tag>
|
||||
<el-button
|
||||
v-if="editor.selectedStep.value.stepStatus === 'dzx'"
|
||||
v-if="
|
||||
editor.mode.value === 'execution' &&
|
||||
editor.canEditStep(editor.selectedStep.value) &&
|
||||
editor.selectedStep.value.stepStatus === 'dzx'
|
||||
"
|
||||
class="btn-main task-exec-toolbar-btn"
|
||||
type="primary"
|
||||
:loading="editor.stepActionLoading.value"
|
||||
@@ -23,7 +27,11 @@
|
||||
<el-icon><VideoPlay /></el-icon>执行此步骤
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="editor.selectedStep.value.stepStatus === 'jxz'"
|
||||
v-if="
|
||||
editor.mode.value === 'execution' &&
|
||||
editor.canEditStep(editor.selectedStep.value) &&
|
||||
editor.selectedStep.value.stepStatus === 'jxz'
|
||||
"
|
||||
class="btn-main task-exec-toolbar-btn"
|
||||
type="success"
|
||||
:loading="editor.stepActionLoading.value"
|
||||
@@ -34,6 +42,10 @@
|
||||
</el-button>
|
||||
</template>
|
||||
<el-button
|
||||
v-if="
|
||||
editor.canEditStep(editor.selectedStep.value) ||
|
||||
(editor.canEditStepDispatch() && !readonly)
|
||||
"
|
||||
class="btn-main task-exec-toolbar-btn"
|
||||
type="primary"
|
||||
:loading="editor.manualSaveLoading.value"
|
||||
@@ -100,6 +112,81 @@
|
||||
:disabled="readonly"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="editor.canEditStepDispatch() && !readonly"
|
||||
label="负责人"
|
||||
class="step-form-col-half"
|
||||
>
|
||||
<el-select
|
||||
v-model="editor.selectedStep.value.assigneeUserIds"
|
||||
multiple
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
placeholder="选择负责人(可多选)"
|
||||
style="width: 100%"
|
||||
:loading="editor.stepAssigneeUserOptionsLoading.value"
|
||||
:remote-method="editor.remoteSearchStepAssigneeUsers"
|
||||
@visible-change="editor.onStepAssigneeSelectVisible"
|
||||
>
|
||||
<el-option
|
||||
v-for="u in editor.mergedStepAssigneeUserOptions(editor.selectedStep.value)"
|
||||
:key="u.id"
|
||||
:label="`${u.nickName}(${u.userNo})`"
|
||||
:value="u.id"
|
||||
/>
|
||||
</el-select>
|
||||
<p
|
||||
v-if="!(editor.selectedStep.value.assigneeUserIds || []).length"
|
||||
class="form-tip"
|
||||
>
|
||||
未派发;保存后可在本处或「步骤派发」中指定负责人
|
||||
</p>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-else-if="editor.mode.value === 'edit' || editor.mode.value === 'execution'"
|
||||
label="负责人"
|
||||
class="step-form-col-half"
|
||||
>
|
||||
<template v-if="(editor.selectedStep.value.assignees || []).length">
|
||||
<el-tag
|
||||
v-for="a in editor.selectedStep.value.assignees"
|
||||
:key="a.userId"
|
||||
size="small"
|
||||
class="step-assignee-readonly-tag"
|
||||
>
|
||||
{{ a.nickName || a.userNo || a.userId }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<span v-else class="form-tip">未派发</span>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="editor.canEditStepDispatch() && !readonly"
|
||||
label="计划开始时间"
|
||||
class="step-form-col-half"
|
||||
>
|
||||
<template #label
|
||||
>计划开始时间<span class="form-label-tip">仅展示与排序,不限制执行</span></template
|
||||
>
|
||||
<el-date-picker
|
||||
v-model="editor.selectedStep.value.plannedStartTime"
|
||||
type="datetime"
|
||||
placeholder="可选"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
value-format="YYYY-MM-DDTHH:mm:00"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-else-if="editor.mode.value === 'edit' || editor.mode.value === 'execution'"
|
||||
label="计划开始时间"
|
||||
class="step-form-col-half"
|
||||
>
|
||||
<span>{{ editor.selectedStep.value.plannedStartTime || '—' }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述" class="step-form-col-half">
|
||||
<el-input
|
||||
v-model="editor.selectedStep.value.description"
|
||||
@@ -946,6 +1033,10 @@
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.step-assignee-readonly-tag {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.step-sop-attachment-row {
|
||||
margin-top: -4px;
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
<div class="execution-step-list-header">
|
||||
<h3>工序步骤</h3>
|
||||
<span class="execution-progress-badge"
|
||||
>{{ editor.completedStepCount.value }}/{{ editor.stepList.value.length }}</span
|
||||
>{{ editor.completedStepCount.value }}/{{ editor.executionStepList.value.length }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="execution-step-list-body">
|
||||
@@ -227,12 +227,13 @@
|
||||
@end="editor.onStepDragEnd"
|
||||
>
|
||||
<div
|
||||
v-for="(element, index) in editor.stepList.value"
|
||||
v-for="(element, index) in editor.executionStepList.value"
|
||||
:key="element.id"
|
||||
class="route-config-step-card"
|
||||
:class="{
|
||||
'is-active': editor.selectedStepId.value === element.id,
|
||||
'is-done': element.stepStatus === 'ywc'
|
||||
'is-done': element.stepStatus === 'ywc',
|
||||
'is-readonly': !editor.canEditStep(element)
|
||||
}"
|
||||
@click="editor.selectStep(element)"
|
||||
>
|
||||
@@ -277,7 +278,7 @@
|
||||
</div>
|
||||
</draggable>
|
||||
|
||||
<div v-if="!editor.stepList.value.length" class="execution-step-list-empty">
|
||||
<div v-if="!editor.executionStepList.value.length" class="execution-step-list-empty">
|
||||
<el-icon :size="32" color="#a8d4c4"><Plus /></el-icon>
|
||||
<p>从左侧拖拽工序到此处,添加任务步骤</p>
|
||||
</div>
|
||||
@@ -716,6 +717,10 @@
|
||||
.route-config-step-card.is-done {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.route-config-step-card.is-readonly:not(.is-active) {
|
||||
opacity: 0.72;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* 右侧详情面板 */
|
||||
.execution-detail-panel {
|
||||
|
||||
@@ -96,11 +96,8 @@
|
||||
<el-dropdown-item v-if="canEnterExecution(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canForwardTask(row)" command="forward">
|
||||
<el-icon><Share /></el-icon>转发任务
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canReassignTask(row)" command="reassign">
|
||||
<el-icon><User /></el-icon>改派负责人
|
||||
<el-dropdown-item v-if="canDispatchSteps(row)" command="stepDispatch">
|
||||
<el-icon><Position /></el-icon>步骤派发
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canEditTask(row)" command="editInfo">
|
||||
<el-icon><EditPen /></el-icon>编辑信息
|
||||
@@ -158,24 +155,24 @@
|
||||
:task-name="executionTaskName"
|
||||
:readonly="executionReadonly"
|
||||
:operate-scope="operateScope"
|
||||
:allow-forward="canForwardInDialog"
|
||||
:allow-forward="false"
|
||||
append-to-body
|
||||
@success="handleTaskMutationSuccess"
|
||||
/>
|
||||
|
||||
<ForwardTaskDialog
|
||||
v-model:visible="forwardVisible"
|
||||
:task-id="forwardTaskId"
|
||||
:mode="forwardMode"
|
||||
:operate-scope="operateScope"
|
||||
@success="handleTaskMutationSuccess"
|
||||
/>
|
||||
|
||||
<DispatchTaskDialog
|
||||
v-if="workOrder"
|
||||
v-model:visible="dispatchVisible"
|
||||
:work-order-row="workOrder"
|
||||
@success="handleTaskMutationSuccess"
|
||||
@need-step-dispatch="handleNeedStepDispatch"
|
||||
/>
|
||||
|
||||
<DispatchStepDialog
|
||||
v-model:visible="stepDispatchVisible"
|
||||
:task-id="stepDispatchTaskId"
|
||||
:task-name="stepDispatchTaskName"
|
||||
@success="handleTaskMutationSuccess"
|
||||
/>
|
||||
|
||||
<DispatchTaskDialog
|
||||
@@ -204,9 +201,7 @@
|
||||
Position,
|
||||
EditPen,
|
||||
More,
|
||||
Delete,
|
||||
Share,
|
||||
User
|
||||
Delete
|
||||
} from '@element-plus/icons-vue'
|
||||
import {
|
||||
fetchProductionTaskList,
|
||||
@@ -215,8 +210,8 @@
|
||||
type ProductionTaskOperateScope
|
||||
} from '@/api/production-task'
|
||||
import TaskExecutionDialog from './TaskExecutionDialog.vue'
|
||||
import ForwardTaskDialog from './ForwardTaskDialog.vue'
|
||||
import DispatchTaskDialog from './DispatchTaskDialog.vue'
|
||||
import DispatchStepDialog from './DispatchStepDialog.vue'
|
||||
import EditTaskInfoDialog from './EditTaskInfoDialog.vue'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import {
|
||||
@@ -274,7 +269,10 @@
|
||||
|
||||
function isCurrentAssignee(row: Record<string, any>) {
|
||||
const uid = String(userStore.info?.id || userStore.info?.userId || '').trim()
|
||||
return uid && String(row.currentAssigneeUserId || '') === uid
|
||||
if (!uid) return false
|
||||
if (String(row.currentAssigneeUserId || '') === uid) return true
|
||||
if (isMineMode.value && props.listMode !== 'mine-history' && !row.handoverTime) return true
|
||||
return false
|
||||
}
|
||||
|
||||
function isMineHistoryRow(row: Record<string, any>) {
|
||||
@@ -290,14 +288,17 @@
|
||||
return row.taskStatus === 'dpz' || row.taskStatus === 'jxz'
|
||||
}
|
||||
|
||||
function canForwardTask(row: Record<string, any>) {
|
||||
if (isMineHistoryRow(row)) return false
|
||||
if (isMineMode.value) return isCurrentAssignee(row)
|
||||
return operateScope.value === 'manage'
|
||||
function canForwardTask(_row: Record<string, any>) {
|
||||
return false
|
||||
}
|
||||
|
||||
function canReassignTask(row: Record<string, any>) {
|
||||
return !isMineMode.value && operateScope.value === 'manage'
|
||||
function canReassignTask(_row: Record<string, any>) {
|
||||
return false
|
||||
}
|
||||
|
||||
function canDispatchSteps(row: Record<string, any>) {
|
||||
if (isMineMode.value) return false
|
||||
return row.taskStatus === 'dpz' || row.taskStatus === 'jxz'
|
||||
}
|
||||
|
||||
function canEditTask(row: Record<string, any>) {
|
||||
@@ -313,7 +314,7 @@
|
||||
|
||||
function hasMoreTaskActions(row: Record<string, any>) {
|
||||
if (canEnterExecution(row)) return true
|
||||
return canEditTask(row) || canDeleteTask(row)
|
||||
return canEditTask(row) || canDeleteTask(row) || canDispatchSteps(row)
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
@@ -365,17 +366,31 @@
|
||||
|
||||
const dispatchVisible = ref(false)
|
||||
|
||||
const stepDispatchVisible = ref(false)
|
||||
const stepDispatchTaskId = ref('')
|
||||
const stepDispatchTaskName = ref('')
|
||||
|
||||
function handleNeedStepDispatch(payload: { taskId: string; taskName: string }) {
|
||||
stepDispatchTaskId.value = payload.taskId
|
||||
stepDispatchTaskName.value = payload.taskName
|
||||
stepDispatchVisible.value = true
|
||||
}
|
||||
|
||||
function openStepDispatch(row: Record<string, any>) {
|
||||
stepDispatchTaskId.value = row.id
|
||||
stepDispatchTaskName.value = row.taskName || ''
|
||||
stepDispatchVisible.value = true
|
||||
}
|
||||
|
||||
const executionDialogVisible = ref(false)
|
||||
const executionTaskId = ref('')
|
||||
const executionTaskName = ref('')
|
||||
const executionReadonly = ref(false)
|
||||
const canForwardInDialog = ref(false)
|
||||
|
||||
function handleEnterExecution(row: Record<string, any>) {
|
||||
executionTaskId.value = row.id
|
||||
executionTaskName.value = row.taskName || ''
|
||||
executionReadonly.value = false
|
||||
canForwardInDialog.value = canForwardTask(row)
|
||||
executionDialogVisible.value = true
|
||||
}
|
||||
|
||||
@@ -383,14 +398,9 @@
|
||||
executionTaskId.value = row.id
|
||||
executionTaskName.value = row.taskName || ''
|
||||
executionReadonly.value = true
|
||||
canForwardInDialog.value = false
|
||||
executionDialogVisible.value = true
|
||||
}
|
||||
|
||||
const forwardVisible = ref(false)
|
||||
const forwardTaskId = ref('')
|
||||
const forwardMode = ref<'forward' | 'reassign'>('forward')
|
||||
|
||||
const editInfoVisible = ref(false)
|
||||
const editInfoTaskId = ref('')
|
||||
|
||||
@@ -412,15 +422,8 @@
|
||||
editRouteTaskName.value = row.taskName || ''
|
||||
editRouteVisible.value = true
|
||||
break
|
||||
case 'forward':
|
||||
forwardTaskId.value = row.id
|
||||
forwardMode.value = 'forward'
|
||||
forwardVisible.value = true
|
||||
break
|
||||
case 'reassign':
|
||||
forwardTaskId.value = row.id
|
||||
forwardMode.value = 'reassign'
|
||||
forwardVisible.value = true
|
||||
case 'stepDispatch':
|
||||
openStepDispatch(row)
|
||||
break
|
||||
case 'delete':
|
||||
handleDelete(row)
|
||||
|
||||
@@ -72,6 +72,14 @@
|
||||
v-model:visible="dispatchVisible"
|
||||
:work-order-row="dispatchRow"
|
||||
@success="refreshActiveTab"
|
||||
@need-step-dispatch="handleNeedStepDispatch"
|
||||
/>
|
||||
|
||||
<DispatchStepDialog
|
||||
v-model:visible="stepDispatchVisible"
|
||||
:task-id="stepDispatchTaskId"
|
||||
:task-name="stepDispatchTaskName"
|
||||
@success="refreshActiveTab"
|
||||
/>
|
||||
|
||||
<DispatchQcWorkOrderDialog
|
||||
@@ -117,6 +125,7 @@
|
||||
} from '@/utils/production-work-order-tabs'
|
||||
import ProductionWorkOrderTabPanel from './tabs/ProductionWorkOrderTabPanel.vue'
|
||||
import DispatchTaskDialog from './DispatchTaskDialog.vue'
|
||||
import DispatchStepDialog from './DispatchStepDialog.vue'
|
||||
import DispatchQcWorkOrderDialog from './DispatchQcWorkOrderDialog.vue'
|
||||
import WorkOrderRemarkDialog from '@/components/business/work-order-remark-dialog/index.vue'
|
||||
import SampleReceptionDialog from './SampleReceptionDialog.vue'
|
||||
@@ -210,6 +219,16 @@
|
||||
|
||||
const dispatchVisible = ref(false)
|
||||
const dispatchRow = ref<ProductionWorkOrderItem | null>(null)
|
||||
const stepDispatchVisible = ref(false)
|
||||
const stepDispatchTaskId = ref('')
|
||||
const stepDispatchTaskName = ref('')
|
||||
|
||||
function handleNeedStepDispatch(payload: { taskId: string; taskName: string }) {
|
||||
stepDispatchTaskId.value = payload.taskId
|
||||
stepDispatchTaskName.value = payload.taskName
|
||||
stepDispatchVisible.value = true
|
||||
}
|
||||
|
||||
function handleOpenDispatch(row: ProductionWorkOrderItem) {
|
||||
dispatchRow.value = row
|
||||
dispatchVisible.value = true
|
||||
|
||||
@@ -13,8 +13,10 @@ import {
|
||||
fetchUpdateProductionTaskStatus,
|
||||
fetchUpdateProductionTask,
|
||||
fetchSetTaskInputs,
|
||||
fetchSetTaskOutputs
|
||||
fetchSetTaskOutputs,
|
||||
fetchDispatchProductionTaskSteps
|
||||
} from '@/api/production-task'
|
||||
import { fetchUserList } from '@/api/admin'
|
||||
import {
|
||||
fetchAllProcesses,
|
||||
fetchAllProcessCategories,
|
||||
@@ -37,6 +39,7 @@ import {
|
||||
} from '@/api/production-material'
|
||||
import type { FinanceAttachmentItem } from '@/components/business/protocol-finance-confirm-fields/finance-attachments'
|
||||
import { financeAttachmentsToUrlString } from '@/components/business/protocol-finance-confirm-fields/finance-attachments'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
||||
// ── helpers ──────────────────────────────────────────────────────────
|
||||
function parseTaskAttachmentsFromUrls(urls: string): FinanceAttachmentItem[] {
|
||||
@@ -57,9 +60,20 @@ function fromApiFlag(val: boolean | number | string | undefined): boolean {
|
||||
return val === true || val === 1 || val === '1'
|
||||
}
|
||||
function normalizeStepSubTables(step: Record<string, any>) {
|
||||
const assigneeUserIds = (step.assigneeUserIds || []).length
|
||||
? [...step.assigneeUserIds]
|
||||
: (step.assignees || [])
|
||||
.map((a: Record<string, any>) => a.userId)
|
||||
.filter((id: string) => String(id || '').trim())
|
||||
const plannedStartTime = step.plannedStartTime || null
|
||||
return {
|
||||
...step,
|
||||
equipmentIds: parseEquipmentIds(step.equipmentIds || step.equipmentName),
|
||||
assigneeUserIds,
|
||||
assignees: step.assignees || [],
|
||||
plannedStartTime,
|
||||
_snapshotAssigneeUserIds: [...assigneeUserIds],
|
||||
_snapshotPlannedStartTime: plannedStartTime || '',
|
||||
reagents: (step.reagents || []).map((r: Record<string, any>) => ({
|
||||
...r,
|
||||
isKeyMaterial: fromApiFlag(r.isKeyMaterial)
|
||||
@@ -81,11 +95,46 @@ function parseOrderNum(value: unknown): number {
|
||||
|
||||
// ── composable ───────────────────────────────────────────────────────
|
||||
export function useTaskStepEditor() {
|
||||
const userStore = useUserStore()
|
||||
const operateScope = ref<import('@/api/production-task').ProductionTaskOperateScope | undefined>(
|
||||
undefined
|
||||
)
|
||||
const taskId = ref('')
|
||||
const stepList = ref<Record<string, any>[]>([])
|
||||
|
||||
function canEditStep(step: Record<string, any> | null | undefined): boolean {
|
||||
if (!step) return false
|
||||
if (operateScope.value !== 'mine') return true
|
||||
const uid = String(userStore.info?.id || userStore.info?.userId || '').trim()
|
||||
const ids: string[] = step.assigneeUserIds || []
|
||||
if (uid && ids.includes(uid)) return true
|
||||
if (!ids.length && canEditStepOnTaskForMine(uid)) return true
|
||||
return false
|
||||
}
|
||||
|
||||
/** 步骤负责人与计划开始时间是否可在详情中编辑(执行弹窗 manage / mine 均可) */
|
||||
function canEditStepDispatch(): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
function canEditStepOnTaskForMine(uid: string): boolean {
|
||||
if (!uid) return false
|
||||
if (stepList.value.some((s) => (s.assigneeUserIds || []).includes(uid))) return true
|
||||
const taskAssignee = String(taskDetail.value?.currentAssigneeUserId || '').trim()
|
||||
return taskAssignee === uid
|
||||
}
|
||||
|
||||
const executionStepList = computed(() => {
|
||||
if (operateScope.value !== 'mine') return stepList.value
|
||||
const uid = String(userStore.info?.id || userStore.info?.userId || '').trim()
|
||||
return stepList.value.filter((s) => {
|
||||
const ids: string[] = s.assigneeUserIds || []
|
||||
if (uid && ids.includes(uid)) return true
|
||||
// 未派发步骤:任务内任一步负责人可在执行弹窗中看见并配置(含工艺库新增)
|
||||
if (!ids.length && canEditStepOnTaskForMine(uid)) return true
|
||||
return false
|
||||
})
|
||||
})
|
||||
const selectedStepId = ref('')
|
||||
const stepListLoading = ref(false)
|
||||
const processLibraryLoading = ref(false)
|
||||
@@ -155,6 +204,9 @@ export function useTaskStepEditor() {
|
||||
const sampleCodeOptions = ref<Api.BizSampleCode.SampleCodeItem[]>([])
|
||||
const sampleCodeOptionsLoading = ref(false)
|
||||
|
||||
const stepAssigneeUserOptions = ref<Api.User.UserItem[]>([])
|
||||
const stepAssigneeUserOptionsLoading = ref(false)
|
||||
|
||||
function mapItemUnitOption(u: { unitName?: string; unitCode?: string }) {
|
||||
const name = (u.unitName || '').trim()
|
||||
const code = (u.unitCode || '').trim()
|
||||
@@ -862,6 +914,7 @@ export function useTaskStepEditor() {
|
||||
}
|
||||
}
|
||||
function selectStep(step: Record<string, any>) {
|
||||
ensureStepAssigneeFields(step)
|
||||
selectedStepId.value = step.id
|
||||
selectedVirtualStep.value = null
|
||||
}
|
||||
@@ -901,6 +954,77 @@ export function useTaskStepEditor() {
|
||||
}
|
||||
}
|
||||
|
||||
function stepDispatchChanged(step: Record<string, any>): boolean {
|
||||
const curIds = [...(step.assigneeUserIds || [])].sort().join(',')
|
||||
const snapIds = [...(step._snapshotAssigneeUserIds || [])].sort().join(',')
|
||||
if (curIds !== snapIds) return true
|
||||
const curTime = step.plannedStartTime || ''
|
||||
const snapTime = step._snapshotPlannedStartTime || ''
|
||||
return curTime !== snapTime
|
||||
}
|
||||
|
||||
function mergedStepAssigneeUserOptions(step: Record<string, any> | null) {
|
||||
const map = new Map<string, Api.User.UserItem>()
|
||||
for (const u of stepAssigneeUserOptions.value) map.set(u.id, u)
|
||||
for (const a of step?.assignees || []) {
|
||||
const id = String(a.userId || '').trim()
|
||||
if (!id) continue
|
||||
map.set(id, {
|
||||
id,
|
||||
nickName: a.nickName || '',
|
||||
userNo: a.userNo || ''
|
||||
} as Api.User.UserItem)
|
||||
}
|
||||
return [...map.values()]
|
||||
}
|
||||
|
||||
async function remoteSearchStepAssigneeUsers(query: string) {
|
||||
stepAssigneeUserOptionsLoading.value = true
|
||||
try {
|
||||
const res = await fetchUserList({
|
||||
page: 1,
|
||||
pageSize: 50,
|
||||
keyword: query?.trim() || undefined,
|
||||
status: '1'
|
||||
})
|
||||
stepAssigneeUserOptions.value = res.list || []
|
||||
} catch {
|
||||
stepAssigneeUserOptions.value = []
|
||||
} finally {
|
||||
stepAssigneeUserOptionsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onStepAssigneeSelectVisible(visible: boolean) {
|
||||
if (visible) void remoteSearchStepAssigneeUsers('')
|
||||
}
|
||||
|
||||
function ensureStepAssigneeFields(step: Record<string, any>) {
|
||||
if (!Array.isArray(step.assigneeUserIds)) step.assigneeUserIds = []
|
||||
}
|
||||
|
||||
async function saveStepDispatch() {
|
||||
if (!selectedStep.value || !canEditStepDispatch()) return
|
||||
const step = selectedStep.value
|
||||
if (!stepDispatchChanged(step)) return
|
||||
const assigneeUserIds = [...(step.assigneeUserIds || [])]
|
||||
await fetchDispatchProductionTaskSteps(
|
||||
taskId.value,
|
||||
{
|
||||
steps: [
|
||||
{
|
||||
stepId: step.id,
|
||||
assigneeUserIds,
|
||||
plannedStartTime: step.plannedStartTime || null
|
||||
}
|
||||
]
|
||||
},
|
||||
operateScope.value
|
||||
)
|
||||
step._snapshotAssigneeUserIds = [...assigneeUserIds]
|
||||
step._snapshotPlannedStartTime = step.plannedStartTime || ''
|
||||
}
|
||||
|
||||
async function saveStepBasic() {
|
||||
if (!selectedStep.value) return
|
||||
try {
|
||||
@@ -1379,16 +1503,25 @@ export function useTaskStepEditor() {
|
||||
const taskActionLoading = ref(false)
|
||||
async function handleManualSave() {
|
||||
if (!selectedStep.value || manualSaveLoading.value) return
|
||||
const step = selectedStep.value
|
||||
const canBasic = canEditStep(step)
|
||||
const canDispatch = canEditStepDispatch() && stepDispatchChanged(step)
|
||||
if (!canBasic && !canDispatch) return
|
||||
manualSaveLoading.value = true
|
||||
try {
|
||||
await Promise.all([
|
||||
saveStepBasic(),
|
||||
saveReagents(),
|
||||
saveConsumables(),
|
||||
saveConfiguredReagents(),
|
||||
saveOutputs(),
|
||||
saveDataCollections()
|
||||
])
|
||||
if (canBasic) {
|
||||
await Promise.all([
|
||||
saveStepBasic(),
|
||||
saveReagents(),
|
||||
saveConsumables(),
|
||||
saveConfiguredReagents(),
|
||||
saveOutputs(),
|
||||
saveDataCollections()
|
||||
])
|
||||
}
|
||||
if (canDispatch) {
|
||||
await saveStepDispatch()
|
||||
}
|
||||
ElMessage.success('保存成功')
|
||||
} catch {
|
||||
ElMessage.error('保存失败,请重试')
|
||||
@@ -1399,6 +1532,10 @@ export function useTaskStepEditor() {
|
||||
|
||||
async function handleStartStep(step: Record<string, any>) {
|
||||
if (!taskId.value || !step.id || stepActionLoading.value) return
|
||||
if (!canEditStep(step)) {
|
||||
ElMessage.warning('非当前步骤负责人,无法操作')
|
||||
return
|
||||
}
|
||||
stepActionLoading.value = true
|
||||
try {
|
||||
await fetchUpdateTaskStep(taskId.value, step.id, { step_status: 'jxz' }, operateScope.value)
|
||||
@@ -1413,6 +1550,10 @@ export function useTaskStepEditor() {
|
||||
|
||||
async function handleCompleteStep(step: Record<string, any>) {
|
||||
if (!taskId.value || !step.id || stepActionLoading.value) return
|
||||
if (!canEditStep(step)) {
|
||||
ElMessage.warning('非当前步骤负责人,无法操作')
|
||||
return
|
||||
}
|
||||
try {
|
||||
await ElMessageBox.confirm('确定完成该步骤吗?', '提示', { type: 'warning' })
|
||||
} catch {
|
||||
@@ -1648,6 +1789,9 @@ export function useTaskStepEditor() {
|
||||
void loadConfigReferenceData().catch(() => {
|
||||
/* 工艺库参考数据失败不阻断步骤展示 */
|
||||
})
|
||||
if (canEditStepDispatch()) {
|
||||
void remoteSearchStepAssigneeUsers('')
|
||||
}
|
||||
} finally {
|
||||
stepListLoading.value = false
|
||||
await nextTick()
|
||||
@@ -1659,6 +1803,9 @@ export function useTaskStepEditor() {
|
||||
return {
|
||||
taskId,
|
||||
stepList,
|
||||
executionStepList,
|
||||
canEditStep,
|
||||
canEditStepDispatch,
|
||||
selectedStepId,
|
||||
selectedStep,
|
||||
stepListLoading,
|
||||
@@ -1730,6 +1877,14 @@ export function useTaskStepEditor() {
|
||||
taskStatusTag,
|
||||
stepStatusTag,
|
||||
saveStepBasic,
|
||||
saveStepDispatch,
|
||||
stepDispatchChanged,
|
||||
stepAssigneeUserOptions,
|
||||
stepAssigneeUserOptionsLoading,
|
||||
mergedStepAssigneeUserOptions,
|
||||
remoteSearchStepAssigneeUsers,
|
||||
onStepAssigneeSelectVisible,
|
||||
ensureStepAssigneeFields,
|
||||
onStepEquipmentChange,
|
||||
onSopIdsChange,
|
||||
searchItemUnitOptions,
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
-- 生产过程派发质检:支持仅关联步骤产出物(无细胞产品时也可派发)
|
||||
ALTER TABLE `biz_qc_work_order`
|
||||
ADD COLUMN `production_step_output_id` varchar(64) DEFAULT NULL
|
||||
COMMENT '关联生产任务步骤产出物ID(生产过程触发时)'
|
||||
AFTER `production_task_id`;
|
||||
|
||||
CREATE INDEX `idx_qc_wo_prod_step_output` ON `biz_qc_work_order` (`production_step_output_id`, `del_flag`);
|
||||
|
||||
|
||||
|
||||
|
||||
-- 生产任务 · 工艺步骤级派发
|
||||
-- 步骤计划开始时间、完成人 + 步骤负责人关联表
|
||||
|
||||
ALTER TABLE `biz_production_task_step`
|
||||
ADD COLUMN `planned_start_time` datetime DEFAULT NULL COMMENT '计划开始时间' AFTER `step_status`;
|
||||
|
||||
ALTER TABLE `biz_production_task_step`
|
||||
ADD COLUMN `completed_by` varchar(64) DEFAULT NULL COMMENT '完成步骤的用户ID' AFTER `completed_time`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `biz_production_task_step_assignee` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键',
|
||||
`step_id` varchar(64) NOT NULL COMMENT '生产任务步骤ID',
|
||||
`user_id` varchar(64) NOT NULL COMMENT '负责人用户ID',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
|
||||
`order_num` int DEFAULT 0 COMMENT '展示顺序',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人id',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
|
||||
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人id',
|
||||
`update_time` datetime NOT NULL COMMENT '更新时间',
|
||||
`del_flag` tinyint NOT NULL DEFAULT 0 COMMENT '删除标记',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_step_assignee_step` (`step_id`),
|
||||
KEY `idx_step_assignee_user` (`user_id`, `tenant_no`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生产任务步骤负责人';
|
||||
|
||||
|
||||
|
||||
-- 可选:将仍有 task.current_assignee_user_id 且无步骤负责人的旧任务回填到全部步骤
|
||||
--
|
||||
-- 注意:MySQL 5.7 在 INSERT...SELECT 中 UUID() 可能整批只计算一次,导致主键重复。
|
||||
-- 此处用 SHA2(step_id) 生成确定性主键,每步唯一,且可重复执行(已存在则跳过)。
|
||||
|
||||
INSERT INTO `biz_production_task_step_assignee` (
|
||||
`id`, `step_id`, `user_id`, `tenant_no`, `order_num`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
|
||||
)
|
||||
SELECT
|
||||
LOWER(SHA2(CONCAT('step-assignee-backfill:', s.id), 256)),
|
||||
s.id,
|
||||
t.current_assignee_user_id,
|
||||
s.tenant_no,
|
||||
0,
|
||||
t.create_by,
|
||||
IFNULL(t.create_dept_id, ''),
|
||||
NOW(),
|
||||
t.update_by,
|
||||
NOW(),
|
||||
0
|
||||
FROM `biz_production_task` t
|
||||
JOIN `biz_production_task_step` s ON s.task_id = t.id AND s.del_flag = 0
|
||||
WHERE t.del_flag = 0
|
||||
AND t.current_assignee_user_id IS NOT NULL
|
||||
AND TRIM(t.current_assignee_user_id) <> ''
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM `biz_production_task_step_assignee` a
|
||||
WHERE a.step_id = s.id AND a.del_flag = 0
|
||||
);
|
||||
Reference in new issue
Block a user