提交
This commit is contained in:
1 parent
4ea71a1bae
commit
3abe69c1cc
83 files changed
+33505
-21867
No files matched your search
+1
-1
@@ -1 +1 @@
|
||||
68064
|
||||
91694
|
||||
@@ -34,6 +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.crud import qc_work_order as qc_work_order_svc
|
||||
from app.schemas.production_work_order import (
|
||||
ProductionWorkOrderListQuery,
|
||||
ProductionWorkOrderComplete,
|
||||
@@ -55,6 +56,7 @@ from app.schemas.production_task import (
|
||||
TaskStepReorderBody,
|
||||
)
|
||||
from app.schemas.cell_product import CellProductCreate, CellProductUpdate
|
||||
from app.schemas.qc_work_order import ProductionQcWorkOrderCreateBody
|
||||
|
||||
router = APIRouter(prefix="/web/admin", tags=["生产管理"])
|
||||
|
||||
@@ -1729,6 +1731,51 @@ async def configure_production_work_order(
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.get("/production-work-orders/{wo_id}/cell-product-options")
|
||||
async def list_production_work_order_cell_product_options(
|
||||
wo_id: str,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
items = qc_work_order_svc.list_cell_product_options_for_production_work_order(
|
||||
db, production_work_order_id=wo_id, tenant_no=tenant_no
|
||||
)
|
||||
return success_response(items)
|
||||
except ValueError as e:
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@router.post("/production-work-orders/{wo_id}/qc-work-orders")
|
||||
async def create_qc_work_order_from_production_api(
|
||||
wo_id: str,
|
||||
body: ProductionQcWorkOrderCreateBody,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
try:
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
wo = qc_work_order_svc.create_qc_work_order_from_production(
|
||||
db,
|
||||
production_work_order_id=wo_id,
|
||||
cell_product_id=body.cell_product_id,
|
||||
production_task_id=body.production_task_id,
|
||||
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(qc_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. 生产任务
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -632,6 +632,7 @@ async def list_qc_work_orders(
|
||||
createTimeEnd: Optional[str] = Query(None, alias="createTimeEnd"),
|
||||
infusionTimeStart: Optional[str] = Query(None, alias="infusionTimeStart"),
|
||||
infusionTimeEnd: Optional[str] = Query(None, alias="infusionTimeEnd"),
|
||||
triggerSource: Optional[str] = Query(None, alias="triggerSource"),
|
||||
db: Session = Depends(get_db),
|
||||
user: dict = Depends(require_menu_code("biz:qcWorkOrder:list")),
|
||||
):
|
||||
@@ -645,6 +646,7 @@ async def list_qc_work_orders(
|
||||
work_order_status=workOrderStatus,
|
||||
work_order_type=workOrderType,
|
||||
biz_type=bizType,
|
||||
trigger_source=triggerSource,
|
||||
create_time_start=createTimeStart,
|
||||
create_time_end=createTimeEnd,
|
||||
infusion_time_start=infusionTimeStart,
|
||||
|
||||
@@ -20,6 +20,7 @@ from app.crud import sample_reception as sample_reception_svc
|
||||
from app.crud.sample_reception import _donation_sample_id_col
|
||||
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.services.qc_work_order_fee_summary import enrich_work_order_fee_summaries
|
||||
from app.models.models import (
|
||||
BizCellProduct,
|
||||
BizCellSampleType,
|
||||
@@ -30,6 +31,9 @@ from app.models.models import (
|
||||
BizPilotInfusionScheduleProduct,
|
||||
BizPilotPatient,
|
||||
BizProtocolSample,
|
||||
BizProductionTask,
|
||||
BizProductionTaskOutput,
|
||||
BizProductionWorkOrder,
|
||||
BizQcLabTestItem,
|
||||
BizQcTask,
|
||||
BizQcThirdPartyItem,
|
||||
@@ -52,6 +56,10 @@ _QC_BIZ_TYPE_LABELS = {
|
||||
"outbound": "出库质检",
|
||||
"temporary": "临时质检",
|
||||
}
|
||||
_TRIGGER_SOURCE_LABELS = {
|
||||
"reception": "样本接收",
|
||||
"production": "生产过程",
|
||||
}
|
||||
_ACCEPT_CONCLUSION_LABELS = {"js": "接收", "bj": "拒收"}
|
||||
_WORK_ORDER_STATUS_LABELS = {"dpz": "待配置", "ypz": "已配置", "ywc": "已完成", "yzf": "已作废"}
|
||||
_VALID_QC_WORK_ORDER_STATUSES = frozenset(_WORK_ORDER_STATUS_LABELS.keys())
|
||||
@@ -413,20 +421,51 @@ def _enrich_work_order_list_items(
|
||||
if not items:
|
||||
return items
|
||||
rec_ids = [x["receptionId"] for x in items if x.get("receptionId")]
|
||||
if not rec_ids:
|
||||
sample_codes_no_rec = list(
|
||||
{
|
||||
(x.get("sampleCode") or "").strip()
|
||||
for x in items
|
||||
if not (x.get("receptionId") or "").strip() and (x.get("sampleCode") or "").strip()
|
||||
}
|
||||
)
|
||||
rec_map = {}
|
||||
if rec_ids:
|
||||
rec_map = {
|
||||
r.id: r
|
||||
for r in db.query(BizSampleReception)
|
||||
.filter(BizSampleReception.id.in_(rec_ids), BizSampleReception.del_flag == 0)
|
||||
.all()
|
||||
}
|
||||
sample_code_rec_map: Dict[str, BizSampleReception] = {}
|
||||
if sample_codes_no_rec:
|
||||
for r in (
|
||||
db.query(BizSampleReception)
|
||||
.filter(
|
||||
BizSampleReception.sample_code.in_(sample_codes_no_rec),
|
||||
BizSampleReception.del_flag == 0,
|
||||
)
|
||||
.order_by(BizSampleReception.create_time.desc())
|
||||
.all()
|
||||
):
|
||||
code = (r.sample_code or "").strip()
|
||||
if code and code not in sample_code_rec_map:
|
||||
sample_code_rec_map[code] = r
|
||||
if not rec_map and not sample_code_rec_map:
|
||||
return items
|
||||
rec_map = {
|
||||
r.id: r
|
||||
for r in db.query(BizSampleReception)
|
||||
.filter(BizSampleReception.id.in_(rec_ids), BizSampleReception.del_flag == 0)
|
||||
.all()
|
||||
}
|
||||
|
||||
def _resolve_reception(item: Dict[str, Any]) -> Optional[BizSampleReception]:
|
||||
rec = rec_map.get(item.get("receptionId") or "")
|
||||
if rec:
|
||||
return rec
|
||||
code = (item.get("sampleCode") or "").strip()
|
||||
return sample_code_rec_map.get(code) if code else None
|
||||
|
||||
cell_sample_ids: List[str] = []
|
||||
donation_sample_ids: List[str] = []
|
||||
cell_proto_ids: List[str] = []
|
||||
donation_ids: List[str] = []
|
||||
for item in items:
|
||||
rec = rec_map.get(item.get("receptionId") or "")
|
||||
rec = _resolve_reception(item)
|
||||
source = _effective_reception_source(item, rec)
|
||||
if source == "research_donation":
|
||||
dsid = _effective_donation_sample_id(item, rec)
|
||||
@@ -500,7 +539,7 @@ def _enrich_work_order_list_items(
|
||||
item["receptionSource"] = ""
|
||||
item["receptionSourceLabel"] = ""
|
||||
continue
|
||||
rec = rec_map.get(item.get("receptionId") or "")
|
||||
rec = _resolve_reception(item)
|
||||
source = _effective_reception_source(item, rec)
|
||||
item["receptionSource"] = source
|
||||
item["receptionSourceLabel"] = _reception_source_label(source)
|
||||
@@ -540,6 +579,31 @@ def _enrich_work_order_list_items(
|
||||
return items
|
||||
|
||||
|
||||
def _enrich_production_work_order_refs(
|
||||
db: Session, items: List[Dict[str, Any]]
|
||||
) -> List[Dict[str, Any]]:
|
||||
if not items:
|
||||
return items
|
||||
pwo_ids = list(
|
||||
{x.get("productionWorkOrderId") for x in items if (x.get("productionWorkOrderId") or "").strip()}
|
||||
)
|
||||
pwo_map: Dict[str, str] = {}
|
||||
if pwo_ids:
|
||||
rows = (
|
||||
db.query(BizProductionWorkOrder.id, BizProductionWorkOrder.work_order_no)
|
||||
.filter(
|
||||
BizProductionWorkOrder.id.in_(pwo_ids),
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
pwo_map = {r.id: r.work_order_no or "" for r in rows}
|
||||
for item in items:
|
||||
pid = (item.get("productionWorkOrderId") or "").strip()
|
||||
item["productionWorkOrderNo"] = pwo_map.get(pid, "") if pid else ""
|
||||
return items
|
||||
|
||||
|
||||
def _gen_daily_no(db: Session, tenant_no: str, prefix: str) -> str:
|
||||
day = datetime.now().strftime("%Y%m%d")
|
||||
like = f"{prefix}{day}%"
|
||||
@@ -603,6 +667,13 @@ def _wo_to_dict(
|
||||
"cellProductTypeName": "",
|
||||
"cellProductPassage": "",
|
||||
"cellProductSpecName": "",
|
||||
"triggerSource": getattr(wo, "trigger_source", None) or "reception",
|
||||
"triggerSourceLabel": _TRIGGER_SOURCE_LABELS.get(
|
||||
getattr(wo, "trigger_source", None) or "reception", ""
|
||||
),
|
||||
"productionWorkOrderId": getattr(wo, "production_work_order_id", None) or "",
|
||||
"productionWorkOrderNo": "",
|
||||
"productionTaskId": getattr(wo, "production_task_id", None) or "",
|
||||
"receptionTime": "",
|
||||
"handlerName": "",
|
||||
"sampleTypeName": "",
|
||||
@@ -680,6 +751,7 @@ def create_work_order_from_reception(
|
||||
sample_code=sample_code or None,
|
||||
reception_source="research_donation",
|
||||
qc_biz_type="inbound",
|
||||
trigger_source="reception",
|
||||
work_order_status="dpz",
|
||||
has_lab="0",
|
||||
has_third_party="0",
|
||||
@@ -721,6 +793,7 @@ def create_work_order_from_reception(
|
||||
sample_code=sample_code or None,
|
||||
reception_source="cell_storage",
|
||||
qc_biz_type="inbound",
|
||||
trigger_source="reception",
|
||||
work_order_status="dpz",
|
||||
has_lab="0",
|
||||
has_third_party="0",
|
||||
@@ -737,6 +810,182 @@ def create_work_order_from_reception(
|
||||
return wo
|
||||
|
||||
|
||||
def create_qc_work_order_from_production(
|
||||
db: Session,
|
||||
*,
|
||||
production_work_order_id: str,
|
||||
cell_product_id: str,
|
||||
production_task_id: Optional[str] = None,
|
||||
remark: str = "",
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
) -> BizQcWorkOrder:
|
||||
"""生产过程派发质检工单(flush,不 commit)。"""
|
||||
pwo = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(
|
||||
BizProductionWorkOrder.id == production_work_order_id,
|
||||
BizProductionWorkOrder.tenant_no == tenant_no,
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if not pwo:
|
||||
raise ValueError("生产工单不存在")
|
||||
wo_type = (getattr(pwo, "work_order_type", None) or "inbound").strip()
|
||||
if wo_type != "inbound":
|
||||
raise ValueError("仅入库生产工单可派发质检")
|
||||
status = (pwo.work_order_status or "").strip()
|
||||
if status == "yzf":
|
||||
raise ValueError("已作废的生产工单不可派发质检")
|
||||
if status not in ("jxz", "ywc"):
|
||||
raise ValueError("仅进行中或已完成的入库生产工单可派发质检")
|
||||
|
||||
cp_id = _validate_cell_product_id(db, cell_product_id, tenant_no)
|
||||
options = list_cell_product_options_for_production_work_order(
|
||||
db, production_work_order_id=production_work_order_id, tenant_no=tenant_no
|
||||
)
|
||||
option_ids = {o["id"] for o in options}
|
||||
if cp_id not in option_ids:
|
||||
raise ValueError("所选细胞产品不在该生产工单的产出列表中")
|
||||
|
||||
task_id = (production_task_id or "").strip() or None
|
||||
if task_id:
|
||||
task = (
|
||||
db.query(BizProductionTask)
|
||||
.filter(
|
||||
BizProductionTask.id == task_id,
|
||||
BizProductionTask.work_order_id == pwo.id,
|
||||
BizProductionTask.tenant_no == tenant_no,
|
||||
BizProductionTask.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if not task:
|
||||
raise ValueError("关联生产任务不存在")
|
||||
|
||||
wo = BizQcWorkOrder(
|
||||
id=generate_uuid(),
|
||||
work_order_no=_gen_daily_no(db, tenant_no, "ZJ"),
|
||||
work_order_type="inbound",
|
||||
# 生产过程触发不写入 reception_id,避免与 uk_qc_wo_reception(reception_id,del_flag) 冲突;
|
||||
# 样本关联仍通过 sample_code / protocol_sample_id 等快照字段。
|
||||
reception_id=None,
|
||||
protocol_sample_id=pwo.protocol_sample_id,
|
||||
collection_protocol_id=pwo.collection_protocol_id,
|
||||
protocol_no=pwo.protocol_no or None,
|
||||
sample_code=pwo.sample_code or None,
|
||||
reception_source=getattr(pwo, "reception_source", "cell_storage") or "cell_storage",
|
||||
qc_biz_type="inbound",
|
||||
trigger_source="production",
|
||||
cell_product_id=cp_id,
|
||||
production_work_order_id=pwo.id,
|
||||
production_task_id=task_id,
|
||||
work_order_status="dpz",
|
||||
has_lab="0",
|
||||
has_third_party="0",
|
||||
tenant_no=tenant_no,
|
||||
remark=(remark or "").strip() or None,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id or "",
|
||||
update_by=user_id,
|
||||
create_time=datetime.now(),
|
||||
update_time=datetime.now(),
|
||||
del_flag=0,
|
||||
)
|
||||
db.add(wo)
|
||||
db.flush()
|
||||
return wo
|
||||
|
||||
|
||||
def list_cell_product_options_for_production_work_order(
|
||||
db: Session,
|
||||
*,
|
||||
production_work_order_id: str,
|
||||
tenant_no: str,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""汇总生产工单下任务产出中的细胞产品(去重)。"""
|
||||
pwo = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(
|
||||
BizProductionWorkOrder.id == production_work_order_id,
|
||||
BizProductionWorkOrder.tenant_no == tenant_no,
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if not pwo:
|
||||
raise ValueError("生产工单不存在")
|
||||
|
||||
tasks = (
|
||||
db.query(BizProductionTask)
|
||||
.filter(
|
||||
BizProductionTask.work_order_id == pwo.id,
|
||||
BizProductionTask.tenant_no == tenant_no,
|
||||
BizProductionTask.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
if not tasks:
|
||||
return []
|
||||
|
||||
task_map = {t.id: t for t in tasks}
|
||||
task_ids = list(task_map.keys())
|
||||
outputs = (
|
||||
db.query(BizProductionTaskOutput)
|
||||
.filter(
|
||||
BizProductionTaskOutput.task_id.in_(task_ids),
|
||||
BizProductionTaskOutput.tenant_no == tenant_no,
|
||||
BizProductionTaskOutput.del_flag == 0,
|
||||
BizProductionTaskOutput.cell_product_id.isnot(None),
|
||||
BizProductionTaskOutput.cell_product_id != "",
|
||||
)
|
||||
.order_by(BizProductionTaskOutput.order_num.asc(), BizProductionTaskOutput.create_time.asc())
|
||||
.all()
|
||||
)
|
||||
seen: set[str] = set()
|
||||
items: List[Dict[str, Any]] = []
|
||||
for out in outputs:
|
||||
cp_id = (out.cell_product_id or "").strip()
|
||||
if not cp_id or cp_id in seen:
|
||||
continue
|
||||
seen.add(cp_id)
|
||||
task = task_map.get(out.task_id)
|
||||
items.append(
|
||||
{
|
||||
"id": cp_id,
|
||||
"cellProductId": cp_id,
|
||||
"taskId": out.task_id,
|
||||
"taskNo": task.task_no if task else "",
|
||||
}
|
||||
)
|
||||
|
||||
if not items:
|
||||
return []
|
||||
|
||||
cp_ids = [i["id"] for i in 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["id"]) or {}
|
||||
item["productCode"] = cp.get("productCode", "")
|
||||
item["productName"] = cp.get("productName", "")
|
||||
item["productTypeName"] = cp.get("productTypeName", "")
|
||||
item["passage"] = cp.get("passage", "")
|
||||
item["storageSlotName"] = cp.get("storageSlotName", "")
|
||||
return items
|
||||
|
||||
|
||||
def list_work_orders(
|
||||
db: Session,
|
||||
*,
|
||||
@@ -746,6 +995,7 @@ def list_work_orders(
|
||||
work_order_status: Optional[str] = None,
|
||||
work_order_type: Optional[str] = None,
|
||||
biz_type: Optional[str] = None,
|
||||
trigger_source: Optional[str] = None,
|
||||
create_time_start: Optional[str] = None,
|
||||
create_time_end: Optional[str] = None,
|
||||
infusion_time_start: Optional[str] = None,
|
||||
@@ -763,6 +1013,9 @@ def list_work_orders(
|
||||
bt = (biz_type or "").strip()
|
||||
if bt:
|
||||
q0 = q0.filter(BizQcWorkOrder.biz_type == bt)
|
||||
ts = (trigger_source or "").strip()
|
||||
if ts:
|
||||
q0 = q0.filter(BizQcWorkOrder.trigger_source == ts)
|
||||
kw = (keyword or "").strip()
|
||||
if kw:
|
||||
like = f"%{kw}%"
|
||||
@@ -841,7 +1094,9 @@ def list_work_orders(
|
||||
items = _enrich_work_order_list_items(db, items)
|
||||
if tenant_no:
|
||||
items = _enrich_work_order_cell_products(db, tenant_no, items)
|
||||
items = _enrich_production_work_order_refs(db, items)
|
||||
items = _enrich_outbound_work_orders(db, tenant_no, items)
|
||||
items = enrich_work_order_fee_summaries(db, items, tenant_no)
|
||||
return items, int(total)
|
||||
|
||||
|
||||
@@ -1040,6 +1295,10 @@ def get_work_order_detail(
|
||||
out["labItems"] = _lab_lines(db, wo.id)
|
||||
out["thirdPartyItems"] = _third_lines(db, wo.id)
|
||||
out["tasks"] = task_svc.list_tasks_by_work_order(db, wo.id, tenant_no)
|
||||
enriched_fee = enrich_work_order_fee_summaries(db, [out], tenant_no)
|
||||
if enriched_fee:
|
||||
out["paymentSummary"] = enriched_fee[0].get("paymentSummary")
|
||||
out["feeSummary"] = enriched_fee[0].get("feeSummary")
|
||||
return out
|
||||
|
||||
|
||||
@@ -2034,9 +2293,17 @@ def get_outbound_qc_detail(
|
||||
|
||||
if not schedule_id:
|
||||
out["tasks"] = task_svc.list_tasks_by_work_order(db, wo.id, tenant_no)
|
||||
enriched_fee = enrich_work_order_fee_summaries(db, [out["workOrder"]], tenant_no)
|
||||
if enriched_fee:
|
||||
out["workOrder"]["feeSummary"] = enriched_fee[0].get("feeSummary")
|
||||
out["feeSummary"] = enriched_fee[0].get("feeSummary")
|
||||
return out
|
||||
|
||||
out["tasks"] = task_svc.list_tasks_by_work_order(db, wo.id, tenant_no)
|
||||
enriched_fee = enrich_work_order_fee_summaries(db, [out["workOrder"]], tenant_no)
|
||||
if enriched_fee:
|
||||
out["workOrder"]["feeSummary"] = enriched_fee[0].get("feeSummary")
|
||||
out["feeSummary"] = enriched_fee[0].get("feeSummary")
|
||||
return out
|
||||
|
||||
|
||||
|
||||
@@ -550,6 +550,7 @@ def _build_qc_info(
|
||||
q = db.query(BizQcWorkOrder).filter(
|
||||
BizQcWorkOrder.tenant_no == tenant_no,
|
||||
BizQcWorkOrder.del_flag == 0,
|
||||
BizQcWorkOrder.trigger_source == "reception",
|
||||
)
|
||||
wo = q.filter(BizQcWorkOrder.sample_code == code).first() if code else None
|
||||
if not wo and rev.reception_id:
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_assignee_py", "label": "qc_task_assignee.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L1"}, {"id": "crud_qc_task_assignee_active_users_in_tenant", "label": "_active_users_in_tenant()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L14"}, {"id": "crud_qc_task_assignee_validate_assignee_user_ids", "label": "validate_assignee_user_ids()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L33"}, {"id": "crud_qc_task_assignee_sync_assignees_for_task", "label": "sync_assignees_for_task()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L54"}, {"id": "crud_qc_task_assignee_soft_delete_assignees_by_task_ids", "label": "soft_delete_assignees_by_task_ids()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L108"}, {"id": "crud_qc_task_assignee_list_assignees_by_task_ids", "label": "list_assignees_by_task_ids()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L129"}, {"id": "crud_qc_task_assignee_is_user_assignee", "label": "is_user_assignee()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L158"}, {"id": "crud_qc_task_assignee_enrich_tasks_with_assignees", "label": "enrich_tasks_with_assignees()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L174"}, {"id": "crud_qc_task_assignee_rationale_63", "label": "\u5168\u91cf\u66ff\u6362\u4efb\u52a1\u8d1f\u8d23\u4eba\uff08\u8f6f\u5220\u65e7\u8bb0\u5f55 + \u63d2\u5165\u65b0\u8bb0\u5f55\uff09\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L63"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_assignee_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_assignee_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_assignee_py", "target": "sqlalchemy_orm", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L7", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_assignee_py", "target": "app_core_db_collation", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_assignee_py", "target": "app_core_utils", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L10", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_assignee_py", "target": "app_models_models", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L11", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_assignee_py", "target": "crud_qc_task_assignee_active_users_in_tenant", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L14", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_assignee_py", "target": "crud_qc_task_assignee_validate_assignee_user_ids", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L33", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_assignee_py", "target": "crud_qc_task_assignee_sync_assignees_for_task", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py", "source_location": "L54", "weight": 1.0}, {"source": "users_wLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_services_qc_work_order_fee_summary_py", "label": "qc_work_order_fee_summary.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L1"}, {"id": "services_qc_work_order_fee_summary_dec", "label": "_dec()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L27"}, {"id": "services_qc_work_order_fee_summary_received_amount_from_details", "label": "_received_amount_from_details()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L36"}, {"id": "services_qc_work_order_fee_summary_protocol_status_hint", "label": "_protocol_status_hint()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L45"}, {"id": "services_qc_work_order_fee_summary_protocol_overall_status", "label": "_protocol_overall_status()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L69"}, {"id": "services_qc_work_order_fee_summary_fmt_ymd", "label": "_fmt_ymd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L91"}, {"id": "services_qc_work_order_fee_summary_payment_detail_row", "label": "_payment_detail_row()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L98"}, {"id": "services_qc_work_order_fee_summary_sort_payment_details", "label": "_sort_payment_details()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L116"}, {"id": "services_qc_work_order_fee_summary_build_protocol_payment_summary", "label": "build_protocol_payment_summary()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L127"}, {"id": "services_qc_work_order_fee_summary_build_protocol_payment_summaries", "label": "build_protocol_payment_summaries()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L155"}, {"id": "services_qc_work_order_fee_summary_build_basic_experiment_fee_summary", "label": "build_basic_experiment_fee_summary()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L197"}, {"id": "services_qc_work_order_fee_summary_build_basic_experiment_fee_summaries", "label": "build_basic_experiment_fee_summaries()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L217"}, {"id": "services_qc_work_order_fee_summary_is_inbound_cell_storage_item", "label": "_is_inbound_cell_storage_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L253"}, {"id": "services_qc_work_order_fee_summary_load_reception_map", "label": "_load_reception_map()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L260"}, {"id": "services_qc_work_order_fee_summary_load_protocol_id_by_no", "label": "_load_protocol_id_by_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L274"}, {"id": "services_qc_work_order_fee_summary_effective_collection_protocol_id", "label": "_effective_collection_protocol_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L292"}, {"id": "services_qc_work_order_fee_summary_enrich_work_order_fee_summaries", "label": "enrich_work_order_fee_summaries()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L308"}, {"id": "services_qc_work_order_fee_summary_rationale_1", "label": "\u8d28\u68c0\u5de5\u5355 \u00b7 \u7528\u6237\u8d39\u7528\u6458\u8981\uff08\u91c7\u96c6\u534f\u8bae / \u57fa\u7840\u5b9e\u9a8c\uff09", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_services_qc_work_order_fee_summary_py", "target": "decimal", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_work_order_py", "label": "qc_work_order.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L1"}, {"id": "schemas_qc_work_order_outboundqcdetailapplication", "label": "OutboundQcDetailApplication", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L5"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "schemas_qc_work_order_outboundqcdetailpatient", "label": "OutboundQcDetailPatient", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L14"}, {"id": "schemas_qc_work_order_outboundqcdetailinfusionplan", "label": "OutboundQcDetailInfusionPlan", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L28"}, {"id": "schemas_qc_work_order_outboundqcdetailinfusionschedule", "label": "OutboundQcDetailInfusionSchedule", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L39"}, {"id": "schemas_qc_work_order_outboundqcdetailproduct", "label": "OutboundQcDetailProduct", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L51"}, {"id": "schemas_qc_work_order_outboundqcdetailresponse", "label": "OutboundQcDetailResponse", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L64"}, {"id": "schemas_qc_work_order_qcworkordercreatebody", "label": "QcWorkOrderCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L76"}, {"id": "schemas_qc_work_order_productionqcworkordercreatebody", "label": "ProductionQcWorkOrderCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L89"}, {"id": "schemas_qc_work_order_qcworkorderupdatebody", "label": "QcWorkOrderUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L98"}, {"id": "schemas_qc_work_order_rationale_99", "label": "\u7f16\u8f91\u8d28\u68c0\u5de5\u5355\uff08\u5165\u5e93/\u51fa\u5e93\u53ef\u6539\u5907\u6ce8\u4e0e\u72b6\u6001\uff1b\u4e34\u65f6\u53ef\u542b\u8d28\u68c0\u5bf9\u8c61\uff09", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L99"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_work_order_py", "target": "pydantic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_work_order_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_work_order_py", "target": "schemas_qc_work_order_outboundqcdetailapplication", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L5", "weight": 1.0}, {"source": "schemas_qc_work_order_outboundqcdetailapplication", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_work_order_py", "target": "schemas_qc_work_order_outboundqcdetailpatient", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L14", "weight": 1.0}, {"source": "schemas_qc_work_order_outboundqcdetailpatient", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L14", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_qc_work_order_py", "target": "schemas_qc_work_order_outboundqcdetailinfusionplan", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py", "source_location": "L28", "weight": 1.0}, {"source": "schemas_qc_work_order_outboundqcdetailinfusionplan", "target": "basLine truncated
|
||||
+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": "L44"}, {"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": "L61"}, {"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": "L79"}, {"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": "L101"}, {"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": "L115"}, {"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": "L149"}, {"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": "L185"}, {"id": "api_qc_thirdpartyitembody", "label": "ThirdPartyItemBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L205"}, {"id": "api_qc_thirdpartyitemupdatebody", "label": "ThirdPartyItemUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L217"}, {"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": "L230"}, {"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": "L259"}, {"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": "L274"}, {"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": "L303"}, {"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": "L334"}, {"id": "api_qc_labtestitembody", "label": "LabTestItemBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L354"}, {"id": "api_qc_labtestitemupdatebody", "label": "LabTestItemUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L365"}, {"id": "api_qc_itemparambody", "label": "ItemParamBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L379"}, {"id": "api_qc_taskresultbody", "label": "TaskResultBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L384"}, {"id": "api_qc_taskcompletewithresultbody", "label": "TaskCompleteWithResultBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L389"}, {"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": "L399"}, {"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": "L421"}, {"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": "L435"}, {"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": "L463"}, {"id": "api_Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_work_order_py", "label": "qc_work_order.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L1"}, {"id": "crud_qc_work_order_resolve_outbound_biz_type_for_schedule", "label": "resolve_outbound_biz_type_for_schedule()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L82"}, {"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": "L123"}, {"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": "L129"}, {"id": "crud_qc_work_order_normalize_date_bound", "label": "_normalize_date_bound()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L133"}, {"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": "L140"}, {"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": "L145"}, {"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": "L150"}, {"id": "crud_qc_work_order_validate_cell_product_id", "label": "_validate_cell_product_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L157"}, {"id": "crud_qc_work_order_enrich_work_order_cell_products", "label": "_enrich_work_order_cell_products()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L169"}, {"id": "crud_qc_work_order_enrich_outbound_work_orders", "label": "_enrich_outbound_work_orders()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L198"}, {"id": "crud_qc_work_order_outbound_qc_work_order_ids_by_keyword", "label": "_outbound_qc_work_order_ids_by_keyword()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L288"}, {"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": "L333"}, {"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": "L338"}, {"id": "crud_qc_work_order_effective_reception_source", "label": "_effective_reception_source()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L350"}, {"id": "crud_qc_work_order_effective_donation_sample_id", "label": "_effective_donation_sample_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L359"}, {"id": "crud_qc_work_order_effective_protocol_sample_id", "label": "_effective_protocol_sample_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L368"}, {"id": "crud_qc_work_order_sample_type_name_for_item", "label": "_sample_type_name_for_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L376"}, {"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": "L394"}, {"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": "L417"}, {"id": "crud_qc_work_order_enrich_production_work_order_refs", "label": "_enrich_production_work_order_refs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L550"}, {"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_orLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_work_order_py", "label": "qc_work_order.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L1"}, {"id": "crud_qc_work_order_resolve_outbound_biz_type_for_schedule", "label": "resolve_outbound_biz_type_for_schedule()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L83"}, {"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": "L124"}, {"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": "L130"}, {"id": "crud_qc_work_order_normalize_date_bound", "label": "_normalize_date_bound()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L134"}, {"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": "L141"}, {"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": "L146"}, {"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": "L151"}, {"id": "crud_qc_work_order_validate_cell_product_id", "label": "_validate_cell_product_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L158"}, {"id": "crud_qc_work_order_enrich_work_order_cell_products", "label": "_enrich_work_order_cell_products()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L170"}, {"id": "crud_qc_work_order_enrich_outbound_work_orders", "label": "_enrich_outbound_work_orders()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L199"}, {"id": "crud_qc_work_order_outbound_qc_work_order_ids_by_keyword", "label": "_outbound_qc_work_order_ids_by_keyword()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L289"}, {"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": "L334"}, {"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": "L339"}, {"id": "crud_qc_work_order_effective_reception_source", "label": "_effective_reception_source()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L351"}, {"id": "crud_qc_work_order_effective_donation_sample_id", "label": "_effective_donation_sample_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L360"}, {"id": "crud_qc_work_order_effective_protocol_sample_id", "label": "_effective_protocol_sample_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L369"}, {"id": "crud_qc_work_order_sample_type_name_for_item", "label": "_sample_type_name_for_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L377"}, {"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": "L395"}, {"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": "L418"}, {"id": "crud_qc_work_order_enrich_production_work_order_refs", "label": "_enrich_production_work_order_refs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L582"}, {"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_orLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_task_py", "label": "qc_task.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L1"}, {"id": "crud_qc_task_dec", "label": "_dec()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L35"}, {"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": "L41"}, {"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": "L45"}, {"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": "L58"}, {"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": "L63"}, {"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": "L96"}, {"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": "L133"}, {"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": "L241"}, {"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": "L252"}, {"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": "L297"}, {"id": "crud_qc_task_list_mine_tasks", "label": "list_mine_tasks()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L378"}, {"id": "crud_qc_task_assert_task_assignee", "label": "assert_task_assignee()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L461"}, {"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": "L468"}, {"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": "L486"}, {"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": "L495"}, {"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": "L523"}, {"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": "L540"}, {"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": "L544"}, {"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": "L588"}, {"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": "L640"}, {"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": "L670"}, {"id": "crud_qc_task_delete_qc_task", "label": "delete_qc_task()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py", "source_location": "L719"}, {"id": "crud_qc_task_rationale_599", "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": "L599"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_taLine truncated
|
||||
+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": "L44"}, {"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": "L61"}, {"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": "L79"}, {"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": "L101"}, {"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": "L115"}, {"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": "L149"}, {"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": "L185"}, {"id": "api_qc_thirdpartyitembody", "label": "ThirdPartyItemBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L205"}, {"id": "api_qc_thirdpartyitemupdatebody", "label": "ThirdPartyItemUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L217"}, {"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": "L230"}, {"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": "L259"}, {"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": "L274"}, {"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": "L303"}, {"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": "L334"}, {"id": "api_qc_labtestitembody", "label": "LabTestItemBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L354"}, {"id": "api_qc_labtestitemupdatebody", "label": "LabTestItemUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L365"}, {"id": "api_qc_itemparambody", "label": "ItemParamBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L379"}, {"id": "api_qc_taskresultbody", "label": "TaskResultBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L384"}, {"id": "api_qc_taskcompletewithresultbody", "label": "TaskCompleteWithResultBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py", "source_location": "L389"}, {"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": "L399"}, {"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": "L421"}, {"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": "L435"}, {"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": "L463"}, {"id": "api_Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_models_models_py", "label": "models.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L1"}, {"id": "models_models_userrole", "label": "UserRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L10"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_models_sysuser", "label": "SysUser", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L22"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_models_sysrole", "label": "SysRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L48"}, {"id": "models_models_sysuserrole", "label": "SysUserRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L68"}, {"id": "models_models_sysrolemenu", "label": "SysRoleMenu", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L87"}, {"id": "models_models_sysroledatascopedetail", "label": "SysRoleDataScopeDetail", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L106"}, {"id": "models_models_sysmenu", "label": "SysMenu", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L126"}, {"id": "models_models_sysdept", "label": "SysDept", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L152"}, {"id": "models_models_systenant", "label": "SysTenant", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L175"}, {"id": "models_models_syssite", "label": "SysSite", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L195"}, {"id": "models_models_syspost", "label": "SysPost", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L220"}, {"id": "models_models_sysuserpost", "label": "SysUserPost", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L240"}, {"id": "models_models_bizitemunit", "label": "BizItemUnit", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L259"}, {"id": "models_models_bizexpresscompany", "label": "BizExpressCompany", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L278"}, {"id": "models_models_bizcustomer", "label": "BizCustomer", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L297"}, {"id": "models_models_bizcellsampletype", "label": "BizCellSampleType", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L320"}, {"id": "models_models_bizcollectionregion", "label": "BizCollectionRegion", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L341"}, {"id": "models_models_bizcollectionhospital", "label": "BizCollectionHospital", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L359"}, {"id": "models_models_bizcollectionprotocolno", "label": "BizCollectionProtocolNo", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L378"}, {"id": "models_models_bizbiznosequence", "label": "BizBizNoSequence", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L400"}, {"id": "models_models_bizsamplecode", "label": "BizSampleCode", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L420"}, {"id": "models_models_sysdicttype", "label": "SysDictType", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L448"}, {"id": "models_models_sysethnic", "label": "SysEthnic", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L467"}, {"id": "models_models_sysdictdata", "label": "SysDictData", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location"Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_storage_release_review_py", "label": "storage_release_review.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L1"}, {"id": "crud_storage_release_review_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L49"}, {"id": "crud_storage_release_review_total_pages", "label": "total_pages()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L53"}, {"id": "crud_storage_release_review_row_to_dict", "label": "_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L59"}, {"id": "crud_storage_release_review_create_review_from_reception", "label": "create_review_from_reception()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L87"}, {"id": "crud_storage_release_review_list_reviews", "label": "list_reviews()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L125"}, {"id": "crud_storage_release_review_enrich_review_list_items", "label": "_enrich_review_list_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L190"}, {"id": "crud_storage_release_review_get_user_name", "label": "_get_user_name()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L271"}, {"id": "crud_storage_release_review_get_review_detail", "label": "get_review_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L276"}, {"id": "crud_storage_release_review_build_cell_storage_protocol_info", "label": "_build_cell_storage_protocol_info()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L339"}, {"id": "crud_storage_release_review_build_research_donation_protocol_info", "label": "_build_research_donation_protocol_info()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L396"}, {"id": "crud_storage_release_review_build_cell_storage_transport_info", "label": "_build_cell_storage_transport_info()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L453"}, {"id": "crud_storage_release_review_build_research_donation_transport_info", "label": "_build_research_donation_transport_info()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L487"}, {"id": "crud_storage_release_review_build_reception_info", "label": "_build_reception_info()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L521"}, {"id": "crud_storage_release_review_build_qc_info", "label": "_build_qc_info()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L544"}, {"id": "crud_storage_release_review_build_production_info", "label": "_build_production_info()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L563"}, {"id": "crud_storage_release_review_submit_review", "label": "submit_review()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L581"}, {"id": "crud_storage_release_review_batch_submit_review", "label": "batch_submit_review()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L616"}, {"id": "crud_storage_release_review_store_sample", "label": "store_sample()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L645"}, {"id": "crud_storage_release_review_batch_store_samples", "label": "batch_store_samples()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py", "source_location": "L699"}, {"id": "crud_storage_release_review_get_storage_release_map_for_samples", "label": "get_storage_release_map_for_samples()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/storaLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_work_order_py", "label": "qc_work_order.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L1"}, {"id": "crud_qc_work_order_resolve_outbound_biz_type_for_schedule", "label": "resolve_outbound_biz_type_for_schedule()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L82"}, {"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": "L123"}, {"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": "L129"}, {"id": "crud_qc_work_order_normalize_date_bound", "label": "_normalize_date_bound()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L133"}, {"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": "L140"}, {"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": "L145"}, {"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": "L150"}, {"id": "crud_qc_work_order_validate_cell_product_id", "label": "_validate_cell_product_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L157"}, {"id": "crud_qc_work_order_enrich_work_order_cell_products", "label": "_enrich_work_order_cell_products()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L169"}, {"id": "crud_qc_work_order_enrich_outbound_work_orders", "label": "_enrich_outbound_work_orders()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L198"}, {"id": "crud_qc_work_order_outbound_qc_work_order_ids_by_keyword", "label": "_outbound_qc_work_order_ids_by_keyword()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L288"}, {"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": "L333"}, {"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": "L338"}, {"id": "crud_qc_work_order_effective_reception_source", "label": "_effective_reception_source()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L350"}, {"id": "crud_qc_work_order_effective_donation_sample_id", "label": "_effective_donation_sample_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L359"}, {"id": "crud_qc_work_order_effective_protocol_sample_id", "label": "_effective_protocol_sample_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L368"}, {"id": "crud_qc_work_order_sample_type_name_for_item", "label": "_sample_type_name_for_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L376"}, {"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": "L394"}, {"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": "L417"}, {"id": "crud_qc_work_order_enrich_production_work_order_refs", "label": "_enrich_production_work_order_refs()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L581"}, {"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_orLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_work_order_py", "label": "qc_work_order.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L1"}, {"id": "crud_qc_work_order_resolve_outbound_biz_type_for_schedule", "label": "resolve_outbound_biz_type_for_schedule()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L82"}, {"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": "L123"}, {"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": "L129"}, {"id": "crud_qc_work_order_normalize_date_bound", "label": "_normalize_date_bound()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L133"}, {"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": "L140"}, {"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": "L145"}, {"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": "L150"}, {"id": "crud_qc_work_order_validate_cell_product_id", "label": "_validate_cell_product_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L157"}, {"id": "crud_qc_work_order_enrich_work_order_cell_products", "label": "_enrich_work_order_cell_products()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L169"}, {"id": "crud_qc_work_order_enrich_outbound_work_orders", "label": "_enrich_outbound_work_orders()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L198"}, {"id": "crud_qc_work_order_outbound_qc_work_order_ids_by_keyword", "label": "_outbound_qc_work_order_ids_by_keyword()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L288"}, {"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": "L333"}, {"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": "L338"}, {"id": "crud_qc_work_order_effective_reception_source", "label": "_effective_reception_source()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L350"}, {"id": "crud_qc_work_order_effective_donation_sample_id", "label": "_effective_donation_sample_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L359"}, {"id": "crud_qc_work_order_effective_protocol_sample_id", "label": "_effective_protocol_sample_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L368"}, {"id": "crud_qc_work_order_sample_type_name_for_item", "label": "_sample_type_name_for_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L376"}, {"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": "L394"}, {"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": "L417"}, {"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": "L550"}, {"id": "crud_qc_work_order_user_nick_name_map", "label": "_user_nick_name_map()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "LLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_production_py", "label": "production.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L1"}, {"id": "api_production_get_tenant_no", "label": "_get_tenant_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L64"}, {"id": "api_production_consumablecreatebody", "label": "ConsumableCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L77"}, {"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": "L91"}, {"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": "L106"}, {"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": "L120"}, {"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": "L130"}, {"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": "L158"}, {"id": "api_production_delete_consumable", "label": "delete_consumable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L187"}, {"id": "api_production_stockinbody", "label": "StockInBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L199"}, {"id": "api_production_stockoutbody", "label": "StockOutBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L205"}, {"id": "api_production_batchstockinitem", "label": "BatchStockInItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L213"}, {"id": "api_production_batchstockinbody", "label": "BatchStockInBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L220"}, {"id": "api_production_batchstockoutitem", "label": "BatchStockOutItem", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L226"}, {"id": "api_production_batchstockoutbody", "label": "BatchStockOutBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L232"}, {"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": "L241"}, {"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": "L263"}, {"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": "L287"}, {"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": "L305"}, {"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": "L324"}, {"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": "L343"}, {"id": "api_production_reagentcreatebody", "label": "ReagentCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L369"}, {"id": "api_production_reagentupdatebody", "label": "ReagentUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L383"}, {"id": "api_production_list_reagents", "label": "list_reagents()", "file_type": "code", "source_fiLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_services_qc_work_order_fee_summary_py", "label": "qc_work_order_fee_summary.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L1"}, {"id": "services_qc_work_order_fee_summary_dec", "label": "_dec()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L26"}, {"id": "services_qc_work_order_fee_summary_received_amount_from_details", "label": "_received_amount_from_details()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L35"}, {"id": "services_qc_work_order_fee_summary_protocol_status_hint", "label": "_protocol_status_hint()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L44"}, {"id": "services_qc_work_order_fee_summary_protocol_overall_status", "label": "_protocol_overall_status()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L68"}, {"id": "services_qc_work_order_fee_summary_build_protocol_payment_summary", "label": "build_protocol_payment_summary()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L90"}, {"id": "services_qc_work_order_fee_summary_build_protocol_payment_summaries", "label": "build_protocol_payment_summaries()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L114"}, {"id": "services_qc_work_order_fee_summary_build_basic_experiment_fee_summary", "label": "build_basic_experiment_fee_summary()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L156"}, {"id": "services_qc_work_order_fee_summary_build_basic_experiment_fee_summaries", "label": "build_basic_experiment_fee_summaries()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L176"}, {"id": "services_qc_work_order_fee_summary_enrich_work_order_fee_summaries", "label": "enrich_work_order_fee_summaries()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L212"}, {"id": "services_qc_work_order_fee_summary_rationale_1", "label": "\u8d28\u68c0\u5de5\u5355 \u00b7 \u7528\u6237\u8d39\u7528\u6458\u8981\uff08\u91c7\u96c6\u534f\u8bae / \u57fa\u7840\u5b9e\u9a8c\uff09", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_services_qc_work_order_fee_summary_py", "target": "decimal", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_services_qc_work_order_fee_summary_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_services_qc_work_order_fee_summary_py", "target": "sqlalchemy_orm", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L7", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_services_qc_work_order_fee_summary_py", "target": "app_models_clinical_payment", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_services_qc_work_order_fee_summary_py", "target": "app_models_models", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L10", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_services_qc_work_order_fee_summary_py", "target": "services_qc_work_order_fee_summary_dec", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py", "source_location": "L26", "weight": 1.0}, {"source": "users_wuzLine truncated
|
||||
@@ -1287,9 +1287,17 @@ class BizQcWorkOrder(Base):
|
||||
default="inbound",
|
||||
comment="质检业务类型 inbound入库质检 outbound出库质检 temporary临时质检",
|
||||
)
|
||||
trigger_source = Column(
|
||||
String(20),
|
||||
nullable=False,
|
||||
default="reception",
|
||||
comment="触发来源 reception=样本接收 production=生产过程",
|
||||
)
|
||||
infusion_schedule_id = Column(String(64), nullable=True, comment="中试输注计划ID(出库质检关联)")
|
||||
biz_type = Column(String(20), nullable=True, comment="业务类型: pilot_service=中试服务, clinical_application=临床应用")
|
||||
cell_product_id = Column(String(64), nullable=True, comment="质检对象-细胞产品ID")
|
||||
production_work_order_id = Column(String(64), nullable=True, comment="关联生产工单ID(生产过程触发时)")
|
||||
production_task_id = Column(String(64), nullable=True, comment="关联生产任务ID(可选)")
|
||||
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="含第三方检测")
|
||||
|
||||
@@ -86,6 +86,15 @@ class QcWorkOrderCreateBody(BaseModel):
|
||||
remark: Optional[str] = Field(None, description="备注")
|
||||
|
||||
|
||||
class ProductionQcWorkOrderCreateBody(BaseModel):
|
||||
"""生产过程派发质检工单"""
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
cell_product_id: str = Field(..., alias="cellProductId", description="细胞产品ID")
|
||||
production_task_id: Optional[str] = Field(None, alias="productionTaskId", description="关联生产任务ID(可选)")
|
||||
remark: Optional[str] = Field(None, description="备注")
|
||||
|
||||
|
||||
class QcWorkOrderUpdateBody(BaseModel):
|
||||
"""编辑质检工单(入库/出库可改备注与状态;临时可含质检对象)"""
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
@@ -0,0 +1,368 @@
|
||||
"""质检工单 · 用户费用摘要(采集协议 / 基础实验)"""
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models.clinical_payment import BizPilotPayment
|
||||
from app.models.models import (
|
||||
BizPilotInfusionSchedule,
|
||||
BizProtocolPayment,
|
||||
BizProtocolPaymentDetail,
|
||||
)
|
||||
|
||||
_PAY_MODE_LABELS = {"dj": "趸交", "fq": "分期"}
|
||||
_PAY_STATUS_LABELS = {
|
||||
"dfj": "待缴费",
|
||||
"jfqrz": "缴费确认中",
|
||||
"yjf": "已缴费",
|
||||
"tfqrz": "退费确认中",
|
||||
"ytf": "已退费",
|
||||
}
|
||||
|
||||
|
||||
def _dec(val: Any) -> Optional[float]:
|
||||
if val is None:
|
||||
return None
|
||||
try:
|
||||
return float(val)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def _received_amount_from_details(details: List[BizProtocolPaymentDetail]) -> float:
|
||||
total = Decimal("0")
|
||||
for d in details:
|
||||
st = (d.pay_status or "").strip()
|
||||
if st in ("yjf", "jfqrz"):
|
||||
total += d.transfer_amount or Decimal("0")
|
||||
return float(total)
|
||||
|
||||
|
||||
def _protocol_status_hint(pay_mode: str, statuses: List[str]) -> str:
|
||||
counts: Dict[str, int] = {}
|
||||
for st in statuses:
|
||||
if st:
|
||||
counts[st] = counts.get(st, 0) + 1
|
||||
paid = counts.get("yjf", 0)
|
||||
confirm = counts.get("jfqrz", 0)
|
||||
pending = counts.get("dfj", 0)
|
||||
if pay_mode == "fq":
|
||||
parts: List[str] = ["分期"]
|
||||
if paid:
|
||||
parts.append(f"{paid} 期已缴")
|
||||
if confirm:
|
||||
parts.append(f"{confirm} 期待确认")
|
||||
if pending:
|
||||
parts.append(f"{pending} 期待缴费")
|
||||
return " · ".join(parts) if len(parts) > 1 else parts[0]
|
||||
if confirm:
|
||||
return f"{confirm} 期待确认" if confirm > 1 else "收款确认中"
|
||||
if pending:
|
||||
return "待缴费"
|
||||
return ""
|
||||
|
||||
|
||||
def _protocol_overall_status(
|
||||
statuses: List[str], contract: Optional[float], pending: Optional[float]
|
||||
) -> Dict[str, str]:
|
||||
if "tfqrz" in statuses:
|
||||
return {"overallPayStatus": "tfqrz", "overallPayStatusLabel": "退费确认中", "overallPayStatusTagType": "warning"}
|
||||
if statuses and all(s == "ytf" for s in statuses):
|
||||
return {"overallPayStatus": "ytf", "overallPayStatusLabel": "已退费", "overallPayStatusTagType": "info"}
|
||||
if (
|
||||
contract is not None
|
||||
and pending is not None
|
||||
and pending <= 0
|
||||
and "dfj" not in statuses
|
||||
and "jfqrz" not in statuses
|
||||
):
|
||||
return {"overallPayStatus": "cleared", "overallPayStatusLabel": "已缴清", "overallPayStatusTagType": "success"}
|
||||
if "jfqrz" in statuses:
|
||||
return {"overallPayStatus": "jfqrz", "overallPayStatusLabel": "收款确认中", "overallPayStatusTagType": "warning"}
|
||||
if "dfj" in statuses:
|
||||
return {"overallPayStatus": "dfj", "overallPayStatusLabel": "待缴费", "overallPayStatusTagType": "info"}
|
||||
return {"overallPayStatus": "", "overallPayStatusLabel": "—", "overallPayStatusTagType": "info"}
|
||||
|
||||
|
||||
def _fmt_ymd(val: Any) -> str:
|
||||
s = (str(val or "")).strip()
|
||||
if len(s) == 8 and s.isdigit():
|
||||
return f"{s[:4]}-{s[4:6]}-{s[6:8]}"
|
||||
return s
|
||||
|
||||
|
||||
def _payment_detail_row(d: BizProtocolPaymentDetail, pay_mode: str, idx: int) -> Dict[str, Any]:
|
||||
st = (d.pay_status or "").strip()
|
||||
inst_no = d.installment_no
|
||||
if pay_mode == "fq" and inst_no is not None:
|
||||
label = f"第{inst_no}期"
|
||||
else:
|
||||
label = f"缴费{idx + 1}"
|
||||
return {
|
||||
"installmentNo": inst_no,
|
||||
"installmentLabel": label,
|
||||
"installmentDueDate": _fmt_ymd(d.installment_due_date),
|
||||
"dueAmount": _dec(d.due_amount),
|
||||
"transferAmount": _dec(d.transfer_amount),
|
||||
"payStatus": st,
|
||||
"payStatusLabel": _PAY_STATUS_LABELS.get(st, st or "—"),
|
||||
}
|
||||
|
||||
|
||||
def _sort_payment_details(details: List[BizProtocolPaymentDetail]) -> List[BizProtocolPaymentDetail]:
|
||||
return sorted(
|
||||
details,
|
||||
key=lambda d: (
|
||||
d.installment_no if d.installment_no is not None else 10_000,
|
||||
d.order_num if d.order_num is not None else 0,
|
||||
d.create_time or datetime.min,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def build_protocol_payment_summary(
|
||||
pay: Optional[BizProtocolPayment],
|
||||
details: List[BizProtocolPaymentDetail],
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
if not pay:
|
||||
return None
|
||||
pay_mode = (pay.pay_mode or "dj").strip() or "dj"
|
||||
contract = _dec(pay.contract_amount)
|
||||
sorted_details = _sort_payment_details(details)
|
||||
detail_rows = [_payment_detail_row(d, pay_mode, i) for i, d in enumerate(sorted_details)]
|
||||
received = _received_amount_from_details(sorted_details)
|
||||
pending = max(contract - received, 0) if contract is not None else None
|
||||
statuses = [(d.pay_status or "").strip() for d in sorted_details]
|
||||
overall = _protocol_overall_status(statuses, contract, pending)
|
||||
hint = _protocol_status_hint(pay_mode, statuses) or overall["overallPayStatusLabel"]
|
||||
return {
|
||||
"payMode": pay_mode,
|
||||
"payModeLabel": _PAY_MODE_LABELS.get(pay_mode, pay_mode),
|
||||
"contractAmount": contract,
|
||||
"receivedAmount": received,
|
||||
"pendingAmount": pending,
|
||||
"statusHint": hint,
|
||||
"installmentCount": len(detail_rows) if pay_mode == "fq" else None,
|
||||
"paymentDetails": detail_rows,
|
||||
**overall,
|
||||
}
|
||||
|
||||
|
||||
def build_protocol_payment_summaries(
|
||||
db: Session,
|
||||
protocol_ids: List[str],
|
||||
tenant_no: str,
|
||||
) -> Dict[str, Dict[str, Any]]:
|
||||
ids = [x.strip() for x in protocol_ids if (x or "").strip()]
|
||||
if not ids:
|
||||
return {}
|
||||
payments = (
|
||||
db.query(BizProtocolPayment)
|
||||
.filter(
|
||||
BizProtocolPayment.collection_protocol_id.in_(ids),
|
||||
BizProtocolPayment.tenant_no == tenant_no,
|
||||
BizProtocolPayment.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
pay_by_proto = {p.collection_protocol_id: p for p in payments}
|
||||
payment_ids = [p.id for p in payments]
|
||||
details_by_payment: Dict[str, List[BizProtocolPaymentDetail]] = {}
|
||||
if payment_ids:
|
||||
for d in (
|
||||
db.query(BizProtocolPaymentDetail)
|
||||
.filter(
|
||||
BizProtocolPaymentDetail.payment_id.in_(payment_ids),
|
||||
BizProtocolPaymentDetail.tenant_no == tenant_no,
|
||||
BizProtocolPaymentDetail.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
):
|
||||
details_by_payment.setdefault(d.payment_id, []).append(d)
|
||||
out: Dict[str, Dict[str, Any]] = {}
|
||||
for pid in ids:
|
||||
pay = pay_by_proto.get(pid)
|
||||
if not pay:
|
||||
continue
|
||||
summary = build_protocol_payment_summary(pay, details_by_payment.get(pay.id, []))
|
||||
if summary:
|
||||
out[pid] = summary
|
||||
return out
|
||||
|
||||
|
||||
def build_basic_experiment_fee_summary(
|
||||
schedule: Optional[BizPilotInfusionSchedule],
|
||||
payment: Optional[BizPilotPayment],
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
sale = _dec(schedule.amount) if schedule else None
|
||||
if not schedule and not payment:
|
||||
return None
|
||||
pay_status = (payment.pay_status or "").strip() if payment else ""
|
||||
transfer = None
|
||||
if payment and pay_status in ("yjf", "jfqrz"):
|
||||
transfer = _dec(payment.transfer_amount)
|
||||
return {
|
||||
"saleAmount": sale,
|
||||
"paymentAmount": _dec(payment.amount) if payment else None,
|
||||
"transferAmount": transfer,
|
||||
"payStatus": pay_status or None,
|
||||
"payStatusLabel": _PAY_STATUS_LABELS.get(pay_status, "—") if pay_status else None,
|
||||
}
|
||||
|
||||
|
||||
def build_basic_experiment_fee_summaries(
|
||||
db: Session,
|
||||
schedule_ids: List[str],
|
||||
tenant_no: str,
|
||||
) -> Dict[str, Dict[str, Any]]:
|
||||
ids = [x.strip() for x in schedule_ids if (x or "").strip()]
|
||||
if not ids:
|
||||
return {}
|
||||
schedules = {
|
||||
s.id: s
|
||||
for s in db.query(BizPilotInfusionSchedule)
|
||||
.filter(
|
||||
BizPilotInfusionSchedule.id.in_(ids),
|
||||
BizPilotInfusionSchedule.tenant_no == tenant_no,
|
||||
BizPilotInfusionSchedule.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
}
|
||||
payments = {
|
||||
p.infusion_schedule_id: p
|
||||
for p in db.query(BizPilotPayment)
|
||||
.filter(
|
||||
BizPilotPayment.infusion_schedule_id.in_(ids),
|
||||
BizPilotPayment.tenant_no == tenant_no,
|
||||
BizPilotPayment.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
}
|
||||
out: Dict[str, Dict[str, Any]] = {}
|
||||
for sid in ids:
|
||||
summary = build_basic_experiment_fee_summary(schedules.get(sid), payments.get(sid))
|
||||
if summary:
|
||||
out[sid] = summary
|
||||
return out
|
||||
|
||||
|
||||
def _is_inbound_cell_storage_item(item: Dict[str, Any]) -> bool:
|
||||
wo_type = (item.get("workOrderType") or "inbound").strip() or "inbound"
|
||||
if wo_type in ("outbound", "temporary"):
|
||||
return False
|
||||
return (item.get("receptionSource") or "cell_storage").strip() in ("", "cell_storage")
|
||||
|
||||
|
||||
def _load_reception_map(db: Session, reception_ids: List[str]) -> Dict[str, Any]:
|
||||
from app.models.models import BizSampleReception
|
||||
|
||||
ids = [x for x in reception_ids if x]
|
||||
if not ids:
|
||||
return {}
|
||||
return {
|
||||
r.id: r
|
||||
for r in db.query(BizSampleReception)
|
||||
.filter(BizSampleReception.id.in_(ids), BizSampleReception.del_flag == 0)
|
||||
.all()
|
||||
}
|
||||
|
||||
|
||||
def _load_protocol_id_by_no(db: Session, protocol_nos: List[str], tenant_no: str) -> Dict[str, str]:
|
||||
from app.models.models import BizCollectionProtocol
|
||||
|
||||
nos = [x for x in protocol_nos if x]
|
||||
if not nos:
|
||||
return {}
|
||||
rows = (
|
||||
db.query(BizCollectionProtocol.protocol_no, BizCollectionProtocol.id)
|
||||
.filter(
|
||||
BizCollectionProtocol.protocol_no.in_(nos),
|
||||
BizCollectionProtocol.tenant_no == tenant_no,
|
||||
BizCollectionProtocol.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
return {(r.protocol_no or "").strip(): r.id for r in rows if (r.protocol_no or "").strip()}
|
||||
|
||||
|
||||
def _effective_collection_protocol_id(
|
||||
item: Dict[str, Any],
|
||||
rec: Optional[Any],
|
||||
proto_no_map: Dict[str, str],
|
||||
) -> str:
|
||||
pid = (item.get("collectionProtocolId") or "").strip()
|
||||
if pid:
|
||||
return pid
|
||||
if rec is not None:
|
||||
pid = (getattr(rec, "collection_protocol_id", None) or "").strip()
|
||||
if pid:
|
||||
return pid
|
||||
pno = (item.get("protocolNo") or "").strip()
|
||||
return proto_no_map.get(pno, "")
|
||||
|
||||
|
||||
def enrich_work_order_fee_summaries(
|
||||
db: Session,
|
||||
items: List[Dict[str, Any]],
|
||||
tenant_no: str,
|
||||
) -> List[Dict[str, Any]]:
|
||||
if not items or not tenant_no:
|
||||
return items
|
||||
|
||||
inbound_items = [x for x in items if _is_inbound_cell_storage_item(x)]
|
||||
rec_ids = [(x.get("receptionId") or "").strip() for x in inbound_items if (x.get("receptionId") or "").strip()]
|
||||
rec_map = _load_reception_map(db, rec_ids)
|
||||
proto_nos = list(
|
||||
dict.fromkeys(
|
||||
(x.get("protocolNo") or "").strip()
|
||||
for x in inbound_items
|
||||
if (x.get("protocolNo") or "").strip()
|
||||
)
|
||||
)
|
||||
proto_no_map = _load_protocol_id_by_no(db, proto_nos, tenant_no)
|
||||
|
||||
protocol_ids: List[str] = []
|
||||
for item in inbound_items:
|
||||
rec = rec_map.get((item.get("receptionId") or "").strip())
|
||||
pid = _effective_collection_protocol_id(item, rec, proto_no_map)
|
||||
if pid:
|
||||
protocol_ids.append(pid)
|
||||
|
||||
schedule_ids = list(
|
||||
dict.fromkeys(
|
||||
(x.get("infusionScheduleId") or "").strip()
|
||||
for x in items
|
||||
if (x.get("workOrderType") or "") == "outbound"
|
||||
and (x.get("bizType") or "") == "basic_experiment"
|
||||
and (x.get("infusionScheduleId") or "").strip()
|
||||
)
|
||||
)
|
||||
|
||||
payment_map = build_protocol_payment_summaries(db, list(dict.fromkeys(protocol_ids)), tenant_no)
|
||||
fee_map = build_basic_experiment_fee_summaries(db, schedule_ids, tenant_no)
|
||||
|
||||
for item in items:
|
||||
wo_type = item.get("workOrderType") or "inbound"
|
||||
if wo_type == "outbound":
|
||||
item["paymentSummary"] = None
|
||||
if (item.get("bizType") or "") == "basic_experiment":
|
||||
sid = (item.get("infusionScheduleId") or "").strip()
|
||||
item["feeSummary"] = fee_map.get(sid) if sid else None
|
||||
else:
|
||||
item["feeSummary"] = None
|
||||
elif wo_type == "temporary":
|
||||
item["paymentSummary"] = None
|
||||
item["feeSummary"] = None
|
||||
else:
|
||||
item["feeSummary"] = None
|
||||
if _is_inbound_cell_storage_item(item):
|
||||
rec = rec_map.get((item.get("receptionId") or "").strip())
|
||||
pid = _effective_collection_protocol_id(item, rec, proto_no_map)
|
||||
item["paymentSummary"] = payment_map.get(pid) if pid else None
|
||||
else:
|
||||
item["paymentSummary"] = None
|
||||
return items
|
||||
File diff suppressed because it is too large.
Load diff
+8772
-6645
File diff suppressed because it is too large.
Load diff
@@ -1,12 +1,12 @@
|
||||
# Graph Report - app (2026-06-12)
|
||||
|
||||
## Corpus Check
|
||||
- 188 files · ~199,729 words
|
||||
- 189 files · ~201,737 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 3570 nodes · 16121 edges · 52 communities detected
|
||||
- Extraction: 37% EXTRACTED · 63% INFERRED · 0% AMBIGUOUS · INFERRED: 10132 edges (avg confidence: 0.61)
|
||||
- 3596 nodes · 16321 edges · 47 communities detected
|
||||
- Extraction: 37% EXTRACTED · 63% INFERRED · 0% AMBIGUOUS · INFERRED: 10283 edges (avg confidence: 0.61)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
@@ -51,28 +51,23 @@
|
||||
- [[_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 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]]
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `success_response()` - 552 edges
|
||||
2. `error_response()` - 452 edges
|
||||
3. `SysUser` - 377 edges
|
||||
4. `BizQcTaskResult` - 278 edges
|
||||
1. `success_response()` - 554 edges
|
||||
2. `error_response()` - 454 edges
|
||||
3. `SysUser` - 379 edges
|
||||
4. `BizQcTaskResult` - 280 edges
|
||||
5. `BizQcMaterialUsage` - 278 edges
|
||||
6. `BizQcMaterial` - 273 edges
|
||||
7. `BizQcMaterialStockBatch` - 265 edges
|
||||
8. `BizMaterialStockLog` - 260 edges
|
||||
9. `BizPilotPayment` - 259 edges
|
||||
9. `BizPilotPayment` - 260 edges
|
||||
10. `BizMaterial` - 257 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
@@ -80,8 +75,8 @@
|
||||
core/api_request_log_middleware.py → models/models.py
|
||||
- `get_menu_list()` --calls--> `success_response()` [INFERRED]
|
||||
api/menu.py → core/response.py
|
||||
- `保留匹配节点及其全部上级,供关键词检索后仍能正确组树。` --uses--> `SysDept` [INFERRED]
|
||||
crud/dept.py → models/models.py
|
||||
- `中试服务交付管理 API(交付信息、交付物料、交付方式)` --uses--> `SysUser` [INFERRED]
|
||||
api/pilot_delivery.py → models/models.py
|
||||
- `物品单位 CRUD(biz_item_unit)` --uses--> `BizItemUnit` [INFERRED]
|
||||
crud/item_unit.py → models/models.py
|
||||
- `快递公司 CRUD(biz_express_company)` --uses--> `BizExpressCompany` [INFERRED]
|
||||
@@ -91,252 +86,232 @@
|
||||
|
||||
### Community 0 - "Community 0"
|
||||
Cohesion: 0.01
|
||||
Nodes (622): create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post(), create_role_management() (+614 more)
|
||||
Nodes (613): create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post(), create_role_management() (+605 more)
|
||||
|
||||
### Community 1 - "Community 1"
|
||||
Cohesion: 0.01
|
||||
Nodes (502): attachment_download_url(), AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, dict_data_options(), DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody (+494 more)
|
||||
Nodes (489): BatchPaymentIdsBody, BatchSubmitReceiptBody, BatchSubmitRefundBody, ConfirmReceiptBody, ConfirmRefundBody, PaymentIdBody, SubmitReceiptBody, SubmitRefundBody (+481 more)
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.06
|
||||
Nodes (303): 环境检测 — 检测项维护 + 登记管理 API, 保险公司及险种价格管理 API(保险公司 + 开票信息 + 险种价格), Base, ApiRequestLogCRUD, 耗材包 CRUD(biz_consumable_pack + biz_consumable_pack_item), 耗材 CRUD(biz_consumable), 字典类型 CRUD(sys_dict_type), 批量入库,同一事务;任一条失败则全部回滚。 (+295 more)
|
||||
Cohesion: 0.05
|
||||
Nodes (278): 环境检测 — 检测项维护 + 登记管理 API, InsuranceCompanyCreateBody, InsuranceCompanyInvoiceCreateBody, InsuranceCompanyInvoiceUpdateBody, InsuranceCompanyUpdateBody, InsuranceProjectPriceCreateBody, InsuranceProjectPriceUpdateBody, 保险公司及险种价格管理 API(保险公司 + 开票信息 + 险种价格) (+270 more)
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.02
|
||||
Nodes (214): list_customers(), list_protocol_nos(), _normalize_date_bound(), list_ethnics_for_select(), _list_insurance_companies(), _total_pages(), apply_data_scope(), _get_child_dept_ids() (+206 more)
|
||||
Cohesion: 0.07
|
||||
Nodes (206): CellSampleTypeCreateBody, CellSampleTypeUpdateBody, CollectionRegionCreateBody, CollectionRegionUpdateBody, CustomerCreateBody, CustomerUpdateBody, HospitalCreateBody, HospitalUpdateBody (+198 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.07
|
||||
Nodes (209): CellSampleTypeCreateBody, CellSampleTypeUpdateBody, CollectionRegionCreateBody, CollectionRegionUpdateBody, CustomerCreateBody, CustomerUpdateBody, HospitalCreateBody, HospitalUpdateBody (+201 more)
|
||||
Cohesion: 0.05
|
||||
Nodes (182): generate_uuid(), _deduct_fee_on_delivery(), 中试交付管理 CRUD(交付信息、交付物料、交付方式 + 费用扣减), 创建交付时扣减费用。 流程: 1. schedule → plan → application 2. application.chan, List all deliveries for an application (through plan → schedule → delivery)., Bulk save: soft-delete existing + insert new., Create or update delivery method (upsert pattern)., activate_channel_agreement() (+174 more)
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.02
|
||||
Nodes (177): generate_uuid(), _apply_cell_product_status_change(), create_cell_product(), batch_stock_in(), batch_stock_out(), consumable_code_exists(), create_consumable(), _dec() (+169 more)
|
||||
Nodes (153): delete(), get_multi_with_filters(), 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() (+145 more)
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.02
|
||||
Nodes (173): _format_attachment_file_size(), urls_to_attachment_list(), list_production_tasks(), apply_task_result(), assert_task_assignee(), _active_users_in_tenant(), enrich_tasks_with_assignees(), is_user_assignee() (+165 more)
|
||||
Cohesion: 0.03
|
||||
Nodes (117): attachment_download_url(), AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, dict_data_options(), DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody (+109 more)
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.02
|
||||
Nodes (142): get_role_menus(), get_user_by_id(), _avatar_url_field(), _build_current_user_payload(), _build_user_info_payload(), get_current_user_profile(), _jwt_user_payload(), logout() (+134 more)
|
||||
Cohesion: 0.03
|
||||
Nodes (95): get_designer_data(), _error_json(), lifespan(), 数据库异常:返回 JSON 并保留 CORS 头,避免浏览器只报跨域错误, 未捕获异常:统一 JSON 500,确保跨域场景下仍有 Access-Control-Allow-Origin, sqlalchemy_exception_handler(), unhandled_exception_handler(), BaseHTTPMiddleware (+87 more)
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.03
|
||||
Nodes (103): _business_type_label(), get_business_all_tasks(), _get_business_form_fields(), get_designer_data(), get_instance_detail(), ProcessDefCreateBody, ProcessDefUpdateBody, PublishVersionBody (+95 more)
|
||||
Nodes (108): batch_delete_research_donations(), change_donation_status(), convert_from_storage(), convert_to_storage(), create_research_donation(), delete_research_donation(), _get_current_user_id(), get_research_donation_detail() (+100 more)
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.04
|
||||
Nodes (100): _ensure_customer_for_mother(), _persist_protocol_sub_resources(), align_fq_payment_details_payload(), _apply_payment_detail_list_filters(), _apply_submit_receipt_finance(), _apply_submit_refund_finance(), attachments_to_urls(), _audit_to_dict() (+92 more)
|
||||
Nodes (115): eq_unicode(), like_unicode(), MySQL 字符串比较/模糊匹配时统一排序规则,避免 Illegal mix of collations。, 跨表字符串等值比较(JOIN / WHERE)时统一为 utf8mb4_unicode_ci。, 将列显式设为 utf8mb4_unicode_ci。, unicode_ci(), list_production_tasks(), _outbound_work_order_ids_by_keyword() (+107 more)
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.04
|
||||
Nodes (98): eq_unicode(), like_unicode(), MySQL 字符串比较/模糊匹配时统一排序规则,避免 Illegal mix of collations。, 跨表字符串等值比较(JOIN / WHERE)时统一为 utf8mb4_unicode_ci。, 将列显式设为 utf8mb4_unicode_ci。, unicode_ci(), _fmt_dt(), get_handover_by_schedule() (+90 more)
|
||||
Cohesion: 0.03
|
||||
Nodes (77): _avatar_url_field(), _build_current_user_payload(), _build_user_info_payload(), get_current_user_profile(), _jwt_user_payload(), logout(), 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/zkxw.sql 基线), Web 端登录用 RSA 公钥(PKCS#1 v1.5,与 JSEncrypt 一致) (+69 more)
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.07
|
||||
Nodes (68): AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, ExhibitionAppointmentCreateBody, ExhibitionAppointmentUpdateBody, OccupancyCreateBody, 运营支撑 API(洁净室、进出记录、仓储设施、储位、展厅预约) (+60 more)
|
||||
Cohesion: 0.04
|
||||
Nodes (110): _persist_protocol_sub_resources(), list_ethnics_for_select(), apply_data_scope(), align_fq_payment_details_payload(), _apply_payment_detail_list_filters(), _apply_submit_receipt_finance(), _apply_submit_refund_finance(), attachments_to_urls() (+102 more)
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.35
|
||||
Nodes (61): BatchStockInBody, BatchStockInItem, BatchStockOutBody, BatchStockOutItem, ConsumableCreateBody, ConsumablePackCreateBody, ConsumablePackUpdateBody, ConsumableUpdateBody (+53 more)
|
||||
Cohesion: 0.03
|
||||
Nodes (98): get_protocol_nos_used_in_protocols(), create_dict_type(), dict_type_code_exists(), get_dict_type(), list_dict_types(), _row_to_dict(), soft_delete_dict_type(), update_dict_type() (+90 more)
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.07
|
||||
Nodes (58): batch_delete_research_donations(), change_donation_status(), convert_from_storage(), convert_to_storage(), create_research_donation(), delete_research_donation(), _get_current_user_id(), get_research_donation_detail() (+50 more)
|
||||
Cohesion: 0.04
|
||||
Nodes (95): _format_attachment_file_size(), urls_to_attachment_list(), get_check_results_for_reception(), _legacy_results_from_reception(), list_results_by_reception_ids(), _result_to_dict(), soft_delete_reception_check_results(), sync_legacy_columns_from_results() (+87 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.08
|
||||
Nodes (51): code_exists(), create_material(), _dec(), _fmt_dt(), get_material(), _is_enabled_status(), list_materials(), _norm_status() (+43 more)
|
||||
Cohesion: 0.05
|
||||
Nodes (90): api_save_application(), auto_create_payment(), auto_generate_schedules(), complete_application(), create_application(), create_basic_experiment_sale_schedules(), create_infusion_plan(), create_schedule() (+82 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.09
|
||||
Nodes (50): complete_application(), create_basic_experiment_sale_schedules(), create_infusion_plan(), create_schedule(), _create_schedule_products(), _format_yyyy_mm_dd(), _generate_application_no(), get_application() (+42 more)
|
||||
Cohesion: 0.06
|
||||
Nodes (87): AccessLogCreateBody, AccessLogUpdateBody, batch_create_storage_slots(), CleanRoomCreateBody, CleanRoomUpdateBody, create_access_log(), create_storage_slot(), delete_access_log() (+79 more)
|
||||
|
||||
### Community 16 - "Community 16"
|
||||
Cohesion: 0.06
|
||||
Nodes (18): extract_avatar_storage_key(), 用户头像 URL 解析(sys_user.avatar 可能存 MinIO 相对路径或完整 URL), 从 upload 返回值或历史完整 URL 中提取 avatar/ 相对路径。, 服务端内部拼完整 URL(邮件等);Web API 应返回库中原始路径。, resolve_avatar_display_url(), BaseStorage, convert_heic_to_jpeg(), get_storage() (+10 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (49): code_exists(), create_material(), _dec(), _fmt_dt(), get_material(), _is_enabled_status(), list_materials(), _norm_status() (+41 more)
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
Cohesion: 0.12
|
||||
Nodes (32): get_next_cell_product_code(), _ancestor_link_from_cell_product_input(), _ancestor_sample_chain_link(), _build_ancestor_chain(), _build_descendant_chain(), _build_facility_path_label(), build_split_product_codes(), create_cell_products_batch() (+24 more)
|
||||
Nodes (32): add_task_step(), _clone_route_to_task(), _clone_step_consumables(), _clone_step_data_collections(), _clone_step_outputs(), _clone_step_reagents(), _consume_task_input_cell_products(), _create_occupancy_for_product() (+24 more)
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
Cohesion: 0.11
|
||||
Nodes (33): get_next_cell_product_code(), _ancestor_link_from_cell_product_input(), _ancestor_sample_chain_link(), _apply_cell_product_status_change(), _build_ancestor_chain(), _build_descendant_chain(), _build_facility_path_label(), build_split_product_codes() (+25 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
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 19 - "Community 19"
|
||||
Cohesion: 0.21
|
||||
Nodes (23): _amount_for_row(), _batch_map(), deduct_for_task(), _deduct_task_usage_legacy_batch(), _display_remark(), list_linked_task_usages(), list_my_usages(), list_requisition_options() (+15 more)
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
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 21 - "Community 21"
|
||||
Cohesion: 0.17
|
||||
Nodes (18): get_by_schedule(), get_method(), _get_tenant_no(), list_by_application(), list_materials(), 中试服务交付管理 API(交付信息、交付物料、交付方式), soft_delete(), create_delivery() (+10 more)
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
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 23 - "Community 23"
|
||||
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 21 - "Community 21"
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.21
|
||||
Nodes (15): batch_generate_protocol_nos(), batch_issue_protocol_nos(), batch_revoke_protocol_nos(), create_protocol_no(), get_protocol_no(), list_protocol_nos(), _parse_issued_time(), protocol_no_exists() (+7 more)
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
Cohesion: 0.23
|
||||
Nodes (12): create_collection_region(), create_hospital(), get_collection_region(), get_hospital(), _hospital_names_by_region_ids(), _hospital_to_dict(), list_collection_regions(), list_hospitals() (+4 more)
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
### Community 25 - "Community 25"
|
||||
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 24 - "Community 24"
|
||||
Cohesion: 0.24
|
||||
Nodes (11): deduct_for_step(), _display_remark(), list_stock_logs(), _parse_receiver_purpose_from_remark(), 试剂变动记录 CRUD(biz_reagent_stock_log), 撤销步骤此前 step_save 扣减,便于重新填报。, 扣减试剂库存并生成变动记录。调用方控制事务,本函数不 commit。, _resolve_receiver_purpose() (+3 more)
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.23
|
||||
Nodes (12): Config, ProductBase, ProductCategoryBase, ProductCategoryCreate, ProductCategoryResponse, ProductCreate, ProductResponse, ProductUnitBase (+4 more)
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
### Community 27 - "Community 27"
|
||||
Cohesion: 0.31
|
||||
Nodes (12): _code_exists(), create_material(), _dec(), _fmt_dt(), get_material(), list_materials(), options_list(), _row_to_dict() (+4 more)
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.32
|
||||
Nodes (11): create_env_detect_record(), _generate_record_no(), get_env_detect_record(), _join_csv(), list_env_detect_records(), _resolve_inspector_snapshots(), _resolve_item_snapshot(), _row_to_dict() (+3 more)
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.27
|
||||
Nodes (11): _build_tree(), _cascade_soft_delete(), _collect_with_ancestors(), create_dept(), get_dept(), list_depts(), list_depts_tree(), 保留匹配节点及其全部上级,供关键词检索后仍能正确组树。 (+3 more)
|
||||
### Community 29 - "Community 29"
|
||||
Cohesion: 0.24
|
||||
Nodes (9): _ensure_customer_for_mother(), create_customer(), get_customer(), id_card_taken(), list_customers(), 客户 CRUD(biz_customer), _row_to_dict(), soft_delete_customer() (+1 more)
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
### Community 30 - "Community 30"
|
||||
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)
|
||||
|
||||
### Community 31 - "Community 31"
|
||||
Cohesion: 0.29
|
||||
Nodes (9): _build_tree(), _cascade_soft_delete(), create_menu(), get_menu(), list_menus(), list_menus_tree(), _row_to_dict(), soft_delete_menu() (+1 more)
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): create_express_company(), express_code_exists(), get_express_company(), list_express_companies(), 快递公司 CRUD(biz_express_company), _row_to_dict(), soft_delete_express_company(), update_express_company()
|
||||
|
||||
### Community 29 - "Community 29"
|
||||
Cohesion: 0.38
|
||||
Nodes (9): create_check_item(), get_check_item(), item_code_exists(), list_active_check_items(), list_check_items(), _order_query(), _row_to_dict(), soft_delete_check_item() (+1 more)
|
||||
|
||||
### Community 30 - "Community 30"
|
||||
### Community 32 - "Community 32"
|
||||
Cohesion: 0.38
|
||||
Nodes (9): create_env_detect_item(), get_env_detect_item(), item_code_exists(), list_active_env_detect_items(), list_env_detect_items(), _order_query(), _row_to_dict(), soft_delete_env_detect_item() (+1 more)
|
||||
|
||||
### Community 31 - "Community 31"
|
||||
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 32 - "Community 32"
|
||||
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 33 - "Community 33"
|
||||
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 34 - "Community 34"
|
||||
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 35 - "Community 35"
|
||||
Cohesion: 0.36
|
||||
Nodes (7): create_post(), get_post(), list_posts(), post_code_exists(), _row_to_dict(), soft_delete_post(), update_post()
|
||||
|
||||
### Community 36 - "Community 36"
|
||||
Cohesion: 0.36
|
||||
Nodes (7): create_tenant(), get_tenant(), list_tenants(), _row_to_dict(), soft_delete_tenant(), tenant_no_exists(), update_tenant()
|
||||
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.36
|
||||
Nodes (7): create_site(), get_site(), list_sites(), _row_to_dict(), site_code_exists(), soft_delete_site(), update_site()
|
||||
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.25
|
||||
Nodes (7): 菜单 code 权限守卫(V0.3:通过 sys_user_role → sys_role_menu → sys_menu.perms), 运营端角色守卫:admin / super_admin 可访问。, 接口菜单权限守卫。super_admin 直接放行。, 接口菜单权限守卫:拥有任一 menuCode 即可访问。super_admin 直接放行。, require_admin_or_super_admin(), require_any_menu_code(), require_menu_code()
|
||||
|
||||
### Community 39 - "Community 39"
|
||||
### Community 34 - "Community 34"
|
||||
Cohesion: 0.29
|
||||
Nodes (2): BaseModel, SoftDeleteModel
|
||||
|
||||
### Community 40 - "Community 40"
|
||||
### Community 35 - "Community 35"
|
||||
Cohesion: 0.38
|
||||
Nodes (6): derive_legacy_status_from_three(), derive_three_status_from_legacy(), 阶段A兼容:从旧 status 推导三字段。 约束:旧 status 本身混合了支付/配送/订单生命周期,因此只能尽力推断; 若业务侧已有更精确, 阶段A兼容:从三字段反推旧 status(用于旧前端/旧筛选参数兼容)。, ThreeStatus, _to_decimal()
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
### Community 36 - "Community 36"
|
||||
Cohesion: 0.5
|
||||
Nodes (3): BaseSettings, Config, Settings
|
||||
|
||||
### Community 42 - "Community 42"
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): _auto_fill_create_dept_id(), ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID
|
||||
|
||||
### Community 43 - "Community 43"
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): get_menu_list(), 运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,13 个一级菜单)
|
||||
|
||||
### Community 44 - "Community 44"
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传
|
||||
|
||||
### Community 45 - "Community 45"
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)
|
||||
|
||||
### Community 48 - "Community 48"
|
||||
### Community 43 - "Community 43"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送订单状态通知 Args: openid: 用户openid ord
|
||||
|
||||
### Community 49 - "Community 49"
|
||||
### Community 44 - "Community 44"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送支付成功通知 Args: openid: 用户openid ord
|
||||
|
||||
### Community 50 - "Community 50"
|
||||
### Community 45 - "Community 45"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送配送通知 Args: openid: 配送员openid task
|
||||
|
||||
### Community 51 - "Community 51"
|
||||
### Community 46 - "Community 46"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送配送时效预警 Args: openid: 配送员openid ta
|
||||
|
||||
### Community 52 - "Community 52"
|
||||
### Community 47 - "Community 47"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送退款结果通知 Args: openid: 用户openid ord
|
||||
|
||||
### Community 53 - "Community 53"
|
||||
### Community 48 - "Community 48"
|
||||
Cohesion: 1.0
|
||||
Nodes (1): 发送催单通知给配送员 Args: deliver_openid: 配送员openid
|
||||
|
||||
## Knowledge Gaps
|
||||
- **109 isolated node(s):** `刷新会话 TTL(refreshToken 续期;已登录用户每次 API 校验通过后滑动续期)`, `写入 refreshToken(用于 one-time 使用/吊销)`, `根据 token 获取当前用户(包含 Redis 会话校验;会话滑动续期)`, `登录凭据 RSA 解密(与前端 JSEncrypt PKCS#1 v1.5 兼容)。`, `Base64 密文 -> JSON 对象(须含 username、password、ts 毫秒时间戳)。` (+104 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **Thin community `Community 39`** (8 nodes): `BaseModel`, `.to_dict()`, `get_active()`, `base.py`, `SoftDeleteModel`, `.restore()`, `.soft_delete()`, `__tablename__()`
|
||||
- **Thin community `Community 34`** (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 42`** (4 nodes): `_auto_fill_create_dept_id()`, `get_db()`, `database.py`, `ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID`
|
||||
- **Thin community `Community 37`** (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 43`** (3 nodes): `get_menu_list()`, `menu.py`, `运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,13 个一级菜单)`
|
||||
- **Thin community `Community 38`** (3 nodes): `get_menu_list()`, `menu.py`, `运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,13 个一级菜单)`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 44`** (2 nodes): `context.py`, `请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传`
|
||||
- **Thin community `Community 39`** (2 nodes): `context.py`, `请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 45`** (2 nodes): `__init__.py`, `API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)`
|
||||
- **Thin community `Community 40`** (2 nodes): `__init__.py`, `API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 48`** (1 nodes): `发送订单状态通知 Args: openid: 用户openid ord`
|
||||
- **Thin community `Community 43`** (1 nodes): `发送订单状态通知 Args: openid: 用户openid ord`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 49`** (1 nodes): `发送支付成功通知 Args: openid: 用户openid ord`
|
||||
- **Thin community `Community 44`** (1 nodes): `发送支付成功通知 Args: openid: 用户openid ord`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 50`** (1 nodes): `发送配送通知 Args: openid: 配送员openid task`
|
||||
- **Thin community `Community 45`** (1 nodes): `发送配送通知 Args: openid: 配送员openid task`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 51`** (1 nodes): `发送配送时效预警 Args: openid: 配送员openid ta`
|
||||
- **Thin community `Community 46`** (1 nodes): `发送配送时效预警 Args: openid: 配送员openid ta`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 52`** (1 nodes): `发送退款结果通知 Args: openid: 用户openid ord`
|
||||
- **Thin community `Community 47`** (1 nodes): `发送退款结果通知 Args: openid: 用户openid ord`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 53`** (1 nodes): `发送催单通知给配送员 Args: deliver_openid: 配送员openid`
|
||||
- **Thin community `Community 48`** (1 nodes): `发送催单通知给配送员 Args: deliver_openid: 配送员openid`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `SysUser` connect `Community 1` to `Community 2`, `Community 3`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 21`, `Community 24`?**
|
||||
_High betweenness centrality (0.113) - this node is a cross-community bridge._
|
||||
- **Why does `generate_uuid()` connect `Community 5` to `Community 0`, `Community 2`, `Community 3`, `Community 4`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 13`, `Community 14`, `Community 17`, `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`?**
|
||||
_High betweenness centrality (0.069) - this node is a cross-community bridge._
|
||||
- **Why does `success_response()` connect `Community 0` to `Community 1`, `Community 3`, `Community 7`, `Community 8`, `Community 43`, `Community 13`, `Community 17`?**
|
||||
_High betweenness centrality (0.055) - this node is a cross-community bridge._
|
||||
- **Are the 560 inferred relationships involving `str` (e.g. with `unhandled_exception_handler()` and `get_current_user_by_token()`) actually correct?**
|
||||
_`str` has 560 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 551 inferred relationships involving `success_response()` (e.g. with `list_storage_release_reviews()` and `get_storage_release_review_detail()`) actually correct?**
|
||||
_`success_response()` has 551 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 451 inferred relationships involving `error_response()` (e.g. with `_json_error_response()` and `list_storage_release_reviews()`) actually correct?**
|
||||
_`error_response()` has 451 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 375 inferred relationships involving `SysUser` (e.g. with `数据权限过滤(V0.3:基于角色 data_scope 的查询级行级过滤) data_scope 值: 1 = 全部数据 2 = 本部门数据 3` and `从 SysUser 读取用户的 dept_id。`) actually correct?**
|
||||
_`SysUser` has 375 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Why does `SysUser` connect `Community 1` to `Community 2`, `Community 3`, `Community 4`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 12`, `Community 15`, `Community 21`, `Community 24`?**
|
||||
_High betweenness centrality (0.117) - this node is a cross-community bridge._
|
||||
- **Why does `generate_uuid()` connect `Community 4` to `Community 0`, `Community 2`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 14`, `Community 15`, `Community 16`, `Community 17`, `Community 18`, `Community 20`, `Community 22`, `Community 23`, `Community 24`, `Community 27`, `Community 28`, `Community 29`, `Community 30`, `Community 31`, `Community 32`?**
|
||||
_High betweenness centrality (0.066) - this node is a cross-community bridge._
|
||||
- **Why does `success_response()` connect `Community 0` to `Community 1`, `Community 38`, `Community 6`, `Community 8`, `Community 7`, `Community 10`, `Community 11`, `Community 14`, `Community 15`, `Community 18`, `Community 21`?**
|
||||
_High betweenness centrality (0.060) - this node is a cross-community bridge._
|
||||
- **Are the 563 inferred relationships involving `str` (e.g. with `unhandled_exception_handler()` and `get_current_user_by_token()`) actually correct?**
|
||||
_`str` has 563 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 553 inferred relationships involving `success_response()` (e.g. with `list_storage_release_reviews()` and `get_storage_release_review_detail()`) actually correct?**
|
||||
_`success_response()` has 553 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 453 inferred relationships involving `error_response()` (e.g. with `_json_error_response()` and `list_storage_release_reviews()`) actually correct?**
|
||||
_`error_response()` has 453 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 377 inferred relationships involving `SysUser` (e.g. with `数据权限过滤(V0.3:基于角色 data_scope 的查询级行级过滤) data_scope 值: 1 = 全部数据 2 = 本部门数据 3` and `从 SysUser 读取用户的 dept_id。`) actually correct?**
|
||||
_`SysUser` has 377 INFERRED edges - model-reasoned connections that need verification._
|
||||
@@ -57,12 +57,12 @@
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">3570 nodes · 16121 edges · 58 communities</div>
|
||||
<div id="stats">3596 nodes · 16321 edges · 53 communities</div>
|
||||
</div>
|
||||
<script>
|
||||
const RAW_NODES = [{"id": "init_py", "label": "__init__.py", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 46, "community_name": "Community 46", "source_file": "__init__.py", "file_type": "code", "degree": 0}, {"id": "main_py", "label": "main.py", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.py", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 7}, {"id": "app_main_lifespan", "label": "lifespan()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "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_error_json", "label": "_error_json()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "_error_json()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 3}, {"id": "app_main_sqlalchemy_exception_handler", "label": "sqlalchemy_exception_handler()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "sqlalchemy_exception_handler()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_unhandled_exception_handler", "label": "unhandled_exception_handler()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "unhandled_exception_handler()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 5}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "_mask_secret()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_root", "label": "root()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "root()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_health_check", "label": "health_check()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "health_check()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_rationale_81", "label": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "app_main_rationale_92", "label": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "tasks_init_py", "label": "__init__.py", "color": {"background": "#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", "degLine truncated
|
||||
const RAW_EDGES = [{"from": "main_py", "to": "app_main_lifespan", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_error_json", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_sqlalchemy_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_unhandled_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_mask_secret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_root", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_health_check", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_lifespan", "to": "core_login_crypto_ensure_initialized", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_init_scheduled_tasks", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_shutdown_scheduler", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_error_json", "to": "app_main_sqlalchemy_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_error_json", "to": "app_main_unhandled_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "app_main_rationale_81", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "app_main_rationale_92", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_unhandled_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "str", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tasks_init_py", "to": "tasks_init_init_scheduled_tasks", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tasks_init_py", "to": "tasks_init_shutdown_scheduler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_redis_session_enabled", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_redis_client", "labeLine truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 646}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 538}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 308}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 241}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 212}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 197}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 189}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 173}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 137}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 110}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 106}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 72}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 68}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 67}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 56}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 52}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 51}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 34}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 31}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 24}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 20}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 17}, {"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": 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": 9}, {"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": 8}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 8}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 7}, {"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": 2}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 2}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 1}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 1}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 1}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 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": 0}];
|
||||
const RAW_NODES = [{"id": "init_py", "label": "__init__.py", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 41, "community_name": "Community 41", "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.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.py", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 7}, {"id": "app_main_lifespan", "label": "lifespan()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "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_error_json", "label": "_error_json()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "_error_json()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 3}, {"id": "app_main_sqlalchemy_exception_handler", "label": "sqlalchemy_exception_handler()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "sqlalchemy_exception_handler()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_unhandled_exception_handler", "label": "unhandled_exception_handler()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "unhandled_exception_handler()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 5}, {"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": "app_main_rationale_81", "label": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "app_main_rationale_92", "label": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"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", "degLine truncated
|
||||
const RAW_EDGES = [{"from": "main_py", "to": "app_main_lifespan", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_error_json", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_sqlalchemy_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_unhandled_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_mask_secret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_root", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_health_check", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_lifespan", "to": "core_login_crypto_ensure_initialized", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_init_scheduled_tasks", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_shutdown_scheduler", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_error_json", "to": "app_main_sqlalchemy_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_error_json", "to": "app_main_unhandled_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "app_main_rationale_81", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "app_main_rationale_92", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_unhandled_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "str", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tasks_init_py", "to": "tasks_init_init_scheduled_tasks", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tasks_init_py", "to": "tasks_init_shutdown_scheduler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_redis_session_enabled", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_redis_client", "labeLine truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 638}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 529}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 283}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 208}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 191}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 186}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 133}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 129}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 128}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 122}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 119}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 119}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 110}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 107}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 94}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 92}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 54}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 35}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 35}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 31}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 28}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 21}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 21}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 20}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 17}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 13}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 13}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 13}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 12}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 12}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 12}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 11}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 10}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 8}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 8}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 7}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 4}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 4}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 3}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 2}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 2}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 1}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 1}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 1}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 1}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 1}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 1}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 1}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 1}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 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": 0}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 0}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 0}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 0}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 0}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 0}];
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
|
||||
+11753
-9119
File diff suppressed because it is too large.
Load diff
@@ -27,7 +27,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/core/wechat_message.py": 1778578258.0458734,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/material.py": 1779283385.245847,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/qc_param.py": 1779022399.0175831,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py": 1781232619.5127413,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py": 1781245309.0810163,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/__init__.py": 1779418058.876012,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py": 1780458012.8329656,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/qc_material.py": 1781193802.4598653,
|
||||
@@ -61,7 +61,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/category_parameter.py": 1778578258.0944862,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/common.py": 1778578258.094703,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/unit.py": 1778578258.0996897,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py": 1779965437.3667517,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/qc_work_order.py": 1781245309.0806582,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/outbound_release_material.py": 1779827058.9935315,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/product.py": 1778578258.0968297,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/workflow.py": 1778633845.5937889,
|
||||
@@ -69,8 +69,8 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/outbound_handover.py": 1780455571.0749218,
|
||||
"/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": 1781063443.5073216,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py": 1781232662.9280763,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/storage_release_review.py": 1781245325.124061,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task.py": 1781233180.038229,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_route.py": 1779587424.6859367,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/sample_code.py": 1780479191.5382729,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_result.py": 1779331731.6720955,
|
||||
@@ -106,7 +106,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/role.py": 1779265616.3701816,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_material_stock_batch.py": 1781193849.087376,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py": 1781063498.5542552,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py": 1781232601.6883087,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_task_assignee.py": 1781233180.3766735,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation_sample_collection.py": 1781063441.5812025,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py": 1779927536.8881981,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/menu.py": 1779265729.0381103,
|
||||
@@ -122,7 +122,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/env_detect_item.py": 1781145689.9525824,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_category.py": 1779265700.0606413,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/item_unit.py": 1779265653.7504313,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py": 1781232652.837524,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py": 1781247642.2371693,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/outbound_handover_inventory.py": 1779928420.2494187,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/env_detect_record.py": 1781145773.959546,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/outbound_release_material.py": 1779928413.9677577,
|
||||
@@ -154,7 +154,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/outbound_release_review.py": 1779968232.5759368,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/public.py": 1780540754.892583,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/material.py": 1779526648.041865,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py": 1781232683.4209259,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/qc.py": 1781245328.1318824,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/collection_protocol.py": 1781063459.1075609,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/basic_info.py": 1779882001.7519956,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/pilot_infusion_confirm.py": 1779657043.1389203,
|
||||
@@ -177,11 +177,12 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py": 1780325524.907156,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_reception.py": 1781190032.4213104,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/insurance_company.py": 1779281097.279193,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py": 1779924318.5910363,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py": 1781245330.194127,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/protocol_sample_collection.py": 1780457788.2093296,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/leave.py": 1779266168.8693042,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/clinical_payment.py": 1781079914.3908625,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/workflow_callback.py": 1778727966.7277644,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/qc_work_order_fee_summary.py": 1781248273.0896494,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/workflow_engine.py": 1778634664.6293883,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/web_auth_roles.py": 1778775532.8878627,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/protocol_payment_installment.py": 1781076733.062029,
|
||||
|
||||
@@ -0,0 +1,532 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>中科兴皖 · 一体化流程 + 角色聚焦(兼容原型)</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||
<style>
|
||||
:root {
|
||||
--primary: #10b981; --primary-dark: #059669; --primary-bg: #ecfdf5;
|
||||
--text: #1e293b; --text-muted: #64748b; --border: #d9e8e2;
|
||||
--surface: #fff; --table-head: #f8fafc; --row-hover: #f1f5f9;
|
||||
--radius: 10px; --warn: #d97706; --warn-bg: #fffbeb;
|
||||
--info: #3b82f6; --info-bg: #eff6ff;
|
||||
}
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: Inter, sans-serif; font-size: 14px; line-height: 1.5; color: var(--text); background: #fefefe; }
|
||||
.layout { display: flex; min-height: 100vh; }
|
||||
|
||||
.sidebar { width: 220px; background: var(--surface); border-right: 1px solid var(--border); padding: 20px 14px; flex-shrink: 0; }
|
||||
.logo { font-size: 15px; font-weight: 700; padding: 0 10px 16px; border-bottom: 1px solid var(--border); margin-bottom: 12px; }
|
||||
.logo span { color: var(--primary); }
|
||||
.nav-item { display: block; padding: 8px 12px; color: var(--text-muted); text-decoration: none; border-radius: 8px; font-size: 13px; margin-bottom: 2px; }
|
||||
.nav-item.active { background: var(--primary-bg); color: var(--primary-dark); font-weight: 600; }
|
||||
.nav-sub { font-size: 11px; color: var(--text-muted); padding: 8px 12px 4px; }
|
||||
|
||||
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
|
||||
|
||||
/* Role bar */
|
||||
.role-bar {
|
||||
background: var(--surface); border-bottom: 1px solid var(--border);
|
||||
padding: 10px 20px; display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
|
||||
}
|
||||
.role-bar-label { font-size: 12px; font-weight: 600; color: var(--text-muted); }
|
||||
.role-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
|
||||
.role-tab {
|
||||
padding: 6px 14px; border-radius: 8px; border: 1px solid var(--border);
|
||||
background: var(--surface); font-size: 13px; cursor: pointer; transition: all 0.15s;
|
||||
}
|
||||
.role-tab:hover { border-color: var(--primary); }
|
||||
.role-tab.active { background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 600; }
|
||||
.role-desc { font-size: 12px; color: var(--text-muted); flex: 1; min-width: 200px; }
|
||||
|
||||
.view-toggle { display: flex; gap: 4px; margin-left: auto; }
|
||||
.view-toggle button {
|
||||
padding: 5px 10px; font-size: 12px; border: 1px solid var(--border); border-radius: 6px;
|
||||
background: var(--surface); cursor: pointer;
|
||||
}
|
||||
.view-toggle button.active { background: var(--primary-bg); border-color: var(--primary); color: var(--primary-dark); font-weight: 600; }
|
||||
|
||||
.topbar { padding: 12px 20px; border-bottom: 1px solid var(--border); background: var(--surface); }
|
||||
.topbar h1 { font-size: 15px; font-weight: 600; }
|
||||
.topbar p { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
|
||||
|
||||
.content { flex: 1; padding: 16px 20px; overflow: auto; }
|
||||
|
||||
.concept-banner {
|
||||
padding: 10px 14px; background: linear-gradient(90deg, var(--primary-bg), #fff);
|
||||
border: 1px solid var(--border); border-radius: var(--radius); font-size: 12px; color: var(--text-muted); margin-bottom: 14px;
|
||||
}
|
||||
.concept-banner strong { color: var(--primary-dark); }
|
||||
|
||||
.panel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: 14px; }
|
||||
.panel-head {
|
||||
padding: 12px 16px; border-bottom: 1px solid var(--border);
|
||||
display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px;
|
||||
}
|
||||
.panel-head h2 { font-size: 14px; font-weight: 600; display: flex; align-items: center; gap: 6px; }
|
||||
.panel-head h2::before { content: ''; width: 3px; height: 14px; background: var(--primary); border-radius: 2px; }
|
||||
|
||||
.stat-row { display: flex; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
|
||||
.stat-pill {
|
||||
padding: 6px 12px; border-radius: 8px; background: var(--table-head); font-size: 12px;
|
||||
}
|
||||
.stat-pill em { font-style: normal; font-weight: 700; color: var(--warn); margin-left: 4px; }
|
||||
|
||||
table { width: 100%; border-collapse: collapse; }
|
||||
th { background: var(--table-head); font-size: 12px; color: var(--text-muted); padding: 9px 12px; text-align: center; border-bottom: 1px solid var(--border); }
|
||||
td { padding: 11px 12px; text-align: center; border-bottom: 1px solid var(--border); font-size: 13px; }
|
||||
tr { cursor: pointer; }
|
||||
tr:hover td { background: var(--row-hover); }
|
||||
tr.selected td { background: var(--primary-bg); }
|
||||
|
||||
.tag { display: inline-block; padding: 2px 7px; border-radius: 5px; font-size: 11px; font-weight: 500; }
|
||||
.tag.success { background: var(--primary-bg); color: var(--primary-dark); }
|
||||
.tag.warning { background: var(--warn-bg); color: var(--warn); }
|
||||
.tag.info { background: var(--info-bg); color: var(--info); }
|
||||
.tag.muted { background: var(--table-head); color: var(--text-muted); }
|
||||
|
||||
.btn {
|
||||
height: 30px; padding: 0 11px; border-radius: 7px; font-size: 12px; font-weight: 500;
|
||||
border: 1px solid var(--border); background: var(--surface); cursor: pointer;
|
||||
}
|
||||
.btn-primary { background: var(--primary); border-color: var(--primary); color: #fff; }
|
||||
|
||||
/* ── Process Spine (shared component) ── */
|
||||
.spine-wrap {
|
||||
border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
|
||||
margin-bottom: 14px; overflow: hidden;
|
||||
}
|
||||
.spine-header {
|
||||
padding: 10px 14px; display: flex; align-items: center; justify-content: space-between;
|
||||
background: var(--table-head); cursor: pointer; user-select: none;
|
||||
}
|
||||
.spine-header h3 { font-size: 13px; font-weight: 600; }
|
||||
.spine-header .meta { font-size: 12px; color: var(--text-muted); }
|
||||
.spine-toggle { font-size: 12px; color: var(--primary-dark); font-weight: 500; }
|
||||
.spine-body { padding: 12px 14px 14px; border-top: 1px solid var(--border); }
|
||||
.spine-body.collapsed { display: none; }
|
||||
|
||||
.spine-compact { display: flex; align-items: center; gap: 0; overflow-x: auto; padding: 4px 0; }
|
||||
.sp-node {
|
||||
flex: 0 0 auto; text-align: center; min-width: 72px; position: relative; padding: 0 2px;
|
||||
}
|
||||
.sp-node:not(:last-child)::after {
|
||||
content: ''; position: absolute; top: 11px; left: calc(50% + 18px); width: calc(100% - 36px); height: 2px; background: var(--border);
|
||||
}
|
||||
.sp-node.done:not(:last-child)::after { background: var(--primary); }
|
||||
.sp-dot {
|
||||
width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--border); margin: 0 auto 4px;
|
||||
font-size: 10px; display: flex; align-items: center; justify-content: center; background: var(--surface); position: relative; z-index: 1;
|
||||
}
|
||||
.sp-node.done .sp-dot { border-color: var(--primary); background: var(--primary-bg); color: var(--primary-dark); }
|
||||
.sp-node.you .sp-dot { border-color: var(--primary); background: var(--primary); color: #fff; box-shadow: 0 0 0 3px rgba(16,185,129,0.2); }
|
||||
.sp-node.parallel .sp-dot { border-color: var(--warn); background: var(--warn-bg); color: var(--warn); }
|
||||
.sp-node.indep .sp-dot { border-style: dashed; }
|
||||
.sp-name { font-size: 10px; font-weight: 600; line-height: 1.2; }
|
||||
.sp-node.dim .sp-name, .sp-node.dim .sp-dot { opacity: 0.35; }
|
||||
|
||||
.spine-side {
|
||||
margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--border);
|
||||
display: flex; align-items: center; gap: 8px; font-size: 11px; color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* Detail drawer / bottom panel */
|
||||
.detail-panel { display: none; }
|
||||
.detail-panel.open { display: block; }
|
||||
.detail-grid { display: grid; grid-template-columns: 1fr 340px; gap: 14px; }
|
||||
.work-area { padding: 16px; }
|
||||
.work-area h3 { font-size: 14px; font-weight: 600; margin-bottom: 12px; }
|
||||
.form-row { margin-bottom: 12px; }
|
||||
.form-row label { display: block; font-size: 11px; font-weight: 600; color: var(--text-muted); margin-bottom: 4px; }
|
||||
.form-row input, .form-row select { width: 100%; max-width: 360px; height: 34px; border: 1px solid var(--border); border-radius: 8px; padding: 0 10px; }
|
||||
|
||||
.context-card {
|
||||
padding: 14px; background: var(--table-head); border-left: 1px solid var(--border);
|
||||
}
|
||||
.context-card h4 { font-size: 12px; font-weight: 600; color: var(--text-muted); margin-bottom: 10px; }
|
||||
.ctx-line { font-size: 12px; margin-bottom: 6px; }
|
||||
.ctx-line span { color: var(--text-muted); }
|
||||
|
||||
/* Full process view (coordinator only) */
|
||||
.full-process { display: none; }
|
||||
.full-process.show { display: block; }
|
||||
.focused-view.hidden { display: none; }
|
||||
|
||||
.fork-row { display: flex; gap: 20px; justify-content: center; margin: 8px 0; }
|
||||
.flow-card {
|
||||
width: 120px; padding: 10px; border: 2px solid var(--border); border-radius: 8px; text-align: center; font-size: 12px;
|
||||
}
|
||||
.flow-card.active { border-color: var(--primary); background: var(--primary-bg); }
|
||||
.flow-card.done { border-color: var(--primary); opacity: 0.85; }
|
||||
|
||||
.toast {
|
||||
position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%) translateY(60px);
|
||||
background: var(--text); color: #fff; padding: 10px 18px; border-radius: 8px; font-size: 13px;
|
||||
opacity: 0; transition: all 0.3s; z-index: 99;
|
||||
}
|
||||
.toast.show { transform: translateX(-50%) translateY(0); opacity: 1; }
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.detail-grid { grid-template-columns: 1fr; }
|
||||
.layout { flex-direction: column; }
|
||||
.sidebar { width: 100%; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layout">
|
||||
<aside class="sidebar" id="sidebar"></aside>
|
||||
<div class="main">
|
||||
<div class="role-bar">
|
||||
<span class="role-bar-label">模拟角色(切换看兼容效果)</span>
|
||||
<div class="role-tabs" id="roleTabs"></div>
|
||||
<div class="view-toggle" id="viewToggle" style="display:none">
|
||||
<button type="button" data-view="focused" class="active">聚焦作业</button>
|
||||
<button type="button" data-view="full">流程全景</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="role-desc" id="roleDesc" style="padding:8px 20px 0;font-size:12px;color:var(--text-muted)"></p>
|
||||
|
||||
<header class="topbar">
|
||||
<h1 id="pageTitle">—</h1>
|
||||
<p id="pageSub">—</p>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<div class="concept-banner">
|
||||
<strong>兼容模式:</strong>同一套流程数据 · 角色默认只看<strong>本岗列表+操作区</strong> · 流程通过可折叠<strong>脊柱</strong>保持一体清晰 · 跟单可切换<strong>流程全景</strong>
|
||||
</div>
|
||||
|
||||
<!-- 聚焦视图:各角色主路径 -->
|
||||
<div class="focused-view" id="focusedView">
|
||||
<div class="panel">
|
||||
<div class="panel-head">
|
||||
<h2 id="listTitle">待办列表</h2>
|
||||
<span id="listHint" style="font-size:12px;color:var(--text-muted)"></span>
|
||||
</div>
|
||||
<div class="stat-row" id="statRow"></div>
|
||||
<table>
|
||||
<thead id="tableHead"></thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 选中行后:脊柱 + 作业区 -->
|
||||
<div class="detail-panel" id="detailPanel">
|
||||
<div id="detailSpine"></div>
|
||||
<div class="panel detail-grid">
|
||||
<div class="work-area">
|
||||
<h3 id="workTitle">—</h3>
|
||||
<div id="workForm"></div>
|
||||
<div style="margin-top:14px" id="workActions"></div>
|
||||
</div>
|
||||
<div class="context-card">
|
||||
<h4>流程上下文(只读,跨部门共享)</h4>
|
||||
<div id="contextLines"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 全景视图:仅跟单 -->
|
||||
<div class="full-process" id="fullProcess">
|
||||
<div class="panel" style="padding:16px">
|
||||
<h2 style="font-size:14px;margin-bottom:12px">业务办理 · 依赖全景(跟单/coordinator 专用)</h2>
|
||||
<div id="fullFlowDiagram"></div>
|
||||
<p style="font-size:12px;color:var(--text-muted);margin-top:12px">全景与职能列表是同一数据;实验员/财务日常使用「聚焦作业」即可。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
const ROLES = {
|
||||
finance: {
|
||||
label: '财务', menu: ['缴退费确认'], defaultMenu: 0,
|
||||
desc: '主路径:确认列表。流程脊柱默认折叠,只看金额与协议摘要。',
|
||||
pageTitle: '缴退费财务确认', pageSub: '仅看待确认单据 · 不关心实验主链操作',
|
||||
highlightNode: 'payment', dimNodes: ['qc', 'production'],
|
||||
spineDefaultCollapsed: true,
|
||||
canFullView: false,
|
||||
stats: [{ label: '待确认', count: 3 }, { label: '今日已确认', count: 8 }],
|
||||
columns: ['协议号', '客户', '金额', '类型', '实验进度', '操作'],
|
||||
list: [
|
||||
{ id: 1, protocol: 'XY-2025-0066', customer: '张明华', amount: '28,800', type: '缴费确认', milestone: '已接收', nodes: mkNodes({ payment: 'you', reception: 'done', qc: 'parallel', production: 'parallel' }) },
|
||||
{ id: 2, protocol: 'XY-2025-0077', customer: '李芳', amount: '18,000', type: '缴费确认', milestone: '待采集', nodes: mkNodes({ payment: 'you', collection: 'parallel' }) },
|
||||
{ id: 3, protocol: 'XY-2025-0044', customer: '陈静', amount: '2,000', type: '退费确认', milestone: '质检中', nodes: mkNodes({ payment: 'you', qc: 'parallel', production: 'parallel' }) }
|
||||
]
|
||||
},
|
||||
qc_recv: {
|
||||
label: '质检接收', menu: ['样本接收', '接收检查项'], defaultMenu: 0,
|
||||
desc: '主路径:接收列表。脊柱高亮「接收」,缴费为虚线独立支路。',
|
||||
pageTitle: '样本接收', pageSub: '待接收 / 已接收 · 提交后并行创建质检+生产工单',
|
||||
highlightNode: 'reception', dimNodes: ['payment'],
|
||||
spineDefaultCollapsed: false,
|
||||
canFullView: false,
|
||||
stats: [{ label: '待接收', count: 5 }, { label: '今日已接收', count: 12 }],
|
||||
columns: ['样本编码', '协议号', '客户', '预计到达', '里程碑', '操作'],
|
||||
list: [
|
||||
{ id: 1, sample: 'ZK202506120001', protocol: 'XY-2025-0066', customer: '张明华', eta: '今日 14:00', milestone: '待接收', nodes: mkNodes({ reception: 'you', payment: 'indep' }) },
|
||||
{ id: 2, sample: 'ZK202506110008', protocol: 'XY-2025-0077', customer: '李芳', eta: '明日 10:00', milestone: '待接收', nodes: mkNodes({ reception: 'you', collection: 'done', payment: 'indep' }) }
|
||||
]
|
||||
},
|
||||
qc_lab: {
|
||||
label: '质检实验', menu: ['我的质检任务', '质检工单'], defaultMenu: 0,
|
||||
desc: '主路径:我的任务。脊柱高亮「质检」,可看生产并行进度(只读)。',
|
||||
pageTitle: '我的质检任务', pageSub: '待执行 / 进行中 · 与生产工单并行',
|
||||
highlightNode: 'qc', dimNodes: ['payment'],
|
||||
spineDefaultCollapsed: false,
|
||||
canFullView: false,
|
||||
stats: [{ label: '待执行', count: 4 }, { label: '进行中', count: 2 }],
|
||||
columns: ['任务号', '样本编码', '检测项目', '工单状态', '生产(只读)', '操作'],
|
||||
list: [
|
||||
{ id: 1, task: 'RW20260612001', sample: 'ZK202506120001', item: '细胞活性', wo: '配置中', prod: '待配置', nodes: mkNodes({ qc: 'you', production: 'parallel', reception: 'done' }) },
|
||||
{ id: 2, task: 'RW20260612002', sample: 'XY202506100003', item: '无菌检测', wo: '进行中', prod: '进行中', nodes: mkNodes({ qc: 'you', production: 'parallel' }) }
|
||||
]
|
||||
},
|
||||
production: {
|
||||
label: '生产', menu: ['生产工单', '生产任务'], defaultMenu: 0,
|
||||
desc: '主路径:生产工单。脊柱高亮「生产」,质检进度只读。',
|
||||
pageTitle: '入库生产工单', pageSub: '待配置 / 进行中 · 与质检并行',
|
||||
highlightNode: 'production', dimNodes: ['payment'],
|
||||
spineDefaultCollapsed: false,
|
||||
canFullView: false,
|
||||
stats: [{ label: '待配置', count: 2 }, { label: '进行中', count: 3 }],
|
||||
columns: ['工单号', '样本编码', '协议号', '状态', '质检(只读)', '操作'],
|
||||
list: [
|
||||
{ id: 1, wo: 'SC202606110003', sample: 'ZK202506120001', protocol: 'XY-2025-0066', status: '待配置', qc: '配置中', nodes: mkNodes({ production: 'you', qc: 'parallel', reception: 'done' }) }
|
||||
]
|
||||
},
|
||||
coordinator: {
|
||||
label: '市场跟单', menu: ['协议列表', '业务办理'], defaultMenu: 1,
|
||||
desc: '可选聚焦列表或流程全景。日常跟单用列表+脊柱;卡点时切换全景。',
|
||||
pageTitle: '细胞存储 · 业务办理', pageSub: '进行中协议 · 可切换「聚焦 / 全景」',
|
||||
highlightNode: null, dimNodes: [],
|
||||
spineDefaultCollapsed: false,
|
||||
canFullView: true,
|
||||
stats: [{ label: '进行中', count: 23 }, { label: '卡点', count: 4 }],
|
||||
columns: ['协议号', '客户', '样本', '当前里程碑', '并行状态', '操作'],
|
||||
list: [
|
||||
{ id: 1, protocol: 'XY-2025-0066', customer: '张明华', sample: 'ZK…001', milestone: '接收完成', parallel: '质检+生产', nodes: mkNodes({ qc: 'parallel', production: 'parallel', reception: 'done', payment: 'indep' }) },
|
||||
{ id: 2, protocol: 'XY-2025-0088', customer: '王强', sample: 'XY…003', milestone: '质检完成', parallel: '生产进行中', nodes: mkNodes({ qc: 'done', production: 'you', reception: 'done' }) }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const SPINE_STEPS = [
|
||||
{ id: 'protocol', name: '协议' },
|
||||
{ id: 'collection', name: '采集' },
|
||||
{ id: 'reception', name: '接收' },
|
||||
{ id: 'qc', name: '质检' },
|
||||
{ id: 'production', name: '生产' },
|
||||
{ id: 'release', name: '放行' },
|
||||
{ id: 'storage', name: '入库' }
|
||||
];
|
||||
const SPINE_INDEP = { id: 'payment', name: '缴费' };
|
||||
|
||||
function mkNodes(overrides) {
|
||||
const base = { protocol: 'done', collection: 'done', reception: 'done', qc: 'pending', production: 'pending', release: 'pending', storage: 'pending', payment: 'pending' };
|
||||
return { ...base, ...overrides };
|
||||
}
|
||||
|
||||
let currentRole = 'finance';
|
||||
let currentView = 'focused';
|
||||
let selectedRow = null;
|
||||
let spineCollapsed = true;
|
||||
|
||||
function renderRoleTabs() {
|
||||
document.getElementById('roleTabs').innerHTML = Object.entries(ROLES).map(([k, r]) =>
|
||||
`<button type="button" class="role-tab ${k === currentRole ? 'active' : ''}" onclick="setRole('${k}')">${r.label}</button>`
|
||||
).join('');
|
||||
}
|
||||
|
||||
function renderSidebar() {
|
||||
const r = ROLES[currentRole];
|
||||
document.getElementById('sidebar').innerHTML = `
|
||||
<div class="logo">中科兴皖<span> · 管理端</span></div>
|
||||
<div class="nav-sub">当前角色菜单(聚焦)</div>
|
||||
${r.menu.map((m, i) => `<a href="#" class="nav-item ${i === r.defaultMenu ? 'active' : ''}">${m}</a>`).join('')}
|
||||
${r.canFullView ? '<a href="#" class="nav-item" onclick="setView(\'full\');return false">业务办理全景</a>' : ''}
|
||||
`;
|
||||
}
|
||||
|
||||
function setRole(role) {
|
||||
currentRole = role;
|
||||
selectedRow = null;
|
||||
spineCollapsed = ROLES[role].spineDefaultCollapsed;
|
||||
currentView = 'focused';
|
||||
renderAll();
|
||||
}
|
||||
|
||||
function setView(v) {
|
||||
currentView = v;
|
||||
document.querySelectorAll('.view-toggle button').forEach(b => b.classList.toggle('active', b.dataset.view === v));
|
||||
document.getElementById('focusedView').classList.toggle('hidden', v === 'full');
|
||||
document.getElementById('fullProcess').classList.toggle('show', v === 'full');
|
||||
}
|
||||
|
||||
function renderSpine(row, roleKey, opts = {}) {
|
||||
const r = ROLES[roleKey];
|
||||
const nodes = row.nodes || mkNodes({});
|
||||
const collapsed = opts.forceExpand ? false : spineCollapsed;
|
||||
const hl = r.highlightNode;
|
||||
|
||||
const mainSteps = SPINE_STEPS.map(s => {
|
||||
const st = nodes[s.id] || 'pending';
|
||||
let cls = st === 'done' ? 'done' : st === 'you' ? 'you' : st === 'parallel' ? 'parallel' : '';
|
||||
if (r.dimNodes && r.dimNodes.includes(s.id)) cls += ' dim';
|
||||
if (hl === s.id && st !== 'you') cls = 'you';
|
||||
const icon = st === 'done' ? '✓' : st === 'you' ? '●' : st === 'parallel' ? '…' : '○';
|
||||
return `<div class="sp-node ${cls}"><div class="sp-dot">${icon}</div><div class="sp-name">${s.name}</div></div>`;
|
||||
}).join('');
|
||||
|
||||
const paySt = nodes.payment || 'pending';
|
||||
const payCls = paySt === 'indep' ? 'indep' : paySt === 'you' ? 'you' : paySt === 'done' ? 'done' : '';
|
||||
const indep = `<div class="sp-node ${payCls}"><div class="sp-dot">${paySt === 'done' ? '✓' : paySt === 'you' ? '●' : '○'}</div><div class="sp-name">缴费</div></div>`;
|
||||
|
||||
const title = row.protocol || row.sample || '—';
|
||||
const sub = row.customer ? `${row.customer} · ${row.milestone || row.type || ''}` : '';
|
||||
|
||||
return `
|
||||
<div class="spine-wrap">
|
||||
<div class="spine-header" onclick="toggleSpine()">
|
||||
<div>
|
||||
<h3>流程脊柱 · ${title}</h3>
|
||||
<div class="meta">${sub} ${hl ? '· 高亮你的环节' : '· 跟单视图'}</div>
|
||||
</div>
|
||||
<span class="spine-toggle">${collapsed ? '展开流程 ▼' : '收起 ▲'}</span>
|
||||
</div>
|
||||
<div class="spine-body ${collapsed ? 'collapsed' : ''}">
|
||||
<div class="spine-compact">${mainSteps}</div>
|
||||
<div class="spine-side"><span>独立支路:</span>${indep}<span>— 不阻塞实验主链</span></div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function toggleSpine() {
|
||||
spineCollapsed = !spineCollapsed;
|
||||
if (selectedRow) document.getElementById('detailSpine').innerHTML = renderSpine(selectedRow, currentRole);
|
||||
}
|
||||
|
||||
function renderList(roleKey) {
|
||||
const r = ROLES[roleKey];
|
||||
document.getElementById('pageTitle').textContent = r.pageTitle;
|
||||
document.getElementById('pageSub').textContent = r.pageSub;
|
||||
document.getElementById('roleDesc').textContent = r.desc;
|
||||
document.getElementById('listTitle').textContent = r.pageTitle;
|
||||
document.getElementById('listHint').textContent = r.canFullView ? '可右上角切换流程全景' : '本岗聚焦列表';
|
||||
|
||||
document.getElementById('viewToggle').style.display = r.canFullView ? 'flex' : 'none';
|
||||
|
||||
document.getElementById('statRow').innerHTML = r.stats.map(s =>
|
||||
`<div class="stat-pill">${s.label}<em>${s.count}</em></div>`
|
||||
).join('');
|
||||
|
||||
document.getElementById('tableHead').innerHTML = `<tr>${r.columns.map(c => `<th>${c}</th>`).join('')}</tr>`;
|
||||
|
||||
document.getElementById('tableBody').innerHTML = r.list.map((row, i) => {
|
||||
let cells = '';
|
||||
if (roleKey === 'finance') {
|
||||
cells = `<td>${row.protocol}</td><td>${row.customer}</td><td>${row.amount}</td><td>${row.type}</td><td><span class="tag info">${row.milestone}</span></td><td><button class="btn btn-primary btn-sm" onclick="event.stopPropagation();selectRow(${i})">确认</button></td>`;
|
||||
} else if (roleKey === 'qc_recv') {
|
||||
cells = `<td>${row.sample}</td><td>${row.protocol}</td><td>${row.customer}</td><td>${row.eta}</td><td><span class="tag warning">${row.milestone}</span></td><td><button class="btn btn-primary" onclick="event.stopPropagation();selectRow(${i})">接收</button></td>`;
|
||||
} else if (roleKey === 'qc_lab') {
|
||||
cells = `<td>${row.task}</td><td>${row.sample}</td><td>${row.item}</td><td>${row.wo}</td><td><span class="tag muted">${row.prod}</span></td><td><button class="btn btn-primary" onclick="event.stopPropagation();selectRow(${i})">执行</button></td>`;
|
||||
} else if (roleKey === 'production') {
|
||||
cells = `<td>${row.wo}</td><td>${row.sample}</td><td>${row.protocol}</td><td>${row.status}</td><td><span class="tag muted">${row.qc}</span></td><td><button class="btn btn-primary" onclick="event.stopPropagation();selectRow(${i})">配置</button></td>`;
|
||||
} else {
|
||||
cells = `<td>${row.protocol}</td><td>${row.customer}</td><td>${row.sample}</td><td>${row.milestone}</td><td>${row.parallel}</td><td><button class="btn" onclick="event.stopPropagation();selectRow(${i})">跟单</button></td>`;
|
||||
}
|
||||
return `<tr class="${selectedRow === row ? 'selected' : ''}" onclick="selectRow(${i})">${cells}</tr>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function selectRow(index) {
|
||||
const r = ROLES[currentRole];
|
||||
selectedRow = r.list[index];
|
||||
document.getElementById('detailPanel').classList.add('open');
|
||||
document.getElementById('detailSpine').innerHTML = renderSpine(selectedRow, currentRole);
|
||||
|
||||
const forms = {
|
||||
finance: `
|
||||
<div class="form-row"><label>到账金额</label><input value="${selectedRow.amount}" /></div>
|
||||
<div class="form-row"><label>到账日期</label><input type="date" value="2026-06-12" /></div>
|
||||
<div class="form-row"><label>财务备注</label><input placeholder="可选" /></div>`,
|
||||
qc_recv: `
|
||||
<div class="form-row"><label>接收时间</label><input type="datetime-local" /></div>
|
||||
<div class="form-row"><label>接收温度 ℃</label><input value="4.2" /></div>
|
||||
<div class="form-row"><label>接收结论</label><select><option>接收</option><option>拒收</option></select></div>`,
|
||||
qc_lab: `
|
||||
<div class="form-row"><label>检测项目</label><input value="${selectedRow.item}" readonly /></div>
|
||||
<div class="form-row"><label>采集值 / 结果</label><input placeholder="实验录入" /></div>`,
|
||||
production: `
|
||||
<div class="form-row"><label>工艺路线</label><select><option>入库标准工艺 v2</option></select></div>
|
||||
<div class="form-row"><label>生产任务</label><input placeholder="创建任务…" /></div>`,
|
||||
coordinator: `
|
||||
<div class="form-row"><label>跟单备注</label><input placeholder="记录协调事项" /></div>
|
||||
<p style="font-size:12px;color:var(--text-muted)">跟单在此查看脊柱;需要时可切「流程全景」。</p>`
|
||||
};
|
||||
|
||||
const titles = { finance: '财务确认', qc_recv: '样本接收登记', qc_lab: '质检任务执行', production: '生产工单配置', coordinator: '跟单备注' };
|
||||
document.getElementById('workTitle').textContent = titles[currentRole];
|
||||
document.getElementById('workForm').innerHTML = forms[currentRole];
|
||||
document.getElementById('workActions').innerHTML = `<button class="btn btn-primary" onclick="toast('已提交 · 流程状态已同步更新')">提交</button><button class="btn" onclick="closeDetail()">关闭</button>`;
|
||||
|
||||
document.getElementById('contextLines').innerHTML = `
|
||||
<div class="ctx-line"><span>协议:</span>${selectedRow.protocol || '—'}</div>
|
||||
<div class="ctx-line"><span>客户:</span>${selectedRow.customer || '—'}</div>
|
||||
<div class="ctx-line"><span>样本:</span>${selectedRow.sample || '—'}</div>
|
||||
<div class="ctx-line"><span>实验里程碑:</span>${selectedRow.milestone || selectedRow.type || '—'}</div>
|
||||
<div class="ctx-line" style="margin-top:10px;font-size:11px;color:var(--text-muted)">↑ 其他部门可见同一上下文,无需进同一操作页</div>`;
|
||||
|
||||
renderList(currentRole);
|
||||
}
|
||||
|
||||
function closeDetail() {
|
||||
selectedRow = null;
|
||||
document.getElementById('detailPanel').classList.remove('open');
|
||||
renderList(currentRole);
|
||||
}
|
||||
|
||||
function renderFullProcess() {
|
||||
document.getElementById('fullFlowDiagram').innerHTML = `
|
||||
<div style="font-size:12px;color:var(--text-muted);margin-bottom:10px">协议 → 采集 → 接收 → (质检 ∥ 生产) → 放行 → 入库 · 缴费独立</div>
|
||||
<div class="fork-row">
|
||||
<div class="flow-card done">协议✓</div><span>→</span>
|
||||
<div class="flow-card done">采集✓</div><span>→</span>
|
||||
<div class="flow-card done">接收✓</div><span>→</span>
|
||||
<div class="flow-card active">质检…</div>
|
||||
<div class="flow-card active">生产…</div><span>→</span>
|
||||
<div class="flow-card">放行</div><span>→</span>
|
||||
<div class="flow-card">入库</div>
|
||||
</div>
|
||||
<div style="margin-top:12px;padding:10px;border:1px dashed var(--border);border-radius:8px;font-size:12px">缴费 ○ 独立支路(虚线关联,不阻塞主链)</div>`;
|
||||
}
|
||||
|
||||
function renderAll() {
|
||||
renderRoleTabs();
|
||||
renderSidebar();
|
||||
renderList(currentRole);
|
||||
setView(currentView);
|
||||
renderFullProcess();
|
||||
if (selectedRow) document.getElementById('detailSpine').innerHTML = renderSpine(selectedRow, currentRole);
|
||||
}
|
||||
|
||||
document.getElementById('viewToggle').addEventListener('click', e => {
|
||||
const btn = e.target.closest('button[data-view]');
|
||||
if (btn) setView(btn.dataset.view);
|
||||
});
|
||||
|
||||
function toast(msg) {
|
||||
const t = document.getElementById('toast'); t.textContent = msg; t.classList.add('show');
|
||||
setTimeout(() => t.classList.remove('show'), 2500);
|
||||
}
|
||||
|
||||
renderAll();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,511 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>中科兴皖 · 业务办理(并行流程原型 v2)</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||
<style>
|
||||
:root {
|
||||
--primary: #10b981; --primary-dark: #059669; --primary-bg: #ecfdf5;
|
||||
--text: #1e293b; --text-muted: #64748b; --border: #d9e8e2;
|
||||
--bg-page: #fefefe; --surface: #fff; --table-head: #f8fafc;
|
||||
--row-hover: #f1f5f9; --shadow: 0 1px 3px rgba(0,0,0,0.05);
|
||||
--radius: 10px; --warn: #d97706; --warn-bg: #fffbeb;
|
||||
--info: #3b82f6; --info-bg: #eff6ff;
|
||||
}
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: Inter, sans-serif; font-size: 14px; line-height: 1.5; color: var(--text); background: var(--bg-page); }
|
||||
.layout { display: flex; min-height: 100vh; }
|
||||
.sidebar { width: 220px; background: var(--surface); border-right: 1px solid var(--border); padding: 24px 16px; flex-shrink: 0; }
|
||||
.logo { font-size: 16px; font-weight: 700; padding: 0 12px 20px; border-bottom: 1px solid var(--border); margin-bottom: 12px; }
|
||||
.logo span { color: var(--primary); }
|
||||
.nav-item { display: block; padding: 8px 12px; color: var(--text-muted); text-decoration: none; border-radius: 8px; font-size: 13px; }
|
||||
.nav-item.active { background: var(--primary-bg); color: var(--primary-dark); font-weight: 600; }
|
||||
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
|
||||
.topbar { height: 56px; padding: 0 24px; display: flex; align-items: center; justify-content: space-between; background: var(--surface); border-bottom: 1px solid var(--border); }
|
||||
.topbar h1 { font-size: 15px; font-weight: 600; }
|
||||
.topbar-meta { font-size: 12px; color: var(--text-muted); }
|
||||
.page { flex: 1; display: flex; min-height: 0; }
|
||||
|
||||
.case-list { width: 300px; border-right: 1px solid var(--border); background: var(--surface); display: flex; flex-direction: column; }
|
||||
.case-list-head { padding: 14px 16px; border-bottom: 1px solid var(--border); }
|
||||
.case-list-head h2 { font-size: 13px; font-weight: 600; margin-bottom: 8px; }
|
||||
.search-input { width: 100%; height: 34px; border: 1px solid var(--border); border-radius: 8px; padding: 0 10px; font-size: 12px; }
|
||||
.case-items { flex: 1; overflow-y: auto; }
|
||||
.case-card { padding: 12px 16px; border-bottom: 1px solid var(--border); cursor: pointer; }
|
||||
.case-card:hover { background: var(--row-hover); }
|
||||
.case-card.active { background: var(--primary-bg); border-left: 3px solid var(--primary); padding-left: 13px; }
|
||||
.case-protocol { font-weight: 600; font-size: 13px; }
|
||||
.case-customer { font-size: 12px; color: var(--text-muted); margin: 4px 0 8px; }
|
||||
.active-tags { display: flex; flex-wrap: wrap; gap: 4px; }
|
||||
.tag { font-size: 11px; padding: 1px 6px; border-radius: 5px; font-weight: 500; }
|
||||
.tag.success { background: var(--primary-bg); color: var(--primary-dark); }
|
||||
.tag.warning { background: var(--warn-bg); color: var(--warn); }
|
||||
.tag.info { background: var(--info-bg); color: var(--info); }
|
||||
.tag.muted { background: var(--table-head); color: var(--text-muted); }
|
||||
|
||||
.console { flex: 1; overflow-y: auto; padding: 12px 16px 16px; }
|
||||
.proto-tip {
|
||||
padding: 10px 14px; background: linear-gradient(90deg, var(--primary-bg), #fff);
|
||||
border: 1px solid var(--border); border-radius: var(--radius); font-size: 12px; color: var(--text-muted); margin-bottom: 12px;
|
||||
}
|
||||
.proto-tip strong { color: var(--primary-dark); }
|
||||
|
||||
.legend { display: flex; flex-wrap: wrap; gap: 12px 20px; font-size: 11px; color: var(--text-muted); margin-bottom: 12px; }
|
||||
.legend span { display: flex; align-items: center; gap: 5px; }
|
||||
.legend i { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
|
||||
.legend .solid { background: var(--primary); }
|
||||
.legend .dash { border: 2px dashed var(--text-muted); background: transparent; height: 0; width: 16px; }
|
||||
.legend .fork { background: var(--warn); }
|
||||
|
||||
.summary-bar {
|
||||
display: flex; flex-wrap: wrap; gap: 16px 28px; padding: 12px 16px;
|
||||
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: 12px;
|
||||
}
|
||||
.summary-item dt { font-size: 11px; color: var(--text-muted); }
|
||||
.summary-item dd { font-size: 14px; font-weight: 600; }
|
||||
|
||||
/* ── Flow graph (DAG, not linear) ── */
|
||||
.flow-panel {
|
||||
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
|
||||
padding: 16px; margin-bottom: 12px; overflow-x: auto;
|
||||
}
|
||||
.flow-panel h3 { font-size: 12px; font-weight: 600; color: var(--text-muted); margin-bottom: 14px; }
|
||||
|
||||
.flow-main { display: flex; align-items: center; gap: 0; min-width: max-content; padding-bottom: 8px; }
|
||||
.flow-arrow { color: var(--text-muted); font-size: 18px; padding: 0 4px; flex-shrink: 0; user-select: none; }
|
||||
|
||||
.flow-node {
|
||||
width: 88px; text-align: center; cursor: pointer; flex-shrink: 0;
|
||||
padding: 4px; border-radius: 8px; transition: background 0.12s;
|
||||
}
|
||||
.flow-node:hover { background: var(--row-hover); }
|
||||
.flow-node.selected { background: var(--primary-bg); outline: 2px solid var(--primary); outline-offset: 1px; }
|
||||
.flow-node.independent { opacity: 0.95; }
|
||||
.node-box {
|
||||
width: 72px; height: 52px; margin: 0 auto 4px; border-radius: 8px; border: 2px solid var(--border);
|
||||
background: var(--surface); display: flex; align-items: center; justify-content: center;
|
||||
font-size: 11px; font-weight: 600; line-height: 1.2; padding: 4px; position: relative;
|
||||
}
|
||||
.flow-node.done .node-box { border-color: var(--primary); background: var(--primary-bg); color: var(--primary-dark); }
|
||||
.flow-node.active .node-box { border-color: var(--primary); background: var(--primary); color: #fff; box-shadow: 0 0 0 3px rgba(16,185,129,0.25); }
|
||||
.flow-node.ready .node-box { border-color: var(--warn); background: var(--warn-bg); color: var(--warn); }
|
||||
.flow-node.locked .node-box { opacity: 0.45; cursor: not-allowed; }
|
||||
.flow-node.independent .node-box { border-style: dashed; }
|
||||
.node-dept { font-size: 9px; color: var(--text-muted); }
|
||||
.node-status { font-size: 10px; margin-top: 2px; }
|
||||
.flow-node.done .node-status { color: var(--primary-dark); }
|
||||
.flow-node.active .node-status, .flow-node.ready .node-status { color: var(--warn); font-weight: 600; }
|
||||
|
||||
/* Fork: reception → qc + production */
|
||||
.flow-fork { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
|
||||
.fork-bar { width: 2px; height: 12px; background: var(--border); }
|
||||
.fork-row { display: flex; gap: 24px; align-items: center; position: relative; }
|
||||
.fork-row::before {
|
||||
content: ''; position: absolute; top: 26px; left: 44px; right: 44px; height: 2px; background: var(--border);
|
||||
}
|
||||
.fork-label {
|
||||
font-size: 10px; color: var(--warn); font-weight: 600; background: var(--warn-bg);
|
||||
padding: 2px 8px; border-radius: 4px; margin-bottom: 4px;
|
||||
}
|
||||
.join-wrap { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
|
||||
.join-label { font-size: 10px; color: var(--text-muted); margin: 4px 0; }
|
||||
|
||||
/* Independent track: payment */
|
||||
.flow-side {
|
||||
margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--border);
|
||||
display: flex; align-items: center; gap: 8px; min-width: max-content;
|
||||
}
|
||||
.side-label { font-size: 11px; color: var(--text-muted); white-space: nowrap; }
|
||||
|
||||
.workspace {
|
||||
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
|
||||
min-height: 320px; display: flex; flex-direction: column;
|
||||
}
|
||||
.workspace-head {
|
||||
padding: 12px 16px; border-bottom: 1px solid var(--border);
|
||||
display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px;
|
||||
}
|
||||
.workspace-head h3 { font-size: 15px; font-weight: 600; }
|
||||
.node-badge { font-size: 11px; background: var(--primary-bg); color: var(--primary-dark); padding: 2px 8px; border-radius: 6px; font-weight: 500; }
|
||||
.dep-hint { font-size: 12px; color: var(--text-muted); padding: 8px 16px; background: var(--table-head); border-bottom: 1px solid var(--border); }
|
||||
.dep-hint strong { color: var(--primary-dark); }
|
||||
.workspace-body { padding: 16px; flex: 1; }
|
||||
.workspace-actions { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
|
||||
.btn {
|
||||
height: 32px; padding: 0 12px; border-radius: 8px; font-size: 13px; font-weight: 500;
|
||||
border: 1px solid var(--border); background: var(--surface); cursor: pointer;
|
||||
}
|
||||
.btn-primary { background: var(--primary); border-color: var(--primary); color: #fff; }
|
||||
.btn-sm { height: 28px; padding: 0 10px; font-size: 12px; }
|
||||
|
||||
.readonly-panel { background: var(--table-head); border: 1px solid var(--border); border-radius: 8px; padding: 12px 14px; margin-bottom: 12px; }
|
||||
.readonly-panel h4 { font-size: 12px; color: var(--text-muted); margin-bottom: 8px; }
|
||||
.kv-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
|
||||
.kv-row dt { font-size: 11px; color: var(--text-muted); }
|
||||
.kv-row dd { font-size: 13px; font-weight: 500; }
|
||||
.parallel-note {
|
||||
margin-top: 12px; padding: 10px 12px; background: var(--info-bg); border: 1px solid rgba(59,130,246,0.2);
|
||||
border-radius: 8px; font-size: 12px; color: #1d4ed8;
|
||||
}
|
||||
.locked-msg { text-align: center; padding: 40px 20px; color: var(--text-muted); }
|
||||
.toast {
|
||||
position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%) translateY(80px);
|
||||
background: var(--text); color: #fff; padding: 12px 20px; border-radius: var(--radius);
|
||||
font-size: 13px; opacity: 0; transition: all 0.3s; z-index: 99; max-width: 92vw; text-align: center;
|
||||
}
|
||||
.toast.show { transform: translateX(-50%) translateY(0); opacity: 1; }
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.page { flex-direction: column; }
|
||||
.case-list { width: 100%; max-height: 200px; }
|
||||
.kv-row { grid-template-columns: 1fr 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layout">
|
||||
<aside class="sidebar">
|
||||
<div class="logo">中科兴皖<span> · 管理端</span></div>
|
||||
<a href="#" class="nav-item active">细胞存储 · 业务办理</a>
|
||||
</aside>
|
||||
<div class="main">
|
||||
<header class="topbar">
|
||||
<h1>细胞存储 · 业务办理</h1>
|
||||
<span class="topbar-meta">v2 · 并行/独立依赖,非简单串行</span>
|
||||
</header>
|
||||
<div class="page">
|
||||
<aside class="case-list">
|
||||
<div class="case-list-head">
|
||||
<h2>进行中业务</h2>
|
||||
<input class="search-input" id="caseSearch" placeholder="协议号 / 客户 / 样本" />
|
||||
</div>
|
||||
<div class="case-items" id="caseList"></div>
|
||||
</aside>
|
||||
<section class="console">
|
||||
<div class="proto-tip">
|
||||
<strong>v2 修正:</strong>流程不是 8 步串行。缴费<strong>不阻塞</strong>接收/质检/生产;接收后<strong>质检与生产并行</strong>;放行需<strong>两者都完成</strong>(汇合门禁)。点击节点查看下方工作区。
|
||||
</div>
|
||||
<div class="legend">
|
||||
<span><i class="solid"></i> 主链 / 已完成</span>
|
||||
<span><i class="fork"></i> 并行进行中</span>
|
||||
<span><i class="dash"></i> 独立支路(不阻塞实验链)</span>
|
||||
<span>汇合 ⬦ = 需全部前置完成才解锁</span>
|
||||
</div>
|
||||
<div class="summary-bar" id="summaryBar"></div>
|
||||
<div class="flow-panel">
|
||||
<h3>里程碑依赖图(每个节点独立状态,只按 dependsOn 解锁)</h3>
|
||||
<div id="flowGraph"></div>
|
||||
</div>
|
||||
<div class="workspace">
|
||||
<div class="workspace-head">
|
||||
<h3><span id="nodeTitle">—</span> <span class="node-badge" id="nodeBadge">—</span></h3>
|
||||
<div class="workspace-actions" id="nodeActions"></div>
|
||||
</div>
|
||||
<div class="dep-hint" id="depHint"></div>
|
||||
<div class="workspace-body" id="nodeBody"></div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 节点定义:dependsOn = 硬依赖(全部完成才解锁)
|
||||
* independent = true → 不参与阻塞其他节点(如缴费)
|
||||
* parallelGroup = 仅 UI 分组,逻辑上各自独立状态
|
||||
*/
|
||||
const NODES = {
|
||||
protocol: { name: '协议单', dept: '市场', dependsOn: [], embed: 'ProtocolAuditTab' },
|
||||
collection: { name: '样本采集', dept: '采集岗', dependsOn: ['protocol'], embed: 'SampleCollectionInfoTab' },
|
||||
reception: { name: '样本接收', dept: '质检接收', dependsOn: ['collection'], embed: 'sample-reception' },
|
||||
qc: { name: '质检工单', dept: '质检部', dependsOn: ['reception'], parallelGroup: 'lab', embed: 'qc-work-order' },
|
||||
production: { name: '生产工单', dept: '生产部', dependsOn: ['reception'], parallelGroup: 'lab', embed: 'production-work-order' },
|
||||
release: { name: '入库放行', dept: 'QA', dependsOn: ['qc', 'production'], joinGate: true, embed: 'storage-release-review' },
|
||||
storage: { name: '样本入库', dept: '库管', dependsOn: ['release'], embed: 'StorageEntryInfoTab' },
|
||||
payment: { name: '缴费', dept: '市场+财务', dependsOn: [], independent: true, embed: 'PaymentInfoTab' }
|
||||
};
|
||||
|
||||
const STATUS_LABEL = {
|
||||
locked: '未解锁', ready: '可办理', active: '进行中', done: '已完成', skipped: '—'
|
||||
};
|
||||
|
||||
const CASES = [
|
||||
{
|
||||
id: 'c1', protocol: 'XY-2025-0066', customer: '张明华', sample: 'ZK202506120001', type: '脐带血',
|
||||
// 已接收:质检、生产并行进行中;缴费仍待办但不阻塞
|
||||
nodes: {
|
||||
protocol: 'done', collection: 'done', reception: 'done',
|
||||
qc: 'active', production: 'ready',
|
||||
release: 'locked', storage: 'locked', payment: 'ready'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'c2', protocol: 'XY-2025-0077', customer: '李芳', sample: '—', type: '胎盘',
|
||||
nodes: {
|
||||
protocol: 'done', collection: 'ready', reception: 'locked',
|
||||
qc: 'locked', production: 'locked', release: 'locked', storage: 'locked',
|
||||
payment: 'active' // 财务在催缴费,但不影响后续实验链解锁逻辑
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'c3', protocol: 'XY-2025-0088', customer: '王强', sample: 'XY202506100003', type: '脐带血',
|
||||
nodes: {
|
||||
protocol: 'done', collection: 'done', reception: 'done',
|
||||
qc: 'done', production: 'active', // 质检已完成,生产还在做
|
||||
release: 'locked', storage: 'locked', payment: 'done'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'c4', protocol: 'XY-2025-0055', customer: '赵敏', sample: 'ZK202506090005', type: '脐带血',
|
||||
nodes: {
|
||||
protocol: 'done', collection: 'done', reception: 'done',
|
||||
qc: 'done', production: 'done', release: 'ready', storage: 'locked',
|
||||
payment: 'done'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
let activeCaseId = 'c1';
|
||||
let selectedNode = 'qc';
|
||||
|
||||
function getCase(id) { return CASES.find(c => c.id === id) || CASES[0]; }
|
||||
|
||||
/** 计算节点是否解锁(不含 independent 对别人的影响) */
|
||||
function isUnlocked(caseData, nodeId) {
|
||||
const node = NODES[nodeId];
|
||||
return (node.dependsOn || []).every(dep => caseData.nodes[dep] === 'done');
|
||||
}
|
||||
|
||||
function getNodeUiStatus(caseData, nodeId) {
|
||||
const raw = caseData.nodes[nodeId];
|
||||
if (raw === 'done') return 'done';
|
||||
if (!isUnlocked(caseData, nodeId)) return 'locked';
|
||||
if (raw === 'active') return 'active';
|
||||
return 'ready'; // ready = 可办理
|
||||
}
|
||||
|
||||
function getActiveTags(caseData) {
|
||||
return Object.entries(caseData.nodes)
|
||||
.filter(([, st]) => st === 'active' || st === 'ready')
|
||||
.filter(([id]) => getNodeUiStatus(caseData, id) !== 'locked')
|
||||
.map(([id]) => NODES[id].name);
|
||||
}
|
||||
|
||||
function renderCaseList() {
|
||||
const q = (document.getElementById('caseSearch').value || '').toLowerCase();
|
||||
document.getElementById('caseList').innerHTML = CASES.filter(c =>
|
||||
!q || [c.protocol, c.customer, c.sample].join(' ').toLowerCase().includes(q)
|
||||
).map(c => {
|
||||
const tags = getActiveTags(c);
|
||||
return `
|
||||
<div class="case-card ${c.id === activeCaseId ? 'active' : ''}" onclick="selectCase('${c.id}')">
|
||||
<div class="case-protocol">${c.protocol}</div>
|
||||
<div class="case-customer">${c.customer} · ${c.type}</div>
|
||||
<div class="active-tags">
|
||||
${tags.length ? tags.map(t => `<span class="tag warning">${t}</span>`).join('') : '<span class="tag muted">暂无待办节点</span>'}
|
||||
${c.nodes.payment !== 'done' ? '<span class="tag info">缴费未完成</span>' : ''}
|
||||
</div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function renderSummary(c) {
|
||||
const tags = getActiveTags(c);
|
||||
document.getElementById('summaryBar').innerHTML = `
|
||||
<dl class="summary-item"><dt>协议号</dt><dd>${c.protocol}</dd></dl>
|
||||
<dl class="summary-item"><dt>客户</dt><dd>${c.customer}</dd></dl>
|
||||
<dl class="summary-item"><dt>样本</dt><dd>${c.sample}</dd></dl>
|
||||
<dl class="summary-item"><dt>并行进行中</dt><dd style="color:var(--warn)">${tags.join('、') || '—'}</dd></dl>
|
||||
`;
|
||||
}
|
||||
|
||||
function nodeHtml(id, caseData) {
|
||||
const n = NODES[id];
|
||||
const ui = getNodeUiStatus(caseData, id);
|
||||
const sel = id === selectedNode ? ' selected' : '';
|
||||
const indep = n.independent ? ' independent' : '';
|
||||
const st = caseData.nodes[id];
|
||||
const statusText = ui === 'locked' ? '未解锁' : STATUS_LABEL[st] || STATUS_LABEL[ui];
|
||||
return `
|
||||
<div class="flow-node ${ui}${indep}${sel}" onclick="selectNode('${id}')" title="${n.dept}">
|
||||
<div class="node-box">${n.name}</div>
|
||||
<div class="node-dept">${n.dept}</div>
|
||||
<div class="node-status">${statusText}</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function renderFlowGraph(c) {
|
||||
document.getElementById('flowGraph').innerHTML = `
|
||||
<div class="flow-main">
|
||||
${nodeHtml('protocol', c)}
|
||||
<span class="flow-arrow">→</span>
|
||||
${nodeHtml('collection', c)}
|
||||
<span class="flow-arrow">→</span>
|
||||
${nodeHtml('reception', c)}
|
||||
<span class="flow-arrow">→</span>
|
||||
<div class="flow-fork">
|
||||
<span class="fork-label">接收后并行创建</span>
|
||||
<div class="fork-row">
|
||||
${nodeHtml('qc', c)}
|
||||
${nodeHtml('production', c)}
|
||||
</div>
|
||||
</div>
|
||||
<span class="flow-arrow">→</span>
|
||||
<div class="join-wrap">
|
||||
<span class="join-label">⬦ 质检+生产均完成</span>
|
||||
${nodeHtml('release', c)}
|
||||
</div>
|
||||
<span class="flow-arrow">→</span>
|
||||
${nodeHtml('storage', c)}
|
||||
</div>
|
||||
<div class="flow-side">
|
||||
<span class="side-label">独立支路(不阻塞实验主链):</span>
|
||||
${nodeHtml('payment', c)}
|
||||
<span style="font-size:11px;color:var(--text-muted)">— 未缴费仍可接收、质检、生产;储存证/合同等另按业务规则控制</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function getDepHint(id, c) {
|
||||
const n = NODES[id];
|
||||
if (n.independent) return '独立节点:与实验主链无阻塞关系,可随时办理。';
|
||||
if (!isUnlocked(c, id)) {
|
||||
const pending = (n.dependsOn || []).filter(d => c.nodes[d] !== 'done');
|
||||
return `未解锁:需先完成 ${pending.map(d => '「' + NODES[d].name + '」').join(n.joinGate ? ' 且 ' : '、')}`;
|
||||
}
|
||||
if (n.parallelGroup === 'lab') return '并行节点:与「' + (id === 'qc' ? '生产工单' : '质检工单') + '」同时进行,互不等对方完成。';
|
||||
if (n.joinGate) return '汇合门禁:质检工单与生产工单均完成后,方可审核放行。';
|
||||
return '已解锁,可按权限办理。';
|
||||
}
|
||||
|
||||
function renderNode(c, id) {
|
||||
const n = NODES[id];
|
||||
const ui = getNodeUiStatus(c, id);
|
||||
document.getElementById('nodeTitle').textContent = n.name;
|
||||
document.getElementById('nodeBadge').textContent = n.dept + ' · ' + n.embed;
|
||||
document.getElementById('depHint').innerHTML = getDepHint(id, c);
|
||||
|
||||
if (ui === 'locked') {
|
||||
document.getElementById('nodeActions').innerHTML = '';
|
||||
document.getElementById('nodeBody').innerHTML = `
|
||||
<div class="locked-msg">
|
||||
<p><strong>🔒 此节点尚未解锁</strong></p>
|
||||
<p style="margin-top:8px;font-size:13px">${getDepHint(id, c)}</p>
|
||||
</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const st = c.nodes[id];
|
||||
const isActive = st === 'active' || st === 'ready';
|
||||
document.getElementById('nodeActions').innerHTML = getActions(id, isActive);
|
||||
document.getElementById('nodeBody').innerHTML = getBody(c, id, isActive);
|
||||
}
|
||||
|
||||
function getActions(id, canEdit) {
|
||||
const btns = {
|
||||
protocol: canEdit ? '<button class="btn btn-primary btn-sm" onclick="completeNode(\'protocol\')">提交审核</button>' : '<button class="btn btn-sm">查看</button>',
|
||||
collection: canEdit ? '<button class="btn btn-primary btn-sm" onclick="completeNode(\'collection\')">确认采集</button>' : '<button class="btn btn-sm">查看</button>',
|
||||
reception: canEdit ? '<button class="btn btn-primary btn-sm" onclick="completeReception()">提交接收</button>' : '<button class="btn btn-sm">查看</button>',
|
||||
qc: canEdit ? '<button class="btn btn-primary btn-sm" onclick="toast(\'配置检测\')">配置检测</button><button class="btn btn-sm" onclick="completeNode(\'qc\')">标记完成</button>' : '<button class="btn btn-sm">查看报告</button>',
|
||||
production: canEdit ? '<button class="btn btn-primary btn-sm" onclick="toast(\'创建生产任务\')">创建任务</button><button class="btn btn-sm" onclick="completeNode(\'production\')">标记完成</button>' : '<button class="btn btn-sm">查看</button>',
|
||||
release: canEdit ? '<button class="btn btn-primary btn-sm" onclick="completeNode(\'release\')">审核通过</button>' : '<button class="btn btn-sm">查看</button>',
|
||||
storage: canEdit ? '<button class="btn btn-primary btn-sm" onclick="completeNode(\'storage\')">确认入库</button>' : '<button class="btn btn-sm">查看</button>',
|
||||
payment: canEdit ? '<button class="btn btn-primary btn-sm" onclick="completeNode(\'payment\')">提交/确认缴费</button>' : '<button class="btn btn-sm">查看</button>'
|
||||
};
|
||||
return btns[id] || '';
|
||||
}
|
||||
|
||||
function getBody(c, id, canEdit) {
|
||||
if (id === 'reception' && canEdit) {
|
||||
return `<div class="readonly-panel"><h4>接收登记(不依赖缴费状态)</h4>
|
||||
<p style="font-size:13px;color:var(--text-muted)">即使缴费未完成,只要采集完成即可接收。提交后<strong>同时</strong>创建质检工单 + 生产工单。</p></div>
|
||||
<div class="parallel-note">⚡ 提交接收 → 后端同一事务创建 ZJ 质检工单 与 SC 生产工单(与现有实现一致)</div>`;
|
||||
}
|
||||
if (id === 'qc' || id === 'production') {
|
||||
const other = id === 'qc' ? 'production' : 'qc';
|
||||
const otherSt = c.nodes[other];
|
||||
return `<div class="readonly-panel"><h4>${NODES[id].name}</h4>
|
||||
<dl class="kv-row">
|
||||
<div><dt>本节点</dt><dd>${STATUS_LABEL[c.nodes[id]]}</dd></div>
|
||||
<div><dt>并行节点「${NODES[other].name}」</dt><dd>${STATUS_LABEL[otherSt]}(不阻塞本节点)</dd></div>
|
||||
</dl></div>
|
||||
<div class="parallel-note">两路可不同人、不同时间推进;放行环节才要求两者都 done。</div>`;
|
||||
}
|
||||
if (id === 'release') {
|
||||
return `<div class="readonly-panel"><h4>汇合门禁</h4>
|
||||
<dl class="kv-row">
|
||||
<div><dt>质检工单</dt><dd>${c.nodes.qc === 'done' ? '✓ 已完成' : '✗ 未完成'}</dd></div>
|
||||
<div><dt>生产工单</dt><dd>${c.nodes.production === 'done' ? '✓ 已完成' : '✗ 未完成'}</dd></div>
|
||||
<div><dt>缴费</dt><dd>${c.nodes.payment === 'done' ? '已缴费' : '未缴费(不阻塞放行)'}</dd></div>
|
||||
</dl></div>`;
|
||||
}
|
||||
if (id === 'payment') {
|
||||
return `<div class="readonly-panel"><h4>独立支路 · 缴费</h4>
|
||||
<p style="font-size:13px">与接收/质检/生产<strong>无 dependsOn 关系</strong>。列表上显示「缴费未完成」提醒,但不锁实验主链。</p>
|
||||
<p style="font-size:12px;color:var(--text-muted);margin-top:8px">若储存证开具等业务需要已缴费,在<strong>储存证节点</strong>单独加 softDependsOn: ['payment'] 即可。</p></div>`;
|
||||
}
|
||||
return `<p style="color:var(--text-muted);font-size:13px">嵌入 ${NODES[id].embed} · ${canEdit ? '可编辑' : '只读'}</p>`;
|
||||
}
|
||||
|
||||
function selectCase(id) { activeCaseId = id; const c = getCase(id); selectedNode = getActiveTags(c)[0] ? Object.keys(NODES).find(k => NODES[k].name === getActiveTags(c)[0]) : 'protocol'; renderAll(); }
|
||||
function selectNode(id) {
|
||||
const c = getCase(activeCaseId);
|
||||
if (getNodeUiStatus(c, id) === 'locked') { toast(getDepHint(id, c)); return; }
|
||||
selectedNode = id; renderAll();
|
||||
}
|
||||
|
||||
function completeReception() {
|
||||
const c = getCase(activeCaseId);
|
||||
c.nodes.reception = 'done';
|
||||
c.nodes.qc = 'active';
|
||||
c.nodes.production = 'ready';
|
||||
if (c.sample === '—') c.sample = 'ZK' + Date.now().toString().slice(-6);
|
||||
toast('接收完成 → 质检工单、生产工单已并行创建');
|
||||
selectedNode = 'qc';
|
||||
renderAll();
|
||||
}
|
||||
|
||||
function completeNode(id) {
|
||||
const c = getCase(activeCaseId);
|
||||
c.nodes[id] = 'done';
|
||||
// 解锁:把 dependsOn 含 id 且全部 deps done 的 locked 节点改为 ready
|
||||
Object.keys(NODES).forEach(nid => {
|
||||
if (c.nodes[nid] === 'locked' || c.nodes[nid] === 'ready' || c.nodes[nid] === 'active') {
|
||||
if (isUnlocked(c, nid) && c.nodes[nid] !== 'done' && c.nodes[nid] !== 'active') {
|
||||
c.nodes[nid] = 'ready';
|
||||
}
|
||||
}
|
||||
});
|
||||
if (id === 'qc' || id === 'production') {
|
||||
if (c.nodes.qc === 'done' && c.nodes.production === 'done') {
|
||||
c.nodes.release = 'ready';
|
||||
toast('质检+生产均完成 → 入库放行已解锁');
|
||||
} else {
|
||||
toast('「' + NODES[id].name + '」已完成,并行另一路仍可继续');
|
||||
}
|
||||
} else {
|
||||
toast('「' + NODES[id].name + '」已完成');
|
||||
}
|
||||
renderAll();
|
||||
}
|
||||
|
||||
function renderAll() {
|
||||
const c = getCase(activeCaseId);
|
||||
renderCaseList(); renderSummary(c); renderFlowGraph(c); renderNode(c, selectedNode);
|
||||
}
|
||||
|
||||
function toast(msg) {
|
||||
const t = document.getElementById('toast'); t.textContent = msg; t.classList.add('show');
|
||||
setTimeout(() => t.classList.remove('show'), 2800);
|
||||
}
|
||||
|
||||
document.getElementById('caseSearch').addEventListener('input', renderCaseList);
|
||||
renderAll();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,689 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>质检工单 · 单列 Tab 模式 Demo</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<style>
|
||||
:root {
|
||||
--primary: #10b981; --primary-dark: #059669; --primary-bg: #ecfdf5;
|
||||
--text: #1e293b; --muted: #64748b; --border: #e2e8f0; --border-soft: #d9e8e2;
|
||||
--radius: 10px;
|
||||
}
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: Inter, -apple-system, sans-serif;
|
||||
font-size: 14px; line-height: 1.5; color: var(--text);
|
||||
background: #fefefe;
|
||||
}
|
||||
|
||||
.page-container { max-width: 1200px; margin: 0 auto; padding: 24px; }
|
||||
|
||||
.panel {
|
||||
background: #fff; border: 1px solid var(--border-soft);
|
||||
border-radius: var(--radius); overflow: hidden;
|
||||
}
|
||||
.panel-top { padding: 16px 20px 0; }
|
||||
.title-bar-heading {
|
||||
font-size: 15px; font-weight: 600; padding-left: 10px;
|
||||
border-left: 3px solid var(--primary); margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.work-order-type-tabs {
|
||||
display: flex; border-bottom: 1px solid var(--border); padding: 0 20px;
|
||||
}
|
||||
.wo-type-tab {
|
||||
padding: 10px 16px; font-size: 13px; color: var(--muted);
|
||||
border-bottom: 2px solid transparent; margin-bottom: -1px; cursor: default;
|
||||
}
|
||||
.wo-type-tab.active { color: var(--primary-dark); border-bottom-color: var(--primary); font-weight: 600; }
|
||||
|
||||
.demo-banner {
|
||||
margin: 12px 20px 0; padding: 10px 12px;
|
||||
background: var(--primary-bg); border-radius: 8px;
|
||||
font-size: 12px; color: var(--muted); line-height: 1.55;
|
||||
}
|
||||
.demo-banner strong { color: var(--primary-dark); }
|
||||
|
||||
.filter-block { padding: 16px 20px; border-bottom: 1px solid var(--border); }
|
||||
.filter-grid {
|
||||
display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px 16px;
|
||||
}
|
||||
.filter-item label { display: block; font-size: 11px; color: var(--muted); margin-bottom: 4px; }
|
||||
.filter-item input, .filter-item select {
|
||||
width: 100%; height: 36px; border: 1px solid var(--border);
|
||||
border-radius: 8px; padding: 0 10px; font-size: 13px; background: #fff;
|
||||
}
|
||||
.filter-actions {
|
||||
display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px;
|
||||
}
|
||||
|
||||
/* ★ 单列布局(替代现网 minmax(480px) 多列网格) */
|
||||
.qc-work-order-cards-body { border-top: 1px solid var(--border); }
|
||||
.qc-work-order-cards-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
padding: 16px 20px;
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
/* 样本组卡片(一行一个) */
|
||||
.qc-sample-row {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
transition: border-color 0.15s, box-shadow 0.15s;
|
||||
}
|
||||
.qc-sample-row:hover {
|
||||
border-color: #a7f3d0;
|
||||
box-shadow: 0 2px 8px rgba(16, 185, 129, 0.08);
|
||||
}
|
||||
|
||||
.qc-sample-row__ctx {
|
||||
display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px;
|
||||
padding: 10px 16px;
|
||||
background: var(--primary-bg);
|
||||
border-bottom: 1px solid #a7f3d0;
|
||||
font-size: 12px;
|
||||
}
|
||||
.qc-sample-row__idx { font-size: 12px; color: #94a3b8; min-width: 20px; }
|
||||
.qc-sample-row__code {
|
||||
font-weight: 600; font-size: 14px;
|
||||
font-family: ui-monospace, Menlo, monospace; color: var(--text);
|
||||
}
|
||||
.qc-sample-row__sub { color: var(--muted); }
|
||||
.qc-sample-row__badge {
|
||||
margin-left: auto;
|
||||
font-size: 11px; font-weight: 600;
|
||||
padding: 2px 8px; border-radius: 4px;
|
||||
background: #fff; color: var(--primary-dark); border: 1px solid #a7f3d0;
|
||||
}
|
||||
|
||||
/* 组内 Tab(同样本多条工单) */
|
||||
.qc-wo-tabs {
|
||||
display: flex; border-bottom: 1px solid var(--border);
|
||||
background: #fafafa; overflow-x: auto;
|
||||
}
|
||||
.qc-wo-tab {
|
||||
padding: 10px 16px; font-size: 12px; color: var(--muted);
|
||||
border-bottom: 2px solid transparent; cursor: pointer;
|
||||
white-space: nowrap; transition: color 0.12s, background 0.12s;
|
||||
}
|
||||
.qc-wo-tab:hover { color: var(--text); background: #f8fafc; }
|
||||
.qc-wo-tab.active {
|
||||
color: var(--primary-dark); font-weight: 600;
|
||||
border-bottom-color: var(--primary); background: #fff;
|
||||
}
|
||||
.qc-wo-tab__no { font-family: ui-monospace, Menlo, monospace; }
|
||||
.qc-wo-tab__dot {
|
||||
display: inline-block; width: 6px; height: 6px; border-radius: 50%;
|
||||
margin-right: 4px; vertical-align: middle;
|
||||
}
|
||||
.qc-wo-tab__dot--reception { background: #3b82f6; }
|
||||
.qc-wo-tab__dot--production { background: var(--primary); }
|
||||
|
||||
.qc-wo-pane { display: none; }
|
||||
.qc-wo-pane.active { display: block; }
|
||||
|
||||
/* 工单 head(对齐 QcWorkOrderCardList) */
|
||||
.qc-work-order-card__head {
|
||||
display: flex; flex-direction: column; gap: 10px;
|
||||
padding: 14px 16px; background: #fafafa;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.qc-work-order-card__head-inner {
|
||||
display: flex; flex-wrap: wrap; align-items: flex-start; gap: 12px 20px;
|
||||
}
|
||||
.qc-work-order-card__head-main { flex: 1; min-width: 280px; }
|
||||
.qc-work-order-card__title-row {
|
||||
display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 10px;
|
||||
}
|
||||
.qc-work-order-card__no {
|
||||
font-size: 15px; font-weight: 600; color: #1e293b;
|
||||
font-family: ui-monospace, Menlo, monospace;
|
||||
}
|
||||
.qc-work-order-card__meta {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
gap: 8px 12px;
|
||||
}
|
||||
.qc-work-order-card__meta-item dt { font-size: 11px; color: #94a3b8; margin-bottom: 2px; }
|
||||
.qc-work-order-card__meta-item dd { font-size: 13px; color: #334155; }
|
||||
.qc-work-order-card__ops {
|
||||
display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end;
|
||||
gap: 8px; flex-shrink: 0; align-self: flex-end;
|
||||
}
|
||||
|
||||
.el-tag {
|
||||
display: inline-block; font-size: 11px; padding: 2px 7px;
|
||||
border-radius: 4px; font-weight: 500;
|
||||
}
|
||||
.el-tag--success { background: var(--primary-bg); color: var(--primary-dark); }
|
||||
.el-tag--warning { background: #fffbeb; color: #d97706; }
|
||||
.el-tag--info { background: #f1f5f9; color: #64748b; }
|
||||
.el-tag--primary { background: #eff6ff; color: #2563eb; }
|
||||
|
||||
.btn-op-item {
|
||||
height: 32px; padding: 0 12px; border-radius: 8px; font-size: 13px;
|
||||
border: 1px solid var(--border); background: #fff; cursor: pointer;
|
||||
}
|
||||
.btn-op-item.primary {
|
||||
background: var(--primary); border-color: var(--primary); color: #fff;
|
||||
}
|
||||
|
||||
/* 任务区(对齐 QcWorkOrderTaskSubList) */
|
||||
.qc-work-order-card__tasks {
|
||||
padding: 10px 16px 12px; background: #f8fafc;
|
||||
}
|
||||
.qc-work-order-task-sublist__head {
|
||||
display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;
|
||||
}
|
||||
.qc-work-order-task-sublist__head-title {
|
||||
padding-left: 10px; border-left: 3px solid var(--primary);
|
||||
font-size: 12px; font-weight: 600; color: #334155;
|
||||
}
|
||||
.qc-work-order-task-sublist__count { font-size: 12px; color: #94a3b8; }
|
||||
|
||||
/* 任务:三列 × 两行融合(行内并排,减少左侧空白) */
|
||||
.qc-task-cards-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
.qc-task-card {
|
||||
display: flex; flex-direction: column; justify-content: center; gap: 5px;
|
||||
min-height: 68px; padding: 7px 10px;
|
||||
border: 1px solid var(--border); border-radius: 8px; background: #fff;
|
||||
transition: border-color 0.15s, box-shadow 0.15s;
|
||||
min-width: 0;
|
||||
}
|
||||
.qc-task-card:hover {
|
||||
border-color: #a7f3d0;
|
||||
box-shadow: 0 1px 4px rgba(16, 185, 129, 0.1);
|
||||
}
|
||||
.qc-task-card__line {
|
||||
display: flex; align-items: center; gap: 6px; min-width: 0;
|
||||
}
|
||||
.qc-task-card__line--top { flex-wrap: wrap; row-gap: 4px; }
|
||||
.qc-task-card__name {
|
||||
font-size: 13px; font-weight: 600; color: #1e293b; line-height: 1.25;
|
||||
flex-shrink: 0; max-width: 100%;
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
}
|
||||
.qc-task-card__tags {
|
||||
display: flex; flex-wrap: wrap; align-items: center;
|
||||
gap: 3px; flex: 1; min-width: 0;
|
||||
}
|
||||
.qc-task-card__code {
|
||||
font-family: ui-monospace, Menlo, monospace;
|
||||
font-size: 10px; color: #475569; line-height: 1.25;
|
||||
flex: 1; min-width: 0;
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
}
|
||||
.qc-task-card__sep { flex-shrink: 0; color: #cbd5e1; font-size: 11px; }
|
||||
.qc-task-card__assignees {
|
||||
flex-shrink: 0; max-width: 64px;
|
||||
font-size: 11px; color: #64748b;
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
}
|
||||
.qc-work-order-task-sublist__ops {
|
||||
flex-shrink: 0; display: flex; gap: 4px; margin-left: auto;
|
||||
}
|
||||
.btn-op-item.sm { height: 26px; font-size: 11px; padding: 0 8px; }
|
||||
.btn-op-item.sm.icon-only { min-width: 26px; padding: 0; justify-content: center; }
|
||||
|
||||
.qc-work-order-task-sublist__empty {
|
||||
min-height: 72px; display: flex; align-items: center; justify-content: center;
|
||||
font-size: 13px; color: #94a3b8; text-align: center;
|
||||
border: 1px dashed var(--border); border-radius: 8px; background: #fff;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex; justify-content: flex-end; align-items: center; gap: 8px;
|
||||
padding: 12px 20px; border-top: 1px solid var(--border);
|
||||
font-size: 13px; color: var(--muted);
|
||||
}
|
||||
.pagination button {
|
||||
height: 28px; min-width: 28px; padding: 0 8px;
|
||||
border: 1px solid var(--border); border-radius: 6px; background: #fff; cursor: pointer;
|
||||
}
|
||||
.pagination button.active { background: var(--primary); color: #fff; border-color: var(--primary); }
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.qc-task-cards-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.filter-grid { grid-template-columns: 1fr 1fr; }
|
||||
.qc-work-order-card__head-inner { flex-direction: column; }
|
||||
.qc-work-order-card__ops { align-self: stretch; justify-content: flex-start; }
|
||||
}
|
||||
@media (max-width: 520px) {
|
||||
.qc-task-cards-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page-container">
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">质检工单</h2>
|
||||
</div>
|
||||
|
||||
<div class="work-order-type-tabs">
|
||||
<div class="wo-type-tab active">入库质检工单</div>
|
||||
<div class="wo-type-tab">出库质检工单</div>
|
||||
<div class="wo-type-tab">临时质检工单</div>
|
||||
</div>
|
||||
|
||||
<p class="demo-banner">
|
||||
<strong>目标布局:</strong>列表<strong>一行一个样本组</strong>(单列)+ 同样本 <strong>Tab 切换</strong>;
|
||||
质检任务为<strong>三列 × 两行融合</strong>卡片:第 1 行「项目名 + Tag」,第 2 行「任务号 · 负责人 · 操作」,减少左侧空白。
|
||||
</p>
|
||||
|
||||
<div class="filter-block">
|
||||
<div class="filter-grid">
|
||||
<div class="filter-item">
|
||||
<label>关键词</label>
|
||||
<input type="text" placeholder="工单号 / 样本编码 / 入库编码" />
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>工单状态</label>
|
||||
<select><option>全部</option><option>待配置</option><option>已配置</option><option>已完成</option></select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>触发来源</label>
|
||||
<select><option>全部</option><option>样本接收</option><option>生产过程</option></select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>创建时间</label>
|
||||
<input type="text" placeholder="开始日期 — 结束日期" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-actions">
|
||||
<button class="btn-op-item">重置</button>
|
||||
<button class="btn-op-item primary">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-body qc-work-order-cards-body">
|
||||
<div class="qc-work-order-cards-wrap">
|
||||
|
||||
<!-- 行 1:同样本 2 条 → Tab 切换 -->
|
||||
<article class="qc-sample-row" data-group="g1">
|
||||
<div class="qc-sample-row__ctx">
|
||||
<span class="qc-sample-row__idx">1</span>
|
||||
<span class="qc-sample-row__code">ZK202506120001</span>
|
||||
<span class="qc-sample-row__sub">脐带血 · 协议 XY-2025-0066 · 已生效 · 接收 2026-06-12 · 李四</span>
|
||||
<span class="qc-sample-row__badge">2 条质检</span>
|
||||
</div>
|
||||
<div class="qc-wo-tabs">
|
||||
<div class="qc-wo-tab active" data-group="g1" data-pane="g1-p1">
|
||||
<span class="qc-wo-tab__dot qc-wo-tab__dot--reception"></span>
|
||||
<span class="qc-wo-tab__no">ZJ202606120001</span> · 样本接收
|
||||
<span class="el-tag el-tag--warning" style="margin-left:6px">已配置</span>
|
||||
</div>
|
||||
<div class="qc-wo-tab" data-group="g1" data-pane="g1-p2">
|
||||
<span class="qc-wo-tab__dot qc-wo-tab__dot--production"></span>
|
||||
<span class="qc-wo-tab__no">ZJ202606120015</span> · 生产过程
|
||||
<span class="el-tag el-tag--info" style="margin-left:6px">待配置</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="qc-wo-pane active" id="g1-p1">
|
||||
<header class="qc-work-order-card__head">
|
||||
<div class="qc-work-order-card__head-inner">
|
||||
<div class="qc-work-order-card__head-main">
|
||||
<div class="qc-work-order-card__title-row">
|
||||
<span class="qc-work-order-card__no">ZJ202606120001</span>
|
||||
<span class="el-tag el-tag--warning">已配置</span>
|
||||
<span class="el-tag el-tag--primary">样本接收</span>
|
||||
</div>
|
||||
<dl class="qc-work-order-card__meta">
|
||||
<div class="qc-work-order-card__meta-item"><dt>实验室入库编码</dt><dd>LAB-202506120001</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>来源类型</dt><dd><span class="el-tag el-tag--success">细胞存储</span></dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>样本类型</dt><dd>脐带血</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>检测方式</dt><dd>实验室 / 第三方</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>创建时间</dt><dd>2026-06-12 09:35</dd></div>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="qc-work-order-card__ops">
|
||||
<button class="btn-op-item primary">⚙ 调整检测</button>
|
||||
<button class="btn-op-item">👁 查看</button>
|
||||
<button class="btn-op-item">⋯</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<section class="qc-work-order-card__tasks">
|
||||
<div class="qc-work-order-task-sublist__head">
|
||||
<div class="qc-work-order-task-sublist__head-title">质检任务</div>
|
||||
<span class="qc-work-order-task-sublist__count">共 3 项任务 ↻</span>
|
||||
</div>
|
||||
<div class="qc-task-cards-grid">
|
||||
<div class="qc-task-card">
|
||||
<div class="qc-task-card__line qc-task-card__line--top">
|
||||
<span class="qc-task-card__name">HBV-DNA</span>
|
||||
<div class="qc-task-card__tags">
|
||||
<span class="el-tag el-tag--success">已完成</span>
|
||||
<span class="el-tag el-tag--success">实验室</span>
|
||||
<span class="el-tag el-tag--success">通过</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-task-card__line">
|
||||
<span class="qc-task-card__code">RW202606120001</span>
|
||||
<span class="qc-task-card__sep">·</span>
|
||||
<span class="qc-task-card__assignees">张质检</span>
|
||||
<div class="qc-work-order-task-sublist__ops">
|
||||
<button class="btn-op-item primary sm">查看</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-task-card">
|
||||
<div class="qc-task-card__line qc-task-card__line--top">
|
||||
<span class="qc-task-card__name">细菌培养</span>
|
||||
<div class="qc-task-card__tags">
|
||||
<span class="el-tag el-tag--success">已完成</span>
|
||||
<span class="el-tag el-tag--success">实验室</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-task-card__line">
|
||||
<span class="qc-task-card__code">RW202606120002</span>
|
||||
<span class="qc-task-card__sep">·</span>
|
||||
<span class="qc-task-card__assignees">张质检</span>
|
||||
<div class="qc-work-order-task-sublist__ops">
|
||||
<button class="btn-op-item primary sm">查看</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-task-card">
|
||||
<div class="qc-task-card__line qc-task-card__line--top">
|
||||
<span class="qc-task-card__name">支原体检测</span>
|
||||
<div class="qc-task-card__tags">
|
||||
<span class="el-tag el-tag--warning">进行中</span>
|
||||
<span class="el-tag el-tag--warning">第三方</span>
|
||||
<span class="el-tag el-tag--info">待结论</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-task-card__line">
|
||||
<span class="qc-task-card__code">RW202606120003</span>
|
||||
<span class="qc-task-card__sep">·</span>
|
||||
<span class="qc-task-card__assignees">—</span>
|
||||
<div class="qc-work-order-task-sublist__ops">
|
||||
<button class="btn-op-item primary sm">开始</button>
|
||||
<button class="btn-op-item sm icon-only">⋯</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="qc-wo-pane" id="g1-p2">
|
||||
<header class="qc-work-order-card__head">
|
||||
<div class="qc-work-order-card__head-inner">
|
||||
<div class="qc-work-order-card__head-main">
|
||||
<div class="qc-work-order-card__title-row">
|
||||
<span class="qc-work-order-card__no">ZJ202606120015</span>
|
||||
<span class="el-tag el-tag--info">待配置</span>
|
||||
<span class="el-tag el-tag--success">生产过程</span>
|
||||
</div>
|
||||
<dl class="qc-work-order-card__meta">
|
||||
<div class="qc-work-order-card__meta-item"><dt>触发来源</dt><dd>生产过程</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>质检对象</dt><dd>CP-202506120003</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>产品名称</dt><dd>脐带血 MSC · P2</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>关联生产工单</dt><dd>SC202606120001</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>检测方式</dt><dd>—</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>创建时间</dt><dd>2026-06-14 15:20</dd></div>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="qc-work-order-card__ops">
|
||||
<button class="btn-op-item primary">⚙ 配置检测</button>
|
||||
<button class="btn-op-item">👁 查看</button>
|
||||
<button class="btn-op-item">⋯</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<section class="qc-work-order-card__tasks">
|
||||
<div class="qc-work-order-task-sublist__head">
|
||||
<div class="qc-work-order-task-sublist__head-title">质检任务</div>
|
||||
<span class="qc-work-order-task-sublist__count">共 0 项任务 ↻</span>
|
||||
</div>
|
||||
<div class="qc-work-order-task-sublist__empty">暂无任务,请先在工单行「配置检测」</div>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- 行 2:同样本 3 条 → Tab 切换 -->
|
||||
<article class="qc-sample-row" data-group="g2">
|
||||
<div class="qc-sample-row__ctx">
|
||||
<span class="qc-sample-row__idx">2</span>
|
||||
<span class="qc-sample-row__code">ZK202506090005</span>
|
||||
<span class="qc-sample-row__sub">胎盘 · 协议 XY-2025-0055 · 赵敏</span>
|
||||
<span class="qc-sample-row__badge">3 条质检</span>
|
||||
</div>
|
||||
<div class="qc-wo-tabs">
|
||||
<div class="qc-wo-tab active" data-group="g2" data-pane="g2-p1">
|
||||
<span class="qc-wo-tab__dot qc-wo-tab__dot--reception"></span>
|
||||
<span class="qc-wo-tab__no">ZJ202606090001</span> · 样本接收
|
||||
<span class="el-tag el-tag--success" style="margin-left:6px">已完成</span>
|
||||
</div>
|
||||
<div class="qc-wo-tab" data-group="g2" data-pane="g2-p2">
|
||||
<span class="qc-wo-tab__dot qc-wo-tab__dot--production"></span>
|
||||
<span class="qc-wo-tab__no">ZJ202606100008</span> · 生产过程
|
||||
<span class="el-tag el-tag--success" style="margin-left:6px">已完成</span>
|
||||
</div>
|
||||
<div class="qc-wo-tab" data-group="g2" data-pane="g2-p3">
|
||||
<span class="qc-wo-tab__dot qc-wo-tab__dot--production"></span>
|
||||
<span class="qc-wo-tab__no">ZJ202606110012</span> · 生产过程
|
||||
<span class="el-tag el-tag--warning" style="margin-left:6px">已配置</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-wo-pane active" id="g2-p1">
|
||||
<header class="qc-work-order-card__head">
|
||||
<div class="qc-work-order-card__head-inner">
|
||||
<div class="qc-work-order-card__head-main">
|
||||
<div class="qc-work-order-card__title-row">
|
||||
<span class="qc-work-order-card__no">ZJ202606090001</span>
|
||||
<span class="el-tag el-tag--success">已完成</span>
|
||||
<span class="el-tag el-tag--primary">样本接收</span>
|
||||
</div>
|
||||
<dl class="qc-work-order-card__meta">
|
||||
<div class="qc-work-order-card__meta-item"><dt>检测方式</dt><dd>实验室 / 第三方</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>创建时间</dt><dd>2026-06-09 10:00</dd></div>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="qc-work-order-card__ops"><button class="btn-op-item">👁 查看</button></div>
|
||||
</div>
|
||||
</header>
|
||||
<section class="qc-work-order-card__tasks">
|
||||
<div class="qc-task-cards-grid">
|
||||
<div class="qc-task-card">
|
||||
<div class="qc-task-card__line qc-task-card__line--top">
|
||||
<span class="qc-task-card__name">无菌检测</span>
|
||||
<div class="qc-task-card__tags"><span class="el-tag el-tag--success">已完成</span></div>
|
||||
</div>
|
||||
<div class="qc-task-card__line">
|
||||
<span class="qc-task-card__code">RW202606090001</span>
|
||||
<span class="qc-task-card__sep">·</span>
|
||||
<span class="qc-task-card__assignees">张质检</span>
|
||||
<div class="qc-work-order-task-sublist__ops"><button class="btn-op-item primary sm">查看</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-task-card">
|
||||
<div class="qc-task-card__line qc-task-card__line--top">
|
||||
<span class="qc-task-card__name">内毒素</span>
|
||||
<div class="qc-task-card__tags"><span class="el-tag el-tag--success">已完成</span></div>
|
||||
</div>
|
||||
<div class="qc-task-card__line">
|
||||
<span class="qc-task-card__code">RW202606090002</span>
|
||||
<span class="qc-task-card__sep">·</span>
|
||||
<span class="qc-task-card__assignees">李质检</span>
|
||||
<div class="qc-work-order-task-sublist__ops"><button class="btn-op-item primary sm">查看</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="qc-wo-pane" id="g2-p2">
|
||||
<header class="qc-work-order-card__head">
|
||||
<div class="qc-work-order-card__head-inner">
|
||||
<div class="qc-work-order-card__head-main">
|
||||
<div class="qc-work-order-card__title-row">
|
||||
<span class="qc-work-order-card__no">ZJ202606100008</span>
|
||||
<span class="el-tag el-tag--success">已完成</span>
|
||||
<span class="el-tag el-tag--success">生产过程</span>
|
||||
</div>
|
||||
<dl class="qc-work-order-card__meta">
|
||||
<div class="qc-work-order-card__meta-item"><dt>质检对象</dt><dd>CP-202506090001 · P1</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>关联生产工单</dt><dd>SC202606090001</dd></div>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="qc-work-order-card__ops"><button class="btn-op-item">👁 查看</button></div>
|
||||
</div>
|
||||
</header>
|
||||
<section class="qc-work-order-card__tasks">
|
||||
<div class="qc-task-cards-grid">
|
||||
<div class="qc-task-card">
|
||||
<div class="qc-task-card__line qc-task-card__line--top">
|
||||
<span class="qc-task-card__name">细胞活性</span>
|
||||
<div class="qc-task-card__tags">
|
||||
<span class="el-tag el-tag--success">已完成</span>
|
||||
<span class="el-tag el-tag--success">实验室</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-task-card__line">
|
||||
<span class="qc-task-card__code">RW202606100008</span>
|
||||
<span class="qc-task-card__sep">·</span>
|
||||
<span class="qc-task-card__assignees">王质检</span>
|
||||
<div class="qc-work-order-task-sublist__ops"><button class="btn-op-item primary sm">查看</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="qc-wo-pane" id="g2-p3">
|
||||
<header class="qc-work-order-card__head">
|
||||
<div class="qc-work-order-card__head-inner">
|
||||
<div class="qc-work-order-card__head-main">
|
||||
<div class="qc-work-order-card__title-row">
|
||||
<span class="qc-work-order-card__no">ZJ202606110012</span>
|
||||
<span class="el-tag el-tag--warning">已配置</span>
|
||||
<span class="el-tag el-tag--success">生产过程</span>
|
||||
</div>
|
||||
<dl class="qc-work-order-card__meta">
|
||||
<div class="qc-work-order-card__meta-item"><dt>质检对象</dt><dd>CP-202506110002 · P3</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>关联生产工单</dt><dd>SC202606090001</dd></div>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="qc-work-order-card__ops">
|
||||
<button class="btn-op-item primary">⚙ 调整检测</button>
|
||||
<button class="btn-op-item">👁 查看</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<section class="qc-work-order-card__tasks">
|
||||
<div class="qc-task-cards-grid">
|
||||
<div class="qc-task-card">
|
||||
<div class="qc-task-card__line qc-task-card__line--top">
|
||||
<span class="qc-task-card__name">STR 鉴定</span>
|
||||
<div class="qc-task-card__tags">
|
||||
<span class="el-tag el-tag--warning">进行中</span>
|
||||
<span class="el-tag el-tag--success">实验室</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-task-card__line">
|
||||
<span class="qc-task-card__code">RW202606110001</span>
|
||||
<span class="qc-task-card__sep">·</span>
|
||||
<span class="qc-task-card__assignees">张质检</span>
|
||||
<div class="qc-work-order-task-sublist__ops"><button class="btn-op-item primary sm">开始</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-task-card">
|
||||
<div class="qc-task-card__line qc-task-card__line--top">
|
||||
<span class="qc-task-card__name">支原体</span>
|
||||
<div class="qc-task-card__tags">
|
||||
<span class="el-tag el-tag--info">待执行</span>
|
||||
<span class="el-tag el-tag--warning">第三方</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-task-card__line">
|
||||
<span class="qc-task-card__code">RW202606110002</span>
|
||||
<span class="qc-task-card__sep">·</span>
|
||||
<span class="qc-task-card__assignees">—</span>
|
||||
<div class="qc-work-order-task-sublist__ops"><button class="btn-op-item primary sm">开始</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- 行 3:仅 1 条 → 无 Tab,与现网单卡一致 -->
|
||||
<article class="qc-sample-row">
|
||||
<div class="qc-sample-row__ctx">
|
||||
<span class="qc-sample-row__idx">3</span>
|
||||
<span class="qc-sample-row__code">ZK202506080003</span>
|
||||
<span class="qc-sample-row__sub">脐带血 · 协议 XY-2025-0088 · 王强 · 接收 2026-06-08</span>
|
||||
</div>
|
||||
<header class="qc-work-order-card__head">
|
||||
<div class="qc-work-order-card__head-inner">
|
||||
<div class="qc-work-order-card__head-main">
|
||||
<div class="qc-work-order-card__title-row">
|
||||
<span class="qc-work-order-card__no">ZJ202606080001</span>
|
||||
<span class="el-tag el-tag--info">待配置</span>
|
||||
<span class="el-tag el-tag--primary">样本接收</span>
|
||||
</div>
|
||||
<dl class="qc-work-order-card__meta">
|
||||
<div class="qc-work-order-card__meta-item"><dt>实验室入库编码</dt><dd>LAB-202506080001</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>来源类型</dt><dd><span class="el-tag el-tag--success">细胞存储</span></dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>协议状态</dt><dd><span class="el-tag el-tag--success">已生效</span></dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>样本类型</dt><dd>脐带血</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>接收时间</dt><dd>2026-06-08 09:15</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>接收经手人</dt><dd>李四</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>检测方式</dt><dd>—</dd></div>
|
||||
<div class="qc-work-order-card__meta-item"><dt>创建时间</dt><dd>2026-06-08 09:20</dd></div>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="qc-work-order-card__ops">
|
||||
<button class="btn-op-item primary">⚙ 配置检测</button>
|
||||
<button class="btn-op-item">⋯</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<section class="qc-work-order-card__tasks">
|
||||
<div class="qc-work-order-task-sublist__head">
|
||||
<div class="qc-work-order-task-sublist__head-title">质检任务</div>
|
||||
<span class="qc-work-order-task-sublist__count">共 0 项任务 ↻</span>
|
||||
</div>
|
||||
<div class="qc-work-order-task-sublist__empty">暂无任务,请先在工单行「配置检测」</div>
|
||||
</section>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="pagination">
|
||||
<span>共 3 个样本 · 5 条质检工单</span>
|
||||
<button>‹</button>
|
||||
<button class="active">1</button>
|
||||
<button>›</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.querySelectorAll('.qc-wo-tab').forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
const group = tab.closest('.qc-sample-row');
|
||||
const paneId = tab.dataset.pane;
|
||||
group.querySelectorAll('.qc-wo-tab').forEach(t => t.classList.remove('active'));
|
||||
group.querySelectorAll('.qc-wo-pane').forEach(p => p.classList.remove('active'));
|
||||
tab.classList.add('active');
|
||||
document.getElementById(paneId).classList.add('active');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,13 @@
|
||||
-- 质检工单:生产过程触发来源字段
|
||||
ALTER TABLE biz_qc_work_order
|
||||
ADD COLUMN trigger_source VARCHAR(20) NOT NULL DEFAULT 'reception'
|
||||
COMMENT '触发来源 reception=样本接收 production=生产过程' AFTER qc_biz_type,
|
||||
ADD COLUMN production_work_order_id VARCHAR(64) NULL
|
||||
COMMENT '关联生产工单ID(生产过程触发时)' AFTER cell_product_id,
|
||||
ADD COLUMN production_task_id VARCHAR(64) NULL
|
||||
COMMENT '关联生产任务ID(可选)' AFTER production_work_order_id;
|
||||
|
||||
UPDATE biz_qc_work_order SET trigger_source = 'reception' WHERE trigger_source IS NULL OR trigger_source = '';
|
||||
|
||||
CREATE INDEX idx_qc_wo_sample_trigger ON biz_qc_work_order (tenant_no, sample_code, trigger_source, del_flag);
|
||||
CREATE INDEX idx_qc_wo_prod_wo ON biz_qc_work_order (production_work_order_id, del_flag);
|
||||
@@ -0,0 +1,399 @@
|
||||
# 生产过程发起质检 + 质检工单统一展示 实现计划
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development or superpowers:executing-plans to implement task-by-task.
|
||||
|
||||
**Goal:** 生产专员在【生产工单】卡片列表中「派发质检工单」(选细胞产品 + 备注);质检专员在【质检工单】同列表看到接收/生产两种来源并按样本 Tab 展示。同时【生产工单】入库/出库/临时三个 Tab 列表由表格改为与质检侧一致的单列卡片模式。
|
||||
|
||||
**Architecture:** 扩展 `biz_qc_work_order` 触发来源字段;生产 API 建单;生产/质检列表均改为单列大卡片 + 内嵌任务区(生产任务沿用现有子列表逻辑并收敛紧凑样式);质检侧同样本 Tab 分组;生产侧每工单卡片操作区增加「派发质检工单」弹窗。
|
||||
|
||||
**Tech Stack:** MySQL 5.7 · FastAPI · Vue 3 · Element Plus
|
||||
|
||||
**UI 权威 Demo:** `docs/mockups/qc-work-order-related-cards-prototype.html`(质检侧);生产侧卡片结构对齐 `QcWorkOrderCardList.vue` + 现网 `WorkOrderTaskSubList.vue`
|
||||
|
||||
---
|
||||
|
||||
## 1. 需求结论(能否实现)
|
||||
|
||||
**可以实现,且与现有架构兼容。**
|
||||
|
||||
| 诉求 | 结论 |
|
||||
|------|------|
|
||||
| 生产专员派发质检(选细胞产品+备注) | 生产工单卡片「派发质检工单」+ 弹窗 + API |
|
||||
| 质检工单界面可见两种来源 | 同表 + 样本 Tab 分组展示 |
|
||||
| 生产工单三 Tab 改卡片列表 | **可以**;新建 `ProductionWorkOrderCardList`,单列 + 内嵌任务 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 业务流程(目标态)
|
||||
|
||||
```
|
||||
市场专员 → 采集协议单
|
||||
↓
|
||||
质检专员 → 样本接收(结论=接收)
|
||||
├→ 自动:入库质检工单 [trigger_source=reception] (放行门禁)
|
||||
└→ 自动:入库生产工单
|
||||
↓
|
||||
生产专员 → 生产任务执行 → 产出细胞产品
|
||||
↓
|
||||
生产专员 → 【生产工单】卡片列表 → 【派发质检工单】
|
||||
(选择细胞产品 + 填写备注 → 提交)
|
||||
↓
|
||||
新建:入库质检工单 [trigger_source=production] (过程质检,不替代门禁)
|
||||
↓
|
||||
质检专员 → 【质检工单】列表
|
||||
同一样本编码下 Tab 切换:样本接收 | 生产过程(可多条)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 已确认 UI 设计
|
||||
|
||||
### 3.1 质检工单列表(Demo 定稿)
|
||||
|
||||
参考 `docs/mockups/qc-work-order-related-cards-prototype.html`:
|
||||
|
||||
| 层级 | 规则 |
|
||||
|------|------|
|
||||
| 列表布局 | **单列**,一行 = 一个样本组(`flex-direction: column`) |
|
||||
| 同样本多条工单 | 顶部样本上下文条 + **Tab 切换**工单;下方 meta + 任务区联动 |
|
||||
| 仅 1 条工单 | 无 Tab,结构与现网单卡一致 |
|
||||
| 质检任务 | **三列网格**;每卡 **2 行融合**:① 项目名 + Tag ② 任务号 · 负责人 · 操作 |
|
||||
| 筛选 | 入库 Tab 增加「触发来源」:全部 / 样本接收 / 生产过程 |
|
||||
|
||||
### 3.2 生产工单列表(新增,对齐卡片模式)
|
||||
|
||||
**现网:** `production-work-order/index.vue` 使用 `el-table` + `type="expand"` 展开生产任务(`WorkOrderTaskSubList`)。
|
||||
|
||||
**目标:** 入库 / 出库 / 临时三个 Tab **均改为单列卡片**,结构与质检工单大卡片一致:
|
||||
|
||||
```
|
||||
┌─ 生产工单 SC202606120001 ─────────────────────────────┐
|
||||
│ head:工单号 + 状态 Tag + meta 栅格 + 操作按钮 │
|
||||
│ 操作含:查看 | 派发任务 | 派发质检工单 | 完成 | … │
|
||||
├──────────────────────────────────────────────────────┤
|
||||
│ tasks:生产任务子列表(内嵌,非表格 expand) │
|
||||
└──────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
| Tab | 卡片 meta 字段 | 分组策略 |
|
||||
|-----|----------------|----------|
|
||||
| **入库** | 与现网表格列一致:样本编码、协议状态、样本类型、接收时间… | 单列;通常 1 样本 1 生产工单,**不做 Tab 分组**(与质检侧不同) |
|
||||
| **出库** | 业务类型、申请单号、用户名称、输注时间… | 单列,一工单一卡 |
|
||||
| **临时** | 工单号、状态、备注、配置时间… | 单列,一工单一卡 |
|
||||
|
||||
| 层级 | 规则 |
|
||||
|------|------|
|
||||
| 列表布局 | **单列** `flex-direction: column`(替换 `minmax` 多列 / 表格) |
|
||||
| 生产任务 | 内嵌于卡片底部 `#fafafa` 任务区;复用 `WorkOrderTaskSubList`,样式收敛为 **三列 + 两行融合**(与质检任务视觉统一,内容字段仍为任务名/状态/工艺类型) |
|
||||
| 工具栏 | 保留「已选 N 项」、新增/派发任务/完成;批量逻辑暂保留(卡片可加 checkbox 或后续迭代) |
|
||||
| 移除 | `el-table` + `expand` 行 |
|
||||
|
||||
**新建组件:**
|
||||
|
||||
- `ProductionWorkOrderCardList.vue` — 对标 `QcWorkOrderCardList.vue`
|
||||
- `index.vue` — 表格区域替换为上述 CardList
|
||||
|
||||
### 3.3 派发质检工单(生产工单入口)
|
||||
|
||||
**位置:** 生产工单卡片 **操作区** 主按钮(入库 Tab 必做;出库若有关联细胞产品可二期扩展)。
|
||||
|
||||
**交互:**
|
||||
|
||||
1. 点击 **「派发质检工单」**(`Promotion` / `Document` 类图标 + 文案,非 primary 实心,与「派发任务」并列描边按钮;每卡仅一个 primary 时仍留给「进入执行/派发任务」)
|
||||
2. 打开弹窗 `DispatchQcWorkOrderDialog.vue`
|
||||
3. 表单(`label-position="top"`,`.dialog-form-layout` + `.form-grid-2`):
|
||||
- **细胞产品**(必填):下拉,数据来自该生产工单下已产出细胞产品
|
||||
- **备注**(选填):`textarea`,max 512
|
||||
4. 确定 → `POST /web/admin/production-work-orders/{id}/qc-work-orders`
|
||||
5. 成功:`ElMessage.success`;可选「前往质检工单」跳转 `/#/quality-manage/qc-work-order?sampleCode=xxx`
|
||||
|
||||
**细胞产品选项来源(后端):**
|
||||
|
||||
```
|
||||
GET /web/admin/production-work-orders/{id}/cell-product-options
|
||||
→ [{ id, productCode, productName, productTypeName, passage, storageSlotName, taskNo }]
|
||||
```
|
||||
|
||||
从该工单下所有生产任务的 **输出子表**(`biz_production_task_output` / cell_product)去重汇总;无产出时禁用按钮并 tooltip「请先完成生产任务并录入输出细胞产品」。
|
||||
|
||||
**前置条件:**
|
||||
|
||||
- 工单状态建议 `jxz` 或 `ywc`(`dpz` 无产出时不可派发)
|
||||
- 租户隔离、软删除一致
|
||||
|
||||
---
|
||||
|
||||
## 4. 数据模型
|
||||
|
||||
### 4.1 `biz_qc_work_order` 新增字段
|
||||
|
||||
```sql
|
||||
ALTER TABLE biz_qc_work_order
|
||||
ADD COLUMN trigger_source VARCHAR(20) NOT NULL DEFAULT 'reception'
|
||||
COMMENT '触发来源 reception=样本接收 production=生产过程' AFTER qc_biz_type,
|
||||
ADD COLUMN production_work_order_id VARCHAR(64) NULL
|
||||
COMMENT '关联生产工单ID(生产过程触发时)' AFTER cell_product_id,
|
||||
ADD COLUMN production_task_id VARCHAR(64) NULL
|
||||
COMMENT '关联生产任务ID(可选)' AFTER production_work_order_id;
|
||||
|
||||
-- 历史数据:全部为 reception
|
||||
UPDATE biz_qc_work_order SET trigger_source = 'reception' WHERE trigger_source IS NULL OR trigger_source = '';
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX idx_qc_wo_sample_trigger ON biz_qc_work_order (tenant_no, sample_code, trigger_source, del_flag);
|
||||
CREATE INDEX idx_qc_wo_prod_wo ON biz_qc_work_order (production_work_order_id, del_flag);
|
||||
```
|
||||
|
||||
**说明:**
|
||||
|
||||
- `uk_qc_wo_reception(reception_id, del_flag)` 保留,保证接收触发仍 1:1。
|
||||
- 生产过程触发 **不占用** 该唯一键;同一样本可有多条 `trigger_source=production` 工单。
|
||||
- `cell_product_id` 已有;生产触发时 **必填**,接收触发时为空。
|
||||
- **不放** `work_order_type=temporary`;过程质检仍属入库链路(`work_order_type=inbound`)。
|
||||
|
||||
### 4.2 业务规则(需产品确认,建议默认)
|
||||
|
||||
| 规则 | 建议默认值 |
|
||||
|------|------------|
|
||||
| 放行门禁质检 | 仅 `trigger_source=reception` 的那条参与入库放行 |
|
||||
| 过程质检是否阻塞放行 | **否**(默认) |
|
||||
| 发起时机 | 细胞产品已写入 `biz_cell_product`(生产任务输出后) |
|
||||
| 同一产品重复发起 | 允许(如 P1/P2 各一次);可选幂等:同 `production_work_order_id + cell_product_id` 且状态非 yzf 时不重复建 |
|
||||
| 检测项目 | 与现网一致:质检专员在工单上「配置检测」时自选 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 后端实现
|
||||
|
||||
### 5.1 新建 CRUD
|
||||
|
||||
**文件:** `backend/app/crud/qc_work_order.py`
|
||||
|
||||
```python
|
||||
def create_qc_work_order_from_production(
|
||||
db, *,
|
||||
production_work_order_id: str,
|
||||
cell_product_id: str,
|
||||
production_task_id: str | None = None,
|
||||
remark: str = "",
|
||||
tenant_no: str,
|
||||
user_id: str,
|
||||
create_dept_id: str = "",
|
||||
) -> BizQcWorkOrder:
|
||||
"""
|
||||
1. 校验生产工单存在、tenant、work_order_type=inbound
|
||||
2. 校验 cell_product 存在且 tenant 一致
|
||||
3. 从生产工单快照 sample_code / protocol_no / reception_id 等
|
||||
4. 插入 biz_qc_work_order:
|
||||
trigger_source=production, work_order_status=dpz
|
||||
5. flush,不 commit(由 API 层 commit)
|
||||
"""
|
||||
```
|
||||
|
||||
**文件:** `backend/app/schemas/qc_work_order.py` — 新增 `ProductionQcWorkOrderCreateBody`
|
||||
|
||||
### 5.2 API
|
||||
|
||||
**文件:** `backend/app/api/production.py`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | `/production-work-orders/{work_order_id}/qc-work-orders` | 派发质检工单 Body: `{ cellProductId, remark? }` |
|
||||
| GET | `/production-work-orders/{work_order_id}/cell-product-options` | 弹窗细胞产品下拉选项 |
|
||||
|
||||
权限:生产工单菜单(如 `biz:productionWorkOrder:list`);建单写操作可复用或新增 `biz:productionWorkOrder:dispatchQc`。
|
||||
|
||||
### 5.3 列表 API 扩展
|
||||
|
||||
**文件:** `backend/app/crud/qc_work_order.py` · `list_work_orders`
|
||||
|
||||
- `_wo_to_dict` 增加:`triggerSource`, `triggerSourceLabel`, `productionWorkOrderId`, `productionTaskId`
|
||||
- 筛选参数:`triggerSource=reception|production`
|
||||
- **分组(二选一):**
|
||||
- **A(推荐)** 后端返回 `groups: [{ sampleCode, sampleMeta, workOrders: [...] }]`,分页按样本组
|
||||
- **B** 仍返回 flat list,前端按 `sampleCode` 分组(改动小,分页语义弱)
|
||||
|
||||
### 5.4 接收触发现有逻辑
|
||||
|
||||
**文件:** `backend/app/crud/qc_work_order.py` · `create_work_order_from_reception`
|
||||
|
||||
创建时显式写 `trigger_source='reception'`。
|
||||
|
||||
### 5.5 入库放行联动
|
||||
|
||||
**文件:** `backend/app/crud/storage_release_review.py` · `_build_qc_info`
|
||||
|
||||
查询质检工单时增加:
|
||||
|
||||
```python
|
||||
.filter(BizQcWorkOrder.trigger_source == 'reception')
|
||||
```
|
||||
|
||||
避免多条同工单时取错;过程质检不参与放行展示。
|
||||
|
||||
---
|
||||
|
||||
## 6. 前端实现
|
||||
|
||||
### 6.1 生产侧 — 列表卡片化 + 派发质检
|
||||
|
||||
**核心文件:**
|
||||
|
||||
| 文件 | 改动 |
|
||||
|------|------|
|
||||
| `production-work-order/index.vue` | 移除 `el-table`;接入 `ProductionWorkOrderCardList`;挂载 `DispatchQcWorkOrderDialog` |
|
||||
| 新建 `ProductionWorkOrderCardList.vue` | 单列卡片;head(meta+ops) + 内嵌 `WorkOrderTaskSubList`;三 Tab 字段分支 |
|
||||
| `WorkOrderTaskSubList.vue` | 任务卡改为三列 + 两行融合(与质检任务样式对齐) |
|
||||
| 新建 `DispatchQcWorkOrderDialog.vue` | 细胞产品 select + 备注 + 提交 |
|
||||
| `api/production-work-order.ts` | `fetchCreateQcFromProduction`、`fetchProductionWorkOrderCellProductOptions` |
|
||||
|
||||
**卡片操作区按钮(入库示例,从左到右):**
|
||||
|
||||
| 按钮 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| 派发任务 | primary(每卡唯一主色) | 现有逻辑,打开 `DispatchTaskDialog` |
|
||||
| 派发质检工单 | 描边 | 打开 `DispatchQcWorkOrderDialog` |
|
||||
| 完成工单 | 描边 | 现有逻辑 |
|
||||
| 查看 / 编辑 / 删除 | 描边 / 更多 | 现有逻辑 |
|
||||
|
||||
**`DispatchQcWorkOrderDialog.vue` 要点:**
|
||||
|
||||
```vue
|
||||
<!-- 560px dialog-form-layout -->
|
||||
<!-- 只读:工单号、样本编码 -->
|
||||
<!-- 必填:el-select 细胞产品(filterable,option 展示 编码 · 名称 · 代次) -->
|
||||
<!-- 选填:备注 textarea -->
|
||||
<!-- footer:取消 Close / 确定 Check -->
|
||||
```
|
||||
|
||||
**不再**在 `TaskOutputList` 单独做「发起质检」入口(统一为工单卡片「派发质检工单」,避免两处入口)。
|
||||
|
||||
### 6.2 质检侧 — 列表重构
|
||||
|
||||
**核心文件:**
|
||||
|
||||
| 文件 | 改动 |
|
||||
|------|------|
|
||||
| `QcWorkOrderCardList.vue` | 单列布局;引入样本组 + Tab 容器 |
|
||||
| 新建 `QcWorkOrderSampleGroup.vue` | 样本上下文条 + Tab + 内嵌单工单 head/tasks |
|
||||
| `QcWorkOrderTaskSubList.vue` | 任务卡改为三列网格 + 两行融合布局 |
|
||||
| `qc-work-order/index.vue` | 筛选增加「触发来源」;适配分组列表数据结构 |
|
||||
| `api/qc-work-order.ts` | 类型扩展 + 分组 list 或前端 groupBy 工具 |
|
||||
|
||||
**Tab 标签:** `{workOrderNo} · 样本接收|生产过程` + 状态 Tag
|
||||
|
||||
**单条工单 meta 差异:**
|
||||
|
||||
| 字段 | 样本接收 | 生产过程 |
|
||||
|------|----------|----------|
|
||||
| 触发来源 | 样本接收 | 生产过程 |
|
||||
| 质检对象 | 原始样本 / — | 细胞产品编码 + 名称 |
|
||||
| 关联生产工单 | — | 生产工单号 |
|
||||
|
||||
样本级字段(样本编码、协议、接收信息)提到 **样本上下文条**,Tab 内 meta 不重复。
|
||||
|
||||
### 6.3 任务卡片样式(质检 + 生产任务统一)
|
||||
|
||||
质检任务(`QcWorkOrderTaskSubList`)与生产任务(`WorkOrderTaskSubList`)均采用:
|
||||
|
||||
```scss
|
||||
.qc-task-cards-grid, .production-task-cards-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
// 每卡 2 行:name+tags / code·meta·ops
|
||||
// min-height ~68px
|
||||
```
|
||||
|
||||
可抽公共 SCSS 片段到 `web-admin/src/styles/` 或共享 class 前缀 `work-order-task-cards-grid`。
|
||||
|
||||
---
|
||||
|
||||
## 7. 任务分解(实施顺序)
|
||||
|
||||
### Phase 1 — 数据与后端建单(可独立验收)
|
||||
|
||||
- [ ] 1.1 SQL 迁移写入 `docs/sql/migrations/2026-06-12-qc-work-order-trigger-source.sql`
|
||||
- [ ] 1.2 Model / Schema 增加字段
|
||||
- [ ] 1.3 `create_qc_work_order_from_reception` 写 `trigger_source=reception`
|
||||
- [ ] 1.4 实现 `create_qc_work_order_from_production`
|
||||
- [ ] 1.5 实现 `list_cell_product_options_for_production_work_order`
|
||||
- [ ] 1.6 生产 API:`POST .../qc-work-orders`、`GET .../cell-product-options`
|
||||
- [ ] 1.7 `_wo_to_dict` + list 筛选 `triggerSource`
|
||||
- [ ] 1.8 放行审核 `_build_qc_info` 仅取 reception 工单
|
||||
- [ ] 1.9 运行 `python scripts/check_field_consistency.py`(若涉及 CRUD 字段)
|
||||
|
||||
### Phase 2 — 生产工单 UI(卡片化 + 派发质检)
|
||||
|
||||
- [ ] 2.1 API:`fetchCreateQcFromProduction`、`fetchProductionWorkOrderCellProductOptions`
|
||||
- [ ] 2.2 新建 `DispatchQcWorkOrderDialog.vue`
|
||||
- [ ] 2.3 新建 `ProductionWorkOrderCardList.vue`(入库/出库/临时 meta 分支)
|
||||
- [ ] 2.4 `index.vue` 表格 → CardList;工具栏与选择逻辑适配
|
||||
- [ ] 2.5 `WorkOrderTaskSubList.vue` 三列紧凑任务卡
|
||||
- [ ] 2.6 卡片操作区「派发质检工单」接入弹窗
|
||||
- [ ] 2.7 权限码(如需)
|
||||
|
||||
### Phase 3 — 质检列表 UI(Demo 落地)
|
||||
|
||||
- [ ] 3.1 `QcWorkOrderSampleGroup.vue`(Tab + 样本条)
|
||||
- [ ] 3.2 `QcWorkOrderCardList.vue` 改单列 + 分组渲染
|
||||
- [ ] 3.3 列表 API 分组或前端 `groupWorkOrdersBySample()`
|
||||
- [ ] 3.4 筛选「触发来源」
|
||||
- [ ] 3.5 `QcWorkOrderTaskSubList.vue` 三列紧凑任务卡
|
||||
- [ ] 3.6 查看弹窗 / 配置检测:生产过程工单展示 `cellProduct*`、生产工单号
|
||||
|
||||
### Phase 4 — 联调与文档
|
||||
|
||||
- [ ] 4.1 端到端:接收 → 生产卡片 → 派发质检 → 质检列表 Tab 可见
|
||||
- [ ] 4.2 生产三 Tab 卡片列表回归:派发任务、完成工单、查看
|
||||
- [ ] 4.3 放行审核仍只认 reception 工单
|
||||
- [ ] 4.4 更新 OpenSpec / 设计 spec(可选)
|
||||
- [ ] 4.5 `./scripts/update-graph.sh web-admin`(若改 import/组件)
|
||||
|
||||
---
|
||||
|
||||
## 8. 风险与待确认项
|
||||
|
||||
| 项 | 说明 | 建议 |
|
||||
|----|------|------|
|
||||
| 放行门禁 | 过程质检是否影响放行 | 默认不影响,仅 reception 工单入门禁 |
|
||||
| 分页语义 | 按工单分页 vs 按样本分页 | 改按样本组分页,总数展示「N 样本 · M 工单」 |
|
||||
| 出库/临时 Tab | 是否同样本分组 | 质检入库 Tab 按样本 Tab;生产三 Tab 均 **一工单一卡** 无样本 Tab |
|
||||
| 派发质检范围 | 出库生产是否派发 | 一期 **入库生产工单**;出库有细胞产品场景二期 |
|
||||
| 生产列表批量选择 | 卡片模式多选 | 一期可保留工具栏批量按钮 + 卡片 checkbox,或暂禁批量仅单卡操作 |
|
||||
| 临时质检 Tab | 与生产过程质检区别 | 临时工单无样本关联;勿与 production 触发混淆 |
|
||||
| 权限 | 谁可派发质检 | 生产专员 + 生产工单相关权限 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 验收标准
|
||||
|
||||
**质检工单**
|
||||
|
||||
1. 样本接收后,质检列表出现 1 条「样本接收」工单(行为与现网一致)。
|
||||
2. 生产专员 **派发质检工单** 后,同一样本组出现新 Tab「生产过程」,状态为待配置。
|
||||
3. 质检专员 Tab 切换可分别配置检测、查看任务;任务区为三列两行融合卡片。
|
||||
4. 筛选「触发来源=生产过程」仅显示生产触发工单。
|
||||
5. 入库放行审核详情中,质检信息仍为接收触发工单。
|
||||
|
||||
**生产工单**
|
||||
|
||||
6. 入库 / 出库 / 临时三个 Tab 均为 **单列卡片**,无 `el-table` 主列表。
|
||||
7. 卡片内嵌生产任务子列表,任务为紧凑三列布局。
|
||||
8. 入库生产工单卡片可点击 **派发质检工单**,选细胞产品 + 备注后创建成功。
|
||||
9. 无细胞产品产出时按钮不可用或有明确提示。
|
||||
10. 原有「派发任务」「完成工单」「查看」等操作在卡片模式下仍可用。
|
||||
|
||||
---
|
||||
|
||||
## 10. 参考
|
||||
|
||||
- UI Demo(质检):`docs/mockups/qc-work-order-related-cards-prototype.html`
|
||||
- 质检卡片:`web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue`
|
||||
- 生产工单页(待改):`web-admin/src/views/production/production-work-order/index.vue`
|
||||
- 生产任务子列表:`web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue`
|
||||
- 派发任务弹窗(表单参考):`DispatchTaskDialog.vue`
|
||||
- 接收建单:`backend/app/crud/qc_work_order.py` · `create_work_order_from_reception`
|
||||
- 接收事务:`backend/app/crud/sample_reception.py`
|
||||
- 质检工单表:`biz_qc_work_order`
|
||||
@@ -0,0 +1,44 @@
|
||||
# 质检工单 · 用户费用摘要 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 在入库/出库质检工单列表与查看弹窗中,为采集协议单与基础实验来源展示用户费用当前快照。
|
||||
|
||||
**Architecture:** 后端新增 `qc_work_order_fee_summary` 服务批量计算 `paymentSummary` / `feeSummary`,在列表与详情 enrich 中挂载;前端在样本组/卡片增加摘要条,查看弹窗补充缴费区块。
|
||||
|
||||
**Tech Stack:** Python 3.9 / FastAPI / SQLAlchemy · Vue 3 / Element Plus / TypeScript
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-06-12-qc-work-order-fee-summary-design.md`
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 后端费用摘要服务
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/services/qc_work_order_fee_summary.py`
|
||||
- Modify: `backend/app/crud/qc_work_order.py`
|
||||
|
||||
- [x] 实现 `build_protocol_payment_summaries` / `build_basic_experiment_fee_summaries` / `enrich_work_order_fee_summaries`
|
||||
- [x] 在 `list_work_orders` 与 `get_work_order_detail` / `get_outbound_qc_detail` 调用 enrich
|
||||
|
||||
### Task 2: 前端 API 类型
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/api/qc-work-order.ts`
|
||||
|
||||
- [x] 新增 `QcProtocolPaymentSummary` / `QcBasicExperimentFeeSummary` 并扩展 `QcWorkOrder`
|
||||
|
||||
### Task 3: 列表 UI
|
||||
|
||||
**Files:**
|
||||
- Create: `web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderFeeSummaryBar.vue`
|
||||
- Modify: `QcWorkOrderSampleGroup.vue`、`QcWorkOrderSingleCard.vue`、`index.vue`(筛选补基础实验)
|
||||
|
||||
### Task 4: 查看弹窗
|
||||
|
||||
**Files:**
|
||||
- Modify: `index.vue`(入库 viewSections)、`OutboundQcViewDialog.vue`
|
||||
|
||||
### Task 5: 图谱更新
|
||||
|
||||
- [x] `./scripts/update-graph.sh frontend`(若新建组件)
|
||||
@@ -0,0 +1,292 @@
|
||||
# 质检工单 · 用户费用摘要展示设计
|
||||
|
||||
> 日期:2026-06-12
|
||||
> 状态:已实现
|
||||
> 需求确认:**方案 A — 当前快照**(展示合同/已收/待缴/缴费状态,不含历史轨迹、不含与质检动作的联动规则)
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
### 1.1 业务诉求
|
||||
|
||||
质检专员在 **入库质检工单**、**出库质检工单** 列表中处理工单时,需要快速了解关联来源单据上的 **用户费用当前状态**,避免在配置/执行质检时忽略欠费、待确认收款等情况。
|
||||
|
||||
### 1.2 展示范围(已确认)
|
||||
|
||||
| Tab | 来源 | 系统标识 | 是否展示费用 |
|
||||
|-----|------|----------|-------------|
|
||||
| 入库质检 | 采集协议单(细胞存储) | `receptionSource = cell_storage` | **是** |
|
||||
| 入库质检 | 捐赠协议单(科研捐赠) | `receptionSource = research_donation` | **否**(业务无缴费) |
|
||||
| 出库质检 | 中试服务申请单 | `bizType = pilot_service` | **否**(渠道扣费) |
|
||||
| 出库质检 | 基础实验 | `bizType = basic_experiment` | **是** |
|
||||
| 出库质检 | 临床应用 | `bizType = clinical_application` | **否**(本期不做,架构预留) |
|
||||
|
||||
### 1.3 非目标
|
||||
|
||||
- 不展示费用 **变更历史**、操作日志、时间线
|
||||
- 不根据费用状态 **阻断或自动推进** 质检流程
|
||||
- 不在本模块 **编辑** 协议/申请单费用
|
||||
- 不展示 **质检检测自身费用**(第三方检测 `thirdPartyFeeTotal`、任务 `feeAmount`)——与用户协议/申请单费用分区展示,避免混淆
|
||||
|
||||
### 1.4 与现有 UI 的关系
|
||||
|
||||
- **列表层**:新增紧凑「费用摘要条」,满足「特别关注」的扫视需求
|
||||
- **查看弹窗层**:补充完整只读缴费区块,可跳转来源单据详情
|
||||
- 视觉对齐 Fresh Mint 规范;金额用 `formatMoneyDisplay`;状态用 `el-tag`
|
||||
|
||||
---
|
||||
|
||||
## 2. 费用字段定义
|
||||
|
||||
### 2.1 入库 · 采集协议单(`paymentSummary`)
|
||||
|
||||
数据来源:`biz_protocol_payment` + `biz_protocol_payment_detail`(经 `collection_protocol_id` 关联)。
|
||||
|
||||
| 字段 | API 别名 | 说明 | 计算/口径 |
|
||||
|------|----------|------|-----------|
|
||||
| 缴费模式 | `payMode` | `dj` 趸交 / `fq` 分期 | 主表 |
|
||||
| 缴费模式标签 | `payModeLabel` | 趸交 / 分期 | 后端或前端码表 |
|
||||
| 合同金额 | `contractAmount` | 元 | 主表 `contract_amount` |
|
||||
| 已收金额 | `receivedAmount` | 元 | 明细中 `payStatus ∈ {yjf, jfqrz}` 的 `transferAmount` 之和(与 `ProtocolViewDialog` 一致) |
|
||||
| 待收金额 | `pendingAmount` | 元 | `max(contractAmount - receivedAmount, 0)`,合同为空时返回 `null` |
|
||||
| 缴费状态摘要 | `statusHint` | 如「已缴清」「1 期待确认」「2 期待缴费」 | 由明细 `payStatus` 聚合生成 |
|
||||
| 整体缴费状态 Tag | `overallPayStatus` / `overallPayStatusLabel` | 用于摘要条 Tag | 见 §2.1.1 |
|
||||
|
||||
#### 2.1.1 整体缴费状态(摘要 Tag 语义)
|
||||
|
||||
优先级从高到低:
|
||||
|
||||
1. 存在 `tfqrz`(退费确认中)→ Tag `warning`,文案「退费确认中」
|
||||
2. 存在 `ytf` 且无其他未完结明细 → Tag `info`,文案「已退费」
|
||||
3. 合同金额有效且 `pendingAmount <= 0` 且不存在 `dfj`/`jfqrz` → Tag `success`,文案「已缴清」
|
||||
4. 存在 `jfqrz` → Tag `warning`,文案「收款确认中」
|
||||
5. 存在 `dfj` → Tag `info`,文案「待缴费」
|
||||
6. 其他 → Tag `info`,文案「—」
|
||||
|
||||
分期场景下 `statusHint` 附加明细计数,例如:「分期 · 2 期已缴 / 1 期待缴费」。
|
||||
|
||||
### 2.2 出库 · 基础实验(`feeSummary`)
|
||||
|
||||
数据来源:`biz_pilot_infusion_schedule.amount`(售卖金额)+ `biz_pilot_payment`(按 `infusion_schedule_id` 一对一)。
|
||||
|
||||
| 字段 | API 别名 | 说明 |
|
||||
|------|----------|------|
|
||||
| 售卖金额 | `saleAmount` | `schedule.amount` |
|
||||
| 应缴金额 | `paymentAmount` | `BizPilotPayment.amount` |
|
||||
| 实收金额 | `transferAmount` | 已确认收款时的 `transfer_amount`,否则 `null` |
|
||||
| 缴费状态 | `payStatus` | `dfj` / `jfqrz` / `yjf` / `tfqrz` / `ytf` |
|
||||
| 缴费状态标签 | `payStatusLabel` | 与临床应用缴费模块码表一致 |
|
||||
| 缴费状态 Tag 类型 | `payStatusTagType` | 复用 `payStatusTagType()` |
|
||||
|
||||
无缴费记录时:`paymentAmount`、`payStatus` 等为 `null`,摘要展示「暂无缴费记录」。
|
||||
|
||||
---
|
||||
|
||||
## 3. 后端设计
|
||||
|
||||
### 3.1 列表 API 扩展
|
||||
|
||||
**接口**:现有 `GET /web/admin/qc-work-orders`(`list_work_orders`)
|
||||
|
||||
在 `_enrich_list_items` 流程末尾批量 enrich,避免 N+1:
|
||||
|
||||
#### 入库 Tab(`workOrderType=inbound`)
|
||||
|
||||
1. 收集本页工单的有效 `collectionProtocolId`(且 `receptionSource === cell_storage`)
|
||||
2. 批量查询 payment 主表 + 明细
|
||||
3. 为每条工单写入 `paymentSummary`(非 cell_storage 时为 `null`)
|
||||
|
||||
#### 出库 Tab(`workOrderType=outbound`)
|
||||
|
||||
1. 收集本页 `bizType === basic_experiment` 的 `infusionScheduleId`
|
||||
2. 批量查询 `BizPilotPayment` + schedule.amount
|
||||
3. 写入 `feeSummary`(非 basic_experiment 时为 `null`)
|
||||
|
||||
**新增工具函数建议位置**:`backend/app/crud/qc_work_order.py` 或拆至 `backend/app/services/qc_work_order_fee_summary.py`
|
||||
|
||||
```python
|
||||
def build_protocol_payment_summaries(db, protocol_ids: List[str], tenant_no: str) -> Dict[str, dict]: ...
|
||||
def build_basic_experiment_fee_summaries(db, schedule_ids: List[str], tenant_no: str) -> Dict[str, dict]: ...
|
||||
```
|
||||
|
||||
### 3.2 详情 API(可选增强)
|
||||
|
||||
- **入库查看**:现有工单详情接口增加 `paymentSummary` + `paymentDetails`(明细列表,供弹窗展开;可限制最多返回当前协议全部明细,通常 ≤ 分期期数)
|
||||
- **出库查看**:`get_outbound_qc_detail` 增加 `feeSummary`;`OutboundQcViewDialog` 已有 schedule 区块,补充缴费只读段
|
||||
|
||||
本期 **最低交付**:列表摘要字段;详情弹窗至少与列表同级信息,推荐附带 1~3 条关键明细(分期时下一期应缴)。
|
||||
|
||||
### 3.3 数据库
|
||||
|
||||
**无需 DDL**。只读 join 现有表:
|
||||
|
||||
- `biz_protocol_payment` / `biz_protocol_payment_detail`
|
||||
- `biz_pilot_payment` / `biz_pilot_infusion_schedule`
|
||||
|
||||
### 3.4 性能
|
||||
|
||||
- 列表 enrich 按 **当前页 protocol_id / schedule_id 去重** 后批量查询
|
||||
- 单页默认 10~20 条,额外 1~2 次 batch query,可接受
|
||||
|
||||
---
|
||||
|
||||
## 4. 前端设计
|
||||
|
||||
### 4.1 入库 · 样本组费用摘要条
|
||||
|
||||
**文件**:`web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSampleGroup.vue`
|
||||
|
||||
**位置**:`.qc-sample-row__ctx` 下方、工单 Tab 上方,仅当组内任一工单 `receptionSource === 'cell_storage'` 且存在 `paymentSummary` 时渲染。
|
||||
|
||||
**布局**(单行 flex,窄屏换行):
|
||||
|
||||
```
|
||||
[协议费用] 趸交 · 合同 ¥28,000.00 · 已收 ¥28,000.00 · 待收 ¥0.00 · [已缴清]
|
||||
```
|
||||
|
||||
- 背景:`#ecfdf5`(`--primary-bg`),上边框与 ctx 区分
|
||||
- 字体:12px,标签 muted,金额 semibold
|
||||
- 右侧 Tag:`overallPayStatusLabel` + 语义色
|
||||
- 点击摘要条或「查看缴费」链接:打开入库工单查看弹窗并滚动至缴费区(可选,P1)
|
||||
|
||||
**组内多工单**:费用按 `collectionProtocolId` 去重,同协议只展示一份(组 context 已按样本聚合)。
|
||||
|
||||
### 4.2 出库 · 基础实验卡片摘要
|
||||
|
||||
**文件**:`web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue`
|
||||
|
||||
**条件**:`activeTypeTab === 'outbound' && row.bizType === 'basic_experiment' && row.feeSummary`
|
||||
|
||||
**位置**:`.qc-work-order-card__meta` 末尾或独立 `.qc-fee-summary` 行(全宽 `grid-column: 1 / -1`)
|
||||
|
||||
```
|
||||
[费用信息] 售卖 ¥12,000.00 · 应缴 ¥12,000.00 · [待缴费]
|
||||
```
|
||||
|
||||
已缴费时追加:`实收 ¥12,000.00`
|
||||
|
||||
### 4.3 查看弹窗
|
||||
|
||||
| 场景 | 文件 | 新增区块 |
|
||||
|------|------|----------|
|
||||
| 入库(cell_storage) | `index.vue` `viewSections` | 「协议缴费信息」:模式、合同、已收、待收、状态 Tag;分期时列 1 行下一期应缴(如有) |
|
||||
| 出库(basic_experiment) | `OutboundQcViewDialog.vue` | 「缴费信息」:售卖、应缴、实收、状态;可复用 `ClinicalPaymentSubmitReadonly` 精简字段 |
|
||||
|
||||
跳转链接(可选 P1):
|
||||
|
||||
- 入库 → `/#/cell-storage/protocol` 并打开对应协议查看弹窗(需协议 id)
|
||||
- 出库 → 基础实验申请单查看(`applicationId` 若列表已有)
|
||||
|
||||
### 4.4 筛选修正
|
||||
|
||||
**文件**:`index.vue` 出库 Tab 筛选「业务类型」
|
||||
|
||||
补全选项:
|
||||
|
||||
```html
|
||||
<el-option label="基础实验" value="basic_experiment" />
|
||||
```
|
||||
|
||||
与三种出库来源一致。
|
||||
|
||||
### 4.5 API 类型
|
||||
|
||||
**文件**:`web-admin/src/api/qc-work-order.ts`
|
||||
|
||||
```typescript
|
||||
export type QcProtocolPaymentSummary = {
|
||||
payMode?: string
|
||||
payModeLabel?: string
|
||||
contractAmount?: number | null
|
||||
receivedAmount?: number | null
|
||||
pendingAmount?: number | null
|
||||
statusHint?: string
|
||||
overallPayStatus?: string
|
||||
overallPayStatusLabel?: string
|
||||
}
|
||||
|
||||
export type QcBasicExperimentFeeSummary = {
|
||||
saleAmount?: number | null
|
||||
paymentAmount?: number | null
|
||||
transferAmount?: number | null
|
||||
payStatus?: string
|
||||
payStatusLabel?: string
|
||||
}
|
||||
|
||||
// QcWorkOrder 扩展
|
||||
paymentSummary?: QcProtocolPaymentSummary | null
|
||||
feeSummary?: QcBasicExperimentFeeSummary | null
|
||||
```
|
||||
|
||||
### 4.6 公共组件(可选)
|
||||
|
||||
若入库/出库摘要条样式一致,可抽 `QcWorkOrderFeeSummaryBar.vue`(props: `variant: 'inbound-protocol' | 'outbound-basic'` + summary object)。**非必须**,首版可在两处各写 scoped 块,YAGNI。
|
||||
|
||||
---
|
||||
|
||||
## 5. 交互与空态
|
||||
|
||||
| 情况 | 展示 |
|
||||
|------|------|
|
||||
| 科研捐赠入库工单 | 不渲染费用区块 |
|
||||
| 中试/临床出库工单 | 不渲染费用区块 |
|
||||
| 采集协议无 payment 主表 | 摘要:「暂无缴费信息」 |
|
||||
| 基础实验无 payment 记录 | 摘要:「暂无缴费记录」;仍展示售卖金额(若有) |
|
||||
| 金额为 null | 显示 `—` |
|
||||
|
||||
**只读**:摘要区无编辑、无确认收款按钮。
|
||||
|
||||
---
|
||||
|
||||
## 6. 测试要点
|
||||
|
||||
### 6.1 入库
|
||||
|
||||
- [ ] 细胞存储样本组显示协议费用摘要,数值与采集协议单查看弹窗一致
|
||||
- [ ] 科研捐赠样本组不显示费用摘要
|
||||
- [ ] 趸交已缴清 / 分期部分待缴 / 收款确认中 / 退费确认中 Tag 正确
|
||||
- [ ] 同页多条工单同协议,摘要去重一致
|
||||
|
||||
### 6.2 出库
|
||||
|
||||
- [ ] 基础实验卡片显示售卖 + 缴费状态
|
||||
- [ ] 中试服务、临床应用卡片无费用摘要
|
||||
- [ ] 筛选「基础实验」可正确过滤
|
||||
- [ ] 查看弹窗缴费区与列表摘要一致
|
||||
|
||||
### 6.3 回归
|
||||
|
||||
- [ ] 第三方检测费用展示不受影响
|
||||
- [ ] 临时质检 Tab 无费用区块
|
||||
- [ ] 列表分页、分组、Tab 切换正常
|
||||
|
||||
---
|
||||
|
||||
## 7. 影响文件清单
|
||||
|
||||
| 层级 | 文件 |
|
||||
|------|------|
|
||||
| 后端 | `backend/app/crud/qc_work_order.py`(+ 可选 `services/qc_work_order_fee_summary.py`) |
|
||||
| 后端 Schema | `backend/app/schemas/qc_work_order.py`(若响应体走 Pydantic) |
|
||||
| 前端 API | `web-admin/src/api/qc-work-order.ts` |
|
||||
| 前端页面 | `QcWorkOrderSampleGroup.vue`、`QcWorkOrderSingleCard.vue`、`index.vue`、`OutboundQcViewDialog.vue` |
|
||||
| 工具 | 复用 `formatMoneyDisplay`、`payModeLabel`、`payStatusLabel`、`payStatusTagType` |
|
||||
|
||||
---
|
||||
|
||||
## 8. 后续扩展(本期不做)
|
||||
|
||||
- 临床应用出库工单费用摘要(`feeSummary` 结构可复用 `BizPilotPayment`)
|
||||
- 摘要条点击跳转来源单据
|
||||
- 与「分期缴费用户预警」模块联动高亮欠费
|
||||
|
||||
---
|
||||
|
||||
## 9. 决策记录
|
||||
|
||||
| 日期 | 决策 |
|
||||
|------|------|
|
||||
| 2026-06-12 | 「费用变化」= **当前快照**,不做历史轨迹 |
|
||||
| 2026-06-12 | 入库仅 **采集协议单**;出库仅 **基础实验** |
|
||||
| 2026-06-12 | 列表摘要 + 查看弹窗详情,推荐实现路径 |
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,11 +1,11 @@
|
||||
# Graph Report - src (2026-06-12)
|
||||
|
||||
## Corpus Check
|
||||
- Large corpus: 697 files · ~440,830 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
|
||||
- Large corpus: 704 files · ~444,651 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
|
||||
|
||||
## Summary
|
||||
- 2079 nodes · 2717 edges · 51 communities detected
|
||||
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 610 edges (avg confidence: 0.8)
|
||||
- 2103 nodes · 2742 edges · 53 communities detected
|
||||
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 615 edges (avg confidence: 0.8)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
@@ -40,32 +40,34 @@
|
||||
- [[_COMMUNITY_Community 28|Community 28]]
|
||||
- [[_COMMUNITY_Community 29|Community 29]]
|
||||
- [[_COMMUNITY_Community 30|Community 30]]
|
||||
- [[_COMMUNITY_Community 32|Community 32]]
|
||||
- [[_COMMUNITY_Community 31|Community 31]]
|
||||
- [[_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 48|Community 48]]
|
||||
- [[_COMMUNITY_Community 49|Community 49]]
|
||||
- [[_COMMUNITY_Community 50|Community 50]]
|
||||
- [[_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 58|Community 58]]
|
||||
- [[_COMMUNITY_Community 60|Community 60]]
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `get()` - 219 edges
|
||||
2. `push()` - 43 edges
|
||||
1. `get()` - 221 edges
|
||||
2. `push()` - 44 edges
|
||||
3. `WebSocketClient` - 26 edges
|
||||
4. `emit()` - 16 edges
|
||||
4. `emit()` - 17 edges
|
||||
5. `MenuProcessor` - 16 edges
|
||||
6. `VersionManager` - 15 edges
|
||||
7. `handleDynamicRoutes()` - 15 edges
|
||||
@@ -74,220 +76,228 @@
|
||||
10. `withFullscreenLoading()` - 13 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `handleReceptionAttachmentDownload()` --calls--> `downloadAttachmentFile()` [INFERRED]
|
||||
views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue → utils/download-attachment.ts
|
||||
- `handleDownloadAttachment()` --calls--> `downloadAttachmentFile()` [INFERRED]
|
||||
views/pilot-service/infusion-schedule-management/InfusionScheduleHandoverDialog.vue → utils/download-attachment.ts
|
||||
- `subscribeTokenRefresh()` --calls--> `push()` [INFERRED]
|
||||
utils/http/index.ts → views/operations/storage-facility/index.vue
|
||||
- `fetchLeaveList()` --calls--> `get()` [INFERRED]
|
||||
api/leave.ts → views/production/process/ProcessRouteTab.vue
|
||||
- `fetchLeaveDetail()` --calls--> `get()` [INFERRED]
|
||||
api/leave.ts → views/production/process/ProcessRouteTab.vue
|
||||
- `fetchConsumableList()` --calls--> `get()` [INFERRED]
|
||||
api/production.ts → views/production/process/ProcessRouteTab.vue
|
||||
- `fetchReagentList()` --calls--> `get()` [INFERRED]
|
||||
api/production.ts → views/production/process/ProcessRouteTab.vue
|
||||
- `fetchAllReagents()` --calls--> `get()` [INFERRED]
|
||||
api/production.ts → views/production/process/ProcessRouteTab.vue
|
||||
|
||||
## Communities
|
||||
|
||||
### Community 0 - "Community 0"
|
||||
Cohesion: 0.01
|
||||
Nodes (115): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchCellSampleTypeList() (+107 more)
|
||||
Nodes (114): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchCellSampleTypeList() (+106 more)
|
||||
|
||||
### Community 1 - "Community 1"
|
||||
Cohesion: 0.03
|
||||
Nodes (80): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionList(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchCheckupInstitutionProjects(), fetchPilotCheckupActualItems(), fetchPilotCheckupDetail() (+72 more)
|
||||
Nodes (82): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionList(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchCheckupInstitutionProjects(), fetchPilotCheckupActualItems(), fetchPilotCheckupDetail() (+74 more)
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.03
|
||||
Nodes (35): fetchGetMenuList(), fetchGetMenuCodes(), clickTab(), handleTouchEnd(), setTransition(), IframeRouteManager, MenuProcessor, RoutePermissionValidator (+27 more)
|
||||
Nodes (36): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllConsumableStockLogs(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents(), fetchAllReagentStockLogs() (+28 more)
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.03
|
||||
Nodes (36): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllConsumableStockLogs(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents(), fetchAllReagentStockLogs() (+28 more)
|
||||
Nodes (34): fetchAttachmentDownloadUrl(), handleReset(), handleSearch(), syncAppliedFilters(), fullFileUrl(), handleDownloadAttachment(), handlePreviewAttachment(), isVideoFile() (+26 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.04
|
||||
Nodes (56): fetchUploadAttachment(), FireworkSystem, reload(), handleReportUpload(), formatNowDatetime(), handleReportUpload(), formatHandoverUserLabel(), formatNowDatetime() (+48 more)
|
||||
Nodes (30): clickTab(), handleTouchEnd(), setTransition(), IframeRouteManager, RoutePermissionValidator, RouteRegistry, useCommon(), setupAfterEachGuard() (+22 more)
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.03
|
||||
Nodes (34): fetchAttachmentDownloadUrl(), fullFileUrl(), handleDownloadAttachment(), handlePreviewAttachment(), isVideoFile(), formatTempEmptyField(), handleReceptionAttachmentDownload(), shouldShowTempEmptyField() (+26 more)
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.04
|
||||
Nodes (25): fetchOutboundReleaseMaterial(), fetchOutboundReleaseReviewDetail(), fetchOutboundReleaseReviewList(), fetchReleaseReviewList(), submitOutboundReleaseReview(), fetchStorageReleaseReviewDetail(), fetchStorageReleaseReviewList(), submitStorageReleaseReview() (+17 more)
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.05
|
||||
Nodes (33): handleBlur(), handleFocus(), handleInput(), formatAmount(), formatAmount(), fmtMoney(), auditorDisplay(), dash() (+25 more)
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.06
|
||||
Nodes (48): fetchUploadAttachment(), reload(), handleReportUpload(), formatNowDatetime(), handleReportUpload(), pad(), handleMenuJump(), openExternalLink() (+40 more)
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.06
|
||||
Nodes (11): fetchGetLatestUpgradeLog(), getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, getSystemStorage(), getSysVersion(), StorageKeyManager, StorageCompatibilityManager (+3 more)
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.06
|
||||
Nodes (33): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), updateInfusionScheduleStatus(), fetchCreateProductionWorkOrder(), fetchProductionWorkOrderDetail(), fetchProductionWorkOrderList() (+25 more)
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.06
|
||||
Nodes (39): fetchCreateSite(), fetchCreateUser(), fetchDeleteSite(), fetchDeleteUser(), fetchResetPassword(), fetchSiteList(), fetchUpdateSite(), fetchUpdateUser() (+31 more)
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.05
|
||||
Nodes (25): fetchClinicalPaymentDetail(), fetchClinicalPayments(), fetchClinicalReceiptConfirmed(), fetchClinicalReceiptPending(), fetchClinicalRefundConfirmed(), fetchClinicalRefundPending(), fetchOrderAdjusts(), fetchOrderDetail() (+17 more)
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.06
|
||||
Nodes (28): fetchFullmoonTodoList(), fetchUpdateFullmoonTodoInsurance(), fetchCollectionProtocolAuditList(), fetchCollectionProtocolDetail(), fetchCollectionProtocolList(), fetchPaymentDetailList(), fetchReceiptConfirmedList(), fetchReceiptConfirmList() (+20 more)
|
||||
Nodes (24): fetchGetMenuList(), fetchGetMenuCodes(), fetchGetUserInfo(), fetchLogin(), fetchUpdateProfile(), fetchUploadProfileAvatar(), MenuProcessor, useAppMode() (+16 more)
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.06
|
||||
Nodes (31): handleBlur(), handleFocus(), handleInput(), fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateMenu(), formatAmount() (+23 more)
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.06
|
||||
Nodes (29): fetchFullmoonTodoList(), fetchUpdateFullmoonTodoInsurance(), fetchCollectionProtocolAuditList(), fetchCollectionProtocolDetail(), fetchCollectionProtocolList(), fetchPaymentDetailList(), fetchReceiptConfirmedList(), fetchReceiptConfirmList() (+21 more)
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.07
|
||||
Nodes (21): auditorDisplay(), dash(), expressName(), formatYm(), formatYmd(), sampleTypeName(), siteName(), unitName() (+13 more)
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.1
|
||||
Nodes (2): WebSocketClient, TableCache
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.05
|
||||
Nodes (13): fetchCreateProductionWorkOrder(), fetchProductionWorkOrderCellProductOptions(), fetchProductionWorkOrderDetail(), fetchProductionWorkOrderList(), formatTempEmptyField(), shouldShowTempEmptyField(), submitAdd(), canDeleteWorkOrder() (+5 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.08
|
||||
Nodes (33): fetchRefreshToken(), toLogin(), base64ToBytes(), bytesToBase64(), decryptJson(), deriveKey(), encryptJson(), fromBase64Url() (+25 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.07
|
||||
Nodes (22): for(), set(), walk(), annotateForkEdges(), chainApiToElements(), walkAncestorBranch(), walkAncestorParents(), if() (+14 more)
|
||||
|
||||
### Community 16 - "Community 16"
|
||||
Cohesion: 0.07
|
||||
Nodes (13): maskIdCard(), buildBasicExperimentApplicationFields(), buildDefaultApplicationFields(), buildOutboundPilotContextSections(), applicationStatusLabel(), applicationStatusTagType(), infusionMethodLabel(), infusionStatusLabel() (+5 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (29): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), updateInfusionScheduleStatus(), handleAdd(), handleDelete(), handleDropdownCommand() (+21 more)
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
Cohesion: 0.07
|
||||
Nodes (15): fetchEthnicList(), applyDonationBundleToForm(), createEmptyTransport(), ensureEthnicOptionInList(), handleOpenForAdd(), loadEthnicOptions(), normalizeSampleRow(), resetForm() (+7 more)
|
||||
Nodes (26): fetchCreateSite(), fetchDeleteSite(), fetchSiteList(), fetchUpdateSite(), fetchUserList(), formatHandoverUserLabel(), formatNowDatetime(), fullFileUrl() (+18 more)
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
Cohesion: 0.08
|
||||
Nodes (20): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateMenu(), collectIds(), postorder(), preorder(), applyTreeExpand() (+12 more)
|
||||
Cohesion: 0.07
|
||||
Nodes (20): for(), set(), walk(), annotateForkEdges(), chainApiToElements(), walkAncestorBranch(), walkAncestorParents(), if() (+12 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.11
|
||||
Nodes (25): completePilotApplication(), deletePilotApplication(), fetchPilotApplicationList(), startPilotApplication(), voidPilotApplication(), clearTableSelection(), handleBatchComplete(), handleBatchStart() (+17 more)
|
||||
Cohesion: 0.07
|
||||
Nodes (13): maskIdCard(), buildBasicExperimentApplicationFields(), buildDefaultApplicationFields(), buildOutboundPilotContextSections(), applicationStatusLabel(), applicationStatusTagType(), infusionMethodLabel(), infusionStatusLabel() (+5 more)
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
Cohesion: 0.12
|
||||
Nodes (19): fetchGetUserInfo(), fetchLogin(), fetchUpdateProfile(), fetchUploadProfileAvatar(), fetchUserInfo(), buildWebEncryptedLoginBody(), defaultAvatarPathByRole(), hasCustomUserAvatar() (+11 more)
|
||||
Cohesion: 0.09
|
||||
Nodes (27): completePilotApplication(), deletePilotApplication(), fetchPilotApplicationList(), startPilotApplication(), voidPilotApplication(), handleBatchComplete(), handleBatchStart(), handleBatchVoid() (+19 more)
|
||||
|
||||
### Community 21 - "Community 21"
|
||||
Cohesion: 0.07
|
||||
Nodes (15): fetchEthnicList(), applyDonationBundleToForm(), createEmptyTransport(), ensureEthnicOptionInList(), handleOpenForAdd(), loadEthnicOptions(), normalizeSampleRow(), resetForm() (+7 more)
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
Cohesion: 0.12
|
||||
Nodes (20): fetchCreateUser(), fetchDeleteUser(), fetchResetPassword(), fetchUpdateUser(), fetchUserDetail(), formatUserDeptDisplay(), handleAdd(), handleBatchDelete() (+12 more)
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.12
|
||||
Nodes (15): addCopyButton(), highlightCode(), insertLineNumbers(), isBlockProcessed(), markBlockAsProcessed(), processBlock(), setupHighlightDirective(), setupRippleDirective() (+7 more)
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.1
|
||||
Nodes (6): fetchProductionTaskDetail(), fetchProductionTaskList(), fetchUpdateProductionTask(), handleClose(), handleSubmit(), loadTaskDetail()
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.11
|
||||
Nodes (8): handleReset(), handleSearch(), syncAppliedFilters(), addMaterialRow(), handleReceptionAttachmentDownload(), nextMaterialRowKey(), onRequisitionSelect(), removeMaterialRow()
|
||||
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.12
|
||||
Nodes (12): fetchApproveTask(), fetchBusinessAllTasks(), fetchCompletedTasks(), fetchDesignerData(), fetchInstanceDetail(), fetchMyInstances(), fetchPendingTasks(), fetchProcessDefList() (+4 more)
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
Cohesion: 0.16
|
||||
Nodes (14): fetchCreateEnvDetectItem(), fetchDeleteEnvDetectItem(), fetchEnvDetectItemDetail(), fetchEnvDetectItemList(), fetchEnvDetectItemsActive(), fetchUpdateEnvDetectItem(), handleAdd(), handleBatchDelete() (+6 more)
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.16
|
||||
Nodes (10): useTable(), useTableImpl(), getColumnChecks(), useTableColumns(), createErrorHandler(), createSmartDebounce(), defaultResponseAdapter(), extractPagination() (+2 more)
|
||||
Cohesion: 0.12
|
||||
Nodes (12): fetchApproveTask(), fetchBusinessAllTasks(), fetchCompletedTasks(), fetchDesignerData(), fetchInstanceDetail(), fetchMyInstances(), fetchPendingTasks(), fetchProcessDefList() (+4 more)
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
Cohesion: 0.2
|
||||
Nodes (2): ComponentLoader, RouteTransformer
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.16
|
||||
Nodes (10): useTable(), useTableImpl(), getColumnChecks(), useTableColumns(), createErrorHandler(), createSmartDebounce(), defaultResponseAdapter(), extractPagination() (+2 more)
|
||||
|
||||
### Community 29 - "Community 29"
|
||||
Cohesion: 0.27
|
||||
Nodes (14): useChart(), useChartComponent(), useChartOps(), colourBlend(), getCssVar(), getDarkColor(), getLightColor(), handleElementThemeColor() (+6 more)
|
||||
|
||||
### Community 29 - "Community 29"
|
||||
### Community 30 - "Community 30"
|
||||
Cohesion: 0.14
|
||||
Nodes (8): useSettingsHandlers(), useSettingsPanel(), useSettingsState(), useCeremony(), useTheme(), themeAnimation(), toggleTheme(), toggleTransition()
|
||||
|
||||
### Community 30 - "Community 30"
|
||||
### Community 31 - "Community 31"
|
||||
Cohesion: 0.18
|
||||
Nodes (5): fetchServiceOrderTxnList(), handleReset(), handleSearch(), handleTabChange(), loadData()
|
||||
|
||||
### Community 32 - "Community 32"
|
||||
### Community 33 - "Community 33"
|
||||
Cohesion: 0.15
|
||||
Nodes (4): fetchQcMaterialBatchList(), fetchQcMaterialBatchOptions(), fetchQcMaterialList(), fetchQcMaterialOptions()
|
||||
|
||||
### Community 33 - "Community 33"
|
||||
### Community 34 - "Community 34"
|
||||
Cohesion: 0.17
|
||||
Nodes (3): fetchResearchDonationAuditList(), fetchResearchDonationDetail(), fetchResearchDonationList()
|
||||
|
||||
### Community 34 - "Community 34"
|
||||
### Community 35 - "Community 35"
|
||||
Cohesion: 0.18
|
||||
Nodes (3): fetchMaterialList(), fetchMaterialOptions(), fetchMaterialStockLogList()
|
||||
|
||||
### Community 36 - "Community 36"
|
||||
Cohesion: 0.28
|
||||
Nodes (1): FireworkSystem
|
||||
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.22
|
||||
Nodes (3): fetchMyQcTaskList(), fetchQcTaskDetail(), fetchQcTaskList()
|
||||
|
||||
### Community 37 - "Community 37"
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 0.39
|
||||
Nodes (6): isIgnorableScriptError(), normalizeErrorMessage(), registerPromiseErrorHandler(), registerResourceErrorHandler(), scriptErrorHandler(), setupErrorHandle()
|
||||
|
||||
### Community 38 - "Community 38"
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 0.36
|
||||
Nodes (1): TableHeightCalculator
|
||||
|
||||
### Community 39 - "Community 39"
|
||||
### Community 41 - "Community 41"
|
||||
Cohesion: 0.25
|
||||
Nodes (3): fetchOutboundQcDetail(), fetchQcWorkOrderDetail(), fetchQcWorkOrderList()
|
||||
|
||||
### Community 42 - "Community 42"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): logApiCryptoBootInfo(), maskSecret()
|
||||
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 0.29
|
||||
Nodes (2): fetchLeaveDetail(), fetchLeaveList()
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
### Community 43 - "Community 43"
|
||||
Cohesion: 0.29
|
||||
Nodes (2): fetchQcMaterialStockCheckDetail(), fetchQcMaterialStockCheckList()
|
||||
|
||||
### Community 42 - "Community 42"
|
||||
### Community 44 - "Community 44"
|
||||
Cohesion: 0.47
|
||||
Nodes (3): isPaymentDueWithinWarnWindow(), parsePaymentDueYmd(), startOfLocalDay()
|
||||
|
||||
### Community 44 - "Community 44"
|
||||
### Community 46 - "Community 46"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchSampleReceptionCheckItemList(), fetchSampleReceptionCheckItemsActive()
|
||||
|
||||
### Community 45 - "Community 45"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcThirdPartyCompanyList(), fetchQcThirdPartyCompanyOptions()
|
||||
Nodes (2): fetchQcThirdPartyItemList(), fetchQcThirdPartyItemsActive()
|
||||
|
||||
### Community 47 - "Community 47"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcLabTestItemList(), fetchQcLabTestItemsActive()
|
||||
|
||||
### Community 49 - "Community 49"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): formatProtocolDocDeleteConfirm(), formatProtocolDocSubject()
|
||||
|
||||
### Community 48 - "Community 48"
|
||||
### Community 50 - "Community 50"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): focusInput(), handleKeydown()
|
||||
|
||||
### Community 50 - "Community 50"
|
||||
### Community 52 - "Community 52"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): if(), logSidebarMenu()
|
||||
|
||||
### Community 52 - "Community 52"
|
||||
### Community 54 - "Community 54"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): fetchStorageEntrySmsList()
|
||||
|
||||
### Community 53 - "Community 53"
|
||||
### Community 55 - "Community 55"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): fetchSampleSmsNotificationList()
|
||||
|
||||
### Community 54 - "Community 54"
|
||||
### Community 56 - "Community 56"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): fetchQcSmsList()
|
||||
|
||||
### Community 56 - "Community 56"
|
||||
### Community 58 - "Community 58"
|
||||
Cohesion: 1.0
|
||||
Nodes (2): getSettingDefaults(), resetToDefaults()
|
||||
|
||||
### Community 58 - "Community 58"
|
||||
### Community 60 - "Community 60"
|
||||
Cohesion: 1.0
|
||||
Nodes (2): copyTextToClipboard(), copyTextWithFallback()
|
||||
|
||||
@@ -296,49 +306,49 @@ Nodes (2): copyTextToClipboard(), copyTextWithFallback()
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 27`** (17 nodes): `ComponentLoader`, `.constructor()`, `.createEmptyComponent()`, `.createErrorComponent()`, `.load()`, `.loadIframe()`, `.loadLayout()`, `.load()`, `RouteTransformer`, `.extractFirstSegment()`, `.handleFirstLevelRoute()`, `.handleIframeRoute()`, `.handleNormalRoute()`, `.isFirstLevelRoute()`, `.transform()`, `ComponentLoader.ts`, `RouteTransformer.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 38`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
|
||||
- **Thin community `Community 36`** (9 nodes): `FireworkSystem`, `.constructor()`, `.createFirework()`, `.createParticle()`, `.getAvailableParticle()`, `.initializePool()`, `.preloadAllImages()`, `.preloadImage()`, `index.vue`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 39`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
|
||||
- **Thin community `Community 40`** (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 40`** (7 nodes): `fetchCreateLeave()`, `fetchDeleteLeave()`, `fetchLeaveDetail()`, `fetchLeaveList()`, `fetchSubmitLeave()`, `fetchUpdateLeave()`, `leave.ts`
|
||||
- **Thin community `Community 42`** (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 41`** (7 nodes): `fetchCancelQcMaterialStockCheck()`, `fetchCompleteQcMaterialStockCheck()`, `fetchCreateQcMaterialStockCheck()`, `fetchQcMaterialStockCheckDetail()`, `fetchQcMaterialStockCheckList()`, `fetchSaveQcMaterialStockCheckUnusedLines()`, `qc-material-stock-check.ts`
|
||||
- **Thin community `Community 43`** (7 nodes): `fetchCancelQcMaterialStockCheck()`, `fetchCompleteQcMaterialStockCheck()`, `fetchCreateQcMaterialStockCheck()`, `fetchQcMaterialStockCheckDetail()`, `fetchQcMaterialStockCheckList()`, `fetchSaveQcMaterialStockCheckUnusedLines()`, `qc-material-stock-check.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 44`** (6 nodes): `fetchCreateSampleReceptionCheckItem()`, `fetchDeleteSampleReceptionCheckItem()`, `fetchSampleReceptionCheckItemList()`, `fetchSampleReceptionCheckItemsActive()`, `fetchUpdateSampleReceptionCheckItem()`, `sample-reception-check-item.ts`
|
||||
- **Thin community `Community 46`** (6 nodes): `fetchCreateQcThirdPartyItem()`, `fetchDeleteQcThirdPartyItem()`, `fetchQcThirdPartyItemList()`, `fetchQcThirdPartyItemsActive()`, `fetchUpdateQcThirdPartyItem()`, `qc-third-party-item.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 45`** (6 nodes): `fetchCreateQcThirdPartyCompany()`, `fetchDeleteQcThirdPartyCompany()`, `fetchQcThirdPartyCompanyList()`, `fetchQcThirdPartyCompanyOptions()`, `fetchUpdateQcThirdPartyCompany()`, `qc-third-party-company.ts`
|
||||
- **Thin community `Community 47`** (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 47`** (5 nodes): `formatProtocolDocBatchDeleteConfirm()`, `formatProtocolDocDeleteConfirm()`, `formatProtocolDocSubject()`, `getProtocolDocTypeLabel()`, `protocol-doc-label.ts`
|
||||
- **Thin community `Community 49`** (5 nodes): `formatProtocolDocBatchDeleteConfirm()`, `formatProtocolDocDeleteConfirm()`, `formatProtocolDocSubject()`, `getProtocolDocTypeLabel()`, `protocol-doc-label.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 48`** (5 nodes): `focusInput()`, `handleKeydown()`, `if()`, `search()`, `index.vue`
|
||||
- **Thin community `Community 50`** (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 50`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
|
||||
- **Thin community `Community 52`** (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 52`** (4 nodes): `fetchGenerateStorageEntrySms()`, `fetchStorageEntrySmsList()`, `fetchToggleStorageEntrySmsNotified()`, `storage-entry-sms-notification.ts`
|
||||
- **Thin community `Community 54`** (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 53`** (4 nodes): `fetchGenerateSms()`, `fetchSampleSmsNotificationList()`, `fetchToggleSmsNotified()`, `sample-sms-notification.ts`
|
||||
- **Thin community `Community 55`** (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 54`** (4 nodes): `fetchGenerateQcSms()`, `fetchQcSmsList()`, `fetchToggleQcSmsNotified()`, `qc-sms-notification.ts`
|
||||
- **Thin community `Community 56`** (4 nodes): `fetchGenerateQcSms()`, `fetchQcSmsList()`, `fetchToggleQcSmsNotified()`, `qc-sms-notification.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 56`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
|
||||
- **Thin community `Community 58`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 58`** (3 nodes): `copyTextToClipboard()`, `copyTextWithFallback()`, `copy-text.ts`
|
||||
- **Thin community `Community 60`** (3 nodes): `copyTextToClipboard()`, `copyTextWithFallback()`, `copy-text.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 6`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 15`, `Community 17`, `Community 18`, `Community 19`, `Community 20`, `Community 22`, `Community 24`, `Community 25`, `Community 30`, `Community 32`, `Community 33`, `Community 34`, `Community 36`, `Community 40`, `Community 41`, `Community 44`, `Community 45`, `Community 52`, `Community 53`, `Community 54`?**
|
||||
_High betweenness centrality (0.255) - this node is a cross-community bridge._
|
||||
- **Why does `push()` connect `Community 4` to `Community 0`, `Community 1`, `Community 3`, `Community 5`, `Community 8`, `Community 10`, `Community 12`, `Community 13`, `Community 14`, `Community 15`, `Community 16`, `Community 17`, `Community 23`?**
|
||||
_High betweenness centrality (0.190) - this node is a cross-community bridge._
|
||||
- **Why does `fetchNotDeletedRegions()` connect `Community 0` to `Community 4`?**
|
||||
_High betweenness centrality (0.059) - this node is a cross-community bridge._
|
||||
- **Are the 218 inferred relationships involving `get()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `buildTreePathLabelFromFlat()`) actually correct?**
|
||||
_`get()` has 218 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 42 inferred relationships involving `push()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `fetchAllPagedRecords()`) actually correct?**
|
||||
_`push()` has 42 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 15 inferred relationships involving `emit()` (e.g. with `handleSubmit()` and `handleBlur()`) actually correct?**
|
||||
_`emit()` has 15 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 14`, `Community 16`, `Community 17`, `Community 18`, `Community 20`, `Community 21`, `Community 22`, `Community 24`, `Community 25`, `Community 26`, `Community 31`, `Community 33`, `Community 34`, `Community 35`, `Community 38`, `Community 41`, `Community 43`, `Community 46`, `Community 47`, `Community 54`, `Community 55`, `Community 56`?**
|
||||
_High betweenness centrality (0.305) - this node is a cross-community bridge._
|
||||
- **Why does `push()` connect `Community 6` to `Community 0`, `Community 1`, `Community 2`, `Community 3`, `Community 36`, `Community 7`, `Community 11`, `Community 13`, `Community 15`, `Community 17`, `Community 18`, `Community 19`, `Community 20`, `Community 21`?**
|
||||
_High betweenness centrality (0.163) - this node is a cross-community bridge._
|
||||
- **Why does `buildOutboundPilotContextSections()` connect `Community 19` to `Community 6`?**
|
||||
_High betweenness centrality (0.043) - this node is a cross-community bridge._
|
||||
- **Are the 220 inferred relationships involving `get()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `groupInboundQcWorkOrders()`) actually correct?**
|
||||
_`get()` has 220 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 43 inferred relationships involving `push()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `fetchAllPagedRecords()`) actually correct?**
|
||||
_`push()` has 43 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 16 inferred relationships involving `emit()` (e.g. with `handleSubmit()` and `handleBlur()`) actually correct?**
|
||||
_`emit()` has 16 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Should `Community 0` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.01 - nodes in this community are weakly interconnected._
|
||||
@@ -57,12 +57,12 @@
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">2079 nodes · 2717 edges · 309 communities</div>
|
||||
<div id="stats">2103 nodes · 2742 edges · 313 communities</div>
|
||||
</div>
|
||||
<script>
|
||||
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 39, "community_name": "Community 39", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 39, "community_name": "Community 39", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 39, "community_name": "Community 39", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 39, "community_name": "Community 39", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 39, "community_name": "Community 39", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 39, "community_name": "Community 39", "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": 88, "community_name": "Community 88", "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": 89, "community_name": "Community 89", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 21, "community_name": "Community 21", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 21, "community_name": "Community 21", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 21, "community_name": "Community 21", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 21, "community_name": "Community 21", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 21, "community_name": "Community 21", "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": 342}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 109}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 96}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 81}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 80}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 74}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 63}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 59}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 55}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 49}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 48}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 48}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 45}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 42}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 41}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 37}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 36}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 34}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 34}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 30}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 27}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 22}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 22}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 22}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 19}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 19}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 17}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 17}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 16}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 15}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 14}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 13}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 13}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 12}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 11}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 9}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 9}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 8}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 8}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 7}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 7}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 7}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 6}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 6}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 6}, {"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": 5}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 5}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 5}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 4}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 4}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 4}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 4}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 4}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 4}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 3}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 3}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 3}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 3}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 3}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 3}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 3}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 3}, {"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": Line truncated
|
||||
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 42, "community_name": "Community 42", "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": 42, "community_name": "Community 42", "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": 42, "community_name": "Community 42", "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.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 42, "community_name": "Community 42", "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.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 42, "community_name": "Community 42", "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.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 42, "community_name": "Community 42", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 90, "community_name": "Community 90", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#F28E2B", "border": "#F28E2B", "highlight": {"background": "#ffffff", "border": "#F28E2B"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 91, "community_name": "Community 91", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 23, "community_name": "Community 23", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 23, "community_name": "Community 23", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 23, "community_name": "Community 23", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 23, "community_name": "Community 23", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 23, "community_name": "Community 23", "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": 341}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 110}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 81}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 79}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 76}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 64}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 60}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 55}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 48}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 48}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 46}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 46}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 42}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 42}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 42}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 41}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 40}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 38}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 37}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 36}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 34}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 34}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 24}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 22}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 22}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 19}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 19}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 17}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 17}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 16}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 15}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 14}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 13}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 13}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 12}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 11}, {"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": 8}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 8}, {"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": 7}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 6}, {"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": 6}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 6}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 5}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 5}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 5}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 4}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 4}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 4}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 4}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 4}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 4}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 3}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 3}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 3}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 3}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 3}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 3}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 3}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 3}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 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":Line truncated
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
|
||||
+2161
-1678
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": 1781235935.3278806,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1781235905.915799,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1781246166.8389935,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1781246095.71424,
|
||||
"/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": 1780480414.9574106,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/locales/index.ts": 1778582068.004279,
|
||||
@@ -50,6 +50,7 @@
|
||||
"/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": 1779790341.2952042,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/outbound-qc-pilot-view-sections.ts": 1781080334.6168308,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts": 1781245724.945728,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/copy-text.ts": 1781077714.2912376,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/tree-path.ts": 1779790341.776808,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/mask-sensitive.ts": 1778984825.4182227,
|
||||
@@ -220,7 +221,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/env-detect-record.ts": 1781145722.88074,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/storage-release-review.ts": 1780478965.1159081,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/workflow.ts": 1779790323.5709383,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts": 1779924334.417812,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts": 1781245385.307889,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task-result.ts": 1781232714.5618048,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/protocol-sample-collection.ts": 1780457181.854043,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-third-party-company.ts": 1779021425.3773527,
|
||||
@@ -247,7 +248,7 @@
|
||||
"/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": 1780462889.9246686,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/auth.ts": 1780539439.6854532,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts": 1781232710.8590982,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts": 1781248276.4110606,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/auth/login/index.vue": 1780480414.9591243,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/refund-confirm/index.vue": 1779866933.9349332,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/index.vue": 1781063349.3629117,
|
||||
@@ -328,17 +329,19 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/sop/index.vue": 1779882001.8321233,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-task/index.vue": 1779925496.7869844,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/reagent/index.vue": 1779863928.5798419,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue": 1781080334.6168587,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue": 1781245471.5188477,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts": 1780459274.6793678,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue": 1780306770.0831616,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/CompleteProductionTaskDialog.vue": 1779790359.5464847,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskInputEnhancedTable.vue": 1780459293.3141825,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue": 1781245347.4836073,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue": 1780459276.445585,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue": 1779925648.9018784,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputList.vue": 1779967896.0077794,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue": 1781063324.0294309,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue": 1779967394.775425,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue": 1781245403.0507572,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputProductDialog.vue": 1779925660.055737,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue": 1781245472.0641115,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/consumable-pack/index.vue": 1779863746.111673,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/consumable/index.vue": 1779863845.5777776,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/consumable/ConsumablePackTab.vue": 1779863731.2002044,
|
||||
@@ -348,10 +351,14 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-category/index.vue": 1779864070.4019275,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-category/OutputTypeTab.vue": 1779864078.964701,
|
||||
"/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": 1781235485.724401,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue": 1781236360.3712525,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue": 1781195540.3765936,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue": 1781236324.7682652,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue": 1781248364.9092808,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue": 1781248310.590171,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderFeeSummaryBar.vue": 1781247653.7613583,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSampleGroup.vue": 1781248062.534885,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue": 1781245816.5224924,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue": 1781247706.6829572,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue": 1781245766.0003755,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue": 1781248366.9077792,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception-check-item/index.vue": 1779857055.2939715,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/lab-test-item/index.vue": 1779864504.1085482,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/lab-test-item/ThirdPartyCompanyTab.vue": 1779864511.579237,
|
||||
|
||||
@@ -22,8 +22,14 @@ export interface ProductionWorkOrderItem {
|
||||
workOrderStatus: string
|
||||
createTime?: string
|
||||
remark?: string
|
||||
labStorageCode?: string
|
||||
protocolStatus?: string
|
||||
bizType?: string
|
||||
bizTypeLabel?: string
|
||||
/** 出库工单:关联申请单号 */
|
||||
applicationNo?: string
|
||||
applicationName?: string
|
||||
channelName?: string
|
||||
/** 出库工单:患者/用户姓名 */
|
||||
patientName?: string
|
||||
/** 出库工单:当前为第几次输注计划 */
|
||||
@@ -127,3 +133,31 @@ export function fetchUpdateProductionWorkOrder(id: string, data: { remark?: stri
|
||||
export function fetchDeleteProductionWorkOrder(id: string) {
|
||||
return request.del({ url: `/web/admin/production-work-orders/${id}` })
|
||||
}
|
||||
|
||||
export interface ProductionCellProductOption {
|
||||
id: string
|
||||
cellProductId?: string
|
||||
productCode?: string
|
||||
productName?: string
|
||||
productTypeName?: string
|
||||
passage?: string
|
||||
storageSlotName?: string
|
||||
taskId?: string
|
||||
taskNo?: string
|
||||
}
|
||||
|
||||
export function fetchProductionWorkOrderCellProductOptions(workOrderId: string) {
|
||||
return request.get<ProductionCellProductOption[]>({
|
||||
url: `/web/admin/production-work-orders/${workOrderId}/cell-product-options`
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchCreateQcFromProduction(
|
||||
workOrderId: string,
|
||||
data: { cellProductId: string; productionTaskId?: string; remark?: string }
|
||||
) {
|
||||
return request.post({
|
||||
url: `/web/admin/production-work-orders/${workOrderId}/qc-work-orders`,
|
||||
data
|
||||
})
|
||||
}
|
||||
@@ -15,6 +15,38 @@ export type SampleReceptionCheckResult = {
|
||||
checkItemId?: string
|
||||
}
|
||||
|
||||
export type QcProtocolPaymentDetailSummary = {
|
||||
installmentNo?: number | null
|
||||
installmentLabel?: string
|
||||
installmentDueDate?: string
|
||||
dueAmount?: number | null
|
||||
transferAmount?: number | null
|
||||
payStatus?: string
|
||||
payStatusLabel?: string
|
||||
}
|
||||
|
||||
export type QcProtocolPaymentSummary = {
|
||||
payMode?: string
|
||||
payModeLabel?: string
|
||||
contractAmount?: number | null
|
||||
receivedAmount?: number | null
|
||||
pendingAmount?: number | null
|
||||
statusHint?: string
|
||||
overallPayStatus?: string
|
||||
overallPayStatusLabel?: string
|
||||
overallPayStatusTagType?: string
|
||||
installmentCount?: number | null
|
||||
paymentDetails?: QcProtocolPaymentDetailSummary[]
|
||||
}
|
||||
|
||||
export type QcBasicExperimentFeeSummary = {
|
||||
saleAmount?: number | null
|
||||
paymentAmount?: number | null
|
||||
transferAmount?: number | null
|
||||
payStatus?: string
|
||||
payStatusLabel?: string
|
||||
}
|
||||
|
||||
export type QcWorkOrderReceptionDetail = {
|
||||
protocolNo?: string
|
||||
sampleCode?: string
|
||||
@@ -93,6 +125,15 @@ export type QcWorkOrder = {
|
||||
/** 出库工单:输注计划总次数 */
|
||||
totalCourseCount?: number | null
|
||||
infusionTime?: string
|
||||
triggerSource?: string
|
||||
triggerSourceLabel?: string
|
||||
productionWorkOrderId?: string
|
||||
productionWorkOrderNo?: string
|
||||
productionTaskId?: string
|
||||
protocolStatus?: string
|
||||
protocolStatusLabel?: string
|
||||
paymentSummary?: QcProtocolPaymentSummary | null
|
||||
feeSummary?: QcBasicExperimentFeeSummary | null
|
||||
}
|
||||
|
||||
export type QcWorkOrderDetail = QcWorkOrder & {
|
||||
@@ -139,6 +180,7 @@ export function fetchQcWorkOrderList(params?: {
|
||||
createTimeEnd?: string
|
||||
infusionTimeStart?: string
|
||||
infusionTimeEnd?: string
|
||||
triggerSource?: string
|
||||
}) {
|
||||
return request.get<PageList<QcWorkOrder>>({
|
||||
url: '/web/admin/qc-work-orders',
|
||||
@@ -249,6 +291,7 @@ export type OutboundQcDetailProduct = {
|
||||
|
||||
export type OutboundQcDetail = {
|
||||
workOrder: QcWorkOrderDetail
|
||||
feeSummary?: QcBasicExperimentFeeSummary | null
|
||||
application?: OutboundQcDetailApplication
|
||||
patient?: OutboundQcDetailPatient
|
||||
infusionPlan?: OutboundQcDetailInfusionPlan
|
||||
|
||||
+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": "L160"}, {"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": "L179"}, {"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": "L185"}, {"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": "L202"}, {"id": "api_qc_work_order_fetchupdateqcworkorder", "label": "fetchUpdateQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L217"}, {"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": "L227"}, {"id": "api_qc_work_order_fetchoutboundqcdetail", "label": "fetchOutboundQcDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L291"}], "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": "L160", "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": "L179", "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": "L185", "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": "L202", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchupdateqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L217", "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": "L227", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchoutboundqcdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L291", "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": "L173"}, {"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": "L180"}, {"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": "L196"}, {"caller_nid": "api_qc_work_order_fetchcreateqcworkoLine 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_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L511"}, {"id": "qc_work_order_index_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L516"}, {"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": "L972"}, {"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": "L977"}, {"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": "L981"}, {"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": "L988"}, {"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": "L993"}, {"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": "L1009"}, {"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": "L1015"}, {"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": "L1026"}, {"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": "L1115"}, {"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": "L1133"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L459", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L460", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L461", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L462", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_lab_test_item", "Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersamplegroup_vue", "label": "QcWorkOrderSampleGroup.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSampleGroup.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_work_order_qcworkorderfeesummarybar_vue", "label": "QcWorkOrderFeeSummaryBar.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderFeeSummaryBar.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderfeesummarybar_vue", "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/views/quality-inspection/qc-work-order/QcWorkOrderFeeSummaryBar.vue", "source_location": "L63", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderfeesummarybar_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_money_format", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderFeeSummaryBar.vue", "source_location": "L67", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderfeesummarybar_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderFeeSummaryBar.vue", "source_location": "L68", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderfeesummarybar_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderFeeSummaryBar.vue", "source_location": "L69", "weight": 1.0}], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_productionworkordercardlist_vue", "label": "ProductionWorkOrderCardList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L1"}, {"id": "production_work_order_productionworkordercardlist_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L280"}, {"id": "production_work_order_productionworkordercardlist_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L284"}, {"id": "production_work_order_productionworkordercardlist_shouldshowtempemptyfield", "label": "shouldShowTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L288"}, {"id": "production_work_order_productionworkordercardlist_formattempemptyfield", "label": "formatTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L292"}, {"id": "production_work_order_productionworkordercardlist_formatoutboundschedulesortno", "label": "formatOutboundScheduleSortNo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L296"}, {"id": "production_work_order_productionworkordercardlist_formatoutboundscheduletotalcount", "label": "formatOutboundScheduleTotalCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L302"}, {"id": "production_work_order_productionworkordercardlist_productionwostatustag", "label": "productionWoStatusTag()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L322"}, {"id": "production_work_order_productionworkordercardlist_handlecardselect", "label": "handleCardSelect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L332"}, {"id": "production_work_order_productionworkordercardlist_cardindex", "label": "cardIndex()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L336"}, {"id": "production_work_order_productionworkordercardlist_isselected", "label": "isSelected()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L340"}, {"id": "production_work_order_productionworkordercardlist_candispatchtask", "label": "canDispatchTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L344"}, {"id": "production_work_order_productionworkordercardlist_candispatchqc", "label": "canDispatchQc()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L348"}, {"id": "production_work_order_productionworkordercardlist_dispatchqctooltip", "label": "dispatchQcTooltip()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L354"}, {"id": "production_work_order_productionworkordercardlist_cancomplete", "label": "canComplete()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L361"}, {"id": "production_work_order_productionworkordercardlist_candeleteworkorder", "label": "canDeleteWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L365"}, {"id": "production_work_order_productionworkordercardlist_hasmoreactions", "label": "hasMoreActions()", "file_type": "code", "source_file":Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "label": "OutboundQcViewDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L1"}, {"id": "qc_work_order_outboundqcviewdialog_handledownload", "label": "handleDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L296"}, {"id": "qc_work_order_outboundqcviewdialog_taskattachmentslotname", "label": "taskAttachmentSlotName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L309"}, {"id": "qc_work_order_outboundqcviewdialog_taskmaterialslotname", "label": "taskMaterialSlotName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L313"}, {"id": "qc_work_order_outboundqcviewdialog_handletaskpreview", "label": "handleTaskPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L317"}, {"id": "qc_work_order_outboundqcviewdialog_handletaskdownload", "label": "handleTaskDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L322"}, {"id": "qc_work_order_outboundqcviewdialog_conclusiontagtype", "label": "conclusionTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L328"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "target": "qc_work_order_outboundqcviewdialog_handledownload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L296", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "target": "qc_work_order_outboundqcviewdialog_taskattachmentslotname", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L309", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "target": "qc_work_order_outboundqcviewdialog_taskmaterialslotname", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L313", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "target": "qc_work_order_outboundqcviewdialog_handletaskpreview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L317", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "target": "qc_work_order_outboundqcviewdialog_handletaskdownload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L322", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "target": "qc_work_order_outboundqcviewdialog_conclusiontagtype", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L328", "weight": 1.0}], "raw_calls": [{"caller_nid": "qc_work_order_outboundqcviewdialog_handledownload", "callee": "downloadAttachmentFile", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L297"}, {"caller_nid": "qc_work_order_outboundqcviewdialog_handletaskpreview", "callee": "fullUrl", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_locatLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "label": "QcWorkOrderSingleCard.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L1"}, {"id": "qc_work_order_qcworkordersinglecard_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L311"}, {"id": "qc_work_order_qcworkordersinglecard_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L315"}, {"id": "qc_work_order_qcworkordersinglecard_shouldshowtempemptyfield", "label": "shouldShowTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L319"}, {"id": "qc_work_order_qcworkordersinglecard_formattempemptyfield", "label": "formatTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L323"}, {"id": "qc_work_order_qcworkordersinglecard_formattempcellproductfield", "label": "formatTempCellProductField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L327"}, {"id": "qc_work_order_qcworkordersinglecard_formatoutboundschedulesortno", "label": "formatOutboundScheduleSortNo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L332"}, {"id": "qc_work_order_qcworkordersinglecard_formatoutboundscheduletotalcount", "label": "formatOutboundScheduleTotalCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L338"}, {"id": "qc_work_order_qcworkordersinglecard_formatdetectmethods", "label": "formatDetectMethods()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L344"}, {"id": "qc_work_order_qcworkordersinglecard_formatqctarget", "label": "formatQcTarget()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L351"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_protocolstatuslabelbysource", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L311", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_protocolstatustagtypebysource", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L315", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_shouldshowtempemptyfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L319", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_formattempemptyfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L323", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_formattempcellproductfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspectioLine 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": "L138"}, {"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": "L157"}, {"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": "L163"}, {"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": "L180"}, {"id": "api_qc_work_order_fetchupdateqcworkorder", "label": "fetchUpdateQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L195"}, {"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": "L205"}, {"id": "api_qc_work_order_fetchoutboundqcdetail", "label": "fetchOutboundQcDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L268"}], "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": "L138", "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": "L157", "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": "L163", "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": "L180", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchupdateqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L195", "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": "L205", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchoutboundqcdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L268", "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": "L151"}, {"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": "L158"}, {"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": "L174"}, {"caller_nid": "api_qc_work_order_fetchcreateqcworkoLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups_ts", "label": "qc-work-order-groups.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L1"}, {"id": "utils_qc_work_order_groups_triggersortweight", "label": "triggerSortWeight()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L9"}, {"id": "utils_qc_work_order_groups_sortworkordersingroup", "label": "sortWorkOrdersInGroup()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L13"}, {"id": "utils_qc_work_order_groups_groupinboundqcworkorders", "label": "groupInboundQcWorkOrders()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L22"}, {"id": "utils_qc_work_order_groups_triggersourcetablabel", "label": "triggerSourceTabLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L40"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups_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/utils/qc-work-order-groups.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups_ts", "target": "utils_qc_work_order_groups_triggersortweight", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups_ts", "target": "utils_qc_work_order_groups_sortworkordersingroup", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L13", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups_ts", "target": "utils_qc_work_order_groups_groupinboundqcworkorders", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L22", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups_ts", "target": "utils_qc_work_order_groups_triggersourcetablabel", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L40", "weight": 1.0}], "raw_calls": [{"caller_nid": "utils_qc_work_order_groups_sortworkordersingroup", "callee": "sort", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L14"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L25"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L26"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "push", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L27"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "set", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L28"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "map", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L30"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "from", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L30"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "entries", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L30"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "label": "QcWorkOrderTaskSubList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1"}, {"id": "qc_work_order_qcworkordertasksublist_iscurrentuserassignee", "label": "isCurrentUserAssignee()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L708"}, {"id": "qc_work_order_qcworkordertasksublist_nextmaterialrowkey", "label": "nextMaterialRowKey()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L736"}, {"id": "qc_work_order_qcworkordertasksublist_onrequisitionselect", "label": "onRequisitionSelect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L900"}, {"id": "qc_work_order_qcworkordertasksublist_addmaterialrow", "label": "addMaterialRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L928"}, {"id": "qc_work_order_qcworkordertasksublist_removematerialrow", "label": "removeMaterialRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L942"}, {"id": "qc_work_order_qcworkordertasksublist_materialrowsfromapi", "label": "materialRowsFromApi()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L946"}, {"id": "qc_work_order_qcworkordertasksublist_enrichmaterialusagerows", "label": "enrichMaterialUsageRows()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L966"}, {"id": "qc_work_order_qcworkordertasksublist_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1065"}, {"id": "qc_work_order_qcworkordertasksublist_normalizeresultparams", "label": "normalizeResultParams()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1069"}, {"id": "qc_work_order_qcworkordertasksublist_toresultnumber", "label": "toResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1077"}, {"id": "qc_work_order_qcworkordertasksublist_setresultnumber", "label": "setResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1083"}, {"id": "qc_work_order_qcworkordertasksublist_hasresultvalue", "label": "hasResultValue()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1087"}, {"id": "qc_work_order_qcworkordertasksublist_formatmetric", "label": "formatMetric()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1091"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "target": "qc_work_order_qcworkordertasksublist_iscurrentuserassignee", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L708", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "target": "qc_work_order_qcworkordertasksublist_nextmaterialrowkey", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L736", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "target": "qc_work_orderLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "label": "QcWorkOrderSingleCard.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.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_work_order_qcworkordersamplegroup_vue", "label": "QcWorkOrderSampleGroup.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSampleGroup.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_work_order_qcworkorderprotocolpaymentpanel_vue", "label": "QcWorkOrderProtocolPaymentPanel.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_workordertasksublist_vue", "label": "WorkOrderTaskSubList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+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_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L512"}, {"id": "qc_work_order_index_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L517"}, {"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": "L936"}, {"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": "L941"}, {"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": "L945"}, {"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": "L952"}, {"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": "L957"}, {"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": "L973"}, {"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": "L979"}, {"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": "L990"}, {"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": "L1079"}, {"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": "L1097"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L462", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L463", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L464", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L465", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_lab_test_item", "relLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_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_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L508"}, {"id": "qc_work_order_index_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L513"}, {"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": "L931"}, {"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": "L936"}, {"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": "L940"}, {"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": "L947"}, {"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": "L952"}, {"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": "L968"}, {"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": "L974"}, {"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": "L985"}, {"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": "L1074"}, {"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": "L1092"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L458", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L459", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L460", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L461", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_lab_test_item", "relLine 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_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L496"}, {"id": "qc_work_order_index_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "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_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": "L914"}, {"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": "L919"}, {"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": "L923"}, {"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": "L930"}, {"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": "L935"}, {"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": "L951"}, {"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": "L957"}, {"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": "L968"}, {"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": "L1057"}, {"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": "L1075"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L447", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L448", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L449", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_lab_test_item", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L457", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "users_wuzilong_woLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "label": "DispatchQcWorkOrderDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L79", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L80", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L81", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L82", "weight": 1.0}], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "label": "QcWorkOrderCardList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L1"}, {"id": "qc_work_order_qcworkordercardlist_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L281"}, {"id": "qc_work_order_qcworkordercardlist_shouldshowtempemptyfield", "label": "shouldShowTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L285"}, {"id": "qc_work_order_qcworkordercardlist_formattempemptyfield", "label": "formatTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L289"}, {"id": "qc_work_order_qcworkordercardlist_formattempcellproductfield", "label": "formatTempCellProductField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L293"}, {"id": "qc_work_order_qcworkordercardlist_formatoutboundschedulesortno", "label": "formatOutboundScheduleSortNo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L298"}, {"id": "qc_work_order_qcworkordercardlist_formatoutboundscheduletotalcount", "label": "formatOutboundScheduleTotalCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L304"}, {"id": "qc_work_order_qcworkordercardlist_formatdetectmethods", "label": "formatDetectMethods()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L310"}, {"id": "qc_work_order_qcworkordercardlist_workorderstatustagtype", "label": "workOrderStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L317"}, {"id": "qc_work_order_qcworkordercardlist_cardindex", "label": "cardIndex()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L324"}, {"id": "qc_work_order_qcworkordercardlist_canconfigureworkorder", "label": "canConfigureWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L328"}, {"id": "qc_work_order_qcworkordercardlist_canedittemporaryworkorder", "label": "canEditTemporaryWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L332"}, {"id": "qc_work_order_qcworkordercardlist_caneditremarkworkorder", "label": "canEditRemarkWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L339"}, {"id": "qc_work_order_qcworkordercardlist_candeleteworkorder", "label": "canDeleteWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L352"}, {"id": "qc_work_order_qcworkordercardlist_hasmoreworkorderactions", "label": "hasMoreWorkOrderActions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L360"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "target": "qc_work_order_qcworkordercardlist_protocolstatustagtypebysource", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L281", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "target": "qc_work_order_qcworkordercardlist_shouldshowtempemptyfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuLine 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": "L172"}, {"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": "L191"}, {"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": "L197"}, {"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": "L214"}, {"id": "api_qc_work_order_fetchupdateqcworkorder", "label": "fetchUpdateQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L229"}, {"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": "L239"}, {"id": "api_qc_work_order_fetchoutboundqcdetail", "label": "fetchOutboundQcDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L303"}], "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": "L172", "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": "L191", "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": "L197", "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": "L214", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchupdateqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L229", "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": "L239", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchoutboundqcdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L303", "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": "L185"}, {"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": "L192"}, {"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": "L208"}, {"caller_nid": "api_qc_work_order_fetchcreateqcworkoLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "label": "QcWorkOrderTaskSubList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1"}, {"id": "qc_work_order_qcworkordertasksublist_iscurrentuserassignee", "label": "isCurrentUserAssignee()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L615"}, {"id": "qc_work_order_qcworkordertasksublist_nextmaterialrowkey", "label": "nextMaterialRowKey()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L643"}, {"id": "qc_work_order_qcworkordertasksublist_onrequisitionselect", "label": "onRequisitionSelect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L807"}, {"id": "qc_work_order_qcworkordertasksublist_addmaterialrow", "label": "addMaterialRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L835"}, {"id": "qc_work_order_qcworkordertasksublist_removematerialrow", "label": "removeMaterialRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L849"}, {"id": "qc_work_order_qcworkordertasksublist_materialrowsfromapi", "label": "materialRowsFromApi()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L853"}, {"id": "qc_work_order_qcworkordertasksublist_enrichmaterialusagerows", "label": "enrichMaterialUsageRows()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L873"}, {"id": "qc_work_order_qcworkordertasksublist_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L972"}, {"id": "qc_work_order_qcworkordertasksublist_normalizeresultparams", "label": "normalizeResultParams()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L976"}, {"id": "qc_work_order_qcworkordertasksublist_toresultnumber", "label": "toResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L984"}, {"id": "qc_work_order_qcworkordertasksublist_setresultnumber", "label": "setResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L990"}, {"id": "qc_work_order_qcworkordertasksublist_hasresultvalue", "label": "hasResultValue()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L994"}, {"id": "qc_work_order_qcworkordertasksublist_formatmetric", "label": "formatMetric()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L998"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "target": "qc_work_order_qcworkordertasksublist_iscurrentuserassignee", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L615", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "target": "qc_work_order_qcworkordertasksublist_nextmaterialrowkey", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L643", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "target": "qc_work_order_qcworLine 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": "L69"}, {"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": "L89"}, {"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": "L93"}, {"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": "L97"}, {"id": "api_production_work_order_fetchconfigureproductionworkorder", "label": "fetchConfigureProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L110"}, {"id": "api_production_work_order_fetchupdateproductionworkorder", "label": "fetchUpdateProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L126"}, {"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": "L133"}, {"id": "api_production_work_order_fetchproductionworkordercellproductoptions", "label": "fetchProductionWorkOrderCellProductOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L149"}, {"id": "api_production_work_order_fetchcreateqcfromproduction", "label": "fetchCreateQcFromProduction()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L155"}], "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": "L69", "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": "L89", "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": "L93", "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": "L97", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "api_production_work_order_fetchconfigureproductionworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "soLine truncated
|
||||
+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_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L331"}, {"id": "production_work_order_index_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L336"}, {"id": "production_work_order_index_shouldshowtempemptyfield", "label": "shouldShowTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L343"}, {"id": "production_work_order_index_formattempemptyfield", "label": "formatTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L346"}, {"id": "production_work_order_index_formatoutboundschedulesortno", "label": "formatOutboundScheduleSortNo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L350"}, {"id": "production_work_order_index_formatoutboundscheduletotalcount", "label": "formatOutboundScheduleTotalCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L356"}, {"id": "production_work_order_index_handleadd", "label": "handleAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L429"}, {"id": "production_work_order_index_handletypetabchange", "label": "handleTypeTabChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L437"}, {"id": "production_work_order_index_submitadd", "label": "submitAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L443"}, {"id": "production_work_order_index_handlereceptionattachmentpreview", "label": "handleReceptionAttachmentPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L706"}, {"id": "production_work_order_index_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L710"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L286", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L287", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L288", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L298", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_labels", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-oLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "label": "QcWorkOrderCardList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "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/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L56", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L57", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersamplegroup_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L58", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L59", "weight": 1.0}], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "label": "QcWorkOrderSingleCard.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L1"}, {"id": "qc_work_order_qcworkordersinglecard_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L298"}, {"id": "qc_work_order_qcworkordersinglecard_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L302"}, {"id": "qc_work_order_qcworkordersinglecard_shouldshowtempemptyfield", "label": "shouldShowTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L306"}, {"id": "qc_work_order_qcworkordersinglecard_formattempemptyfield", "label": "formatTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L310"}, {"id": "qc_work_order_qcworkordersinglecard_formattempcellproductfield", "label": "formatTempCellProductField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L314"}, {"id": "qc_work_order_qcworkordersinglecard_formatoutboundschedulesortno", "label": "formatOutboundScheduleSortNo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L319"}, {"id": "qc_work_order_qcworkordersinglecard_formatoutboundscheduletotalcount", "label": "formatOutboundScheduleTotalCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L325"}, {"id": "qc_work_order_qcworkordersinglecard_formatdetectmethods", "label": "formatDetectMethods()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L331"}, {"id": "qc_work_order_qcworkordersinglecard_formatqctarget", "label": "formatQcTarget()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L338"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_protocolstatuslabelbysource", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L298", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_protocolstatustagtypebysource", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L302", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_shouldshowtempemptyfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L306", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_formattempemptyfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L310", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_formattempcellproductfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspectioLine truncated
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { QcWorkOrder } from '@/api/qc-work-order'
|
||||
|
||||
export type QcWorkOrderSampleGroupModel = {
|
||||
groupKey: string
|
||||
sampleCode: string
|
||||
workOrders: QcWorkOrder[]
|
||||
}
|
||||
|
||||
function triggerSortWeight(row: QcWorkOrder) {
|
||||
return (row.triggerSource || 'reception') === 'reception' ? 0 : 1
|
||||
}
|
||||
|
||||
function sortWorkOrdersInGroup(rows: QcWorkOrder[]) {
|
||||
return [...rows].sort((a, b) => {
|
||||
const byTrigger = triggerSortWeight(a) - triggerSortWeight(b)
|
||||
if (byTrigger !== 0) return byTrigger
|
||||
return String(a.createTime || '').localeCompare(String(b.createTime || ''))
|
||||
})
|
||||
}
|
||||
|
||||
/** 入库 Tab:按样本编码分组(前端分组,分页仍按工单条数) */
|
||||
export function groupInboundQcWorkOrders(rows: QcWorkOrder[]): QcWorkOrderSampleGroupModel[] {
|
||||
const map = new Map<string, QcWorkOrder[]>()
|
||||
for (const row of rows) {
|
||||
const key = (row.sampleCode || '').trim() || row.id
|
||||
const list = map.get(key)
|
||||
if (list) list.push(row)
|
||||
else map.set(key, [row])
|
||||
}
|
||||
return Array.from(map.entries()).map(([groupKey, workOrders]) => {
|
||||
const sorted = sortWorkOrdersInGroup(workOrders)
|
||||
return {
|
||||
groupKey,
|
||||
sampleCode: sorted[0]?.sampleCode || '',
|
||||
workOrders: sorted
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function triggerSourceTabLabel(row: QcWorkOrder) {
|
||||
return row.triggerSourceLabel || ((row.triggerSource || 'reception') === 'production' ? '生产过程' : '样本接收')
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<!-- 生产工单 · 派发质检工单弹窗 -->
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
title="派发质检工单"
|
||||
width="560px"
|
||||
class="dialog-form-layout"
|
||||
align-center
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose"
|
||||
>
|
||||
<div class="dispatch-qc-dialog-work-order-info">
|
||||
<span
|
||||
>工单号:<b>{{ workOrderRow?.workOrderNo || '—' }}</b></span
|
||||
>
|
||||
<span>样本编码:{{ workOrderRow?.sampleCode || '—' }}</span>
|
||||
</div>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-position="top"
|
||||
class="dialog-form-layout"
|
||||
v-loading="optionsLoading"
|
||||
>
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="细胞产品" prop="cellProductId" class="form-col-span-2">
|
||||
<el-select
|
||||
v-model="form.cellProductId"
|
||||
placeholder="请选择细胞产品"
|
||||
filterable
|
||||
style="width: 100%"
|
||||
:disabled="!productOptions.length"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in productOptions"
|
||||
:key="opt.id"
|
||||
:label="formatProductOptionLabel(opt)"
|
||||
:value="opt.id"
|
||||
/>
|
||||
</el-select>
|
||||
<p v-if="!optionsLoading && !productOptions.length" class="hint-muted">
|
||||
暂无产出细胞产品,请先完成生产任务并录入输出。
|
||||
</p>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" class="form-col-span-2">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="选填"
|
||||
maxlength="512"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>取消
|
||||
</el-button>
|
||||
<el-button
|
||||
class="btn-main"
|
||||
type="primary"
|
||||
:loading="submitting"
|
||||
:disabled="!productOptions.length"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
<el-icon><Check /></el-icon>确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch, computed } from 'vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Close, Check } from '@element-plus/icons-vue'
|
||||
import {
|
||||
fetchProductionWorkOrderCellProductOptions,
|
||||
fetchCreateQcFromProduction,
|
||||
type ProductionWorkOrderItem,
|
||||
type ProductionCellProductOption
|
||||
} from '@/api/production-work-order'
|
||||
|
||||
defineOptions({ name: 'DispatchQcWorkOrderDialog' })
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean
|
||||
workOrderRow: ProductionWorkOrderItem | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:visible': [val: boolean]
|
||||
success: [payload: { sampleCode?: string }]
|
||||
}>()
|
||||
|
||||
const dialogVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: (v) => emit('update:visible', v)
|
||||
})
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const form = reactive({ cellProductId: '', remark: '' })
|
||||
const rules: FormRules = {
|
||||
cellProductId: [{ required: true, message: '请选择细胞产品', trigger: 'change' }]
|
||||
}
|
||||
const productOptions = ref<ProductionCellProductOption[]>([])
|
||||
const optionsLoading = ref(false)
|
||||
const submitting = ref(false)
|
||||
|
||||
function formatProductOptionLabel(opt: ProductionCellProductOption) {
|
||||
const parts = [
|
||||
opt.productCode,
|
||||
opt.productName,
|
||||
opt.productTypeName ? `(${opt.productTypeName})` : '',
|
||||
opt.passage ? `P${opt.passage}` : '',
|
||||
opt.storageSlotName ? `@${opt.storageSlotName}` : ''
|
||||
].filter(Boolean)
|
||||
const base = parts.join(' ') || opt.id
|
||||
return opt.taskNo ? `${base} · ${opt.taskNo}` : base
|
||||
}
|
||||
|
||||
async function loadOptions() {
|
||||
if (!props.workOrderRow?.id) {
|
||||
productOptions.value = []
|
||||
return
|
||||
}
|
||||
optionsLoading.value = true
|
||||
try {
|
||||
productOptions.value = (await fetchProductionWorkOrderCellProductOptions(props.workOrderRow.id)) || []
|
||||
} finally {
|
||||
optionsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
form.cellProductId = ''
|
||||
form.remark = ''
|
||||
formRef.value?.clearValidate()
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
dialogVisible.value = false
|
||||
resetForm()
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!props.workOrderRow?.id) return
|
||||
await formRef.value?.validate()
|
||||
submitting.value = true
|
||||
try {
|
||||
const selected = productOptions.value.find((o) => o.id === form.cellProductId)
|
||||
await fetchCreateQcFromProduction(props.workOrderRow.id, {
|
||||
cellProductId: form.cellProductId,
|
||||
productionTaskId: selected?.taskId,
|
||||
remark: form.remark || undefined
|
||||
})
|
||||
ElMessage.success('质检工单派发成功')
|
||||
emit('success', { sampleCode: props.workOrderRow.sampleCode })
|
||||
handleClose()
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [props.visible, props.workOrderRow?.id] as const,
|
||||
([visible]) => {
|
||||
if (visible) {
|
||||
resetForm()
|
||||
loadOptions()
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dispatch-qc-dialog-work-order-info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 20px;
|
||||
margin-bottom: 12px;
|
||||
padding: 10px 12px;
|
||||
font-size: 13px;
|
||||
color: #64748b;
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
|
||||
b {
|
||||
color: #1e293b;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.hint-muted {
|
||||
margin: 6px 0 0;
|
||||
font-size: 12px;
|
||||
color: var(--mint-text-muted, #94a3b8);
|
||||
line-height: 1.4;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,496 @@
|
||||
<!-- 生产工单 · 卡片列表(单列 + 内嵌生产任务) -->
|
||||
<template>
|
||||
<div class="list-body list-wrap production-work-order-cards-body">
|
||||
<div v-loading="loading" class="production-work-order-cards-wrap">
|
||||
<article v-for="(row, idx) in rows" :key="row.id" class="production-work-order-card">
|
||||
<header class="production-work-order-card__head">
|
||||
<div class="production-work-order-card__head-main">
|
||||
<div class="production-work-order-card__title-row">
|
||||
<el-checkbox
|
||||
:model-value="isSelected(row.id)"
|
||||
class="production-work-order-card__checkbox"
|
||||
@change="(val) => handleCardSelect(row, Boolean(val))"
|
||||
/>
|
||||
<span class="production-work-order-card__index">{{ cardIndex(idx) }}</span>
|
||||
<span class="production-work-order-card__no">{{ row.workOrderNo || '—' }}</span>
|
||||
<el-tag :type="productionWoStatusTag(row.workOrderStatus).type" size="small">
|
||||
{{ productionWoStatusTag(row.workOrderStatus).label }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<dl class="production-work-order-card__meta">
|
||||
<template v-if="activeTypeTab === 'outbound'">
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>业务类型</dt>
|
||||
<dd>
|
||||
<el-tag
|
||||
:type="
|
||||
row.bizType === 'pilot_service'
|
||||
? 'primary'
|
||||
: row.bizType === 'clinical_application'
|
||||
? 'warning'
|
||||
: 'info'
|
||||
"
|
||||
size="small"
|
||||
>
|
||||
{{ row.bizTypeLabel || '—' }}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>申请单号</dt>
|
||||
<dd>{{ row.applicationNo || '—' }}</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>用户名称</dt>
|
||||
<dd>{{ row.patientName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>第几次</dt>
|
||||
<dd>{{ formatOutboundScheduleSortNo(row) }}</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>总次数</dt>
|
||||
<dd>{{ formatOutboundScheduleTotalCount(row) }}</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>申请单名称</dt>
|
||||
<dd>{{ row.applicationName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>渠道名称</dt>
|
||||
<dd>{{ row.channelName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>输注时间</dt>
|
||||
<dd>{{ row.infusionTime || '—' }}</dd>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="activeTypeTab === 'temporary'">
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>备注</dt>
|
||||
<dd>{{ row.remark || '—' }}</dd>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>样本编码</dt>
|
||||
<dd>{{ formatTempEmptyField(row, row.sampleCode) }}</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>实验室入库编码</dt>
|
||||
<dd>{{ formatTempEmptyField(row, row.labStorageCode) }}</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>来源类型</dt>
|
||||
<dd>
|
||||
<span v-if="shouldShowTempEmptyField(row, row.receptionSource)">—</span>
|
||||
<el-tag
|
||||
v-else
|
||||
:type="row.receptionSource === 'research_donation' ? 'warning' : 'success'"
|
||||
size="small"
|
||||
>
|
||||
{{ row.receptionSourceLabel || receptionSourceLabel(row.receptionSource || '') }}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>协议状态</dt>
|
||||
<dd>
|
||||
<span v-if="shouldShowTempEmptyField(row, row.protocolStatus)">—</span>
|
||||
<el-tag
|
||||
v-else
|
||||
:type="
|
||||
protocolStatusTagTypeBySource(
|
||||
String(row.protocolStatus || ''),
|
||||
row.receptionSource || 'cell_storage'
|
||||
)
|
||||
"
|
||||
size="small"
|
||||
>
|
||||
{{
|
||||
protocolStatusLabelBySource(
|
||||
String(row.protocolStatus || ''),
|
||||
row.receptionSource || 'cell_storage'
|
||||
)
|
||||
}}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>样本类型</dt>
|
||||
<dd>{{ row.sampleTypeName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>接收经手人</dt>
|
||||
<dd>{{ row.handlerName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>是否超24小时</dt>
|
||||
<dd>
|
||||
<span v-if="!row.receptionTime">—</span>
|
||||
<el-tag v-else :type="receptionOver24HoursTag(row.receptionTime).type" size="small">
|
||||
{{ receptionOver24HoursTag(row.receptionTime).label }}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>接收时间</dt>
|
||||
<dd>{{ row.receptionTime || '—' }}</dd>
|
||||
</div>
|
||||
</template>
|
||||
<div class="production-work-order-card__meta-item">
|
||||
<dt>创建时间</dt>
|
||||
<dd>{{ row.createTime || '—' }}</dd>
|
||||
</div>
|
||||
<div
|
||||
v-if="row.remark && activeTypeTab !== 'temporary'"
|
||||
class="production-work-order-card__meta-item production-work-order-card__meta-item--wide"
|
||||
>
|
||||
<dt>备注</dt>
|
||||
<dd>{{ row.remark }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="production-work-order-card__ops">
|
||||
<el-button
|
||||
v-if="canDispatchTask(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
@click="emit('dispatch', row)"
|
||||
>
|
||||
<el-icon><Position /></el-icon>派发任务
|
||||
</el-button>
|
||||
<el-button v-else class="btn-op-item primary" @click="emit('view', row)">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-tooltip
|
||||
v-if="activeTypeTab === 'inbound'"
|
||||
:content="dispatchQcTooltip(row)"
|
||||
:disabled="canDispatchQc(row)"
|
||||
placement="top"
|
||||
>
|
||||
<span>
|
||||
<el-button
|
||||
class="btn-op-item"
|
||||
:disabled="!canDispatchQc(row)"
|
||||
@click="emit('dispatch-qc', row)"
|
||||
>
|
||||
<el-icon><Document /></el-icon>派发质检工单
|
||||
</el-button>
|
||||
</span>
|
||||
</el-tooltip>
|
||||
<el-button v-if="canComplete(row)" class="btn-op-item" @click="emit('complete', row)">
|
||||
<el-icon><Check /></el-icon>完成工单
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="hasMoreActions(row)"
|
||||
trigger="hover"
|
||||
@command="(cmd) => emit('command', cmd, row)"
|
||||
>
|
||||
<el-button class="btn-op-item">
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="canDispatchTask(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="edit">
|
||||
<el-icon><EditPen /></el-icon>编辑
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteWorkOrder(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</header>
|
||||
<section class="production-work-order-card__tasks">
|
||||
<WorkOrderTaskSubList
|
||||
embedded
|
||||
:work-order="row"
|
||||
:refresh-token="taskRefreshToken"
|
||||
@changed="emit('tasks-changed')"
|
||||
/>
|
||||
</section>
|
||||
</article>
|
||||
<el-empty
|
||||
v-if="!loading && !rows.length"
|
||||
class="production-work-order-cards-empty"
|
||||
description="暂无生产工单"
|
||||
:image-size="72"
|
||||
/>
|
||||
</div>
|
||||
<div class="pagination list-pager-bar">
|
||||
<el-pagination
|
||||
:current-page="page"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@size-change="(v) => emit('page-size-change', v)"
|
||||
@current-change="(v) => emit('page-change', v)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { View, Position, Document, Check, More, EditPen, Delete } from '@element-plus/icons-vue'
|
||||
import type { ProductionWorkOrderItem } from '@/api/production-work-order'
|
||||
import { receptionSourceLabel } from '@/utils/qc-labels'
|
||||
import {
|
||||
protocolStatusLabel,
|
||||
protocolStatusTagType,
|
||||
donationStatusLabel,
|
||||
donationStatusTagType
|
||||
} from '@/utils/status-tag-registry'
|
||||
import type { TagType } from '@/utils/status-tag-registry'
|
||||
import WorkOrderTaskSubList from './WorkOrderTaskSubList.vue'
|
||||
|
||||
defineOptions({ name: 'ProductionWorkOrderCardList' })
|
||||
|
||||
type WorkOrderTypeTab = 'inbound' | 'temporary' | 'outbound'
|
||||
|
||||
const props = defineProps<{
|
||||
rows: ProductionWorkOrderItem[]
|
||||
loading: boolean
|
||||
activeTypeTab: WorkOrderTypeTab
|
||||
page: number
|
||||
pageSize: number
|
||||
total: number
|
||||
taskRefreshToken: number
|
||||
selectedIds: string[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
view: [row: ProductionWorkOrderItem]
|
||||
dispatch: [row: ProductionWorkOrderItem]
|
||||
'dispatch-qc': [row: ProductionWorkOrderItem]
|
||||
complete: [row: ProductionWorkOrderItem]
|
||||
command: [cmd: string, row: ProductionWorkOrderItem]
|
||||
'toggle-select': [row: ProductionWorkOrderItem, checked: boolean]
|
||||
'tasks-changed': []
|
||||
'page-change': [page: number]
|
||||
'page-size-change': [size: number]
|
||||
}>()
|
||||
|
||||
const RECEPTION_OVER_HOURS_MS = 24 * 60 * 60 * 1000
|
||||
|
||||
function protocolStatusLabelBySource(status: string, source: string): string {
|
||||
return source === 'research_donation' ? donationStatusLabel(status) : protocolStatusLabel(status)
|
||||
}
|
||||
|
||||
function protocolStatusTagTypeBySource(status: string, source: string): TagType {
|
||||
return source === 'research_donation' ? donationStatusTagType(status) : protocolStatusTagType(status)
|
||||
}
|
||||
|
||||
function shouldShowTempEmptyField(row: ProductionWorkOrderItem, value?: string | null) {
|
||||
return row.workOrderType === 'temporary' && !String(value || '').trim()
|
||||
}
|
||||
|
||||
function formatTempEmptyField(row: ProductionWorkOrderItem, value?: string | null) {
|
||||
return shouldShowTempEmptyField(row, value) ? '—' : String(value || '')
|
||||
}
|
||||
|
||||
function formatOutboundScheduleSortNo(row: Record<string, unknown>) {
|
||||
const n = row.sortNo ?? row.orderNum
|
||||
if (n == null || n === '' || Number(n) <= 0) return '—'
|
||||
return `第${Number(n)}次`
|
||||
}
|
||||
|
||||
function formatOutboundScheduleTotalCount(row: Record<string, unknown>) {
|
||||
const n = row.totalCourseCount
|
||||
if (n == null || n === '' || Number(n) <= 0) return '—'
|
||||
return `共${Number(n)}次`
|
||||
}
|
||||
|
||||
function parseReceptionTime(value?: string | null): Date | null {
|
||||
const s = String(value || '').trim()
|
||||
if (!s) return null
|
||||
const dt = new Date(s.replace(/-/g, '/'))
|
||||
return Number.isNaN(dt.getTime()) ? null : dt
|
||||
}
|
||||
|
||||
function receptionOver24HoursTag(receptionTime?: string | null): { label: string; type: TagType } {
|
||||
const dt = parseReceptionTime(receptionTime)
|
||||
if (!dt) return { label: '—', type: 'info' }
|
||||
if (Date.now() - dt.getTime() > RECEPTION_OVER_HOURS_MS) return { label: '是', type: 'danger' }
|
||||
return { label: '否', type: 'success' }
|
||||
}
|
||||
|
||||
function productionWoStatusTag(status: string): { label: string; type: TagType } {
|
||||
const map: Record<string, { label: string; type: TagType }> = {
|
||||
dpz: { label: '待配置', type: 'info' },
|
||||
jxz: { label: '进行中', type: 'warning' },
|
||||
ywc: { label: '已完成', type: 'success' },
|
||||
yzf: { label: '已作废', type: 'danger' }
|
||||
}
|
||||
return map[status] || { label: status, type: 'info' }
|
||||
}
|
||||
|
||||
function handleCardSelect(row: ProductionWorkOrderItem, checked: boolean) {
|
||||
emit('toggle-select', row, checked)
|
||||
}
|
||||
|
||||
function cardIndex(i: number) {
|
||||
return (props.page - 1) * props.pageSize + i + 1
|
||||
}
|
||||
|
||||
function isSelected(id: string) {
|
||||
return props.selectedIds.includes(id)
|
||||
}
|
||||
|
||||
function canDispatchTask(row: ProductionWorkOrderItem) {
|
||||
return row.workOrderStatus === 'dpz' || row.workOrderStatus === 'jxz'
|
||||
}
|
||||
|
||||
function canDispatchQc(row: ProductionWorkOrderItem) {
|
||||
if (props.activeTypeTab !== 'inbound') return false
|
||||
if (row.workOrderStatus === 'yzf') return false
|
||||
return row.workOrderStatus === 'jxz' || row.workOrderStatus === 'ywc'
|
||||
}
|
||||
|
||||
function dispatchQcTooltip(row: ProductionWorkOrderItem) {
|
||||
if (props.activeTypeTab !== 'inbound') return ''
|
||||
if (row.workOrderStatus === 'dpz') return '请先派发并完成生产任务,录入输出细胞产品后再派发质检'
|
||||
if (row.workOrderStatus === 'yzf') return '已作废工单不可派发质检'
|
||||
return '请先完成生产任务并录入输出细胞产品'
|
||||
}
|
||||
|
||||
function canComplete(row: ProductionWorkOrderItem) {
|
||||
return row.workOrderStatus === 'dpz' || row.workOrderStatus === 'jxz'
|
||||
}
|
||||
|
||||
function canDeleteWorkOrder(row: ProductionWorkOrderItem) {
|
||||
return props.activeTypeTab !== 'outbound' && row.workOrderStatus !== 'ywc'
|
||||
}
|
||||
|
||||
function hasMoreActions(row: ProductionWorkOrderItem) {
|
||||
return canDispatchTask(row) || canDeleteWorkOrder(row) || true
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.production-work-order-cards-body {
|
||||
border-top: 1px solid var(--mint-border, #e2e8f0);
|
||||
}
|
||||
|
||||
.production-work-order-cards-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
min-height: 120px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.production-work-order-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
border-color 0.15s ease,
|
||||
box-shadow 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: #a7f3d0;
|
||||
box-shadow: 0 2px 8px rgba(16, 185, 129, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
.production-work-order-card__head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 10px;
|
||||
padding: 14px 16px;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.production-work-order-card__head-main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.production-work-order-card__title-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.production-work-order-card__checkbox {
|
||||
flex-shrink: 0;
|
||||
margin-right: -4px;
|
||||
}
|
||||
|
||||
.production-work-order-card__index {
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
.production-work-order-card__no {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.production-work-order-card__meta {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
gap: 8px 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.production-work-order-card__meta-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
|
||||
dt {
|
||||
margin: 0;
|
||||
font-size: 11px;
|
||||
line-height: 1.35;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
color: #334155;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
&--wide {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
.production-work-order-card__ops {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.production-work-order-card__tasks {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.production-work-order-cards-empty {
|
||||
padding: 24px 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,121 +1,134 @@
|
||||
<!-- 生产工单展开行 · 生产任务子列表 -->
|
||||
<!-- 生产工单 · 生产任务子列表 -->
|
||||
<template>
|
||||
<div class="work-order-task-sublist">
|
||||
<div class="work-order-task-sublist" :class="{ 'work-order-task-sublist--embedded': embedded }">
|
||||
<div class="work-order-task-sublist__panel" v-loading="loading">
|
||||
<div v-if="tableData.length" class="work-order-task-cards-wrap">
|
||||
<div class="work-order-task-sublist__summary">
|
||||
<span class="work-order-task-sublist__count">共 {{ tableData.length }} 项任务</span>
|
||||
<el-button
|
||||
class="work-order-task-sublist__refresh-icon"
|
||||
link
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="loadData"
|
||||
>
|
||||
<el-icon><RefreshLeft /></el-icon>
|
||||
</el-button>
|
||||
<el-button
|
||||
class="btn-main work-order-task-sublist__dispatch"
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="!canDispatch"
|
||||
@click="handleDispatch"
|
||||
>
|
||||
<el-icon><Position /></el-icon>派发任务
|
||||
</el-button>
|
||||
<div v-if="tableData.length" class="work-order-task-cards-area">
|
||||
<div class="work-order-task-sublist__head">
|
||||
<div class="work-order-task-sublist__head-title">生产任务</div>
|
||||
<div class="work-order-task-sublist__head-extra">
|
||||
<span class="work-order-task-sublist__count">共 {{ tableData.length }} 项任务</span>
|
||||
<el-button
|
||||
class="work-order-task-sublist__refresh-icon"
|
||||
link
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="loadData"
|
||||
>
|
||||
<el-icon><RefreshLeft /></el-icon>
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="!embedded"
|
||||
class="btn-main work-order-task-sublist__dispatch"
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="!canDispatch"
|
||||
@click="handleDispatch"
|
||||
>
|
||||
<el-icon><Position /></el-icon>派发任务
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="(row, idx) in tableData"
|
||||
:key="row.id || idx"
|
||||
class="work-order-task-card"
|
||||
@dblclick="handleViewDetail(row)"
|
||||
>
|
||||
<div class="work-order-task-card__head">
|
||||
<span class="work-order-task-card__name">{{ row.taskName || row.taskNo || '—' }}</span>
|
||||
<el-tag :type="taskStatusTag(row.taskStatus).type" size="small">
|
||||
{{ taskStatusTag(row.taskStatus).label }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="work-order-task-card__meta">
|
||||
<span class="work-order-task-card__code">{{ row.taskNo || '—' }}</span>
|
||||
<el-tag :type="productionTaskTypeTag(row.taskType, row.orderSource).type" size="small">
|
||||
{{ productionTaskTypeTag(row.taskType, row.orderSource).label }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-if="productionConclusionTagType(row.conclusion)"
|
||||
:type="productionConclusionTagType(row.conclusion)"
|
||||
size="small"
|
||||
>
|
||||
{{ row.conclusionLabel || productionConclusionLabel(row.conclusion) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="work-order-task-sublist__ops">
|
||||
<el-button
|
||||
v-if="canEnterExecution(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleEnterExecution(row)"
|
||||
>
|
||||
<el-icon><VideoPlay /></el-icon>进入执行
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleViewDetail(row)"
|
||||
>
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="hasMoreTaskActions(row)"
|
||||
trigger="hover"
|
||||
@command="(cmd) => handleDropdownCommand(cmd, row)"
|
||||
>
|
||||
<el-button class="btn-op-item" size="small" @click.stop>
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="canEnterExecution(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canEditTask(row)" command="editInfo">
|
||||
<el-icon><EditPen /></el-icon>编辑信息
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canEditTask(row)" command="editRoute">
|
||||
<el-icon><EditPen /></el-icon>编辑工艺
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteTask(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<div class="work-order-task-cards-grid">
|
||||
<div
|
||||
v-for="(row, idx) in tableData"
|
||||
:key="row.id || idx"
|
||||
class="work-order-task-card"
|
||||
@dblclick="handleViewDetail(row)"
|
||||
>
|
||||
<div class="work-order-task-card__line work-order-task-card__line--top">
|
||||
<span class="work-order-task-card__name">{{ row.taskName || row.taskNo || '—' }}</span>
|
||||
<div class="work-order-task-card__tags">
|
||||
<el-tag :type="taskStatusTag(row.taskStatus).type" size="small">
|
||||
{{ taskStatusTag(row.taskStatus).label }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-if="productionConclusionTagType(row.conclusion)"
|
||||
:type="productionConclusionTagType(row.conclusion)"
|
||||
size="small"
|
||||
>
|
||||
{{ row.conclusionLabel || productionConclusionLabel(row.conclusion) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="work-order-task-card__line work-order-task-card__line--bottom">
|
||||
<span class="work-order-task-card__code">{{ row.taskNo || '—' }}</span>
|
||||
<span class="work-order-task-card__sep">·</span>
|
||||
<el-tag :type="productionTaskTypeTag(row.taskType, row.orderSource).type" size="small">
|
||||
{{ productionTaskTypeTag(row.taskType, row.orderSource).label }}
|
||||
</el-tag>
|
||||
<div class="work-order-task-sublist__ops">
|
||||
<el-button
|
||||
v-if="canEnterExecution(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleEnterExecution(row)"
|
||||
>
|
||||
<el-icon><VideoPlay /></el-icon>进入执行
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleViewDetail(row)"
|
||||
>
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="hasMoreTaskActions(row)"
|
||||
trigger="hover"
|
||||
@command="(cmd) => handleDropdownCommand(cmd, row)"
|
||||
>
|
||||
<el-button class="btn-op-item" size="small" @click.stop>
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="canEnterExecution(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canEditTask(row)" command="editInfo">
|
||||
<el-icon><EditPen /></el-icon>编辑信息
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canEditTask(row)" command="editRoute">
|
||||
<el-icon><EditPen /></el-icon>编辑工艺
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteTask(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="!loading" class="work-order-task-cards-wrap work-order-task-cards-wrap--empty">
|
||||
<div class="work-order-task-sublist__summary">
|
||||
<el-button
|
||||
class="work-order-task-sublist__refresh-icon"
|
||||
link
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="loadData"
|
||||
>
|
||||
<el-icon><RefreshLeft /></el-icon>
|
||||
</el-button>
|
||||
<el-button
|
||||
class="btn-main work-order-task-sublist__dispatch"
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="!canDispatch"
|
||||
@click="handleDispatch"
|
||||
>
|
||||
<el-icon><Position /></el-icon>派发任务
|
||||
</el-button>
|
||||
<div v-else-if="!loading" class="work-order-task-cards-area work-order-task-cards-area--empty">
|
||||
<div class="work-order-task-sublist__head">
|
||||
<div class="work-order-task-sublist__head-title">生产任务</div>
|
||||
<div class="work-order-task-sublist__head-extra">
|
||||
<el-button
|
||||
class="work-order-task-sublist__refresh-icon"
|
||||
link
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="loadData"
|
||||
>
|
||||
<el-icon><RefreshLeft /></el-icon>
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="!embedded"
|
||||
class="btn-main work-order-task-sublist__dispatch"
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="!canDispatch"
|
||||
@click="handleDispatch"
|
||||
>
|
||||
<el-icon><Position /></el-icon>派发任务
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty
|
||||
class="work-order-task-sublist__empty"
|
||||
@@ -183,6 +196,8 @@
|
||||
workOrder: Record<string, any>
|
||||
/** 父级派发/完成工单后递增,用于刷新已展开子列表 */
|
||||
refreshToken?: number
|
||||
/** 内嵌于工单卡片时收紧布局并隐藏子列表派发按钮 */
|
||||
embedded?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -320,27 +335,65 @@
|
||||
padding: 8px 12px 10px 40px;
|
||||
background: #f8fafc;
|
||||
text-align: left;
|
||||
|
||||
&--embedded {
|
||||
padding: 10px 14px 12px;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.work-order-task-sublist__panel {
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.work-order-task-cards-wrap {
|
||||
.work-order-task-cards-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
|
||||
&--empty {
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.work-order-task-sublist__head {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.work-order-task-sublist__summary {
|
||||
flex: 0 0 auto;
|
||||
.work-order-task-sublist__head-title {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #64748b;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.work-order-task-sublist__head-extra {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px 8px;
|
||||
padding-top: 8px;
|
||||
min-height: 34px;
|
||||
}
|
||||
|
||||
.work-order-task-cards-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.work-order-task-cards-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.work-order-task-cards-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.work-order-task-sublist__count {
|
||||
@@ -365,18 +418,7 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.work-order-task-cards-wrap--empty {
|
||||
align-items: center;
|
||||
|
||||
.work-order-task-sublist__summary {
|
||||
padding-top: 0;
|
||||
min-height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.work-order-task-sublist__empty {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
padding: 4px 0;
|
||||
|
||||
:deep(.el-empty__description) {
|
||||
@@ -388,9 +430,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
flex: 0 0 248px;
|
||||
width: 248px;
|
||||
max-width: 248px;
|
||||
min-width: 0;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
@@ -404,12 +444,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
.work-order-task-card__head {
|
||||
.work-order-task-card__line {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
|
||||
&--top {
|
||||
flex-wrap: wrap;
|
||||
row-gap: 4px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&--bottom {
|
||||
flex-wrap: wrap;
|
||||
row-gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.work-order-task-card__name {
|
||||
@@ -420,18 +470,18 @@
|
||||
color: #1e293b;
|
||||
line-height: 1.35;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.work-order-task-card__meta {
|
||||
display: flex;
|
||||
.work-order-task-card__tags {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 4px 6px;
|
||||
min-width: 0;
|
||||
gap: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.work-order-task-card__code {
|
||||
@@ -439,17 +489,20 @@
|
||||
font-size: 11px;
|
||||
color: #475569;
|
||||
line-height: 1.35;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.work-order-task-card__sep {
|
||||
flex-shrink: 0;
|
||||
color: #cbd5e1;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.work-order-task-sublist__ops {
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding-top: 2px;
|
||||
gap: 4px;
|
||||
margin-left: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -93,270 +93,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-body list-wrap">
|
||||
<el-table
|
||||
ref="workOrderListTableRef"
|
||||
class="production-work-order-table list-table"
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
row-key="id"
|
||||
@selection-change="handleSelectionChange"
|
||||
@expand-change="handleWorkOrderRowExpand"
|
||||
>
|
||||
<el-table-column type="selection" min-width="55" align="center" header-align="center" />
|
||||
<el-table-column type="expand" min-width="64">
|
||||
<template #default="{ row }">
|
||||
<WorkOrderTaskSubList
|
||||
:work-order="row"
|
||||
:refresh-token="taskSubListRefreshToken"
|
||||
@changed="handleWorkOrderTasksChanged"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
min-width="68"
|
||||
align="center"
|
||||
:index="(i) => (pagination.page - 1) * pagination.pageSize + i + 1"
|
||||
/>
|
||||
<el-table-column prop="workOrderNo" label="工单号" min-width="150" align="center" />
|
||||
<el-table-column
|
||||
v-if="activeTypeTab === 'outbound'"
|
||||
prop="workOrderStatus"
|
||||
label="工单状态"
|
||||
min-width="100"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="woStatusTag(row.workOrderStatus).type" size="small">
|
||||
{{ woStatusTag(row.workOrderStatus).label }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 出库工单专属列 -->
|
||||
<el-table-column
|
||||
v-if="activeTypeTab === 'outbound'"
|
||||
prop="bizTypeLabel"
|
||||
label="业务类型"
|
||||
min-width="110"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
v-if="row.bizType"
|
||||
:type="bizTypeTagType(row.bizType) as TagType"
|
||||
size="small"
|
||||
>
|
||||
{{ row.bizTypeLabel || bizTypeLabel(row.bizType) }}
|
||||
</el-tag>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="activeTypeTab === 'outbound'"
|
||||
prop="applicationNo"
|
||||
label="申请单号"
|
||||
min-width="150"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">{{ row.applicationNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="activeTypeTab === 'outbound'"
|
||||
prop="patientName"
|
||||
label="用户名称"
|
||||
min-width="100"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">{{ row.patientName || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="activeTypeTab === 'outbound'"
|
||||
label="第几次"
|
||||
min-width="88"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">{{ formatOutboundScheduleSortNo(row) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="activeTypeTab === 'outbound'"
|
||||
label="总次数"
|
||||
min-width="88"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">{{ formatOutboundScheduleTotalCount(row) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="activeTypeTab === 'outbound'"
|
||||
prop="infusionTime"
|
||||
label="输注时间"
|
||||
min-width="170"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">{{ row.infusionTime || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="showReceptionCols"
|
||||
prop="protocolStatus"
|
||||
label="协议状态"
|
||||
min-width="100"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span v-if="shouldShowTempEmptyField(row, row.protocolStatus)">—</span>
|
||||
<el-tag
|
||||
v-else
|
||||
:type="
|
||||
protocolStatusTagTypeBySource(
|
||||
String(row.protocolStatus || ''),
|
||||
row.receptionSource || 'cell_storage'
|
||||
)
|
||||
"
|
||||
size="small"
|
||||
>{{
|
||||
protocolStatusLabelBySource(
|
||||
String(row.protocolStatus || ''),
|
||||
row.receptionSource || 'cell_storage'
|
||||
)
|
||||
}}</el-tag
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="showReceptionCols"
|
||||
prop="sampleCode"
|
||||
label="样本编码"
|
||||
min-width="120"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">{{ formatTempEmptyField(row, row.sampleCode) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="showReceptionCols"
|
||||
prop="labStorageCode"
|
||||
label="实验室入库编码"
|
||||
min-width="150"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">{{
|
||||
formatTempEmptyField(row, row.labStorageCode)
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="showReceptionCols"
|
||||
prop="receptionSource"
|
||||
label="来源类型"
|
||||
min-width="110"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span v-if="shouldShowTempEmptyField(row, row.receptionSource)">—</span>
|
||||
<el-tag v-else :type="sourceTag(row.receptionSource).type" size="small">
|
||||
{{ row.receptionSourceLabel || sourceTag(row.receptionSource).label }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="showReceptionCols"
|
||||
prop="sampleTypeName"
|
||||
label="样本类型"
|
||||
min-width="110"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">{{ row.sampleTypeName || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="showReceptionCols"
|
||||
prop="handlerName"
|
||||
label="接收人"
|
||||
min-width="100"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">{{ row.handlerName || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="showReceptionCols"
|
||||
label="是否超24小时"
|
||||
min-width="120"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span v-if="!row.receptionTime">—</span>
|
||||
<el-tag v-else :type="receptionOver24HoursTag(row.receptionTime).type" size="small">
|
||||
{{ receptionOver24HoursTag(row.receptionTime).label }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="showReceptionCols"
|
||||
prop="receptionTime"
|
||||
label="接收时间"
|
||||
min-width="170"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">{{ row.receptionTime || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="140" align="center">
|
||||
<template #default="{ row }">{{ row.remark || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="activeTypeTab !== 'outbound'"
|
||||
prop="workOrderStatus"
|
||||
label="工单状态"
|
||||
min-width="100"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="woStatusTag(row.workOrderStatus).type" size="small">
|
||||
{{ woStatusTag(row.workOrderStatus).label }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" min-width="170" align="center" />
|
||||
<el-table-column
|
||||
label="操作"
|
||||
min-width="160"
|
||||
fixed="right"
|
||||
align="center"
|
||||
header-align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div style="display: flex; justify-content: center; gap: 8px">
|
||||
<el-button class="btn-op-item primary" @click="handleView(row)">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-dropdown trigger="hover" @command="(cmd) => handleDropdownCommand(cmd, row)">
|
||||
<el-button class="btn-op-item">
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="edit">
|
||||
<el-icon><EditPen /></el-icon>编辑
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteWorkOrder(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination list-pager-bar">
|
||||
<el-pagination
|
||||
:current-page="pagination.page"
|
||||
:page-size="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@size-change="(v) => ((pagination.page = 1), (pagination.pageSize = v), loadData())"
|
||||
@current-change="(v) => ((pagination.page = v), loadData())"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ProductionWorkOrderCardList
|
||||
:rows="tableData"
|
||||
:loading="loading"
|
||||
:active-type-tab="activeTypeTab"
|
||||
:page="pagination.page"
|
||||
:page-size="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:task-refresh-token="taskSubListRefreshToken"
|
||||
:selected-ids="selectedIds"
|
||||
@view="handleView"
|
||||
@dispatch="handleOpenDispatch"
|
||||
@dispatch-qc="handleOpenDispatchQc"
|
||||
@complete="handleCompleteSingle"
|
||||
@command="handleDropdownCommand"
|
||||
@toggle-select="handleCardToggleSelect"
|
||||
@tasks-changed="handleWorkOrderTasksChanged"
|
||||
@page-change="(v) => ((pagination.page = v), loadData())"
|
||||
@page-size-change="(v) => ((pagination.page = 1), (pagination.pageSize = v), loadData())"
|
||||
/>
|
||||
|
||||
|
||||
<!-- 查看详情弹窗 -->
|
||||
<SystemViewDialog
|
||||
@@ -448,6 +204,12 @@
|
||||
@success="handleDispatchSuccess"
|
||||
/>
|
||||
|
||||
<DispatchQcWorkOrderDialog
|
||||
v-model:visible="dispatchQcVisible"
|
||||
:work-order-row="dispatchQcRow"
|
||||
@success="handleDispatchQcSuccess"
|
||||
/>
|
||||
|
||||
<!-- 新增生产工单弹窗 -->
|
||||
<el-dialog
|
||||
v-model="addVisible"
|
||||
@@ -520,8 +282,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, onMounted, nextTick } from 'vue'
|
||||
import type { TableInstance } from 'element-plus'
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
Plus,
|
||||
@@ -531,10 +293,7 @@
|
||||
RefreshLeft,
|
||||
View,
|
||||
Document,
|
||||
Position,
|
||||
EditPen,
|
||||
Delete,
|
||||
More
|
||||
Position
|
||||
} from '@element-plus/icons-vue'
|
||||
import {
|
||||
fetchProductionWorkOrderList,
|
||||
@@ -543,7 +302,8 @@
|
||||
fetchCreateProductionWorkOrder,
|
||||
fetchUpdateProductionWorkOrder,
|
||||
fetchDeleteProductionWorkOrder,
|
||||
type ProductionWorkOrderDetail
|
||||
type ProductionWorkOrderDetail,
|
||||
type ProductionWorkOrderItem
|
||||
} from '@/api/production-work-order'
|
||||
import {
|
||||
receptionSourceLabel,
|
||||
@@ -628,16 +388,16 @@
|
||||
import type { ViewSection } from '@/components/business/system-view-dialog/index.vue'
|
||||
import { downloadAttachmentFile } from '@/utils/download-attachment'
|
||||
import DispatchTaskDialog from './DispatchTaskDialog.vue'
|
||||
import DispatchQcWorkOrderDialog from './DispatchQcWorkOrderDialog.vue'
|
||||
import ProductionWorkOrderCardList from './ProductionWorkOrderCardList.vue'
|
||||
import WorkOrderRemarkDialog from '@/components/business/work-order-remark-dialog/index.vue'
|
||||
import WorkOrderTaskSubList from './WorkOrderTaskSubList.vue'
|
||||
|
||||
defineOptions({ name: 'ProductionProductionWorkOrder' })
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
type WorkOrderTypeTab = 'inbound' | 'temporary' | 'outbound'
|
||||
const activeTypeTab = ref<WorkOrderTypeTab>('inbound')
|
||||
const showReceptionCols = computed(
|
||||
() => activeTypeTab.value !== 'temporary' && activeTypeTab.value !== 'outbound'
|
||||
)
|
||||
const searchPlaceholder = computed(() => {
|
||||
if (activeTypeTab.value === 'temporary') return '工单号'
|
||||
if (activeTypeTab.value === 'outbound') return '工单号/申请单号'
|
||||
@@ -774,9 +534,9 @@
|
||||
|
||||
const searchForm = reactive({ keyword: '', workOrderStatus: '' })
|
||||
const createTimeRange = ref<[string, string] | null>(getDefaultLast30DaysRange())
|
||||
const tableData = ref<any[]>([])
|
||||
const selectedRows = ref<any[]>([])
|
||||
const workOrderListTableRef = ref<TableInstance>()
|
||||
const tableData = ref<ProductionWorkOrderItem[]>([])
|
||||
const selectedRows = ref<ProductionWorkOrderItem[]>([])
|
||||
const selectedIds = computed(() => selectedRows.value.map((r) => r.id))
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
const taskSubListRefreshToken = ref(0)
|
||||
@@ -794,13 +554,18 @@
|
||||
)
|
||||
})
|
||||
|
||||
function handleSelectionChange(rows: any[]) {
|
||||
selectedRows.value = rows
|
||||
function handleCardToggleSelect(row: ProductionWorkOrderItem, checked: boolean) {
|
||||
if (checked) {
|
||||
if (!selectedRows.value.some((r) => r.id === row.id)) {
|
||||
selectedRows.value = [...selectedRows.value, row]
|
||||
}
|
||||
} else {
|
||||
selectedRows.value = selectedRows.value.filter((r) => r.id !== row.id)
|
||||
}
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
selectedRows.value = []
|
||||
workOrderListTableRef.value?.clearSelection?.()
|
||||
}
|
||||
|
||||
function requireSingleSelection(action: string) {
|
||||
@@ -843,19 +608,9 @@
|
||||
await loadData()
|
||||
}
|
||||
|
||||
async function layoutWorkOrderTable() {
|
||||
await nextTick()
|
||||
workOrderListTableRef.value?.doLayout?.()
|
||||
}
|
||||
|
||||
async function handleWorkOrderRowExpand(_row: any, _expandedRows: any[]) {
|
||||
await layoutWorkOrderTable()
|
||||
}
|
||||
|
||||
async function handleWorkOrderTasksChanged() {
|
||||
taskSubListRefreshToken.value += 1
|
||||
await loadData()
|
||||
await layoutWorkOrderTable()
|
||||
}
|
||||
|
||||
async function handleDispatchSuccess() {
|
||||
@@ -892,9 +647,11 @@
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
selectedRows.value = selectedRows.value.filter((row) =>
|
||||
tableData.value.some((item) => item.id === row.id)
|
||||
)
|
||||
} finally {
|
||||
loading.value = false
|
||||
await layoutWorkOrderTable()
|
||||
}
|
||||
}
|
||||
function handleSearch() {
|
||||
@@ -1136,12 +893,53 @@
|
||||
|
||||
// ── 派发任务 ──────────────────────────────────────────
|
||||
const dispatchVisible = ref(false)
|
||||
const dispatchRow = ref<any>(null)
|
||||
function handleOpenDispatch(row: any) {
|
||||
const dispatchRow = ref<ProductionWorkOrderItem | null>(null)
|
||||
function handleOpenDispatch(row: ProductionWorkOrderItem) {
|
||||
dispatchRow.value = row
|
||||
dispatchVisible.value = true
|
||||
}
|
||||
|
||||
const dispatchQcVisible = ref(false)
|
||||
const dispatchQcRow = ref<ProductionWorkOrderItem | null>(null)
|
||||
function handleOpenDispatchQc(row: ProductionWorkOrderItem) {
|
||||
dispatchQcRow.value = row
|
||||
dispatchQcVisible.value = true
|
||||
}
|
||||
|
||||
function handleDispatchQcSuccess(payload: { sampleCode?: string }) {
|
||||
taskSubListRefreshToken.value += 1
|
||||
loadData()
|
||||
if (payload.sampleCode) {
|
||||
ElMessageBox.confirm('是否前往质检工单列表查看?', '提示', {
|
||||
type: 'info',
|
||||
confirmButtonText: '前往',
|
||||
cancelButtonText: '留在此页'
|
||||
})
|
||||
.then(() => {
|
||||
router.push({
|
||||
path: '/quality-manage/qc-work-order',
|
||||
query: { sampleCode: payload.sampleCode }
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCompleteSingle(row: ProductionWorkOrderItem) {
|
||||
if (row.workOrderStatus !== 'dpz' && row.workOrderStatus !== 'jxz') {
|
||||
ElMessage.warning('仅待配置或进行中的工单可完成')
|
||||
return
|
||||
}
|
||||
await ElMessageBox.confirm(`确定要完成工单「${row.workOrderNo || ''}」吗?`, '提示', {
|
||||
type: 'warning'
|
||||
})
|
||||
await fetchCompleteProductionWorkOrder(row.id, {})
|
||||
ElMessage.success('工单已完成')
|
||||
selectedRows.value = selectedRows.value.filter((r) => r.id !== row.id)
|
||||
taskSubListRefreshToken.value += 1
|
||||
await loadData()
|
||||
}
|
||||
|
||||
// 输入检索条件时自动搜索(防抖 300ms)
|
||||
watchDebounced(
|
||||
[searchForm, createTimeRange],
|
||||
@@ -1158,44 +956,6 @@
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.production-work-order-table :deep(td.el-table__expanded-cell) {
|
||||
padding: 0 !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.production-work-order-table :deep(td.el-table__expanded-cell > .cell) {
|
||||
display: block !important;
|
||||
padding: 0 !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.production-work-order-table :deep(.el-table__expand-icon) {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--mint-border, #d9e8e2);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition:
|
||||
background 0.15s ease,
|
||||
border-color 0.15s ease;
|
||||
color: var(--mint-text-muted, #64748b);
|
||||
background: var(--mint-surface, #fff);
|
||||
}
|
||||
|
||||
.production-work-order-table :deep(.el-table__expand-icon:hover) {
|
||||
background: var(--mint-primary-bg, #ecfdf5);
|
||||
border-color: #10b981;
|
||||
color: var(--mint-primary-dark, #059669);
|
||||
}
|
||||
|
||||
.production-work-order-table :deep(.el-table__expand-icon--expanded) {
|
||||
background: var(--mint-primary-bg, #ecfdf5);
|
||||
border-color: #10b981;
|
||||
color: var(--mint-primary-dark, #059669);
|
||||
}
|
||||
|
||||
.work-order-type-tabs {
|
||||
padding: 0 16px;
|
||||
margin-bottom: 4px;
|
||||
|
||||
@@ -145,7 +145,8 @@
|
||||
bizTypeLabel,
|
||||
bizTypeTagType,
|
||||
productStatusLabel,
|
||||
productStatusTagType
|
||||
productStatusTagType,
|
||||
payStatusTagType
|
||||
} from '@/utils/status-tag-registry'
|
||||
import {
|
||||
buildOutboundPilotContextSections,
|
||||
@@ -155,6 +156,7 @@
|
||||
import type { ViewField, ViewSection } from '@/components/business/system-view-dialog/index.vue'
|
||||
import ProtocolAttachmentReadonly from '@/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue'
|
||||
import { downloadAttachmentFile } from '@/utils/download-attachment'
|
||||
import { formatMoneyDisplay } from '@/utils/money-format'
|
||||
|
||||
defineOptions({ name: 'OutboundQcViewDialog' })
|
||||
|
||||
@@ -475,6 +477,43 @@
|
||||
const variant = resolveOutboundViewVariant(d.application?.bizType || d.workOrder?.bizType)
|
||||
result.push(...buildOutboundPilotContextSections(d, variant))
|
||||
|
||||
const feeSummary = d.feeSummary || d.workOrder?.feeSummary
|
||||
if (variant === 'basic_experiment') {
|
||||
result.push({
|
||||
title: '缴费信息',
|
||||
fields: feeSummary
|
||||
? [
|
||||
{
|
||||
label: '售卖金额(元)',
|
||||
value:
|
||||
feeSummary.saleAmount != null
|
||||
? formatMoneyDisplay(feeSummary.saleAmount)
|
||||
: '—'
|
||||
},
|
||||
{
|
||||
label: '应缴金额(元)',
|
||||
value:
|
||||
feeSummary.paymentAmount != null
|
||||
? formatMoneyDisplay(feeSummary.paymentAmount)
|
||||
: '—'
|
||||
},
|
||||
{
|
||||
label: '实收金额(元)',
|
||||
value:
|
||||
feeSummary.transferAmount != null
|
||||
? formatMoneyDisplay(feeSummary.transferAmount)
|
||||
: '—'
|
||||
},
|
||||
{
|
||||
label: '缴费状态',
|
||||
value: feeSummary.payStatusLabel || '—',
|
||||
tagType: payStatusTagType(feeSummary.payStatus || '') as ViewField['tagType']
|
||||
}
|
||||
]
|
||||
: [{ label: '缴费信息', value: '暂无缴费记录', span: true }]
|
||||
})
|
||||
}
|
||||
|
||||
// 检测结果 — lab tasks
|
||||
const labSections = buildTaskTypeSections(tasksWithResults.value, 'sysz', '实验室项目')
|
||||
result.push(...labSections)
|
||||
|
||||
@@ -1,218 +1,36 @@
|
||||
<!-- 质检工单 · 卡片列表(工单大卡片 + 任务小卡片) -->
|
||||
<!-- 质检工单 · 卡片列表(入库按样本分组 + 出库/临时单列) -->
|
||||
<template>
|
||||
<div class="list-body list-wrap qc-work-order-cards-body">
|
||||
<div v-loading="loading" class="qc-work-order-cards-wrap">
|
||||
<article v-for="(row, idx) in rows" :key="row.id" class="qc-work-order-card">
|
||||
<header class="qc-work-order-card__head">
|
||||
<div class="qc-work-order-card__head-main">
|
||||
<div class="qc-work-order-card__title-row">
|
||||
<span class="qc-work-order-card__index">{{ cardIndex(idx) }}</span>
|
||||
<span class="qc-work-order-card__no">{{ row.workOrderNo || '—' }}</span>
|
||||
<el-tag :type="workOrderStatusTagType(row.workOrderStatus)" size="small">
|
||||
{{ workOrderStatusLabel(row.workOrderStatus) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<dl class="qc-work-order-card__meta">
|
||||
<template v-if="activeTypeTab === 'outbound'">
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>业务类型</dt>
|
||||
<dd>
|
||||
<el-tag
|
||||
:type="
|
||||
row.bizType === 'pilot_service'
|
||||
? 'primary'
|
||||
: row.bizType === 'clinical_application'
|
||||
? 'warning'
|
||||
: 'info'
|
||||
"
|
||||
size="small"
|
||||
>
|
||||
{{ row.bizTypeLabel || '—' }}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>申请单号</dt>
|
||||
<dd>{{ row.applicationNo || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>用户名称</dt>
|
||||
<dd>{{ row.patientName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>第几次</dt>
|
||||
<dd>{{ formatOutboundScheduleSortNo(row) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>总次数</dt>
|
||||
<dd>{{ formatOutboundScheduleTotalCount(row) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>申请单名称</dt>
|
||||
<dd>{{ row.applicationName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>渠道名称</dt>
|
||||
<dd>{{ row.channelName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>输注时间</dt>
|
||||
<dd>{{ row.infusionTime || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>来源类型</dt>
|
||||
<dd>
|
||||
<el-tag
|
||||
:type="row.receptionSource === 'research_donation' ? 'warning' : 'success'"
|
||||
size="small"
|
||||
>
|
||||
{{ row.receptionSourceLabel || receptionSourceLabel(row.receptionSource || '') }}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="activeTypeTab === 'temporary'">
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>业务类型</dt>
|
||||
<dd>
|
||||
<el-tag :type="qcBizTypeTagType('temporary')" size="small">
|
||||
{{ row.qcBizTypeLabel || qcBizTypeLabel('temporary') }}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>产品编码</dt>
|
||||
<dd>{{ formatTempCellProductField(row, row.cellProductCode) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>产品名称</dt>
|
||||
<dd>{{ formatTempCellProductField(row, row.cellProductName) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>产品类型</dt>
|
||||
<dd>{{ formatTempCellProductField(row, row.cellProductTypeName) }}</dd>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>样本编码</dt>
|
||||
<dd>{{ formatTempEmptyField(row, row.sampleCode) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>实验室入库编码</dt>
|
||||
<dd>{{ formatTempEmptyField(row, row.labStorageCode) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>来源类型</dt>
|
||||
<dd>
|
||||
<span v-if="shouldShowTempEmptyField(row, row.receptionSource)">—</span>
|
||||
<el-tag
|
||||
v-else
|
||||
:type="row.receptionSource === 'research_donation' ? 'warning' : 'success'"
|
||||
size="small"
|
||||
>
|
||||
{{ row.receptionSourceLabel || receptionSourceLabel(row.receptionSource || '') }}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>协议状态</dt>
|
||||
<dd>
|
||||
<span v-if="shouldShowTempEmptyField(row, row.protocolStatus)">—</span>
|
||||
<el-tag
|
||||
v-else
|
||||
:type="
|
||||
protocolStatusTagTypeBySource(
|
||||
String(row.protocolStatus || ''),
|
||||
row.receptionSource || 'cell_storage'
|
||||
)
|
||||
"
|
||||
size="small"
|
||||
>
|
||||
{{
|
||||
protocolStatusLabelBySource(
|
||||
String(row.protocolStatus || ''),
|
||||
row.receptionSource || 'cell_storage'
|
||||
)
|
||||
}}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>样本类型</dt>
|
||||
<dd>{{ row.sampleTypeName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>接收时间</dt>
|
||||
<dd>{{ row.receptionTime || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>接收经手人</dt>
|
||||
<dd>{{ row.handlerName || '—' }}</dd>
|
||||
</div>
|
||||
</template>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>检测方式</dt>
|
||||
<dd>{{ formatDetectMethods(row) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>{{ activeTypeTab === 'outbound' ? '创建时间' : '创建时间' }}</dt>
|
||||
<dd>{{ row.createTime || '—' }}</dd>
|
||||
</div>
|
||||
<div v-if="row.remark" class="qc-work-order-card__meta-item qc-work-order-card__meta-item--wide">
|
||||
<dt>备注</dt>
|
||||
<dd>{{ row.remark }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
<div v-if="activeTypeTab !== 'all'" class="qc-work-order-card__ops">
|
||||
<el-button
|
||||
v-if="canConfigureWorkOrder(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
@click="emit('configure', row)"
|
||||
>
|
||||
<el-icon><Setting /></el-icon
|
||||
>{{ row.workOrderStatus !== 'dpz' ? '调整检测' : '配置检测' }}
|
||||
</el-button>
|
||||
<el-button v-else class="btn-op-item primary" @click="emit('view', row)">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="hasMoreWorkOrderActions(row)"
|
||||
trigger="hover"
|
||||
@command="(cmd) => emit('command', cmd, row)"
|
||||
>
|
||||
<el-button class="btn-op-item">
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="canConfigureWorkOrder(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="canEditTemporaryWorkOrder(row) || canEditRemarkWorkOrder(row)"
|
||||
command="edit"
|
||||
>
|
||||
<el-icon><EditPen /></el-icon>编辑
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteWorkOrder(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</header>
|
||||
<section v-if="activeTypeTab !== 'all'" class="qc-work-order-card__tasks">
|
||||
<QcWorkOrderTaskSubList
|
||||
:work-order="row"
|
||||
:refresh-token="taskRefreshToken"
|
||||
@changed="emit('tasks-changed')"
|
||||
/>
|
||||
</section>
|
||||
</article>
|
||||
<template v-if="activeTypeTab === 'inbound'">
|
||||
<QcWorkOrderSampleGroup
|
||||
v-for="(group, idx) in inboundGroups"
|
||||
:key="group.groupKey"
|
||||
:group="group"
|
||||
:group-index="cardIndex(idx)"
|
||||
active-type-tab="inbound"
|
||||
:task-refresh-token="taskRefreshToken"
|
||||
@configure="(row) => emit('configure', row)"
|
||||
@view="(row) => emit('view', row)"
|
||||
@command="(cmd, row) => emit('command', cmd, row)"
|
||||
@tasks-changed="emit('tasks-changed')"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<QcWorkOrderSingleCard
|
||||
v-for="(row, idx) in rows"
|
||||
:key="row.id"
|
||||
layout="standalone"
|
||||
:row="row"
|
||||
:active-type-tab="activeTypeTab"
|
||||
:card-index="cardIndex(idx)"
|
||||
:task-refresh-token="taskRefreshToken"
|
||||
@configure="(row) => emit('configure', row)"
|
||||
@view="(row) => emit('view', row)"
|
||||
@command="(cmd, row) => emit('command', cmd, row)"
|
||||
@tasks-changed="emit('tasks-changed')"
|
||||
/>
|
||||
</template>
|
||||
<el-empty
|
||||
v-if="!loading && !rows.length"
|
||||
class="qc-work-order-cards-empty"
|
||||
@@ -234,22 +52,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Setting, View, More, EditPen, Delete } from '@element-plus/icons-vue'
|
||||
import { computed } from 'vue'
|
||||
import type { QcWorkOrder } from '@/api/qc-work-order'
|
||||
import {
|
||||
workOrderStatusLabel,
|
||||
receptionSourceLabel,
|
||||
qcBizTypeLabel
|
||||
} from '@/utils/qc-labels'
|
||||
import {
|
||||
protocolStatusLabel,
|
||||
protocolStatusTagType,
|
||||
donationStatusLabel,
|
||||
donationStatusTagType,
|
||||
qcBizTypeTagType
|
||||
} from '@/utils/status-tag-registry'
|
||||
import type { TagType } from '@/utils/status-tag-registry'
|
||||
import QcWorkOrderTaskSubList from './QcWorkOrderTaskSubList.vue'
|
||||
import { groupInboundQcWorkOrders } from '@/utils/qc-work-order-groups'
|
||||
import QcWorkOrderSampleGroup from './QcWorkOrderSampleGroup.vue'
|
||||
import QcWorkOrderSingleCard from './QcWorkOrderSingleCard.vue'
|
||||
|
||||
defineOptions({ name: 'QcWorkOrderCardList' })
|
||||
|
||||
@@ -274,97 +81,13 @@
|
||||
'page-size-change': [size: number]
|
||||
}>()
|
||||
|
||||
function protocolStatusLabelBySource(status: string, source: string): string {
|
||||
return source === 'research_donation' ? donationStatusLabel(status) : protocolStatusLabel(status)
|
||||
}
|
||||
|
||||
function protocolStatusTagTypeBySource(status: string, source: string): TagType {
|
||||
return source === 'research_donation' ? donationStatusTagType(status) : protocolStatusTagType(status)
|
||||
}
|
||||
|
||||
function shouldShowTempEmptyField(row: QcWorkOrder, value?: string | null) {
|
||||
return row.workOrderType === 'temporary' && !String(value || '').trim()
|
||||
}
|
||||
|
||||
function formatTempEmptyField(row: QcWorkOrder, value?: string | null) {
|
||||
return shouldShowTempEmptyField(row, value) ? '—' : String(value || '')
|
||||
}
|
||||
|
||||
function formatTempCellProductField(row: QcWorkOrder, value?: string | null) {
|
||||
if (row.workOrderType !== 'temporary') return '—'
|
||||
return String(value || '').trim() || '—'
|
||||
}
|
||||
|
||||
function formatOutboundScheduleSortNo(row: Record<string, unknown>) {
|
||||
const n = row.sortNo ?? row.orderNum
|
||||
if (n == null || n === '' || Number(n) <= 0) return '—'
|
||||
return `第${Number(n)}次`
|
||||
}
|
||||
|
||||
function formatOutboundScheduleTotalCount(row: Record<string, unknown>) {
|
||||
const n = row.totalCourseCount
|
||||
if (n == null || n === '' || Number(n) <= 0) return '—'
|
||||
return `共${Number(n)}次`
|
||||
}
|
||||
|
||||
function formatDetectMethods(row: QcWorkOrder) {
|
||||
const parts: string[] = []
|
||||
if (row.hasLab) parts.push('实验室')
|
||||
if (row.hasThirdParty) parts.push('第三方')
|
||||
return parts.length ? parts.join(' / ') : '—'
|
||||
}
|
||||
|
||||
function workOrderStatusTagType(status: string): TagType {
|
||||
if (status === 'ywc') return 'success'
|
||||
if (status === 'ypz') return 'warning'
|
||||
if (status === 'yzf') return 'danger'
|
||||
return 'info'
|
||||
}
|
||||
const inboundGroups = computed(() =>
|
||||
props.activeTypeTab === 'inbound' ? groupInboundQcWorkOrders(props.rows) : []
|
||||
)
|
||||
|
||||
function cardIndex(i: number) {
|
||||
return (props.page - 1) * props.pageSize + i + 1
|
||||
}
|
||||
|
||||
function canConfigureWorkOrder(_row: QcWorkOrder) {
|
||||
return true
|
||||
}
|
||||
|
||||
function canEditTemporaryWorkOrder(row: QcWorkOrder) {
|
||||
return (
|
||||
props.activeTypeTab === 'temporary' ||
|
||||
(props.activeTypeTab === 'all' && row.workOrderType === 'temporary')
|
||||
)
|
||||
}
|
||||
|
||||
function canEditRemarkWorkOrder(row: QcWorkOrder) {
|
||||
if (props.activeTypeTab === 'inbound') return true
|
||||
if (props.activeTypeTab === 'all' && row.workOrderType !== 'temporary') return true
|
||||
if (
|
||||
props.activeTypeTab === 'outbound' &&
|
||||
row.workOrderStatus !== 'ywc' &&
|
||||
row.workOrderStatus !== 'yzf'
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function canDeleteWorkOrder(row: QcWorkOrder) {
|
||||
return (
|
||||
props.activeTypeTab !== 'outbound' &&
|
||||
props.activeTypeTab !== 'all' &&
|
||||
row.workOrderStatus !== 'ywc'
|
||||
)
|
||||
}
|
||||
|
||||
function hasMoreWorkOrderActions(row: QcWorkOrder) {
|
||||
if (canConfigureWorkOrder(row)) return true
|
||||
return (
|
||||
canEditTemporaryWorkOrder(row) ||
|
||||
canEditRemarkWorkOrder(row) ||
|
||||
canDeleteWorkOrder(row)
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -373,163 +96,14 @@
|
||||
}
|
||||
|
||||
.qc-work-order-cards-wrap {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(480px, 1fr));
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
min-height: 120px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.qc-work-order-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
border-color 0.15s ease,
|
||||
box-shadow 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: #a7f3d0;
|
||||
box-shadow: 0 2px 8px rgba(16, 185, 129, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
.qc-work-order-card__head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 10px;
|
||||
padding: 14px 16px;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.qc-work-order-card__head-main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.qc-work-order-card__title-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.qc-work-order-card__index {
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
.qc-work-order-card__no {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.qc-work-order-card__meta {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
gap: 8px 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.qc-work-order-card__meta-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
|
||||
dt {
|
||||
margin: 0;
|
||||
font-size: 11px;
|
||||
line-height: 1.35;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
color: #334155;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
&--wide {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-work-order-card__ops {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.qc-work-order-card__tasks {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 0 1 auto;
|
||||
padding: 12px 16px 14px;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.qc-work-order-card__tasks:has(.qc-task-cards-wrap--empty) {
|
||||
flex: 1 1 auto;
|
||||
min-height: 232px;
|
||||
}
|
||||
|
||||
.qc-work-order-cards-empty {
|
||||
grid-column: 1 / -1;
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
||||
.qc-work-order-card__tasks :deep(.qc-work-order-task-sublist) {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.qc-work-order-card__tasks:has(.qc-task-cards-wrap--empty) :deep(.qc-work-order-task-sublist) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.qc-work-order-card__tasks:has(.qc-task-cards-wrap--empty) :deep(.qc-work-order-task-sublist__panel) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.qc-work-order-card__tasks:has(.qc-task-cards-wrap--empty) :deep(.qc-task-cards-wrap--empty) {
|
||||
flex: 1;
|
||||
min-height: 204px;
|
||||
}
|
||||
|
||||
.qc-work-order-card__tasks:has(.qc-task-cards-wrap--empty) :deep(.qc-work-order-task-sublist__empty) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.qc-work-order-card__tasks :deep(.qc-task-cards-wrap:not(.qc-task-cards-wrap--empty)) {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,139 @@
|
||||
<!-- 质检工单 · 用户费用摘要条(采集协议 / 基础实验) -->
|
||||
<template>
|
||||
<div v-if="visible" class="qc-fee-summary">
|
||||
<span class="qc-fee-summary__label">{{ label }}</span>
|
||||
<template v-if="variant === 'protocol' && paymentSummary">
|
||||
<span v-if="paymentSummary.payModeLabel" class="qc-fee-summary__item">
|
||||
{{ paymentSummary.payModeLabel }}
|
||||
</span>
|
||||
<span class="qc-fee-summary__item">
|
||||
合同 {{ formatAmount(paymentSummary.contractAmount) }}
|
||||
</span>
|
||||
<span class="qc-fee-summary__item">
|
||||
已收 {{ formatAmount(paymentSummary.receivedAmount) }}
|
||||
</span>
|
||||
<span class="qc-fee-summary__item">
|
||||
待收 {{ formatAmount(paymentSummary.pendingAmount) }}
|
||||
</span>
|
||||
<span v-if="paymentSummary.statusHint" class="qc-fee-summary__hint">
|
||||
{{ paymentSummary.statusHint }}
|
||||
</span>
|
||||
<el-tag
|
||||
v-if="paymentSummary.overallPayStatusLabel"
|
||||
:type="protocolTagType"
|
||||
size="small"
|
||||
class="qc-fee-summary__tag"
|
||||
>
|
||||
{{ paymentSummary.overallPayStatusLabel }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<template v-else-if="variant === 'protocol'">
|
||||
<span class="qc-fee-summary__empty">暂无缴费信息</span>
|
||||
</template>
|
||||
<template v-else-if="variant === 'basic-experiment'">
|
||||
<span class="qc-fee-summary__item">
|
||||
售卖 {{ formatAmount(feeSummary?.saleAmount) }}
|
||||
</span>
|
||||
<template v-if="feeSummary?.paymentAmount != null">
|
||||
<span class="qc-fee-summary__item">
|
||||
应缴 {{ formatAmount(feeSummary.paymentAmount) }}
|
||||
</span>
|
||||
<span
|
||||
v-if="feeSummary.transferAmount != null"
|
||||
class="qc-fee-summary__item"
|
||||
>
|
||||
实收 {{ formatAmount(feeSummary.transferAmount) }}
|
||||
</span>
|
||||
<el-tag
|
||||
v-if="feeSummary.payStatusLabel"
|
||||
:type="basicPayTagType"
|
||||
size="small"
|
||||
class="qc-fee-summary__tag"
|
||||
>
|
||||
{{ feeSummary.payStatusLabel }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<span v-else class="qc-fee-summary__empty">暂无缴费记录</span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type {
|
||||
QcBasicExperimentFeeSummary,
|
||||
QcProtocolPaymentSummary
|
||||
} from '@/api/qc-work-order'
|
||||
import { formatMoneyDisplay } from '@/utils/money-format'
|
||||
import { payStatusTagType } from '@/utils/status-tag-registry'
|
||||
import type { TagType } from '@/utils/status-tag-registry'
|
||||
|
||||
defineOptions({ name: 'QcWorkOrderFeeSummaryBar' })
|
||||
|
||||
const props = defineProps<{
|
||||
variant: 'protocol' | 'basic-experiment'
|
||||
paymentSummary?: QcProtocolPaymentSummary | null
|
||||
feeSummary?: QcBasicExperimentFeeSummary | null
|
||||
visible?: boolean
|
||||
}>()
|
||||
|
||||
const visible = computed(() => props.visible !== false)
|
||||
|
||||
const label = computed(() =>
|
||||
props.variant === 'protocol' ? '协议费用' : '费用信息'
|
||||
)
|
||||
|
||||
const protocolTagType = computed((): TagType => {
|
||||
const t = props.paymentSummary?.overallPayStatusTagType
|
||||
if (t === 'success' || t === 'warning' || t === 'danger' || t === 'info') {
|
||||
return t
|
||||
}
|
||||
return 'info'
|
||||
})
|
||||
|
||||
const basicPayTagType = computed((): TagType =>
|
||||
payStatusTagType(props.feeSummary?.payStatus || '')
|
||||
)
|
||||
|
||||
function formatAmount(val?: number | null) {
|
||||
if (val == null || Number.isNaN(Number(val))) return '—'
|
||||
return `¥${formatMoneyDisplay(val)}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.qc-fee-summary {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 6px 12px;
|
||||
padding: 10px 16px;
|
||||
background: #ecfdf5;
|
||||
border-bottom: 1px solid #d1fae5;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.qc-fee-summary__label {
|
||||
flex-shrink: 0;
|
||||
font-weight: 600;
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.qc-fee-summary__item {
|
||||
color: #334155;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.qc-fee-summary__hint {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.qc-fee-summary__empty {
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.qc-fee-summary__tag {
|
||||
margin-left: auto;
|
||||
}
|
||||
</style>
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
<!-- 质检工单 · 采集协议缴费(汇总 + 分期明细表) -->
|
||||
<template>
|
||||
<section class="qc-protocol-payment" :class="{ 'qc-protocol-payment--embedded': embedded }">
|
||||
<div v-if="summary" class="qc-protocol-payment__head">
|
||||
<span v-if="!embedded" class="qc-protocol-payment__title">协议费用</span>
|
||||
<el-tag v-if="summary?.payModeLabel" :type="payModeTagType" size="small">
|
||||
{{ summary.payModeLabel }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-if="summary?.overallPayStatusLabel"
|
||||
:type="overallStatusTagType"
|
||||
size="small"
|
||||
>
|
||||
{{ summary.overallPayStatusLabel }}
|
||||
</el-tag>
|
||||
</div>
|
||||
|
||||
<template v-if="summary">
|
||||
<div class="qc-protocol-payment__metrics">
|
||||
<div class="qc-protocol-payment__metric">
|
||||
<span class="qc-protocol-payment__metric-label">合同金额</span>
|
||||
<span class="qc-protocol-payment__metric-value">{{
|
||||
formatAmount(summary.contractAmount)
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="qc-protocol-payment__metric">
|
||||
<span class="qc-protocol-payment__metric-label">已收金额</span>
|
||||
<span class="qc-protocol-payment__metric-value">{{
|
||||
formatAmount(summary.receivedAmount)
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="qc-protocol-payment__metric">
|
||||
<span class="qc-protocol-payment__metric-label">待收金额</span>
|
||||
<span class="qc-protocol-payment__metric-value">{{
|
||||
formatAmount(summary.pendingAmount)
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="detailRows.length" class="qc-protocol-payment__table-wrap">
|
||||
<div class="qc-protocol-payment__table-title">
|
||||
{{ isInstallment ? `缴费明细(共 ${detailRows.length} 期)` : '缴费明细' }}
|
||||
</div>
|
||||
<el-table
|
||||
:data="detailRows"
|
||||
stripe
|
||||
size="small"
|
||||
class="list-table qc-protocol-payment__table"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="isInstallment"
|
||||
prop="installmentLabel"
|
||||
label="期次"
|
||||
min-width="88"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
v-if="isInstallment"
|
||||
prop="installmentDueDate"
|
||||
label="应缴日期"
|
||||
min-width="110"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">{{ row.installmentDueDate || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="应缴金额" min-width="110" align="center">
|
||||
<template #default="{ row }">{{ formatAmount(row.dueAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="实收金额" min-width="110" align="center">
|
||||
<template #default="{ row }">{{ formatAmount(row.transferAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="缴费状态" min-width="108" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="payStatusTagType(row.payStatus)" size="small">
|
||||
{{ row.payStatusLabel || payStatusLabel(row.payStatus || '') }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<p v-else class="qc-protocol-payment__empty">暂无缴费明细</p>
|
||||
</template>
|
||||
<p v-else class="qc-protocol-payment__empty">暂无缴费信息</p>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { QcProtocolPaymentSummary } from '@/api/qc-work-order'
|
||||
import { formatMoneyDisplay } from '@/utils/money-format'
|
||||
import {
|
||||
payModeTagType as payModeTagTypeGetter,
|
||||
payStatusLabel,
|
||||
payStatusTagType
|
||||
} from '@/utils/status-tag-registry'
|
||||
import type { TagType } from '@/utils/status-tag-registry'
|
||||
|
||||
defineOptions({ name: 'QcWorkOrderProtocolPaymentPanel' })
|
||||
|
||||
const props = defineProps<{
|
||||
summary?: QcProtocolPaymentSummary | null
|
||||
/** 嵌入查看弹窗时隐藏区块标题,避免与 section 标题重复 */
|
||||
embedded?: boolean
|
||||
}>()
|
||||
|
||||
const isInstallment = computed(() => props.summary?.payMode === 'fq')
|
||||
|
||||
const detailRows = computed(() => props.summary?.paymentDetails || [])
|
||||
|
||||
const payModeTagType = computed((): TagType =>
|
||||
payModeTagTypeGetter(props.summary?.payMode || '')
|
||||
)
|
||||
|
||||
const overallStatusTagType = computed((): TagType => {
|
||||
const t = props.summary?.overallPayStatusTagType
|
||||
if (t === 'success' || t === 'warning' || t === 'danger' || t === 'info') return t
|
||||
return 'info'
|
||||
})
|
||||
|
||||
function formatAmount(val?: number | null) {
|
||||
if (val == null || Number.isNaN(Number(val))) return '—'
|
||||
return `¥${formatMoneyDisplay(val)}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.qc-protocol-payment {
|
||||
padding: 12px 16px;
|
||||
background: #ecfdf5;
|
||||
border-top: 1px solid #d1fae5;
|
||||
}
|
||||
|
||||
.qc-protocol-payment__head {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.qc-protocol-payment__title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.qc-protocol-payment__metrics {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px 24px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.qc-protocol-payment__metric {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.qc-protocol-payment__metric-label {
|
||||
font-size: 11px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.qc-protocol-payment__metric-value {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.qc-protocol-payment__table-title {
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.qc-protocol-payment__table-wrap {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.qc-protocol-payment__table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.qc-protocol-payment--embedded {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.qc-protocol-payment__empty {
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,261 @@
|
||||
<!-- 质检工单 · 同样本分组(上下文条 + Tab + 单工单卡片) -->
|
||||
<template>
|
||||
<article class="qc-sample-row">
|
||||
<div class="qc-sample-row__ctx">
|
||||
<span class="qc-sample-row__idx">{{ groupIndex }}</span>
|
||||
<span class="qc-sample-row__code">{{ contextRow.sampleCode || '—' }}</span>
|
||||
<span class="qc-sample-row__sub">{{ contextSubtitle }}</span>
|
||||
<span v-if="group.workOrders.length > 1" class="qc-sample-row__badge">
|
||||
{{ group.workOrders.length }} 条质检
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="group.workOrders.length > 1" class="qc-wo-tabs">
|
||||
<button
|
||||
v-for="wo in group.workOrders"
|
||||
:key="wo.id"
|
||||
type="button"
|
||||
class="qc-wo-tab"
|
||||
:class="{ active: wo.id === activeWorkOrderId }"
|
||||
@click="activeWorkOrderId = wo.id"
|
||||
>
|
||||
<span
|
||||
class="qc-wo-tab__dot"
|
||||
:class="
|
||||
(wo.triggerSource || 'reception') === 'production'
|
||||
? 'qc-wo-tab__dot--production'
|
||||
: 'qc-wo-tab__dot--reception'
|
||||
"
|
||||
></span>
|
||||
<span class="qc-wo-tab__no">{{ wo.workOrderNo }}</span>
|
||||
· {{ triggerSourceTabLabel(wo) }}
|
||||
<el-tag :type="workOrderStatusTagType(wo.workOrderStatus)" size="small" class="qc-wo-tab__status">
|
||||
{{ workOrderStatusLabel(wo.workOrderStatus) }}
|
||||
</el-tag>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<QcWorkOrderSingleCard
|
||||
v-if="activeRow"
|
||||
layout="inbound-grouped"
|
||||
:row="activeRow"
|
||||
:active-type-tab="activeTypeTab"
|
||||
:task-refresh-token="taskRefreshToken"
|
||||
@configure="(row) => emit('configure', row)"
|
||||
@view="(row) => emit('view', row)"
|
||||
@command="(cmd, row) => emit('command', cmd, row)"
|
||||
@tasks-changed="emit('tasks-changed')"
|
||||
/>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import type { QcWorkOrder } from '@/api/qc-work-order'
|
||||
import { workOrderStatusLabel } from '@/utils/qc-labels'
|
||||
import {
|
||||
protocolStatusLabel,
|
||||
donationStatusLabel
|
||||
} from '@/utils/status-tag-registry'
|
||||
import type { TagType } from '@/utils/status-tag-registry'
|
||||
import {
|
||||
type QcWorkOrderSampleGroupModel,
|
||||
triggerSourceTabLabel
|
||||
} from '@/utils/qc-work-order-groups'
|
||||
import QcWorkOrderSingleCard from './QcWorkOrderSingleCard.vue'
|
||||
|
||||
defineOptions({ name: 'QcWorkOrderSampleGroup' })
|
||||
|
||||
const props = defineProps<{
|
||||
group: QcWorkOrderSampleGroupModel
|
||||
groupIndex: number
|
||||
activeTypeTab: 'inbound' | 'temporary' | 'outbound' | 'all'
|
||||
taskRefreshToken: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
configure: [row: QcWorkOrder]
|
||||
view: [row: QcWorkOrder]
|
||||
command: [cmd: string, row: QcWorkOrder]
|
||||
'tasks-changed': []
|
||||
}>()
|
||||
|
||||
const activeWorkOrderId = ref(props.group.workOrders[0]?.id || '')
|
||||
|
||||
watch(
|
||||
() => props.group.workOrders.map((w) => w.id).join(','),
|
||||
() => {
|
||||
const ids = props.group.workOrders.map((w) => w.id)
|
||||
if (!ids.includes(activeWorkOrderId.value)) {
|
||||
activeWorkOrderId.value = ids[0] || ''
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const activeRow = computed(() =>
|
||||
props.group.workOrders.find((w) => w.id === activeWorkOrderId.value)
|
||||
)
|
||||
|
||||
const contextRow = computed(() => {
|
||||
const reception =
|
||||
props.group.workOrders.find((w) => (w.triggerSource || 'reception') === 'reception') ||
|
||||
props.group.workOrders[0]
|
||||
return reception
|
||||
})
|
||||
|
||||
function protocolStatusLabelBySource(status: string, source: string): string {
|
||||
return source === 'research_donation' ? donationStatusLabel(status) : protocolStatusLabel(status)
|
||||
}
|
||||
|
||||
const contextSubtitle = computed(() => {
|
||||
const row = contextRow.value
|
||||
if (!row) return '—'
|
||||
const parts: string[] = []
|
||||
if (row.sampleTypeName) parts.push(row.sampleTypeName)
|
||||
if (row.protocolNo) parts.push(`协议 ${row.protocolNo}`)
|
||||
if (row.protocolStatus) {
|
||||
parts.push(
|
||||
protocolStatusLabelBySource(String(row.protocolStatus), row.receptionSource || 'cell_storage')
|
||||
)
|
||||
}
|
||||
if (row.receptionTime) parts.push(`接收 ${row.receptionTime}`)
|
||||
if (row.handlerName) parts.push(row.handlerName)
|
||||
return parts.length ? parts.join(' · ') : '—'
|
||||
})
|
||||
|
||||
function workOrderStatusTagType(status: string): TagType {
|
||||
if (status === 'ywc') return 'success'
|
||||
if (status === 'ypz') return 'warning'
|
||||
if (status === 'yzf') return 'danger'
|
||||
return 'info'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.qc-sample-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
border-color 0.15s ease,
|
||||
box-shadow 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: #a7f3d0;
|
||||
box-shadow: 0 2px 8px rgba(16, 185, 129, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
.qc-sample-row__ctx {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px 12px;
|
||||
padding: 12px 16px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.qc-sample-row__idx {
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
.qc-sample-row__code {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
}
|
||||
|
||||
.qc-sample-row__sub {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.qc-sample-row__badge {
|
||||
flex-shrink: 0;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
color: #059669;
|
||||
border: 1px solid #a7f3d0;
|
||||
}
|
||||
|
||||
.qc-wo-tabs {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
background: #fafafa;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.qc-wo-tab {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 10px 16px;
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
transition:
|
||||
color 0.12s ease,
|
||||
background 0.12s ease;
|
||||
|
||||
&:hover {
|
||||
color: #334155;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #059669;
|
||||
font-weight: 600;
|
||||
border-bottom-color: #10b981;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-wo-tab__no {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
}
|
||||
|
||||
.qc-wo-tab__dot {
|
||||
display: inline-block;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
|
||||
&--reception {
|
||||
background: #3b82f6;
|
||||
}
|
||||
|
||||
&--production {
|
||||
background: #10b981;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-wo-tab__status {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.qc-sample-row :deep(.qc-work-order-card) {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,520 @@
|
||||
<!-- 质检工单 · 单工单卡片(head + 任务区) -->
|
||||
<template>
|
||||
<article class="qc-work-order-card">
|
||||
<header class="qc-work-order-card__head">
|
||||
<div class="qc-work-order-card__head-inner">
|
||||
<div class="qc-work-order-card__head-main">
|
||||
<div class="qc-work-order-card__title-row">
|
||||
<span v-if="cardIndex != null" class="qc-work-order-card__index">{{ cardIndex }}</span>
|
||||
<span class="qc-work-order-card__no">{{ row.workOrderNo || '—' }}</span>
|
||||
<el-tag :type="workOrderStatusTagType(row.workOrderStatus)" size="small">
|
||||
{{ workOrderStatusLabel(row.workOrderStatus) }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-if="showTriggerTag"
|
||||
:type="triggerSourceTagType(row.triggerSource)"
|
||||
size="small"
|
||||
>
|
||||
{{ row.triggerSourceLabel || triggerSourceTabLabel(row) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<dl class="qc-work-order-card__meta">
|
||||
<template v-if="activeTypeTab === 'outbound'">
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>业务类型</dt>
|
||||
<dd>
|
||||
<el-tag
|
||||
:type="
|
||||
row.bizType === 'pilot_service'
|
||||
? 'primary'
|
||||
: row.bizType === 'clinical_application'
|
||||
? 'warning'
|
||||
: 'info'
|
||||
"
|
||||
size="small"
|
||||
>
|
||||
{{ row.bizTypeLabel || '—' }}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>申请单号</dt>
|
||||
<dd>{{ row.applicationNo || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>用户名称</dt>
|
||||
<dd>{{ row.patientName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>第几次</dt>
|
||||
<dd>{{ formatOutboundScheduleSortNo(row) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>总次数</dt>
|
||||
<dd>{{ formatOutboundScheduleTotalCount(row) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>申请单名称</dt>
|
||||
<dd>{{ row.applicationName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>渠道名称</dt>
|
||||
<dd>{{ row.channelName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>输注时间</dt>
|
||||
<dd>{{ row.infusionTime || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>来源类型</dt>
|
||||
<dd>
|
||||
<el-tag
|
||||
:type="row.receptionSource === 'research_donation' ? 'warning' : 'success'"
|
||||
size="small"
|
||||
>
|
||||
{{ row.receptionSourceLabel || receptionSourceLabel(row.receptionSource || '') }}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="activeTypeTab === 'temporary'">
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>业务类型</dt>
|
||||
<dd>
|
||||
<el-tag :type="qcBizTypeTagType('temporary')" size="small">
|
||||
{{ row.qcBizTypeLabel || qcBizTypeLabel('temporary') }}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>产品编码</dt>
|
||||
<dd>{{ formatTempCellProductField(row, row.cellProductCode) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>产品名称</dt>
|
||||
<dd>{{ formatTempCellProductField(row, row.cellProductName) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>产品类型</dt>
|
||||
<dd>{{ formatTempCellProductField(row, row.cellProductTypeName) }}</dd>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="layout === 'inbound-grouped'">
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>质检对象</dt>
|
||||
<dd>{{ formatQcTarget(row) }}</dd>
|
||||
</div>
|
||||
<div
|
||||
v-if="(row.triggerSource || 'reception') === 'production'"
|
||||
class="qc-work-order-card__meta-item"
|
||||
>
|
||||
<dt>关联生产工单</dt>
|
||||
<dd>{{ row.productionWorkOrderNo || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>实验室入库编码</dt>
|
||||
<dd>{{ row.labStorageCode || '—' }}</dd>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>样本编码</dt>
|
||||
<dd>{{ formatTempEmptyField(row, row.sampleCode) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>实验室入库编码</dt>
|
||||
<dd>{{ formatTempEmptyField(row, row.labStorageCode) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>来源类型</dt>
|
||||
<dd>
|
||||
<span v-if="shouldShowTempEmptyField(row, row.receptionSource)">—</span>
|
||||
<el-tag
|
||||
v-else
|
||||
:type="row.receptionSource === 'research_donation' ? 'warning' : 'success'"
|
||||
size="small"
|
||||
>
|
||||
{{ row.receptionSourceLabel || receptionSourceLabel(row.receptionSource || '') }}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>协议状态</dt>
|
||||
<dd>
|
||||
<span v-if="shouldShowTempEmptyField(row, row.protocolStatus)">—</span>
|
||||
<el-tag
|
||||
v-else
|
||||
:type="
|
||||
protocolStatusTagTypeBySource(
|
||||
String(row.protocolStatus || ''),
|
||||
row.receptionSource || 'cell_storage'
|
||||
)
|
||||
"
|
||||
size="small"
|
||||
>
|
||||
{{
|
||||
protocolStatusLabelBySource(
|
||||
String(row.protocolStatus || ''),
|
||||
row.receptionSource || 'cell_storage'
|
||||
)
|
||||
}}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>样本类型</dt>
|
||||
<dd>{{ row.sampleTypeName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>接收时间</dt>
|
||||
<dd>{{ row.receptionTime || '—' }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>接收经手人</dt>
|
||||
<dd>{{ row.handlerName || '—' }}</dd>
|
||||
</div>
|
||||
</template>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>检测方式</dt>
|
||||
<dd>{{ formatDetectMethods(row) }}</dd>
|
||||
</div>
|
||||
<div class="qc-work-order-card__meta-item">
|
||||
<dt>创建时间</dt>
|
||||
<dd>{{ row.createTime || '—' }}</dd>
|
||||
</div>
|
||||
<div v-if="row.remark" class="qc-work-order-card__meta-item qc-work-order-card__meta-item--wide">
|
||||
<dt>备注</dt>
|
||||
<dd>{{ row.remark }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
<div v-if="activeTypeTab !== 'all'" class="qc-work-order-card__ops">
|
||||
<el-button
|
||||
v-if="canConfigureWorkOrder(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
@click="emit('configure', row)"
|
||||
>
|
||||
<el-icon><Setting /></el-icon
|
||||
>{{ row.workOrderStatus !== 'dpz' ? '调整检测' : '配置检测' }}
|
||||
</el-button>
|
||||
<el-button v-else class="btn-op-item primary" @click="emit('view', row)">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="hasMoreWorkOrderActions(row)"
|
||||
trigger="hover"
|
||||
@command="(cmd) => emit('command', cmd, row)"
|
||||
>
|
||||
<el-button class="btn-op-item">
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="canConfigureWorkOrder(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="canEditTemporaryWorkOrder(row) || canEditRemarkWorkOrder(row)"
|
||||
command="edit"
|
||||
>
|
||||
<el-icon><EditPen /></el-icon>编辑
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteWorkOrder(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<QcWorkOrderProtocolPaymentPanel
|
||||
v-if="showProtocolFeeSummary"
|
||||
:summary="row.paymentSummary"
|
||||
/>
|
||||
<QcWorkOrderFeeSummaryBar
|
||||
v-if="showBasicExperimentFeeSummary"
|
||||
variant="basic-experiment"
|
||||
:fee-summary="row.feeSummary"
|
||||
class="qc-work-order-card__fee-in-head"
|
||||
/>
|
||||
</header>
|
||||
<section v-if="activeTypeTab !== 'all'" class="qc-work-order-card__tasks">
|
||||
<QcWorkOrderTaskSubList
|
||||
embedded
|
||||
:work-order="row"
|
||||
:refresh-token="taskRefreshToken"
|
||||
@changed="emit('tasks-changed')"
|
||||
/>
|
||||
</section>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { Setting, View, More, EditPen, Delete } from '@element-plus/icons-vue'
|
||||
import type { QcWorkOrder } from '@/api/qc-work-order'
|
||||
import {
|
||||
workOrderStatusLabel,
|
||||
receptionSourceLabel,
|
||||
qcBizTypeLabel
|
||||
} from '@/utils/qc-labels'
|
||||
import {
|
||||
protocolStatusLabel,
|
||||
protocolStatusTagType,
|
||||
donationStatusLabel,
|
||||
donationStatusTagType,
|
||||
qcBizTypeTagType
|
||||
} from '@/utils/status-tag-registry'
|
||||
import type { TagType } from '@/utils/status-tag-registry'
|
||||
import { triggerSourceTabLabel } from '@/utils/qc-work-order-groups'
|
||||
import QcWorkOrderTaskSubList from './QcWorkOrderTaskSubList.vue'
|
||||
import QcWorkOrderFeeSummaryBar from './QcWorkOrderFeeSummaryBar.vue'
|
||||
import QcWorkOrderProtocolPaymentPanel from './QcWorkOrderProtocolPaymentPanel.vue'
|
||||
|
||||
defineOptions({ name: 'QcWorkOrderSingleCard' })
|
||||
|
||||
type WorkOrderTypeTab = 'inbound' | 'temporary' | 'outbound' | 'all'
|
||||
type CardLayout = 'standalone' | 'inbound-grouped'
|
||||
|
||||
const props = defineProps<{
|
||||
row: QcWorkOrder
|
||||
activeTypeTab: WorkOrderTypeTab
|
||||
layout?: CardLayout
|
||||
cardIndex?: number | null
|
||||
taskRefreshToken: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
configure: [row: QcWorkOrder]
|
||||
view: [row: QcWorkOrder]
|
||||
command: [cmd: string, row: QcWorkOrder]
|
||||
'tasks-changed': []
|
||||
}>()
|
||||
|
||||
const layout = computed(() => props.layout || 'standalone')
|
||||
const showTriggerTag = computed(
|
||||
() => props.activeTypeTab === 'inbound' && layout.value === 'inbound-grouped'
|
||||
)
|
||||
|
||||
const showBasicExperimentFeeSummary = computed(
|
||||
() => props.activeTypeTab === 'outbound' && props.row.bizType === 'basic_experiment'
|
||||
)
|
||||
|
||||
const showProtocolFeeSummary = computed(() => {
|
||||
const woType = props.row.workOrderType || 'inbound'
|
||||
if (woType === 'outbound' || woType === 'temporary') return false
|
||||
const source = (props.row.receptionSource || 'cell_storage').trim()
|
||||
return source === 'cell_storage' || source === ''
|
||||
})
|
||||
|
||||
function protocolStatusLabelBySource(status: string, source: string): string {
|
||||
return source === 'research_donation' ? donationStatusLabel(status) : protocolStatusLabel(status)
|
||||
}
|
||||
|
||||
function protocolStatusTagTypeBySource(status: string, source: string): TagType {
|
||||
return source === 'research_donation' ? donationStatusTagType(status) : protocolStatusTagType(status)
|
||||
}
|
||||
|
||||
function shouldShowTempEmptyField(row: QcWorkOrder, value?: string | null) {
|
||||
return row.workOrderType === 'temporary' && !String(value || '').trim()
|
||||
}
|
||||
|
||||
function formatTempEmptyField(row: QcWorkOrder, value?: string | null) {
|
||||
return shouldShowTempEmptyField(row, value) ? '—' : String(value || '')
|
||||
}
|
||||
|
||||
function formatTempCellProductField(row: QcWorkOrder, value?: string | null) {
|
||||
if (row.workOrderType !== 'temporary') return '—'
|
||||
return String(value || '').trim() || '—'
|
||||
}
|
||||
|
||||
function formatOutboundScheduleSortNo(row: Record<string, unknown>) {
|
||||
const n = row.sortNo ?? row.orderNum
|
||||
if (n == null || n === '' || Number(n) <= 0) return '—'
|
||||
return `第${Number(n)}次`
|
||||
}
|
||||
|
||||
function formatOutboundScheduleTotalCount(row: Record<string, unknown>) {
|
||||
const n = row.totalCourseCount
|
||||
if (n == null || n === '' || Number(n) <= 0) return '—'
|
||||
return `共${Number(n)}次`
|
||||
}
|
||||
|
||||
function formatDetectMethods(row: QcWorkOrder) {
|
||||
const parts: string[] = []
|
||||
if (row.hasLab) parts.push('实验室')
|
||||
if (row.hasThirdParty) parts.push('第三方')
|
||||
return parts.length ? parts.join(' / ') : '—'
|
||||
}
|
||||
|
||||
function formatQcTarget(row: QcWorkOrder) {
|
||||
if ((row.triggerSource || 'reception') === 'production') {
|
||||
const parts = [row.cellProductCode, row.cellProductName].filter(Boolean)
|
||||
return parts.length ? parts.join(' · ') : '—'
|
||||
}
|
||||
return '原始样本'
|
||||
}
|
||||
|
||||
function triggerSourceTagType(source?: string): TagType {
|
||||
return (source || 'reception') === 'production' ? 'warning' : 'primary'
|
||||
}
|
||||
|
||||
function workOrderStatusTagType(status: string): TagType {
|
||||
if (status === 'ywc') return 'success'
|
||||
if (status === 'ypz') return 'warning'
|
||||
if (status === 'yzf') return 'danger'
|
||||
return 'info'
|
||||
}
|
||||
|
||||
function canConfigureWorkOrder(_row: QcWorkOrder) {
|
||||
return true
|
||||
}
|
||||
|
||||
function canEditTemporaryWorkOrder(row: QcWorkOrder) {
|
||||
return (
|
||||
props.activeTypeTab === 'temporary' ||
|
||||
(props.activeTypeTab === 'all' && row.workOrderType === 'temporary')
|
||||
)
|
||||
}
|
||||
|
||||
function canEditRemarkWorkOrder(row: QcWorkOrder) {
|
||||
if (props.activeTypeTab === 'inbound') return true
|
||||
if (props.activeTypeTab === 'all' && row.workOrderType !== 'temporary') return true
|
||||
if (
|
||||
props.activeTypeTab === 'outbound' &&
|
||||
row.workOrderStatus !== 'ywc' &&
|
||||
row.workOrderStatus !== 'yzf'
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function canDeleteWorkOrder(row: QcWorkOrder) {
|
||||
return (
|
||||
props.activeTypeTab !== 'outbound' &&
|
||||
props.activeTypeTab !== 'all' &&
|
||||
row.workOrderStatus !== 'ywc'
|
||||
)
|
||||
}
|
||||
|
||||
function hasMoreWorkOrderActions(row: QcWorkOrder) {
|
||||
if (canConfigureWorkOrder(row)) return true
|
||||
return canEditTemporaryWorkOrder(row) || canEditRemarkWorkOrder(row) || canDeleteWorkOrder(row)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.qc-work-order-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.qc-work-order-card__head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 14px 16px;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.qc-work-order-card__head-inner {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
gap: 12px 20px;
|
||||
}
|
||||
|
||||
.qc-work-order-card__head-main {
|
||||
flex: 1;
|
||||
min-width: 280px;
|
||||
}
|
||||
|
||||
.qc-work-order-card__title-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.qc-work-order-card__index {
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
.qc-work-order-card__no {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.qc-work-order-card__meta {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
gap: 8px 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.qc-work-order-card__meta-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
|
||||
dt {
|
||||
margin: 0;
|
||||
font-size: 11px;
|
||||
line-height: 1.35;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
color: #334155;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
&--wide {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-work-order-card__fee-in-head {
|
||||
margin: 10px -16px -14px;
|
||||
border-top: 1px solid #d1fae5;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.qc-work-order-card__ops {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.qc-work-order-card__tasks {
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.qc-work-order-card__tasks :deep(.qc-work-order-task-sublist) {
|
||||
padding: 10px 14px 12px;
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
@@ -3,7 +3,10 @@
|
||||
<template>
|
||||
<div
|
||||
class="qc-work-order-task-sublist"
|
||||
:class="{ 'qc-work-order-task-sublist--mine': listMode === 'mine' }"
|
||||
:class="{
|
||||
'qc-work-order-task-sublist--mine': listMode === 'mine',
|
||||
'qc-work-order-task-sublist--embedded': embedded
|
||||
}"
|
||||
>
|
||||
<div class="qc-work-order-task-sublist__panel" v-loading="loading">
|
||||
<div
|
||||
@@ -26,7 +29,10 @@
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-task-cards-row">
|
||||
<div
|
||||
v-if="listMode === 'mine'"
|
||||
class="qc-task-cards-row"
|
||||
>
|
||||
<div
|
||||
v-for="(row, idx) in tableData"
|
||||
:key="row.id || idx"
|
||||
@@ -51,7 +57,7 @@
|
||||
</el-tag>
|
||||
<el-tag v-else type="info" size="small">待结论</el-tag>
|
||||
</div>
|
||||
<div v-if="listMode === 'mine'" class="qc-task-card__context">
|
||||
<div class="qc-task-card__context">
|
||||
<span v-if="row.workOrderNo" class="qc-task-card__context-item"
|
||||
>工单 {{ row.workOrderNo }}</span
|
||||
>
|
||||
@@ -70,56 +76,141 @@
|
||||
{{ row.assigneeUserNames ? `负责人:${row.assigneeUserNames}` : '负责人:—' }}
|
||||
</div>
|
||||
<div class="qc-work-order-task-sublist__ops">
|
||||
<template v-if="hasPrimaryTaskActions(row)">
|
||||
<el-button
|
||||
v-if="canStartTask(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleStart(row)"
|
||||
>
|
||||
<el-icon><VideoPlay /></el-icon>开始
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canFillResult(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="openResult(row)"
|
||||
>
|
||||
<el-icon><EditPen /></el-icon>填写结果
|
||||
</el-button>
|
||||
</template>
|
||||
<el-button
|
||||
v-else
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleView(row)"
|
||||
>
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="hasMoreTaskActions(row)"
|
||||
trigger="hover"
|
||||
@command="(cmd) => handleDropdownCommand(cmd, row)"
|
||||
>
|
||||
<el-button class="btn-op-item" size="small" @click.stop>
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="hasPrimaryTaskActions(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteTask(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
<template v-if="hasPrimaryTaskActions(row)">
|
||||
<el-button
|
||||
v-if="canStartTask(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleStart(row)"
|
||||
>
|
||||
<el-icon><VideoPlay /></el-icon>开始
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canFillResult(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="openResult(row)"
|
||||
>
|
||||
<el-icon><EditPen /></el-icon>填写结果
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-button
|
||||
v-else
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleView(row)"
|
||||
>
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="hasMoreTaskActions(row)"
|
||||
trigger="hover"
|
||||
@command="(cmd) => handleDropdownCommand(cmd, row)"
|
||||
>
|
||||
<el-button class="btn-op-item" size="small" @click.stop>
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="hasPrimaryTaskActions(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteTask(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="qc-task-cards-grid">
|
||||
<div
|
||||
v-for="(row, idx) in tableData"
|
||||
:key="row.id || idx"
|
||||
class="qc-task-card qc-task-card--compact"
|
||||
@dblclick="handleView(row)"
|
||||
>
|
||||
<div class="qc-task-card__line qc-task-card__line--top">
|
||||
<span class="qc-task-card__name">{{ row.itemName || row.taskNo || '—' }}</span>
|
||||
<div class="qc-task-card__tags">
|
||||
<el-tag :type="taskStatusTagType(row.taskStatus)" size="small">
|
||||
{{ taskStatusLabel(row.taskStatus) }}
|
||||
</el-tag>
|
||||
<el-tag :type="taskTypeTagType(row.taskType)" size="small">
|
||||
{{ taskTypeLabel(row.taskType) }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-if="row.conclusion === 'tg' || row.conclusion === 'btg'"
|
||||
:type="conclusionTagType(row.conclusion)"
|
||||
size="small"
|
||||
>
|
||||
{{ row.conclusionLabel || qcTaskConclusionLabel(row.conclusion) }}
|
||||
</el-tag>
|
||||
<el-tag v-else type="info" size="small">待结论</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-task-card__line qc-task-card__line--bottom">
|
||||
<span class="qc-task-card__code">{{ row.taskNo || '—' }}</span>
|
||||
<span class="qc-task-card__sep">·</span>
|
||||
<span class="qc-task-card__assignees">{{
|
||||
row.assigneeUserNames || '—'
|
||||
}}</span>
|
||||
<div class="qc-work-order-task-sublist__ops">
|
||||
<template v-if="hasPrimaryTaskActions(row)">
|
||||
<el-button
|
||||
v-if="canStartTask(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleStart(row)"
|
||||
>
|
||||
<el-icon><VideoPlay /></el-icon>开始
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canFillResult(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="openResult(row)"
|
||||
>
|
||||
<el-icon><EditPen /></el-icon>填写结果
|
||||
</el-button>
|
||||
</template>
|
||||
<el-button
|
||||
v-else
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleView(row)"
|
||||
>
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="hasMoreTaskActions(row)"
|
||||
trigger="hover"
|
||||
@command="(cmd) => handleDropdownCommand(cmd, row)"
|
||||
>
|
||||
<el-button class="btn-op-item" size="small" @click.stop>
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="hasPrimaryTaskActions(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteTask(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -590,6 +681,8 @@
|
||||
pageSize?: number
|
||||
/** 父级配置检测成功后递增,用于刷新已展开子列表 */
|
||||
refreshToken?: number
|
||||
/** 内嵌于工单卡片时收紧布局 */
|
||||
embedded?: boolean
|
||||
}>(),
|
||||
{
|
||||
listMode: 'workOrder',
|
||||
@@ -1487,6 +1580,11 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
&--embedded {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-work-order-task-sublist__panel {
|
||||
@@ -1510,6 +1608,24 @@
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.qc-task-cards-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.qc-task-cards-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.qc-task-cards-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-work-order-task-sublist__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1616,6 +1732,54 @@
|
||||
border-color: #a7f3d0;
|
||||
box-shadow: 0 2px 6px rgba(16, 185, 129, 0.1);
|
||||
}
|
||||
|
||||
&--compact {
|
||||
min-height: 68px;
|
||||
flex: unset;
|
||||
width: auto;
|
||||
max-width: none;
|
||||
gap: 5px;
|
||||
padding: 7px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-task-card__line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
|
||||
&--top {
|
||||
flex-wrap: wrap;
|
||||
row-gap: 4px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&--bottom {
|
||||
flex-wrap: wrap;
|
||||
row-gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-task-card__sep {
|
||||
flex-shrink: 0;
|
||||
color: #cbd5e1;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.qc-task-card--compact .qc-task-card__name {
|
||||
min-height: auto;
|
||||
-webkit-line-clamp: 1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.qc-task-card--compact .qc-task-card__assignees {
|
||||
min-height: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.qc-task-card--compact .qc-work-order-task-sublist__ops {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.qc-task-card__name {
|
||||
|
||||
@@ -46,10 +46,22 @@
|
||||
<el-option label="已作废" value="yzf" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeTypeTab === 'inbound'" label="触发来源">
|
||||
<el-select
|
||||
v-model="searchForm.triggerSource"
|
||||
placeholder="全部"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option label="样本接收" value="reception" />
|
||||
<el-option label="生产过程" value="production" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeTypeTab === 'outbound'" label="业务类型">
|
||||
<el-select v-model="searchForm.bizType" placeholder="全部" clearable style="width: 100%">
|
||||
<el-option label="中试服务" value="pilot_service" />
|
||||
<el-option label="临床应用" value="clinical_application" />
|
||||
<el-option label="基础实验" value="basic_experiment" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="filterTimeLabel">
|
||||
@@ -267,6 +279,9 @@
|
||||
:sections="viewSections"
|
||||
modal-class="qc-work-order-view-dialog-mask"
|
||||
>
|
||||
<template #protocol-payment-details>
|
||||
<QcWorkOrderProtocolPaymentPanel :summary="detail?.paymentSummary" embedded />
|
||||
</template>
|
||||
<template #reception-extra>
|
||||
<div class="view-reception-attachments">
|
||||
<div class="view-kv view-kv-span-2">
|
||||
@@ -445,6 +460,7 @@
|
||||
<script setup lang="ts">
|
||||
import { formatMoneyDisplay } from '@/utils/money-format'
|
||||
import { ref, reactive, computed, onMounted, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
Close,
|
||||
@@ -511,9 +527,12 @@
|
||||
import WorkOrderRemarkDialog from '@/components/business/work-order-remark-dialog/index.vue'
|
||||
import OutboundQcViewDialog from './OutboundQcViewDialog.vue'
|
||||
import QcWorkOrderCardList from './QcWorkOrderCardList.vue'
|
||||
import QcWorkOrderProtocolPaymentPanel from './QcWorkOrderProtocolPaymentPanel.vue'
|
||||
|
||||
defineOptions({ name: 'QualityInspectionQcWorkOrder' })
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const taskSubListRefreshToken = ref(0)
|
||||
|
||||
type WorkOrderTypeTab = 'inbound' | 'temporary' | 'outbound' | 'all'
|
||||
@@ -700,6 +719,9 @@
|
||||
|
||||
function handleTypeTabChange() {
|
||||
pagination.page = 1
|
||||
if (activeTypeTab.value !== 'inbound') {
|
||||
searchForm.triggerSource = ''
|
||||
}
|
||||
loadData()
|
||||
}
|
||||
|
||||
@@ -745,7 +767,7 @@
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const searchForm = reactive({ keyword: '', workOrderStatus: '', bizType: '' })
|
||||
const searchForm = reactive({ keyword: '', workOrderStatus: '', bizType: '', triggerSource: '' })
|
||||
const createTimeRange = ref<[string, string] | null>(getDefaultLast30DaysRange())
|
||||
const tableData = ref<QcWorkOrder[]>([])
|
||||
const loading = ref(false)
|
||||
@@ -1111,6 +1133,10 @@
|
||||
transportFields.length > 1 || r.transportType
|
||||
? [{ title: '运输信息', fields: transportFields }]
|
||||
: []
|
||||
const paymentSection =
|
||||
!isTemp && (d.receptionSource || 'cell_storage') === 'cell_storage'
|
||||
? [{ title: '协议缴费信息', fields: [], slot: 'protocol-payment-details' }]
|
||||
: []
|
||||
|
||||
return [
|
||||
{
|
||||
@@ -1178,6 +1204,7 @@
|
||||
]
|
||||
},
|
||||
...(isTemp ? [] : transportSection),
|
||||
...(isTemp ? [] : paymentSection),
|
||||
...(isTemp
|
||||
? []
|
||||
: [
|
||||
@@ -1272,6 +1299,10 @@
|
||||
workOrderStatus: searchForm.workOrderStatus || undefined,
|
||||
workOrderType: activeTypeTab.value === 'all' ? undefined : activeTypeTab.value,
|
||||
bizType: searchForm.bizType || undefined,
|
||||
triggerSource:
|
||||
activeTypeTab.value === 'inbound' && searchForm.triggerSource
|
||||
? searchForm.triggerSource
|
||||
: undefined,
|
||||
...timeParams
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
@@ -1289,6 +1320,7 @@
|
||||
searchForm.keyword = ''
|
||||
searchForm.workOrderStatus = ''
|
||||
searchForm.bizType = ''
|
||||
searchForm.triggerSource = ''
|
||||
createTimeRange.value = getDefaultLast30DaysRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
@@ -1445,6 +1477,11 @@
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
const sampleCode = String(route.query.sampleCode || '').trim()
|
||||
if (sampleCode) {
|
||||
activeTypeTab.value = 'inbound'
|
||||
searchForm.keyword = sampleCode
|
||||
}
|
||||
loadData()
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in new issue
Block a user