提交
This commit is contained in:
1 parent
9dd7eb56ba
commit
7cec1f2190
112 files changed
+22684
-6952
No files matched your search
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -1 +1 @@
|
||||
84901
|
||||
95768
|
||||
@@ -1,5 +1,5 @@
|
||||
"""生产管理 API 路由(7 个子模块:耗材、试剂、SOP文档、工艺工序分类、产出物类型、耗材包、工艺库)"""
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi import APIRouter, Depends, Query, HTTPException
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import Any, Optional, List
|
||||
@@ -34,7 +34,7 @@ from app.models.models import SysUser
|
||||
from app.crud import production_work_order as production_work_order_svc
|
||||
from app.crud import production_task as production_task_svc
|
||||
from app.crud import cell_product as cell_product_svc
|
||||
from app.schemas.production_work_order import ProductionWorkOrderListQuery, ProductionWorkOrderComplete
|
||||
from app.schemas.production_work_order import ProductionWorkOrderListQuery, ProductionWorkOrderComplete, ProductionWorkOrderCreate, ProductionWorkOrderConfigureBody
|
||||
from app.schemas.production_task import (
|
||||
ProductionTaskCreate,
|
||||
ProductionTaskUpdate,
|
||||
@@ -1543,6 +1543,43 @@ async def update_step_data_collections(
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@router.post("/production-work-orders")
|
||||
async def create_production_work_order(
|
||||
body: ProductionWorkOrderCreate,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
wo_type = (body.work_order_type or "inbound").strip()
|
||||
if wo_type == "temporary":
|
||||
wo = production_work_order_svc.create_temp_production_work_order(
|
||||
db,
|
||||
tenant_no=tenant_no,
|
||||
user_id=user.get("user_id"),
|
||||
create_dept_id=user.get("dept_id", ""),
|
||||
remark=body.remark or "",
|
||||
)
|
||||
else:
|
||||
wo = production_work_order_svc.create_production_work_order_manual(
|
||||
db,
|
||||
tenant_no=tenant_no,
|
||||
user_id=user.get("user_id"),
|
||||
create_dept_id=user.get("dept_id", ""),
|
||||
protocol_no=body.protocol_no or "",
|
||||
sample_code=body.sample_code or "",
|
||||
reception_source=body.reception_source or "cell_storage",
|
||||
remark=body.remark or "",
|
||||
)
|
||||
db.commit()
|
||||
return success_response(production_work_order_svc._wo_to_dict(wo), message="创建成功")
|
||||
except ValueError as e:
|
||||
return error_response(400, str(e))
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.get("/production-work-orders")
|
||||
async def list_production_work_orders(
|
||||
page: int = Query(1, ge=1),
|
||||
@@ -1550,6 +1587,7 @@ async def list_production_work_orders(
|
||||
keyword: Optional[str] = None,
|
||||
workOrderNo: Optional[str] = None,
|
||||
workOrderStatus: Optional[str] = None,
|
||||
workOrderType: Optional[str] = None,
|
||||
protocolNo: Optional[str] = None,
|
||||
sampleCode: Optional[str] = None,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
@@ -1560,6 +1598,7 @@ async def list_production_work_orders(
|
||||
page=page, page_size=pageSize,
|
||||
keyword=keyword,
|
||||
work_order_no=workOrderNo, work_order_status=workOrderStatus,
|
||||
work_order_type=workOrderType,
|
||||
protocol_no=protocolNo, sample_code=sampleCode,
|
||||
)
|
||||
result = production_work_order_svc.list_production_work_orders(
|
||||
@@ -1602,6 +1641,51 @@ async def complete_production_work_order(
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.delete("/production-work-orders/{wo_id}")
|
||||
async def delete_production_work_order_api(
|
||||
wo_id: str,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
production_work_order_svc.delete_production_work_order(db, wo_id, tenant_no, user.get("user_id"))
|
||||
return success_response(None, message="删除成功")
|
||||
except ValueError as e:
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.post("/production-work-orders/{wo_id}/configure")
|
||||
async def configure_production_work_order(
|
||||
wo_id: str,
|
||||
body: ProductionWorkOrderConfigureBody,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
wo = production_work_order_svc.configure_temp_production_work_order(
|
||||
db,
|
||||
wo_id,
|
||||
task_name=body.task_name or "",
|
||||
task_type=body.task_type or "cell_storage",
|
||||
route_id=body.route_id,
|
||||
description=body.description or "",
|
||||
remark=body.remark or "",
|
||||
tenant_no=tenant_no,
|
||||
user_id=user.get("user_id"),
|
||||
create_dept_id=user.get("dept_id", ""),
|
||||
)
|
||||
db.commit()
|
||||
return success_response(production_work_order_svc._wo_to_dict(wo), message="配置成功")
|
||||
except ValueError as e:
|
||||
db.rollback()
|
||||
return error_response(400, str(e))
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 10. 生产任务
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -1948,6 +2032,7 @@ async def list_cell_products(
|
||||
productTypeId: Optional[str] = None,
|
||||
productStatus: Optional[str] = None,
|
||||
passage: Optional[str] = None,
|
||||
sourceType: Optional[str] = None,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
@@ -1957,7 +2042,7 @@ async def list_cell_products(
|
||||
keyword=keyword,
|
||||
product_code=productCode, product_name=productName,
|
||||
product_type_id=productTypeId, product_status=productStatus,
|
||||
passage=passage,
|
||||
passage=passage, source_type=sourceType,
|
||||
user_info=user,
|
||||
)
|
||||
items = result.get("items", [])
|
||||
@@ -1979,6 +2064,19 @@ async def get_cell_product_detail(
|
||||
return success_response(cell_product_svc.product_to_response(db, tenant_no, obj))
|
||||
|
||||
|
||||
@router.get("/cell-products/{product_id}/chain")
|
||||
async def get_cell_product_chain(
|
||||
product_id: str,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
chain = cell_product_svc.get_product_chain(db, product_id, tenant_no)
|
||||
if not chain:
|
||||
raise HTTPException(status_code=404, detail="细胞产品不存在")
|
||||
return success_response(chain)
|
||||
|
||||
|
||||
@router.post("/cell-products")
|
||||
async def create_cell_product(
|
||||
body: CellProductCreate,
|
||||
|
||||
@@ -23,6 +23,9 @@ from app.crud import qc_material_usage as mu_svc
|
||||
from app.crud import qc_work_order as wo_svc
|
||||
from app.crud.collection_protocol import total_pages
|
||||
from app.api.sample_reception import _get_current_user_id, _get_tenant_no, _page_payload
|
||||
from app.schemas.qc_work_order import QcWorkOrderCreateBody, QcWorkOrderUpdateBody
|
||||
from app.schemas.qc_task import QcTaskCreateBody
|
||||
|
||||
|
||||
router = APIRouter(prefix="/web/admin", tags=["质量检测"])
|
||||
|
||||
@@ -547,12 +550,52 @@ class WorkOrderConfigureBody(BaseModel):
|
||||
third_party_item_ids: List[str] = Field(default_factory=list, alias="thirdPartyItemIds")
|
||||
|
||||
|
||||
@router.post("/qc-work-orders")
|
||||
async def create_qc_work_order(
|
||||
body: QcWorkOrderCreateBody,
|
||||
db: Session = Depends(get_db),
|
||||
user: dict = Depends(require_menu_code("biz:qcWorkOrder:list")),
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
wo_type = (body.work_order_type or "inbound").strip()
|
||||
if wo_type == "temporary":
|
||||
wo = wo_svc.create_temp_qc_work_order(
|
||||
db,
|
||||
tenant_no=tenant_no,
|
||||
user_id=user.get("user_id"),
|
||||
create_dept_id=user.get("dept_id", ""),
|
||||
cell_product_id=body.cell_product_id or "",
|
||||
remark=body.remark or "",
|
||||
)
|
||||
else:
|
||||
wo = wo_svc.create_qc_work_order_manual(
|
||||
db,
|
||||
tenant_no=tenant_no,
|
||||
user_id=user.get("user_id"),
|
||||
create_dept_id=user.get("dept_id", ""),
|
||||
protocol_no=body.protocol_no or "",
|
||||
sample_code=body.sample_code or "",
|
||||
reception_source=body.reception_source or "cell_storage",
|
||||
qc_biz_type=body.qc_biz_type or "inbound",
|
||||
remark=body.remark or "",
|
||||
)
|
||||
db.commit()
|
||||
return success_response(wo_svc._wo_to_dict(wo), message="创建成功")
|
||||
except PermissionError as e:
|
||||
return error_response(403, str(e))
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.get("/qc-work-orders")
|
||||
async def list_qc_work_orders(
|
||||
page: int = Query(1, ge=1),
|
||||
pageSize: int = Query(10, ge=1, le=100),
|
||||
keyword: Optional[str] = None,
|
||||
workOrderStatus: Optional[str] = None,
|
||||
workOrderType: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: dict = Depends(require_menu_code("biz:qcWorkOrder:list")),
|
||||
):
|
||||
@@ -564,6 +607,7 @@ async def list_qc_work_orders(
|
||||
page_size=pageSize,
|
||||
keyword=keyword,
|
||||
work_order_status=workOrderStatus,
|
||||
work_order_type=workOrderType,
|
||||
tenant_no=tenant_no,
|
||||
user_info=user,
|
||||
)
|
||||
@@ -592,6 +636,49 @@ async def get_qc_work_order_detail(
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.put("/qc-work-orders/{work_order_id}")
|
||||
async def update_qc_work_order(
|
||||
work_order_id: str,
|
||||
body: QcWorkOrderUpdateBody,
|
||||
db: Session = Depends(get_db),
|
||||
user: dict = Depends(require_menu_code("biz:qcWorkOrder:list")),
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
wo = wo_svc.update_temp_qc_work_order(
|
||||
db,
|
||||
work_order_id,
|
||||
tenant_no=tenant_no,
|
||||
user_id=_get_current_user_id(user),
|
||||
cell_product_id=body.cell_product_id,
|
||||
remark=body.remark,
|
||||
)
|
||||
db.commit()
|
||||
return success_response(wo_svc._wo_to_dict(wo), message="保存成功")
|
||||
except PermissionError as e:
|
||||
return error_response(403, str(e))
|
||||
except ValueError as e:
|
||||
db.rollback()
|
||||
return error_response(400, str(e))
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.delete("/qc-work-orders/{work_order_id}")
|
||||
async def delete_qc_work_order_api(
|
||||
work_order_id: str,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
wo_svc.delete_qc_work_order(db, work_order_id, tenant_no, user.get("user_id"))
|
||||
return success_response(None, message="删除成功")
|
||||
except ValueError as e:
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.post("/qc-work-orders/{work_order_id}/configure")
|
||||
async def configure_qc_work_order(
|
||||
work_order_id: str,
|
||||
@@ -629,6 +716,38 @@ class TaskAttachmentsBody(BaseModel):
|
||||
third_party_attachments: str = Field("", alias="thirdPartyAttachments")
|
||||
|
||||
|
||||
@router.post("/qc-tasks")
|
||||
async def create_qc_task(
|
||||
body: QcTaskCreateBody,
|
||||
db: Session = Depends(get_db),
|
||||
user: dict = Depends(require_menu_code("biz:qcTask:list")),
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
task = task_svc.create_qc_task_manual(
|
||||
db,
|
||||
tenant_no=tenant_no,
|
||||
user_id=user.get("user_id"),
|
||||
create_dept_id=user.get("dept_id", ""),
|
||||
task_type=body.task_type,
|
||||
item_code=body.item_code,
|
||||
item_name=body.item_name,
|
||||
company_id=body.company_id,
|
||||
company_name=body.company_name,
|
||||
fee_amount=body.fee_amount,
|
||||
sample_code=body.sample_code or "",
|
||||
work_order_id=body.work_order_id or "",
|
||||
remark=body.remark or "",
|
||||
)
|
||||
db.commit()
|
||||
return success_response(task_svc._task_to_dict(task), message="创建成功")
|
||||
except PermissionError as e:
|
||||
return error_response(403, str(e))
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.get("/qc-tasks")
|
||||
async def list_qc_tasks(
|
||||
page: int = Query(1, ge=1),
|
||||
@@ -838,6 +957,20 @@ async def update_qc_task_attachments(
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.delete("/qc-tasks/{task_id}")
|
||||
async def delete_qc_task_api(
|
||||
task_id: str,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
task_svc.delete_qc_task(db, task_id, tenant_no, user.get("user_id"))
|
||||
return success_response(None, message="删除成功")
|
||||
except ValueError as e:
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
# ---------- 质检物料库 ----------
|
||||
|
||||
|
||||
|
||||
@@ -132,6 +132,42 @@ def _enrich_product_dicts(
|
||||
else:
|
||||
slot_map[slot.id] = code or node_path or ""
|
||||
|
||||
# --- 来源信息富化 ---
|
||||
from app.models.models import BizProductionTask, BizProductionWorkOrder
|
||||
|
||||
task_ids = {i.get("productionTaskId") for i in items if i.get("productionTaskId")}
|
||||
task_map: Dict[str, Any] = {}
|
||||
task_to_wo: Dict[str, str] = {}
|
||||
wo_map: Dict[str, Any] = {}
|
||||
|
||||
if task_ids:
|
||||
tasks = (
|
||||
db.query(BizProductionTask)
|
||||
.filter(
|
||||
BizProductionTask.id.in_(task_ids),
|
||||
BizProductionTask.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
for t in tasks:
|
||||
task_map[t.id] = t
|
||||
if t.work_order_id:
|
||||
task_to_wo[t.id] = t.work_order_id
|
||||
|
||||
wo_ids = set(task_to_wo.values())
|
||||
if wo_ids:
|
||||
wos = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(
|
||||
BizProductionWorkOrder.id.in_(wo_ids),
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
wo_map = {w.id: w for w in wos}
|
||||
|
||||
source_type_labels = {"production": "生产入库", "manual": "手动录入"}
|
||||
|
||||
for item in items:
|
||||
tid = item.get("productTypeId") or ""
|
||||
sid = item.get("specId") or ""
|
||||
@@ -139,6 +175,28 @@ def _enrich_product_dicts(
|
||||
item["productTypeName"] = type_map.get(tid, "") if tid else ""
|
||||
item["specName"] = spec_map.get(sid, "") if sid else ""
|
||||
item["storageSlotName"] = slot_map.get(slot_id, "") if slot_id else ""
|
||||
# 来源信息
|
||||
src_type = item.get("sourceType", "")
|
||||
item["sourceTypeLabel"] = source_type_labels.get(src_type, src_type or "")
|
||||
tid = item.get("productionTaskId") or ""
|
||||
if tid and tid in task_map:
|
||||
t_obj = task_map[tid]
|
||||
item["sourceTaskNo"] = t_obj.task_no or ""
|
||||
wo_id = task_to_wo.get(tid)
|
||||
if wo_id and wo_id in wo_map:
|
||||
wo_obj = wo_map[wo_id]
|
||||
item["sourceWorkOrderNo"] = wo_obj.work_order_no or ""
|
||||
item["sourceProtocolNo"] = wo_obj.protocol_no or ""
|
||||
item["sourceReceptionSource"] = wo_obj.reception_source or ""
|
||||
else:
|
||||
item["sourceWorkOrderNo"] = ""
|
||||
item["sourceProtocolNo"] = ""
|
||||
item["sourceReceptionSource"] = ""
|
||||
else:
|
||||
item["sourceTaskNo"] = ""
|
||||
item["sourceWorkOrderNo"] = ""
|
||||
item["sourceProtocolNo"] = ""
|
||||
item["sourceReceptionSource"] = ""
|
||||
return items
|
||||
|
||||
|
||||
@@ -159,6 +217,7 @@ def list_cell_products(
|
||||
product_type_id: Optional[str] = None,
|
||||
product_status: Optional[str] = None,
|
||||
passage: Optional[str] = None,
|
||||
source_type: Optional[str] = None,
|
||||
user_info=None,
|
||||
) -> Dict[str, Any]:
|
||||
def _filtered():
|
||||
@@ -187,6 +246,8 @@ def list_cell_products(
|
||||
q0 = q0.filter(BizCellProduct.product_status == product_status)
|
||||
if passage:
|
||||
q0 = q0.filter(BizCellProduct.passage == passage)
|
||||
if source_type:
|
||||
q0 = q0.filter(BizCellProduct.source_type == source_type)
|
||||
if user_info:
|
||||
from app.core.data_scope import apply_data_scope
|
||||
q0 = apply_data_scope(q0, BizCellProduct, user_info, db, tenant_no)
|
||||
@@ -600,3 +661,287 @@ def total_pages(total: int, page_size: int) -> int:
|
||||
if total <= 0:
|
||||
return 0
|
||||
return int(math.ceil(total / float(page_size)))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 来源链路 API
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_MAX_CHAIN_DEPTH = 10
|
||||
|
||||
_SOURCE_TYPE_LABELS = {"production": "生产入库", "manual": "手动录入"}
|
||||
|
||||
|
||||
def _product_node(obj: BizCellProduct, is_current: bool = False) -> Dict[str, Any]:
|
||||
return {
|
||||
"id": obj.id,
|
||||
"productCode": obj.product_code or "",
|
||||
"productName": obj.product_name or "",
|
||||
"nodeType": "cell_product",
|
||||
"productStatus": obj.product_status or "",
|
||||
"passage": obj.passage or "",
|
||||
"isCurrent": is_current,
|
||||
}
|
||||
|
||||
|
||||
def _first_chain_link(chain: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
|
||||
"""祖先链单链路段:列表仅含一个节点时取首项,供 parent 嵌套为对象而非数组。"""
|
||||
return chain[0] if chain else None
|
||||
|
||||
|
||||
def _edge_meta(task: Any, wo: Any = None) -> Dict[str, Any]:
|
||||
edge: Dict[str, Any] = {
|
||||
"workOrderNo": "",
|
||||
"workOrderType": "",
|
||||
"taskNo": "",
|
||||
"taskName": "",
|
||||
"taskId": "",
|
||||
}
|
||||
if task:
|
||||
edge["taskNo"] = task.task_no or ""
|
||||
edge["taskName"] = task.task_name or ""
|
||||
edge["taskId"] = task.id or ""
|
||||
if wo:
|
||||
edge["workOrderNo"] = wo.work_order_no or ""
|
||||
edge["workOrderType"] = wo.reception_source or ""
|
||||
return edge
|
||||
|
||||
|
||||
def _sample_customer_dict(db: Session, protocol_id: str, tenant_no: str) -> Dict[str, Any]:
|
||||
if not protocol_id:
|
||||
return {}
|
||||
from app.models.models import BizProtocolPartyCustomer
|
||||
|
||||
pc = (
|
||||
db.query(BizProtocolPartyCustomer)
|
||||
.filter(
|
||||
BizProtocolPartyCustomer.collection_protocol_id == protocol_id,
|
||||
BizProtocolPartyCustomer.tenant_no == tenant_no,
|
||||
BizProtocolPartyCustomer.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if not pc:
|
||||
return {}
|
||||
return {
|
||||
"motherName": pc.mother_name or "",
|
||||
"motherPhone": pc.mother_phone or "",
|
||||
"motherIdCard": pc.mother_id_card or "",
|
||||
"newbornName": pc.newborn_name or "",
|
||||
}
|
||||
|
||||
|
||||
def _build_ancestor_chain(
|
||||
db: Session, product: BizCellProduct, depth: int, tenant_no: str
|
||||
) -> List[Dict[str, Any]]:
|
||||
if depth >= _MAX_CHAIN_DEPTH:
|
||||
return []
|
||||
task_id = product.production_task_id
|
||||
if not task_id:
|
||||
return []
|
||||
|
||||
from app.models.models import BizProductionTask, BizProductionWorkOrder
|
||||
from app.models.models import BizProductionTaskInput
|
||||
|
||||
task = (
|
||||
db.query(BizProductionTask)
|
||||
.filter(BizProductionTask.id == task_id, BizProductionTask.del_flag == 0)
|
||||
.first()
|
||||
)
|
||||
if not task:
|
||||
return []
|
||||
|
||||
wo = None
|
||||
if task.work_order_id:
|
||||
wo = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(BizProductionWorkOrder.id == task.work_order_id, BizProductionWorkOrder.del_flag == 0)
|
||||
.first()
|
||||
)
|
||||
edge = _edge_meta(task, wo)
|
||||
|
||||
# 检查投入物中是否有父细胞产品(按排序取首个)
|
||||
parent_input = (
|
||||
db.query(BizProductionTaskInput)
|
||||
.filter(
|
||||
BizProductionTaskInput.task_id == task_id,
|
||||
BizProductionTaskInput.input_type == "cell_product",
|
||||
BizProductionTaskInput.del_flag == 0,
|
||||
)
|
||||
.order_by(
|
||||
BizProductionTaskInput.order_num.asc(),
|
||||
BizProductionTaskInput.create_time.asc(),
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if parent_input and (parent_input.input_id or parent_input.input_code):
|
||||
parent_product = None
|
||||
if parent_input.input_id:
|
||||
parent_product = (
|
||||
db.query(BizCellProduct)
|
||||
.filter(BizCellProduct.id == parent_input.input_id, BizCellProduct.del_flag == 0)
|
||||
.first()
|
||||
)
|
||||
if not parent_product and parent_input.input_code:
|
||||
parent_product = (
|
||||
db.query(BizCellProduct)
|
||||
.filter(BizCellProduct.product_code == parent_input.input_code, BizCellProduct.del_flag == 0)
|
||||
.first()
|
||||
)
|
||||
if parent_product:
|
||||
parent_chain = _build_ancestor_chain(db, parent_product, depth + 1, tenant_no)
|
||||
return [
|
||||
{
|
||||
"node": _product_node(parent_product),
|
||||
"edge": edge,
|
||||
"parent": _first_chain_link(parent_chain),
|
||||
}
|
||||
]
|
||||
|
||||
# 检查投入物中是否有样本(终止节点)
|
||||
sample_input = (
|
||||
db.query(BizProductionTaskInput)
|
||||
.filter(
|
||||
BizProductionTaskInput.task_id == task_id,
|
||||
BizProductionTaskInput.input_type == "sample",
|
||||
BizProductionTaskInput.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if sample_input and (sample_input.input_id or sample_input.input_code):
|
||||
from app.models.models import BizProtocolSample
|
||||
sample = None
|
||||
if sample_input.input_id:
|
||||
sample = (
|
||||
db.query(BizProtocolSample)
|
||||
.filter(BizProtocolSample.id == sample_input.input_id, BizProtocolSample.del_flag == 0)
|
||||
.first()
|
||||
)
|
||||
if not sample and sample_input.input_code:
|
||||
sample = (
|
||||
db.query(BizProtocolSample)
|
||||
.filter(BizProtocolSample.sample_code == sample_input.input_code, BizProtocolSample.del_flag == 0)
|
||||
.first()
|
||||
)
|
||||
if sample:
|
||||
reception_source = wo.reception_source if wo else ""
|
||||
source_labels = {
|
||||
"cell_storage": "细胞存储",
|
||||
"research_donation": "科研捐赠",
|
||||
}
|
||||
protocol_id = sample.collection_protocol_id or ""
|
||||
sample_node = {
|
||||
"id": sample.id,
|
||||
"productCode": sample.sample_code or "",
|
||||
"productName": "",
|
||||
"nodeType": "sample",
|
||||
"sampleCode": sample.sample_code or "",
|
||||
"sampleTypeName": sample_input.input_name or "",
|
||||
"protocolNo": wo.protocol_no if wo else "",
|
||||
"collectionProtocolId": protocol_id,
|
||||
"receptionSource": reception_source,
|
||||
"receptionSourceLabel": source_labels.get(reception_source, reception_source),
|
||||
"customer": _sample_customer_dict(db, protocol_id, tenant_no),
|
||||
"isCurrent": False,
|
||||
}
|
||||
return [{"node": sample_node, "edge": edge, "parent": None}]
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def _build_descendant_chain(
|
||||
db: Session, product_id: str, product_code: str, depth: int, tenant_no: str
|
||||
) -> List[Dict[str, Any]]:
|
||||
if depth >= _MAX_CHAIN_DEPTH:
|
||||
return []
|
||||
|
||||
from app.models.models import BizProductionTaskInput, BizProductionTaskOutput, BizProductionTask, BizProductionWorkOrder
|
||||
|
||||
# 找到引用此产品作为投入物的所有任务(id 或编码)
|
||||
input_match = [BizProductionTaskInput.input_id == product_id]
|
||||
if product_code:
|
||||
input_match.append(BizProductionTaskInput.input_code == product_code)
|
||||
input_rows = (
|
||||
db.query(BizProductionTaskInput)
|
||||
.filter(
|
||||
BizProductionTaskInput.input_type == "cell_product",
|
||||
BizProductionTaskInput.del_flag == 0,
|
||||
or_(*input_match),
|
||||
)
|
||||
.all()
|
||||
)
|
||||
if not input_rows:
|
||||
return []
|
||||
|
||||
task_ids = list({r.task_id for r in input_rows})
|
||||
tasks = (
|
||||
db.query(BizProductionTask)
|
||||
.filter(BizProductionTask.id.in_(task_ids), BizProductionTask.del_flag == 0)
|
||||
.all()
|
||||
)
|
||||
task_by_id = {t.id: t for t in tasks}
|
||||
|
||||
wo_ids = list({t.work_order_id for t in tasks if t.work_order_id})
|
||||
wo_by_id: Dict[str, Any] = {}
|
||||
if wo_ids:
|
||||
wos = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(BizProductionWorkOrder.id.in_(wo_ids), BizProductionWorkOrder.del_flag == 0)
|
||||
.all()
|
||||
)
|
||||
wo_by_id = {w.id: w for w in wos}
|
||||
|
||||
# 对每个任务,找产出
|
||||
result: List[Dict[str, Any]] = []
|
||||
output_rows = (
|
||||
db.query(BizProductionTaskOutput)
|
||||
.filter(
|
||||
BizProductionTaskOutput.task_id.in_(task_ids),
|
||||
BizProductionTaskOutput.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
child_product_ids = list({o.cell_product_id for o in output_rows if o.cell_product_id})
|
||||
child_products = {}
|
||||
if child_product_ids:
|
||||
cps = (
|
||||
db.query(BizCellProduct)
|
||||
.filter(BizCellProduct.id.in_(child_product_ids), BizCellProduct.del_flag == 0)
|
||||
.all()
|
||||
)
|
||||
child_products = {cp.id: cp for cp in cps}
|
||||
|
||||
seen_child_ids: set = set()
|
||||
for o in output_rows:
|
||||
cp = child_products.get(o.cell_product_id)
|
||||
if not cp or cp.id in seen_child_ids:
|
||||
continue
|
||||
seen_child_ids.add(cp.id)
|
||||
t = task_by_id.get(o.task_id)
|
||||
wo_obj = wo_by_id.get(t.work_order_id) if t and t.work_order_id else None
|
||||
edge = _edge_meta(t, wo_obj)
|
||||
|
||||
result.append({
|
||||
"node": _product_node(cp),
|
||||
"edge": edge,
|
||||
"children": _build_descendant_chain(
|
||||
db, cp.id, cp.product_code or "", depth + 1, tenant_no
|
||||
),
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_product_chain(db: Session, product_id: str, tenant_no: str) -> Optional[Dict[str, Any]]:
|
||||
product = get_cell_product(db, product_id, tenant_no)
|
||||
if not product:
|
||||
return None
|
||||
|
||||
return {
|
||||
"current": _product_node(product, is_current=True),
|
||||
"ancestors": _build_ancestor_chain(db, product, 0, tenant_no),
|
||||
"descendants": _build_descendant_chain(
|
||||
db, product.id, product.product_code or "", 0, tenant_no
|
||||
),
|
||||
}
|
||||
@@ -73,6 +73,7 @@ def _task_to_dict(t: BizProductionTask, *, work_order_no: str = "") -> Dict[str,
|
||||
"id": t.id,
|
||||
"taskNo": t.task_no,
|
||||
"workOrderId": t.work_order_id,
|
||||
"orderSource": getattr(t, "order_source", "inbound") or "inbound",
|
||||
"workOrderNo": work_order_no,
|
||||
"taskType": t.task_type or "cell_storage",
|
||||
"taskName": t.task_name or "",
|
||||
@@ -382,13 +383,30 @@ def _clone_route_to_task(
|
||||
def create_production_task(
|
||||
db: Session, *, tenant_no: str, user_id: Optional[str] = None,
|
||||
create_dept_id: str = "", data: Dict[str, Any],
|
||||
order_source: str = "inbound",
|
||||
) -> BizProductionTask:
|
||||
work_order_id = (data.get("work_order_id") or "").strip()
|
||||
wo = None
|
||||
if work_order_id:
|
||||
wo = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(
|
||||
BizProductionWorkOrder.id == work_order_id,
|
||||
BizProductionWorkOrder.tenant_no == tenant_no,
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if wo and (getattr(wo, "work_order_type", None) or "inbound") == "temporary":
|
||||
order_source = "temporary"
|
||||
|
||||
task_no = _generate_task_no(db, tenant_no)
|
||||
now = datetime.now()
|
||||
task = BizProductionTask(
|
||||
id=generate_uuid(),
|
||||
task_no=task_no,
|
||||
work_order_id=data.get("work_order_id", ""),
|
||||
order_source=order_source,
|
||||
task_type=data.get("task_type") or "cell_storage",
|
||||
task_name=(data.get("task_name") or "").strip() or None,
|
||||
description=(data.get("description") or "").strip() or None,
|
||||
@@ -417,6 +435,13 @@ def create_production_task(
|
||||
production_work_order_svc.sync_production_work_order_status_from_tasks(
|
||||
db, task.work_order_id or "", tenant_no, user_id
|
||||
)
|
||||
if wo and (getattr(wo, "work_order_type", None) or "inbound") == "temporary":
|
||||
if not getattr(wo, "configured_time", None):
|
||||
wo.configured_time = now
|
||||
wo.configured_by = user_id
|
||||
wo.update_by = user_id
|
||||
wo.update_time = now
|
||||
db.add(wo)
|
||||
db.flush()
|
||||
return task
|
||||
|
||||
@@ -579,11 +604,9 @@ def list_production_tasks(
|
||||
if wo:
|
||||
item["protocolNo"] = wo.protocol_no or ""
|
||||
item["sampleCode"] = wo.sample_code or ""
|
||||
# 接收人、接收时间
|
||||
reception = reception_map.get(wo.reception_id) if wo.reception_id else None
|
||||
item["receiverName"] = reception.handler_name or "" if reception else ""
|
||||
item["receptionTime"] = _fmt_dt(reception.reception_time) if reception else ""
|
||||
# 样本类型
|
||||
item["sampleTypeName"] = sample_type_map.get(wo.protocol_sample_id, "") if wo.protocol_sample_id else ""
|
||||
return items, int(total)
|
||||
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
"""入库生产工单 CRUD"""
|
||||
"""入库生产工单 CRUD(含临时生产工单)"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from sqlalchemy import func, or_
|
||||
from sqlalchemy import and_, func, or_
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.utils import generate_uuid
|
||||
from app.crud.collection_protocol import urls_to_attachment_list
|
||||
from app.crud import sample_reception as sample_reception_svc
|
||||
from app.crud import sample_reception_check_result as check_result_svc
|
||||
from app.crud import production_task as production_task_svc
|
||||
from app.models.models import (
|
||||
BizCollectionProtocol,
|
||||
BizProductionTask,
|
||||
BizProductionTaskInput,
|
||||
BizProductionTaskOutput,
|
||||
BizProductionTaskStep,
|
||||
BizProductionTaskStepConsumable,
|
||||
BizProductionTaskStepDataCollection,
|
||||
BizProductionTaskStepOutput,
|
||||
BizProductionTaskStepReagent,
|
||||
BizProductionWorkOrder,
|
||||
BizProtocolSample,
|
||||
BizSampleReception,
|
||||
@@ -39,6 +45,18 @@ def _fmt_dt(t: Optional[datetime]) -> str:
|
||||
return t.strftime("%Y-%m-%d %H:%M:%S") if t else ""
|
||||
|
||||
|
||||
def _soft_delete_sub(db: Session, model_class, parent_field: str, parent_id: str, now: datetime) -> None:
|
||||
rows = db.query(model_class).filter(
|
||||
and_(
|
||||
getattr(model_class, parent_field) == parent_id,
|
||||
model_class.del_flag == 0,
|
||||
)
|
||||
).all()
|
||||
for r in rows:
|
||||
r.del_flag = 1
|
||||
r.update_time = now
|
||||
|
||||
|
||||
def _generate_work_order_no(db: Session, tenant_no: str) -> str:
|
||||
today_str = datetime.now().strftime("%Y%m%d")
|
||||
prefix = f"SC{today_str}"
|
||||
@@ -62,6 +80,7 @@ def _wo_to_dict(wo: BizProductionWorkOrder) -> Dict[str, Any]:
|
||||
return {
|
||||
"id": wo.id,
|
||||
"workOrderNo": wo.work_order_no,
|
||||
"workOrderType": getattr(wo, "work_order_type", None) or "inbound",
|
||||
"receptionId": wo.reception_id,
|
||||
"protocolSampleId": wo.protocol_sample_id,
|
||||
"collectionProtocolId": wo.collection_protocol_id,
|
||||
@@ -276,6 +295,8 @@ def list_production_work_orders(
|
||||
q0 = q0.filter(BizProductionWorkOrder.work_order_no.like(like))
|
||||
if query.work_order_status and query.work_order_status.strip():
|
||||
q0 = q0.filter(BizProductionWorkOrder.work_order_status == query.work_order_status.strip())
|
||||
if query.work_order_type and query.work_order_type.strip():
|
||||
q0 = q0.filter(BizProductionWorkOrder.work_order_type == query.work_order_type.strip())
|
||||
if query.protocol_no and query.protocol_no.strip():
|
||||
like = f"%{query.protocol_no.strip()}%"
|
||||
q0 = q0.filter(BizProductionWorkOrder.protocol_no.like(like))
|
||||
@@ -516,3 +537,350 @@ def get_production_info_map_for_samples(
|
||||
if sid:
|
||||
out[sid] = _production_info_item(db, wo)
|
||||
return out
|
||||
|
||||
|
||||
def create_production_work_order_manual(
|
||||
db: Session,
|
||||
*,
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
protocol_no: str = "",
|
||||
sample_code: str = "",
|
||||
reception_source: str = "cell_storage",
|
||||
remark: str = "",
|
||||
) -> BizProductionWorkOrder:
|
||||
"""手动创建生产工单(不关联接收记录)"""
|
||||
wo = BizProductionWorkOrder(
|
||||
id=generate_uuid(),
|
||||
work_order_no=_generate_work_order_no(db, tenant_no),
|
||||
work_order_type="inbound",
|
||||
reception_id=None,
|
||||
protocol_sample_id=None,
|
||||
collection_protocol_id=None,
|
||||
protocol_no=protocol_no or None,
|
||||
sample_code=sample_code or None,
|
||||
reception_source=reception_source,
|
||||
work_order_status="dpz",
|
||||
tenant_no=tenant_no,
|
||||
remark=remark,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id,
|
||||
)
|
||||
db.add(wo)
|
||||
db.flush()
|
||||
return wo
|
||||
|
||||
|
||||
def delete_production_work_order(db: Session, work_order_id: str, tenant_no: str, user_id: Optional[str]) -> None:
|
||||
wo = db.query(BizProductionWorkOrder).filter(
|
||||
and_(
|
||||
BizProductionWorkOrder.id == work_order_id,
|
||||
BizProductionWorkOrder.tenant_no == tenant_no,
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
)
|
||||
).first()
|
||||
if not wo:
|
||||
raise ValueError("工单不存在")
|
||||
if wo.work_order_status == "ywc":
|
||||
raise ValueError("已完成的工单不能删除")
|
||||
|
||||
now = datetime.now()
|
||||
|
||||
tasks = db.query(BizProductionTask).filter(
|
||||
and_(BizProductionTask.work_order_id == work_order_id, BizProductionTask.del_flag == 0)
|
||||
).all()
|
||||
|
||||
for task in tasks:
|
||||
steps = db.query(BizProductionTaskStep).filter(
|
||||
and_(BizProductionTaskStep.task_id == task.id, BizProductionTaskStep.del_flag == 0)
|
||||
).all()
|
||||
for step in steps:
|
||||
_soft_delete_sub(db, BizProductionTaskStepReagent, "step_id", step.id, now)
|
||||
_soft_delete_sub(db, BizProductionTaskStepConsumable, "step_id", step.id, now)
|
||||
_soft_delete_sub(db, BizProductionTaskStepOutput, "step_id", step.id, now)
|
||||
_soft_delete_sub(db, BizProductionTaskStepDataCollection, "step_id", step.id, now)
|
||||
step.del_flag = 1
|
||||
step.update_by = user_id
|
||||
step.update_time = now
|
||||
|
||||
_soft_delete_sub(db, BizProductionTaskInput, "task_id", task.id, now)
|
||||
_soft_delete_sub(db, BizProductionTaskOutput, "task_id", task.id, now)
|
||||
|
||||
task.del_flag = 1
|
||||
task.update_by = user_id
|
||||
task.update_time = now
|
||||
|
||||
wo.del_flag = 1
|
||||
wo.update_by = user_id
|
||||
wo.update_time = now
|
||||
|
||||
db.commit()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 临时生产工单(work_order_type='temporary')
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _generate_temp_work_order_no(db: Session, tenant_no: str) -> str:
|
||||
today_str = datetime.now().strftime("%Y%m%d")
|
||||
prefix = f"LSSC{today_str}"
|
||||
last = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(
|
||||
BizProductionWorkOrder.tenant_no == tenant_no,
|
||||
BizProductionWorkOrder.work_order_no.like(f"{prefix}%"),
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
)
|
||||
.order_by(BizProductionWorkOrder.work_order_no.desc())
|
||||
.first()
|
||||
)
|
||||
seq = 1
|
||||
if last:
|
||||
seq = int(last.work_order_no[-4:]) + 1
|
||||
return f"{prefix}{seq:04d}"
|
||||
|
||||
|
||||
def _temp_wo_to_dict(wo: BizProductionWorkOrder) -> Dict[str, Any]:
|
||||
return {
|
||||
"id": wo.id,
|
||||
"workOrderNo": wo.work_order_no,
|
||||
"workOrderStatus": wo.work_order_status,
|
||||
"workOrderStatusLabel": _WORK_ORDER_STATUS_LABELS.get(wo.work_order_status, wo.work_order_status),
|
||||
"configuredTime": _fmt_dt(getattr(wo, "configured_time", None)),
|
||||
"configuredBy": getattr(wo, "configured_by", None) or "",
|
||||
"remark": wo.remark or "",
|
||||
"createTime": _fmt_dt(wo.create_time),
|
||||
"updateTime": _fmt_dt(wo.update_time),
|
||||
}
|
||||
|
||||
|
||||
def create_temp_production_work_order(
|
||||
db: Session,
|
||||
*,
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
remark: str = "",
|
||||
) -> BizProductionWorkOrder:
|
||||
wo = BizProductionWorkOrder(
|
||||
id=generate_uuid(),
|
||||
work_order_no=_generate_temp_work_order_no(db, tenant_no),
|
||||
work_order_type="temporary",
|
||||
work_order_status="dpz",
|
||||
tenant_no=tenant_no,
|
||||
remark=remark,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id,
|
||||
update_by=user_id,
|
||||
create_time=datetime.now(),
|
||||
update_time=datetime.now(),
|
||||
del_flag=0,
|
||||
)
|
||||
db.add(wo)
|
||||
db.flush()
|
||||
return wo
|
||||
|
||||
|
||||
def list_temp_production_work_orders(
|
||||
db: Session,
|
||||
*,
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
keyword: Optional[str] = None,
|
||||
work_order_status: Optional[str] = None,
|
||||
tenant_no: Optional[str] = None,
|
||||
user_info=None,
|
||||
) -> Tuple[List[Dict[str, Any]], int]:
|
||||
q = db.query(BizProductionWorkOrder).filter(
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
BizProductionWorkOrder.work_order_type == "temporary",
|
||||
)
|
||||
if tenant_no:
|
||||
q = q.filter(BizProductionWorkOrder.tenant_no == tenant_no)
|
||||
kw = (keyword or "").strip()
|
||||
if kw:
|
||||
like = f"%{kw}%"
|
||||
q = q.filter(BizProductionWorkOrder.work_order_no.like(like))
|
||||
if work_order_status and work_order_status.strip():
|
||||
q = q.filter(BizProductionWorkOrder.work_order_status == work_order_status.strip())
|
||||
if user_info:
|
||||
from app.core.data_scope import apply_data_scope
|
||||
q = apply_data_scope(q, BizProductionWorkOrder, user_info, db, tenant_no or "")
|
||||
total = q.order_by(None).with_entities(func.count(BizProductionWorkOrder.id)).scalar() or 0
|
||||
page = max(1, page)
|
||||
page_size = min(max(1, page_size), 100)
|
||||
rows = (
|
||||
q.order_by(BizProductionWorkOrder.create_time.desc())
|
||||
.offset((page - 1) * page_size)
|
||||
.limit(page_size)
|
||||
.all()
|
||||
)
|
||||
items = [_temp_wo_to_dict(x) for x in rows]
|
||||
return items, int(total)
|
||||
|
||||
|
||||
def get_temp_production_work_order(
|
||||
db: Session, row_id: str, tenant_no: str
|
||||
) -> Optional[BizProductionWorkOrder]:
|
||||
return (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(
|
||||
BizProductionWorkOrder.id == row_id,
|
||||
BizProductionWorkOrder.tenant_no == tenant_no,
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
BizProductionWorkOrder.work_order_type == "temporary",
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
|
||||
def get_temp_production_work_order_detail(
|
||||
db: Session, row_id: str, tenant_no: str
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
wo = get_temp_production_work_order(db, row_id, tenant_no)
|
||||
if not wo:
|
||||
return None
|
||||
result = _temp_wo_to_dict(wo)
|
||||
tasks = (
|
||||
db.query(BizProductionTask)
|
||||
.filter(
|
||||
BizProductionTask.work_order_id == row_id,
|
||||
BizProductionTask.order_source == "temporary",
|
||||
BizProductionTask.tenant_no == tenant_no,
|
||||
BizProductionTask.del_flag == 0,
|
||||
)
|
||||
.order_by(BizProductionTask.order_num, BizProductionTask.create_time)
|
||||
.all()
|
||||
)
|
||||
result["tasks"] = [production_task_svc._task_to_dict(t) for t in tasks]
|
||||
return result
|
||||
|
||||
|
||||
def configure_temp_production_work_order(
|
||||
db: Session,
|
||||
work_order_id: str,
|
||||
*,
|
||||
task_name: str,
|
||||
task_type: str,
|
||||
route_id: Optional[str],
|
||||
description: str,
|
||||
remark: str,
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
) -> BizProductionWorkOrder:
|
||||
wo = get_temp_production_work_order(db, work_order_id, tenant_no)
|
||||
if not wo:
|
||||
raise ValueError("工单不存在")
|
||||
if wo.work_order_status != "dpz":
|
||||
raise ValueError("工单已配置,不能重复配置")
|
||||
|
||||
production_task_svc.create_production_task(
|
||||
db,
|
||||
tenant_no=tenant_no,
|
||||
user_id=user_id,
|
||||
create_dept_id=create_dept_id,
|
||||
data={
|
||||
"work_order_id": work_order_id,
|
||||
"task_name": task_name,
|
||||
"task_type": task_type,
|
||||
"route_id": route_id,
|
||||
"description": description,
|
||||
"remark": remark,
|
||||
},
|
||||
order_source="temporary",
|
||||
)
|
||||
|
||||
now = datetime.now()
|
||||
wo.work_order_status = "jxz"
|
||||
wo.configured_time = now
|
||||
wo.configured_by = user_id
|
||||
wo.update_by = user_id
|
||||
wo.update_time = now
|
||||
db.add(wo)
|
||||
db.flush()
|
||||
return wo
|
||||
|
||||
|
||||
def sync_temp_production_work_order_status(
|
||||
db: Session,
|
||||
work_order_id: str,
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
) -> None:
|
||||
if not (work_order_id or "").strip():
|
||||
return
|
||||
wo = get_temp_production_work_order(db, work_order_id.strip(), tenant_no)
|
||||
if not wo:
|
||||
return
|
||||
tasks = (
|
||||
db.query(BizProductionTask.task_status)
|
||||
.filter(
|
||||
BizProductionTask.work_order_id == work_order_id.strip(),
|
||||
BizProductionTask.order_source == "temporary",
|
||||
BizProductionTask.tenant_no == tenant_no,
|
||||
BizProductionTask.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
if not tasks:
|
||||
new_status = "dpz"
|
||||
elif all(t.task_status == "ywc" for t in tasks):
|
||||
new_status = "ywc"
|
||||
else:
|
||||
new_status = "jxz"
|
||||
if wo.work_order_status == new_status:
|
||||
return
|
||||
now = datetime.now()
|
||||
wo.work_order_status = new_status
|
||||
wo.update_by = user_id
|
||||
wo.update_time = now
|
||||
db.add(wo)
|
||||
|
||||
|
||||
def delete_temp_production_work_order(
|
||||
db: Session, work_order_id: str, tenant_no: str, user_id: Optional[str]
|
||||
) -> None:
|
||||
wo = get_temp_production_work_order(db, work_order_id, tenant_no)
|
||||
if not wo:
|
||||
raise ValueError("工单不存在")
|
||||
if wo.work_order_status == "ywc":
|
||||
raise ValueError("已完成的工单不能删除")
|
||||
|
||||
now = datetime.now()
|
||||
|
||||
tasks = db.query(BizProductionTask).filter(
|
||||
and_(
|
||||
BizProductionTask.work_order_id == work_order_id,
|
||||
BizProductionTask.order_source == "temporary",
|
||||
BizProductionTask.del_flag == 0,
|
||||
)
|
||||
).all()
|
||||
|
||||
for task in tasks:
|
||||
steps = db.query(BizProductionTaskStep).filter(
|
||||
and_(BizProductionTaskStep.task_id == task.id, BizProductionTaskStep.del_flag == 0)
|
||||
).all()
|
||||
for step in steps:
|
||||
_soft_delete_sub(db, BizProductionTaskStepReagent, "step_id", step.id, now)
|
||||
_soft_delete_sub(db, BizProductionTaskStepConsumable, "step_id", step.id, now)
|
||||
_soft_delete_sub(db, BizProductionTaskStepOutput, "step_id", step.id, now)
|
||||
_soft_delete_sub(db, BizProductionTaskStepDataCollection, "step_id", step.id, now)
|
||||
step.del_flag = 1
|
||||
step.update_by = user_id
|
||||
step.update_time = now
|
||||
|
||||
_soft_delete_sub(db, BizProductionTaskInput, "task_id", task.id, now)
|
||||
_soft_delete_sub(db, BizProductionTaskOutput, "task_id", task.id, now)
|
||||
|
||||
task.del_flag = 1
|
||||
task.update_by = user_id
|
||||
task.update_time = now
|
||||
|
||||
wo.del_flag = 1
|
||||
wo.update_by = user_id
|
||||
wo.update_time = now
|
||||
|
||||
db.commit()
|
||||
+123
-9
@@ -38,7 +38,7 @@ def _fmt_dt(t: Optional[datetime]) -> str:
|
||||
return t.strftime("%Y-%m-%d %H:%M:%S") if t else ""
|
||||
|
||||
|
||||
def _gen_task_no(db: Session, work_order: BizQcWorkOrder, seq: int) -> str:
|
||||
def _gen_task_no(db: Session, work_order, seq: int) -> str:
|
||||
return f"{work_order.work_order_no}-{seq:02d}"
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ def _task_to_dict(
|
||||
return {
|
||||
"id": t.id,
|
||||
"workOrderId": t.work_order_id,
|
||||
"orderSource": getattr(t, "order_source", "inbound") or "inbound",
|
||||
"workOrderNo": work_order_no,
|
||||
"taskNo": t.task_no,
|
||||
"taskType": t.task_type,
|
||||
@@ -90,15 +91,26 @@ def _task_to_dict(
|
||||
|
||||
def _task_work_order_context(wo: BizQcWorkOrder, t: BizQcTask) -> Dict[str, Any]:
|
||||
biz = _work_order_qc_biz_type(wo)
|
||||
source = getattr(wo, "reception_source", "cell_storage") or "cell_storage"
|
||||
order_source = getattr(t, "order_source", "inbound") or "inbound"
|
||||
wo_type = getattr(wo, "work_order_type", None) or "inbound"
|
||||
if order_source == "temporary" or wo_type == "temporary":
|
||||
recv_source = ""
|
||||
else:
|
||||
recv_source = getattr(wo, "reception_source", "cell_storage") or "cell_storage"
|
||||
return {
|
||||
"receptionId": wo.reception_id,
|
||||
"protocolNo": wo.protocol_no or "",
|
||||
"sampleCode": wo.sample_code or t.sample_code or "",
|
||||
"qcBizType": biz,
|
||||
"qcBizTypeLabel": _qc_biz_type_label(biz),
|
||||
"receptionSource": source,
|
||||
"receptionSourceLabel": _reception_source_label(source),
|
||||
"receptionSource": recv_source,
|
||||
"receptionSourceLabel": _reception_source_label(recv_source) if recv_source else "",
|
||||
"cellProductId": getattr(wo, "cell_product_id", None) or "",
|
||||
"cellProductCode": "",
|
||||
"cellProductName": "",
|
||||
"cellProductTypeName": "",
|
||||
"cellProductPassage": "",
|
||||
"cellProductSpecName": "",
|
||||
"receptionTime": "",
|
||||
"handlerName": "",
|
||||
"sampleTypeName": "",
|
||||
@@ -184,6 +196,10 @@ def _enrich_tasks_reception_fields(
|
||||
):
|
||||
donation_status_map[d.id] = d.donation_status or ""
|
||||
for item in items:
|
||||
if item.get("orderSource") == "temporary":
|
||||
item["receptionSource"] = ""
|
||||
item["receptionSourceLabel"] = ""
|
||||
continue
|
||||
rec = rec_map.get(item.get("receptionId") or "")
|
||||
if not rec:
|
||||
continue
|
||||
@@ -236,14 +252,16 @@ def create_task_for_line(
|
||||
company_id: Optional[str] = None,
|
||||
company_name: Optional[str] = None,
|
||||
fee_amount: Optional[Decimal] = None,
|
||||
order_source: str = "inbound",
|
||||
) -> BizQcTask:
|
||||
obj = BizQcTask(
|
||||
id=generate_uuid(),
|
||||
work_order_id=work_order.id,
|
||||
order_source=order_source,
|
||||
task_no=_gen_task_no(db, work_order, seq),
|
||||
task_type=task_type,
|
||||
source_line_id=source_line_id,
|
||||
sample_code=work_order.sample_code or None,
|
||||
sample_code=getattr(work_order, "sample_code", None) or None,
|
||||
item_code=item_code,
|
||||
item_name=item_name,
|
||||
company_id=company_id,
|
||||
@@ -313,7 +331,15 @@ def list_tasks(
|
||||
q0 = q0.filter(BizQcTask.task_status == st)
|
||||
bt = (qc_biz_type or "").strip()
|
||||
if bt:
|
||||
q0 = q0.filter(BizQcWorkOrder.qc_biz_type == bt)
|
||||
if bt == "temporary":
|
||||
q0 = q0.filter(
|
||||
or_(
|
||||
BizQcWorkOrder.qc_biz_type == "temporary",
|
||||
BizQcWorkOrder.work_order_type == "temporary",
|
||||
)
|
||||
)
|
||||
else:
|
||||
q0 = q0.filter(BizQcWorkOrder.qc_biz_type == bt)
|
||||
if user_info:
|
||||
from app.core.data_scope import apply_data_scope
|
||||
q0 = apply_data_scope(q0, BizQcTask, user_info, db, tenant_no)
|
||||
@@ -380,9 +406,13 @@ def get_task_detail(db: Session, row_id: str, tenant_no: str) -> Dict[str, Any]:
|
||||
t, wo = row
|
||||
out = _task_row_to_dict(t, wo, db, tenant_no)
|
||||
out = _enrich_tasks_reception_fields(db, [out])[0]
|
||||
reception_detail = sample_reception_svc.get_reception_by_id(db, wo.reception_id, tenant_no)
|
||||
if reception_detail:
|
||||
out["reception"] = reception_detail
|
||||
from app.crud.qc_work_order import _enrich_work_order_cell_products
|
||||
|
||||
out = _enrich_work_order_cell_products(db, tenant_no, [out])[0]
|
||||
if (out.get("qcBizType") or "") != "temporary":
|
||||
reception_detail = sample_reception_svc.get_reception_by_id(db, wo.reception_id, tenant_no)
|
||||
if reception_detail:
|
||||
out["reception"] = reception_detail
|
||||
return out
|
||||
|
||||
|
||||
@@ -531,3 +561,87 @@ def update_task_attachments(
|
||||
else:
|
||||
db.flush()
|
||||
return t
|
||||
|
||||
|
||||
def create_qc_task_manual(
|
||||
db: Session,
|
||||
*,
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
task_type: str = "sysz",
|
||||
item_code: str = "",
|
||||
item_name: str = "",
|
||||
company_id: Optional[str] = None,
|
||||
company_name: Optional[str] = None,
|
||||
fee_amount: Optional[float] = None,
|
||||
sample_code: str = "",
|
||||
work_order_id: str = "",
|
||||
remark: str = "",
|
||||
) -> BizQcTask:
|
||||
"""手动创建质检任务(可独立于工单)"""
|
||||
# 生成任务号:ZJRW + 日期 + 序号
|
||||
day = datetime.now().strftime("%Y%m%d")
|
||||
like = f"ZJRW{day}%"
|
||||
cnt = db.query(BizQcTask).filter(
|
||||
BizQcTask.tenant_no == tenant_no,
|
||||
BizQcTask.task_no.like(like),
|
||||
).count()
|
||||
task_no = f"ZJRW{day}{cnt + 1:04d}"
|
||||
|
||||
task = BizQcTask(
|
||||
id=generate_uuid(),
|
||||
work_order_id=work_order_id or "",
|
||||
task_no=task_no,
|
||||
task_type=task_type,
|
||||
source_line_id="",
|
||||
sample_code=sample_code,
|
||||
item_code=item_code,
|
||||
item_name=item_name,
|
||||
company_id=company_id,
|
||||
company_name=company_name,
|
||||
fee_amount=fee_amount,
|
||||
task_status="dzx",
|
||||
tenant_no=tenant_no,
|
||||
remark=remark,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id,
|
||||
)
|
||||
db.add(task)
|
||||
db.flush()
|
||||
return task
|
||||
|
||||
|
||||
def delete_qc_task(db: Session, task_id: str, tenant_no: str, user_id: Optional[str]) -> None:
|
||||
"""软删除质检任务及其关联的检测结果"""
|
||||
task = db.query(BizQcTask).filter(
|
||||
and_(
|
||||
BizQcTask.id == task_id,
|
||||
BizQcTask.tenant_no == tenant_no,
|
||||
BizQcTask.del_flag == 0,
|
||||
)
|
||||
).first()
|
||||
if not task:
|
||||
raise ValueError("任务不存在")
|
||||
if task.task_status != "dzx":
|
||||
raise ValueError("仅待执行的任务可以删除")
|
||||
|
||||
now = datetime.now()
|
||||
|
||||
# 软删除任务结果
|
||||
from app.models.qc_param import BizQcTaskResult
|
||||
|
||||
results = db.query(BizQcTaskResult).filter(
|
||||
and_(BizQcTaskResult.task_id == task_id, BizQcTaskResult.del_flag == 0)
|
||||
).all()
|
||||
for r in results:
|
||||
r.del_flag = 1
|
||||
r.update_by = user_id
|
||||
r.update_time = now
|
||||
|
||||
# 软删除任务本体
|
||||
task.del_flag = 1
|
||||
task.update_by = user_id
|
||||
task.update_time = now
|
||||
|
||||
db.commit()
|
||||
@@ -16,7 +16,9 @@ from app.crud.qc_third_party_company import get_company
|
||||
from app.crud.collection_protocol import urls_to_attachment_list
|
||||
from app.crud import sample_reception as sample_reception_svc
|
||||
from app.crud import sample_reception_check_result as check_result_svc
|
||||
from app.crud.cell_product import _enrich_product_dicts as _cp_enrich, _row_to_dict as _cp_row_to_dict, get_cell_product
|
||||
from app.models.models import (
|
||||
BizCellProduct,
|
||||
BizCellSampleType,
|
||||
BizCollectionProtocol,
|
||||
BizProtocolSample,
|
||||
@@ -38,6 +40,7 @@ _RECEPTION_SOURCE_LABELS = {
|
||||
_QC_BIZ_TYPE_LABELS = {
|
||||
"inbound": "入库质检",
|
||||
"outbound": "出库质检",
|
||||
"temporary": "临时质检",
|
||||
}
|
||||
_ACCEPT_CONCLUSION_LABELS = {"js": "接收", "bj": "拒收"}
|
||||
_WORK_ORDER_STATUS_LABELS = {"dpz": "待配置", "ypz": "已配置", "ywc": "已完成"}
|
||||
@@ -73,9 +76,53 @@ def _qc_biz_type_label(biz_type: Optional[str]) -> str:
|
||||
|
||||
|
||||
def _work_order_qc_biz_type(wo: BizQcWorkOrder) -> str:
|
||||
wo_type = getattr(wo, "work_order_type", None) or "inbound"
|
||||
if wo_type == "temporary":
|
||||
return "temporary"
|
||||
return getattr(wo, "qc_biz_type", None) or "inbound"
|
||||
|
||||
|
||||
def _validate_cell_product_id(
|
||||
db: Session, cell_product_id: Optional[str], tenant_no: str
|
||||
) -> str:
|
||||
cp_id = (cell_product_id or "").strip()
|
||||
if not cp_id:
|
||||
raise ValueError("请选择质检对象(细胞产品)")
|
||||
cp = get_cell_product(db, cp_id, tenant_no)
|
||||
if not cp:
|
||||
raise ValueError("细胞产品不存在")
|
||||
return cp_id
|
||||
|
||||
|
||||
def _enrich_work_order_cell_products(
|
||||
db: Session, tenant_no: str, items: List[Dict[str, Any]]
|
||||
) -> List[Dict[str, Any]]:
|
||||
if not items:
|
||||
return items
|
||||
cp_ids = list({x.get("cellProductId") for x in items if x.get("cellProductId")})
|
||||
if not cp_ids:
|
||||
return items
|
||||
products = (
|
||||
db.query(BizCellProduct)
|
||||
.filter(
|
||||
BizCellProduct.id.in_(cp_ids),
|
||||
BizCellProduct.tenant_no == tenant_no,
|
||||
BizCellProduct.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.get("cellProductId") or "")
|
||||
item["cellProductCode"] = cp.get("productCode", "") if cp else ""
|
||||
item["cellProductName"] = cp.get("productName", "") if cp else ""
|
||||
item["cellProductTypeName"] = cp.get("productTypeName", "") if cp else ""
|
||||
item["cellProductPassage"] = cp.get("passage", "") if cp else ""
|
||||
item["cellProductSpecName"] = cp.get("specName", "") if cp else ""
|
||||
return items
|
||||
|
||||
|
||||
def _accept_conclusion_label(v: Optional[str]) -> str:
|
||||
key = (v or "").strip()
|
||||
return _ACCEPT_CONCLUSION_LABELS.get(key, key)
|
||||
@@ -188,6 +235,10 @@ def _enrich_work_order_list_items(
|
||||
):
|
||||
donation_status_map[d.id] = d.donation_status or ""
|
||||
for item in items:
|
||||
if item.get("workOrderType") == "temporary":
|
||||
item["receptionSource"] = ""
|
||||
item["receptionSourceLabel"] = ""
|
||||
continue
|
||||
rec = rec_map.get(item.get("receptionId") or "")
|
||||
source = item.get("receptionSource") or (rec.reception_source if rec else "cell_storage")
|
||||
item["receptionSourceLabel"] = _reception_source_label(source)
|
||||
@@ -233,24 +284,38 @@ def _gen_daily_no(db: Session, tenant_no: str, prefix: str) -> str:
|
||||
|
||||
|
||||
def _wo_to_dict(wo: BizQcWorkOrder) -> Dict[str, Any]:
|
||||
wo_type = getattr(wo, "work_order_type", None) or "inbound"
|
||||
recv_source_raw = getattr(wo, "reception_source", None)
|
||||
if wo_type == "temporary":
|
||||
recv_source = (recv_source_raw or "").strip()
|
||||
else:
|
||||
recv_source = (recv_source_raw or "cell_storage").strip() or "cell_storage"
|
||||
return {
|
||||
"id": wo.id,
|
||||
"workOrderNo": wo.work_order_no,
|
||||
"workOrderType": wo_type,
|
||||
"receptionId": wo.reception_id,
|
||||
"protocolSampleId": wo.protocol_sample_id,
|
||||
"collectionProtocolId": wo.collection_protocol_id,
|
||||
"protocolNo": wo.protocol_no or "",
|
||||
"sampleCode": wo.sample_code or "",
|
||||
"receptionSource": getattr(wo, "reception_source", "cell_storage") or "cell_storage",
|
||||
"receptionSourceLabel": _reception_source_label(
|
||||
getattr(wo, "reception_source", "cell_storage") or "cell_storage"
|
||||
),
|
||||
"receptionSource": recv_source,
|
||||
"receptionSourceLabel": _reception_source_label(recv_source) if recv_source else "",
|
||||
"qcBizType": _work_order_qc_biz_type(wo),
|
||||
"qcBizTypeLabel": _qc_biz_type_label(_work_order_qc_biz_type(wo)),
|
||||
"cellProductId": getattr(wo, "cell_product_id", None) or "",
|
||||
"cellProductCode": "",
|
||||
"cellProductName": "",
|
||||
"cellProductTypeName": "",
|
||||
"cellProductPassage": "",
|
||||
"cellProductSpecName": "",
|
||||
"receptionTime": "",
|
||||
"handlerName": "",
|
||||
"sampleTypeName": "",
|
||||
"workOrderStatus": wo.work_order_status,
|
||||
"workOrderStatusLabel": _WORK_ORDER_STATUS_LABELS.get(
|
||||
wo.work_order_status or "", wo.work_order_status or ""
|
||||
),
|
||||
"hasLab": wo.has_lab == "1",
|
||||
"hasThirdParty": wo.has_third_party == "1",
|
||||
"configuredTime": _fmt_dt(wo.configured_time),
|
||||
@@ -384,6 +449,7 @@ def list_work_orders(
|
||||
page_size: int = 10,
|
||||
keyword: Optional[str] = None,
|
||||
work_order_status: Optional[str] = None,
|
||||
work_order_type: Optional[str] = None,
|
||||
tenant_no: Optional[str] = None,
|
||||
user_info=None,
|
||||
) -> Tuple[List[Dict[str, Any]], int]:
|
||||
@@ -391,6 +457,9 @@ def list_work_orders(
|
||||
q0 = db.query(BizQcWorkOrder).filter(BizQcWorkOrder.del_flag == 0)
|
||||
if tenant_no:
|
||||
q0 = q0.filter(BizQcWorkOrder.tenant_no == tenant_no)
|
||||
wt = (work_order_type or "").strip()
|
||||
if wt:
|
||||
q0 = q0.filter(BizQcWorkOrder.work_order_type == wt)
|
||||
kw = (keyword or "").strip()
|
||||
if kw:
|
||||
like = f"%{kw}%"
|
||||
@@ -420,7 +489,10 @@ def list_work_orders(
|
||||
.all()
|
||||
)
|
||||
items = [_wo_to_dict(x) for x in rows]
|
||||
return _enrich_work_order_list_items(db, items), int(total)
|
||||
items = _enrich_work_order_list_items(db, items)
|
||||
if tenant_no:
|
||||
items = _enrich_work_order_cell_products(db, tenant_no, items)
|
||||
return items, int(total)
|
||||
|
||||
|
||||
def get_work_order(
|
||||
@@ -568,13 +640,21 @@ def get_work_order_detail(
|
||||
if not wo:
|
||||
raise ValueError("工单不存在")
|
||||
out = _wo_to_dict(wo)
|
||||
enriched = _enrich_work_order_list_items(db, [out])[0]
|
||||
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 = enriched_list[0]
|
||||
out.update(
|
||||
{
|
||||
"receptionTime": enriched.get("receptionTime", ""),
|
||||
"handlerName": enriched.get("handlerName", ""),
|
||||
"sampleTypeName": enriched.get("sampleTypeName", ""),
|
||||
"receptionSourceLabel": enriched.get("receptionSourceLabel", ""),
|
||||
"cellProductCode": enriched.get("cellProductCode", ""),
|
||||
"cellProductName": enriched.get("cellProductName", ""),
|
||||
"cellProductTypeName": enriched.get("cellProductTypeName", ""),
|
||||
"cellProductPassage": enriched.get("cellProductPassage", ""),
|
||||
"cellProductSpecName": enriched.get("cellProductSpecName", ""),
|
||||
}
|
||||
)
|
||||
reception_detail = sample_reception_svc.get_reception_by_id(db, wo.reception_id, tenant_no)
|
||||
@@ -664,6 +744,7 @@ def configure_work_order(
|
||||
raise ValueError("工单已完成,无法调整检测项目")
|
||||
if wo.work_order_status not in ("dpz", "ypz"):
|
||||
raise ValueError("当前工单状态不可配置检测项目")
|
||||
order_source = "temporary" if (getattr(wo, "work_order_type", None) or "inbound") == "temporary" else "inbound"
|
||||
if wo.work_order_status == "ypz":
|
||||
_soft_delete_pending_work_order_tasks(db, wo.id, tenant_no)
|
||||
|
||||
@@ -703,6 +784,7 @@ def configure_work_order(
|
||||
line = BizQcWorkOrderLabItem(
|
||||
id=generate_uuid(),
|
||||
work_order_id=wo.id,
|
||||
order_source=order_source,
|
||||
lab_test_item_id=item.id,
|
||||
item_code=item.item_code,
|
||||
item_name=item.item_name,
|
||||
@@ -728,6 +810,7 @@ def configure_work_order(
|
||||
user_id=user_id,
|
||||
create_dept_id=create_dept_id,
|
||||
seq=seq,
|
||||
order_source=order_source,
|
||||
)
|
||||
|
||||
for tid in third_party_item_ids:
|
||||
@@ -743,6 +826,7 @@ def configure_work_order(
|
||||
line = BizQcWorkOrderThirdItem(
|
||||
id=generate_uuid(),
|
||||
work_order_id=wo.id,
|
||||
order_source=order_source,
|
||||
third_party_item_id=item.id,
|
||||
company_id=comp.id,
|
||||
company_name=comp.company_name,
|
||||
@@ -774,6 +858,7 @@ def configure_work_order(
|
||||
company_id=comp.id,
|
||||
company_name=comp.company_name,
|
||||
fee_amount=fee,
|
||||
order_source=order_source,
|
||||
)
|
||||
|
||||
wo.has_lab = "1" if has_lab else "0"
|
||||
@@ -804,8 +889,599 @@ def try_complete_work_order(db: Session, work_order_id: str, tenant_no: str) ->
|
||||
if pending:
|
||||
return
|
||||
wo = get_work_order(db, work_order_id, tenant_no=tenant_no)
|
||||
if wo and wo.work_order_status == "ypz":
|
||||
wo.work_order_status = "ywc"
|
||||
wo.update_time = datetime.now()
|
||||
db.add(wo)
|
||||
db.commit()
|
||||
|
||||
|
||||
# ---------- 临时质检工单 ----------
|
||||
|
||||
|
||||
def _temp_lab_lines(db: Session, work_order_id: str) -> List[Dict[str, Any]]:
|
||||
rows = (
|
||||
db.query(BizQcWorkOrderLabItem)
|
||||
.filter(
|
||||
BizQcWorkOrderLabItem.work_order_id == work_order_id,
|
||||
BizQcWorkOrderLabItem.order_source == "temporary",
|
||||
BizQcWorkOrderLabItem.del_flag == 0,
|
||||
)
|
||||
.order_by(BizQcWorkOrderLabItem.order_num.asc())
|
||||
.all()
|
||||
)
|
||||
return [
|
||||
{
|
||||
"id": r.id,
|
||||
"labTestItemId": r.lab_test_item_id,
|
||||
"itemCode": r.item_code,
|
||||
"itemName": r.item_name,
|
||||
}
|
||||
for r in rows
|
||||
]
|
||||
|
||||
|
||||
def _temp_third_lines(db: Session, work_order_id: str) -> List[Dict[str, Any]]:
|
||||
rows = (
|
||||
db.query(BizQcWorkOrderThirdItem)
|
||||
.filter(
|
||||
BizQcWorkOrderThirdItem.work_order_id == work_order_id,
|
||||
BizQcWorkOrderThirdItem.order_source == "temporary",
|
||||
BizQcWorkOrderThirdItem.del_flag == 0,
|
||||
)
|
||||
.order_by(BizQcWorkOrderThirdItem.order_num.asc())
|
||||
.all()
|
||||
)
|
||||
return [
|
||||
{
|
||||
"id": r.id,
|
||||
"thirdPartyItemId": r.third_party_item_id,
|
||||
"companyId": r.company_id,
|
||||
"companyName": r.company_name,
|
||||
"itemCode": r.item_code,
|
||||
"itemName": r.item_name,
|
||||
"feeAmount": _dec(r.fee_amount),
|
||||
}
|
||||
for r in rows
|
||||
]
|
||||
|
||||
|
||||
def _temp_tasks(db: Session, work_order_id: str, tenant_no: str) -> List[Dict[str, Any]]:
|
||||
rows = (
|
||||
db.query(BizQcTask)
|
||||
.filter(
|
||||
BizQcTask.work_order_id == work_order_id,
|
||||
BizQcTask.order_source == "temporary",
|
||||
BizQcTask.tenant_no == tenant_no,
|
||||
BizQcTask.del_flag == 0,
|
||||
)
|
||||
.order_by(BizQcTask.order_num.asc())
|
||||
.all()
|
||||
)
|
||||
items = []
|
||||
for t in rows:
|
||||
d = task_svc._task_to_dict(t, "", db, tenant_no)
|
||||
tt = (t.task_type or "").strip()
|
||||
ts = (t.task_status or "").strip()
|
||||
tc = (t.conclusion or "").strip()
|
||||
d["taskTypeLabel"] = _TASK_TYPE_LABELS.get(tt, tt)
|
||||
d["taskStatusLabel"] = _TASK_STATUS_LABELS.get(ts, ts)
|
||||
d["conclusionLabel"] = _CONCLUSION_LABELS.get(tc, tc or "—")
|
||||
items.append(d)
|
||||
return items
|
||||
|
||||
|
||||
def create_temp_qc_work_order(
|
||||
db: Session,
|
||||
*,
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
cell_product_id: str = "",
|
||||
remark: str = "",
|
||||
) -> BizQcWorkOrder:
|
||||
"""创建临时质检工单(work_order_type='temporary',LSZJ前缀编号)"""
|
||||
cp_id = _validate_cell_product_id(db, cell_product_id, tenant_no)
|
||||
wo = BizQcWorkOrder(
|
||||
id=generate_uuid(),
|
||||
work_order_no=_gen_daily_no(db, tenant_no, "LSZJ"),
|
||||
work_order_type="temporary",
|
||||
reception_id=None,
|
||||
protocol_sample_id=None,
|
||||
collection_protocol_id=None,
|
||||
protocol_no=None,
|
||||
sample_code=None,
|
||||
reception_source=None,
|
||||
qc_biz_type="temporary",
|
||||
cell_product_id=cp_id,
|
||||
work_order_status="dpz",
|
||||
has_lab="0",
|
||||
has_third_party="0",
|
||||
tenant_no=tenant_no,
|
||||
remark=remark,
|
||||
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,
|
||||
)
|
||||
db.add(wo)
|
||||
db.flush()
|
||||
return wo
|
||||
|
||||
|
||||
def update_temp_qc_work_order(
|
||||
db: Session,
|
||||
work_order_id: str,
|
||||
*,
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
cell_product_id: Optional[str] = None,
|
||||
remark: Optional[str] = None,
|
||||
) -> BizQcWorkOrder:
|
||||
"""编辑临时质检工单(备注、质检对象)"""
|
||||
wo = get_work_order(db, work_order_id, tenant_no=tenant_no)
|
||||
if not wo:
|
||||
raise ValueError("工单不存在")
|
||||
if (getattr(wo, "work_order_type", None) or "inbound") != "temporary":
|
||||
raise ValueError("仅临时质检工单可编辑")
|
||||
if cell_product_id is not None:
|
||||
wo.cell_product_id = _validate_cell_product_id(db, cell_product_id, tenant_no)
|
||||
if remark is not None:
|
||||
wo.remark = (remark or "").strip() or None
|
||||
wo.update_by = user_id
|
||||
wo.update_time = datetime.now()
|
||||
db.add(wo)
|
||||
db.flush()
|
||||
return wo
|
||||
|
||||
|
||||
def list_temp_qc_work_orders(
|
||||
db: Session,
|
||||
*,
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
keyword: Optional[str] = None,
|
||||
work_order_status: Optional[str] = None,
|
||||
tenant_no: Optional[str] = None,
|
||||
user_info=None,
|
||||
) -> Tuple[List[Dict[str, Any]], int]:
|
||||
def _filtered():
|
||||
q0 = db.query(BizQcWorkOrder).filter(
|
||||
BizQcWorkOrder.del_flag == 0,
|
||||
BizQcWorkOrder.work_order_type == "temporary",
|
||||
)
|
||||
if tenant_no:
|
||||
q0 = q0.filter(BizQcWorkOrder.tenant_no == tenant_no)
|
||||
kw = (keyword or "").strip()
|
||||
if kw:
|
||||
like = f"%{kw}%"
|
||||
q0 = q0.filter(BizQcWorkOrder.work_order_no.like(like))
|
||||
st = (work_order_status or "").strip()
|
||||
if st:
|
||||
q0 = q0.filter(BizQcWorkOrder.work_order_status == st)
|
||||
if user_info:
|
||||
from app.core.data_scope import apply_data_scope
|
||||
|
||||
q0 = apply_data_scope(q0, BizQcWorkOrder, user_info, db, tenant_no)
|
||||
return q0
|
||||
|
||||
total = _filtered().order_by(None).with_entities(func.count(BizQcWorkOrder.id)).scalar() or 0
|
||||
page = max(1, page)
|
||||
page_size = min(max(1, page_size), 100)
|
||||
rows = (
|
||||
_filtered()
|
||||
.order_by(BizQcWorkOrder.create_time.desc())
|
||||
.offset((page - 1) * page_size)
|
||||
.limit(page_size)
|
||||
.all()
|
||||
)
|
||||
items = [_wo_to_dict(x) for x in rows]
|
||||
if tenant_no:
|
||||
items = _enrich_work_order_cell_products(db, tenant_no, items)
|
||||
return items, int(total)
|
||||
|
||||
|
||||
def get_temp_qc_work_order(
|
||||
db: Session, row_id: str, tenant_no: str
|
||||
) -> Optional[BizQcWorkOrder]:
|
||||
q = db.query(BizQcWorkOrder).filter(
|
||||
BizQcWorkOrder.id == row_id,
|
||||
BizQcWorkOrder.del_flag == 0,
|
||||
BizQcWorkOrder.work_order_type == "temporary",
|
||||
)
|
||||
if tenant_no:
|
||||
q = q.filter(BizQcWorkOrder.tenant_no == tenant_no)
|
||||
return q.first()
|
||||
|
||||
|
||||
def get_temp_qc_work_order_detail(
|
||||
db: Session, row_id: str, tenant_no: str
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
wo = get_temp_qc_work_order(db, row_id, tenant_no)
|
||||
if not wo:
|
||||
return None
|
||||
out = _wo_to_dict(wo)
|
||||
enriched_list = _enrich_work_order_cell_products(db, tenant_no, [out])
|
||||
out = enriched_list[0]
|
||||
out["labItems"] = _temp_lab_lines(db, wo.id)
|
||||
out["thirdPartyItems"] = _temp_third_lines(db, wo.id)
|
||||
out["tasks"] = _temp_tasks(db, wo.id, tenant_no)
|
||||
return out
|
||||
|
||||
|
||||
def configure_temp_qc_work_order(
|
||||
db: Session,
|
||||
work_order_id: str,
|
||||
*,
|
||||
has_lab: bool,
|
||||
has_third_party: bool,
|
||||
lab_item_ids: List[str],
|
||||
third_party_item_ids: List[str],
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
) -> BizQcWorkOrder:
|
||||
wo = get_temp_qc_work_order(db, work_order_id, tenant_no)
|
||||
if not wo:
|
||||
raise ValueError("工单不存在")
|
||||
if wo.work_order_status == "ywc":
|
||||
raise ValueError("工单已完成,无法调整检测项目")
|
||||
if wo.work_order_status not in ("dpz", "ypz"):
|
||||
raise ValueError("当前工单状态不可配置检测项目")
|
||||
|
||||
if wo.work_order_status == "ypz":
|
||||
tasks = (
|
||||
db.query(BizQcTask)
|
||||
.filter(
|
||||
BizQcTask.work_order_id == wo.id,
|
||||
BizQcTask.order_source == "temporary",
|
||||
BizQcTask.tenant_no == tenant_no,
|
||||
BizQcTask.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
if any(t.task_status in ("jxz", "ywc") for t in tasks):
|
||||
raise ValueError("存在进行中或已完成的质检任务,无法调整检测项目")
|
||||
now = datetime.now()
|
||||
task_ids = [t.id for t in tasks]
|
||||
if task_ids:
|
||||
db.query(BizQcTaskResult).filter(
|
||||
BizQcTaskResult.task_id.in_(task_ids),
|
||||
BizQcTaskResult.tenant_no == tenant_no,
|
||||
BizQcTaskResult.del_flag == 0,
|
||||
).update(
|
||||
{"del_flag": 1, "update_time": now},
|
||||
synchronize_session="fetch",
|
||||
)
|
||||
for t in tasks:
|
||||
t.del_flag = 1
|
||||
t.update_time = now
|
||||
db.add(t)
|
||||
|
||||
if not has_lab and not has_third_party:
|
||||
raise ValueError("请至少选择一种检测方式")
|
||||
if has_lab and not lab_item_ids:
|
||||
raise ValueError("请选择实验室自检项目")
|
||||
if has_third_party and not third_party_item_ids:
|
||||
raise ValueError("请选择第三方检测项目")
|
||||
if not has_lab:
|
||||
lab_item_ids = []
|
||||
if not has_third_party:
|
||||
third_party_item_ids = []
|
||||
|
||||
for row in (
|
||||
db.query(BizQcWorkOrderLabItem)
|
||||
.filter(
|
||||
BizQcWorkOrderLabItem.work_order_id == wo.id,
|
||||
BizQcWorkOrderLabItem.order_source == "temporary",
|
||||
BizQcWorkOrderLabItem.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
):
|
||||
row.del_flag = 1
|
||||
for row in (
|
||||
db.query(BizQcWorkOrderThirdItem)
|
||||
.filter(
|
||||
BizQcWorkOrderThirdItem.work_order_id == wo.id,
|
||||
BizQcWorkOrderThirdItem.order_source == "temporary",
|
||||
BizQcWorkOrderThirdItem.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
):
|
||||
row.del_flag = 1
|
||||
|
||||
fee_total = Decimal("0")
|
||||
seq = 0
|
||||
|
||||
for lid in lab_item_ids:
|
||||
item = lab_item_svc.get_lab_item(db, lid, tenant_no=tenant_no)
|
||||
if not item or item.status != "1":
|
||||
raise ValueError("实验室项目无效或已停用")
|
||||
seq += 1
|
||||
line = BizQcWorkOrderLabItem(
|
||||
id=generate_uuid(),
|
||||
work_order_id=wo.id,
|
||||
order_source="temporary",
|
||||
lab_test_item_id=item.id,
|
||||
item_code=item.item_code,
|
||||
item_name=item.item_name,
|
||||
tenant_no=tenant_no,
|
||||
order_num=seq,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id or "",
|
||||
create_time=datetime.now(),
|
||||
update_by=user_id,
|
||||
update_time=datetime.now(),
|
||||
del_flag=0,
|
||||
)
|
||||
db.add(line)
|
||||
db.flush()
|
||||
task_svc.create_task_for_line(
|
||||
db,
|
||||
work_order=wo,
|
||||
task_type="sysz",
|
||||
source_line_id=line.id,
|
||||
item_code=line.item_code,
|
||||
item_name=line.item_name,
|
||||
tenant_no=tenant_no,
|
||||
user_id=user_id,
|
||||
create_dept_id=create_dept_id,
|
||||
seq=seq,
|
||||
order_source="temporary",
|
||||
)
|
||||
|
||||
for tid in third_party_item_ids:
|
||||
item = third_item_svc.get_item(db, tid, tenant_no=tenant_no)
|
||||
if not item or item.status != "1":
|
||||
raise ValueError("第三方项目无效或已停用")
|
||||
comp = get_company(db, item.company_id, tenant_no=tenant_no)
|
||||
if not comp:
|
||||
raise ValueError("第三方公司不存在")
|
||||
seq += 1
|
||||
fee = item.fee_amount or Decimal("0")
|
||||
fee_total += fee
|
||||
line = BizQcWorkOrderThirdItem(
|
||||
id=generate_uuid(),
|
||||
work_order_id=wo.id,
|
||||
order_source="temporary",
|
||||
third_party_item_id=item.id,
|
||||
company_id=comp.id,
|
||||
company_name=comp.company_name,
|
||||
item_code=item.item_code,
|
||||
item_name=item.item_name,
|
||||
fee_amount=fee,
|
||||
tenant_no=tenant_no,
|
||||
order_num=seq,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id or "",
|
||||
create_time=datetime.now(),
|
||||
update_by=user_id,
|
||||
update_time=datetime.now(),
|
||||
del_flag=0,
|
||||
)
|
||||
db.add(line)
|
||||
db.flush()
|
||||
task_svc.create_task_for_line(
|
||||
db,
|
||||
work_order=wo,
|
||||
task_type="dsfjc",
|
||||
source_line_id=line.id,
|
||||
item_code=line.item_code,
|
||||
item_name=line.item_name,
|
||||
tenant_no=tenant_no,
|
||||
user_id=user_id,
|
||||
create_dept_id=create_dept_id,
|
||||
seq=seq,
|
||||
company_id=comp.id,
|
||||
company_name=comp.company_name,
|
||||
fee_amount=fee,
|
||||
order_source="temporary",
|
||||
)
|
||||
|
||||
wo.has_lab = "1" if has_lab else "0"
|
||||
wo.has_third_party = "1" if has_third_party else "0"
|
||||
wo.work_order_status = "ypz"
|
||||
wo.configured_time = datetime.now()
|
||||
wo.configured_by = user_id
|
||||
wo.third_party_fee_total = fee_total if has_third_party else None
|
||||
wo.update_by = user_id
|
||||
wo.update_time = datetime.now()
|
||||
db.add(wo)
|
||||
db.commit()
|
||||
db.refresh(wo)
|
||||
return wo
|
||||
|
||||
|
||||
def try_complete_temp_qc_work_order(
|
||||
db: Session, work_order_id: str, tenant_no: str
|
||||
) -> None:
|
||||
pending = (
|
||||
db.query(BizQcTask)
|
||||
.filter(
|
||||
BizQcTask.work_order_id == work_order_id,
|
||||
BizQcTask.order_source == "temporary",
|
||||
BizQcTask.tenant_no == tenant_no,
|
||||
BizQcTask.del_flag == 0,
|
||||
BizQcTask.task_status != "ywc",
|
||||
)
|
||||
.count()
|
||||
)
|
||||
if pending:
|
||||
return
|
||||
wo = get_temp_qc_work_order(db, work_order_id, tenant_no)
|
||||
if wo and wo.work_order_status == "ypz":
|
||||
wo.work_order_status = "ywc"
|
||||
wo.update_time = datetime.now()
|
||||
db.add(wo)
|
||||
db.commit()
|
||||
|
||||
|
||||
def delete_temp_qc_work_order(
|
||||
db: Session, work_order_id: str, tenant_no: str, user_id: Optional[str]
|
||||
) -> None:
|
||||
wo = get_temp_qc_work_order(db, work_order_id, tenant_no)
|
||||
if not wo:
|
||||
raise ValueError("工单不存在")
|
||||
if wo.work_order_status == "ywc":
|
||||
raise ValueError("已完成的工单不能删除")
|
||||
|
||||
now = datetime.now()
|
||||
|
||||
tasks = (
|
||||
db.query(BizQcTask)
|
||||
.filter(
|
||||
BizQcTask.work_order_id == work_order_id,
|
||||
BizQcTask.order_source == "temporary",
|
||||
BizQcTask.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
for task in tasks:
|
||||
results = (
|
||||
db.query(BizQcTaskResult)
|
||||
.filter(
|
||||
BizQcTaskResult.task_id == task.id,
|
||||
BizQcTaskResult.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
for r in results:
|
||||
r.del_flag = 1
|
||||
r.update_by = user_id
|
||||
r.update_time = now
|
||||
task.del_flag = 1
|
||||
task.update_by = user_id
|
||||
task.update_time = now
|
||||
|
||||
lab_items = (
|
||||
db.query(BizQcWorkOrderLabItem)
|
||||
.filter(
|
||||
BizQcWorkOrderLabItem.work_order_id == work_order_id,
|
||||
BizQcWorkOrderLabItem.order_source == "temporary",
|
||||
BizQcWorkOrderLabItem.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
for item in lab_items:
|
||||
item.del_flag = 1
|
||||
item.update_by = user_id
|
||||
item.update_time = now
|
||||
|
||||
third_items = (
|
||||
db.query(BizQcWorkOrderThirdItem)
|
||||
.filter(
|
||||
BizQcWorkOrderThirdItem.work_order_id == work_order_id,
|
||||
BizQcWorkOrderThirdItem.order_source == "temporary",
|
||||
BizQcWorkOrderThirdItem.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
for item in third_items:
|
||||
item.del_flag = 1
|
||||
item.update_by = user_id
|
||||
item.update_time = now
|
||||
|
||||
wo.del_flag = 1
|
||||
wo.update_by = user_id
|
||||
wo.update_time = now
|
||||
|
||||
db.commit()
|
||||
|
||||
|
||||
def create_qc_work_order_manual(
|
||||
db: Session,
|
||||
*,
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
protocol_no: str = "",
|
||||
sample_code: str = "",
|
||||
reception_source: str = "cell_storage",
|
||||
qc_biz_type: str = "inbound",
|
||||
remark: str = "",
|
||||
) -> BizQcWorkOrder:
|
||||
"""手动创建质检工单(不关联接收记录)"""
|
||||
wo = BizQcWorkOrder(
|
||||
id=generate_uuid(),
|
||||
work_order_no=_gen_daily_no(db, tenant_no, "ZJ"),
|
||||
work_order_type="inbound",
|
||||
reception_id=None,
|
||||
protocol_sample_id=None,
|
||||
collection_protocol_id=None,
|
||||
protocol_no=protocol_no or None,
|
||||
sample_code=sample_code or None,
|
||||
reception_source=reception_source,
|
||||
qc_biz_type=qc_biz_type,
|
||||
work_order_status="dpz",
|
||||
has_lab="0",
|
||||
has_third_party="0",
|
||||
tenant_no=tenant_no,
|
||||
remark=remark,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id,
|
||||
)
|
||||
db.add(wo)
|
||||
db.flush()
|
||||
return wo
|
||||
|
||||
|
||||
def delete_qc_work_order(db: Session, work_order_id: str, tenant_no: str, user_id: Optional[str]) -> None:
|
||||
"""软删除质检工单及其关联的任务、任务结果、检测项目和第三方检测项目"""
|
||||
wo = db.query(BizQcWorkOrder).filter(
|
||||
and_(
|
||||
BizQcWorkOrder.id == work_order_id,
|
||||
BizQcWorkOrder.tenant_no == tenant_no,
|
||||
BizQcWorkOrder.del_flag == 0,
|
||||
)
|
||||
).first()
|
||||
if not wo:
|
||||
raise ValueError("工单不存在")
|
||||
if wo.work_order_status == "ywc":
|
||||
raise ValueError("已完成的工单不能删除")
|
||||
|
||||
now = datetime.now()
|
||||
|
||||
# 1. 软删除所有关联任务及其结果
|
||||
tasks = db.query(BizQcTask).filter(
|
||||
and_(BizQcTask.work_order_id == work_order_id, BizQcTask.del_flag == 0)
|
||||
).all()
|
||||
from app.models.qc_param import BizQcTaskResult
|
||||
|
||||
for task in tasks:
|
||||
results = db.query(BizQcTaskResult).filter(
|
||||
and_(BizQcTaskResult.task_id == task.id, BizQcTaskResult.del_flag == 0)
|
||||
).all()
|
||||
for r in results:
|
||||
r.del_flag = 1
|
||||
r.update_by = user_id
|
||||
r.update_time = now
|
||||
task.del_flag = 1
|
||||
task.update_by = user_id
|
||||
task.update_time = now
|
||||
|
||||
# 2. 软删除检测项目
|
||||
lab_items = db.query(BizQcWorkOrderLabItem).filter(
|
||||
and_(BizQcWorkOrderLabItem.work_order_id == work_order_id, BizQcWorkOrderLabItem.del_flag == 0)
|
||||
).all()
|
||||
for item in lab_items:
|
||||
item.del_flag = 1
|
||||
item.update_by = user_id
|
||||
item.update_time = now
|
||||
|
||||
# 3. 软删除第三方检测项目
|
||||
third_items = db.query(BizQcWorkOrderThirdItem).filter(
|
||||
and_(BizQcWorkOrderThirdItem.work_order_id == work_order_id, BizQcWorkOrderThirdItem.del_flag == 0)
|
||||
).all()
|
||||
for item in third_items:
|
||||
item.del_flag = 1
|
||||
item.update_by = user_id
|
||||
item.update_time = now
|
||||
|
||||
# 4. 软删除工单本体
|
||||
wo.del_flag = 1
|
||||
wo.update_by = user_id
|
||||
wo.update_time = now
|
||||
|
||||
db.commit()
|
||||
+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_qcworkordercreatebody", "label": "QcWorkOrderCreateBody", "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": ""}], "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_qcworkordercreatebody", "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_qcworkordercreatebody", "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}], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_py", "label": "qc.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L1"}, {"id": "api_qc_thirdpartycompanybody", "label": "ThirdPartyCompanyBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L35"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "api_qc_thirdpartycompanyupdatebody", "label": "ThirdPartyCompanyUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L52"}, {"id": "api_qc_list_qc_third_party_companies", "label": "list_qc_third_party_companies()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L70"}, {"id": "api_qc_list_qc_third_party_company_options", "label": "list_qc_third_party_company_options()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L92"}, {"id": "api_qc_create_qc_third_party_company", "label": "create_qc_third_party_company()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L106"}, {"id": "api_qc_update_qc_third_party_company", "label": "update_qc_third_party_company()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L140"}, {"id": "api_qc_delete_qc_third_party_company", "label": "delete_qc_third_party_company()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L176"}, {"id": "api_qc_thirdpartyitembody", "label": "ThirdPartyItemBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L196"}, {"id": "api_qc_thirdpartyitemupdatebody", "label": "ThirdPartyItemUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L208"}, {"id": "api_qc_list_qc_third_party_items", "label": "list_qc_third_party_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L221"}, {"id": "api_qc_list_qc_third_party_items_active", "label": "list_qc_third_party_items_active()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L250"}, {"id": "api_qc_create_qc_third_party_item", "label": "create_qc_third_party_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L265"}, {"id": "api_qc_update_qc_third_party_item", "label": "update_qc_third_party_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L294"}, {"id": "api_qc_delete_qc_third_party_item", "label": "delete_qc_third_party_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L325"}, {"id": "api_qc_labtestitembody", "label": "LabTestItemBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L345"}, {"id": "api_qc_labtestitemupdatebody", "label": "LabTestItemUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L356"}, {"id": "api_qc_itemparambody", "label": "ItemParamBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L370"}, {"id": "api_qc_taskresultbody", "label": "TaskResultBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L375"}, {"id": "api_qc_taskcompletewithresultbody", "label": "TaskCompleteWithResultBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L380"}, {"id": "api_qc_list_qc_lab_test_items", "label": "list_qc_lab_test_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L390"}, {"id": "api_qc_list_qc_lab_test_items_active", "label": "list_qc_lab_test_items_active()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L412"}, {"id": "api_qc_create_qc_lab_test_item", "label": "create_qc_lab_test_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L426"}, {"id": "api_qc_update_qc_lab_test_item", "label": "update_qc_lab_test_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L454"}, {"id": "api_qLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_production_work_order_py", "label": "production_work_order.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L1"}, {"id": "crud_production_work_order_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L38"}, {"id": "crud_production_work_order_generate_work_order_no", "label": "_generate_work_order_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L42"}, {"id": "crud_production_work_order_wo_to_dict", "label": "_wo_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L61"}, {"id": "crud_production_work_order_enrich_wo_items", "label": "_enrich_wo_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L86"}, {"id": "crud_production_work_order_reception_source_label", "label": "_reception_source_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L92"}, {"id": "crud_production_work_order_accept_conclusion_label", "label": "_accept_conclusion_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L97"}, {"id": "crud_production_work_order_attach_reception_detail", "label": "_attach_reception_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L102"}, {"id": "crud_production_work_order_wo_to_response_dict", "label": "_wo_to_response_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L132"}, {"id": "crud_production_work_order_create_production_work_order_from_reception", "label": "create_production_work_order_from_reception()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L139"}, {"id": "crud_production_work_order_list_production_work_orders", "label": "list_production_work_orders()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L250"}, {"id": "crud_production_work_order_sync_production_work_order_status_from_tasks", "label": "sync_production_work_order_status_from_tasks()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L307"}, {"id": "crud_production_work_order_get_production_work_order", "label": "get_production_work_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L347"}, {"id": "crud_production_work_order_complete_production_work_order", "label": "complete_production_work_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L361"}, {"id": "crud_production_work_order_production_task_info", "label": "_production_task_info()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L392"}, {"id": "crud_production_work_order_production_info_item", "label": "_production_info_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L439"}, {"id": "crud_production_work_order_get_production_info_map_for_samples", "label": "get_production_info_map_for_samples()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L459"}, {"id": "crud_production_work_order_create_production_work_order_manual", "label": "create_production_work_order_manual()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L521"}, {"id": "crud_production_work_order_rationale_105", "label": "\u8be6\u60c5\u54cd\u5e94\u9644\u52a0\u8fd0\u8f93\u4e0e\u6837\u672c\u63a5\u6536\u4fe1\u606f\uff08\u4e0e\u8d28\u68c0\u5de5\u5355\u8be6\u60c5\u4e00\u81f4\uff09\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py", "source_location": "L105"}, {"id": "crud_production_work_order_rationale_133", "label": "\u5de5\u5355\u54cd\u5e94\uff08\u542b\u63a5\u6536\u8bb0\u5f55\u5173\u8054\u7684\u6837\u672c\u7c7b\u578b\u3001\u63a5\u6536\u4eba\u3001\u63Line 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_dec", "label": "_dec()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L55"}, {"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": "L61"}, {"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": "L65"}, {"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": "L70"}, {"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": "L75"}, {"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": "L79"}, {"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": "L84"}, {"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": "L96"}, {"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/backend/app/crud/qc_work_order.py", "source_location": "L113"}, {"id": "crud_qc_work_order_gen_daily_no", "label": "_gen_daily_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L221"}, {"id": "crud_qc_work_order_wo_to_dict", "label": "_wo_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L235"}, {"id": "crud_qc_work_order_create_work_order_from_reception", "label": "create_work_order_from_reception()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L265"}, {"id": "crud_qc_work_order_list_work_orders", "label": "list_work_orders()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L380"}, {"id": "crud_qc_work_order_get_work_order", "label": "get_work_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L426"}, {"id": "crud_qc_work_order_lab_lines", "label": "_lab_lines()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L435"}, {"id": "crud_qc_work_order_third_lines", "label": "_third_lines()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L456"}, {"id": "crud_qc_work_order_qc_info_item", "label": "_qc_info_item()", "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_get_qc_info_map_for_samples", "label": "get_qc_info_map_for_samples()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L501"}, {"id": "crud_qc_work_order_get_work_order_detail", "label": "get_work_order_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L564"}, {"id": "crud_qc_work_order_soft_delete_pending_work_order_tasks", "label": "_soft_delete_pending_work_order_tasks()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L614"}, {"id": "crud_qc_work_order_configure_work_order", "label": "configure_work_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L648"}, {"id": "crud_qc_work_order_try_complete_work_order", "label": "try_complete_work_order()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.pLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_cell_product_py", "label": "cell_product.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L1"}, {"id": "crud_cell_product_row_to_dict", "label": "_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L24"}, {"id": "crud_cell_product_build_facility_path_label", "label": "_build_facility_path_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L57"}, {"id": "crud_cell_product_enrich_product_dicts", "label": "_enrich_product_dicts()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L72"}, {"id": "crud_cell_product_product_to_response", "label": "product_to_response()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L203"}, {"id": "crud_cell_product_list_cell_products", "label": "list_cell_products()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L208"}, {"id": "crud_cell_product_get_cell_product", "label": "get_cell_product()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L272"}, {"id": "crud_cell_product_create_cell_product", "label": "create_cell_product()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L286"}, {"id": "crud_cell_product_update_cell_product", "label": "update_cell_product()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L366"}, {"id": "crud_cell_product_delete_cell_product", "label": "delete_cell_product()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L428"}, {"id": "crud_cell_product_next_code_start_seq", "label": "_next_code_start_seq()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L444"}, {"id": "crud_cell_product_get_next_code", "label": "get_next_code()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L465"}, {"id": "crud_cell_product_normalize_product_code_base", "label": "normalize_product_code_base()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L475"}, {"id": "crud_cell_product_build_split_product_codes", "label": "build_split_product_codes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L486"}, {"id": "crud_cell_product_reserve_next_codes", "label": "reserve_next_codes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L493"}, {"id": "crud_cell_product_validate_batch_items", "label": "_validate_batch_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L503"}, {"id": "crud_cell_product_create_cell_products_by_quantity", "label": "create_cell_products_by_quantity()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L546"}, {"id": "crud_cell_product_create_cell_products_batch", "label": "create_cell_products_batch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L578"}, {"id": "crud_cell_product_total_pages", "label": "total_pages()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L660"}, {"id": "crud_cell_product_product_node", "label": "_product_node()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L675"}, {"id": "crud_cell_product_first_chain_link", "label": "_first_chain_link()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L687"}, {"id": "crud_cell_product_build_ancestor_chain", "label": "_build_ancestor_chain()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L692"}, {"id": "crud_cell_product_build_descendant_chain", "label": "_build_descendant_chain()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L810"}, Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_task_py", "label": "qc_task.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_task.py", "source_location": "L1"}, {"id": "schemas_qc_task_qctaskcreatebody", "label": "QcTaskCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_task.py", "source_location": "L5"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_task_py", "target": "pydantic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_task.py", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_task_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_task.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_task_py", "target": "schemas_qc_task_qctaskcreatebody", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_task.py", "source_location": "L5", "weight": 1.0}, {"source": "schemas_qc_task_qctaskcreatebody", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_task.py", "source_location": "L5", "weight": 1.0}], "raw_calls": []}
|
||||
+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": "L31"}, {"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": "L37"}, {"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": "L41"}, {"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": "L54"}, {"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": "L59"}, {"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": "L91"}, {"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": "L109"}, {"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": "L213"}, {"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": "L224"}, {"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": "L267"}, {"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": "L340"}, {"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": "L357"}, {"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": "L366"}, {"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": "L389"}, {"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": "L406"}, {"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": "L410"}, {"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": "L454"}, {"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": "L506"}, {"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": "L536"}, {"id": "crud_qc_task_rationale_465", "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": "L465"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_py", "target": "decimal", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_py", "target": "typing", "relation": "imports_from", "cLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "label": "cell_product.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L1"}, {"id": "schemas_cell_product_coerce_optional_datetime", "label": "_coerce_optional_datetime()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L9"}, {"id": "schemas_cell_product_cellproductbatchitem", "label": "CellProductBatchItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L23"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "schemas_cell_product_cellproductcreate", "label": "CellProductCreate", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L32"}, {"id": "schemas_cell_product_coerce_date_fields", "label": "coerce_date_fields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L56"}, {"id": "schemas_cell_product_validate_viability", "label": "validate_viability()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L61"}, {"id": "schemas_cell_product_validate_passage", "label": "validate_passage()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L68"}, {"id": "schemas_cell_product_cellproductupdate", "label": "CellProductUpdate", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L77"}, {"id": "schemas_cell_product_validate_status", "label": "validate_status()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L120"}, {"id": "schemas_cell_product_cellproductlistquery", "label": "CellProductListQuery", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L127"}, {"id": "schemas_cell_product_rationale_10", "label": "\u517c\u5bb9\u524d\u7aef date-picker \u7684 YYYY-MM-DD \u4e0e\u5b8c\u6574\u65e5\u671f\u65f6\u95f4\u5b57\u7b26\u4e32\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L10"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "pydantic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "app_core_utils", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "schemas_cell_product_coerce_optional_datetime", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "schemas_cell_product_cellproductbatchitem", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L23", "weight": 1.0}, {"source": "schemas_cell_product_cellproductbatchitem", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L23", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "schemas_cell_product_cellproductcreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L32", "weigLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_work_order_py", "label": "production_work_order.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L1"}, {"id": "schemas_production_work_order_productionworkorderbase", "label": "ProductionWorkOrderBase", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L6"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "schemas_production_work_order_productionworkorderlistquery", "label": "ProductionWorkOrderListQuery", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L10"}, {"id": "schemas_production_work_order_productionworkordercomplete", "label": "ProductionWorkOrderComplete", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L20"}, {"id": "schemas_production_work_order_productionworkordercreate", "label": "ProductionWorkOrderCreate", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L24"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_work_order_py", "target": "pydantic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_work_order_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_work_order_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_work_order_py", "target": "schemas_production_work_order_productionworkorderbase", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L6", "weight": 1.0}, {"source": "schemas_production_work_order_productionworkorderbase", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_work_order_py", "target": "schemas_production_work_order_productionworkorderlistquery", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L10", "weight": 1.0}, {"source": "schemas_production_work_order_productionworkorderlistquery", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L10", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_work_order_py", "target": "schemas_production_work_order_productionworkordercomplete", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L20", "weight": 1.0}, {"source": "schemas_production_work_order_productionworkordercomplete", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L20", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_production_work_order_py", "target": "schemas_production_work_order_productionworkordercreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L24", "weight": 1.0}, {"source": "schemas_production_work_order_productionworkordercreate", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py", "source_location": "L24", "weight": 1.0}], "raw_calls": []}
|
||||
+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_get_tenant_no", "label": "_get_tenant_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L56"}, {"id": "api_production_consumablecreatebody", "label": "ConsumableCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L69"}, {"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": "L83"}, {"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": "L98"}, {"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": "L112"}, {"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": "L122"}, {"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": "L150"}, {"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": "L179"}, {"id": "api_production_stockinbody", "label": "StockInBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L191"}, {"id": "api_production_stockoutbody", "label": "StockOutBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L197"}, {"id": "api_production_batchstockinitem", "label": "BatchStockInItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L205"}, {"id": "api_production_batchstockinbody", "label": "BatchStockInBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L212"}, {"id": "api_production_batchstockoutitem", "label": "BatchStockOutItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L218"}, {"id": "api_production_batchstockoutbody", "label": "BatchStockOutBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L224"}, {"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": "L233"}, {"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": "L255"}, {"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": "L279"}, {"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": "L297"}, {"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": "L316"}, {"id": "api_production_list_all_consumable_stock_logs", "label": "list_all_consumable_stock_logs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L335"}, {"id": "api_production_reagentcreatebody", "label": "ReagentCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L361"}, {"id": "api_production_reagentupdatebody", "label": "ReagentUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L375"}, {"id": "api_production_list_reagents", "label": "list_reagents()", "file_type": "code", "source_filLine truncated
|
||||
@@ -1223,18 +1223,20 @@ class BizQcWorkOrder(Base):
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID")
|
||||
work_order_no = Column(String(32), nullable=False, comment="工单号")
|
||||
reception_id = Column(String(64), nullable=False, comment="接收记录ID")
|
||||
protocol_sample_id = Column(String(64), nullable=False, comment="协议样本ID")
|
||||
collection_protocol_id = Column(String(64), nullable=False, comment="协议单ID")
|
||||
work_order_type = Column(String(20), nullable=False, default="inbound", comment="工单类型: inbound=入库, temporary=临时")
|
||||
reception_id = Column(String(64), nullable=True, comment="接收记录ID")
|
||||
protocol_sample_id = Column(String(64), nullable=True, comment="协议样本ID")
|
||||
collection_protocol_id = Column(String(64), nullable=True, comment="协议单ID")
|
||||
protocol_no = Column(String(64), nullable=True, comment="协议号快照")
|
||||
sample_code = Column(String(32), nullable=True, comment="样本编码快照")
|
||||
reception_source = Column(String(20), nullable=False, default="cell_storage", comment="来源类型 cell_storage/research_donation")
|
||||
reception_source = Column(String(20), nullable=True, default="cell_storage", comment="来源类型 cell_storage/research_donation")
|
||||
qc_biz_type = Column(
|
||||
String(20),
|
||||
nullable=False,
|
||||
default="inbound",
|
||||
comment="质检业务类型 inbound入库质检 outbound出库质检",
|
||||
comment="质检业务类型 inbound入库质检 outbound出库质检 temporary临时质检",
|
||||
)
|
||||
cell_product_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="含第三方检测")
|
||||
@@ -1259,6 +1261,7 @@ class BizQcWorkOrderLabItem(Base):
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID")
|
||||
work_order_id = Column(String(64), nullable=False, comment="工单ID")
|
||||
order_source = Column(String(20), nullable=False, default="inbound", comment="工单来源: inbound=入库, temporary=临时")
|
||||
lab_test_item_id = Column(String(64), nullable=False, comment="实验室项目ID")
|
||||
item_code = Column(String(64), nullable=False, comment="项目编码快照")
|
||||
item_name = Column(String(200), nullable=False, comment="项目名称快照")
|
||||
@@ -1280,6 +1283,7 @@ class BizQcWorkOrderThirdItem(Base):
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID")
|
||||
work_order_id = Column(String(64), nullable=False, comment="工单ID")
|
||||
order_source = Column(String(20), nullable=False, default="inbound", comment="工单来源: inbound=入库, temporary=临时")
|
||||
third_party_item_id = Column(String(64), nullable=False, comment="第三方项目ID")
|
||||
company_id = Column(String(64), nullable=False, comment="公司ID")
|
||||
company_name = Column(String(200), nullable=False, comment="公司名快照")
|
||||
@@ -1304,6 +1308,7 @@ class BizQcTask(Base):
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID")
|
||||
work_order_id = Column(String(64), nullable=False, comment="工单ID")
|
||||
order_source = Column(String(20), nullable=False, default="inbound", comment="工单来源: inbound=入库, temporary=临时")
|
||||
task_no = Column(String(32), nullable=False, comment="任务号")
|
||||
task_type = Column(String(16), nullable=False, comment="sysz实验室 dsfjc第三方")
|
||||
source_line_id = Column(String(64), nullable=False, comment="工单明细行ID")
|
||||
@@ -2273,13 +2278,16 @@ class BizProductionWorkOrder(Base):
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID")
|
||||
work_order_no = Column(String(32), nullable=False, comment="工单号")
|
||||
reception_id = Column(String(64), nullable=False, comment="接收记录ID")
|
||||
protocol_sample_id = Column(String(64), nullable=False, comment="协议样本ID")
|
||||
collection_protocol_id = Column(String(64), nullable=False, comment="采集协议单ID")
|
||||
work_order_type = Column(String(20), nullable=False, default="inbound", comment="工单类型: inbound=入库, temporary=临时")
|
||||
reception_id = Column(String(64), nullable=True, comment="接收记录ID")
|
||||
protocol_sample_id = Column(String(64), nullable=True, comment="协议样本ID")
|
||||
collection_protocol_id = Column(String(64), nullable=True, comment="采集协议单ID")
|
||||
protocol_no = Column(String(64), nullable=True, comment="协议号快照")
|
||||
sample_code = Column(String(32), nullable=True, comment="样本编码快照")
|
||||
reception_source = Column(String(20), nullable=False, default="cell_storage", comment="来源类型 cell_storage细胞存储 research_donation科研捐赠")
|
||||
reception_source = Column(String(20), nullable=True, default="cell_storage", comment="来源类型 cell_storage细胞存储 research_donation科研捐赠")
|
||||
work_order_status = Column(String(16), nullable=False, default="dpz", comment="工单状态 dpz待配置 jxz进行中 ywc已完成")
|
||||
configured_time = Column(DateTime, nullable=True, comment="配置时间")
|
||||
configured_by = Column(String(64), nullable=True, comment="配置人")
|
||||
tenant_no = Column(String(64), nullable=False, default="zkxw", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号")
|
||||
remark = Column(String(512), nullable=True, comment="备注")
|
||||
@@ -2291,7 +2299,6 @@ class BizProductionWorkOrder(Base):
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
|
||||
|
||||
|
||||
class BizProductionTask(Base):
|
||||
"""生产任务 biz_production_task"""
|
||||
|
||||
@@ -2300,6 +2307,7 @@ class BizProductionTask(Base):
|
||||
id = Column(String(64), primary_key=True, comment="主键ID")
|
||||
task_no = Column(String(32), nullable=False, comment="任务号")
|
||||
work_order_id = Column(String(64), nullable=False, comment="工单ID")
|
||||
order_source = Column(String(20), nullable=False, default="inbound", comment="工单来源: inbound=入库, temporary=临时")
|
||||
task_type = Column(String(20), nullable=False, default="cell_storage", comment="任务类型 cell_storage入库生产单 outbound出库生产单")
|
||||
task_name = Column(String(200), nullable=True, comment="任务名称")
|
||||
description = Column(String(500), nullable=True, comment="描述")
|
||||
|
||||
@@ -135,3 +135,4 @@ class CellProductListQuery(BaseModel):
|
||||
product_type_id: Optional[str] = Field(None, alias="productTypeId")
|
||||
product_status: Optional[str] = Field(None, alias="productStatus")
|
||||
passage: Optional[str] = None
|
||||
source_type: Optional[str] = Field(None, alias="sourceType")
|
||||
@@ -1,4 +1,4 @@
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
@@ -13,9 +13,30 @@ class ProductionWorkOrderListQuery(BaseModel):
|
||||
keyword: Optional[str] = None
|
||||
work_order_no: Optional[str] = None
|
||||
work_order_status: Optional[str] = None
|
||||
work_order_type: Optional[str] = None
|
||||
protocol_no: Optional[str] = None
|
||||
sample_code: Optional[str] = None
|
||||
|
||||
|
||||
class ProductionWorkOrderComplete(BaseModel):
|
||||
remark: Optional[str] = None
|
||||
|
||||
|
||||
class ProductionWorkOrderCreate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
work_order_type: Optional[str] = Field("inbound", alias="workOrderType", description="工单类型 inbound/temporary")
|
||||
protocol_no: Optional[str] = Field(None, alias="protocolNo", description="协议号")
|
||||
sample_code: Optional[str] = Field(None, alias="sampleCode", description="样本编码")
|
||||
reception_source: Optional[str] = Field("cell_storage", alias="receptionSource", description="来源类型")
|
||||
remark: Optional[str] = Field(None, description="备注")
|
||||
|
||||
|
||||
class ProductionWorkOrderConfigureBody(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
task_name: Optional[str] = Field("", alias="taskName")
|
||||
task_type: Optional[str] = Field("cell_storage", alias="taskType")
|
||||
route_id: Optional[str] = Field(None, alias="routeId")
|
||||
description: Optional[str] = Field("", alias="description")
|
||||
remark: Optional[str] = Field("", alias="remark")
|
||||
@@ -0,0 +1,18 @@
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class QcTaskCreateBody(BaseModel):
|
||||
"""手动创建质检任务"""
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
task_type: str = Field(..., alias="taskType", description="检测类型 sysz/dsfjc")
|
||||
item_code: str = Field(..., alias="itemCode", description="项目编码")
|
||||
item_name: str = Field(..., alias="itemName", description="项目名称")
|
||||
company_id: Optional[str] = Field(None, alias="companyId", description="第三方公司ID")
|
||||
company_name: Optional[str] = Field(None, alias="companyName", description="第三方公司名")
|
||||
fee_amount: Optional[float] = Field(None, alias="feeAmount", description="费用")
|
||||
sample_code: Optional[str] = Field(None, alias="sampleCode", description="样本编码")
|
||||
qc_biz_type: Optional[str] = Field("inbound", alias="qcBizType", description="质检业务类型")
|
||||
work_order_id: Optional[str] = Field(None, alias="workOrderId", description="关联工单ID(可选)")
|
||||
remark: Optional[str] = Field(None, description="备注")
|
||||
@@ -0,0 +1,23 @@
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class QcWorkOrderCreateBody(BaseModel):
|
||||
"""手动创建质检工单"""
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
work_order_type: Optional[str] = Field("inbound", alias="workOrderType", description="工单类型 inbound/temporary")
|
||||
protocol_no: Optional[str] = Field(None, alias="protocolNo", description="协议号")
|
||||
sample_code: Optional[str] = Field(None, alias="sampleCode", description="样本编码")
|
||||
reception_source: Optional[str] = Field("cell_storage", alias="receptionSource", description="来源类型")
|
||||
qc_biz_type: Optional[str] = Field("inbound", alias="qcBizType", description="质检业务类型")
|
||||
cell_product_id: Optional[str] = Field(None, alias="cellProductId", description="质检对象-细胞产品ID")
|
||||
remark: Optional[str] = Field(None, description="备注")
|
||||
|
||||
|
||||
class QcWorkOrderUpdateBody(BaseModel):
|
||||
"""编辑临时质检工单"""
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
cell_product_id: Optional[str] = Field(None, alias="cellProductId", description="质检对象-细胞产品ID")
|
||||
remark: Optional[str] = Field(None, description="备注")
|
||||
File diff suppressed because it is too large.
Load diff
+3005
-1133
File diff suppressed because it is too large.
Load diff
@@ -1,12 +1,12 @@
|
||||
# Graph Report - app (2026-05-24)
|
||||
|
||||
## Corpus Check
|
||||
- 146 files · ~135,185 words
|
||||
- 148 files · ~136,649 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 2601 nodes · 10532 edges · 54 communities detected
|
||||
- Extraction: 41% EXTRACTED · 59% INFERRED · 0% AMBIGUOUS · INFERRED: 6233 edges (avg confidence: 0.63)
|
||||
- 2619 nodes · 10690 edges · 58 communities detected
|
||||
- Extraction: 40% EXTRACTED · 60% INFERRED · 0% AMBIGUOUS · INFERRED: 6361 edges (avg confidence: 0.63)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
@@ -58,16 +58,20 @@
|
||||
- [[_COMMUNITY_Community 45|Community 45]]
|
||||
- [[_COMMUNITY_Community 46|Community 46]]
|
||||
- [[_COMMUNITY_Community 47|Community 47]]
|
||||
- [[_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 58|Community 58]]
|
||||
- [[_COMMUNITY_Community 59|Community 59]]
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `success_response()` - 409 edges
|
||||
2. `error_response()` - 328 edges
|
||||
1. `success_response()` - 413 edges
|
||||
2. `error_response()` - 331 edges
|
||||
3. `SysUser` - 234 edges
|
||||
4. `BizQcMaterialUsage` - 208 edges
|
||||
5. `BizMaterialStockLog` - 204 edges
|
||||
@@ -75,7 +79,7 @@
|
||||
7. `BizQcMaterial` - 204 edges
|
||||
8. `BizMaterial` - 201 edges
|
||||
9. `BizQcItemParam` - 199 edges
|
||||
10. `generate_uuid()` - 148 edges
|
||||
10. `generate_uuid()` - 151 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `统一记录 API 请求/响应出入参的中间件` --uses--> `SysApiRequestLog` [INFERRED]
|
||||
@@ -93,107 +97,107 @@
|
||||
|
||||
### Community 0 - "Community 0"
|
||||
Cohesion: 0.02
|
||||
Nodes (439): attachment_download_url(), create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post() (+431 more)
|
||||
Nodes (462): attachment_download_url(), create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post() (+454 more)
|
||||
|
||||
### Community 1 - "Community 1"
|
||||
Cohesion: 0.01
|
||||
Nodes (408): AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody, DictTypeUpdateBody, ExpressCompanyCreateBody (+400 more)
|
||||
Nodes (391): AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody, DictTypeUpdateBody, ExpressCompanyCreateBody (+383 more)
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.05
|
||||
Nodes (285): AuditCreateBody, BatchDetailIdsBody, BatchRefundFinanceSubmitBody, FinanceConfirmBody, FullmoonTodoInsuranceBody, ProtocolCreateBody, ProtocolUpdateBody, 细胞存储 — 采集协议单 / 审核 / 财务确认 / 分期预警 API (+277 more)
|
||||
Cohesion: 0.02
|
||||
Nodes (240): _persist_protocol_sub_resources(), get_designer_data(), apply_data_scope(), _get_child_dept_ids(), get_user_dept_id(), _resolve_user_role_scopes(), generate_uuid(), _add_months_yyyymmdd() (+232 more)
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.02
|
||||
Nodes (175): generate_uuid(), batch_stock_in(), batch_stock_out(), consumable_code_exists(), create_consumable(), _dec(), get_consumable(), _is_enabled_status() (+167 more)
|
||||
Cohesion: 0.05
|
||||
Nodes (244): InsuranceCompanyCreateBody, InsuranceCompanyInvoiceCreateBody, InsuranceCompanyInvoiceUpdateBody, InsuranceCompanyUpdateBody, InsuranceProjectPriceCreateBody, InsuranceProjectPriceUpdateBody, 保险公司及险种价格管理 API(保险公司 + 开票信息 + 险种价格), ProcessDefCreateBody (+236 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.02
|
||||
Nodes (158): list_collection_regions(), create_collection_protocol(), delete_collection_protocol(), _ensure_customer_for_mother(), get_collection_protocol_detail(), _get_current_user_id(), _get_tenant_no(), list_collection_protocol_audits() (+150 more)
|
||||
Nodes (105): list_roles_for_select(), _avatar_url_field(), _build_user_info_payload(), _jwt_user_payload(), logout(), 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/zkxw.sql 基线), 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。, 与 web-admin `userInfo` 字段约定一致。 (+97 more)
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.04
|
||||
Nodes (119): _format_attachment_file_size(), get_protocol_nos_used_in_protocols(), urls_to_attachment_list(), _accept_conclusion_label(), _attach_reception_detail(), complete_production_work_order(), create_production_work_order_from_reception(), _enrich_wo_items() (+111 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (136): CellSampleTypeCreateBody, CellSampleTypeUpdateBody, CollectionRegionCreateBody, CollectionRegionUpdateBody, CustomerCreateBody, CustomerUpdateBody, HospitalCreateBody, HospitalUpdateBody (+128 more)
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.07
|
||||
Nodes (67): AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, ExhibitionAppointmentCreateBody, ExhibitionAppointmentUpdateBody, OccupancyCreateBody, 运营支撑 API(洁净室、进出记录、仓储设施、储位、展厅预约) (+59 more)
|
||||
Cohesion: 0.05
|
||||
Nodes (99): _format_attachment_file_size(), urls_to_attachment_list(), _accept_conclusion_label(), _attach_reception_detail(), complete_production_work_order(), create_production_work_order_manual(), _enrich_wo_items(), _fmt_dt() (+91 more)
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.05
|
||||
Nodes (57): list_roles_for_select(), _avatar_url_field(), _build_user_info_payload(), _jwt_user_payload(), logout(), 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/zkxw.sql 基线), 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。, 与 web-admin `userInfo` 字段约定一致。 (+49 more)
|
||||
Nodes (74): get_next_cell_product_code(), _build_ancestor_chain(), _build_descendant_chain(), _build_facility_path_label(), create_cell_products_batch(), delete_cell_product(), _enrich_product_dicts(), _first_chain_link() (+66 more)
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.06
|
||||
Nodes (55): get_designer_data(), ProcessDefCreateBody, ProcessDefUpdateBody, PublishVersionBody, 审批意见:前端传 commentText,兼容 comment。, StartInstanceBody, TaskActionBody, list_params_by_item() (+47 more)
|
||||
Cohesion: 0.04
|
||||
Nodes (31): BusinessException, InvalidStatusTransitionException, log_delivery_operation(), log_operation(), log_order_operation(), log_settlement_operation(), log_user_operation(), OrderLockedException (+23 more)
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.05
|
||||
Nodes (26): BusinessException, InvalidStatusTransitionException, log_delivery_operation(), log_operation(), log_order_operation(), log_settlement_operation(), log_user_operation(), OrderLockedException (+18 more)
|
||||
Cohesion: 0.07
|
||||
Nodes (67): AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, ExhibitionAppointmentCreateBody, ExhibitionAppointmentUpdateBody, OccupancyCreateBody, 运营支撑 API(洁净室、进出记录、仓储设施、储位、展厅预约) (+59 more)
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.34
|
||||
Nodes (58): BatchStockInBody, BatchStockInItem, BatchStockOutBody, BatchStockOutItem, ConsumableCreateBody, ConsumablePackCreateBody, ConsumablePackUpdateBody, ConsumableUpdateBody (+50 more)
|
||||
Nodes (59): BatchStockInBody, BatchStockInItem, BatchStockOutBody, BatchStockOutItem, ConsumableCreateBody, ConsumablePackCreateBody, ConsumablePackUpdateBody, ConsumableUpdateBody (+51 more)
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.06
|
||||
Nodes (57): get_next_cell_product_code(), _build_facility_path_label(), build_split_product_codes(), create_cell_product(), create_cell_products_batch(), create_cell_products_by_quantity(), delete_cell_product(), _enrich_product_dicts() (+49 more)
|
||||
Cohesion: 0.14
|
||||
Nodes (33): list_research_donation_audits(), _audit_to_dict(), batch_delete_donations(), _collection_to_dict(), _create_collection(), create_donation(), _create_party(), _create_samples() (+25 more)
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.05
|
||||
Nodes (38): ApiRequestLogMiddleware, _claims_from_auth(), _format_body_bytes(), _persist_log(), 统一记录 API 请求/响应出入参的中间件, _redact_obj(), _schedule_persist_log(), _should_skip() (+30 more)
|
||||
Cohesion: 0.12
|
||||
Nodes (11): get_wechat_pay_client(), get_wechat_pay_v2(), 微信支付工具模块 支持微信支付 V3 API 文档参考: https://pay.weixin.qq.com/docs/v3/apis/index.ht, 统一下单接口 (V3) Args: out_trade_no: 商户订单号 total, 申请退款 Args: out_trade_no: 商户订单号 total_amount, 小程序调起支付的二次签名参数(与公众号 JSAPI 规则一致), 统一下单 (V2 API) Args: out_trade_no: 商户订单号 tot, 生成签名 V3 (SHA256 with RSA) (+3 more)
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.11
|
||||
Nodes (44): create_collection_protocol(), _active_link_query(), assert_biz_no_available(), create_convert_link(), get_convert_partner(), get_partner_sample_codes(), has_active_convert_link(), upsert_convert_link_for_to_storage() (+36 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.16
|
||||
Nodes (32): _create_insurance_company(), _create_insurance_company_invoice(), _create_insurance_project_price(), delete_insurance_company(), delete_insurance_company_invoice(), delete_insurance_project_price(), _fmt_dt(), _generate_uuid() (+24 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.1
|
||||
Nodes (26): BaseHTTPMiddleware, parse_admin_request_json(), 运营 Web(/web/admin)JSON 请求体解析。 与 ApiCryptoMiddleware 配合:中间件未改写 body 时,在路由内解密 `, 读取 JSON body;dict 时走 resolve_request_payload(明文 / 密文 / data 包装)。 Returns:, ApiCryptoError, _b64url_decode(), _b64url_encode(), decrypt_json() (+18 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.16
|
||||
Nodes (26): add_step(), copy_step(), create_route(), _create_step_consumable(), _create_step_data_collection(), _create_step_output(), _create_step_reagent(), get_route() (+18 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.21
|
||||
Nodes (19): _consumable_row_to_dict(), create_process(), _create_sub_consumable(), _create_sub_data_collection(), _create_sub_output(), _create_sub_reagent(), _data_collection_row_to_dict(), get_process() (+11 more)
|
||||
|
||||
### Community 16 - "Community 16"
|
||||
Cohesion: 0.12
|
||||
Nodes (11): get_wechat_pay_client(), get_wechat_pay_v2(), 微信支付工具模块 支持微信支付 V3 API 文档参考: https://pay.weixin.qq.com/docs/v3/apis/index.ht, 统一下单接口 (V3) Args: out_trade_no: 商户订单号 total, 申请退款 Args: out_trade_no: 商户订单号 total_amount, 小程序调起支付的二次签名参数(与公众号 JSAPI 规则一致), 统一下单 (V2 API) Args: out_trade_no: 商户订单号 tot, 生成签名 V3 (SHA256 with RSA) (+3 more)
|
||||
Cohesion: 0.18
|
||||
Nodes (17): generate_sms(), _get_current_user_id(), _get_tenant_no(), list_notifications(), _page_payload(), toggle_status(), ToggleStatusBody, _accept_conclusion_label() (+9 more)
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
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)
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
Cohesion: 0.2
|
||||
Nodes (14): deduct_for_task(), _display_remark(), list_usages(), list_usages_by_task(), _parse_receiver_purpose_from_remark(), 查询质检任务关联的物料使用记录(task_complete)。, 撤销任务此前 task_complete 扣减,便于重新填报物料使用。, 兼容旧数据:领用人/用途曾拼接在 remark 中。 (+6 more)
|
||||
Cohesion: 0.25
|
||||
Nodes (14): batch_stock_in(), batch_stock_out(), create_reagent(), _dec(), get_reagent(), _is_enabled_status(), list_reagents(), _norm_status() (+6 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.21
|
||||
Nodes (13): create_collection_region(), create_hospital(), get_collection_region(), get_hospital(), _hospital_names_by_region_ids(), _hospital_to_dict(), list_collection_regions(), list_hospitals() (+5 more)
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
Cohesion: 0.25
|
||||
Nodes (13): code_exists(), create_material(), _dec(), _fmt_dt(), get_material(), list_materials(), _norm_status(), options_list() (+5 more)
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
### Community 21 - "Community 21"
|
||||
Cohesion: 0.25
|
||||
Nodes (13): batch_issue_protocol_nos(), batch_revoke_protocol_nos(), create_protocol_no(), get_protocol_no(), list_protocol_nos(), _parse_issued_time(), protocol_no_exists(), 采集协议号池 CRUD(biz_collection_protocol_no) (+5 more)
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
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"
|
||||
### Community 23 - "Community 23"
|
||||
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 22 - "Community 22"
|
||||
Cohesion: 0.23
|
||||
Nodes (12): Config, ProductBase, ProductCategoryBase, ProductCategoryCreate, ProductCategoryResponse, ProductCreate, ProductResponse, ProductUnitBase (+4 more)
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.29
|
||||
Nodes (10): _accept_conclusion_label(), _base_query(), _ensure_notification(), _fmt_dt(), generate_sms_content(), list_notifications(), resolve_notification(), _row_to_dict() (+2 more)
|
||||
|
||||
### 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)
|
||||
Cohesion: 0.31
|
||||
Nodes (12): _code_exists(), create_material(), _dec(), _fmt_dt(), get_material(), list_materials(), options_list(), _row_to_dict() (+4 more)
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
Cohesion: 0.3
|
||||
Nodes (10): create_consumable_pack(), get_consumable_pack(), get_pack_detail(), _item_row_to_dict(), list_all_packs(), list_consumable_packs(), pack_code_exists(), _row_to_dict() (+2 more)
|
||||
Cohesion: 0.28
|
||||
Nodes (10): _base_query(), _ensure_notification(), _fmt_dt(), generate_sms_content(), list_notifications(), resolve_notification(), _row_to_dict(), _storage_status_label() (+2 more)
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.27
|
||||
@@ -208,145 +212,161 @@ Cohesion: 0.31
|
||||
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 29 - "Community 29"
|
||||
Cohesion: 0.36
|
||||
Nodes (9): deduct_for_task(), _display_remark(), list_usages(), list_usages_by_task(), _parse_receiver_purpose_from_remark(), _resolve_receiver_purpose(), revert_task_material_usages(), _row_to_dict() (+1 more)
|
||||
|
||||
### Community 30 - "Community 30"
|
||||
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()
|
||||
|
||||
### Community 30 - "Community 30"
|
||||
### Community 31 - "Community 31"
|
||||
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 31 - "Community 31"
|
||||
### Community 32 - "Community 32"
|
||||
Cohesion: 0.27
|
||||
Nodes (8): create_dict_data(), get_dict_data(), list_dict_data(), list_dict_data_options(), 字典数据 CRUD(sys_dict_data), _row_to_dict(), soft_delete_dict_data(), update_dict_data()
|
||||
|
||||
### Community 32 - "Community 32"
|
||||
### Community 33 - "Community 33"
|
||||
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 33 - "Community 33"
|
||||
### Community 34 - "Community 34"
|
||||
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 34 - "Community 34"
|
||||
### Community 35 - "Community 35"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): create_customer(), get_customer(), id_card_taken(), list_customers(), 客户 CRUD(biz_customer), _row_to_dict(), soft_delete_customer(), update_customer()
|
||||
|
||||
### Community 36 - "Community 36"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): 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(), update_cell_sample_type()
|
||||
|
||||
### Community 35 - "Community 35"
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): create_output_type(), get_output_type(), list_output_types(), 工艺产出物类型 CRUD(biz_output_type), _row_to_dict(), soft_delete_output_type(), type_code_exists(), update_output_type()
|
||||
|
||||
### Community 36 - "Community 36"
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.36
|
||||
Nodes (7): create_post(), get_post(), list_posts(), post_code_exists(), _row_to_dict(), soft_delete_post(), update_post()
|
||||
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.36
|
||||
Nodes (7): create_dict_type(), dict_type_code_exists(), get_dict_type(), list_dict_types(), _row_to_dict(), soft_delete_dict_type(), update_dict_type()
|
||||
|
||||
### 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()
|
||||
Nodes (7): create_tenant(), get_tenant(), list_tenants(), _row_to_dict(), soft_delete_tenant(), tenant_no_exists(), update_tenant()
|
||||
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 0.39
|
||||
Nodes (8): create_lab_item(), get_lab_item(), item_code_exists(), list_active_lab_items(), list_lab_items(), _row_to_dict(), soft_delete_lab_item(), update_lab_item()
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
Cohesion: 0.36
|
||||
Nodes (7): create_site(), get_site(), list_sites(), _row_to_dict(), site_code_exists(), soft_delete_site(), update_site()
|
||||
|
||||
### Community 42 - "Community 42"
|
||||
Cohesion: 0.29
|
||||
Nodes (2): BaseModel, SoftDeleteModel
|
||||
|
||||
### Community 42 - "Community 42"
|
||||
### Community 43 - "Community 43"
|
||||
Cohesion: 0.43
|
||||
Nodes (7): _display_remark(), list_stock_logs(), _parse_receiver_purpose_from_remark(), _resolve_receiver_purpose(), revert_step_stock_changes(), _row_to_dict(), _user_nick_name_map()
|
||||
|
||||
### Community 44 - "Community 44"
|
||||
Cohesion: 0.38
|
||||
Nodes (6): derive_legacy_status_from_three(), derive_three_status_from_legacy(), 阶段A兼容:从旧 status 推导三字段。 约束:旧 status 本身混合了支付/配送/订单生命周期,因此只能尽力推断; 若业务侧已有更精确, 阶段A兼容:从三字段反推旧 status(用于旧前端/旧筛选参数兼容)。, ThreeStatus, _to_decimal()
|
||||
|
||||
### Community 43 - "Community 43"
|
||||
### Community 45 - "Community 45"
|
||||
Cohesion: 0.6
|
||||
Nodes (5): _dec(), _fmt_dt(), list_stock_logs(), _row_to_dict(), _user_nick_name_map()
|
||||
|
||||
### Community 46 - "Community 46"
|
||||
Cohesion: 0.4
|
||||
Nodes (4): list_ethnics_for_select(), list_ethnics(), 民族码表 CRUD(全局 sys_ethnic), _row_to_dict()
|
||||
|
||||
### Community 47 - "Community 47"
|
||||
Cohesion: 0.5
|
||||
Nodes (3): BaseSettings, Config, Settings
|
||||
|
||||
### Community 44 - "Community 44"
|
||||
### Community 48 - "Community 48"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): _auto_fill_create_dept_id(), ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID
|
||||
|
||||
### Community 45 - "Community 45"
|
||||
### Community 49 - "Community 49"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): get_menu_list(), 运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,供后端菜单模式联调)
|
||||
|
||||
### Community 46 - "Community 46"
|
||||
### Community 50 - "Community 50"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传
|
||||
|
||||
### Community 47 - "Community 47"
|
||||
### Community 51 - "Community 51"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)
|
||||
|
||||
### Community 50 - "Community 50"
|
||||
### Community 54 - "Community 54"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送订单状态通知 Args: openid: 用户openid ord
|
||||
|
||||
### Community 51 - "Community 51"
|
||||
### Community 55 - "Community 55"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送支付成功通知 Args: openid: 用户openid ord
|
||||
|
||||
### Community 52 - "Community 52"
|
||||
### Community 56 - "Community 56"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送配送通知 Args: openid: 配送员openid task
|
||||
|
||||
### Community 53 - "Community 53"
|
||||
### Community 57 - "Community 57"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送配送时效预警 Args: openid: 配送员openid ta
|
||||
|
||||
### Community 54 - "Community 54"
|
||||
### Community 58 - "Community 58"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送退款结果通知 Args: openid: 用户openid ord
|
||||
|
||||
### Community 55 - "Community 55"
|
||||
### Community 59 - "Community 59"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送催单通知给配送员 Args: deliver_openid: 配送员openid
|
||||
|
||||
## Knowledge Gaps
|
||||
- **90 isolated node(s):** `刷新会话 TTL(refreshToken 续期;已登录用户每次 API 校验通过后滑动续期)`, `写入 refreshToken(用于 one-time 使用/吊销)`, `根据 token 获取当前用户(包含 Redis 会话校验;会话滑动续期)`, `登录凭据 RSA 解密(与前端 JSEncrypt PKCS#1 v1.5 兼容)。`, `Base64 密文 -> JSON 对象(须含 username、password、ts 毫秒时间戳)。` (+85 more)
|
||||
- **89 isolated node(s):** `刷新会话 TTL(refreshToken 续期;已登录用户每次 API 校验通过后滑动续期)`, `写入 refreshToken(用于 one-time 使用/吊销)`, `根据 token 获取当前用户(包含 Redis 会话校验;会话滑动续期)`, `登录凭据 RSA 解密(与前端 JSEncrypt PKCS#1 v1.5 兼容)。`, `Base64 密文 -> JSON 对象(须含 username、password、ts 毫秒时间戳)。` (+84 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **Thin community `Community 41`** (8 nodes): `BaseModel`, `.to_dict()`, `get_active()`, `base.py`, `SoftDeleteModel`, `.restore()`, `.soft_delete()`, `__tablename__()`
|
||||
- **Thin community `Community 42`** (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 44`** (4 nodes): `_auto_fill_create_dept_id()`, `get_db()`, `database.py`, `ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID`
|
||||
- **Thin community `Community 48`** (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 45`** (3 nodes): `get_menu_list()`, `menu.py`, `运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,供后端菜单模式联调)`
|
||||
- **Thin community `Community 49`** (3 nodes): `get_menu_list()`, `menu.py`, `运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,供后端菜单模式联调)`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 46`** (2 nodes): `context.py`, `请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传`
|
||||
- **Thin community `Community 50`** (2 nodes): `context.py`, `请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 47`** (2 nodes): `__init__.py`, `API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)`
|
||||
- **Thin community `Community 51`** (2 nodes): `__init__.py`, `API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)`
|
||||
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 54`** (1 nodes): `发送订单状态通知 Args: openid: 用户openid ord`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 51`** (1 nodes): `发送支付成功通知 Args: openid: 用户openid ord`
|
||||
- **Thin community `Community 55`** (1 nodes): `发送支付成功通知 Args: openid: 用户openid ord`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 52`** (1 nodes): `发送配送通知 Args: openid: 配送员openid task`
|
||||
- **Thin community `Community 56`** (1 nodes): `发送配送通知 Args: openid: 配送员openid task`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 53`** (1 nodes): `发送配送时效预警 Args: openid: 配送员openid ta`
|
||||
- **Thin community `Community 57`** (1 nodes): `发送配送时效预警 Args: openid: 配送员openid ta`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 54`** (1 nodes): `发送退款结果通知 Args: openid: 用户openid ord`
|
||||
- **Thin community `Community 58`** (1 nodes): `发送退款结果通知 Args: openid: 用户openid ord`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 55`** (1 nodes): `发送催单通知给配送员 Args: deliver_openid: 配送员openid`
|
||||
- **Thin community `Community 59`** (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 `generate_uuid()` connect `Community 3` to `Community 0`, `Community 1`, `Community 2`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 11`, `Community 12`, `Community 13`, `Community 17`, `Community 18`, `Community 19`, `Community 20`, `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 36`, `Community 37`, `Community 38`, `Community 39`, `Community 40`?**
|
||||
_High betweenness centrality (0.137) - this node is a cross-community bridge._
|
||||
- **Why does `SysUser` connect `Community 1` to `Community 0`, `Community 2`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 10`, `Community 12`, `Community 14`, `Community 18`, `Community 20`, `Community 24`?**
|
||||
- **Why does `generate_uuid()` connect `Community 2` to `Community 0`, `Community 3`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 9`, `Community 11`, `Community 14`, `Community 15`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 20`, `Community 21`, `Community 22`, `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 36`, `Community 37`, `Community 38`, `Community 39`, `Community 40`, `Community 41`?**
|
||||
_High betweenness centrality (0.113) - this node is a cross-community bridge._
|
||||
- **Why does `SysUser` connect `Community 1` to `Community 0`, `Community 3`, `Community 4`, `Community 5`, `Community 9`, `Community 10`, `Community 16`, `Community 21`, `Community 22`?**
|
||||
_High betweenness centrality (0.081) - this node is a cross-community bridge._
|
||||
- **Why does `success_response()` connect `Community 0` to `Community 1`, `Community 4`, `Community 7`, `Community 8`, `Community 11`, `Community 45`, `Community 14`?**
|
||||
_High betweenness centrality (0.056) - this node is a cross-community bridge._
|
||||
- **Are the 408 inferred relationships involving `success_response()` (e.g. with `list_storage_release_reviews()` and `get_storage_release_review_detail()`) actually correct?**
|
||||
_`success_response()` has 408 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 389 inferred relationships involving `str` (e.g. with `extract_login_credentials()` and `._make_request()`) actually correct?**
|
||||
_`str` has 389 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 327 inferred relationships involving `error_response()` (e.g. with `_json_error_response()` and `list_storage_release_reviews()`) actually correct?**
|
||||
_`error_response()` has 327 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Why does `success_response()` connect `Community 0` to `Community 1`, `Community 2`, `Community 4`, `Community 7`, `Community 11`, `Community 46`, `Community 16`, `Community 49`?**
|
||||
_High betweenness centrality (0.068) - this node is a cross-community bridge._
|
||||
- **Are the 412 inferred relationships involving `success_response()` (e.g. with `list_storage_release_reviews()` and `get_storage_release_review_detail()`) actually correct?**
|
||||
_`success_response()` has 412 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 392 inferred relationships involving `str` (e.g. with `extract_login_credentials()` and `._make_request()`) actually correct?**
|
||||
_`str` has 392 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 330 inferred relationships involving `error_response()` (e.g. with `_json_error_response()` and `list_storage_release_reviews()`) actually correct?**
|
||||
_`error_response()` has 330 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 232 inferred relationships involving `SysUser` (e.g. with `数据权限过滤(V0.3:基于角色 data_scope 的查询级行级过滤) data_scope 值: 1 = 全部数据 2 = 本部门数据 3` and `从 SysUser 读取用户的 dept_id。`) actually correct?**
|
||||
_`SysUser` has 232 INFERRED edges - model-reasoned connections that need verification._
|
||||
@@ -57,12 +57,12 @@
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">2601 nodes · 10532 edges · 60 communities</div>
|
||||
<div id="stats">2619 nodes · 10690 edges · 64 communities</div>
|
||||
</div>
|
||||
<script>
|
||||
const RAW_NODES = [{"id": "init_py", "label": "__init__.py", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 48, "community_name": "Community 48", "source_file": "__init__.py", "file_type": "code", "degree": 0}, {"id": "main_py", "label": "main.py", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "main.py", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_lifespan", "label": "lifespan()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "lifespan()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "_mask_secret()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_root", "label": "root()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "root()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_health_check", "label": "health_check()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "health_check()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "tasks_init_py", "label": "__init__.py", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 7, "community_name": "Community 7", "source_file": "tasks/__init__.py", "file_type": "code", "degree": 2}, {"id": "tasks_init_init_scheduled_tasks", "label": "init_scheduled_tasks()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "init_scheduled_tasks()", "community": 7, "community_name": "Community 7", "source_file": "tasks/__init__.py", "file_type": "code", "degree": 2}, {"id": "tasks_init_shutdown_scheduler", "label": "shutdown_scheduler()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "shutdown_scheduler()", "community": 7, "community_name": "Community 7", "source_file": "tasks/__init__.py", "file_type": "code", "degree": 2}, {"id": "core_auth_py", "label": "auth.py", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 11.3, "font": {"size": 0, "color": "#ffffff"}, "title": "auth.py", "community": 7, "community_name": "Community 7", "source_file": "core/auth.py", "file_type": "code", "degree": 18}, {"id": "core_auth_redis_session_enabled", "label": "_redis_session_enabled()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "_redis_session_enabled()", "community": 7, "community_name": "Community 7", "source_file": "core/auth.py", "file_type": "code", "degree": 2}, {"id": "core_auth_get_redis_client", "label": "_get_redis_client()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.7, "font": {"size": 0, "color": "#ffffff"}, "title": "_get_redis_client()", "community": 7, "community_name": "Community 7", "source_file": "core/auth.py", "file_type": "code", "degree": 9}, {"id": "core_auth_session_key", "label": "_session_key()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "_session_key()", "community": 7, "community_name": "Community 7", "source_file": "core/auth.py", "file_type": "code", "degree": 5}, {"id": "core_auth_refresh_key", "label": "_refresh_key()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "boLine 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_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": "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", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_session_key", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_refresh_key", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_store_session", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_revoke_session", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_extend_session", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_is_session_valid", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_store_refresh_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_is_refresh_token_valid", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_revoke_refresh_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_create_access_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_create_refresh_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_decode_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_current_user_by_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_current_user", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "Line truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 453}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 435}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 290}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 195}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 178}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 128}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 71}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 70}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 69}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 68}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 65}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 62}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 59}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 46}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 33}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 31}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 31}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 20}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 15}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 15}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 14}, {"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": 13}, {"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": 10}, {"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": 9}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 8}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 7}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 4}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 4}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 3}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 2}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 2}, {"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": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 52, "community_name": "Community 52", "source_file": "__init__.py", "file_type": "code", "degree": 0}, {"id": "main_py", "label": "main.py", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "main.py", "community": 4, "community_name": "Community 4", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_lifespan", "label": "lifespan()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "lifespan()", "community": 4, "community_name": "Community 4", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "_mask_secret()", "community": 4, "community_name": "Community 4", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_root", "label": "root()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "root()", "community": 4, "community_name": "Community 4", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_health_check", "label": "health_check()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "health_check()", "community": 4, "community_name": "Community 4", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "tasks_init_py", "label": "__init__.py", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 4, "community_name": "Community 4", "source_file": "tasks/__init__.py", "file_type": "code", "degree": 2}, {"id": "tasks_init_init_scheduled_tasks", "label": "init_scheduled_tasks()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "init_scheduled_tasks()", "community": 4, "community_name": "Community 4", "source_file": "tasks/__init__.py", "file_type": "code", "degree": 2}, {"id": "tasks_init_shutdown_scheduler", "label": "shutdown_scheduler()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "shutdown_scheduler()", "community": 4, "community_name": "Community 4", "source_file": "tasks/__init__.py", "file_type": "code", "degree": 2}, {"id": "core_auth_py", "label": "auth.py", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 11.3, "font": {"size": 0, "color": "#ffffff"}, "title": "auth.py", "community": 4, "community_name": "Community 4", "source_file": "core/auth.py", "file_type": "code", "degree": 18}, {"id": "core_auth_redis_session_enabled", "label": "_redis_session_enabled()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "_redis_session_enabled()", "community": 4, "community_name": "Community 4", "source_file": "core/auth.py", "file_type": "code", "degree": 2}, {"id": "core_auth_get_redis_client", "label": "_get_redis_client()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.7, "font": {"size": 0, "color": "#ffffff"}, "title": "_get_redis_client()", "community": 4, "community_name": "Community 4", "source_file": "core/auth.py", "file_type": "code", "degree": 9}, {"id": "core_auth_session_key", "label": "_session_key()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "_session_key()", "community": 4, "community_name": "Community 4", "source_file": "core/auth.py", "file_type": "code", "degree": 5}, {"id": "core_auth_refresh_key", "label": "_refresh_key()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "boLine 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_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": "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", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_session_key", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_refresh_key", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_store_session", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_revoke_session", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_extend_session", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_is_session_valid", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_store_refresh_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_is_refresh_token_valid", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_revoke_refresh_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_create_access_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_create_refresh_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_decode_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_current_user_by_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_current_user", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "Line truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 476}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 421}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 273}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 251}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 142}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 139}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 105}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 80}, {"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": 66}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 34}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 31}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 31}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 28}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 21}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 21}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 20}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 16}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 15}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 15}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 15}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 14}, {"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": 13}, {"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": 10}, {"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": 10}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 10}, {"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": 9}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 9}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 8}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 8}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 7}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 6}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 6}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 4}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 4}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 3}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 2}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 2}, {"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}];
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
|
||||
+4355
-2297
File diff suppressed because it is too large.
Load diff
@@ -31,12 +31,13 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/qc_material.py": 1779284411.5179992,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/base.py": 1778578258.0821667,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/storage_release_review.py": 1779491680.5729434,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_task.py": 1779597960.4337523,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/process_route.py": 1779367496.1718137,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/auth.py": 1778578258.0939043,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/delivery.py": 1778578258.0949655,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/price_list.py": 1778578258.096609,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/user.py": 1778578258.099944,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py": 1779586786.8458486,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/production_work_order.py": 1779598101.8960276,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/storage_occupancy.py": 1779418054.7652438,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/quotation.py": 1778578258.0991468,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/product_parameter_value.py": 1778578258.0980055,
|
||||
@@ -50,26 +51,27 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/order.py": 1778578258.0960286,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/__init__.py": 1778578258.0864499,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/order_adjust.py": 1778578258.0963318,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py": 1779505698.9461272,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py": 1779594151.5265117,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/menu.py": 1778578258.0957444,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/attachment.py": 1778763456.6244864,
|
||||
"/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": 1779597848.673695,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/product.py": 1778578258.0968297,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/workflow.py": 1778633845.5937889,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/product_review.py": 1778578258.098316,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/category.py": 1778578258.0941947,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/leave.py": 1778666088.7680702,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py": 1779542343.2331185,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py": 1779533582.355786,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py": 1779597967.1911633,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py": 1779587424.6859367,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/sample_code.py": 1779279460.690872,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_result.py": 1779331731.6720955,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/post.py": 1779265648.38155,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/sample_reception_check_result.py": 1779255909.8554008,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/user.py": 1778775532.8870275,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py": 1779586791.5759737,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_work_order.py": 1779598076.1864269,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/material.py": 1779283386.3879013,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/dict_type.py": 1779265621.5212462,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_occupancy.py": 1779418213.0446064,
|
||||
@@ -90,7 +92,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/express_company.py": 1779265659.3453207,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_lab_test_item.py": 1779265673.3888667,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/role.py": 1779265616.3701816,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py": 1779421014.4336343,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py": 1779598140.610689,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/menu.py": 1779265729.0381103,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_region.py": 1779277867.6408322,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/sample_reception_check_item.py": 1779007909.2933013,
|
||||
@@ -101,7 +103,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/ethnic.py": 1779265849.547566,
|
||||
"/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": 1779533586.5012808,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py": 1779597853.4248848,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py": 1779309113.0447981,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/pilot_service.py": 1779310971.8304002,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/customer.py": 1778733031.447253,
|
||||
@@ -124,7 +126,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_release_review.py": 1779526635.1455016,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/public.py": 1779313409.0685387,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/material.py": 1779526648.041865,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py": 1779526647.7395403,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py": 1779597978.6108778,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/collection_protocol.py": 1779265813.1605325,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/basic_info.py": 1779280842.8447173,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py": 1779528183.6934836,
|
||||
@@ -139,7 +141,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py": 1779526395.021059,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_reception.py": 1779526633.9689634,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/insurance_company.py": 1779281097.279193,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py": 1779586806.431537,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py": 1779598093.744562,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/leave.py": 1779266168.8693042,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/workflow_callback.py": 1778727966.7277644,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/workflow_engine.py": 1778634664.6293883,
|
||||
|
||||
@@ -0,0 +1,731 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>细胞产品来源链路 Demo</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary: #10b981;
|
||||
--primary-dark: #059669;
|
||||
--primary-light: #ecfdf5;
|
||||
--primary-border: #a7f3d0;
|
||||
--text: #1f2937;
|
||||
--text-muted: #6b7280;
|
||||
--text-light: #9ca3af;
|
||||
--sample-bg: #eff6ff;
|
||||
--sample-border: #93c5fd;
|
||||
--line-color: #d1d5db;
|
||||
--line-active: #10b981;
|
||||
--font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: var(--font-family);
|
||||
background: #f9fafb;
|
||||
color: var(--text);
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
h1 { font-size: 18px; font-weight: 600; margin-bottom: 8px; }
|
||||
.subtitle { font-size: 13px; color: var(--text-muted); margin-bottom: 24px; }
|
||||
|
||||
.scenario-tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.scenario-tab {
|
||||
padding: 6px 16px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--line-color);
|
||||
background: white;
|
||||
color: var(--text-muted);
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.scenario-tab:hover { border-color: var(--primary); color: var(--primary); }
|
||||
.scenario-tab.active { background: var(--primary); color: white; border-color: var(--primary); }
|
||||
|
||||
.scenario-desc {
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
background: #fffbeb;
|
||||
border: 1px solid #fde68a;
|
||||
border-radius: 8px;
|
||||
padding: 10px 16px;
|
||||
margin-bottom: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.scenario-desc strong { color: var(--text); }
|
||||
|
||||
.scenario-panel { display: none; }
|
||||
.scenario-panel.active { display: block; }
|
||||
|
||||
.chain-container {
|
||||
background: white;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 12px;
|
||||
padding: 32px 24px 24px;
|
||||
overflow-x: auto;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.chain-section-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.chain-section-title::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 3px;
|
||||
height: 14px;
|
||||
background: var(--primary);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.chain-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.chain-node {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
z-index: 2;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.node-card {
|
||||
width: 148px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
border: 1.5px solid var(--primary-border);
|
||||
background: var(--primary-light);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
position: relative;
|
||||
}
|
||||
.node-card:hover {
|
||||
box-shadow: 0 4px 12px rgba(16,185,129,0.2);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.node-card.sample {
|
||||
background: var(--sample-bg);
|
||||
border-color: var(--sample-border);
|
||||
}
|
||||
.node-card.sample:hover {
|
||||
box-shadow: 0 4px 12px rgba(147,197,253,0.3);
|
||||
}
|
||||
.node-card.current {
|
||||
border-color: var(--primary);
|
||||
border-width: 2px;
|
||||
box-shadow: 0 0 0 3px rgba(16,185,129,0.15);
|
||||
}
|
||||
.node-card.current::after {
|
||||
content: '当前';
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -8px;
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
font-size: 10px;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.node-type-tag {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
padding: 1px 5px;
|
||||
border-radius: 3px;
|
||||
margin-bottom: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.node-type-tag.product { background: #d1fae5; color: #065f46; }
|
||||
.node-type-tag.sample-type { background: #dbeafe; color: #1e40af; }
|
||||
|
||||
.node-code { font-size: 12px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.node-name { font-size: 11px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.node-passage { font-size: 10px; color: var(--text-light); margin-top: 2px; }
|
||||
|
||||
/* 连线 — 加长到 180px */
|
||||
.chain-connector {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
min-width: 180px;
|
||||
height: 60px;
|
||||
z-index: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.connector-label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1px;
|
||||
font-size: 10px;
|
||||
color: var(--text-muted);
|
||||
white-space: nowrap;
|
||||
padding: 3px 8px;
|
||||
background: white;
|
||||
border: 1px solid #f3f4f6;
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.connector-label .wo { color: var(--primary-dark); font-weight: 500; }
|
||||
.connector-label .task { color: var(--text-light); }
|
||||
|
||||
.connector-line {
|
||||
position: absolute;
|
||||
bottom: 14px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: var(--line-color);
|
||||
}
|
||||
.connector-line.active { background: var(--line-active); }
|
||||
|
||||
.connector-arrow {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: -5px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 5px solid transparent;
|
||||
border-bottom: 5px solid transparent;
|
||||
border-left: 7px solid var(--line-color);
|
||||
}
|
||||
.connector-line.active + .connector-arrow { border-left-color: var(--line-active); }
|
||||
|
||||
/* 分叉 */
|
||||
.fork-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.fork-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
min-height: 72px;
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
.fork-area::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
top: 36px;
|
||||
bottom: 36px;
|
||||
width: 2px;
|
||||
background: var(--line-color);
|
||||
}
|
||||
|
||||
.fork-row::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
top: 50%;
|
||||
width: 22px;
|
||||
height: 2px;
|
||||
background: var(--line-color);
|
||||
}
|
||||
.fork-row::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
top: 0;
|
||||
height: 50%;
|
||||
width: 2px;
|
||||
background: white;
|
||||
z-index: 1;
|
||||
}
|
||||
.fork-row:last-child::after {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
}
|
||||
.fork-row:first-child::after {
|
||||
top: 0;
|
||||
bottom: auto;
|
||||
height: 50%;
|
||||
background: white;
|
||||
}
|
||||
|
||||
/* 图例 */
|
||||
.legend {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 24px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #f3f4f6;
|
||||
}
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.legend-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 3px;
|
||||
border: 1.5px solid;
|
||||
}
|
||||
.legend-dot.product { background: var(--primary-light); border-color: var(--primary-border); }
|
||||
.legend-dot.sample { background: var(--sample-bg); border-color: var(--sample-border); }
|
||||
.legend-dot.current-node { background: var(--primary-light); border-color: var(--primary); border-width: 2px; }
|
||||
.legend-dot.line-legend { background: transparent; border: none; width: 24px; height: 2px; border-radius: 0; background: var(--line-active); }
|
||||
|
||||
.popover-detail {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: white;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
min-width: 200px;
|
||||
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
|
||||
z-index: 100;
|
||||
font-size: 12px;
|
||||
}
|
||||
.popover-detail.visible { display: block; }
|
||||
.popover-detail .detail-row { display: flex; justify-content: space-between; padding: 3px 0; }
|
||||
.popover-detail .detail-label { color: var(--text-muted); }
|
||||
.popover-detail .detail-value { color: var(--text); font-weight: 500; }
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
.empty-state .empty-icon { font-size: 32px; margin-bottom: 8px; opacity: 0.4; }
|
||||
|
||||
.sub-label {
|
||||
font-size: 11px;
|
||||
color: var(--text-light);
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.sub-label .arrow { color: var(--primary); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>细胞产品来源链路 — 设计 Demo</h1>
|
||||
<p class="subtitle">展示细胞产品查看弹窗中的「来源链路」可视化方案。点击任意节点可查看详情。</p>
|
||||
|
||||
<div class="scenario-tabs">
|
||||
<div class="scenario-tab active" onclick="switchScenario('s1', this)">场景1:简单链路</div>
|
||||
<div class="scenario-tab" onclick="switchScenario('s2', this)">场景2:一生多(一个产品产出多个新产品)</div>
|
||||
<div class="scenario-tab" onclick="switchScenario('s3', this)">场景3:完整追溯(往前看祖先 + 往后看子代)</div>
|
||||
<div class="scenario-tab" onclick="switchScenario('s4', this)">场景4:手动录入(无祖先,但有子代)</div>
|
||||
</div>
|
||||
|
||||
<div id="desc-s1" class="scenario-desc active">
|
||||
<strong>场景1 说明:</strong>最简单的情况。一个样本经过一次生产工单,产出一个细胞产品(P1代)。这个P1代产品又经过另一个生产工单,产出了当前查看的P2代产品。每个节点之间只有一条连线。
|
||||
</div>
|
||||
<div id="desc-s2" class="scenario-desc" style="display:none;">
|
||||
<strong>场景2 说明:</strong>当前产品(P1代)被进一步拿去做生产,<strong>一次生产产出了 3 个不同的新细胞产品</strong>。就像一块面团可以同时做出多个包子 — 连线从当前产品分叉出去,每条分叉线上面标注了对应的工单号和任务号。这就是「一生多」。
|
||||
</div>
|
||||
<div id="desc-s3" class="scenario-desc" style="display:none;">
|
||||
<strong>场景3 说明:</strong>最完整的情况。全部在<strong>同一行</strong>展示 — 从左到右:<strong>样本 → P1(父产品) → P2(当前) → 分叉出2个P3(子产品)</strong>。祖先在左边,当前在中间,子代直接从当前节点往右延伸分叉。不分两行,一条链路从头看到尾。
|
||||
</div>
|
||||
<div id="desc-s4" class="scenario-desc" style="display:none;">
|
||||
<strong>场景4 说明:</strong>手动录入的细胞产品是「起源」— 它没有祖先(不是从样本或别的产品生产来的),但后续它可以被拿去生产新的子产品。所以它左边没有祖先链路,但右边会分叉出子代。只有从未被用于生产的「孤立产品」才会显示空状态。
|
||||
</div>
|
||||
|
||||
<div id="s1" class="scenario-panel active">
|
||||
<div class="chain-container">
|
||||
<div class="chain-section-title">来源链路</div>
|
||||
|
||||
<div class="chain-row">
|
||||
<div class="chain-node">
|
||||
<div class="node-card sample" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag sample-type">样本</span>
|
||||
<div class="node-code">ZKZX34000627</div>
|
||||
<div class="node-name">脐带血干细胞</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-connector">
|
||||
<div class="connector-label">
|
||||
<span class="wo">工单 WO20260519001</span>
|
||||
<span class="task">任务 T20260519001</span>
|
||||
</div>
|
||||
<div class="connector-line active"></div>
|
||||
<div class="connector-arrow"></div>
|
||||
</div>
|
||||
|
||||
<div class="chain-node">
|
||||
<div class="node-card" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260520001</div>
|
||||
<div class="node-name">脐带间充质干细胞</div>
|
||||
<div class="node-passage">P1 代</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-connector">
|
||||
<div class="connector-label">
|
||||
<span class="wo">工单 WO20260521002</span>
|
||||
<span class="task">任务 T20260521002</span>
|
||||
</div>
|
||||
<div class="connector-line active"></div>
|
||||
<div class="connector-arrow"></div>
|
||||
</div>
|
||||
|
||||
<div class="chain-node">
|
||||
<div class="node-card current" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260522001</div>
|
||||
<div class="node-name">脐带间充质干细胞</div>
|
||||
<div class="node-passage">P2 代</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="legend">
|
||||
<div class="legend-item"><div class="legend-dot sample"></div>样本</div>
|
||||
<div class="legend-item"><div class="legend-dot product"></div>细胞产品</div>
|
||||
<div class="legend-item"><div class="legend-dot current-node"></div>当前查看</div>
|
||||
<div class="legend-item"><div class="legend-dot line-legend"></div>生产连线(标注工单/任务号)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="s2" class="scenario-panel">
|
||||
<div class="chain-container">
|
||||
<div class="chain-section-title">来源链路</div>
|
||||
<div class="sub-label"><span class="arrow">●</span> 当前产品被拿去生产,一次产出了 3 个新产品(分叉)</div>
|
||||
|
||||
<div class="chain-row">
|
||||
<div class="chain-node">
|
||||
<div class="node-card sample" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag sample-type">样本</span>
|
||||
<div class="node-code">ZKZX34000627</div>
|
||||
<div class="node-name">脐带血干细胞</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-connector">
|
||||
<div class="connector-label">
|
||||
<span class="wo">工单 WO20260519001</span>
|
||||
<span class="task">任务 T20260519001</span>
|
||||
</div>
|
||||
<div class="connector-line active"></div>
|
||||
<div class="connector-arrow"></div>
|
||||
</div>
|
||||
|
||||
<div class="chain-node">
|
||||
<div class="node-card current" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260520001</div>
|
||||
<div class="node-name">脐带间充质干细胞</div>
|
||||
<div class="node-passage">P1 代</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fork-area">
|
||||
<div class="fork-row">
|
||||
<div class="chain-connector" style="min-width:160px;">
|
||||
<div class="connector-label">
|
||||
<span class="wo">工单 WO20260522003</span>
|
||||
<span class="task">任务 T20260522003</span>
|
||||
</div>
|
||||
<div class="connector-line active"></div>
|
||||
<div class="connector-arrow"></div>
|
||||
</div>
|
||||
<div class="chain-node">
|
||||
<div class="node-card" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260523001</div>
|
||||
<div class="node-name">脐带间充质干细胞</div>
|
||||
<div class="node-passage">P2 代</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fork-row">
|
||||
<div class="chain-connector" style="min-width:160px;">
|
||||
<div class="connector-label">
|
||||
<span class="wo">工单 WO20260522003</span>
|
||||
<span class="task">任务 T20260522004</span>
|
||||
</div>
|
||||
<div class="connector-line active"></div>
|
||||
<div class="connector-arrow"></div>
|
||||
</div>
|
||||
<div class="chain-node">
|
||||
<div class="node-card" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260523002</div>
|
||||
<div class="node-name">脐带间充质干细胞</div>
|
||||
<div class="node-passage">P2 代</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fork-row">
|
||||
<div class="chain-connector" style="min-width:160px;">
|
||||
<div class="connector-label">
|
||||
<span class="wo">工单 WO20260522005</span>
|
||||
<span class="task">任务 T20260522005</span>
|
||||
</div>
|
||||
<div class="connector-line active"></div>
|
||||
<div class="connector-arrow"></div>
|
||||
</div>
|
||||
<div class="chain-node">
|
||||
<div class="node-card" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260523003</div>
|
||||
<div class="node-name">围产期造血干细胞</div>
|
||||
<div class="node-passage">P1 代</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="legend">
|
||||
<div class="legend-item"><div class="legend-dot sample"></div>样本</div>
|
||||
<div class="legend-item"><div class="legend-dot product"></div>细胞产品</div>
|
||||
<div class="legend-item"><div class="legend-dot current-node"></div>当前查看</div>
|
||||
<div class="legend-item"><div class="legend-dot line-legend"></div>生产连线</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="s3" class="scenario-panel">
|
||||
<div class="chain-container">
|
||||
<div class="chain-section-title">来源链路(完整双向追溯)</div>
|
||||
<div class="sub-label"><span class="arrow">←</span> 祖先(从哪来)<span style="margin: 0 12px; color: #d1d5db;">|</span> 当前产品 <span style="margin: 0 12px; color: #d1d5db;">|</span> <span class="arrow">→</span> 子代(被拿去做什么)— 全部在同一行</div>
|
||||
|
||||
<div class="chain-row">
|
||||
<div class="chain-node">
|
||||
<div class="node-card sample" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag sample-type">样本</span>
|
||||
<div class="node-code">ZKZX34000627</div>
|
||||
<div class="node-name">脐带血干细胞</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-connector">
|
||||
<div class="connector-label">
|
||||
<span class="wo">工单 WO20260519001</span>
|
||||
<span class="task">任务 T20260519001</span>
|
||||
</div>
|
||||
<div class="connector-line active"></div>
|
||||
<div class="connector-arrow"></div>
|
||||
</div>
|
||||
|
||||
<div class="chain-node">
|
||||
<div class="node-card" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260520001</div>
|
||||
<div class="node-name">脐带间充质干细胞</div>
|
||||
<div class="node-passage">P1 代(父产品)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chain-connector">
|
||||
<div class="connector-label">
|
||||
<span class="wo">工单 WO20260521002</span>
|
||||
<span class="task">任务 T20260521002</span>
|
||||
</div>
|
||||
<div class="connector-line active"></div>
|
||||
<div class="connector-arrow"></div>
|
||||
</div>
|
||||
|
||||
<div class="chain-node">
|
||||
<div class="node-card current" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260522001</div>
|
||||
<div class="node-name">脐带间充质干细胞</div>
|
||||
<div class="node-passage">P2 代(当前)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fork-area">
|
||||
<div class="fork-row">
|
||||
<div class="chain-connector" style="min-width:160px;">
|
||||
<div class="connector-label">
|
||||
<span class="wo">工单 WO20260523003</span>
|
||||
<span class="task">任务 T20260523003</span>
|
||||
</div>
|
||||
<div class="connector-line active"></div>
|
||||
<div class="connector-arrow"></div>
|
||||
</div>
|
||||
<div class="chain-node">
|
||||
<div class="node-card" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260524001</div>
|
||||
<div class="node-name">脐带间充质干细胞</div>
|
||||
<div class="node-passage">P3 代(子产品1)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fork-row">
|
||||
<div class="chain-connector" style="min-width:160px;">
|
||||
<div class="connector-label">
|
||||
<span class="wo">工单 WO20260523004</span>
|
||||
<span class="task">任务 T20260523004</span>
|
||||
</div>
|
||||
<div class="connector-line active"></div>
|
||||
<div class="connector-arrow"></div>
|
||||
</div>
|
||||
<div class="chain-node">
|
||||
<div class="node-card" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260524002</div>
|
||||
<div class="node-name">脐带间充质干细胞</div>
|
||||
<div class="node-passage">P3 代(子产品2)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="legend">
|
||||
<div class="legend-item"><div class="legend-dot sample"></div>样本</div>
|
||||
<div class="legend-item"><div class="legend-dot product"></div>细胞产品</div>
|
||||
<div class="legend-item"><div class="legend-dot current-node"></div>当前查看</div>
|
||||
<div class="legend-item"><div class="legend-dot line-legend"></div>生产连线</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="s4" class="scenario-panel">
|
||||
<div class="chain-container">
|
||||
<div class="chain-section-title">来源链路</div>
|
||||
<div class="sub-label"><span class="arrow">●</span> 手动录入产品(起源节点),无祖先,但后续被拿去生产了子产品</div>
|
||||
|
||||
<div class="chain-row">
|
||||
<div class="chain-node">
|
||||
<div class="node-card current" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260520001</div>
|
||||
<div class="node-name">脐带间充质干细胞</div>
|
||||
<div class="node-passage">手动录入(起源)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fork-area">
|
||||
<div class="fork-row">
|
||||
<div class="chain-connector" style="min-width:160px;">
|
||||
<div class="connector-label">
|
||||
<span class="wo">工单 WO20260522003</span>
|
||||
<span class="task">任务 T20260522003</span>
|
||||
</div>
|
||||
<div class="connector-line active"></div>
|
||||
<div class="connector-arrow"></div>
|
||||
</div>
|
||||
<div class="chain-node">
|
||||
<div class="node-card" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260523001</div>
|
||||
<div class="node-name">脐带间充质干细胞</div>
|
||||
<div class="node-passage">P1 代</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fork-row">
|
||||
<div class="chain-connector" style="min-width:160px;">
|
||||
<div class="connector-label">
|
||||
<span class="wo">工单 WO20260522004</span>
|
||||
<span class="task">任务 T20260522004</span>
|
||||
</div>
|
||||
<div class="connector-line active"></div>
|
||||
<div class="connector-arrow"></div>
|
||||
</div>
|
||||
<div class="chain-node">
|
||||
<div class="node-card" onclick="togglePopover(this)">
|
||||
<span class="node-type-tag product">细胞产品</span>
|
||||
<div class="node-code">CP20260523002</div>
|
||||
<div class="node-name">围产期造血干细胞</div>
|
||||
<div class="node-passage">P1 代</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="legend">
|
||||
<div class="legend-item"><div class="legend-dot product"></div>细胞产品</div>
|
||||
<div class="legend-item"><div class="legend-dot current-node"></div>当前查看(手动录入/起源)</div>
|
||||
<div class="legend-item"><div class="legend-dot line-legend"></div>生产连线</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function switchScenario(id, tab) {
|
||||
document.querySelectorAll('.scenario-panel').forEach(function(p) { p.classList.remove('active'); });
|
||||
document.querySelectorAll('.scenario-tab').forEach(function(t) { t.classList.remove('active'); });
|
||||
document.querySelectorAll('.scenario-desc').forEach(function(d) { d.style.display = 'none'; });
|
||||
document.getElementById(id).classList.add('active');
|
||||
tab.classList.add('active');
|
||||
var descMap = { s1: 'desc-s1', s2: 'desc-s2', s3: 'desc-s3', s4: 'desc-s4' };
|
||||
document.getElementById(descMap[id]).style.display = 'block';
|
||||
}
|
||||
|
||||
function togglePopover(card) {
|
||||
var existing = card.querySelector('.popover-detail');
|
||||
if (existing) { existing.classList.toggle('visible'); return; }
|
||||
|
||||
var code = card.querySelector('.node-code') ? card.querySelector('.node-code').textContent : '';
|
||||
var name = card.querySelector('.node-name') ? card.querySelector('.node-name').textContent : '';
|
||||
var isCurrent = card.classList.contains('current');
|
||||
var isSample = card.classList.contains('sample');
|
||||
var passage = card.querySelector('.node-passage') ? card.querySelector('.node-passage').textContent : '';
|
||||
var status = isSample ? '已入库' : '冷冻中';
|
||||
|
||||
var popover = document.createElement('div');
|
||||
popover.className = 'popover-detail visible';
|
||||
var html = '<div class="detail-row"><span class="detail-label">编码</span><span class="detail-value">' + code + '</span></div>';
|
||||
html += '<div class="detail-row"><span class="detail-label">名称</span><span class="detail-value">' + name + '</span></div>';
|
||||
html += '<div class="detail-row"><span class="detail-label">状态</span><span class="detail-value">' + status + '</span></div>';
|
||||
if (!isSample) { html += '<div class="detail-row"><span class="detail-label">类型</span><span class="detail-value">细胞产品</span></div>'; }
|
||||
if (passage) { html += '<div class="detail-row"><span class="detail-label">代次</span><span class="detail-value">' + passage + '</span></div>'; }
|
||||
if (isCurrent) { html += '<div class="detail-row"><span class="detail-label">标识</span><span class="detail-value" style="color:#10b981">当前查看</span></div>'; }
|
||||
popover.innerHTML = html;
|
||||
card.appendChild(popover);
|
||||
|
||||
setTimeout(function() {
|
||||
document.addEventListener('click', function close(e) {
|
||||
if (!popover.contains(e.target) && e.target !== card) {
|
||||
popover.classList.remove('visible');
|
||||
document.removeEventListener('click', close);
|
||||
}
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,23 +0,0 @@
|
||||
-- 样本接收短信通知记录表
|
||||
CREATE TABLE biz_sample_sms_notification (
|
||||
id VARCHAR(64) NOT NULL COMMENT 'UUID',
|
||||
sample_reception_id VARCHAR(64) NOT NULL COMMENT '关联 biz_sample_reception.id',
|
||||
protocol_id VARCHAR(64) DEFAULT NULL COMMENT '关联采集协议单ID(冗余,方便查询)',
|
||||
sms_content VARCHAR(500) DEFAULT NULL COMMENT '提取的短信内容',
|
||||
sms_notified TINYINT(1) DEFAULT 0 COMMENT '0=未通知 1=已通知',
|
||||
notified_by VARCHAR(64) DEFAULT NULL COMMENT '通知操作人ID',
|
||||
notified_time DATETIME DEFAULT NULL COMMENT '通知时间',
|
||||
-- 公共字段
|
||||
tenant_no VARCHAR(32) DEFAULT NULL,
|
||||
order_num INT DEFAULT 0,
|
||||
remark VARCHAR(500) DEFAULT NULL,
|
||||
create_by VARCHAR(64) DEFAULT NULL,
|
||||
create_dept_id VARCHAR(64) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
update_by VARCHAR(64) DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
del_flag CHAR(1) DEFAULT '0',
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_sample_reception_id (sample_reception_id),
|
||||
KEY idx_protocol_id (protocol_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='样本接收短信通知记录';
|
||||
@@ -1,25 +0,0 @@
|
||||
-- 样本入库短信通知记录表
|
||||
CREATE TABLE biz_storage_entry_sms_notification (
|
||||
id VARCHAR(64) NOT NULL COMMENT 'UUID',
|
||||
storage_review_id VARCHAR(64) NOT NULL COMMENT '关联 biz_storage_release_review.id',
|
||||
protocol_id VARCHAR(64) DEFAULT NULL COMMENT '关联采集协议单ID(冗余)',
|
||||
sms_content VARCHAR(500) DEFAULT NULL COMMENT '生成的短信内容',
|
||||
sms_notified TINYINT(1) DEFAULT 0 COMMENT '0=未通知 1=已通知',
|
||||
notified_by VARCHAR(64) DEFAULT NULL COMMENT '通知操作人ID',
|
||||
notified_by_name VARCHAR(64) DEFAULT NULL COMMENT '通知操作人姓名',
|
||||
notified_time DATETIME DEFAULT NULL COMMENT '通知时间',
|
||||
-- 公共字段
|
||||
tenant_no VARCHAR(32) DEFAULT NULL,
|
||||
order_num INT DEFAULT 0,
|
||||
remark VARCHAR(500) DEFAULT NULL,
|
||||
create_by VARCHAR(64) DEFAULT NULL,
|
||||
create_dept_id VARCHAR(64) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
update_by VARCHAR(64) DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
del_flag CHAR(1) DEFAULT '0',
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_storage_review_id (storage_review_id),
|
||||
KEY idx_protocol_id (protocol_id),
|
||||
KEY idx_tenant_no (tenant_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='样本入库短信通知记录';
|
||||
@@ -1,3 +0,0 @@
|
||||
-- Fix collation mismatch (1267) when joining biz_sample_sms_notification with biz_sample_reception
|
||||
ALTER TABLE biz_sample_sms_notification
|
||||
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -1,24 +0,0 @@
|
||||
-- 样本接收信息菜单(位于退费确认与储存证管理之间)
|
||||
-- 注意:插入后需将储存证管理的 order_num 从 6 改为 7
|
||||
|
||||
-- 1. 新增菜单
|
||||
INSERT INTO `sys_menu` (
|
||||
`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`,
|
||||
`is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
|
||||
) VALUES (
|
||||
'50000000000000000000000000000011',
|
||||
'样本接收信息',
|
||||
'50000000000000000000000000000001',
|
||||
'C',
|
||||
'sample-reception-info',
|
||||
'/cell-storage/sample-reception-info/index',
|
||||
'cell-storage:sample-reception-info:list',
|
||||
1, '1', '1', 'zkxw', 6, NULL,
|
||||
NULL, '', NOW(), NULL, NOW(), 0
|
||||
);
|
||||
|
||||
-- 2. 后续菜单 order_num +1
|
||||
UPDATE `sys_menu` SET `order_num` = `order_num` + 1
|
||||
WHERE `parent_id` = '50000000000000000000000000000001'
|
||||
AND `order_num` >= 6;
|
||||
@@ -1,24 +0,0 @@
|
||||
-- 样本入库信息菜单(位于样本接收信息与储存证管理之间)
|
||||
-- 注意:插入后需将储存证管理及之后的 order_num +1
|
||||
|
||||
-- 1. 新增菜单
|
||||
INSERT INTO `sys_menu` (
|
||||
`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`,
|
||||
`is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
|
||||
) VALUES (
|
||||
'50000000000000000000000000000012',
|
||||
'样本入库信息',
|
||||
'50000000000000000000000000000001',
|
||||
'C',
|
||||
'storage-entry-info',
|
||||
'/cell-storage/storage-entry-info/index',
|
||||
'cell-storage:storage-entry-info:list',
|
||||
1, '1', '1', 'zkxw', 7, NULL,
|
||||
NULL, '', NOW(), NULL, NOW(), 0
|
||||
);
|
||||
|
||||
-- 2. 后续菜单 order_num +1
|
||||
UPDATE `sys_menu` SET `order_num` = `order_num` + 1
|
||||
WHERE `parent_id` = '50000000000000000000000000000001'
|
||||
AND `order_num` >= 7;
|
||||
@@ -0,0 +1,59 @@
|
||||
-- ============================================================
|
||||
-- 工单表合并迁移:biz_temp_* → 主表 + work_order_type
|
||||
-- Date: 2026-05-24
|
||||
-- 执行顺序:先本脚本,再 work_order_unification_phase1.sql
|
||||
-- 适用:仍保留 biz_temp_qc_work_order / biz_temp_production_work_order 的旧库
|
||||
-- ============================================================
|
||||
|
||||
-- 1. biz_qc_work_order: 加 work_order_type(若已存在则跳过,需 MySQL 8+ 或手动检查)
|
||||
-- ALTER TABLE biz_qc_work_order
|
||||
-- ADD COLUMN work_order_type VARCHAR(20) NOT NULL DEFAULT 'inbound'
|
||||
-- COMMENT '工单类型: inbound=入库, temporary=临时' AFTER work_order_no;
|
||||
|
||||
-- 2. reception 关联字段改为可空(临时工单不需要)
|
||||
-- ALTER TABLE biz_qc_work_order
|
||||
-- MODIFY COLUMN reception_id VARCHAR(64) NULL,
|
||||
-- MODIFY COLUMN protocol_sample_id VARCHAR(64) NULL,
|
||||
-- MODIFY COLUMN collection_protocol_id VARCHAR(64) NULL,
|
||||
-- MODIFY COLUMN reception_source VARCHAR(20) NULL DEFAULT 'cell_storage';
|
||||
|
||||
-- 3. 迁移临时质检工单(按 id 去重,避免重复执行)
|
||||
INSERT INTO biz_qc_work_order (
|
||||
id, work_order_no, work_order_type, work_order_status,
|
||||
has_lab, has_third_party, third_party_fee_total,
|
||||
configured_time, configured_by,
|
||||
tenant_no, order_num, remark,
|
||||
create_by, create_dept_id, create_time, update_by, update_time, del_flag
|
||||
)
|
||||
SELECT
|
||||
t.id, t.work_order_no, 'temporary', t.work_order_status,
|
||||
t.has_lab, t.has_third_party, t.third_party_fee_total,
|
||||
t.configured_time, t.configured_by,
|
||||
t.tenant_no, t.order_num, t.remark,
|
||||
t.create_by, t.create_dept_id, t.create_time, t.update_by, t.update_time, t.del_flag
|
||||
FROM biz_temp_qc_work_order t
|
||||
WHERE NOT EXISTS (SELECT 1 FROM biz_qc_work_order m WHERE m.id = t.id);
|
||||
|
||||
-- 4. biz_production_work_order: 加 work_order_type / configured_time / configured_by(若未加请手动 ALTER)
|
||||
-- ALTER TABLE biz_production_work_order ADD COLUMN work_order_type ...
|
||||
-- ALTER TABLE biz_production_work_order ADD COLUMN configured_time DATETIME NULL ...
|
||||
-- ALTER TABLE biz_production_work_order ADD COLUMN configured_by VARCHAR(64) NULL ...
|
||||
|
||||
-- 5. 迁移临时生产工单
|
||||
INSERT INTO biz_production_work_order (
|
||||
id, work_order_no, work_order_type, work_order_status,
|
||||
configured_time, configured_by,
|
||||
tenant_no, order_num, remark,
|
||||
create_by, create_dept_id, create_time, update_by, update_time, del_flag
|
||||
)
|
||||
SELECT
|
||||
t.id, t.work_order_no, 'temporary', t.work_order_status,
|
||||
t.configured_time, t.configured_by,
|
||||
t.tenant_no, t.order_num, t.remark,
|
||||
t.create_by, t.create_dept_id, t.create_time, t.update_by, t.update_time, t.del_flag
|
||||
FROM biz_temp_production_work_order t
|
||||
WHERE NOT EXISTS (SELECT 1 FROM biz_production_work_order m WHERE m.id = t.id);
|
||||
|
||||
-- 6. 删除临时表(确认迁移成功后执行)
|
||||
DROP TABLE IF EXISTS biz_temp_qc_work_order;
|
||||
DROP TABLE IF EXISTS biz_temp_production_work_order;
|
||||
@@ -0,0 +1,7 @@
|
||||
-- ============================================================
|
||||
-- 临时质检工单关联细胞产品(质检对象)
|
||||
-- Date: 2026-05-24
|
||||
-- ============================================================
|
||||
|
||||
ALTER TABLE biz_qc_work_order
|
||||
ADD COLUMN cell_product_id VARCHAR(64) DEFAULT NULL COMMENT '质检对象-细胞产品ID' AFTER qc_biz_type;
|
||||
@@ -0,0 +1,47 @@
|
||||
-- ============================================================
|
||||
-- 工单融合 Phase 1:菜单收口 + 数据修正 + 删除废弃临时表
|
||||
-- Date: 2026-05-24
|
||||
--
|
||||
-- 执行顺序:
|
||||
-- 1) 若库中仍有 biz_temp_* 表 → 先执行 merge_work_order_tables.sql
|
||||
-- 2) 再执行本脚本
|
||||
--
|
||||
-- 说明:zkxw.sql 全量基线已无 biz_temp_* 表;本脚本 DROP 用于清理历史库残留。
|
||||
-- ============================================================
|
||||
|
||||
-- 1. 菜单重命名与软删临时工单菜单
|
||||
UPDATE sys_menu SET menu_name = '质检工单', update_time = NOW()
|
||||
WHERE id = '70000000000000000000000000000007' AND del_flag = 0;
|
||||
|
||||
UPDATE sys_menu SET menu_name = '生产工单', update_time = NOW()
|
||||
WHERE id = '90000000000000000000000000000011' AND del_flag = 0;
|
||||
|
||||
UPDATE sys_menu SET del_flag = 1, update_time = NOW()
|
||||
WHERE id IN (
|
||||
'70000000000000000000000000000012',
|
||||
'90000000000000000000000000000110'
|
||||
) AND del_flag = 0;
|
||||
|
||||
-- 2. 临时工单 reception_id 空串修正为 NULL(避免 uk_qc_wo_reception 冲突)
|
||||
UPDATE biz_qc_work_order
|
||||
SET reception_id = NULL,
|
||||
protocol_sample_id = NULL,
|
||||
collection_protocol_id = NULL,
|
||||
update_time = NOW()
|
||||
WHERE work_order_type = 'temporary'
|
||||
AND del_flag = 0
|
||||
AND (reception_id = '' OR reception_id IS NULL);
|
||||
|
||||
UPDATE biz_production_work_order
|
||||
SET reception_id = NULL,
|
||||
protocol_sample_id = NULL,
|
||||
collection_protocol_id = NULL,
|
||||
update_time = NOW()
|
||||
WHERE work_order_type = 'temporary'
|
||||
AND del_flag = 0
|
||||
AND (reception_id = '' OR reception_id IS NULL);
|
||||
|
||||
-- 3. 删除已废弃的临时工单表(ORM/代码已不再使用)
|
||||
-- 若表内仍有未迁移数据,请先执行 merge_work_order_tables.sql 再 DROP
|
||||
DROP TABLE IF EXISTS biz_temp_qc_work_order;
|
||||
DROP TABLE IF EXISTS biz_temp_production_work_order;
|
||||
+964
-150
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,729 @@
|
||||
# 细胞产品库 — 来源链路展示 实施计划
|
||||
|
||||
> **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:** 后端在现有列表 API 中批量富化来源字段,新增 `/cell-products/{id}/chain` 链路 API。前端列表新增 4 列 + 1 个筛选,查看弹窗新增 `SourceChainGraph.vue` 组件(CSS 绘制横向 DAG)。
|
||||
|
||||
**Tech Stack:** FastAPI + SQLAlchemy + Pydantic v2(后端),Vue 3 + Element Plus + SCSS(前端)
|
||||
|
||||
**Design Spec:** `docs/superpowers/specs/2026-05-24-cell-product-source-chain-design.md`
|
||||
**Demo:** `docs/demo-source-chain-graph.html`
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
| Action | File | Responsibility |
|
||||
|--------|------|----------------|
|
||||
| Modify | `backend/app/crud/cell_product.py` | 来源富化查询 + 链路递归函数 |
|
||||
| Modify | `backend/app/schemas/cell_product.py` | CellProductListQuery 新增 source_type |
|
||||
| Modify | `backend/app/api/production.py` | 列表路由传 source_type + 新增 chain 路由 |
|
||||
| Modify | `web-admin/src/api/cell-product.ts` | 新增 fetchCellProductChain + list 参数扩展 |
|
||||
| Modify | `web-admin/src/views/production/cell-product/index.vue` | 列表新增列/筛选 + 查看弹窗集成链路图 |
|
||||
| Create | `web-admin/src/views/production/cell-product/SourceChainGraph.vue` | 链路图组件 |
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 后端 — Schema 新增 source_type 筛选参数
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/schemas/cell_product.py:127-137`
|
||||
|
||||
- [ ] **Step 1: 在 CellProductListQuery 中新增 source_type 字段**
|
||||
|
||||
在 `backend/app/schemas/cell_product.py` 的 `CellProductListQuery` 类末尾追加:
|
||||
|
||||
```python
|
||||
source_type: Optional[str] = Field(None, alias="sourceType")
|
||||
```
|
||||
|
||||
完整的 `CellProductListQuery` 应变为:
|
||||
|
||||
```python
|
||||
class CellProductListQuery(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
page: int = 1
|
||||
page_size: int = Field(20, alias="pageSize")
|
||||
keyword: Optional[str] = None
|
||||
product_code: Optional[str] = Field(None, alias="productCode")
|
||||
product_name: Optional[str] = Field(None, alias="productName")
|
||||
product_type_id: Optional[str] = Field(None, alias="productTypeId")
|
||||
product_status: Optional[str] = Field(None, alias="productStatus")
|
||||
passage: Optional[str] = None
|
||||
source_type: Optional[str] = Field(None, alias="sourceType")
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 验证无语法错误**
|
||||
|
||||
Run: `cd /Users/wuzilong/work/00code/zkxw/backend && source venv/bin/activate && python -c "from app.schemas.cell_product import CellProductListQuery; print('OK')"`
|
||||
Expected: `OK`
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 后端 — 列表 API 增加 source_type 筛选
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/api/production.py:1941-1966`
|
||||
- Modify: `backend/app/crud/cell_product.py:150-208`
|
||||
|
||||
- [ ] **Step 1: API 路由层新增 sourceType 参数**
|
||||
|
||||
在 `backend/app/api/production.py` 的 `list_cell_products` 函数中:
|
||||
1. 在参数列表 `passage` 之后新增:`sourceType: Optional[str] = None,`
|
||||
2. 在 `cell_product_svc.list_cell_products(...)` 调用中新增:`source_type=sourceType,`
|
||||
|
||||
修改后的函数签名和调用:
|
||||
|
||||
```python
|
||||
@router.get("/cell-products")
|
||||
async def list_cell_products(
|
||||
page: int = Query(1, ge=1),
|
||||
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
|
||||
keyword: Optional[str] = None,
|
||||
productCode: Optional[str] = None,
|
||||
productName: Optional[str] = None,
|
||||
productTypeId: Optional[str] = None,
|
||||
productStatus: Optional[str] = None,
|
||||
passage: Optional[str] = None,
|
||||
sourceType: Optional[str] = None,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
result = cell_product_svc.list_cell_products(
|
||||
db, tenant_no=tenant_no, page=page, page_size=pageSize,
|
||||
keyword=keyword,
|
||||
product_code=productCode, product_name=productName,
|
||||
product_type_id=productTypeId, product_status=productStatus,
|
||||
passage=passage, source_type=sourceType,
|
||||
user_info=user,
|
||||
)
|
||||
items = result.get("items", [])
|
||||
total = result.get("total", 0)
|
||||
tp = cell_product_svc.total_pages(total, pageSize)
|
||||
return success_response({"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp})
|
||||
```
|
||||
|
||||
- [ ] **Step 2: CRUD 层 list_cell_products 新增 source_type 过滤**
|
||||
|
||||
在 `backend/app/crud/cell_product.py` 的 `list_cell_products` 函数中:
|
||||
1. 在参数列表 `passage` 之后新增:`source_type: Optional[str] = None,`
|
||||
2. 在 `_filtered()` 内部、`if passage:` 块之后新增:
|
||||
|
||||
```python
|
||||
if source_type:
|
||||
q0 = q0.filter(BizCellProduct.source_type == source_type)
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 验证无语法错误**
|
||||
|
||||
Run: `cd /Users/wuzilong/work/00code/zkxw/backend && source venv/bin/activate && python -c "from app.crud.cell_product import list_cell_products; print('OK')"`
|
||||
Expected: `OK`
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 后端 — 列表富化查询新增来源字段
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/crud/cell_product.py:72-142`(`_enrich_product_dicts` 函数)
|
||||
|
||||
- [ ] **Step 1: 在 `_enrich_product_dicts` 中新增来源信息批量富化**
|
||||
|
||||
在 `_enrich_product_dicts` 函数中,在 `slot_map` 查询之后、`for item in items:` 循环之前,新增以下代码块:
|
||||
|
||||
```python
|
||||
# --- 来源信息富化 ---
|
||||
from app.models.models import BizProductionTask, BizProductionWorkOrder
|
||||
|
||||
task_ids = {i.get("productionTaskId") for i in items if i.get("productionTaskId")}
|
||||
task_map: Dict[str, Any] = {}
|
||||
task_to_wo: Dict[str, str] = {}
|
||||
wo_map: Dict[str, Any] = {}
|
||||
|
||||
if task_ids:
|
||||
tasks = (
|
||||
db.query(BizProductionTask)
|
||||
.filter(
|
||||
BizProductionTask.id.in_(task_ids),
|
||||
BizProductionTask.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
for t in tasks:
|
||||
task_map[t.id] = t
|
||||
if t.work_order_id:
|
||||
task_to_wo[t.id] = t.work_order_id
|
||||
|
||||
wo_ids = set(task_to_wo.values())
|
||||
if wo_ids:
|
||||
wos = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(
|
||||
BizProductionWorkOrder.id.in_(wo_ids),
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
wo_map = {w.id: w for w in wos}
|
||||
|
||||
source_type_labels = {"production": "生产入库", "manual": "手动录入"}
|
||||
```
|
||||
|
||||
然后在 `for item in items:` 循环内,在 `item["storageSlotName"] = ...` 之后追加:
|
||||
|
||||
```python
|
||||
# 来源信息
|
||||
src_type = item.get("sourceType", "")
|
||||
item["sourceTypeLabel"] = source_type_labels.get(src_type, src_type or "")
|
||||
tid = item.get("productionTaskId") or ""
|
||||
if tid and tid in task_map:
|
||||
t_obj = task_map[tid]
|
||||
item["sourceTaskNo"] = t_obj.task_no or ""
|
||||
wo_id = task_to_wo.get(tid)
|
||||
if wo_id and wo_id in wo_map:
|
||||
wo_obj = wo_map[wo_id]
|
||||
item["sourceWorkOrderNo"] = wo_obj.work_order_no or ""
|
||||
item["sourceProtocolNo"] = wo_obj.protocol_no or ""
|
||||
item["sourceReceptionSource"] = wo_obj.reception_source or ""
|
||||
else:
|
||||
item["sourceWorkOrderNo"] = ""
|
||||
item["sourceProtocolNo"] = ""
|
||||
item["sourceReceptionSource"] = ""
|
||||
else:
|
||||
item["sourceTaskNo"] = ""
|
||||
item["sourceWorkOrderNo"] = ""
|
||||
item["sourceProtocolNo"] = ""
|
||||
item["sourceReceptionSource"] = ""
|
||||
```
|
||||
|
||||
注意:需要确保 `_row_to_dict` 不需要修改 — 它已经返回 `sourceType` 和 `productionTaskId`,新的富化字段是在 `_enrich_product_dicts` 中动态追加的。
|
||||
|
||||
- [ ] **Step 2: 验证无语法错误**
|
||||
|
||||
Run: `cd /Users/wuzilong/work/00code/zkxw/backend && source venv/bin/activate && python -c "from app.crud.cell_product import _enrich_product_dicts; print('OK')"`
|
||||
Expected: `OK`
|
||||
|
||||
- [ ] **Step 3: 启动后端验证列表 API**
|
||||
|
||||
Run: `cd /Users/wuzilong/work/00code/zkxw/backend && source venv/bin/activate && python -c "
|
||||
from app.core.database import SessionLocal
|
||||
from app.crud.cell_product import list_cell_products
|
||||
db = SessionLocal()
|
||||
try:
|
||||
result = list_cell_products(db, tenant_no='zkxw', page=1, page_size=3)
|
||||
for item in result.get('items', []):
|
||||
print(f\"{item.get('productCode')} | src={item.get('sourceTypeLabel')} | proto={item.get('sourceProtocolNo')} | wo={item.get('sourceWorkOrderNo')} | task={item.get('sourceTaskNo')}\")
|
||||
finally:
|
||||
db.close()
|
||||
"`
|
||||
Expected: 每行输出产品编码及来源字段(可能为空字符串)
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 后端 — 新增链路 API
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/crud/cell_product.py`(文件末尾追加)
|
||||
- Modify: `backend/app/api/production.py`(在 `GET /cell-products/{product_id}` 路由之后追加)
|
||||
|
||||
- [ ] **Step 1: 在 `cell_product.py` 末尾新增链路递归查询函数**
|
||||
|
||||
在 `backend/app/crud/cell_product.py` 文件末尾追加:
|
||||
|
||||
```python
|
||||
# ---------------------------------------------------------------------------
|
||||
# 来源链路 API
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_MAX_CHAIN_DEPTH = 10
|
||||
|
||||
_SOURCE_TYPE_LABELS = {"production": "生产入库", "manual": "手动录入"}
|
||||
|
||||
|
||||
def _product_node(obj: BizCellProduct, is_current: bool = False) -> Dict[str, Any]:
|
||||
return {
|
||||
"id": obj.id,
|
||||
"productCode": obj.product_code or "",
|
||||
"productName": obj.product_name or "",
|
||||
"nodeType": "cell_product",
|
||||
"productStatus": obj.product_status or "",
|
||||
"passage": obj.passage or "",
|
||||
"isCurrent": is_current,
|
||||
}
|
||||
|
||||
|
||||
def _build_ancestor_chain(
|
||||
db: Session, product: BizCellProduct, depth: int
|
||||
) -> List[Dict[str, Any]]:
|
||||
if depth >= _MAX_CHAIN_DEPTH:
|
||||
return []
|
||||
task_id = product.production_task_id
|
||||
if not task_id:
|
||||
return []
|
||||
|
||||
from app.models.models import BizProductionTask, BizProductionWorkOrder
|
||||
from app.models.models import BizProductionTaskInput
|
||||
|
||||
task = (
|
||||
db.query(BizProductionTask)
|
||||
.filter(BizProductionTask.id == task_id, BizProductionTask.del_flag == 0)
|
||||
.first()
|
||||
)
|
||||
if not task:
|
||||
return []
|
||||
|
||||
wo = None
|
||||
edge: Dict[str, Any] = {"workOrderNo": "", "workOrderType": "", "taskNo": task.task_no or "", "taskName": task.task_name or ""}
|
||||
if task.work_order_id:
|
||||
wo = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(BizProductionWorkOrder.id == task.work_order_id, BizProductionWorkOrder.del_flag == 0)
|
||||
.first()
|
||||
)
|
||||
if wo:
|
||||
edge["workOrderNo"] = wo.work_order_no or ""
|
||||
edge["workOrderType"] = wo.reception_source or ""
|
||||
|
||||
# 检查投入物中是否有父细胞产品
|
||||
parent_input = (
|
||||
db.query(BizProductionTaskInput)
|
||||
.filter(
|
||||
BizProductionTaskInput.task_id == task_id,
|
||||
BizProductionTaskInput.input_type == "cell_product",
|
||||
BizProductionTaskInput.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if parent_input and parent_input.input_id:
|
||||
parent_product = (
|
||||
db.query(BizCellProduct)
|
||||
.filter(BizCellProduct.id == parent_input.input_id, BizCellProduct.del_flag == 0)
|
||||
.first()
|
||||
)
|
||||
if parent_product:
|
||||
return [{"node": _product_node(parent_product), "edge": edge, "parent": _build_ancestor_chain(db, parent_product, depth + 1)}]
|
||||
|
||||
# 检查投入物中是否有样本(终止节点)
|
||||
sample_input = (
|
||||
db.query(BizProductionTaskInput)
|
||||
.filter(
|
||||
BizProductionTaskInput.task_id == task_id,
|
||||
BizProductionTaskInput.input_type == "sample",
|
||||
BizProductionTaskInput.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if sample_input and sample_input.input_id:
|
||||
from app.models.models import BizProtocolSample
|
||||
sample = (
|
||||
db.query(BizProtocolSample)
|
||||
.filter(BizProtocolSample.id == sample_input.input_id, BizProtocolSample.del_flag == 0)
|
||||
.first()
|
||||
)
|
||||
if sample:
|
||||
sample_node = {
|
||||
"id": sample.id,
|
||||
"productCode": sample.sample_code or "",
|
||||
"productName": "",
|
||||
"nodeType": "sample",
|
||||
"sampleCode": sample.sample_code or "",
|
||||
"sampleType": sample.sample_type or "",
|
||||
"isCurrent": False,
|
||||
}
|
||||
return [{"node": sample_node, "edge": edge, "parent": None}]
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def _build_descendant_chain(
|
||||
db: Session, product_id: str, depth: int
|
||||
) -> List[Dict[str, Any]]:
|
||||
if depth >= _MAX_CHAIN_DEPTH:
|
||||
return []
|
||||
|
||||
from app.models.models import BizProductionTaskInput, BizProductionTaskOutput, BizProductionTask, BizProductionWorkOrder
|
||||
|
||||
# 找到引用此产品作为投入物的所有任务
|
||||
input_rows = (
|
||||
db.query(BizProductionTaskInput)
|
||||
.filter(
|
||||
BizProductionTaskInput.input_type == "cell_product",
|
||||
BizProductionTaskInput.input_id == product_id,
|
||||
BizProductionTaskInput.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
if not input_rows:
|
||||
return []
|
||||
|
||||
task_ids = list({r.task_id for r in input_rows})
|
||||
tasks = (
|
||||
db.query(BizProductionTask)
|
||||
.filter(BizProductionTask.id.in_(task_ids), BizProductionTask.del_flag == 0)
|
||||
.all()
|
||||
)
|
||||
task_by_id = {t.id: t for t in tasks}
|
||||
|
||||
wo_ids = list({t.work_order_id for t in tasks if t.work_order_id})
|
||||
wo_by_id: Dict[str, Any] = {}
|
||||
if wo_ids:
|
||||
wos = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(BizProductionWorkOrder.id.in_(wo_ids), BizProductionWorkOrder.del_flag == 0)
|
||||
.all()
|
||||
)
|
||||
wo_by_id = {w.id: w for w in wos}
|
||||
|
||||
# 对每个任务,找产出
|
||||
result: List[Dict[str, Any]] = []
|
||||
output_rows = (
|
||||
db.query(BizProductionTaskOutput)
|
||||
.filter(
|
||||
BizProductionTaskOutput.task_id.in_(task_ids),
|
||||
BizProductionTaskOutput.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
child_product_ids = list({o.cell_product_id for o in output_rows if o.cell_product_id})
|
||||
child_products = {}
|
||||
if child_product_ids:
|
||||
cps = (
|
||||
db.query(BizCellProduct)
|
||||
.filter(BizCellProduct.id.in_(child_product_ids), BizCellProduct.del_flag == 0)
|
||||
.all()
|
||||
)
|
||||
child_products = {cp.id: cp for cp in cps}
|
||||
|
||||
for o in output_rows:
|
||||
cp = child_products.get(o.cell_product_id)
|
||||
if not cp:
|
||||
continue
|
||||
t = task_by_id.get(o.task_id)
|
||||
edge: Dict[str, Any] = {"workOrderNo": "", "workOrderType": "", "taskNo": "", "taskName": ""}
|
||||
if t:
|
||||
edge["taskNo"] = t.task_no or ""
|
||||
edge["taskName"] = t.task_name or ""
|
||||
if t.work_order_id and t.work_order_id in wo_by_id:
|
||||
wo_obj = wo_by_id[t.work_order_id]
|
||||
edge["workOrderNo"] = wo_obj.work_order_no or ""
|
||||
edge["workOrderType"] = wo_obj.reception_source or ""
|
||||
|
||||
result.append({
|
||||
"node": _product_node(cp),
|
||||
"edge": edge,
|
||||
"children": _build_descendant_chain(db, cp.id, depth + 1),
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_product_chain(db: Session, product_id: str, tenant_no: str) -> Optional[Dict[str, Any]]:
|
||||
product = get_cell_product(db, product_id, tenant_no)
|
||||
if not product:
|
||||
return None
|
||||
|
||||
return {
|
||||
"current": _product_node(product, is_current=True),
|
||||
"ancestors": _build_ancestor_chain(db, product, 0),
|
||||
"descendants": _build_descendant_chain(db, product.id, 0),
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 在 production.py 新增链路路由**
|
||||
|
||||
在 `backend/app/api/production.py` 的 `@router.get("/cell-products/{product_id}")` 路由之后(约 line 1979 之后)追加新路由:
|
||||
|
||||
```python
|
||||
@router.get("/cell-products/{product_id}/chain")
|
||||
async def get_cell_product_chain(
|
||||
product_id: str,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
chain = cell_product_svc.get_product_chain(db, product_id, tenant_no)
|
||||
if not chain:
|
||||
raise HTTPException(status_code=404, detail="细胞产品不存在")
|
||||
return success_response(chain)
|
||||
```
|
||||
|
||||
注意:此路由必须放在 `@router.get("/cell-products/{product_id}")` 之前或之后都可以,因为 FastAPI 按注册顺序匹配,`/cell-products/next-code` 已经在前面。但 `/chain` 是固定路径不会与 `{product_id}` 冲突 — 实际上 `/cell-products/{product_id}/chain` 和 `/cell-products/{product_id}` 是不同的路径模式,不存在冲突。
|
||||
|
||||
- [ ] **Step 3: 验证链路 API**
|
||||
|
||||
Run: `cd /Users/wuzilong/work/00code/zkxw/backend && source venv/bin/activate && python -c "
|
||||
from app.core.database import SessionLocal
|
||||
from app.crud.cell_product import get_product_chain
|
||||
db = SessionLocal()
|
||||
try:
|
||||
from app.crud.cell_product import list_cell_products
|
||||
prods = list_cell_products(db, tenant_no='zkxw', page=1, page_size=1)
|
||||
items = prods.get('items', [])
|
||||
if items:
|
||||
pid = items[0]['id']
|
||||
chain = get_product_chain(db, pid, 'zkxw')
|
||||
if chain:
|
||||
cur = chain['current']
|
||||
print(f'Current: {cur[\"productCode\"]}')
|
||||
print(f'Ancestors: {len(chain[\"ancestors\"])} levels')
|
||||
print(f'Descendants: {len(chain[\"descendants\"])} branches')
|
||||
else:
|
||||
print('No chain data')
|
||||
else:
|
||||
print('No products found')
|
||||
finally:
|
||||
db.close()
|
||||
"`
|
||||
Expected: 输出当前产品的链路信息(祖先层数和子代分支数)
|
||||
|
||||
---
|
||||
|
||||
### Task 5: 前端 — API 层扩展
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/api/cell-product.ts`
|
||||
|
||||
- [ ] **Step 1: 新增 fetchCellProductChain 函数 + fetchCellProductList 参数扩展**
|
||||
|
||||
将 `web-admin/src/api/cell-product.ts` 完整替换为:
|
||||
|
||||
```typescript
|
||||
import request from '@/utils/http'
|
||||
|
||||
export function fetchCellProductList(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
productStatus?: string
|
||||
passage?: string
|
||||
sourceType?: string
|
||||
}) {
|
||||
return request.get<{
|
||||
list: any[]
|
||||
total: number
|
||||
page: number
|
||||
pageSize: number
|
||||
totalPages: number
|
||||
}>({ url: '/web/admin/cell-products', params })
|
||||
}
|
||||
|
||||
export function fetchCellProductDetail(id: string) {
|
||||
return request.get<any>({ url: `/web/admin/cell-products/${id}` })
|
||||
}
|
||||
|
||||
export function fetchCreateCellProduct(data: Record<string, any>) {
|
||||
return request.post({ url: '/web/admin/cell-products', params: data })
|
||||
}
|
||||
|
||||
export function fetchUpdateCellProduct(id: string, data: Record<string, any>) {
|
||||
return request.put({ url: `/web/admin/cell-products/${id}`, params: data })
|
||||
}
|
||||
|
||||
export function fetchDeleteCellProduct(id: string) {
|
||||
return request.del({ url: `/web/admin/cell-products/${id}` })
|
||||
}
|
||||
|
||||
export function fetchNextCellProductCode(count = 1) {
|
||||
return request.get<{ code: string; codes?: string[] }>({
|
||||
url: '/web/admin/cell-products/next-code',
|
||||
params: count > 1 ? { count } : undefined
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchCellProductChain(productId: string) {
|
||||
return request.get<any>({ url: `/web/admin/cell-products/${productId}/chain` })
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 验证无 TS 错误**
|
||||
|
||||
Run: `cd /Users/wuzilong/work/00code/zkxw/web-admin && npx vue-tsc --noEmit --pretty 2>&1 | head -20`
|
||||
Expected: 无新增错误(可能有预存的)
|
||||
|
||||
---
|
||||
|
||||
### Task 6: 前端 — 列表页新增列和筛选
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/views/production/cell-product/index.vue`
|
||||
|
||||
- [ ] **Step 1: 搜索表单新增来源类型筛选**
|
||||
|
||||
在 `index.vue` 的搜索表单中找到 `productStatus` 的 `el-select` 之后,新增一个筛选下拉:
|
||||
|
||||
```html
|
||||
<el-select v-model="searchForm.sourceType" placeholder="来源类型" clearable style="width: 130px">
|
||||
<el-option label="生产入库" value="production" />
|
||||
<el-option label="手动录入" value="manual" />
|
||||
</el-select>
|
||||
```
|
||||
|
||||
同时在 `searchForm` 的响应式定义中增加 `sourceType: ''` 字段。
|
||||
|
||||
在调用 `fetchCellProductList` 时传入 `sourceType: searchForm.sourceType || undefined`。
|
||||
|
||||
- [ ] **Step 2: 表格新增 4 列**
|
||||
|
||||
在 `el-table` 中 `productStatus`(状态)列之后,新增:
|
||||
|
||||
```html
|
||||
<el-table-column label="来源类型" prop="sourceTypeLabel" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.sourceTypeLabel" :type="row.sourceType === 'production' ? 'success' : 'info'" size="small">
|
||||
{{ row.sourceTypeLabel }}
|
||||
</el-tag>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来源协议号" prop="sourceProtocolNo" min-width="160" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.sourceProtocolNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来源工单号" prop="sourceWorkOrderNo" min-width="140" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.sourceWorkOrderNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来源任务号" prop="sourceTaskNo" min-width="140" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.sourceTaskNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 验证列表页渲染**
|
||||
|
||||
Run: `cd /Users/wuzilong/work/00code/zkxw/web-admin && pnpm dev`
|
||||
|
||||
浏览器访问 `http://localhost:3006/#/production/cell-product`,确认:
|
||||
1. 列表新增 4 列可见
|
||||
2. 搜索栏有「来源类型」下拉
|
||||
3. 选择「生产入库」筛选后列表正确过滤
|
||||
|
||||
---
|
||||
|
||||
### Task 7: 前端 — 新增 SourceChainGraph 链路图组件
|
||||
|
||||
**Files:**
|
||||
- Create: `web-admin/src/views/production/cell-product/SourceChainGraph.vue`
|
||||
|
||||
- [ ] **Step 1: 创建链路图组件**
|
||||
|
||||
新建 `web-admin/src/views/production/cell-product/SourceChainGraph.vue`,实现以下功能:
|
||||
- 接收 `productId` 和 `visible` props
|
||||
- `visible` 变为 true 时调用 `fetchCellProductChain(productId)` 获取链路数据
|
||||
- 渲染横向 DAG:祖先节点 → 当前节点 → 子代节点
|
||||
- 节点卡片样式区分:样本(浅蓝)、细胞产品(浅绿)、当前产品(深绿边框 + 角标)
|
||||
- 节点之间用 CSS border + 伪元素画水平连线和箭头
|
||||
- 连线上方显示工单号和任务号标签
|
||||
- 1对多分支使用竖线 + 横线分叉
|
||||
- 手动录入产品(起源节点)无祖先但可能有子代,只有**既无祖先又无子代的孤立产品**才显示空状态文字「该产品暂无来源及衍生链路信息」
|
||||
- 节点 hover 时用 `el-popover` 显示详情
|
||||
|
||||
组件核心模板结构:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="source-chain-graph" v-loading="loading">
|
||||
<div v-if="chainData" class="chain-container">
|
||||
<div class="chain-section-title">来源链路</div>
|
||||
|
||||
<template v-if="chainData.ancestors.length || chainData.descendants.length">
|
||||
<div class="chain-row">
|
||||
<template v-for="(ancestor, idx) in flattenedAncestors" :key="'a-' + idx">
|
||||
<ChainNodeCard :node="ancestor.node" />
|
||||
<ChainConnector :edge="ancestor.edge" />
|
||||
</template>
|
||||
|
||||
<ChainNodeCard :node="chainData.current" :is-current="true" />
|
||||
|
||||
<template v-if="chainData.descendants.length">
|
||||
<ForkBranch :items="chainData.descendants" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-else class="empty-state">该产品暂无来源及衍生链路信息</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
注意:实际实现中 `ChainNodeCard`、`ChainConnector`、`ForkBranch` 可以是同文件内的子组件或直接内联模板。核心样式参考 `docs/demo-source-chain-graph.html`。
|
||||
|
||||
- [ ] **Step 2: 验证组件无 TS 错误**
|
||||
|
||||
Run: `cd /Users/wuzilong/work/00code/zkxw/web-admin && npx vue-tsc --noEmit --pretty 2>&1 | head -20`
|
||||
Expected: 无新增错误
|
||||
|
||||
---
|
||||
|
||||
### Task 8: 前端 — 查看弹窗集成链路图
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/views/production/cell-product/index.vue`
|
||||
|
||||
- [ ] **Step 1: 在查看弹窗中集成 SourceChainGraph**
|
||||
|
||||
在 `index.vue` 中:
|
||||
|
||||
1. 导入组件:
|
||||
```typescript
|
||||
import SourceChainGraph from './SourceChainGraph.vue'
|
||||
```
|
||||
|
||||
2. 在 `SystemViewDialog` 的 sections 配置中新增第三个 section(在产品图片 section 之后):
|
||||
```typescript
|
||||
{
|
||||
label: '来源链路',
|
||||
slot: 'sourceChain',
|
||||
}
|
||||
```
|
||||
|
||||
3. 在 `SystemViewDialog` 的模板中新增 slot:
|
||||
```html
|
||||
<template #sourceChain>
|
||||
<SourceChainGraph :product-id="currentRow?.id" :visible="viewDialogVisible" />
|
||||
</template>
|
||||
```
|
||||
|
||||
注意:需要确认 `SystemViewDialog` 组件是否支持 `slot` 类型的 section。如果不支持,需要查看该组件源码并添加 slot 支持(通常是在 section 渲染时判断 `slot` 字段,用 `<slot :name="section.slot" />` 渲染自定义内容)。
|
||||
|
||||
- [ ] **Step 2: 端到端验证**
|
||||
|
||||
1. 启动后端:`cd backend && source venv/bin/activate && ./start-local.sh`
|
||||
2. 启动前端:`cd web-admin && pnpm dev`
|
||||
3. 浏览器访问 `http://localhost:3006/#/production/cell-product`
|
||||
4. 点击任意产品的「查看」按钮
|
||||
5. 确认查看弹窗中有「来源链路」tab/section
|
||||
6. 确认链路图正确展示节点和连线
|
||||
7. 确认节点点击可显示详情 Popover
|
||||
8. 确认手动录入产品显示空状态
|
||||
|
||||
---
|
||||
|
||||
### Task 9: 提交
|
||||
|
||||
- [ ] **Step 1: 检查变更范围**
|
||||
|
||||
Run: `cd /Users/wuzilong/work/00code/zkxw && git status`
|
||||
Expected: 仅涉及以下文件:
|
||||
- `backend/app/crud/cell_product.py`
|
||||
- `backend/app/schemas/cell_product.py`
|
||||
- `backend/app/api/production.py`
|
||||
- `web-admin/src/api/cell-product.ts`
|
||||
- `web-admin/src/views/production/cell-product/index.vue`
|
||||
- `web-admin/src/views/production/cell-product/SourceChainGraph.vue`(新建)
|
||||
- `docs/demo-source-chain-graph.html`
|
||||
- `docs/superpowers/specs/2026-05-24-cell-product-source-chain-design.md`
|
||||
- `docs/superpowers/plans/2026-05-24-cell-product-source-chain.md`
|
||||
|
||||
- [ ] **Step 2: 提交**
|
||||
|
||||
```bash
|
||||
git add backend/app/crud/cell_product.py backend/app/schemas/cell_product.py backend/app/api/production.py web-admin/src/api/cell-product.ts web-admin/src/views/production/cell-product/ docs/
|
||||
git commit -m "feat(cell-product): 添加细胞产品来源链路展示功能
|
||||
|
||||
列表新增来源类型、来源协议号、来源工单号、来源任务号四列,
|
||||
支持来源类型筛选。查看弹窗新增来源链路图,展示祖先-当前-子代
|
||||
双向追溯链路(横向 DAG,CSS 绘制连线),支持1对多分叉。"
|
||||
```
|
||||
@@ -0,0 +1,305 @@
|
||||
# 工单表合并重构实施计划
|
||||
|
||||
> **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:** 将入库+临时工单表合并为单表(`work_order_type` 字段区分类型),彻底消除多表 JOIN 复杂度。
|
||||
|
||||
**Architecture:** 质检工单合并为 `biz_qc_work_order`(加 `work_order_type`),生产工单合并为 `biz_production_work_order`(加 `work_order_type`)。任务表保持不变(`biz_qc_task` / `biz_production_task` 的 `order_source` 保留)。前端每个工单类型一个页面,根据 `work_order_type` 条件展示不同字段。
|
||||
|
||||
**Tech Stack:** MySQL 5.7 DDL / Python 3.9 FastAPI SQLAlchemy / Vue 3 TypeScript Element Plus
|
||||
|
||||
---
|
||||
|
||||
## 影响文件清单
|
||||
|
||||
### 删除(合并后不再需要)
|
||||
- `backend/app/models/models.py` 中 `BizTempQcWorkOrder`、`BizTempProductionWorkOrder` 两个 class
|
||||
- `backend/app/schemas/temp_qc_work_order.py`
|
||||
- `backend/app/schemas/temp_production_work_order.py`
|
||||
- `backend/app/crud/temp_qc_work_order.py`
|
||||
- `backend/app/crud/temp_production_work_order.py`
|
||||
- `web-admin/src/api/temp-qc-work-order.ts`
|
||||
- `web-admin/src/api/temp-production-work-order.ts`
|
||||
- `web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue`
|
||||
- `web-admin/src/views/production/temp-production-work-order/index.vue`
|
||||
- `web-admin/src/router/modules/sqxp.ts` 中临时工单路由条目
|
||||
|
||||
### 修改
|
||||
- `docs/sql/` — 新建迁移 SQL
|
||||
- `backend/app/models/models.py` — 加 `work_order_type`,reception 字段改 nullable,删 temp model
|
||||
- `backend/app/crud/qc_work_order.py` — 合并临时工单的创建/配置/完成逻辑
|
||||
- `backend/app/crud/production_work_order.py` — 合并临时工单的创建/配置/完成逻辑
|
||||
- `backend/app/crud/qc_task.py` — **恢复** INNER JOIN(不再需要 LEFT JOIN + 子查询 hack)
|
||||
- `backend/app/crud/production_task.py` — 同上,简化批量查询
|
||||
- `backend/app/api/qc.py` — 合并临时工单 API 端点,删除 temp import
|
||||
- `backend/app/api/production.py` — 同上
|
||||
- `backend/app/schemas/qc_work_order.py` — 新增 `work_order_type` 字段
|
||||
- `web-admin/src/api/qc-work-order.ts` 或 `business.ts` — 新增临时工单 API
|
||||
- `web-admin/src/views/quality-inspection/qc-work-order/index.vue` — 支持临时工单创建/筛选
|
||||
- `web-admin/src/views/production/production-work-order/index.vue` — 同上
|
||||
|
||||
---
|
||||
|
||||
## Task 1: DDL 迁移 SQL
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/sql/merge_work_order_tables.sql`
|
||||
|
||||
- [ ] **Step 1: 编写迁移 SQL**
|
||||
|
||||
```sql
|
||||
-- ============================================================
|
||||
-- 工单表合并迁移:入库+临时 → 单表 + work_order_type
|
||||
-- Date: 2026-05-24
|
||||
-- 执行顺序:必须先执行,再部署后端代码
|
||||
-- ============================================================
|
||||
|
||||
-- 1. biz_qc_work_order: 加 work_order_type,现有数据全部设 inbound
|
||||
ALTER TABLE biz_qc_work_order
|
||||
ADD COLUMN work_order_type VARCHAR(20) NOT NULL DEFAULT 'inbound'
|
||||
COMMENT '工单类型: inbound=入库, temporary=临时' AFTER work_order_no;
|
||||
|
||||
-- 2. biz_qc_work_order: reception 关联字段改为可空(临时工单不需要)
|
||||
ALTER TABLE biz_qc_work_order
|
||||
MODIFY COLUMN reception_id VARCHAR(64) NULL COMMENT '样本接收ID',
|
||||
MODIFY COLUMN protocol_sample_id VARCHAR(64) NULL COMMENT '协议样本ID',
|
||||
MODIFY COLUMN collection_protocol_id VARCHAR(64) NULL COMMENT '采集协议ID',
|
||||
MODIFY COLUMN reception_source VARCHAR(20) NULL DEFAULT 'cell_storage' COMMENT '来源: cell_storage/research_donation';
|
||||
|
||||
-- 3. 迁移临时质检工单数据到主表
|
||||
INSERT INTO biz_qc_work_order (
|
||||
id, work_order_no, work_order_type, work_order_status,
|
||||
has_lab, has_third_party, third_party_fee_total,
|
||||
configured_time, configured_by,
|
||||
tenant_no, order_num, remark,
|
||||
create_by, create_dept_id, create_time, update_by, update_time, del_flag
|
||||
)
|
||||
SELECT
|
||||
id, work_order_no, 'temporary', work_order_status,
|
||||
has_lab, has_third_party, third_party_fee_total,
|
||||
configured_time, configured_by,
|
||||
tenant_no, order_num, remark,
|
||||
create_by, create_dept_id, create_time, update_by, update_time, del_flag
|
||||
FROM biz_temp_qc_work_order;
|
||||
|
||||
-- 4. biz_production_work_order: 加 work_order_type
|
||||
ALTER TABLE biz_production_work_order
|
||||
ADD COLUMN work_order_type VARCHAR(20) NOT NULL DEFAULT 'inbound'
|
||||
COMMENT '工单类型: inbound=入库, temporary=临时' AFTER work_order_no;
|
||||
|
||||
-- 5. biz_production_work_order: 加 configured_time/configured_by(临时工单需要)
|
||||
ALTER TABLE biz_production_work_order
|
||||
ADD COLUMN configured_time DATETIME NULL COMMENT '配置时间' AFTER work_order_status,
|
||||
ADD COLUMN configured_by VARCHAR(64) NULL COMMENT '配置人' AFTER configured_time;
|
||||
|
||||
-- 6. biz_production_work_order: reception 关联字段改为可空
|
||||
ALTER TABLE biz_production_work_order
|
||||
MODIFY COLUMN reception_id VARCHAR(64) NULL COMMENT '样本接收ID',
|
||||
MODIFY COLUMN protocol_sample_id VARCHAR(64) NULL COMMENT '协议样本ID',
|
||||
MODIFY COLUMN collection_protocol_id VARCHAR(64) NULL COMMENT '采集协议ID',
|
||||
MODIFY COLUMN reception_source VARCHAR(20) NULL DEFAULT 'cell_storage' COMMENT '来源';
|
||||
|
||||
-- 7. 迁移临时生产工单数据到主表
|
||||
INSERT INTO biz_production_work_order (
|
||||
id, work_order_no, work_order_type, work_order_status,
|
||||
configured_time, configured_by,
|
||||
tenant_no, order_num, remark,
|
||||
create_by, create_dept_id, create_time, update_by, update_time, del_flag
|
||||
)
|
||||
SELECT
|
||||
id, work_order_no, 'temporary', work_order_status,
|
||||
configured_time, configured_by,
|
||||
tenant_no, order_num, remark,
|
||||
create_by, create_dept_id, create_time, update_by, update_time, del_flag
|
||||
FROM biz_temp_production_work_order;
|
||||
|
||||
-- 8. 删除临时表(确认数据迁移成功后执行)
|
||||
DROP TABLE IF EXISTS biz_temp_qc_work_order;
|
||||
DROP TABLE IF EXISTS biz_temp_production_work_order;
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 手动执行前备份**
|
||||
```bash
|
||||
mysqldump -u root -p zkxw biz_qc_work_order biz_temp_qc_work_order biz_production_work_order biz_temp_production_work_order > /tmp/work_order_backup_$(date +%Y%m%d).sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: 后端 Model 更新
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/models/models.py`
|
||||
|
||||
- [ ] **Step 1: 更新 BizQcWorkOrder 模型**
|
||||
- 在 `work_order_no` 后加 `work_order_type = Column(String(20), nullable=False, default="inbound")`
|
||||
- 将 `reception_id`、`protocol_sample_id`、`collection_protocol_id` 改为 `nullable=True`
|
||||
- 将 `reception_source` 改为 `nullable=True`
|
||||
|
||||
- [ ] **Step 2: 更新 BizProductionWorkOrder 模型**
|
||||
- 加 `work_order_type = Column(String(20), nullable=False, default="inbound")`
|
||||
- 加 `configured_time = Column(DateTime, nullable=True)`
|
||||
- 加 `configured_by = Column(String(64), nullable=True)`
|
||||
- 将 `reception_id`、`protocol_sample_id`、`collection_protocol_id` 改为 `nullable=True`
|
||||
- 将 `reception_source` 改为 `nullable=True`
|
||||
|
||||
- [ ] **Step 3: 删除 BizTempQcWorkOrder 和 BizTempProductionWorkOrder 类**
|
||||
|
||||
- [ ] **Step 4: 验证 import**
|
||||
```bash
|
||||
cd backend && source venv/bin/activate && python -c "from app.main import app; print('OK')"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: 后端 CRUD 合并 — 质检工单
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/crud/qc_work_order.py`
|
||||
- Delete: `backend/app/crud/temp_qc_work_order.py`
|
||||
|
||||
- [ ] **Step 1: 在 qc_work_order.py 中新增临时工单函数**
|
||||
- 将 `temp_qc_work_order.py` 中的 `create_temp_qc_work_order`、`configure_temp_qc_work_order`、`list_temp_qc_work_orders`、`get_temp_qc_work_order_detail`、`try_complete_temp_qc_work_order`、`delete_temp_qc_work_order` 合并进 `qc_work_order.py`
|
||||
- 修改工单号生成逻辑:根据 `work_order_type` 选择前缀(inbound=ZJ,temporary=LSZJ)
|
||||
- 修改 list 查询:加 `work_order_type` 过滤
|
||||
- 修改 configure 逻辑:使用同一个 `BizQcWorkOrder` 模型
|
||||
- 修改 task 生成:保持 `order_source` 逻辑不变
|
||||
|
||||
- [ ] **Step 2: 删除 temp_qc_work_order.py**
|
||||
|
||||
---
|
||||
|
||||
## Task 4: 后端 CRUD 合并 — 生产工单
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/crud/production_work_order.py`
|
||||
- Delete: `backend/app/crud/temp_production_work_order.py`
|
||||
|
||||
- [ ] **Step 1: 合并临时生产工单函数**
|
||||
- 同 Task 3 思路:将 temp 函数合并进主文件
|
||||
- 工单号前缀:inbound=SC,temporary=LSSC
|
||||
- 保留工艺路线克隆逻辑
|
||||
- 保留 `order_source` 逻辑
|
||||
|
||||
- [ ] **Step 2: 删除 temp_production_work_order.py**
|
||||
|
||||
---
|
||||
|
||||
## Task 5: 后端 API + Schema 更新
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/api/qc.py`
|
||||
- Modify: `backend/app/api/production.py`
|
||||
- Modify: `backend/app/schemas/qc_work_order.py`
|
||||
- Delete: `backend/app/schemas/temp_qc_work_order.py`
|
||||
- Delete: `backend/app/schemas/temp_production_work_order.py`
|
||||
|
||||
- [ ] **Step 1: 更新 qc_work_order schema**
|
||||
- 在 `QcWorkOrderCreateBody` 中加 `work_order_type: str = "inbound"`
|
||||
- 新增 `TempQcWorkOrderCreateBody`(remark only)或复用现有 schema
|
||||
- 新增 `QcWorkOrderConfigureBody`(合并临时工单配置的 schema)
|
||||
|
||||
- [ ] **Step 2: 合并 qc.py API 端点**
|
||||
- 将临时质检工单的 5 个端点合并到现有工单端点
|
||||
- 新增 `POST /web/admin/qc-work-orders` 支持 `work_order_type` 参数
|
||||
- 新增 `GET /web/admin/qc-work-orders` 支持 `work_order_type` 过滤
|
||||
- 新增 `POST /web/admin/qc-work-orders/{id}/configure` 端点(从 temp 端点移过来)
|
||||
- 删除 temp 相关 import 和端点
|
||||
|
||||
- [ ] **Step 3: 合并 production.py API 端点**
|
||||
- 同上思路
|
||||
|
||||
- [ ] **Step 4: 删除 temp schema 文件**
|
||||
|
||||
- [ ] **Step 5: 验证 import**
|
||||
|
||||
---
|
||||
|
||||
## Task 6: 恢复 qc_task.py 的简单 INNER JOIN
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/crud/qc_task.py`
|
||||
|
||||
- [ ] **Step 1: 恢复 list_tasks 为 INNER JOIN**
|
||||
- 将 `outerjoin(BizQcWorkOrder, ...)` 恢复为 `join(BizQcWorkOrder, ...)`
|
||||
- 删除 `BizTempQcWorkOrder` import
|
||||
- 删除临时工单子查询(`temp_wo_sq`)
|
||||
- 删除临时工单后处理(`temp_wo_ids`、`temp_wo_map`、if/elif 分支)
|
||||
- 恢复原来的 ORDER BY 子句(含 `BizQcWorkOrder.work_order_no.desc()`)
|
||||
|
||||
- [ ] **Step 2: 验证**
|
||||
```bash
|
||||
cd backend && source venv/bin/activate && python -c "from app.crud.qc_task import list_tasks; print('OK')"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 7: 简化 production_task.py
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/crud/production_task.py`
|
||||
|
||||
- [ ] **Step 1: 简化 list_tasks 批量查询**
|
||||
- 删除 `BizTempProductionWorkOrder` import
|
||||
- 删除临时工单子查询和批量补充逻辑
|
||||
- 恢复为只查 `BizProductionWorkOrder` 的简单模式
|
||||
|
||||
---
|
||||
|
||||
## Task 8: 前端 API + 页面合并
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/api/qc-work-order.ts` 或 `business.ts`
|
||||
- Modify: `web-admin/src/api/production-work-order.ts` 或 `business.ts`
|
||||
- Modify: `web-admin/src/views/quality-inspection/qc-work-order/index.vue`
|
||||
- Modify: `web-admin/src/views/production/production-work-order/index.vue`
|
||||
- Delete: `web-admin/src/api/temp-qc-work-order.ts`
|
||||
- Delete: `web-admin/src/api/temp-production-work-order.ts`
|
||||
- Delete: `web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue`
|
||||
- Delete: `web-admin/src/views/production/temp-production-work-order/index.vue`
|
||||
- Modify: `web-admin/src/router/modules/sqxp.ts`
|
||||
|
||||
- [ ] **Step 1: 将临时工单 API 合并到主 API 模块**
|
||||
- 在 qc-work-order API 中新增 configure 端点调用
|
||||
- 新增 work_order_type 参数支持
|
||||
- 删除 temp API 文件
|
||||
|
||||
- [ ] **Step 2: 更新 qc-work-order/index.vue**
|
||||
- 新增"工单类型"筛选(入库/临时)
|
||||
- 新增创建时选择类型(入库走接收流程,临时直接创建)
|
||||
- 新增配置检测弹窗(从 temp 页面移植)
|
||||
- 条件显示 reception 相关列(仅入库类型显示样本编码、协议号等)
|
||||
|
||||
- [ ] **Step 3: 更新 production-work-order/index.vue**
|
||||
- 同上思路
|
||||
|
||||
- [ ] **Step 4: 更新路由 sqxp.ts**
|
||||
- 删除临时工单路由条目
|
||||
- 主工单路由保持不变
|
||||
|
||||
- [ ] **Step 5: 删除临时工单页面和 API 文件**
|
||||
|
||||
- [ ] **Step 6: 前端构建验证**
|
||||
```bash
|
||||
cd web-admin && pnpm build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 9: 全局验证
|
||||
|
||||
- [ ] **Step 1: 后端 import 验证**
|
||||
```bash
|
||||
cd backend && source venv/bin/activate && python -c "from app.main import app; print('OK')"
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 前端构建验证**
|
||||
```bash
|
||||
cd web-admin && pnpm build
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 手动测试流程**
|
||||
- 创建入库质检工单 → 配置 → 生成任务 ✓
|
||||
- 创建临时质检工单 → 配置 → 生成任务 ✓
|
||||
- 质检任务列表显示两种来源 ✓
|
||||
- 创建入库生产工单 → 配置 → 生成任务 ✓
|
||||
- 创建临时生产工单 → 配置 → 生成任务 ✓
|
||||
@@ -0,0 +1,911 @@
|
||||
# 临时工单模块实施计划
|
||||
|
||||
> **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:** 新建 2 张独立临时工单表(极简字段),现有任务表新增 `order_source` 字段区分入库/临时来源。后端 CRUD 独立,复用现有任务创建函数。前端新增 2 个标准列表页,现有任务列表新增"来源"Tag 列。
|
||||
|
||||
**Tech Stack:** Python 3.9 / FastAPI / SQLAlchemy / Pydantic v2 / MySQL 5.7 / Vue 3 / TypeScript / Element Plus / Tailwind CSS 4
|
||||
|
||||
**Design Spec:** `docs/superpowers/specs/2026-05-24-temporary-work-order-design.md`
|
||||
|
||||
---
|
||||
|
||||
## File Map
|
||||
|
||||
### 新建文件
|
||||
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `backend/app/crud/temp_qc_work_order.py` | 临时质检工单 CRUD(创建、列表、详情、配置检测项目→生成任务、删除) |
|
||||
| `backend/app/crud/temp_production_work_order.py` | 临时生产工单 CRUD(创建、列表、详情、配置→生成任务、删除) |
|
||||
| `backend/app/schemas/temp_qc_work_order.py` | 临时质检工单 Pydantic Schema |
|
||||
| `backend/app/schemas/temp_production_work_order.py` | 临时生产工单 Pydantic Schema |
|
||||
| `web-admin/src/api/temp-qc-work-order.ts` | 临时质检工单前端 API 类型+函数 |
|
||||
| `web-admin/src/api/temp-production-work-order.ts` | 临时生产工单前端 API 类型+函数 |
|
||||
| `web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue` | 临时质检工单列表页 |
|
||||
| `web-admin/src/views/production/temp-production-work-order/index.vue` | 临时生产工单列表页 |
|
||||
| `docs/sql/temp_work_order_tables.sql` | 新建表 + ALTER 语句 |
|
||||
|
||||
### 修改文件
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `backend/app/models/models.py` | 新增 2 个模型类;4 个现有模型新增 `order_source` 列 |
|
||||
| `backend/app/crud/qc_task.py` | `create_task_for_line()` 新增 `order_source` 参数;`_task_to_dict()` 序列化 `order_source`;`list_tasks()` 支持按 `order_source` 过滤 |
|
||||
| `backend/app/crud/production_task.py` | `create_production_task()` 新增 `order_source` 参数;序列化 `order_source`;列表支持按来源过滤 |
|
||||
| `backend/app/api/qc.py` | 新增临时质检工单路由组(5 个端点) |
|
||||
| `backend/app/api/production.py` | 新增临时生产工单路由组(5 个端点) |
|
||||
| `web-admin/src/api/qc-task.ts` | 类型新增 `orderSource` 字段 |
|
||||
| `web-admin/src/api/production-task.ts` | 类型新增 `orderSource` 字段 |
|
||||
| `web-admin/src/views/quality-inspection/qc-task/index.vue` | 列表新增"来源"Tag 列 |
|
||||
| `web-admin/src/views/production/production-task/index.vue` | 列表新增"来源"Tag 列 |
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 数据库 DDL — 新建表 + ALTER 语句
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/sql/temp_work_order_tables.sql`
|
||||
|
||||
- [ ] **Step 1: 创建 SQL 文件**
|
||||
|
||||
```sql
|
||||
-- ============================================================
|
||||
-- 临时工单模块 DDL
|
||||
-- Date: 2026-05-24
|
||||
-- ============================================================
|
||||
|
||||
-- 1. 新建临时质检工单表
|
||||
DROP TABLE IF EXISTS biz_temp_qc_work_order;
|
||||
CREATE TABLE biz_temp_qc_work_order (
|
||||
id VARCHAR(64) NOT NULL COMMENT '主键ID',
|
||||
work_order_no VARCHAR(64) NOT NULL COMMENT '工单号(LSZJ+日期+序号)',
|
||||
work_order_status VARCHAR(20) NOT NULL DEFAULT 'dpz' COMMENT '状态: dpz=待配置, ypz=已配置, ywc=已完成',
|
||||
configured_time DATETIME DEFAULT NULL COMMENT '配置时间',
|
||||
configured_by VARCHAR(64) DEFAULT NULL COMMENT '配置人',
|
||||
has_lab TINYINT DEFAULT 0 COMMENT '是否含实验室自检: 0=否, 1=是',
|
||||
has_third_party TINYINT DEFAULT 0 COMMENT '是否含第三方检测: 0=否, 1=是',
|
||||
third_party_fee_total DECIMAL(12,2) DEFAULT NULL COMMENT '第三方费用合计',
|
||||
tenant_no VARCHAR(64) NOT NULL DEFAULT '' COMMENT '租户编号',
|
||||
order_num INT DEFAULT NULL 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 DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_by VARCHAR(64) DEFAULT NULL COMMENT '更新人id',
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
del_flag TINYINT NOT NULL DEFAULT 0 COMMENT '删除标记: 0=正常, 1=已删除',
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_temp_qc_wo_tenant (tenant_no, del_flag),
|
||||
KEY idx_temp_qc_wo_no (work_order_no, tenant_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='临时质检工单';
|
||||
|
||||
-- 2. 新建临时生产工单表
|
||||
DROP TABLE IF EXISTS biz_temp_production_work_order;
|
||||
CREATE TABLE biz_temp_production_work_order (
|
||||
id VARCHAR(64) NOT NULL COMMENT '主键ID',
|
||||
work_order_no VARCHAR(64) NOT NULL COMMENT '工单号(LSSC+日期+序号)',
|
||||
work_order_status VARCHAR(20) NOT NULL DEFAULT 'dpz' COMMENT '状态: dpz=待配置, jxz=进行中, ywc=已完成',
|
||||
configured_time DATETIME DEFAULT NULL COMMENT '配置时间',
|
||||
configured_by VARCHAR(64) DEFAULT NULL COMMENT '配置人',
|
||||
tenant_no VARCHAR(64) NOT NULL DEFAULT '' COMMENT '租户编号',
|
||||
order_num INT DEFAULT NULL 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 DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_by VARCHAR(64) DEFAULT NULL COMMENT '更新人id',
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
del_flag TINYINT NOT NULL DEFAULT 0 COMMENT '删除标记: 0=正常, 1=已删除',
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_temp_prod_wo_tenant (tenant_no, del_flag),
|
||||
KEY idx_temp_prod_wo_no (work_order_no, tenant_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='临时生产工单';
|
||||
|
||||
-- 3. 质检任务表新增来源字段
|
||||
ALTER TABLE biz_qc_task
|
||||
ADD COLUMN order_source VARCHAR(20) NOT NULL DEFAULT 'inbound'
|
||||
COMMENT '工单来源: inbound=入库, temporary=临时' AFTER work_order_id;
|
||||
|
||||
-- 4. 生产任务表新增来源字段
|
||||
ALTER TABLE biz_production_task
|
||||
ADD COLUMN order_source VARCHAR(20) NOT NULL DEFAULT 'inbound'
|
||||
COMMENT '工单来源: inbound=入库, temporary=临时' AFTER work_order_id;
|
||||
|
||||
-- 5. 实验室项目明细表新增来源字段
|
||||
ALTER TABLE biz_qc_work_order_lab_item
|
||||
ADD COLUMN order_source VARCHAR(20) NOT NULL DEFAULT 'inbound'
|
||||
COMMENT '工单来源: inbound=入库, temporary=临时' AFTER work_order_id;
|
||||
|
||||
-- 6. 第三方项目明细表新增来源字段
|
||||
ALTER TABLE biz_qc_work_order_third_item
|
||||
ADD COLUMN order_source VARCHAR(20) NOT NULL DEFAULT 'inbound'
|
||||
COMMENT '工单来源: inbound=入库, temporary=临时' AFTER work_order_id;
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 在数据库执行 DDL**
|
||||
|
||||
Run: `mysql -u root -p zkxw < docs/sql/temp_work_order_tables.sql`
|
||||
Expected: 所有表和字段创建成功,无错误
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add docs/sql/temp_work_order_tables.sql
|
||||
git commit -m "feat(db): add temp work order tables and order_source columns"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 后端 Model — 新增模型类 + 修改现有模型
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/models/models.py`
|
||||
|
||||
- [ ] **Step 1: 在 BizQcTask 模型中新增 `order_source` 列**
|
||||
|
||||
在 `BizQcTask` 类中,`work_order_id` 行之后添加:
|
||||
|
||||
```python
|
||||
class BizQcTask(Base):
|
||||
"""质检任务 biz_qc_task"""
|
||||
|
||||
__tablename__ = "biz_qc_task"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID")
|
||||
work_order_id = Column(String(64), nullable=False, comment="工单ID")
|
||||
order_source = Column(String(20), nullable=False, default="inbound", comment="工单来源: inbound=入库, temporary=临时")
|
||||
task_no = Column(String(32), nullable=False, comment="任务号")
|
||||
# ... 其余字段保持不变
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 在 BizProductionTask 模型中新增 `order_source` 列**
|
||||
|
||||
在 `BizProductionTask` 类中,`work_order_id` 行之后添加:
|
||||
|
||||
```python
|
||||
class BizProductionTask(Base):
|
||||
"""生产任务 biz_production_task"""
|
||||
|
||||
__tablename__ = "biz_production_task"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID")
|
||||
task_no = Column(String(32), nullable=False, comment="任务号")
|
||||
work_order_id = Column(String(64), nullable=False, comment="工单ID")
|
||||
order_source = Column(String(20), nullable=False, default="inbound", comment="工单来源: inbound=入库, temporary=临时")
|
||||
task_type = Column(String(20), nullable=False, default="cell_storage", comment="任务类型")
|
||||
# ... 其余字段保持不变
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 在 BizQcWorkOrderLabItem 模型中新增 `order_source` 列**
|
||||
|
||||
在 `BizQcWorkOrderLabItem` 类中,`work_order_id` 行之后添加:
|
||||
|
||||
```python
|
||||
class BizQcWorkOrderLabItem(Base):
|
||||
"""质检工单-实验室项目明细 biz_qc_work_order_lab_item"""
|
||||
|
||||
__tablename__ = "biz_qc_work_order_lab_item"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID")
|
||||
work_order_id = Column(String(64), nullable=False, comment="工单ID")
|
||||
order_source = Column(String(20), nullable=False, default="inbound", comment="工单来源: inbound=入库, temporary=临时")
|
||||
lab_test_item_id = Column(String(64), nullable=False, comment="实验室项目ID")
|
||||
# ... 其余字段保持不变
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 在 BizQcWorkOrderThirdItem 模型中新增 `order_source` 列**
|
||||
|
||||
在 `BizQcWorkOrderThirdItem` 类中,`work_order_id` 行之后添加:
|
||||
|
||||
```python
|
||||
class BizQcWorkOrderThirdItem(Base):
|
||||
"""质检工单-第三方项目明细 biz_qc_work_order_third_item"""
|
||||
|
||||
__tablename__ = "biz_qc_work_order_third_item"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID")
|
||||
work_order_id = Column(String(64), nullable=False, comment="工单ID")
|
||||
order_source = Column(String(20), nullable=False, default="inbound", comment="工单来源: inbound=入库, temporary=临时")
|
||||
third_party_item_id = Column(String(64), nullable=False, comment="第三方项目ID")
|
||||
# ... 其余字段保持不变
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 新增 BizTempQcWorkOrder 模型类**
|
||||
|
||||
在 `BizQcWorkOrder` 类定义之后(约行 1253)添加:
|
||||
|
||||
```python
|
||||
class BizTempQcWorkOrder(Base):
|
||||
"""临时质检工单 biz_temp_qc_work_order"""
|
||||
|
||||
__tablename__ = "biz_temp_qc_work_order"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID")
|
||||
work_order_no = Column(String(64), nullable=False, comment="工单号(LSZJ+日期+序号)")
|
||||
work_order_status = Column(String(20), nullable=False, default="dpz", comment="状态: dpz=待配置, ypz=已配置, ywc=已完成")
|
||||
configured_time = Column(DateTime, nullable=True, comment="配置时间")
|
||||
configured_by = Column(String(64), nullable=True, comment="配置人")
|
||||
has_lab = Column(SmallInteger, nullable=False, default=0, comment="是否含实验室自检")
|
||||
has_third_party = Column(SmallInteger, nullable=False, default=0, comment="是否含第三方检测")
|
||||
third_party_fee_total = Column(Numeric(18, 2), nullable=True, comment="第三方费用合计")
|
||||
tenant_no = Column(String(64), nullable=False, default="zkxw", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, 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="删除标记")
|
||||
```
|
||||
|
||||
- [ ] **Step 6: 新增 BizTempProductionWorkOrder 模型类**
|
||||
|
||||
在 `BizProductionWorkOrder` 类定义之后(约行 2292)添加:
|
||||
|
||||
```python
|
||||
class BizTempProductionWorkOrder(Base):
|
||||
"""临时生产工单 biz_temp_production_work_order"""
|
||||
|
||||
__tablename__ = "biz_temp_production_work_order"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID")
|
||||
work_order_no = Column(String(64), nullable=False, comment="工单号(LSSC+日期+序号)")
|
||||
work_order_status = Column(String(20), nullable=False, default="dpz", comment="状态: dpz=待配置, jxz=进行中, ywc=已完成")
|
||||
configured_time = Column(DateTime, nullable=True, comment="配置时间")
|
||||
configured_by = Column(String(64), nullable=True, comment="配置人")
|
||||
tenant_no = Column(String(64), nullable=False, default="zkxw", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, 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="删除标记")
|
||||
```
|
||||
|
||||
- [ ] **Step 7: Commit**
|
||||
|
||||
```bash
|
||||
git add backend/app/models/models.py
|
||||
git commit -m "feat(models): add temp work order models and order_source columns to task models"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 后端 — 修改现有 qc_task CRUD 支持 order_source
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/crud/qc_task.py`
|
||||
|
||||
- [ ] **Step 1: `create_task_for_line()` 新增 `order_source` 参数**
|
||||
|
||||
将函数签名改为:
|
||||
|
||||
```python
|
||||
def create_task_for_line(
|
||||
db: Session,
|
||||
*,
|
||||
work_order, # BizQcWorkOrder 或 BizTempQcWorkOrder
|
||||
task_type: str,
|
||||
source_line_id: str,
|
||||
item_code: str,
|
||||
item_name: str,
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
seq: int = 1,
|
||||
company_id: Optional[str] = None,
|
||||
company_name: Optional[str] = None,
|
||||
fee_amount: Optional[Decimal] = None,
|
||||
order_source: str = "inbound", # 新增参数
|
||||
) -> BizQcTask:
|
||||
obj = BizQcTask(
|
||||
id=generate_uuid(),
|
||||
work_order_id=work_order.id,
|
||||
order_source=order_source, # 新增
|
||||
task_no=_gen_task_no(db, work_order, seq),
|
||||
task_type=task_type,
|
||||
source_line_id=source_line_id,
|
||||
sample_code=getattr(work_order, "sample_code", None) or None,
|
||||
item_code=item_code,
|
||||
item_name=item_name,
|
||||
company_id=company_id,
|
||||
company_name=company_name,
|
||||
fee_amount=fee_amount,
|
||||
task_status="dzx",
|
||||
tenant_no=tenant_no,
|
||||
order_num=seq,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id or "",
|
||||
create_time=datetime.now(),
|
||||
update_by=user_id,
|
||||
update_time=datetime.now(),
|
||||
del_flag=0,
|
||||
)
|
||||
db.add(obj)
|
||||
db.flush()
|
||||
return obj
|
||||
```
|
||||
|
||||
- [ ] **Step 2: `_task_to_dict()` 序列化 `order_source`**
|
||||
|
||||
在 `_task_to_dict` 返回的字典中添加 `"orderSource"` 字段:
|
||||
|
||||
```python
|
||||
def _task_to_dict(
|
||||
t: BizQcTask,
|
||||
work_order_no: str = "",
|
||||
db: Optional[Session] = None,
|
||||
tenant_no: Optional[str] = None,
|
||||
) -> Dict[str, Any]:
|
||||
tn = tenant_no or t.tenant_no
|
||||
return {
|
||||
"id": t.id,
|
||||
"workOrderId": t.work_order_id,
|
||||
"orderSource": getattr(t, "order_source", "inbound") or "inbound", # 新增
|
||||
"workOrderNo": work_order_no,
|
||||
# ... 其余字段保持不变
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add backend/app/crud/qc_task.py
|
||||
git commit -m "feat(qc-task): support order_source parameter for task creation"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 后端 — 修改现有 production_task CRUD 支持 order_source
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/crud/production_task.py`
|
||||
|
||||
- [ ] **Step 1: `create_production_task()` 新增 `order_source` 参数**
|
||||
|
||||
在函数签名中添加 `order_source: str = "inbound"` 参数,在创建 BizProductionTask 时设置:
|
||||
|
||||
```python
|
||||
# 在创建 task 对象时添加 order_source
|
||||
task = BizProductionTask(
|
||||
id=generate_uuid(),
|
||||
task_no=task_no,
|
||||
work_order_id=data.get("work_order_id", ""),
|
||||
order_source=order_source, # 新增
|
||||
task_type=data.get("task_type") or "cell_storage",
|
||||
# ... 其余保持不变
|
||||
)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 任务序列化函数添加 `orderSource` 字段**
|
||||
|
||||
在 `_task_to_dict()` 或相应的序列化函数中添加 `"orderSource"` 字段。
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add backend/app/crud/production_task.py
|
||||
git commit -m "feat(production-task): support order_source parameter for task creation"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: 后端 — 临时质检工单 Schema + CRUD + API
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/schemas/temp_qc_work_order.py`
|
||||
- Create: `backend/app/crud/temp_qc_work_order.py`
|
||||
- Modify: `backend/app/api/qc.py`
|
||||
|
||||
- [ ] **Step 1: 创建 Schema**
|
||||
|
||||
Create `backend/app/schemas/temp_qc_work_order.py`:
|
||||
|
||||
```python
|
||||
"""临时质检工单 Schema"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class TempQcWorkOrderCreateBody(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
remark: Optional[str] = Field("", alias="remark")
|
||||
|
||||
|
||||
class TempQcWorkOrderConfigureBody(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
has_lab: bool = Field(False, alias="hasLab")
|
||||
has_third_party: bool = Field(False, alias="hasThirdParty")
|
||||
lab_item_ids: List[str] = Field(default_factory=list, alias="labItemIds")
|
||||
third_party_item_ids: List[str] = Field(default_factory=list, alias="thirdPartyItemIds")
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 创建 CRUD**
|
||||
|
||||
Create `backend/app/crud/temp_qc_work_order.py`。核心函数:
|
||||
|
||||
1. `_gen_daily_no(db, tenant_no)` — 生成 `LSZJ{YYYYMMDD}{序号:04d}`
|
||||
2. `_wo_to_dict(wo)` — 序列化(极简字段)
|
||||
3. `create_temp_qc_work_order(db, *, tenant_no, user_id, create_dept_id, remark)` — 创建
|
||||
4. `list_temp_qc_work_orders(db, *, page, page_size, keyword, work_order_status, tenant_no, user_info)` — 列表
|
||||
5. `get_temp_qc_work_order(db, id, tenant_no)` — 获取单条
|
||||
6. `get_temp_qc_work_order_detail(db, id, tenant_no)` — 详情(含 labItems, thirdPartyItems, tasks)
|
||||
7. `configure_temp_qc_work_order(db, id, *, has_lab, has_third_party, lab_item_ids, third_party_item_ids, tenant_no, user_id, create_dept_id)` — 配置检测项目→自动生成任务(复用 `qc_task.create_task_for_line(order_source='temporary')`)
|
||||
8. `try_complete_temp_qc_work_order(db, work_order_id, tenant_no)` — 所有临时任务完成时标记工单完成
|
||||
9. `delete_temp_qc_work_order(db, id, tenant_no, user_id)` — 软删除
|
||||
|
||||
配置逻辑参照现有 `qc_work_order.configure_work_order()`,区别:
|
||||
- 创建 BizQcWorkOrderLabItem/BizQcWorkOrderThirdItem 时设 `order_source='temporary'`
|
||||
- 调用 `task_svc.create_task_for_line(order_source='temporary')`
|
||||
- `try_complete` 查询时过滤 `order_source='temporary'`
|
||||
|
||||
- [ ] **Step 3: 在 api/qc.py 中新增路由组**
|
||||
|
||||
在文件末尾添加 5 个路由端点:
|
||||
|
||||
```python
|
||||
# ---------- 临时质检工单 ----------
|
||||
|
||||
@router.post("/temp-qc-work-orders")
|
||||
async def create_temp_qc_work_order(
|
||||
body: TempQcWorkOrderCreateBody,
|
||||
db: Session = Depends(get_db),
|
||||
user: dict = Depends(require_menu_code("biz:tempQcWorkOrder:list")),
|
||||
):
|
||||
...
|
||||
|
||||
@router.get("/temp-qc-work-orders")
|
||||
async def list_temp_qc_work_orders(...):
|
||||
...
|
||||
|
||||
@router.get("/temp-qc-work-orders/{work_order_id}")
|
||||
async def get_temp_qc_work_order_detail(...):
|
||||
...
|
||||
|
||||
@router.delete("/temp-qc-work-orders/{work_order_id}")
|
||||
async def delete_temp_qc_work_order(...):
|
||||
...
|
||||
|
||||
@router.post("/temp-qc-work-orders/{work_order_id}/configure")
|
||||
async def configure_temp_qc_work_order(
|
||||
work_order_id: str,
|
||||
body: TempQcWorkOrderConfigureBody,
|
||||
db: Session = Depends(get_db),
|
||||
user: dict = Depends(require_menu_code("biz:tempQcWorkOrder:list")),
|
||||
):
|
||||
...
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 启动后端验证 API 可达**
|
||||
|
||||
Run: `cd backend && source venv/bin/activate && python -c "from app.main import app; print('OK')"`
|
||||
Expected: OK,无 import 错误
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add backend/app/schemas/temp_qc_work_order.py backend/app/crud/temp_qc_work_order.py backend/app/api/qc.py
|
||||
git commit -m "feat(temp-qc): add temp QC work order backend (schema, CRUD, API)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 6: 后端 — 临时生产工单 Schema + CRUD + API
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/schemas/temp_production_work_order.py`
|
||||
- Create: `backend/app/crud/temp_production_work_order.py`
|
||||
- Modify: `backend/app/api/production.py`
|
||||
|
||||
- [ ] **Step 1: 创建 Schema**
|
||||
|
||||
Create `backend/app/schemas/temp_production_work_order.py`:
|
||||
|
||||
```python
|
||||
"""临时生产工单 Schema"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class TempProductionWorkOrderCreateBody(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
remark: Optional[str] = Field("", alias="remark")
|
||||
|
||||
|
||||
class TempProductionWorkOrderConfigureBody(BaseModel):
|
||||
"""配置→创建生产任务(与入库生产工单一致:选择工艺路线+克隆步骤)"""
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
task_name: Optional[str] = Field("", alias="taskName")
|
||||
task_type: Optional[str] = Field("cell_storage", alias="taskType")
|
||||
route_id: Optional[str] = Field(None, alias="routeId")
|
||||
description: Optional[str] = Field("", alias="description")
|
||||
remark: Optional[str] = Field("", alias="remark")
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 创建 CRUD**
|
||||
|
||||
Create `backend/app/crud/temp_production_work_order.py`。核心函数:
|
||||
|
||||
1. `_gen_daily_no(db, tenant_no)` — 生成 `LSSC{YYYYMMDD}{序号:04d}`
|
||||
2. `_wo_to_dict(wo)` — 序列化
|
||||
3. `create_temp_production_work_order(db, *, tenant_no, user_id, create_dept_id, remark)` — 创建
|
||||
4. `list_temp_production_work_orders(db, *, page, page_size, keyword, work_order_status, tenant_no, user_info)` — 列表
|
||||
5. `get_temp_production_work_order(db, id, tenant_no)` — 获取单条
|
||||
6. `get_temp_production_work_order_detail(db, id, tenant_no)` — 详情(含 tasks,每个 task 含 steps+子表)
|
||||
7. `configure_temp_production_work_order(db, id, *, task_name, task_type, route_id, description, remark, tenant_no, user_id, create_dept_id)` — 配置→创建生产任务,**复用 `production_task.create_production_task(order_source='temporary')`,自动触发 `_clone_route_to_task()` 克隆工艺路线步骤+4类子表**
|
||||
8. `delete_temp_production_work_order(db, id, tenant_no, user_id)` — 软删除
|
||||
|
||||
关键:`configure_temp_production_work_order` 直接调用 `production_task.create_production_task()`,传入 `order_source='temporary'` 和 `route_id`,由 `create_production_task` 内部自动执行 `_clone_route_to_task()` 克隆路线步骤。
|
||||
|
||||
同时需要调用 `sync_production_work_order_status_from_tasks` 的临时版本来同步工单状态。
|
||||
|
||||
- [ ] **Step 3: 在 api/production.py 中新增路由组**
|
||||
|
||||
添加 5 个路由端点(POST/GET/GET/{id}/DELETE/{id}/POST/{id}/configure),路由路径前缀 `/temp-production-work-orders`。
|
||||
|
||||
- [ ] **Step 4: 启动后端验证 API 可达**
|
||||
|
||||
Run: `cd backend && source venv/bin/activate && python -c "from app.main import app; print('OK')"`
|
||||
Expected: OK
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add backend/app/schemas/temp_production_work_order.py backend/app/crud/temp_production_work_order.py backend/app/api/production.py
|
||||
git commit -m "feat(temp-production): add temp production work order with route cloning support"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 7: 前端 — 临时质检工单页面
|
||||
|
||||
**Files:**
|
||||
- Create: `web-admin/src/api/temp-qc-work-order.ts`
|
||||
- Create: `web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue`
|
||||
|
||||
- [ ] **Step 1: 创建 API 文件**
|
||||
|
||||
Create `web-admin/src/api/temp-qc-work-order.ts`,参照 `api/qc-work-order.ts` 简化版:
|
||||
|
||||
```typescript
|
||||
import request from '@/utils/http'
|
||||
|
||||
type PageList<T> = {
|
||||
list: T[]
|
||||
total: number
|
||||
page: number
|
||||
pageSize: number
|
||||
totalPages: number
|
||||
}
|
||||
|
||||
export type TempQcWorkOrder = {
|
||||
id: string
|
||||
workOrderNo: string
|
||||
workOrderStatus: string
|
||||
hasLab: boolean
|
||||
hasThirdParty: boolean
|
||||
configuredTime?: string
|
||||
configuredBy?: string
|
||||
thirdPartyFeeTotal?: number
|
||||
remark?: string
|
||||
createTime?: string
|
||||
updateTime?: string
|
||||
}
|
||||
|
||||
export type TempQcWorkOrderDetail = TempQcWorkOrder & {
|
||||
labItems?: Array<{ id: string; labTestItemId: string; itemCode: string; itemName: string }>
|
||||
thirdPartyItems?: Array<{
|
||||
id: string
|
||||
thirdPartyItemId: string
|
||||
companyId: string
|
||||
companyName: string
|
||||
itemCode: string
|
||||
itemName: string
|
||||
feeAmount: number
|
||||
}>
|
||||
tasks?: Array<{
|
||||
id: string
|
||||
taskNo: string
|
||||
taskType: string
|
||||
itemCode?: string
|
||||
itemName?: string
|
||||
taskStatus: string
|
||||
conclusion?: string
|
||||
conclusionLabel?: string
|
||||
}>
|
||||
}
|
||||
|
||||
export function fetchTempQcWorkOrderList(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
workOrderStatus?: string
|
||||
}) {
|
||||
return request.get<PageList<TempQcWorkOrder>>({
|
||||
url: '/web/admin/temp-qc-work-orders',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchTempQcWorkOrderDetail(id: string) {
|
||||
return request.get<TempQcWorkOrderDetail>({
|
||||
url: `/web/admin/temp-qc-work-orders/${id}`
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchCreateTempQcWorkOrder(data: { remark?: string }) {
|
||||
return request.post<TempQcWorkOrder>({
|
||||
url: '/web/admin/temp-qc-work-orders',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchConfigureTempQcWorkOrder(
|
||||
id: string,
|
||||
data: {
|
||||
hasLab: boolean
|
||||
hasThirdParty: boolean
|
||||
labItemIds: string[]
|
||||
thirdPartyItemIds: string[]
|
||||
}
|
||||
) {
|
||||
return request.post<TempQcWorkOrder>({
|
||||
url: `/web/admin/temp-qc-work-orders/${id}/configure`,
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchDeleteTempQcWorkOrder(id: string) {
|
||||
return request.del({ url: `/web/admin/temp-qc-work-orders/${id}` })
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 创建列表页面**
|
||||
|
||||
Create `web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue`
|
||||
|
||||
参照模板页 `src/views/system/unit/index.vue`(标准列表页模式),包含:
|
||||
- **列表列**:工单号、状态(Tag: dpz→info/ypz→warning/ywc→success)、是否含实验室自检、是否含第三方、配置时间、创建时间、操作
|
||||
- **创建弹窗**:仅备注字段(el-input type="textarea")
|
||||
- **配置弹窗**:复用现有配置检测项目组件逻辑(选择实验室自检/第三方检测项目)
|
||||
- **详情弹窗**:工单基本信息 + 关联任务列表
|
||||
- **Toolbar**:搜索(keyword)、状态筛选、新增按钮
|
||||
- **注意**:遵循 AGENTS.md UI 规范(Tag 用 el-tag、dialog label-position="top"、2列 form-grid 等)
|
||||
|
||||
- [ ] **Step 3: 验证前端编译**
|
||||
|
||||
Run: `cd web-admin && pnpm build`
|
||||
Expected: 构建成功,无 TypeScript 错误
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add web-admin/src/api/temp-qc-work-order.ts web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue
|
||||
git commit -m "feat(temp-qc): add temp QC work order frontend page"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 8: 前端 — 临时生产工单页面
|
||||
|
||||
**Files:**
|
||||
- Create: `web-admin/src/api/temp-production-work-order.ts`
|
||||
- Create: `web-admin/src/views/production/temp-production-work-order/index.vue`
|
||||
|
||||
- [ ] **Step 1: 创建 API 文件**
|
||||
|
||||
Create `web-admin/src/api/temp-production-work-order.ts`,参照 `api/production-work-order.ts` 简化版:
|
||||
|
||||
```typescript
|
||||
import request from '@/utils/http'
|
||||
|
||||
type PageList<T> = {
|
||||
list: T[]
|
||||
total: number
|
||||
page: number
|
||||
pageSize: number
|
||||
totalPages: number
|
||||
}
|
||||
|
||||
export type TempProductionWorkOrder = {
|
||||
id: string
|
||||
workOrderNo: string
|
||||
workOrderStatus: string
|
||||
configuredTime?: string
|
||||
configuredBy?: string
|
||||
remark?: string
|
||||
createTime?: string
|
||||
updateTime?: string
|
||||
}
|
||||
|
||||
export type TempProductionWorkOrderDetail = TempProductionWorkOrder & {
|
||||
tasks?: Array<{
|
||||
id: string
|
||||
taskNo: string
|
||||
taskType: string
|
||||
taskName?: string
|
||||
taskStatus: string
|
||||
}>
|
||||
}
|
||||
|
||||
export function fetchTempProductionWorkOrderList(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
workOrderStatus?: string
|
||||
}) {
|
||||
return request.get<PageList<TempProductionWorkOrder>>({
|
||||
url: '/web/admin/temp-production-work-orders',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchTempProductionWorkOrderDetail(id: string) {
|
||||
return request.get<TempProductionWorkOrderDetail>({
|
||||
url: `/web/admin/temp-production-work-orders/${id}`
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchCreateTempProductionWorkOrder(data: { remark?: string }) {
|
||||
return request.post<TempProductionWorkOrder>({
|
||||
url: '/web/admin/temp-production-work-orders',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchConfigureTempProductionWorkOrder(
|
||||
id: string,
|
||||
data: {
|
||||
taskName?: string
|
||||
taskType?: string
|
||||
routeId?: string
|
||||
description?: string
|
||||
remark?: string
|
||||
}
|
||||
) {
|
||||
return request.post<TempProductionWorkOrder>({
|
||||
url: `/web/admin/temp-production-work-orders/${id}/configure`,
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchDeleteTempProductionWorkOrder(id: string) {
|
||||
return request.del({ url: `/web/admin/temp-production-work-orders/${id}` })
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 创建列表页面**
|
||||
|
||||
Create `web-admin/src/views/production/temp-production-work-order/index.vue`
|
||||
|
||||
参照模板页 `src/views/system/unit/index.vue`(标准列表页),包含:
|
||||
- **列表列**:工单号、状态(Tag: dpz→info/jxz→primary/ywc→success)、配置时间、创建时间、操作
|
||||
- **创建弹窗**:仅备注字段
|
||||
- **配置弹窗**:与入库生产工单的 DispatchTaskDialog 类似,包含任务名称(task_name)、任务类型(task_type cell_storage/outbound)、**工艺路线选择(route_id,选择后自动克隆步骤)**、描述(description)、备注(remark)。参照 `views/production/production-work-order/DispatchTaskDialog.vue` 的表单结构。
|
||||
- **详情弹窗**:工单基本信息 + 关联任务列表
|
||||
- **遵循 UI 规范**
|
||||
|
||||
- [ ] **Step 3: 验证前端编译**
|
||||
|
||||
Run: `cd web-admin && pnpm build`
|
||||
Expected: 构建成功
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add web-admin/src/api/temp-production-work-order.ts web-admin/src/views/production/temp-production-work-order/index.vue
|
||||
git commit -m "feat(temp-production): add temp production work order frontend page"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 9: 前端 — 现有任务列表新增"来源"Tag 列
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/api/qc-task.ts`
|
||||
- Modify: `web-admin/src/views/quality-inspection/qc-task/index.vue`
|
||||
- Modify: `web-admin/src/api/production-task.ts`
|
||||
- Modify: `web-admin/src/views/production/production-task/index.vue`
|
||||
|
||||
- [ ] **Step 1: qc-task.ts 类型新增 orderSource**
|
||||
|
||||
在 `QcTask` 类型定义中添加:
|
||||
|
||||
```typescript
|
||||
export type QcTask = {
|
||||
// ... 现有字段
|
||||
orderSource?: string // 'inbound' | 'temporary'
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 质检任务列表新增"来源"列**
|
||||
|
||||
在 `quality-inspection/qc-task/index.vue` 的 el-table 中添加列:
|
||||
|
||||
```vue
|
||||
<el-table-column label="来源" prop="orderSource" min-width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:type="row.orderSource === 'temporary' ? 'warning' : 'success'"
|
||||
size="small"
|
||||
>
|
||||
{{ row.orderSource === 'temporary' ? '临时' : '入库' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
```
|
||||
|
||||
位置放在"工单号"列之后。
|
||||
|
||||
- [ ] **Step 3: production-task.ts 类型新增 orderSource**
|
||||
|
||||
同 Step 1,在 ProductionTask 类型中添加 `orderSource`。
|
||||
|
||||
- [ ] **Step 4: 生产任务列表新增"来源"列**
|
||||
|
||||
同 Step 2,在 `production/production-task/index.vue` 的 el-table 中添加来源 Tag 列。
|
||||
|
||||
- [ ] **Step 5: 验证前端编译**
|
||||
|
||||
Run: `cd web-admin && pnpm build`
|
||||
Expected: 构建成功
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add web-admin/src/api/qc-task.ts web-admin/src/views/quality-inspection/qc-task/index.vue web-admin/src/api/production-task.ts web-admin/src/views/production/production-task/index.vue
|
||||
git commit -m "feat(tasks): add orderSource column with tag display to task lists"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 10: 菜单配置 + 最终验证
|
||||
|
||||
**Files:**
|
||||
- Modify: 数据库 `sys_menu` 表(通过 SQL INSERT)
|
||||
|
||||
- [ ] **Step 1: 插入菜单记录**
|
||||
|
||||
在数据库中执行 SQL,为临时质检工单和临时生产工单各插入菜单记录。具体 menu_id 和 parent_id 需要根据现有菜单树确定。INSERT 语句参考现有菜单数据格式。
|
||||
|
||||
- [ ] **Step 2: 全栈验证**
|
||||
|
||||
1. 启动后端:`cd backend && source venv/bin/activate && ./start-local.sh`
|
||||
2. 启动前端:`cd web-admin && pnpm dev`
|
||||
3. 登录系统,导航到临时质检工单页面
|
||||
4. 测试:创建工单 → 配置检测项目 → 查看生成任务 → 完成任务 → 工单自动完成
|
||||
5. 导航到临时生产工单页面
|
||||
6. 测试:创建工单 → 配置生成任务 → 查看任务
|
||||
7. 导航到质检任务/生产任务页面,确认"来源"Tag 列正确显示
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add docs/sql/temp_work_order_tables.sql
|
||||
git commit -m "feat(menu): add temp work order menu items"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Self-Review Checklist
|
||||
|
||||
- [x] **Spec coverage**: 每个设计文档章节都有对应 Task(数据库→Task1/2,后端→Task3/4/5/6,前端→Task7/8/9,菜单→Task10)
|
||||
- [x] **Placeholder scan**: 无 TBD/TODO,所有步骤有具体代码或指令
|
||||
- [x] **Type consistency**: order_source 字段名在 model/schema/crud/api/typescript 中一致使用
|
||||
@@ -0,0 +1,324 @@
|
||||
# 细胞产品库 — 来源链路展示设计
|
||||
|
||||
> 日期:2026-05-24
|
||||
> 状态:待审核
|
||||
> 方案:A(自定义 Vue 组件 + CSS 绘制连线)
|
||||
> Demo:`docs/demo-source-chain-graph.html`
|
||||
|
||||
## 1. 需求概述
|
||||
|
||||
细胞产品库列表页(`/#/production/cell-product`)当前仅展示产品基础信息,缺少来源追溯能力。需要:
|
||||
|
||||
1. **列表新增来源信息列**:来源类型、来源协议号、来源工单号、来源任务号
|
||||
2. **列表新增来源类型筛选**:下拉筛选(全部/生产入库/手动录入)
|
||||
3. **查看弹窗新增链路图**:横向 DAG 可视化,展示从样本到当前产品的祖先链 + 当前产品到子代产品的后代链,双向递归到顶点/终点
|
||||
4. **链路图连线标注**:连线上方显示工单号、任务号
|
||||
|
||||
### 数据模型
|
||||
|
||||
溯源链路涉及 5 张核心表:
|
||||
|
||||
```
|
||||
biz_collection_protocol (采集协议单)
|
||||
↓ collection_protocol_id
|
||||
biz_protocol_sample (协议样本)
|
||||
↓ protocol_sample_id + collection_protocol_id
|
||||
biz_sample_reception (样本接收记录)
|
||||
↓ reception_id + protocol_sample_id + collection_protocol_id
|
||||
biz_production_work_order (生产工单) ← 冗余存储 protocol_no, sample_code
|
||||
↓ work_order_id
|
||||
biz_production_task (生产任务)
|
||||
↓ task_id
|
||||
biz_cell_product (细胞产品) ← production_task_id 关联到任务
|
||||
```
|
||||
|
||||
后代链路通过投入物/产出物表关联:
|
||||
|
||||
```
|
||||
父细胞产品 (biz_cell_product.id=A)
|
||||
↓ biz_production_task_input(input_type='cell_product', input_id=A, task_id=T)
|
||||
biz_production_task (id=T)
|
||||
↓ biz_production_task_output(task_id=T, cell_product_id=B, C, ...)
|
||||
子细胞产品们 (biz_cell_product.id=B, C, ...)
|
||||
```
|
||||
|
||||
## 2. 后端改造
|
||||
|
||||
### 2.1 列表 API 增强
|
||||
|
||||
**接口**:`GET /web/admin/cell-products`(已有)
|
||||
|
||||
**改造文件**:`backend/app/crud/cell_product.py`
|
||||
|
||||
#### 2.1.1 `_enrich_product_dicts()` 增加来源富化
|
||||
|
||||
在现有富化逻辑(productTypeName, specName, storageSlotName)之后,增加来源信息的批量富化查询:
|
||||
|
||||
1. 收集所有非空 `production_task_id`
|
||||
2. 一次查询 `biz_production_task`,获取 `task_no` 和 `work_order_id`
|
||||
3. 一次查询 `biz_production_work_order`,获取 `work_order_no`、`protocol_no`、`reception_source`
|
||||
4. 映射回每条产品记录
|
||||
|
||||
新增返回字段:
|
||||
|
||||
| 字段名 | 类型 | 来源路径 | 说明 |
|
||||
|--------|------|----------|------|
|
||||
| `sourceTypeLabel` | str | source_type 枚举映射 | 来源类型中文 |
|
||||
| `sourceProtocolNo` | str | task → work_order → protocol_no | 来源协议号 |
|
||||
| `sourceWorkOrderNo` | str | task → work_order → work_order_no | 来源工单号 |
|
||||
| `sourceTaskNo` | str | task → task_no | 来源生产任务号 |
|
||||
| `sourceReceptionSource` | str | work_order → reception_source | cell_storage/research_donation |
|
||||
|
||||
`source_type` 枚举映射:
|
||||
- `production` → "生产入库"
|
||||
- `manual` → "手动录入"
|
||||
|
||||
#### 2.1.2 `list_cell_products()` 增加筛选参数
|
||||
|
||||
入参新增 `source_type: Optional[str] = None`,在查询条件中增加:
|
||||
```python
|
||||
if source_type:
|
||||
query = query.filter(BizCellProduct.source_type == source_type)
|
||||
```
|
||||
|
||||
#### 2.1.3 Schema 更新
|
||||
|
||||
`CellProductListQuery` 新增 `source_type: Optional[str] = None`。
|
||||
|
||||
API 路由层 `production.py` 从 query params 读取 `source_type` 传入 service。
|
||||
|
||||
### 2.2 新增链路 API
|
||||
|
||||
**接口**:`GET /web/admin/cell-products/{product_id}/chain`
|
||||
|
||||
**新文件**:无(在 `backend/app/crud/cell_product.py` 中新增函数,在 `backend/app/api/production.py` 中新增路由)
|
||||
|
||||
#### 2.2.1 返回数据结构
|
||||
|
||||
```json
|
||||
{
|
||||
"current": {
|
||||
"id": "uuid",
|
||||
"productCode": "CP001",
|
||||
"productName": "脐带间充质干细胞",
|
||||
"nodeType": "cell_product",
|
||||
"productStatus": "frozen",
|
||||
"passage": "P2",
|
||||
"isCurrent": true
|
||||
},
|
||||
"ancestors": [
|
||||
{
|
||||
"node": {
|
||||
"id": "uuid",
|
||||
"productCode": "CP000",
|
||||
"productName": "...",
|
||||
"nodeType": "cell_product",
|
||||
"productStatus": "frozen",
|
||||
"passage": "P1",
|
||||
"isCurrent": false
|
||||
},
|
||||
"edge": {
|
||||
"workOrderNo": "WO001",
|
||||
"workOrderType": "cell_storage",
|
||||
"taskNo": "T001",
|
||||
"taskName": "制备任务"
|
||||
},
|
||||
"parent": null
|
||||
}
|
||||
],
|
||||
"descendants": [
|
||||
{
|
||||
"node": {
|
||||
"id": "uuid",
|
||||
"productCode": "CP002",
|
||||
"productName": "...",
|
||||
"nodeType": "cell_product",
|
||||
"productStatus": "frozen",
|
||||
"passage": "P3",
|
||||
"isCurrent": false
|
||||
},
|
||||
"edge": {
|
||||
"workOrderNo": "WO002",
|
||||
"workOrderType": "outbound",
|
||||
"taskNo": "T002",
|
||||
"taskName": "出库生产"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
当追溯链路中遇到样本节点(非细胞产品)时,`nodeType = "sample"`,包含 `sampleCode` 和 `sampleType` 字段。
|
||||
|
||||
#### 2.2.2 递归查询逻辑
|
||||
|
||||
**祖先方向**(从当前产品向上追溯):
|
||||
|
||||
1. 从 `biz_cell_product.production_task_id` 获取任务
|
||||
2. 从 `biz_production_task.work_order_id` 获取工单(含 protocol_no, sample_code)
|
||||
3. 检查该任务的投入物:`biz_production_task_input(input_type='cell_product')` 是否有父产品
|
||||
4. 如有父产品,递归继续(将父产品作为新的起点)
|
||||
5. 如投入物是样本(`input_type='sample'`),创建样本节点,终止递归
|
||||
6. 如 `production_task_id` 为空或 `source_type='manual'`,终止递归
|
||||
|
||||
**子代方向**(从当前产品向下追溯):
|
||||
|
||||
1. 查询 `biz_production_task_input(input_type='cell_product', input_id=当前产品id)` 找到所有引用此产品的任务
|
||||
2. 对每个任务,查询 `biz_production_task_output` 获取产出的细胞产品列表
|
||||
3. 对每个产出产品,递归继续(1对多分支)
|
||||
4. 如无任务引用此产品,终止递归
|
||||
|
||||
**性能保护**:最大递归深度 10 层。
|
||||
|
||||
#### 2.2.3 路由注册
|
||||
|
||||
在 `backend/app/api/production.py` Section 11(细胞产品库)中新增路由,放在 `GET /{product_id}` 之后。
|
||||
|
||||
## 3. 前端改造
|
||||
|
||||
### 3.1 列表页
|
||||
|
||||
**文件**:`web-admin/src/views/production/cell-product/index.vue`
|
||||
|
||||
#### 3.1.1 新增表格列
|
||||
|
||||
在 `productStatus`(状态)列之后,新增 4 列:
|
||||
|
||||
| prop | label | min-width | 渲染 |
|
||||
|------|-------|-----------|------|
|
||||
| `sourceTypeLabel` | 来源类型 | 120 | `<el-tag>`:生产入库=success、手动录入=info |
|
||||
| `sourceProtocolNo` | 来源协议号 | 160 | 文本,无值显示 "—" |
|
||||
| `sourceWorkOrderNo` | 来源工单号 | 140 | 文本,无值显示 "—" |
|
||||
| `sourceTaskNo` | 来源任务号 | 140 | 文本,无值显示 "—" |
|
||||
|
||||
#### 3.1.2 新增搜索筛选
|
||||
|
||||
搜索栏增加「来源类型」下拉,位于 `productStatus` 筛选之后:
|
||||
|
||||
```html
|
||||
<el-select v-model="searchForm.sourceType" placeholder="来源类型" clearable>
|
||||
<el-option label="生产入库" value="production" />
|
||||
<el-option label="手动录入" value="manual" />
|
||||
</el-select>
|
||||
```
|
||||
|
||||
#### 3.1.3 查看弹窗基础信息
|
||||
|
||||
在现有 `viewSections` 的「基本信息」section 中追加 2 个 `ViewField`:
|
||||
|
||||
| field | label | 渲染 |
|
||||
|-------|-------|------|
|
||||
| `sourceTypeLabel` | 来源类型 | `tagType` 映射 |
|
||||
| `sourceProtocolNo` | 来源协议号 | 文本 |
|
||||
|
||||
### 3.2 链路图组件
|
||||
|
||||
**新文件**:`web-admin/src/views/production/cell-product/SourceChainGraph.vue`
|
||||
|
||||
#### 3.2.1 组件职责
|
||||
|
||||
- 接收 `productId` prop
|
||||
- 调用 `GET /web/admin/cell-products/{id}/chain` 获取链路数据
|
||||
- 渲染横向 DAG:祖先 → 当前 → 子代
|
||||
- 支持节点点击查看详情(Element Plus Popover)
|
||||
|
||||
#### 3.2.2 组件 Props
|
||||
|
||||
| prop | type | 说明 |
|
||||
|------|------|------|
|
||||
| `productId` | string | 当前细胞产品 ID |
|
||||
| `visible` | boolean | 是否显示(由父组件控制) |
|
||||
|
||||
#### 3.2.3 布局结构
|
||||
|
||||
```
|
||||
SourceChainGraph
|
||||
├── 祖先区域(水平 flex,从左到右:最早祖先 → ... → 当前节点)
|
||||
│ ├── ChainNode(递归渲染祖先链)
|
||||
│ └── ChainConnector(连线 + 工单/任务标签)
|
||||
├── 当前节点(高亮样式,角标「当前」)
|
||||
└── 子代区域(支持分支,水平 flex-wrap)
|
||||
├── ChainNode(递归渲染子代链,1对多用 flex-wrap)
|
||||
└── ChainConnector(连线 + 工单/任务标签)
|
||||
```
|
||||
|
||||
#### 3.2.4 节点样式
|
||||
|
||||
| 节点类型 | 背景 | 边框 | 内容 |
|
||||
|----------|------|------|------|
|
||||
| 样本 | `#eff6ff`(浅蓝) | `#93c5fd` | 编码、类型 |
|
||||
| 细胞产品 | `#ecfdf5`(浅绿) | `#a7f3d0` | 编码、名称、代次 |
|
||||
| 当前产品 | `#ecfdf5` | `#10b981`(2px 加粗) | 编码、名称、代次 + 角标「当前」 |
|
||||
|
||||
节点尺寸:148×60px,内容过长用 `text-overflow: ellipsis` 截断。
|
||||
|
||||
#### 3.2.5 连线样式
|
||||
|
||||
- 水平线:2px border,颜色 `#d1d5db`
|
||||
- 箭头:CSS border 三角形
|
||||
- 连线上方标签:绝对定位 `<span>`,显示工单号和任务号,字号 10px
|
||||
- 分叉线:从父节点右侧引出竖线 + 横线到各子节点
|
||||
|
||||
#### 3.2.6 查看弹窗集成
|
||||
|
||||
在 `index.vue` 的 `SystemViewDialog` 中新增第三个 section「来源链路」,使用 `template #sourceChain` 自定义插槽:
|
||||
|
||||
```html
|
||||
<SystemViewDialog ...>
|
||||
<!-- 基本信息 section -->
|
||||
<!-- 产品图片 section -->
|
||||
<!-- 来源链路 section (新增) -->
|
||||
<template #sourceChain>
|
||||
<SourceChainGraph :product-id="currentRow.id" :visible="viewDialogVisible" />
|
||||
</template>
|
||||
</SystemViewDialog>
|
||||
```
|
||||
|
||||
`SystemViewDialog` 需支持第三个 section(通过 `viewSections` 配置中增加 `slot: 'sourceChain'`)。
|
||||
|
||||
### 3.3 API 层
|
||||
|
||||
**文件**:`web-admin/src/api/cell-product.ts`
|
||||
|
||||
新增接口函数:
|
||||
|
||||
```typescript
|
||||
export function fetchCellProductChain(productId: string) {
|
||||
return request.get({ url: `/web/admin/cell-products/${productId}/chain` })
|
||||
}
|
||||
```
|
||||
|
||||
`fetchCellProductList` 的参数类型新增 `sourceType?: string`。
|
||||
|
||||
## 4. 影响范围
|
||||
|
||||
### 后端文件
|
||||
|
||||
| 文件 | 改动类型 |
|
||||
|------|----------|
|
||||
| `backend/app/crud/cell_product.py` | 修改:`_enrich_product_dicts` 增加来源富化,新增 `get_product_chain()` 递归函数 |
|
||||
| `backend/app/schemas/cell_product.py` | 修改:`CellProductListQuery` 增加 `source_type` 参数 |
|
||||
| `backend/app/api/production.py` | 修改:列表路由读取 `source_type` 参数,新增 chain 路由 |
|
||||
|
||||
### 前端文件
|
||||
|
||||
| 文件 | 改动类型 |
|
||||
|------|----------|
|
||||
| `web-admin/src/views/production/cell-product/index.vue` | 修改:新增表格列、搜索筛选、查看弹窗字段 |
|
||||
| `web-admin/src/views/production/cell-product/SourceChainGraph.vue` | 新增:链路图组件 |
|
||||
| `web-admin/src/api/cell-product.ts` | 修改:新增 `fetchCellProductChain`,`fetchCellProductList` 参数增加 `sourceType` |
|
||||
|
||||
### 不涉及的文件
|
||||
|
||||
- 数据库无表结构变更(无新表、无新字段)
|
||||
- 不涉及其他模块(订单、协议单、质检等)
|
||||
|
||||
## 5. 约束与边界
|
||||
|
||||
1. **手动录入产品(起源节点)**:无 `production_task_id`,所以祖先链为空。但后续如果被用于生产,子代链路仍然会展示。只有**既无祖先又无子代的孤立产品**才显示空状态提示「该产品暂无来源及衍生链路信息」
|
||||
2. **最大递归深度**:10 层,防止异常数据导致无限递归
|
||||
3. **性能**:链路 API 单次查询,预估节点数 ≤ 50,响应时间 < 500ms
|
||||
4. **科研捐赠来源**:通过 `reception_source='research_donation'` 标识,链路追溯路径相同
|
||||
5. **子代追踪**:依赖 `biz_production_task_input(input_type='cell_product')` 记录,如投入物未正确录入则无法追踪子代
|
||||
6. **配色**:严格使用 Fresh Mint 色系(`#10b981`、`#ecfdf5`),样本节点使用蓝色系(`#eff6ff`、`#93c5fd`)做区分
|
||||
@@ -0,0 +1,312 @@
|
||||
# 临时工单模块设计文档
|
||||
|
||||
> 日期: 2026-05-24
|
||||
> 状态: 待审核
|
||||
> 模块: 临时质检工单 + 临时生产工单
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
### 现状
|
||||
|
||||
系统已有 4 个模块:
|
||||
|
||||
| 模块 | 表名 | 说明 |
|
||||
|------|------|------|
|
||||
| 入库质检工单 | `biz_qc_work_order` | 关联样本接收记录和协议 |
|
||||
| 质检任务 | `biz_qc_task` | 由入库质检工单配置检测项目后自动生成 |
|
||||
| 入库生产工单 | `biz_production_work_order` | 关联样本接收记录和协议 |
|
||||
| 生产任务 | `biz_production_task` | 由入库生产工单手动派发创建 |
|
||||
|
||||
### 目标
|
||||
|
||||
新增 2 个临时工单模块,复用现有任务生成机制,在任务表中记录工单来源:
|
||||
|
||||
1. **临时质检工单** — 独立工单(不关联样本/协议),配置检测项目后自动生成质检任务
|
||||
2. **临时生产工单** — 独立工单(不关联样本/协议),选择工艺路线后创建生产任务(自动克隆路线步骤+子表,流程与入库生产工单一致)
|
||||
|
||||
### 设计决策记录
|
||||
|
||||
| 决策项 | 选择 | 原因 |
|
||||
|--------|------|------|
|
||||
| 关联关系 | 完全不关联 reception/protocol | 临时工单独立于入库流程 |
|
||||
| 来源追踪 | 任务表新增 `order_source` 字段 | 最小侵入,清晰区分来源 |
|
||||
| 任务生成方式 | 配置→自动批量生成 | 和入库模式一致 |
|
||||
| 工单字段 | 极简(工单号+状态+备注) | 用户要求简单 |
|
||||
| 工单号前缀 | LSZJ(临时质检)、LSSC(临时生产) | 区分于入库前缀 |
|
||||
| 实现方案 | 新建独立临时工单表 | 和入库完全解耦,避免混合复杂度 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 数据库设计
|
||||
|
||||
### 2.1 新建 `biz_temp_qc_work_order`(临时质检工单)
|
||||
|
||||
```sql
|
||||
DROP TABLE IF EXISTS biz_temp_qc_work_order;
|
||||
CREATE TABLE biz_temp_qc_work_order (
|
||||
id VARCHAR(64) NOT NULL COMMENT '主键ID',
|
||||
work_order_no VARCHAR(64) NOT NULL COMMENT '工单号(LSZJ+日期+序号)',
|
||||
work_order_status VARCHAR(20) NOT NULL DEFAULT 'dpz' COMMENT '状态: dpz=待配置, ypz=已配置, ywc=已完成',
|
||||
configured_time DATETIME DEFAULT NULL COMMENT '配置时间',
|
||||
configured_by VARCHAR(64) DEFAULT NULL COMMENT '配置人',
|
||||
has_lab TINYINT DEFAULT 0 COMMENT '是否含实验室自检: 0=否, 1=是',
|
||||
has_third_party TINYINT DEFAULT 0 COMMENT '是否含第三方检测: 0=否, 1=是',
|
||||
third_party_fee_total DECIMAL(12,2) DEFAULT NULL COMMENT '第三方费用合计',
|
||||
tenant_no VARCHAR(64) NOT NULL DEFAULT '' COMMENT '租户编号',
|
||||
order_num INT DEFAULT NULL 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 DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_by VARCHAR(64) DEFAULT NULL COMMENT '更新人id',
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
del_flag TINYINT NOT NULL DEFAULT 0 COMMENT '删除标记: 0=正常, 1=已删除',
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_temp_qc_wo_tenant (tenant_no, del_flag),
|
||||
KEY idx_temp_qc_wo_no (work_order_no, tenant_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='临时质检工单';
|
||||
```
|
||||
|
||||
### 2.2 新建 `biz_temp_production_work_order`(临时生产工单)
|
||||
|
||||
```sql
|
||||
DROP TABLE IF EXISTS biz_temp_production_work_order;
|
||||
CREATE TABLE biz_temp_production_work_order (
|
||||
id VARCHAR(64) NOT NULL COMMENT '主键ID',
|
||||
work_order_no VARCHAR(64) NOT NULL COMMENT '工单号(LSSC+日期+序号)',
|
||||
work_order_status VARCHAR(20) NOT NULL DEFAULT 'dpz' COMMENT '状态: dpz=待配置, jxz=进行中, ywc=已完成',
|
||||
configured_time DATETIME DEFAULT NULL COMMENT '配置时间',
|
||||
configured_by VARCHAR(64) DEFAULT NULL COMMENT '配置人',
|
||||
tenant_no VARCHAR(64) NOT NULL DEFAULT '' COMMENT '租户编号',
|
||||
order_num INT DEFAULT NULL 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 DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_by VARCHAR(64) DEFAULT NULL COMMENT '更新人id',
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
del_flag TINYINT NOT NULL DEFAULT 0 COMMENT '删除标记: 0=正常, 1=已删除',
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_temp_prod_wo_tenant (tenant_no, del_flag),
|
||||
KEY idx_temp_prod_wo_no (work_order_no, tenant_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='临时生产工单';
|
||||
```
|
||||
|
||||
### 2.3 任务表新增 `order_source` 字段
|
||||
|
||||
```sql
|
||||
-- 质检任务表新增来源字段
|
||||
ALTER TABLE biz_qc_task
|
||||
ADD COLUMN order_source VARCHAR(20) NOT NULL DEFAULT 'inbound'
|
||||
COMMENT '工单来源: inbound=入库, temporary=临时' AFTER work_order_id;
|
||||
|
||||
-- 生产任务表新增来源字段
|
||||
ALTER TABLE biz_production_task
|
||||
ADD COLUMN order_source VARCHAR(20) NOT NULL DEFAULT 'inbound'
|
||||
COMMENT '工单来源: inbound=入库, temporary=临时' AFTER work_order_id;
|
||||
```
|
||||
|
||||
### 2.4 明细表处理(复用现有表)
|
||||
|
||||
临时质检工单复用现有 `biz_qc_work_order_lab_item` 和 `biz_qc_work_order_third_item` 表,通过 `order_source` 字段区分来源。
|
||||
|
||||
```sql
|
||||
-- 实验室项目明细表新增来源字段
|
||||
ALTER TABLE biz_qc_work_order_lab_item
|
||||
ADD COLUMN order_source VARCHAR(20) NOT NULL DEFAULT 'inbound'
|
||||
COMMENT '工单来源: inbound=入库, temporary=临时' AFTER work_order_id;
|
||||
|
||||
-- 第三方项目明细表新增来源字段
|
||||
ALTER TABLE biz_qc_work_order_third_item
|
||||
ADD COLUMN order_source VARCHAR(20) NOT NULL DEFAULT 'inbound'
|
||||
COMMENT '工单来源: inbound=入库, temporary=临时' AFTER work_order_id;
|
||||
```
|
||||
|
||||
### 2.5 关联关系
|
||||
|
||||
```
|
||||
biz_temp_qc_work_order
|
||||
├─(work_order_id + order_source='temporary')→ biz_qc_work_order_lab_item
|
||||
├─(work_order_id + order_source='temporary')→ biz_qc_work_order_third_item
|
||||
└─(work_order_id + order_source='temporary')→ biz_qc_task
|
||||
→ biz_qc_task_result
|
||||
|
||||
biz_temp_production_work_order
|
||||
└─(work_order_id + order_source='temporary')→ biz_production_task
|
||||
→ biz_production_task_step + 子表
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 后端架构
|
||||
|
||||
### 3.1 新增文件清单
|
||||
|
||||
| 层 | 临时质检工单 | 临时生产工单 |
|
||||
|----|-------------|-------------|
|
||||
| Model | `models.py` 新增 `BizTempQcWorkOrder` | `models.py` 新增 `BizTempProductionWorkOrder` |
|
||||
| Schema | 新建 `schemas/temp_qc_work_order.py` | 新建 `schemas/temp_production_work_order.py` |
|
||||
| CRUD | 新建 `crud/temp_qc_work_order.py` | 新建 `crud/temp_production_work_order.py` |
|
||||
| API | `api/qc.py` 新增路由组 | `api/production.py` 新增路由组 |
|
||||
|
||||
### 3.2 API 路由设计
|
||||
|
||||
**临时质检工单:**
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | `/api/admin/temp-qc-work-orders` | 创建 |
|
||||
| GET | `/api/admin/temp-qc-work-orders` | 列表 |
|
||||
| GET | `/api/admin/temp-qc-work-orders/{id}` | 详情 |
|
||||
| DELETE | `/api/admin/temp-qc-work-orders/{id}` | 删除(软删除) |
|
||||
| POST | `/api/admin/temp-qc-work-orders/{id}/configure` | 配置检测项目(→自动生成任务) |
|
||||
|
||||
**临时生产工单:**
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | `/api/admin/temp-production-work-orders` | 创建 |
|
||||
| GET | `/api/admin/temp-production-work-orders` | 列表 |
|
||||
| GET | `/api/admin/temp-production-work-orders/{id}` | 详情 |
|
||||
| DELETE | `/api/admin/temp-production-work-orders/{id}` | 删除(软删除) |
|
||||
| POST | `/api/admin/temp-production-work-orders/{id}/configure` | 配置→自动生成任务 |
|
||||
|
||||
### 3.3 核心业务逻辑
|
||||
|
||||
#### 3.3.1 工单号生成
|
||||
|
||||
- 临时质检:`LSZJ` + `YYYYMMDD` + 4位序号(如 `LSZJ202605240001`)
|
||||
- 临时生产:`LSSC` + `YYYYMMDD` + 4位序号(如 `LSSC202605240001`)
|
||||
- 生成逻辑:参照现有 `_gen_qc_work_order_no()` 模式,按日期+租户查询当日最大序号+1
|
||||
|
||||
#### 3.3.2 创建工单
|
||||
|
||||
极简创建:仅需 `remark`(可选),自动生成工单号,状态默认 `dpz`(待配置)。
|
||||
|
||||
#### 3.3.3 配置检测项目(临时质检工单)
|
||||
|
||||
流程与入库质检工单的 `configure_work_order()` 一致:
|
||||
|
||||
```
|
||||
用户选择检测项目 (lab_item_ids, third_party_ids)
|
||||
├─ 校验工单状态 (dpz/ypz)
|
||||
├─ 清除旧的待执行任务(order_source='temporary')
|
||||
├─ 遍历 lab_item_ids:
|
||||
│ ├─ 创建 BizQcWorkOrderLabItem (order_source='temporary')
|
||||
│ └─ 调用 qc_task.create_task_for_line(order_source='temporary')
|
||||
├─ 遍历 third_party_ids:
|
||||
│ ├─ 创建 BizQcWorkOrderThirdItem (order_source='temporary')
|
||||
│ └─ 调用 qc_task.create_task_for_line(order_source='temporary')
|
||||
└─ 更新工单状态为 'ypz'
|
||||
```
|
||||
|
||||
#### 3.3.4 配置→生成任务(临时生产工单)
|
||||
|
||||
与入库生产工单完全一致,选择工艺路线后创建生产任务(自动克隆路线步骤+4类子表):
|
||||
|
||||
```
|
||||
用户配置任务信息 (task_name, task_type, route_id 工艺路线, description 可选)
|
||||
├─ 创建 BizProductionTask (order_source='temporary', task_status='dpz')
|
||||
├─ 如果选择了工艺路线: _clone_route_to_task() — 深拷贝路线步骤 + 子表
|
||||
├─ 工单状态更新为 'jxz'
|
||||
└─ 流程与入库生产工单的 create_production_task() 完全一致
|
||||
```
|
||||
|
||||
后需复用 `production_task.create_production_task()` + `_clone_route_to_task()` 机制。
|
||||
|
||||
#### 3.3.5 状态同步
|
||||
|
||||
- **质检**:任务完成时检查同工单下所有任务(order_source='temporary')是否都已完成,若是则工单标记 `ywc`
|
||||
- **生产**:任务完成时同步工单状态(复用 `sync_production_work_order_status_from_tasks()` 逻辑)
|
||||
|
||||
#### 3.3.6 删除
|
||||
|
||||
软删除(`del_flag=1`),级联删除关联的任务(仅 `order_source='temporary'`)和明细行。
|
||||
|
||||
---
|
||||
|
||||
## 4. 前端架构
|
||||
|
||||
### 4.1 新增文件清单
|
||||
|
||||
| 类型 | 临时质检工单 | 临时生产工单 |
|
||||
|------|-------------|-------------|
|
||||
| API | 新建 `api/temp-qc-work-order.ts` | 新建 `api/temp-production-work-order.ts` |
|
||||
| 视图 | 新建 `views/quality-inspection/temp-qc-work-order/index.vue` | 新建 `views/production/temp-production-work-order/index.vue` |
|
||||
|
||||
### 4.2 页面设计
|
||||
|
||||
#### 临时质检工单页
|
||||
|
||||
参照模板页 `views/system/unit/index.vue`(标准列表页),功能简化:
|
||||
|
||||
- **列表列**:工单号、状态(Tag)、是否含实验室自检、是否含第三方、配置时间、创建时间、操作
|
||||
- **创建弹窗**:仅备注字段
|
||||
- **配置弹窗**:复用现有配置检测项目组件(选择实验室自检项目/第三方检测项目+公司+费用)
|
||||
- **详情弹窗**:工单基本信息 + 关联任务列表
|
||||
- **状态 Tag**:dpz→待配置(info)、ypz→已配置(warning)、ywc→已完成(success)
|
||||
|
||||
#### 临时生产工单页
|
||||
|
||||
同样参照标准列表页:
|
||||
|
||||
- **列表列**:工单号、状态(Tag)、配置时间、创建时间、操作
|
||||
- **创建弹窗**:仅备注字段
|
||||
- **配置弹窗**:简单表单(任务名称、任务类型 cell_storage/outbound、描述)
|
||||
- **详情弹窗**:工单基本信息 + 关联任务列表
|
||||
- **状态 Tag**:dpz→待配置(info)、jxz→进行中(primary)、ywc→已完成(success)
|
||||
|
||||
### 4.3 任务来源展示
|
||||
|
||||
在现有质检任务和生产任务列表页中:
|
||||
|
||||
- 新增"来源"列,使用 Tag 展示:
|
||||
- `inbound` → Tag `<el-tag type="success" size="small">入库</el-tag>`
|
||||
- `temporary` → Tag `<el-tag type="warning" size="small">临时</el-tag>`
|
||||
|
||||
### 4.4 路由配置
|
||||
|
||||
在 `src/router/modules/` 中对应的质量检验和生产管理路由组下新增子路由:
|
||||
|
||||
```typescript
|
||||
// 质量检验路由组下
|
||||
{ path: 'temp-qc-work-order', name: 'TempQcWorkOrder', component: () => import('@views/quality-inspection/temp-qc-work-order/index.vue') }
|
||||
|
||||
// 生产管理路由组下
|
||||
{ path: 'temp-production-work-order', name: 'TempProductionWorkOrder', component: () => import('@views/production/temp-production-work-order/index.vue') }
|
||||
```
|
||||
|
||||
### 4.5 菜单配置
|
||||
|
||||
需要在系统菜单管理中添加对应菜单项(数据库 `sys_menu` 表插入)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 修改现有代码清单
|
||||
|
||||
以下列出需要修改的现有文件(非新增文件):
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `backend/app/models/models.py` | 新增 `BizTempQcWorkOrder`、`BizTempProductionWorkOrder` 模型;`BizQcTask`、`BizProductionTask` 新增 `order_source` 列;`BizQcWorkOrderLabItem`、`BizQcWorkOrderThirdItem` 新增 `order_source` 列 |
|
||||
| `backend/app/crud/qc_task.py` | `create_task_for_line()` 接受 `order_source` 参数;`list_tasks()` 展示 `order_source`;`_task_to_dict()` 序列化 `order_source` |
|
||||
| `backend/app/crud/production_task.py` | `create_production_task()` 接受 `order_source` 参数;`list_production_tasks()` 展示 `order_source`;序列化 `order_source` |
|
||||
| `backend/app/api/qc.py` | 新增临时质检工单路由组 |
|
||||
| `backend/app/api/production.py` | 新增临时生产工单路由组 |
|
||||
| `backend/app/api/__init__.py` | 如有新路由文件则注册 |
|
||||
| `web-admin/src/api/qc-task.ts` | 类型定义新增 `orderSource` 字段 |
|
||||
| `web-admin/src/api/production-task.ts` | 类型定义新增 `orderSource` 字段 |
|
||||
| `web-admin/src/views/quality-inspection/qc-task/index.vue` | 列表新增"来源"Tag 列 |
|
||||
| `web-admin/src/views/production/production-task/index.vue` | 列表新增"来源"Tag 列 |
|
||||
| `docs/sql/zkxw.sql` | 同步新增表和 ALTER 语句 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 风险与注意事项
|
||||
|
||||
1. **order_source 默认值**:所有现有数据默认为 `inbound`,无需数据迁移
|
||||
2. **现有查询兼容**:所有现有查询 `work_order_id` 关联时,默认只查 `order_source='inbound'` 或不加过滤(因为现有数据的 work_order_id 不会和临时工单冲突——指向不同表的主键)
|
||||
3. **工单号唯一性**:LSZJ/LSSC 前缀确保不与 ZJ/SC 冲突
|
||||
4. **权限**:临时工单菜单需要在系统中配置,遵循现有 RBAC 权限体系
|
||||
5. **软删除级联**:删除临时工单时,仅删除 `order_source='temporary'` 的任务,不影响入库任务
|
||||
6. **工艺路线克隆**:临时生产工单复用 `_clone_route_to_task()` 机制,与入库生产工单完全一致(步骤+试剂+耗材+产出物+数据采集项全部深拷贝)
|
||||
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-05-24)
|
||||
|
||||
## Corpus Check
|
||||
- Large corpus: 597 files · ~327,181 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
|
||||
- Large corpus: 609 files · ~334,365 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
|
||||
|
||||
## Summary
|
||||
- 1528 nodes · 1917 edges · 41 communities detected
|
||||
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 417 edges (avg confidence: 0.8)
|
||||
- 1581 nodes · 1982 edges · 44 communities detected
|
||||
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 431 edges (avg confidence: 0.8)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
@@ -32,27 +32,30 @@
|
||||
- [[_COMMUNITY_Community 20|Community 20]]
|
||||
- [[_COMMUNITY_Community 21|Community 21]]
|
||||
- [[_COMMUNITY_Community 22|Community 22]]
|
||||
- [[_COMMUNITY_Community 23|Community 23]]
|
||||
- [[_COMMUNITY_Community 24|Community 24]]
|
||||
- [[_COMMUNITY_Community 25|Community 25]]
|
||||
- [[_COMMUNITY_Community 26|Community 26]]
|
||||
- [[_COMMUNITY_Community 27|Community 27]]
|
||||
- [[_COMMUNITY_Community 28|Community 28]]
|
||||
- [[_COMMUNITY_Community 29|Community 29]]
|
||||
- [[_COMMUNITY_Community 30|Community 30]]
|
||||
- [[_COMMUNITY_Community 31|Community 31]]
|
||||
- [[_COMMUNITY_Community 32|Community 32]]
|
||||
- [[_COMMUNITY_Community 33|Community 33]]
|
||||
- [[_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 47|Community 47]]
|
||||
- [[_COMMUNITY_Community 49|Community 49]]
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `get()` - 164 edges
|
||||
1. `get()` - 170 edges
|
||||
2. `WebSocketClient` - 26 edges
|
||||
3. `push()` - 20 edges
|
||||
4. `withFullscreenLoading()` - 17 edges
|
||||
@@ -64,42 +67,42 @@
|
||||
10. `StorageConfig` - 10 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `handleBatchDeleteHospital()` --calls--> `withFullscreenLoading()` [INFERRED]
|
||||
views/basic-info/collection-region/index.vue → utils/fullscreen-loading.ts
|
||||
- `handleBatchDelete()` --calls--> `withFullscreenLoading()` [INFERRED]
|
||||
views/system/site/index.vue → utils/fullscreen-loading.ts
|
||||
- `handleBatchDelete()` --calls--> `withFullscreenLoading()` [INFERRED]
|
||||
views/basic-info/customer/index.vue → utils/fullscreen-loading.ts
|
||||
- `handleUnauthorizedResponse()` --calls--> `fetchRefreshToken()` [INFERRED]
|
||||
utils/http/index.ts → api/auth.ts
|
||||
- `fetchConsumableList()` --calls--> `get()` [INFERRED]
|
||||
api/production.ts → views/production/process-route/index.vue
|
||||
- `fetchAllConsumables()` --calls--> `get()` [INFERRED]
|
||||
api/production.ts → views/production/process-route/index.vue
|
||||
- `fetchReagentList()` --calls--> `get()` [INFERRED]
|
||||
api/production.ts → views/production/process-route/index.vue
|
||||
- `toLogin()` --calls--> `logOut()` [INFERRED]
|
||||
components/core/layouts/art-screen-lock/index.vue → utils/http/index.ts
|
||||
- `fetchLeaveList()` --calls--> `get()` [INFERRED]
|
||||
api/leave.ts → views/production/process-route/index.vue
|
||||
|
||||
## Communities
|
||||
|
||||
### Community 0 - "Community 0"
|
||||
Cohesion: 0.01
|
||||
Nodes (82): fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchCellSampleTypeList(), fetchChannelAgreementPrices() (+74 more)
|
||||
Nodes (87): fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchCellSampleTypeList(), fetchChannelAgreementPrices() (+79 more)
|
||||
|
||||
### Community 1 - "Community 1"
|
||||
Cohesion: 0.03
|
||||
Nodes (60): fetchBatchGenerateProtocolNos(), fetchBatchGenerateSampleCodes(), fetchBatchIssueProtocolNos(), fetchBatchIssueSampleCodes(), fetchCollectionProtocolNoList(), fetchCreateCollectionProtocolNo(), fetchCreateSampleCode(), fetchDeleteCollectionProtocolNo() (+52 more)
|
||||
Nodes (61): fetchBatchGenerateProtocolNos(), fetchBatchGenerateSampleCodes(), fetchBatchIssueProtocolNos(), fetchBatchIssueSampleCodes(), fetchCollectionProtocolNoList(), fetchCreateCollectionProtocolNo(), fetchCreateSampleCode(), fetchDeleteCollectionProtocolNo() (+53 more)
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.04
|
||||
Nodes (31): fetchGetUserInfo(), clickTab(), handleTouchEnd(), setTransition(), IframeRouteManager, RouteRegistry, useCommon(), setupAfterEachGuard() (+23 more)
|
||||
Cohesion: 0.03
|
||||
Nodes (39): fetchGetMenuList(), fetchGetMenuCodes(), fetchGetUserInfo(), fetchLogin(), fetchRefreshToken(), clickTab(), handleTouchEnd(), setTransition() (+31 more)
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.03
|
||||
Nodes (22): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllConsumableStockLogs(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents(), fetchAllReagentStockLogs() (+14 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.04
|
||||
Nodes (40): fetchDeptTree(), fetchPostBoundUserIds(), FireworkSystem, reload(), formatUserLabel(), loadDeptData(), onPersonSelectChange(), subscribeTokenRefresh() (+32 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.03
|
||||
Nodes (21): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllConsumableStockLogs(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents(), fetchAllReagentStockLogs() (+13 more)
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.04
|
||||
Nodes (34): fetchCollectionRegionList(), fetchCreateCollectionRegion(), fetchCreateHospital(), fetchDeleteCollectionRegion(), fetchDeleteHospital(), fetchHospitalList(), fetchUpdateCollectionRegion(), fetchUpdateHospital() (+26 more)
|
||||
Nodes (33): fetchCollectionRegionList(), fetchCreateCollectionRegion(), fetchCreateHospital(), fetchDeleteCollectionRegion(), fetchDeleteHospital(), fetchHospitalList(), fetchUpdateCollectionRegion(), fetchUpdateHospital() (+25 more)
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.04
|
||||
@@ -107,15 +110,15 @@ Nodes (23): fetchAttachmentDownloadUrl(), fetchOrderAdjusts(), fetchOrderDetail(
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.05
|
||||
Nodes (39): fetchAccessLogList(), fetchCleanRoomList(), fetchCreateAccessLog(), fetchCreateCleanRoom(), fetchCreateSite(), fetchDeleteAccessLog(), fetchDeleteCleanRoom(), fetchDeleteSite() (+31 more)
|
||||
Nodes (40): fetchAccessLogList(), fetchCleanRoomList(), fetchCreateAccessLog(), fetchCreateCleanRoom(), fetchCreateSite(), fetchDeleteAccessLog(), fetchDeleteCleanRoom(), fetchDeleteSite() (+32 more)
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.06
|
||||
Nodes (12): collectIds(), useSettingsHandlers(), useSettingsPanel(), useSettingsState(), ComponentLoader, RoutePermissionValidator, RouteTransformer, useCeremony() (+4 more)
|
||||
Cohesion: 0.09
|
||||
Nodes (5): handleReset(), handleSearch(), WebSocketClient, TableCache, emit()
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.1
|
||||
Nodes (2): WebSocketClient, TableCache
|
||||
Cohesion: 0.06
|
||||
Nodes (12): collectIds(), useSettingsHandlers(), useSettingsPanel(), useSettingsState(), ComponentLoader, RoutePermissionValidator, RouteTransformer, useCeremony() (+4 more)
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.07
|
||||
@@ -123,68 +126,68 @@ Nodes (21): auditorDisplay(), dash(), expressName(), formatYm(), formatYmd(), sa
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.09
|
||||
Nodes (8): getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, getSystemStorage(), getSysVersion(), StorageKeyManager, StorageCompatibilityManager, validateStorageData()
|
||||
Nodes (30): base64ToBytes(), bytesToBase64(), decryptJson(), deriveKey(), encryptJson(), fromBase64Url(), hexToBytes(), sha256Hex() (+22 more)
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.09
|
||||
Nodes (29): base64ToBytes(), bytesToBase64(), decryptJson(), deriveKey(), encryptJson(), fromBase64Url(), hexToBytes(), sha256Hex() (+21 more)
|
||||
Nodes (8): getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, getSystemStorage(), getSysVersion(), StorageKeyManager, StorageCompatibilityManager, validateStorageData()
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.11
|
||||
Nodes (8): disableDevTools(), handleLock(), handleUnlock(), isMobile(), toLogin(), logOut(), systemUpgrade(), VersionManager
|
||||
Cohesion: 0.09
|
||||
Nodes (16): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateMenu(), postorder(), preorder(), applyTreeExpand(), handleAdd() (+8 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.1
|
||||
Nodes (16): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateMenu(), postorder(), preorder(), applyTreeExpand(), handleAdd() (+8 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.1
|
||||
Nodes (8): fetchGetMenuList(), fetchGetMenuCodes(), fetchLogin(), fetchRefreshToken(), MenuProcessor, useAppMode(), useAuth(), buildWebEncryptedLoginBody()
|
||||
|
||||
### Community 16 - "Community 16"
|
||||
Cohesion: 0.1
|
||||
Nodes (13): fetchEthnicList(), addSample(), applyDonationBundleToForm(), confirmBatchTransportApply(), createEmptyTransport(), ensureDonationProtocolNoInOptions(), ensureEthnicOptionInList(), handleOpenForAdd() (+5 more)
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.12
|
||||
Nodes (15): addCopyButton(), highlightCode(), insertLineNumbers(), isBlockProcessed(), markBlockAsProcessed(), processBlock(), setupHighlightDirective(), setupRippleDirective() (+7 more)
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
### Community 16 - "Community 16"
|
||||
Cohesion: 0.14
|
||||
Nodes (17): fetchCreateUser(), fetchDeleteUser(), fetchResetPassword(), fetchUpdateUser(), fetchUserDetail(), formatUserDeptDisplay(), handleAdd(), handleDelete() (+9 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.11
|
||||
Nodes (8): fetchCollectionProtocolAuditList(), fetchCollectionProtocolDetail(), fetchCollectionProtocolList(), fetchPaymentDetailList(), fetchReceiptConfirmedList(), fetchReceiptConfirmList(), fetchRefundConfirmedList(), fetchRefundConfirmList()
|
||||
### Community 17 - "Community 17"
|
||||
Cohesion: 0.15
|
||||
Nodes (15): fetchProcessRouteList(), fetchConfigureTempProductionWorkOrder(), fetchCreateTempProductionWorkOrder(), fetchDeleteTempProductionWorkOrder(), fetchTempProductionWorkOrderDetail(), fetchTempProductionWorkOrderList(), handleConfigure(), handleDelete() (+7 more)
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
### Community 18 - "Community 18"
|
||||
Cohesion: 0.19
|
||||
Nodes (3): fetchGetLatestUpgradeLog(), systemUpgrade(), VersionManager
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.12
|
||||
Nodes (12): fetchApproveTask(), fetchBusinessAllTasks(), fetchCompletedTasks(), fetchDesignerData(), fetchInstanceDetail(), fetchMyInstances(), fetchPendingTasks(), fetchProcessDefList() (+4 more)
|
||||
|
||||
### Community 21 - "Community 21"
|
||||
### Community 20 - "Community 20"
|
||||
Cohesion: 0.16
|
||||
Nodes (10): useTable(), useTableImpl(), getColumnChecks(), useTableColumns(), createErrorHandler(), createSmartDebounce(), defaultResponseAdapter(), extractPagination() (+2 more)
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
### Community 21 - "Community 21"
|
||||
Cohesion: 0.27
|
||||
Nodes (14): useChart(), useChartComponent(), useChartOps(), colourBlend(), getCssVar(), getDarkColor(), getLightColor(), handleElementThemeColor() (+6 more)
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.18
|
||||
Nodes (11): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), handleAdd(), handleDelete(), handleReset(), handleSearch() (+3 more)
|
||||
### Community 22 - "Community 22"
|
||||
Cohesion: 0.17
|
||||
Nodes (12): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), handleAdd(), handleBatchDelete(), handleDelete(), handleReset() (+4 more)
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.17
|
||||
Nodes (3): fetchResearchDonationAuditList(), fetchResearchDonationDetail(), fetchResearchDonationList()
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
### Community 25 - "Community 25"
|
||||
Cohesion: 0.18
|
||||
Nodes (3): fetchMaterialList(), fetchMaterialOptions(), fetchMaterialStockLogList()
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.2
|
||||
Nodes (2): fetchQcMaterialList(), fetchQcMaterialOptions()
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.32
|
||||
Nodes (3): annotateForkEdges(), chainApiToElements(), nextAncestorLink()
|
||||
|
||||
### Community 29 - "Community 29"
|
||||
Cohesion: 0.39
|
||||
Nodes (6): isIgnorableScriptError(), normalizeErrorMessage(), registerPromiseErrorHandler(), registerResourceErrorHandler(), scriptErrorHandler(), setupErrorHandle()
|
||||
@@ -194,92 +197,108 @@ Cohesion: 0.36
|
||||
Nodes (1): TableHeightCalculator
|
||||
|
||||
### Community 31 - "Community 31"
|
||||
Cohesion: 0.25
|
||||
Nodes (2): fetchQcTaskDetail(), fetchQcTaskList()
|
||||
|
||||
### Community 32 - "Community 32"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): logApiCryptoBootInfo(), maskSecret()
|
||||
|
||||
### Community 32 - "Community 32"
|
||||
### Community 33 - "Community 33"
|
||||
Cohesion: 0.29
|
||||
Nodes (2): fetchLeaveDetail(), fetchLeaveList()
|
||||
|
||||
### Community 34 - "Community 34"
|
||||
Cohesion: 0.47
|
||||
Nodes (3): isPaymentDueWithinWarnWindow(), parsePaymentDueYmd(), startOfLocalDay()
|
||||
|
||||
### Community 34 - "Community 34"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcThirdPartyItemList(), fetchQcThirdPartyItemsActive()
|
||||
|
||||
### Community 35 - "Community 35"
|
||||
### Community 36 - "Community 36"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcThirdPartyCompanyList(), fetchQcThirdPartyCompanyOptions()
|
||||
|
||||
### Community 36 - "Community 36"
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcLabTestItemList(), fetchQcLabTestItemsActive()
|
||||
|
||||
### Community 37 - "Community 37"
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcTaskDetail(), fetchQcTaskList()
|
||||
Nodes (2): fetchTempQcWorkOrderDetail(), fetchTempQcWorkOrderList()
|
||||
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcWorkOrderDetail(), fetchQcWorkOrderList()
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
Cohesion: 0.53
|
||||
Nodes (4): isEtaTodayOrEarlier(), parseEtaLocalDate(), sampleReceptionRowClassName(), startOfLocalDay()
|
||||
|
||||
### Community 40 - "Community 40"
|
||||
### Community 42 - "Community 42"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): focusInput(), handleKeydown()
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
### Community 44 - "Community 44"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): if(), logSidebarMenu()
|
||||
|
||||
### Community 42 - "Community 42"
|
||||
### Community 45 - "Community 45"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): fetchStorageEntrySmsList()
|
||||
|
||||
### Community 46 - "Community 46"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): fetchSampleSmsNotificationList()
|
||||
|
||||
### Community 43 - "Community 43"
|
||||
### Community 47 - "Community 47"
|
||||
Cohesion: 1.0
|
||||
Nodes (2): getSettingDefaults(), resetToDefaults()
|
||||
|
||||
### Community 45 - "Community 45"
|
||||
### Community 49 - "Community 49"
|
||||
Cohesion: 1.0
|
||||
Nodes (2): defaultAvatarPathByRole(), resolveUserAvatarUrl()
|
||||
|
||||
## Knowledge Gaps
|
||||
- **Thin community `Community 9`** (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 27`** (10 nodes): `fetchBatchStockInQcMaterial()`, `fetchBatchStockOutQcMaterial()`, `fetchCreateQcMaterial()`, `fetchDeleteQcMaterial()`, `fetchQcMaterialList()`, `fetchQcMaterialOptions()`, `fetchStockInQcMaterial()`, `fetchStockOutQcMaterial()`, `fetchUpdateQcMaterial()`, `qc-material.ts`
|
||||
- **Thin community `Community 26`** (10 nodes): `fetchBatchStockInQcMaterial()`, `fetchBatchStockOutQcMaterial()`, `fetchCreateQcMaterial()`, `fetchDeleteQcMaterial()`, `fetchQcMaterialList()`, `fetchQcMaterialOptions()`, `fetchStockInQcMaterial()`, `fetchStockOutQcMaterial()`, `fetchUpdateQcMaterial()`, `qc-material.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 30`** (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 31`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
|
||||
- **Thin community `Community 31`** (8 nodes): `fetchCompleteQcTask()`, `fetchCreateQcTask()`, `fetchDeleteQcTask()`, `fetchQcTaskDetail()`, `fetchQcTaskList()`, `fetchStartQcTask()`, `fetchUpdateQcTaskAttachments()`, `qc-task.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 34`** (6 nodes): `fetchCreateQcThirdPartyItem()`, `fetchDeleteQcThirdPartyItem()`, `fetchQcThirdPartyItemList()`, `fetchQcThirdPartyItemsActive()`, `fetchUpdateQcThirdPartyItem()`, `qc-third-party-item.ts`
|
||||
- **Thin community `Community 32`** (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 35`** (6 nodes): `fetchCreateQcThirdPartyCompany()`, `fetchDeleteQcThirdPartyCompany()`, `fetchQcThirdPartyCompanyList()`, `fetchQcThirdPartyCompanyOptions()`, `fetchUpdateQcThirdPartyCompany()`, `qc-third-party-company.ts`
|
||||
- **Thin community `Community 33`** (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 36`** (6 nodes): `fetchCreateQcLabTestItem()`, `fetchDeleteQcLabTestItem()`, `fetchQcLabTestItemList()`, `fetchQcLabTestItemsActive()`, `fetchUpdateQcLabTestItem()`, `qc-lab-test-item.ts`
|
||||
- **Thin community `Community 36`** (6 nodes): `fetchCreateQcThirdPartyCompany()`, `fetchDeleteQcThirdPartyCompany()`, `fetchQcThirdPartyCompanyList()`, `fetchQcThirdPartyCompanyOptions()`, `fetchUpdateQcThirdPartyCompany()`, `qc-third-party-company.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 37`** (6 nodes): `fetchCompleteQcTask()`, `fetchQcTaskDetail()`, `fetchQcTaskList()`, `fetchStartQcTask()`, `fetchUpdateQcTaskAttachments()`, `qc-task.ts`
|
||||
- **Thin community `Community 37`** (6 nodes): `fetchCreateQcLabTestItem()`, `fetchDeleteQcLabTestItem()`, `fetchQcLabTestItemList()`, `fetchQcLabTestItemsActive()`, `fetchUpdateQcLabTestItem()`, `qc-lab-test-item.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 40`** (5 nodes): `focusInput()`, `handleKeydown()`, `if()`, `search()`, `index.vue`
|
||||
- **Thin community `Community 38`** (6 nodes): `fetchConfigureTempQcWorkOrder()`, `fetchCreateTempQcWorkOrder()`, `fetchDeleteTempQcWorkOrder()`, `fetchTempQcWorkOrderDetail()`, `fetchTempQcWorkOrderList()`, `temp-qc-work-order.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 41`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
|
||||
- **Thin community `Community 39`** (6 nodes): `fetchConfigureQcWorkOrder()`, `fetchCreateQcWorkOrder()`, `fetchDeleteQcWorkOrder()`, `fetchQcWorkOrderDetail()`, `fetchQcWorkOrderList()`, `qc-work-order.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 42`** (4 nodes): `fetchGenerateSms()`, `fetchSampleSmsNotificationList()`, `fetchToggleSmsNotified()`, `sample-sms-notification.ts`
|
||||
- **Thin community `Community 42`** (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 43`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
|
||||
- **Thin community `Community 44`** (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 45`** (3 nodes): `defaultAvatarPathByRole()`, `resolveUserAvatarUrl()`, `user-avatar.ts`
|
||||
- **Thin community `Community 45`** (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 46`** (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 47`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 49`** (3 nodes): `defaultAvatarPathByRole()`, `resolveUserAvatarUrl()`, `user-avatar.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 3`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 14`, `Community 15`, `Community 16`, `Community 18`, `Community 19`, `Community 20`, `Community 23`, `Community 25`, `Community 26`, `Community 27`, `Community 34`, `Community 35`, `Community 36`, `Community 37`, `Community 42`?**
|
||||
_High betweenness centrality (0.293) - this node is a cross-community bridge._
|
||||
- **Why does `push()` connect `Community 4` to `Community 0`, `Community 6`, `Community 8`, `Community 9`, `Community 13`, `Community 16`?**
|
||||
_High betweenness centrality (0.117) - this node is a cross-community bridge._
|
||||
- **Why does `handleDynamicRoutes()` connect `Community 2` to `Community 8`, `Community 15`?**
|
||||
_High betweenness centrality (0.049) - this node is a cross-community bridge._
|
||||
- **Are the 163 inferred relationships involving `get()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `buildTreePathLabelFromFlat()`) actually correct?**
|
||||
_`get()` has 163 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 13`, `Community 14`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 22`, `Community 24`, `Community 25`, `Community 26`, `Community 28`, `Community 31`, `Community 33`, `Community 36`, `Community 37`, `Community 38`, `Community 39`, `Community 45`, `Community 46`?**
|
||||
_High betweenness centrality (0.311) - this node is a cross-community bridge._
|
||||
- **Why does `push()` connect `Community 3` to `Community 0`, `Community 6`, `Community 8`, `Community 9`, `Community 14`, `Community 18`?**
|
||||
_High betweenness centrality (0.100) - this node is a cross-community bridge._
|
||||
- **Why does `fetchGetLatestUpgradeLog()` connect `Community 18` to `Community 0`?**
|
||||
_High betweenness centrality (0.044) - this node is a cross-community bridge._
|
||||
- **Are the 169 inferred relationships involving `get()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `buildTreePathLabelFromFlat()`) actually correct?**
|
||||
_`get()` has 169 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 19 inferred relationships involving `push()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `fetchAllPagedRecords()`) actually correct?**
|
||||
_`push()` has 19 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 16 inferred relationships involving `withFullscreenLoading()` (e.g. with `.close()` and `handleSubmit()`) actually correct?**
|
||||
|
||||
@@ -57,12 +57,12 @@
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">1528 nodes · 1917 edges · 247 communities</div>
|
||||
<div id="stats">1581 nodes · 1982 edges · 257 communities</div>
|
||||
</div>
|
||||
<script>
|
||||
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 31, "community_name": "Community 31", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 31, "community_name": "Community 31", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 31, "community_name": "Community 31", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 31, "community_name": "Community 31", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 31, "community_name": "Community 31", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 31, "community_name": "Community 31", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 78, "community_name": "Community 78", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 79, "community_name": "Community 79", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 17, "community_name": "Community 17", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.7, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 17, "community_name": "Community 17", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 17, "community_name": "Community 17", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 17, "community_name": "Community 17", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 17, "community_name": "Community 17", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_setuprolesdirective", "laLine 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": 237}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 99}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 69}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 65}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 64}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 62}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 51}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 50}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 47}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 42}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 42}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 37}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 37}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 28}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 28}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 27}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 27}, {"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": 19}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 19}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 17}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 16}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 15}, {"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": 11}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 10}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 9}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 8}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 8}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 7}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 6}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 6}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 6}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 6}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 6}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 6}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 6}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 6}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 5}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 4}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 4}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 3}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 3}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 3}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 3}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 3}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 3}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 3}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 3}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 3}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 3}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 2}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 2}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 2}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 2}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 2}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 2}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 2}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 2}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 2}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 2}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 2}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 2}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 2}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 2}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 2}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 2}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 2}, {"cid": 70, "color": "#4E79A7", "label": "Community 70", "count": 2}, {"ciLine truncated
|
||||
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 32, "community_name": "Community 32", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 32, "community_name": "Community 32", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 32, "community_name": "Community 32", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 32, "community_name": "Community 32", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 32, "community_name": "Community 32", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 32, "community_name": "Community 32", "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": 83, "community_name": "Community 83", "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": 84, "community_name": "Community 84", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 15, "community_name": "Community 15", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.7, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 15, "community_name": "Community 15", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 15, "community_name": "Community 15", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 15, "community_name": "Community 15", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 15, "community_name": "Community 15", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_setuprolesdirective", "laLine 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": 247}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 102}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 96}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 64}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 64}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 63}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 51}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 51}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 48}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 47}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 42}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 38}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 36}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 29}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 27}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 22}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 20}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 20}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 19}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 19}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 17}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 16}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 16}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 13}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 12}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 11}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 10}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 9}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 8}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 8}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 8}, {"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": 7}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 6}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 6}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 6}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 6}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 6}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 6}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 6}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 6}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 5}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 5}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 4}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 4}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 4}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 3}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 3}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 3}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 3}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 3}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 3}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 3}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 3}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 3}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 3}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 2}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 2}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 2}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 2}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 2}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 2}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 2}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 2}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 2}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 2}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 2}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 2}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 2}, {"cid": 70, "color": "#4E79A7", "label": "Community 70", "count": 2}, {"ciLine truncated
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
|
||||
+2280
-1023
File diff suppressed because it is too large.
Load diff
@@ -17,8 +17,8 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/common/index.ts": 1778582068.0254738,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/directive/directive.d.ts": 1778582068.026978,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/api/api.d.ts": 1778582068.0246184,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1779591450.358872,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1779591016.4400284,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1779604315.8915417,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1779604032.215516,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/store/index.ts": 1778582068.0293276,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/router/index.ts": 1778775532.895603,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/locales/index.ts": 1778582068.004279,
|
||||
@@ -44,7 +44,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/fullscreen-loading.ts": 1779117454.818312,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts": 1778582068.0393815,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-labels.ts": 1779199125.4894068,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts": 1779491563.5260131,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts": 1779591615.5295093,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/fetch-paged-list.ts": 1778775532.895782,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/sort-order.ts": 1778775532.8963482,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/tree-path.ts": 1778800847.103174,
|
||||
@@ -201,7 +201,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-third-party-item.ts": 1779017836.101254,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/storage-release-review.ts": 1779521577.6135197,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/workflow.ts": 1778729873.096252,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts": 1779586811.7854557,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts": 1779600111.2513275,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task-result.ts": 1779332042.258692,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-third-party-company.ts": 1779021425.3773527,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/collection-protocol.ts": 1779244706.1724706,
|
||||
@@ -211,19 +211,21 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/admin.ts": 1779418057.065808,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/ethnic.ts": 1778929297.3919344,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-lab-test-item.ts": 1779017838.8231559,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts": 1779339624.2590876,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts": 1779594447.3049195,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/sample-sms-notification.ts": 1779526400.8134577,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/research-donation.ts": 1779160004.1431847,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts": 1779182848.881475,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts": 1779602723.2575788,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-item-param.ts": 1779022632.5658252,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task.ts": 1779586811.7854652,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts": 1779602838.322659,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts": 1779602786.8834233,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-material-usage.ts": 1779284726.00147,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-material.ts": 1779283280.0705447,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/system.ts": 1778582067.862994,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/material.ts": 1779283387.4196396,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/sample-reception.ts": 1779255909.8553667,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/auth.ts": 1778582067.8610063,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts": 1779431182.2279022,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts": 1779600090.8001392,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/auth/login/index.vue": 1779525781.6116724,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/refund-confirm/index.vue": 1779525781.6125906,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/index.vue": 1779543540.7143836,
|
||||
@@ -277,17 +279,26 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/system/dept/index.vue": 1779543540.7411766,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/system/dict/index.vue": 1779543540.7390752,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/system/leave/index.vue": 1779543540.7368186,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue": 1779602838.3227367,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/output-type/index.vue": 1779543540.722031,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/index.vue": 1779590060.1180878,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/index.vue": 1779600859.6291723,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/SourceChainGraph.vue": 1779601463.4693549,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainLinkEdge.vue": 1779601451.8287098,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainInject.ts": 1779601450.6340923,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chain-types.ts": 1779601448.2115095,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainFlowTheme.ts": 1779601377.1288052,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainNodeCard.vue": 1779600815.2857296,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/SampleCustomerViewDialog.vue": 1779600821.8288937,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts": 1779601450.3906622,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue": 1779543540.7289982,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/sop/index.vue": 1779543540.726837,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-task/index.vue": 1779586846.3205786,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-task/index.vue": 1779602728.4930344,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/reagent/index.vue": 1779589143.1296964,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue": 1779586813.5815248,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue": 1779602286.5549738,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts": 1779590059.4362776,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue": 1779525781.678735,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskInputEnhancedTable.vue": 1779525781.679505,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue": 1779525781.680895,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue": 1779601455.886211,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue": 1779525781.6816807,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputList.vue": 1779525781.6822913,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue": 1779525781.6835842,
|
||||
@@ -297,12 +308,13 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process/index.vue": 1779543540.717012,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-category/index.vue": 1779543540.7154598,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/index/index.vue": 1779525781.6949234,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue": 1779543540.7031858,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue": 1779602482.5582962,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception-check-item/index.vue": 1779543540.7019148,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/lab-test-item/index.vue": 1779543540.7013087,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-material/index.vue": 1779543540.7000535,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue": 1779543540.698455,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue": 1779586314.29511,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue": 1779604458.3034396,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue": 1779602725.6401753,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/storage-release-review/index.vue": 1779543540.695075,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/storage-release-review/StorageReleaseReviewDialog.vue": 1779525781.7374997,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/storage-release-review/StorageReleaseViewDialog.vue": 1779525781.743236,
|
||||
@@ -342,7 +354,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/core/RoutePermissionValidator.ts": 1778582068.0127926,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/core/index.ts": 1778582068.0138035,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/core/IframeRouteManager.ts": 1778582068.0121944,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/sqxp.ts": 1779528258.7914715,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/sqxp.ts": 1779603531.1964977,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/index.ts": 1778598510.6043763,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/exception.ts": 1779546186.993006,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/routes/staticRoutes.ts": 1779546226.1088154,
|
||||
|
||||
@@ -58,12 +58,14 @@
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
"@iconify/vue": "^5.0.0",
|
||||
"@tailwindcss/vite": "^4.1.14",
|
||||
"@vue-flow/core": "^1.48.2",
|
||||
"@vue/reactivity": "^3.5.21",
|
||||
"@vueuse/core": "^13.9.0",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "next",
|
||||
"axios": "^1.12.2",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dagre": "^0.8.5",
|
||||
"echarts": "^6.0.0",
|
||||
"element-plus": "^2.11.2",
|
||||
"exceljs": "^4.4.0",
|
||||
@@ -89,6 +91,7 @@
|
||||
"@commitlint/cli": "^19.4.1",
|
||||
"@commitlint/config-conventional": "^19.4.1",
|
||||
"@eslint/js": "^9.9.1",
|
||||
"@types/dagre": "^0.7.54",
|
||||
"@types/node": "^24.0.5",
|
||||
"@typescript-eslint/eslint-plugin": "^8.3.0",
|
||||
"@typescript-eslint/parser": "^8.3.0",
|
||||
|
||||
Generated
+152
@@ -20,6 +20,9 @@ importers:
|
||||
'@tailwindcss/vite':
|
||||
specifier: ^4.1.14
|
||||
version: 4.1.14(vite@7.1.7(@types/node@24.8.1)(jiti@2.6.0)(lightningcss@1.30.1)(sass@1.93.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
|
||||
'@vue-flow/core':
|
||||
specifier: ^1.48.2
|
||||
version: 1.48.2(vue@3.5.22(typescript@5.6.3))
|
||||
'@vue/reactivity':
|
||||
specifier: ^3.5.21
|
||||
version: 3.5.22
|
||||
@@ -38,6 +41,9 @@ importers:
|
||||
crypto-js:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
dagre:
|
||||
specifier: ^0.8.5
|
||||
version: 0.8.5
|
||||
echarts:
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0
|
||||
@@ -108,6 +114,9 @@ importers:
|
||||
'@eslint/js':
|
||||
specifier: ^9.9.1
|
||||
version: 9.36.0
|
||||
'@types/dagre':
|
||||
specifier: ^0.7.54
|
||||
version: 0.7.54
|
||||
'@types/node':
|
||||
specifier: ^24.0.5
|
||||
version: 24.8.1
|
||||
@@ -1131,6 +1140,9 @@ packages:
|
||||
'@types/conventional-commits-parser@5.0.1':
|
||||
resolution: {integrity: sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==}
|
||||
|
||||
'@types/dagre@0.7.54':
|
||||
resolution: {integrity: sha512-QjcRY+adGbYvBFS7cwv5txhVIwX1XXIUswWl+kSQTbI6NjgZydrZkEKX/etzVd7i+bCsCb40Z/xlBY5eoFuvWQ==}
|
||||
|
||||
'@types/estree@1.0.8':
|
||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||
|
||||
@@ -1158,6 +1170,9 @@ packages:
|
||||
'@types/web-bluetooth@0.0.16':
|
||||
resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
|
||||
|
||||
'@types/web-bluetooth@0.0.20':
|
||||
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
|
||||
|
||||
'@types/web-bluetooth@0.0.21':
|
||||
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
|
||||
|
||||
@@ -1253,6 +1268,11 @@ packages:
|
||||
'@volar/typescript@2.4.23':
|
||||
resolution: {integrity: sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==}
|
||||
|
||||
'@vue-flow/core@1.48.2':
|
||||
resolution: {integrity: sha512-raxhgKWE+G/mcEvXJjGFUDYW9rAI3GOtiHR3ZkNpwBWuIaCC1EYiBmKGwJOoNzVFgwO7COgErnK7i08i287AFA==}
|
||||
peerDependencies:
|
||||
vue: ^3.3.0
|
||||
|
||||
'@vue/babel-helper-vue-transform-on@1.5.0':
|
||||
resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==}
|
||||
|
||||
@@ -1326,6 +1346,9 @@ packages:
|
||||
'@vue/shared@3.5.22':
|
||||
resolution: {integrity: sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==}
|
||||
|
||||
'@vueuse/core@10.11.1':
|
||||
resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==}
|
||||
|
||||
'@vueuse/core@13.9.0':
|
||||
resolution: {integrity: sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA==}
|
||||
peerDependencies:
|
||||
@@ -1334,12 +1357,18 @@ packages:
|
||||
'@vueuse/core@9.13.0':
|
||||
resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
|
||||
|
||||
'@vueuse/metadata@10.11.1':
|
||||
resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==}
|
||||
|
||||
'@vueuse/metadata@13.9.0':
|
||||
resolution: {integrity: sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==}
|
||||
|
||||
'@vueuse/metadata@9.13.0':
|
||||
resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
|
||||
|
||||
'@vueuse/shared@10.11.1':
|
||||
resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==}
|
||||
|
||||
'@vueuse/shared@13.9.0':
|
||||
resolution: {integrity: sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==}
|
||||
peerDependencies:
|
||||
@@ -1832,10 +1861,51 @@ packages:
|
||||
resolution: {integrity: sha512-LaZ+8whPPUOo6Y0Zy4nIbf6JOleV3ejp41sT6N4RPKiKKA+ICWf4ueeIlxIO8b6JtdlDxRzHH/EcRji07nDxcg==}
|
||||
engines: {node: '>=v12.20.0'}
|
||||
|
||||
d3-color@3.1.0:
|
||||
resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-dispatch@3.0.1:
|
||||
resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-drag@3.0.0:
|
||||
resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-ease@3.0.1:
|
||||
resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-interpolate@3.0.1:
|
||||
resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-selection@3.0.0:
|
||||
resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-timer@3.0.1:
|
||||
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-transition@3.0.1:
|
||||
resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
d3-selection: 2 - 3
|
||||
|
||||
d3-zoom@3.0.0:
|
||||
resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d@1.0.2:
|
||||
resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
dagre@0.8.5:
|
||||
resolution: {integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==}
|
||||
|
||||
danmu.js@1.1.13:
|
||||
resolution: {integrity: sha512-knFd0/cB2HA4FFWiA7eB2suc5vCvoHdqio33FyyCSfP7C+1A+zQcTvnvwfxaZhrxsGj4qaQI2I8XiTqedRaVmg==}
|
||||
|
||||
@@ -2409,6 +2479,9 @@ packages:
|
||||
graphemer@1.4.0:
|
||||
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
|
||||
|
||||
graphlib@2.1.8:
|
||||
resolution: {integrity: sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==}
|
||||
|
||||
has-flag@3.0.0:
|
||||
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -4962,6 +5035,8 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/node': 24.8.1
|
||||
|
||||
'@types/dagre@0.7.54': {}
|
||||
|
||||
'@types/estree@1.0.8': {}
|
||||
|
||||
'@types/event-emitter@0.3.5': {}
|
||||
@@ -4984,6 +5059,8 @@ snapshots:
|
||||
|
||||
'@types/web-bluetooth@0.0.16': {}
|
||||
|
||||
'@types/web-bluetooth@0.0.20': {}
|
||||
|
||||
'@types/web-bluetooth@0.0.21': {}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.6.3))(eslint@9.36.0(jiti@2.6.0))(typescript@5.6.3)':
|
||||
@@ -5126,6 +5203,17 @@ snapshots:
|
||||
path-browserify: 1.0.1
|
||||
vscode-uri: 3.1.0
|
||||
|
||||
'@vue-flow/core@1.48.2(vue@3.5.22(typescript@5.6.3))':
|
||||
dependencies:
|
||||
'@vueuse/core': 10.11.1(vue@3.5.22(typescript@5.6.3))
|
||||
d3-drag: 3.0.0
|
||||
d3-interpolate: 3.0.1
|
||||
d3-selection: 3.0.0
|
||||
d3-zoom: 3.0.0
|
||||
vue: 3.5.22(typescript@5.6.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
|
||||
'@vue/babel-helper-vue-transform-on@1.5.0': {}
|
||||
|
||||
'@vue/babel-plugin-jsx@1.5.0(@babel/core@7.28.4)':
|
||||
@@ -5259,6 +5347,16 @@ snapshots:
|
||||
|
||||
'@vue/shared@3.5.22': {}
|
||||
|
||||
'@vueuse/core@10.11.1(vue@3.5.22(typescript@5.6.3))':
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.20
|
||||
'@vueuse/metadata': 10.11.1
|
||||
'@vueuse/shared': 10.11.1(vue@3.5.22(typescript@5.6.3))
|
||||
vue-demi: 0.14.10(vue@3.5.22(typescript@5.6.3))
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
||||
'@vueuse/core@13.9.0(vue@3.5.22(typescript@5.6.3))':
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.21
|
||||
@@ -5276,10 +5374,19 @@ snapshots:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
||||
'@vueuse/metadata@10.11.1': {}
|
||||
|
||||
'@vueuse/metadata@13.9.0': {}
|
||||
|
||||
'@vueuse/metadata@9.13.0': {}
|
||||
|
||||
'@vueuse/shared@10.11.1(vue@3.5.22(typescript@5.6.3))':
|
||||
dependencies:
|
||||
vue-demi: 0.14.10(vue@3.5.22(typescript@5.6.3))
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
||||
'@vueuse/shared@13.9.0(vue@3.5.22(typescript@5.6.3))':
|
||||
dependencies:
|
||||
vue: 3.5.22(typescript@5.6.3)
|
||||
@@ -5819,11 +5926,52 @@ snapshots:
|
||||
|
||||
cz-git@1.12.0: {}
|
||||
|
||||
d3-color@3.1.0: {}
|
||||
|
||||
d3-dispatch@3.0.1: {}
|
||||
|
||||
d3-drag@3.0.0:
|
||||
dependencies:
|
||||
d3-dispatch: 3.0.1
|
||||
d3-selection: 3.0.0
|
||||
|
||||
d3-ease@3.0.1: {}
|
||||
|
||||
d3-interpolate@3.0.1:
|
||||
dependencies:
|
||||
d3-color: 3.1.0
|
||||
|
||||
d3-selection@3.0.0: {}
|
||||
|
||||
d3-timer@3.0.1: {}
|
||||
|
||||
d3-transition@3.0.1(d3-selection@3.0.0):
|
||||
dependencies:
|
||||
d3-color: 3.1.0
|
||||
d3-dispatch: 3.0.1
|
||||
d3-ease: 3.0.1
|
||||
d3-interpolate: 3.0.1
|
||||
d3-selection: 3.0.0
|
||||
d3-timer: 3.0.1
|
||||
|
||||
d3-zoom@3.0.0:
|
||||
dependencies:
|
||||
d3-dispatch: 3.0.1
|
||||
d3-drag: 3.0.0
|
||||
d3-interpolate: 3.0.1
|
||||
d3-selection: 3.0.0
|
||||
d3-transition: 3.0.1(d3-selection@3.0.0)
|
||||
|
||||
d@1.0.2:
|
||||
dependencies:
|
||||
es5-ext: 0.10.64
|
||||
type: 2.7.3
|
||||
|
||||
dagre@0.8.5:
|
||||
dependencies:
|
||||
graphlib: 2.1.8
|
||||
lodash: 4.17.21
|
||||
|
||||
danmu.js@1.1.13:
|
||||
dependencies:
|
||||
event-emitter: 0.3.5
|
||||
@@ -6485,6 +6633,10 @@ snapshots:
|
||||
|
||||
graphemer@1.4.0: {}
|
||||
|
||||
graphlib@2.1.8:
|
||||
dependencies:
|
||||
lodash: 4.17.21
|
||||
|
||||
has-flag@3.0.0: {}
|
||||
|
||||
has-flag@4.0.0: {}
|
||||
|
||||
@@ -6,6 +6,7 @@ export function fetchCellProductList(params?: {
|
||||
keyword?: string
|
||||
productStatus?: string
|
||||
passage?: string
|
||||
sourceType?: string
|
||||
}) {
|
||||
return request.get<{
|
||||
list: any[]
|
||||
@@ -38,3 +39,7 @@ export function fetchNextCellProductCode(count = 1) {
|
||||
params: count > 1 ? { count } : undefined
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchCellProductChain(productId: string) {
|
||||
return request.get<any>({ url: `/web/admin/cell-products/${productId}/chain` })
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import type { QcWorkOrderReceptionDetail } from '@/api/qc-work-order'
|
||||
export interface ProductionWorkOrderItem {
|
||||
id: string
|
||||
workOrderNo: string
|
||||
workOrderType?: string
|
||||
protocolNo?: string
|
||||
sampleCode?: string
|
||||
receptionSource?: string
|
||||
@@ -25,6 +26,7 @@ export function fetchProductionWorkOrderList(params?: {
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
workOrderStatus?: string
|
||||
workOrderType?: string
|
||||
}) {
|
||||
return request.get<{
|
||||
list: ProductionWorkOrderItem[]
|
||||
@@ -42,3 +44,36 @@ export function fetchProductionWorkOrderDetail(id: string) {
|
||||
export function fetchCompleteProductionWorkOrder(id: string, data: Record<string, any>) {
|
||||
return request.put({ url: `/web/admin/production-work-orders/${id}/complete`, params: data })
|
||||
}
|
||||
|
||||
export function fetchCreateProductionWorkOrder(data: {
|
||||
workOrderType?: string
|
||||
protocolNo?: string
|
||||
sampleCode?: string
|
||||
receptionSource?: string
|
||||
remark?: string
|
||||
}) {
|
||||
return request.post<ProductionWorkOrderItem>({
|
||||
url: '/web/admin/production-work-orders',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchConfigureProductionWorkOrder(
|
||||
id: string,
|
||||
data: {
|
||||
taskName?: string
|
||||
taskType?: string
|
||||
routeId?: string
|
||||
description?: string
|
||||
remark?: string
|
||||
}
|
||||
) {
|
||||
return request.post<ProductionWorkOrderItem>({
|
||||
url: `/web/admin/production-work-orders/${id}/configure`,
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchDeleteProductionWorkOrder(id: string) {
|
||||
return request.del({ url: `/web/admin/production-work-orders/${id}` })
|
||||
}
|
||||
@@ -42,6 +42,7 @@ export type QcTask = {
|
||||
id: string
|
||||
workOrderId: string
|
||||
workOrderNo?: string
|
||||
orderSource?: string
|
||||
taskNo: string
|
||||
taskType: string
|
||||
itemCode: string
|
||||
@@ -62,6 +63,12 @@ export type QcTask = {
|
||||
receptionTime?: string
|
||||
handlerName?: string
|
||||
workOrderStatus?: string
|
||||
cellProductId?: string
|
||||
cellProductCode?: string
|
||||
cellProductName?: string
|
||||
cellProductTypeName?: string
|
||||
cellProductPassage?: string
|
||||
cellProductSpecName?: string
|
||||
thirdPartyAttachments?: string
|
||||
attachmentFiles?: Array<{ id?: string; fileUrl: string; fileName?: string; fileType?: string }>
|
||||
completedTime?: string
|
||||
@@ -121,3 +128,25 @@ export function fetchUpdateQcTaskAttachments(id: string, thirdPartyAttachments:
|
||||
data: { thirdPartyAttachments }
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchCreateQcTask(data: {
|
||||
taskType: string
|
||||
itemCode: string
|
||||
itemName: string
|
||||
companyId?: string
|
||||
companyName?: string
|
||||
feeAmount?: number
|
||||
sampleCode?: string
|
||||
qcBizType?: string
|
||||
workOrderId?: string
|
||||
remark?: string
|
||||
}) {
|
||||
return request.post<QcTask>({
|
||||
url: '/web/admin/qc-tasks',
|
||||
params: data
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchDeleteQcTask(id: string) {
|
||||
return request.del({ url: `/web/admin/qc-tasks/${id}` })
|
||||
}
|
||||
@@ -50,6 +50,7 @@ export type QcWorkOrderReceptionDetail = {
|
||||
export type QcWorkOrder = {
|
||||
id: string
|
||||
workOrderNo: string
|
||||
workOrderType?: string
|
||||
receptionId: string
|
||||
protocolSampleId: string
|
||||
collectionProtocolId: string
|
||||
@@ -57,6 +58,14 @@ export type QcWorkOrder = {
|
||||
sampleCode: string
|
||||
receptionSource?: string
|
||||
receptionSourceLabel?: string
|
||||
qcBizType?: string
|
||||
qcBizTypeLabel?: string
|
||||
cellProductId?: string
|
||||
cellProductCode?: string
|
||||
cellProductName?: string
|
||||
cellProductTypeName?: string
|
||||
cellProductPassage?: string
|
||||
cellProductSpecName?: string
|
||||
sampleTypeName?: string
|
||||
receptionTime?: string
|
||||
handlerName?: string
|
||||
@@ -106,6 +115,7 @@ export function fetchQcWorkOrderList(params?: {
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
workOrderStatus?: string
|
||||
workOrderType?: string
|
||||
}) {
|
||||
return request.get<PageList<QcWorkOrder>>({
|
||||
url: '/web/admin/qc-work-orders',
|
||||
@@ -133,3 +143,29 @@ export function fetchConfigureQcWorkOrder(
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchCreateQcWorkOrder(data: {
|
||||
workOrderType?: string
|
||||
protocolNo?: string
|
||||
sampleCode?: string
|
||||
receptionSource?: string
|
||||
qcBizType?: string
|
||||
cellProductId?: string
|
||||
remark?: string
|
||||
}) {
|
||||
return request.post<QcWorkOrder>({
|
||||
url: '/web/admin/qc-work-orders',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchUpdateQcWorkOrder(id: string, data: { cellProductId?: string; remark?: string }) {
|
||||
return request.put<QcWorkOrder>({
|
||||
url: `/web/admin/qc-work-orders/${id}`,
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchDeleteQcWorkOrder(id: string) {
|
||||
return request.del({ url: `/web/admin/qc-work-orders/${id}` })
|
||||
}
|
||||
@@ -91,6 +91,7 @@
|
||||
taskTypeLabel,
|
||||
taskStatusLabel,
|
||||
qcBizTypeLabel,
|
||||
qcBizTypeTagType,
|
||||
receptionSourceLabel,
|
||||
acceptConclusionLabel,
|
||||
transportTypeLabel,
|
||||
@@ -232,6 +233,7 @@
|
||||
const d = viewDetail.value
|
||||
if (!d) return []
|
||||
const r = d.reception || {}
|
||||
const isTempQc = d.qcBizType === 'temporary'
|
||||
const transportFields: ViewSection['fields'] = [
|
||||
{ label: '运输方式', value: transportTypeLabel(String(r.transportType || '')) }
|
||||
]
|
||||
@@ -249,6 +251,62 @@
|
||||
if (r.etaTime) {
|
||||
transportFields.push({ label: '预计到达', value: r.etaTime })
|
||||
}
|
||||
const cellProductSection: ViewSection[] = isTempQc
|
||||
? [
|
||||
{
|
||||
title: '质检对象',
|
||||
fields: [
|
||||
{ label: '产品编码', value: d.cellProductCode || '—' },
|
||||
{ label: '产品名称', value: d.cellProductName || '—' },
|
||||
{ label: '产品类型', value: d.cellProductTypeName || '—' },
|
||||
{ label: '代次', value: d.cellProductPassage || '—' },
|
||||
{ label: '规格', value: d.cellProductSpecName || '—' }
|
||||
]
|
||||
}
|
||||
]
|
||||
: []
|
||||
const sampleSections: ViewSection[] = isTempQc
|
||||
? []
|
||||
: [
|
||||
{
|
||||
title: '样本信息',
|
||||
fields: [
|
||||
{ label: '协议号', value: r.protocolNo || d.protocolNo || '—' },
|
||||
{ label: '样本编码', value: r.sampleCode || d.sampleCode || '—' },
|
||||
{
|
||||
label: '样本来源',
|
||||
value: r.sourceTypeLabel || d.receptionSourceLabel || receptionSourceLabel(d.receptionSource || ''),
|
||||
tagType: 'primary'
|
||||
},
|
||||
{ label: '样本类型', value: r.sampleTypeName || d.sampleTypeName || '—' }
|
||||
]
|
||||
},
|
||||
...(transportFields.length > 1 || r.transportType
|
||||
? [{ title: '运输信息', fields: transportFields }]
|
||||
: []),
|
||||
{
|
||||
title: '样本接收',
|
||||
slot: 'reception-extra',
|
||||
fields: [
|
||||
{ label: '接收时间', value: r.receptionTime || d.receptionTime || '—' },
|
||||
{ label: '接收经手人', value: r.handlerName || d.handlerName || '—' },
|
||||
{
|
||||
label: '接收温度(℃)',
|
||||
value: r.receiveTemperature ? `${r.receiveTemperature}℃` : '—'
|
||||
},
|
||||
{ label: '体积(ml)', value: formatMetric(r.volumeMl) },
|
||||
{ label: '净重(g)', value: formatMetric(r.netWeightG) },
|
||||
{
|
||||
label: '结论',
|
||||
value:
|
||||
r.acceptConclusionLabel ||
|
||||
acceptConclusionLabel(String(r.acceptConclusion || ''))
|
||||
},
|
||||
{ label: '检查项', value: formatCheckResults(r.checkResults), span: true },
|
||||
{ label: '备注', value: r.remark || '—', span: true }
|
||||
]
|
||||
}
|
||||
]
|
||||
const taskResultSummaryFields: ViewSection['fields'] = [
|
||||
{
|
||||
label: '任务状态',
|
||||
@@ -295,7 +353,7 @@
|
||||
title: '任务信息',
|
||||
fields: [
|
||||
{ label: '任务号', value: d.taskNo },
|
||||
{ label: '业务类型', value: d.qcBizTypeLabel || qcBizTypeLabel(d.qcBizType || ''), tagType: 'success' },
|
||||
{ label: '业务类型', value: d.qcBizTypeLabel || qcBizTypeLabel(d.qcBizType || ''), tagType: qcBizTypeTagType(d.qcBizType || '') },
|
||||
{ label: '工单号', value: d.workOrderNo || '—' },
|
||||
{
|
||||
label: '工单状态',
|
||||
@@ -310,44 +368,8 @@
|
||||
{ label: '创建时间', value: d.createTime || '—' }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '样本信息',
|
||||
fields: [
|
||||
{ label: '协议号', value: r.protocolNo || d.protocolNo || '—' },
|
||||
{ label: '样本编码', value: r.sampleCode || d.sampleCode || '—' },
|
||||
{
|
||||
label: '样本来源',
|
||||
value: r.sourceTypeLabel || d.receptionSourceLabel || receptionSourceLabel(d.receptionSource || ''),
|
||||
tagType: 'primary'
|
||||
},
|
||||
{ label: '样本类型', value: r.sampleTypeName || d.sampleTypeName || '—' }
|
||||
]
|
||||
},
|
||||
...(transportFields.length > 1 || r.transportType
|
||||
? [{ title: '运输信息', fields: transportFields }]
|
||||
: []),
|
||||
{
|
||||
title: '样本接收',
|
||||
slot: 'reception-extra',
|
||||
fields: [
|
||||
{ label: '接收时间', value: r.receptionTime || d.receptionTime || '—' },
|
||||
{ label: '接收经手人', value: r.handlerName || d.handlerName || '—' },
|
||||
{
|
||||
label: '接收温度(℃)',
|
||||
value: r.receiveTemperature ? `${r.receiveTemperature}℃` : '—'
|
||||
},
|
||||
{ label: '体积(ml)', value: formatMetric(r.volumeMl) },
|
||||
{ label: '净重(g)', value: formatMetric(r.netWeightG) },
|
||||
{
|
||||
label: '结论',
|
||||
value:
|
||||
r.acceptConclusionLabel ||
|
||||
acceptConclusionLabel(String(r.acceptConclusion || ''))
|
||||
},
|
||||
{ label: '检查项', value: formatCheckResults(r.checkResults), span: true },
|
||||
{ label: '备注', value: r.remark || '—', span: true }
|
||||
]
|
||||
},
|
||||
...cellProductSection,
|
||||
...sampleSections,
|
||||
...resultSection,
|
||||
...tailSections
|
||||
]
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_temp_production_work_order_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L1"}, {"id": "temp_production_work_order_index_statustagtype", "label": "statusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L312"}, {"id": "temp_production_work_order_index_statuslabel", "label": "statusLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L316"}, {"id": "temp_production_work_order_index_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L327"}, {"id": "temp_production_work_order_index_handlesearch", "label": "handleSearch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L343"}, {"id": "temp_production_work_order_index_handlereset", "label": "handleReset()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L348"}, {"id": "temp_production_work_order_index_handleadd", "label": "handleAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L361"}, {"id": "temp_production_work_order_index_submitadd", "label": "submitAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L366"}, {"id": "temp_production_work_order_index_loadrouteoptions", "label": "loadRouteOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L398"}, {"id": "temp_production_work_order_index_handleconfigure", "label": "handleConfigure()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L407"}, {"id": "temp_production_work_order_index_submitconfigure", "label": "submitConfigure()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L419"}, {"id": "temp_production_work_order_index_handleview", "label": "handleView()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L467"}, {"id": "temp_production_work_order_index_handledelete", "label": "handleDelete()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L473"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_temp_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/temp-production-work-order/index.vue", "source_location": "L287", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_temp_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/temp-production-work-order/index.vue", "source_location": "L288", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_temp_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_system_view_dialog_index_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L298", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_temp_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_system_view_dialog_index_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/temp-production-work-order/index.vue", "source_location": "L299", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_temp_prodLine truncated
|
||||
+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": "L104"}, {"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": "L116"}, {"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": "L122"}, {"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": "L137"}, {"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": "L150"}], "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": "L104", "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": "L116", "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": "L122", "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": "L137", "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": "L150", "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": "L110"}, {"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": "L117"}, {"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": "L131"}, {"caller_nid": "api_qc_work_order_fetchcreateqcworkorder", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L144"}, {"caller_nid": "api_qc_work_order_fetchdeleteqcworkorder", "callee": "del", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L151"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_qc_work_order_ts", "label": "temp-qc-work-order.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L1"}, {"id": "api_temp_qc_work_order_fetchtempqcworkorderlist", "label": "fetchTempQcWorkOrderList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L50"}, {"id": "api_temp_qc_work_order_fetchtempqcworkorderdetail", "label": "fetchTempQcWorkOrderDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L62"}, {"id": "api_temp_qc_work_order_fetchcreatetempqcworkorder", "label": "fetchCreateTempQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L68"}, {"id": "api_temp_qc_work_order_fetchconfiguretempqcworkorder", "label": "fetchConfigureTempQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L75"}, {"id": "api_temp_qc_work_order_fetchdeletetempqcworkorder", "label": "fetchDeleteTempQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L90"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_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/temp-qc-work-order.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_qc_work_order_ts", "target": "api_temp_qc_work_order_fetchtempqcworkorderlist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L50", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_qc_work_order_ts", "target": "api_temp_qc_work_order_fetchtempqcworkorderdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L62", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_qc_work_order_ts", "target": "api_temp_qc_work_order_fetchcreatetempqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L68", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_qc_work_order_ts", "target": "api_temp_qc_work_order_fetchconfiguretempqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L75", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_qc_work_order_ts", "target": "api_temp_qc_work_order_fetchdeletetempqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L90", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_temp_qc_work_order_fetchtempqcworkorderlist", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L56"}, {"caller_nid": "api_temp_qc_work_order_fetchtempqcworkorderdetail", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L63"}, {"caller_nid": "api_temp_qc_work_order_fetchcreatetempqcworkorder", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L69"}, {"caller_nid": "api_temp_qc_work_order_fetchconfiguretempqcworkorder", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L84"}, {"caller_nid": "api_temp_qc_work_order_fetchdeletetempqcworkorder", "callee": "del", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-qc-work-order.ts", "source_location": "L91"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chainlinkedge_vue", "label": "ChainLinkEdge.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainLinkEdge.vue", "source_location": "L1"}, {"id": "source_chain_chainlinkedge_handledblclick", "label": "handleDblClick()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainLinkEdge.vue", "source_location": "L94"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chainlinkedge_vue", "target": "source_chain_chainlinkedge_handledblclick", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainLinkEdge.vue", "source_location": "L94", "weight": 1.0}], "raw_calls": [{"caller_nid": "source_chain_chainlinkedge_handledblclick", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainLinkEdge.vue", "source_location": "L95"}, {"caller_nid": "source_chain_chainlinkedge_handledblclick", "callee": "warning", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainLinkEdge.vue", "source_location": "L97"}, {"caller_nid": "source_chain_chainlinkedge_handledblclick", "callee": "openTask", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainLinkEdge.vue", "source_location": "L100"}, {"caller_nid": "source_chain_chainlinkedge_handledblclick", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainLinkEdge.vue", "source_location": "L100"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chainnodecard_vue", "label": "ChainNodeCard.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainNodeCard.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chain_types_ts", "label": "chain-types.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chain-types.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_sourcechaingraph_vue", "label": "SourceChainGraph.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/SourceChainGraph.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+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": "L23"}, {"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": "L38"}, {"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": "L42"}, {"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": "L46"}, {"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": "L58"}], "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": "L23", "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": "L38", "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": "L42", "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": "L46", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "api_production_work_order_fetchdeleteproductionworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L58", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_production_work_order_fetchproductionworkorderlist", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L29"}, {"caller_nid": "api_production_work_order_fetchproductionworkorderdetail", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L39"}, {"caller_nid": "api_production_work_order_fetchcompleteproductionworkorder", "callee": "put", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L43"}, {"caller_nid": "api_production_work_order_fetchcreateproductionworkorder", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L52"}, {"caller_nid": "api_production_work_order_fetchdeleteproductionworkorder", "callee": "del", "source_file": "/Users/wuzilong/work/00code/zkxw/Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chainnodecard_vue", "label": "ChainNodeCard.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainNodeCard.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chain_types_ts", "label": "chain-types.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chain-types.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_sourcechaingraph_vue", "label": "SourceChainGraph.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/SourceChainGraph.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_router_modules_sqxp_ts", "label": "sqxp.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/sqxp.ts", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_router_modules_sqxp_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_types_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/sqxp.ts", "source_location": "L1", "weight": 1.0}], "raw_calls": []}
|
||||
+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_cell_product_source_chain_chaintoflow_ts", "label": "chainToFlow.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L1"}, {"id": "source_chain_chaintoflow_nextancestorlink", "label": "nextAncestorLink()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L16"}, {"id": "source_chain_chaintoflow_makeflownode", "label": "makeFlowNode()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L24"}, {"id": "source_chain_chaintoflow_makeflowedge", "label": "makeFlowEdge()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L33"}, {"id": "source_chain_chaintoflow_chainapitoelements", "label": "chainApiToElements()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L54"}, {"id": "source_chain_chaintoflow_annotateforkedges", "label": "annotateForkEdges()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L109"}, {"id": "source_chain_chaintoflow_layoutchainelements", "label": "layoutChainElements()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L129"}, {"id": "source_chain_chaintoflow_haschaingraphcontent", "label": "hasChainGraphContent()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L168"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "dagre", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "core", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chain_types", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "source_chain_chaintoflow_nextancestorlink", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L16", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "source_chain_chaintoflow_makeflownode", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L24", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "source_chain_chaintoflow_makeflowedge", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L33", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "source_chain_chaintoflow_chainapitoelements", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L54", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "source_chain_chaintoflow_annotateforkedgLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1"}, {"id": "qc_work_order_index_handlereceptionattachmentpreview", "label": "handleReceptionAttachmentPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L391"}, {"id": "qc_work_order_index_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L396"}, {"id": "qc_work_order_index_taskattachmentfullurl", "label": "taskAttachmentFullUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L400"}, {"id": "qc_work_order_index_handletaskattachmentpreview", "label": "handleTaskAttachmentPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L407"}, {"id": "qc_work_order_index_handletaskattachmentdownload", "label": "handleTaskAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L412"}, {"id": "qc_work_order_index_formatconfiguredlabitems", "label": "formatConfiguredLabItems()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L428"}, {"id": "qc_work_order_index_formatconfiguredthirditems", "label": "formatConfiguredThirdItems()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L434"}, {"id": "qc_work_order_index_buildtasktypesections", "label": "buildTaskTypeSections()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L442"}, {"id": "qc_work_order_index_buildconfiguredonlysection", "label": "buildConfiguredOnlySection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L501"}, {"id": "qc_work_order_index_formatdetectmethods", "label": "formatDetectMethods()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L519"}, {"id": "qc_work_order_index_formatmetric", "label": "formatMetric()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L526"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_handlereceptionattachmentpreview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L391", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_handlereceptionattachmentdownload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L396", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_taskattachmentfullurl", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L400", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_handletaskattachmentpreview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L407", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_handletaskattachmentdownload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue",Line truncated
|
||||
+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": "L104"}, {"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": "L116"}, {"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": "L122"}, {"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": "L137"}], "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": "L104", "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": "L116", "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": "L122", "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": "L137", "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": "L110"}, {"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": "L117"}, {"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": "L131"}, {"caller_nid": "api_qc_work_order_fetchcreateqcworkorder", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L144"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L1"}, {"id": "qc_task_index_canfillresult", "label": "canFillResult()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L528"}, {"id": "qc_task_index_clearmaterialrow", "label": "clearMaterialRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L550"}, {"id": "qc_task_index_ismaterialoptiondisabled", "label": "isMaterialOptionDisabled()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L557"}, {"id": "qc_task_index_isduplicatematerial", "label": "isDuplicateMaterial()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L562"}, {"id": "qc_task_index_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L709"}, {"id": "qc_task_index_normalizeresultparams", "label": "normalizeResultParams()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L713"}, {"id": "qc_task_index_toresultnumber", "label": "toResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L721"}, {"id": "qc_task_index_setresultnumber", "label": "setResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L727"}, {"id": "qc_task_index_hasresultvalue", "label": "hasResultValue()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L731"}, {"id": "qc_task_index_formatmetric", "label": "formatMetric()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L735"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_canfillresult", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L528", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_clearmaterialrow", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L550", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_ismaterialoptiondisabled", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L557", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_isduplicatematerial", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L562", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_handlereceptionattachmentdownload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L709", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_normalizeresultparams", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L713", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_toresultnumber", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "label": "qc-task.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L1"}, {"id": "api_qc_task_fetchqctasklist", "label": "fetchQcTaskList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L85"}, {"id": "api_qc_task_fetchqctaskdetail", "label": "fetchQcTaskDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L100"}, {"id": "api_qc_task_fetchstartqctask", "label": "fetchStartQcTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L106"}, {"id": "api_qc_task_fetchcompleteqctask", "label": "fetchCompleteQcTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L112"}, {"id": "api_qc_task_fetchupdateqctaskattachments", "label": "fetchUpdateQcTaskAttachments()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L118"}, {"id": "api_qc_task_fetchcreateqctask", "label": "fetchCreateQcTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L125"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_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-task.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchqctasklist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L85", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchqctaskdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L100", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchstartqctask", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L106", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchcompleteqctask", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L112", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchupdateqctaskattachments", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L118", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchcreateqctask", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L125", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_qc_task_fetchqctasklist", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L94"}, {"caller_nid": "api_qc_task_fetchqctaskdetail", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L101"}, {"caller_nid": "api_qc_task_fetchstartqctask", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L107"}, {"caller_nid": "api_qc_task_fetchcompleteqctask", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L113"}, {"caller_nid": "api_qc_task_fetchupdateqctaskattachments", "callee": "put", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L119"}, {"caller_nid": "api_qc_task_fetchcreateqctask", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L137"}]}
|
||||
+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_handleview", "label": "handleView()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L576"}, {"id": "production_work_order_index_handlecomplete", "label": "handleComplete()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L580"}, {"id": "production_work_order_index_handleopendispatch", "label": "handleOpenDispatch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L590"}, {"id": "production_work_order_index_handleedittask", "label": "handleEditTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L607"}, {"id": "production_work_order_index_opentaskeditor", "label": "openTaskEditor()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L622"}, {"id": "production_work_order_index_openedittaskinfo", "label": "openEditTaskInfo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L634"}, {"id": "production_work_order_index_handleedittaskinfosuccess", "label": "handleEditTaskInfoSuccess()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L639"}, {"id": "production_work_order_index_handledeletetask", "label": "handleDeleteTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L645"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_handleview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L576", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_handlecomplete", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L580", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_handleopendispatch", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L590", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_handleedittask", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L607", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_opentaskeditor", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L622", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_openedittaskinfo", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L634", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_handleedittaskinfosuccess", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L639", "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_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": "L23"}, {"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": "L38"}, {"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": "L42"}, {"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": "L46"}], "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": "L23", "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": "L38", "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": "L42", "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": "L46", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_production_work_order_fetchproductionworkorderlist", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L29"}, {"caller_nid": "api_production_work_order_fetchproductionworkorderdetail", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L39"}, {"caller_nid": "api_production_work_order_fetchcompleteproductionworkorder", "callee": "put", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L43"}, {"caller_nid": "api_production_work_order_fetchcreateproductionworkorder", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L52"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "label": "cell-product.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L1"}, {"id": "api_cell_product_fetchcellproductlist", "label": "fetchCellProductList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L3"}, {"id": "api_cell_product_fetchcellproductdetail", "label": "fetchCellProductDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L20"}, {"id": "api_cell_product_fetchcreatecellproduct", "label": "fetchCreateCellProduct()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L24"}, {"id": "api_cell_product_fetchupdatecellproduct", "label": "fetchUpdateCellProduct()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L28"}, {"id": "api_cell_product_fetchdeletecellproduct", "label": "fetchDeleteCellProduct()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L32"}, {"id": "api_cell_product_fetchnextcellproductcode", "label": "fetchNextCellProductCode()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L36"}, {"id": "api_cell_product_fetchcellproductchain", "label": "fetchCellProductChain()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L43"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_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/cell-product.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchcellproductlist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchcellproductdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L20", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchcreatecellproduct", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L24", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchupdatecellproduct", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L28", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchdeletecellproduct", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L32", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchnextcellproductcode", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L36", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchcellproductchain", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L43", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_cell_product_fetchcellproductlist", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L11"}, {"caller_nid": "api_cell_product_fetchcellproductdetail", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L21"}, {"caller_nid": "api_cell_product_fetchcreatecellproduct", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L25"}, {"caller_nid": "api_cell_product_fetchupdatecellproduct", "callee": "put", "source_file": "/Users/wuzilong/work/00code/zkxwLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_temp_qc_work_order_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L1"}, {"id": "temp_qc_work_order_index_formatconfiguredlabitems", "label": "formatConfiguredLabItems()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L336"}, {"id": "temp_qc_work_order_index_formatconfiguredthirditems", "label": "formatConfiguredThirdItems()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L342"}, {"id": "temp_qc_work_order_index_buildtasktypesections", "label": "buildTaskTypeSections()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L350"}, {"id": "temp_qc_work_order_index_buildconfiguredonlysection", "label": "buildConfiguredOnlySection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L408"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_temp_qc_work_order_index_vue", "target": "temp_qc_work_order_index_formatconfiguredlabitems", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L336", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_temp_qc_work_order_index_vue", "target": "temp_qc_work_order_index_formatconfiguredthirditems", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L342", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_temp_qc_work_order_index_vue", "target": "temp_qc_work_order_index_buildtasktypesections", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L350", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_temp_qc_work_order_index_vue", "target": "temp_qc_work_order_index_buildconfiguredonlysection", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L408", "weight": 1.0}], "raw_calls": [{"caller_nid": "temp_qc_work_order_index_formatconfiguredlabitems", "callee": "join", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L338"}, {"caller_nid": "temp_qc_work_order_index_formatconfiguredlabitems", "callee": "map", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L338"}, {"caller_nid": "temp_qc_work_order_index_formatconfiguredthirditems", "callee": "join", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L344"}, {"caller_nid": "temp_qc_work_order_index_formatconfiguredthirditems", "callee": "map", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L344"}, {"caller_nid": "temp_qc_work_order_index_buildtasktypesections", "callee": "filter", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L355"}, {"caller_nid": "temp_qc_work_order_index_buildtasktypesections", "callee": "map", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/temp-qc-work-order/index.vue", "source_location": "L358"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_samplecustomerviewdialog_vue", "label": "SampleCustomerViewDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/SampleCustomerViewDialog.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_samplecustomerviewdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/SampleCustomerViewDialog.vue", "source_location": "L19", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_samplecustomerviewdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_system_view_dialog_index_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/SampleCustomerViewDialog.vue", "source_location": "L20", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_samplecustomerviewdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_system_view_dialog_index_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/SampleCustomerViewDialog.vue", "source_location": "L21", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_samplecustomerviewdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chain_types", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/SampleCustomerViewDialog.vue", "source_location": "L22", "weight": 1.0}], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_task_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-task/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "label": "qc-task.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L1"}, {"id": "api_qc_task_fetchqctasklist", "label": "fetchQcTaskList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L86"}, {"id": "api_qc_task_fetchqctaskdetail", "label": "fetchQcTaskDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L101"}, {"id": "api_qc_task_fetchstartqctask", "label": "fetchStartQcTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L107"}, {"id": "api_qc_task_fetchcompleteqctask", "label": "fetchCompleteQcTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L113"}, {"id": "api_qc_task_fetchupdateqctaskattachments", "label": "fetchUpdateQcTaskAttachments()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L119"}, {"id": "api_qc_task_fetchcreateqctask", "label": "fetchCreateQcTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L126"}, {"id": "api_qc_task_fetchdeleteqctask", "label": "fetchDeleteQcTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L144"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_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-task.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchqctasklist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L86", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchqctaskdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L101", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchstartqctask", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L107", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchcompleteqctask", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L113", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchupdateqctaskattachments", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L119", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchcreateqctask", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L126", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_task_ts", "target": "api_qc_task_fetchdeleteqctask", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L144", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_qc_task_fetchqctasklist", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L95"}, {"caller_nid": "api_qc_task_fetchqctaskdetail", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L102"}, {"caller_nid": "api_qc_task_fetchstartqctask", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L108"}, {"caller_nid": "api_qc_task_fetchcompleteqctask", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L114"}, {"caller_nid": "api_qc_task_fetchupdateqctaskattachments", "callee": "put", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts", "source_location": "L120"}, {"caller_nid": "api_qc_task_fetchcreateqctask", "callee": "post",Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_task_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-task/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaininject_ts", "label": "chainInject.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainInject.ts", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaininject_ts", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainInject.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaininject_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chain_types", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainInject.ts", "source_location": "L2", "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_handleview", "label": "handleView()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L567"}, {"id": "production_work_order_index_handlecomplete", "label": "handleComplete()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L571"}, {"id": "production_work_order_index_handleopendispatch", "label": "handleOpenDispatch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L581"}, {"id": "production_work_order_index_handleedittask", "label": "handleEditTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L598"}, {"id": "production_work_order_index_opentaskeditor", "label": "openTaskEditor()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L613"}, {"id": "production_work_order_index_openedittaskinfo", "label": "openEditTaskInfo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L625"}, {"id": "production_work_order_index_handleedittaskinfosuccess", "label": "handleEditTaskInfoSuccess()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L630"}, {"id": "production_work_order_index_handledeletetask", "label": "handleDeleteTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L636"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_handleview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L567", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_handlecomplete", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L571", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_handleopendispatch", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L581", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_handleedittask", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L598", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_opentaskeditor", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L613", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_openedittaskinfo", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L625", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "production_work_order_index_handleedittaskinfosuccess", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L630", "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_cell_product_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L1"}, {"id": "qc_task_index_canfillresult", "label": "canFillResult()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L519"}, {"id": "qc_task_index_clearmaterialrow", "label": "clearMaterialRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L541"}, {"id": "qc_task_index_ismaterialoptiondisabled", "label": "isMaterialOptionDisabled()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L548"}, {"id": "qc_task_index_isduplicatematerial", "label": "isDuplicateMaterial()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L553"}, {"id": "qc_task_index_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L700"}, {"id": "qc_task_index_normalizeresultparams", "label": "normalizeResultParams()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L704"}, {"id": "qc_task_index_toresultnumber", "label": "toResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L712"}, {"id": "qc_task_index_setresultnumber", "label": "setResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L718"}, {"id": "qc_task_index_hasresultvalue", "label": "hasResultValue()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L722"}, {"id": "qc_task_index_formatmetric", "label": "formatMetric()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L726"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_canfillresult", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L519", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_clearmaterialrow", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L541", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_ismaterialoptiondisabled", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L548", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_isduplicatematerial", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L553", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_handlereceptionattachmentdownload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L700", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_normalizeresultparams", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue", "source_location": "L704", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_task_index_vue", "target": "qc_task_index_toresultnumber", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry_ts", "label": "status-tag-registry.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L1"}, {"id": "utils_status_tag_registry_createlabelgetter", "label": "createLabelGetter()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L29"}, {"id": "utils_status_tag_registry_createtagtypegetter", "label": "createTagTypeGetter()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L33"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry_ts", "target": "utils_status_tag_registry_createlabelgetter", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L29", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry_ts", "target": "utils_status_tag_registry_createtagtypegetter", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L33", "weight": 1.0}], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "label": "chainToFlow.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L1"}, {"id": "source_chain_chaintoflow_nextancestorlink", "label": "nextAncestorLink()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L16"}, {"id": "source_chain_chaintoflow_makeflownode", "label": "makeFlowNode()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L24"}, {"id": "source_chain_chaintoflow_makeflowedge", "label": "makeFlowEdge()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L33"}, {"id": "source_chain_chaintoflow_chainapitoelements", "label": "chainApiToElements()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L52"}, {"id": "source_chain_chaintoflow_layoutchainelements", "label": "layoutChainElements()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L104"}, {"id": "source_chain_chaintoflow_haschaingraphcontent", "label": "hasChainGraphContent()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L143"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "dagre", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "core", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chain_types", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "source_chain_chaintoflow_nextancestorlink", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L16", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "source_chain_chaintoflow_makeflownode", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L24", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "source_chain_chaintoflow_makeflowedge", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L33", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "source_chain_chaintoflow_chainapitoelements", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L52", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chaintoflow_ts", "target": "source_chain_chaintoflow_layoutchainelements", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainToFlow.ts", "source_location": "L104", "weight": 1.0}, {"source": "users_wuzilong_work_0Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chainflowtheme_ts", "label": "chainFlowTheme.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainFlowTheme.ts", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chainflowtheme_ts", "target": "core", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/chainFlowTheme.ts", "source_location": "L1", "weight": 1.0}], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chainlinkedge_vue", "label": "ChainLinkEdge.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainLinkEdge.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chainlinkedge_vue", "target": "core", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainLinkEdge.vue", "source_location": "L21", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chainlinkedge_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_source_chain_chain_types", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/source-chain/ChainLinkEdge.vue", "source_location": "L27", "weight": 1.0}], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_production_work_order_ts", "label": "temp-production-work-order.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L1"}, {"id": "api_temp_production_work_order_fetchtempproductionworkorderlist", "label": "fetchTempProductionWorkOrderList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L24"}, {"id": "api_temp_production_work_order_fetchtempproductionworkorderdetail", "label": "fetchTempProductionWorkOrderDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L39"}, {"id": "api_temp_production_work_order_fetchcreatetempproductionworkorder", "label": "fetchCreateTempProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L45"}, {"id": "api_temp_production_work_order_fetchconfiguretempproductionworkorder", "label": "fetchConfigureTempProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L52"}, {"id": "api_temp_production_work_order_fetchdeletetempproductionworkorder", "label": "fetchDeleteTempProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L68"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_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/temp-production-work-order.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_production_work_order_ts", "target": "api_temp_production_work_order_fetchtempproductionworkorderlist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L24", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_production_work_order_ts", "target": "api_temp_production_work_order_fetchtempproductionworkorderdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L39", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_production_work_order_ts", "target": "api_temp_production_work_order_fetchcreatetempproductionworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L45", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_production_work_order_ts", "target": "api_temp_production_work_order_fetchconfiguretempproductionworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L52", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_temp_production_work_order_ts", "target": "api_temp_production_work_order_fetchdeletetempproductionworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L68", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_temp_production_work_order_fetchtempproductionworkorderlist", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L30"}, {"caller_nid": "api_temp_production_work_order_fetchtempproductionworkorderdetail", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L40"}, {"caller_nid": "api_temp_production_work_order_fetchcreatetempproductionworkorder", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L46"}, {"caller_nid": "api_temp_production_work_order_fetchconfiguretempproductionworkorder", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L62"}, {"caller_nid": "api_temp_production_work_order_fetchdeletetempproductionworkorder", "callee": "del", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/temp-production-work-order.ts", "source_location": "L69"}]Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1"}, {"id": "qc_work_order_index_handlereceptionattachmentpreview", "label": "handleReceptionAttachmentPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L392"}, {"id": "qc_work_order_index_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L397"}, {"id": "qc_work_order_index_taskattachmentfullurl", "label": "taskAttachmentFullUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L401"}, {"id": "qc_work_order_index_handletaskattachmentpreview", "label": "handleTaskAttachmentPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L408"}, {"id": "qc_work_order_index_handletaskattachmentdownload", "label": "handleTaskAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L413"}, {"id": "qc_work_order_index_formatconfiguredlabitems", "label": "formatConfiguredLabItems()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L429"}, {"id": "qc_work_order_index_formatconfiguredthirditems", "label": "formatConfiguredThirdItems()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L435"}, {"id": "qc_work_order_index_buildtasktypesections", "label": "buildTaskTypeSections()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L443"}, {"id": "qc_work_order_index_buildconfiguredonlysection", "label": "buildConfiguredOnlySection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L502"}, {"id": "qc_work_order_index_formatdetectmethods", "label": "formatDetectMethods()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L520"}, {"id": "qc_work_order_index_formatmetric", "label": "formatMetric()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L527"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_handlereceptionattachmentpreview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L392", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_handlereceptionattachmentdownload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L397", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_taskattachmentfullurl", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L401", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_handletaskattachmentpreview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L408", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_handletaskattachmentdownload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue",Line truncated
|
||||
@@ -381,7 +381,7 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
|
||||
path: 'qc-work-order',
|
||||
component: '/quality-inspection/qc-work-order/index',
|
||||
meta: {
|
||||
title: '入库质检工单',
|
||||
title: '质检工单',
|
||||
keepAlive: true,
|
||||
menuCode: 'biz:qcWorkOrder:list'
|
||||
}
|
||||
@@ -553,7 +553,7 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
|
||||
name: 'ProductionWorkOrder',
|
||||
path: 'production-work-order',
|
||||
component: '/production/production-work-order/index',
|
||||
meta: { title: '入库生产工单', keepAlive: true, menuCode: 'production:work-order:list' }
|
||||
meta: { title: '生产工单', keepAlive: true, menuCode: 'production:work-order:list' }
|
||||
},
|
||||
{
|
||||
id: '90000000000000000000000000000100',
|
||||
|
||||
@@ -141,7 +141,8 @@ export const sourceTypeTagType = createTagTypeGetter(sourceType)
|
||||
|
||||
export const qcBizType: StatusRegistry = {
|
||||
inbound: { label: '入库质检', tagType: 'success' },
|
||||
outbound: { label: '出库质检', tagType: 'primary' }
|
||||
outbound: { label: '出库质检', tagType: 'primary' },
|
||||
temporary: { label: '临时质检', tagType: 'warning' }
|
||||
}
|
||||
export const qcBizTypeLabel = createLabelGetter(qcBizType)
|
||||
export const qcBizTypeTagType = createTagTypeGetter(qcBizType)
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
<!-- 细胞产品来源链路图(Vue Flow) -->
|
||||
<template>
|
||||
<div class="source-chain-graph" v-loading="loading">
|
||||
<div v-if="chainData" class="chain-container">
|
||||
<div class="chain-section-title">来源链路</div>
|
||||
<p v-if="showFlow" class="chain-hint">双击连线查看生产任务;双击卡片查看产品或客户信息</p>
|
||||
|
||||
<div v-if="!showFlow" class="chain-empty">该产品暂无来源及衍生链路信息</div>
|
||||
|
||||
<div v-else class="chain-flow-viewport">
|
||||
<VueFlow
|
||||
v-model:nodes="nodes"
|
||||
v-model:edges="edges"
|
||||
:nodes-draggable="false"
|
||||
:nodes-connectable="false"
|
||||
:elements-selectable="false"
|
||||
:pan-on-drag="true"
|
||||
:zoom-on-scroll="true"
|
||||
:zoom-on-pinch="true"
|
||||
:min-zoom="0.25"
|
||||
:max-zoom="1.5"
|
||||
:zoom-on-double-click="false"
|
||||
:default-edge-options="defaultEdgeOptions"
|
||||
@node-double-click="onNodeDoubleClick"
|
||||
@edge-double-click="onEdgeDoubleClick"
|
||||
>
|
||||
<template #node-chainNode="nodeProps">
|
||||
<ChainNodeCard v-bind="nodeProps" />
|
||||
</template>
|
||||
<template #edge-chainLink="edgeProps">
|
||||
<ChainLinkEdge v-bind="edgeProps" />
|
||||
</template>
|
||||
</VueFlow>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TaskExecutionDialog
|
||||
v-model:visible="executionDialogVisible"
|
||||
:task-id="executionTaskId"
|
||||
:task-name="executionTaskName"
|
||||
:readonly="true"
|
||||
append-to-body
|
||||
/>
|
||||
<SampleCustomerViewDialog v-model:visible="sampleViewVisible" :sample="sampleViewNode" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, nextTick, computed, provide } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { VueFlow, useVueFlow, type Edge, type Node, type NodeMouseEvent, type EdgeMouseEvent } from '@vue-flow/core'
|
||||
import '@vue-flow/core/dist/style.css'
|
||||
import '@vue-flow/core/dist/theme-default.css'
|
||||
|
||||
import { fetchCellProductChain } from '@/api/cell-product'
|
||||
import { fetchCollectionProtocolDetail } from '@/api/collection-protocol'
|
||||
import TaskExecutionDialog from '../production-work-order/TaskExecutionDialog.vue'
|
||||
import ChainNodeCard from './source-chain/ChainNodeCard.vue'
|
||||
import ChainLinkEdge from './source-chain/ChainLinkEdge.vue'
|
||||
import SampleCustomerViewDialog from './source-chain/SampleCustomerViewDialog.vue'
|
||||
import type { ChainApiData, ChainEdgeData, ChainNode, ChainNodeData } from './source-chain/chain-types'
|
||||
import {
|
||||
chainApiToElements,
|
||||
hasChainGraphContent,
|
||||
layoutChainElements,
|
||||
} from './source-chain/chainToFlow'
|
||||
import { chainDefaultEdgeOptions } from './source-chain/chainFlowTheme'
|
||||
import { CHAIN_OPEN_TASK_KEY } from './source-chain/chainInject'
|
||||
|
||||
const props = defineProps<{
|
||||
productId: string
|
||||
visible: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'openProduct', productId: string): void
|
||||
}>()
|
||||
|
||||
const loading = ref(false)
|
||||
const chainData = ref<ChainApiData | null>(null)
|
||||
const nodes = ref<Node<ChainNodeData>[]>([])
|
||||
const edges = ref<Edge<ChainEdgeData>[]>([])
|
||||
|
||||
const executionDialogVisible = ref(false)
|
||||
const executionTaskId = ref('')
|
||||
const executionTaskName = ref('')
|
||||
const sampleViewVisible = ref(false)
|
||||
const sampleViewNode = ref<ChainNode | null>(null)
|
||||
|
||||
const showFlow = computed(
|
||||
() => chainData.value && hasChainGraphContent(chainData.value)
|
||||
)
|
||||
|
||||
const defaultEdgeOptions = chainDefaultEdgeOptions
|
||||
|
||||
const { fitView, onNodesInitialized } = useVueFlow()
|
||||
|
||||
function scheduleFitView() {
|
||||
nextTick(() => {
|
||||
requestAnimationFrame(() => {
|
||||
fitView({ padding: 0.15, duration: 280 })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
onNodesInitialized(() => {
|
||||
scheduleFitView()
|
||||
})
|
||||
|
||||
async function applyChainData(data: ChainApiData) {
|
||||
const { nodes: rawNodes, edges: rawEdges } = chainApiToElements(data)
|
||||
nodes.value = layoutChainElements(rawNodes, rawEdges)
|
||||
edges.value = rawEdges
|
||||
scheduleFitView()
|
||||
}
|
||||
|
||||
function onNodeDoubleClick({ node }: NodeMouseEvent) {
|
||||
const chainNode = (node.data as ChainNodeData | undefined)?.node
|
||||
if (!chainNode) return
|
||||
|
||||
if (chainNode.nodeType === 'cell_product') {
|
||||
emit('openProduct', chainNode.id)
|
||||
return
|
||||
}
|
||||
|
||||
if (chainNode.nodeType === 'sample') {
|
||||
openSampleCustomer(chainNode)
|
||||
}
|
||||
}
|
||||
|
||||
function openTaskById(taskId?: string, taskName?: string) {
|
||||
const id = taskId?.trim()
|
||||
if (!id) {
|
||||
ElMessage.warning('该连线暂无关联生产任务')
|
||||
return
|
||||
}
|
||||
executionTaskId.value = id
|
||||
executionTaskName.value = taskName?.trim() || ''
|
||||
executionDialogVisible.value = true
|
||||
}
|
||||
|
||||
provide(CHAIN_OPEN_TASK_KEY, openTaskById)
|
||||
|
||||
function onEdgeDoubleClick(evt: EdgeMouseEvent) {
|
||||
const data = evt.edge.data as ChainEdgeData | undefined
|
||||
openTaskById(data?.taskId, data?.taskName)
|
||||
}
|
||||
|
||||
async function openSampleCustomer(chainNode: ChainNode) {
|
||||
let node = chainNode
|
||||
const c = chainNode.customer
|
||||
const hasCustomer =
|
||||
c &&
|
||||
(c.motherName || c.motherPhone || c.motherIdCard || c.newbornName)
|
||||
|
||||
if (!hasCustomer && chainNode.collectionProtocolId) {
|
||||
try {
|
||||
const detail = await fetchCollectionProtocolDetail(chainNode.collectionProtocolId)
|
||||
const pc = detail?.partyCustomer as Record<string, string> | null
|
||||
if (pc) {
|
||||
node = {
|
||||
...chainNode,
|
||||
protocolNo:
|
||||
chainNode.protocolNo ||
|
||||
String((detail?.protocol as Record<string, string>)?.protocolNo || ''),
|
||||
customer: {
|
||||
motherName: pc.motherName || '',
|
||||
motherPhone: pc.motherPhone || '',
|
||||
motherIdCard: pc.motherIdCard || '',
|
||||
newbornName: pc.newbornName || '',
|
||||
},
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* 全局错误处理 */
|
||||
}
|
||||
}
|
||||
|
||||
const final = node.customer
|
||||
if (!final?.motherName && !final?.motherPhone && !final?.motherIdCard && !final?.newbornName) {
|
||||
ElMessage.warning('暂无客户信息')
|
||||
return
|
||||
}
|
||||
|
||||
sampleViewNode.value = node
|
||||
sampleViewVisible.value = true
|
||||
}
|
||||
|
||||
async function loadChain() {
|
||||
if (!props.productId || !props.visible) return
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await fetchCellProductChain(props.productId)
|
||||
chainData.value = (res as ChainApiData) || null
|
||||
nodes.value = []
|
||||
edges.value = []
|
||||
if (chainData.value && hasChainGraphContent(chainData.value)) {
|
||||
await applyChainData(chainData.value)
|
||||
}
|
||||
} catch {
|
||||
chainData.value = null
|
||||
nodes.value = []
|
||||
edges.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [props.productId, props.visible],
|
||||
([id, vis]) => {
|
||||
if (id && vis) loadChain()
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'SourceChainGraph',
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.source-chain-graph {
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
.chain-section-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
padding-left: 10px;
|
||||
border-left: 3px solid #10b981;
|
||||
margin-bottom: 8px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.chain-hint {
|
||||
margin: 0 0 10px 12px;
|
||||
font-size: 11px;
|
||||
color: #94a3b8;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.chain-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.chain-empty {
|
||||
text-align: center;
|
||||
color: #94a3b8;
|
||||
font-size: 13px;
|
||||
padding: 32px 0;
|
||||
}
|
||||
|
||||
.chain-flow-viewport {
|
||||
width: 100%;
|
||||
height: 320px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
background: #f8fafc;
|
||||
overflow: hidden;
|
||||
|
||||
.vue-flow {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.vue-flow__pane {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.vue-flow__pane.dragging {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.vue-flow__edge-path {
|
||||
stroke: #10b981;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.vue-flow__edge.selected .vue-flow__edge-path {
|
||||
stroke: #059669;
|
||||
}
|
||||
|
||||
.vue-flow__edges marker path {
|
||||
fill: #10b981 !important;
|
||||
stroke: #10b981 !important;
|
||||
}
|
||||
|
||||
.vue-flow__edge .chain-flow-edge {
|
||||
stroke: #10b981;
|
||||
}
|
||||
|
||||
.vue-flow__edge-interaction {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -52,6 +52,17 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="来源类型">
|
||||
<el-select
|
||||
v-model="searchForm.sourceType"
|
||||
placeholder="全部"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option label="生产入库" value="production" />
|
||||
<el-option label="手动录入" value="manual" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">按产品编码、产品名称模糊查询,支持按状态和代次筛选。</span>
|
||||
@@ -204,6 +215,42 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来源类型" min-width="110" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
v-if="row.sourceTypeLabel"
|
||||
:type="row.sourceType === 'production' ? 'success' : 'info'"
|
||||
size="small"
|
||||
>
|
||||
{{ row.sourceTypeLabel }}
|
||||
</el-tag>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="来源协议号"
|
||||
min-width="160"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">{{ row.sourceProtocolNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="来源工单号"
|
||||
min-width="140"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">{{ row.sourceWorkOrderNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="来源任务号"
|
||||
min-width="140"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">{{ row.sourceTaskNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="expiryDate"
|
||||
label="有效期"
|
||||
@@ -583,6 +630,8 @@
|
||||
:icon="Box"
|
||||
:meta="viewRow?.productCode || ''"
|
||||
:sections="viewSections"
|
||||
width="1200px"
|
||||
:grid-columns="4"
|
||||
>
|
||||
<template #images>
|
||||
<div class="attachment-upload attachment-upload--readonly">
|
||||
@@ -612,6 +661,13 @@
|
||||
<span v-else class="upload-hint">暂无图片</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #sourceChain>
|
||||
<SourceChainGraph
|
||||
:product-id="viewRow?.id"
|
||||
:visible="viewVisible"
|
||||
@open-product="handleChainOpenProduct"
|
||||
/>
|
||||
</template>
|
||||
</SystemViewDialog>
|
||||
</section>
|
||||
</div>
|
||||
@@ -634,6 +690,7 @@
|
||||
} from '@element-plus/icons-vue'
|
||||
import SystemViewDialog from '@/components/business/system-view-dialog/index.vue'
|
||||
import type { ViewSection } from '@/components/business/system-view-dialog/index.vue'
|
||||
import SourceChainGraph from './SourceChainGraph.vue'
|
||||
import { withFullscreenLoading, fullscreenLoadingText } from '@/utils/fullscreen-loading'
|
||||
import {
|
||||
fetchCellProductList,
|
||||
@@ -691,7 +748,7 @@
|
||||
}
|
||||
|
||||
/* ---- 搜索 & 分页 ---- */
|
||||
const searchForm = reactive({ keyword: '', productStatus: '', passage: '' })
|
||||
const searchForm = reactive({ keyword: '', productStatus: '', passage: '', sourceType: '' })
|
||||
const tableData = ref<any[]>([])
|
||||
const selectedRows = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
@@ -934,6 +991,12 @@
|
||||
slot: 'images',
|
||||
fields: [],
|
||||
},
|
||||
{
|
||||
title: '来源链路',
|
||||
titleStyle: 'field' as const,
|
||||
slot: 'sourceChain',
|
||||
fields: [],
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
@@ -947,6 +1010,7 @@
|
||||
keyword: searchForm.keyword || undefined,
|
||||
productStatus: searchForm.productStatus || undefined,
|
||||
passage: searchForm.passage || undefined,
|
||||
sourceType: searchForm.sourceType || undefined,
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
@@ -987,6 +1051,7 @@
|
||||
searchForm.keyword = ''
|
||||
searchForm.productStatus = ''
|
||||
searchForm.passage = ''
|
||||
searchForm.sourceType = ''
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
@@ -1220,6 +1285,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function handleChainOpenProduct(productId: string) {
|
||||
if (!productId) return
|
||||
await handleView({ id: productId })
|
||||
}
|
||||
|
||||
/* ---- 查看 ---- */
|
||||
async function handleView(row: any) {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
<!-- eslint-disable vue/no-multiple-template-root -->
|
||||
<!-- 来源链路 · 单链折线 / 分叉贝塞尔曲线(组件内处理双击,避免被画布缩放拦截) -->
|
||||
<template>
|
||||
<g class="chain-link-edge-group" @dblclick.stop="handleDblClick">
|
||||
<BaseEdge
|
||||
:id="id"
|
||||
:path="edgePath"
|
||||
:marker-end="markerEnd"
|
||||
:marker-start="markerStart"
|
||||
:interaction-width="edgeInteractionWidth"
|
||||
class="chain-flow-edge"
|
||||
/>
|
||||
<EdgeLabelRenderer v-if="hasLabel">
|
||||
<div
|
||||
class="chain-edge-label-compact nodrag nopan"
|
||||
:style="labelStyle"
|
||||
@dblclick.stop="handleDblClick"
|
||||
>
|
||||
<div v-if="workOrderLabel" class="label-line">
|
||||
<span class="label-k">工单</span>
|
||||
<span class="label-v wo" :title="workOrderLabel">{{ workOrderLabel }}</span>
|
||||
</div>
|
||||
<div v-if="taskLabel" class="label-line">
|
||||
<span class="label-k">任务</span>
|
||||
<span class="label-v task" :title="taskLabel">{{ taskLabel }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</EdgeLabelRenderer>
|
||||
</g>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, inject } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import {
|
||||
BaseEdge,
|
||||
EdgeLabelRenderer,
|
||||
getBezierPath,
|
||||
getSmoothStepPath,
|
||||
type EdgeProps,
|
||||
} from '@vue-flow/core'
|
||||
import type { ChainEdgeData } from './chain-types'
|
||||
import { CHAIN_OPEN_TASK_KEY } from './chainInject'
|
||||
|
||||
const props = defineProps<EdgeProps<ChainEdgeData>>()
|
||||
|
||||
const openTask = inject(CHAIN_OPEN_TASK_KEY)
|
||||
|
||||
const edgeInteractionWidth = computed(() => props.interactionWidth ?? 28)
|
||||
|
||||
const pathInput = computed(() => ({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
targetPosition: props.targetPosition,
|
||||
}))
|
||||
|
||||
const bezierCurvature = computed(() => {
|
||||
const dy = props.targetY - props.sourceY
|
||||
if (Math.abs(dy) < 4) {
|
||||
return 0.28
|
||||
}
|
||||
const sign = dy > 0 ? 1 : -1
|
||||
return sign * Math.min(0.55, 0.32 + Math.abs(dy) / 280)
|
||||
})
|
||||
|
||||
const path = computed(() => {
|
||||
if (props.data?.curved) {
|
||||
return getBezierPath({
|
||||
...pathInput.value,
|
||||
curvature: bezierCurvature.value,
|
||||
})
|
||||
}
|
||||
return getSmoothStepPath({
|
||||
...pathInput.value,
|
||||
borderRadius: 8,
|
||||
})
|
||||
})
|
||||
|
||||
const edgePath = computed(() => path.value[0])
|
||||
const labelX = computed(() => path.value[1])
|
||||
const labelY = computed(() => path.value[2])
|
||||
|
||||
const workOrderLabel = computed(() => props.data?.workOrderNo?.trim() || '')
|
||||
const taskLabel = computed(() => props.data?.taskNo?.trim() || '')
|
||||
const hasLabel = computed(() => Boolean(workOrderLabel.value || taskLabel.value))
|
||||
|
||||
const labelStyle = computed(() => ({
|
||||
transform: `translate(-50%, -50%) translate(${labelX.value}px, ${labelY.value}px)`,
|
||||
}))
|
||||
|
||||
function handleDblClick() {
|
||||
const taskId = props.data?.taskId?.trim()
|
||||
if (!taskId) {
|
||||
ElMessage.warning('该连线暂无关联生产任务')
|
||||
return
|
||||
}
|
||||
openTask?.(taskId, props.data?.taskName?.trim())
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.chain-link-edge-group {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.chain-flow-edge {
|
||||
stroke: #10b981;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.chain-edge-label-compact {
|
||||
position: absolute;
|
||||
pointer-events: all;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 1px;
|
||||
padding: 3px 6px;
|
||||
background: #fff;
|
||||
border: 1px solid #d1fae5;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
|
||||
max-width: 118px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.label-line {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 3px;
|
||||
line-height: 1.2;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.label-k {
|
||||
flex-shrink: 0;
|
||||
font-size: 8px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.label-v {
|
||||
font-size: 8px;
|
||||
font-weight: 600;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
min-width: 0;
|
||||
|
||||
&.wo {
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
&.task {
|
||||
color: #64748b;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user