提交
This commit is contained in:
1 parent
ad0e849f6d
commit
14f1a84bb3
32 files changed
+8199
-5193
No files matched your search
+1
-1
@@ -1 +1 @@
|
||||
37832
|
||||
39408
|
||||
@@ -1547,22 +1547,36 @@ async def set_production_task_outputs(
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@router.get("/cell-products/next-code")
|
||||
async def get_next_cell_product_code(
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
code = cell_product_svc.get_next_code(db, tenant_no)
|
||||
return success_response({"code": code})
|
||||
|
||||
|
||||
@router.get("/cell-products")
|
||||
async def list_cell_products(
|
||||
page: int = Query(1, ge=1),
|
||||
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
|
||||
keyword: Optional[str] = None,
|
||||
productCode: Optional[str] = None,
|
||||
productName: Optional[str] = None,
|
||||
productTypeId: Optional[str] = None,
|
||||
productStatus: Optional[str] = None,
|
||||
passage: Optional[str] = None,
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
result = cell_product_svc.list_cell_products(
|
||||
db, tenant_no=tenant_no, page=page, page_size=pageSize,
|
||||
keyword=keyword,
|
||||
product_code=productCode, product_name=productName,
|
||||
product_type_id=productTypeId, product_status=productStatus,
|
||||
passage=passage,
|
||||
user_info=user,
|
||||
)
|
||||
items = result.get("items", [])
|
||||
@@ -1581,7 +1595,7 @@ async def get_cell_product_detail(
|
||||
obj = cell_product_svc.get_cell_product(db, product_id, tenant_no)
|
||||
if not obj:
|
||||
return error_response(404, "细胞产品不存在")
|
||||
return success_response(cell_product_svc._row_to_dict(obj))
|
||||
return success_response(cell_product_svc.product_to_response(db, tenant_no, obj))
|
||||
|
||||
|
||||
@router.post("/cell-products")
|
||||
@@ -1596,7 +1610,9 @@ async def create_cell_product(
|
||||
db, tenant_no=tenant_no, user_id=user.get("user_id"),
|
||||
create_dept_id="", data=body,
|
||||
)
|
||||
return success_response(cell_product_svc._row_to_dict(obj), message="创建成功")
|
||||
return success_response(
|
||||
cell_product_svc.product_to_response(db, tenant_no, obj), message="创建成功"
|
||||
)
|
||||
except ValueError as e:
|
||||
return error_response(400, str(e))
|
||||
|
||||
@@ -1613,7 +1629,9 @@ async def update_cell_product(
|
||||
obj = cell_product_svc.update_cell_product(
|
||||
db, product_id, tenant_no, user.get("user_id"), data=body,
|
||||
)
|
||||
return success_response(cell_product_svc._row_to_dict(obj), message="更新成功")
|
||||
return success_response(
|
||||
cell_product_svc.product_to_response(db, tenant_no, obj), message="更新成功"
|
||||
)
|
||||
except ValueError as e:
|
||||
return error_response(400, str(e))
|
||||
|
||||
|
||||
@@ -9,7 +9,13 @@ from sqlalchemy import and_, func, or_
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.utils import generate_uuid
|
||||
from app.models.models import BizCellProduct
|
||||
from app.models.models import (
|
||||
BizCellProduct,
|
||||
BizCellProductSpec,
|
||||
BizCellProductType,
|
||||
BizStorageFacility,
|
||||
BizStorageFacilitySlot,
|
||||
)
|
||||
|
||||
|
||||
def _row_to_dict(c: BizCellProduct) -> Dict[str, Any]:
|
||||
@@ -18,9 +24,16 @@ def _row_to_dict(c: BizCellProduct) -> Dict[str, Any]:
|
||||
"productCode": c.product_code,
|
||||
"productName": c.product_name,
|
||||
"productTypeId": c.product_type_id or "",
|
||||
"productTypeName": "",
|
||||
"specId": c.spec_id or "",
|
||||
"specName": "",
|
||||
"batchNo": c.batch_no or "",
|
||||
"storageSlotId": c.storage_slot_id or "",
|
||||
"storageSlotName": "",
|
||||
"passage": c.passage or "",
|
||||
"freezeDate": c.freeze_date.strftime("%Y-%m-%d %H:%M:%S") if c.freeze_date else "",
|
||||
"expectedCellCount": float(c.expected_cell_count) if c.expected_cell_count is not None else None,
|
||||
"viability": float(c.viability) if c.viability is not None else None,
|
||||
"productStatus": c.product_status or "",
|
||||
"sourceType": c.source_type or "",
|
||||
"productionTaskId": c.production_task_id or "",
|
||||
@@ -38,16 +51,111 @@ def _row_to_dict(c: BizCellProduct) -> Dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def _build_facility_path_label(node_id: str, by_id: Dict[str, BizStorageFacility]) -> str:
|
||||
parts: List[str] = []
|
||||
cur_id = (node_id or "").strip()
|
||||
visited: set[str] = set()
|
||||
while cur_id and cur_id != "0" and cur_id not in visited:
|
||||
visited.add(cur_id)
|
||||
node = by_id.get(cur_id)
|
||||
if not node:
|
||||
break
|
||||
parts.append(node.node_name or "")
|
||||
cur_id = (node.parent_id or "").strip()
|
||||
parts.reverse()
|
||||
return " / ".join(p for p in parts if p)
|
||||
|
||||
|
||||
def _enrich_product_dicts(
|
||||
db: Session,
|
||||
tenant_no: str,
|
||||
items: List[Dict[str, Any]],
|
||||
) -> List[Dict[str, Any]]:
|
||||
if not items:
|
||||
return items
|
||||
|
||||
type_ids = {i.get("productTypeId") for i in items if i.get("productTypeId")}
|
||||
spec_ids = {i.get("specId") for i in items if i.get("specId")}
|
||||
slot_ids = {i.get("storageSlotId") for i in items if i.get("storageSlotId")}
|
||||
|
||||
type_map: Dict[str, str] = {}
|
||||
if type_ids:
|
||||
rows = (
|
||||
db.query(BizCellProductType)
|
||||
.filter(
|
||||
BizCellProductType.id.in_(type_ids),
|
||||
BizCellProductType.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
type_map = {r.id: r.product_type_name or "" for r in rows}
|
||||
|
||||
spec_map: Dict[str, str] = {}
|
||||
if spec_ids:
|
||||
rows = (
|
||||
db.query(BizCellProductSpec)
|
||||
.filter(
|
||||
BizCellProductSpec.id.in_(spec_ids),
|
||||
BizCellProductSpec.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
spec_map = {r.id: r.spec_name or "" for r in rows}
|
||||
|
||||
slot_map: Dict[str, str] = {}
|
||||
if slot_ids:
|
||||
slots = (
|
||||
db.query(BizStorageFacilitySlot)
|
||||
.filter(
|
||||
BizStorageFacilitySlot.id.in_(slot_ids),
|
||||
BizStorageFacilitySlot.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
facilities = (
|
||||
db.query(BizStorageFacility)
|
||||
.filter(
|
||||
BizStorageFacility.tenant_no == tenant_no,
|
||||
BizStorageFacility.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
facility_by_id = {f.id: f for f in facilities}
|
||||
for slot in slots:
|
||||
node_path = _build_facility_path_label(slot.facility_node_id, facility_by_id)
|
||||
code = (slot.slot_code or "").strip()
|
||||
if node_path and code:
|
||||
slot_map[slot.id] = f"{node_path} / {code}"
|
||||
else:
|
||||
slot_map[slot.id] = code or node_path or ""
|
||||
|
||||
for item in items:
|
||||
tid = item.get("productTypeId") or ""
|
||||
sid = item.get("specId") or ""
|
||||
slot_id = item.get("storageSlotId") or ""
|
||||
item["productTypeName"] = type_map.get(tid, "") if tid else ""
|
||||
item["specName"] = spec_map.get(sid, "") if sid else ""
|
||||
item["storageSlotName"] = slot_map.get(slot_id, "") if slot_id else ""
|
||||
return items
|
||||
|
||||
|
||||
def product_to_response(db: Session, tenant_no: str, obj: BizCellProduct) -> Dict[str, Any]:
|
||||
enriched = _enrich_product_dicts(db, tenant_no, [_row_to_dict(obj)])
|
||||
return enriched[0] if enriched else _row_to_dict(obj)
|
||||
|
||||
|
||||
def list_cell_products(
|
||||
db: Session,
|
||||
*,
|
||||
tenant_no: str,
|
||||
page: int = 1,
|
||||
page_size: int = 20,
|
||||
keyword: Optional[str] = None,
|
||||
product_code: Optional[str] = None,
|
||||
product_name: Optional[str] = None,
|
||||
product_type_id: Optional[str] = None,
|
||||
product_status: Optional[str] = None,
|
||||
passage: Optional[str] = None,
|
||||
user_info=None,
|
||||
) -> Dict[str, Any]:
|
||||
def _filtered():
|
||||
@@ -55,6 +163,15 @@ def list_cell_products(
|
||||
BizCellProduct.del_flag == 0,
|
||||
BizCellProduct.tenant_no == tenant_no,
|
||||
)
|
||||
kw = (keyword or "").strip()
|
||||
if kw:
|
||||
like = f"%{kw}%"
|
||||
q0 = q0.filter(
|
||||
or_(
|
||||
BizCellProduct.product_code.ilike(like),
|
||||
BizCellProduct.product_name.ilike(like),
|
||||
)
|
||||
)
|
||||
pc = (product_code or "").strip()
|
||||
if pc:
|
||||
q0 = q0.filter(BizCellProduct.product_code.like(f"%{pc}%"))
|
||||
@@ -65,6 +182,8 @@ def list_cell_products(
|
||||
q0 = q0.filter(BizCellProduct.product_type_id == product_type_id)
|
||||
if product_status:
|
||||
q0 = q0.filter(BizCellProduct.product_status == product_status)
|
||||
if passage:
|
||||
q0 = q0.filter(BizCellProduct.passage == passage)
|
||||
if user_info:
|
||||
from app.core.data_scope import apply_data_scope
|
||||
q0 = apply_data_scope(q0, BizCellProduct, user_info, db, tenant_no)
|
||||
@@ -80,7 +199,10 @@ def list_cell_products(
|
||||
.limit(page_size)
|
||||
.all()
|
||||
)
|
||||
return {"items": [_row_to_dict(x) for x in rows], "total": int(total)}
|
||||
items = _enrich_product_dicts(
|
||||
db, tenant_no, [_row_to_dict(x) for x in rows]
|
||||
)
|
||||
return {"items": items, "total": int(total)}
|
||||
|
||||
|
||||
def get_cell_product(db: Session, id: str, tenant_no: str) -> Optional[BizCellProduct]:
|
||||
@@ -125,7 +247,11 @@ def create_cell_product(
|
||||
spec_id=(data.spec_id or "").strip() or None,
|
||||
batch_no=(data.batch_no or "").strip() or None,
|
||||
storage_slot_id=(data.storage_slot_id or "").strip() or None,
|
||||
product_status=data.product_status or "zk",
|
||||
passage=((data.passage or "").strip() or None) if getattr(data, "passage", None) else None,
|
||||
freeze_date=data.freeze_date if hasattr(data, "freeze_date") else None,
|
||||
expected_cell_count=data.expected_cell_count if hasattr(data, "expected_cell_count") else None,
|
||||
viability=data.viability if hasattr(data, "viability") else None,
|
||||
product_status=data.product_status or "frozen",
|
||||
source_type=data.source_type or "manual",
|
||||
quantity=data.quantity,
|
||||
unit=(data.unit or "").strip() or None,
|
||||
@@ -168,7 +294,20 @@ def update_cell_product(
|
||||
obj.batch_no = (data.batch_no or "").strip() or None
|
||||
if data.storage_slot_id is not None:
|
||||
obj.storage_slot_id = (data.storage_slot_id or "").strip() or None
|
||||
if data.product_status is not None:
|
||||
if hasattr(data, "passage") and data.passage is not None:
|
||||
obj.passage = (data.passage or "").strip() or None
|
||||
if hasattr(data, "freeze_date") and data.freeze_date is not None:
|
||||
obj.freeze_date = data.freeze_date
|
||||
if hasattr(data, "expected_cell_count") and data.expected_cell_count is not None:
|
||||
obj.expected_cell_count = data.expected_cell_count
|
||||
if hasattr(data, "viability") and data.viability is not None:
|
||||
obj.viability = data.viability
|
||||
if data.product_status is not None and data.product_status != obj.product_status:
|
||||
allowed = {"frozen": {"sold", "used"}}
|
||||
from_status = obj.product_status
|
||||
to_status = data.product_status
|
||||
if from_status not in allowed or to_status not in allowed[from_status]:
|
||||
raise ValueError(f"不允许从状态 {from_status} 变更为 {to_status}")
|
||||
obj.product_status = data.product_status
|
||||
if data.quantity is not None:
|
||||
obj.quantity = data.quantity
|
||||
@@ -205,6 +344,28 @@ def delete_cell_product(
|
||||
db.commit()
|
||||
|
||||
|
||||
def get_next_code(db: Session, tenant_no: str) -> str:
|
||||
today_str = datetime.now().strftime("%Y%m%d")
|
||||
prefix = f"CP{today_str}"
|
||||
last = (
|
||||
db.query(BizCellProduct)
|
||||
.filter(
|
||||
BizCellProduct.tenant_no == tenant_no,
|
||||
BizCellProduct.product_code.like(f"{prefix}%"),
|
||||
BizCellProduct.del_flag == 0,
|
||||
)
|
||||
.order_by(BizCellProduct.product_code.desc())
|
||||
.first()
|
||||
)
|
||||
seq = 1
|
||||
if last and last.product_code:
|
||||
try:
|
||||
seq = int(last.product_code[-6:]) + 1
|
||||
except (ValueError, IndexError):
|
||||
seq = 1
|
||||
return f"{prefix}{seq:06d}"
|
||||
|
||||
|
||||
def total_pages(total: int, page_size: int) -> int:
|
||||
if total <= 0:
|
||||
return 0
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_cell_product_py", "label": "cell_product.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L1"}, {"id": "crud_cell_product_row_to_dict", "label": "_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L15"}, {"id": "crud_cell_product_list_cell_products", "label": "list_cell_products()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L45"}, {"id": "crud_cell_product_get_cell_product", "label": "get_cell_product()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L93"}, {"id": "crud_cell_product_create_cell_product", "label": "create_cell_product()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L107"}, {"id": "crud_cell_product_update_cell_product", "label": "update_cell_product()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L161"}, {"id": "crud_cell_product_delete_cell_product", "label": "delete_cell_product()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L216"}, {"id": "crud_cell_product_get_next_code", "label": "get_next_code()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L232"}, {"id": "crud_cell_product_total_pages", "label": "total_pages()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L254"}, {"id": "crud_cell_product_rationale_1", "label": "\u7ec6\u80de\u4ea7\u54c1 CRUD\uff08biz_cell_product\uff09", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_cell_product_py", "target": "math", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_cell_product_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_cell_product_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_cell_product_py", "target": "sqlalchemy", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L8", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_cell_product_py", "target": "sqlalchemy_orm", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_cell_product_py", "target": "app_core_utils", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L11", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_cell_product_py", "target": "app_models_models", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L12", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_cell_product_py", "target": "crud_cell_product_row_to_dict", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L15", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_cell_product_py", "target": "crud_cell_product_list_cell_products", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py", "source_location": "L45", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_cell_product_py", "target": "crud_cell_product_get_cell_product", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/cLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_production_py", "label": "production.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L1"}, {"id": "api_production_get_tenant_no", "label": "_get_tenant_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L52"}, {"id": "api_production_consumablecreatebody", "label": "ConsumableCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L65"}, {"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": "L77"}, {"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": "L90"}, {"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": "L104"}, {"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": "L114"}, {"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": "L140"}, {"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": "L167"}, {"id": "api_production_reagentcreatebody", "label": "ReagentCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L184"}, {"id": "api_production_reagentupdatebody", "label": "ReagentUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L196"}, {"id": "api_production_list_reagents", "label": "list_reagents()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L209"}, {"id": "api_production_list_all_reagents", "label": "list_all_reagents()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L223"}, {"id": "api_production_create_reagent", "label": "create_reagent()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L233"}, {"id": "api_production_update_reagent", "label": "update_reagent()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L259"}, {"id": "api_production_delete_reagent", "label": "delete_reagent()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L286"}, {"id": "api_production_sopdocumentcreatebody", "label": "SopDocumentCreateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L303"}, {"id": "api_production_sopdocumentupdatebody", "label": "SopDocumentUpdateBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L313"}, {"id": "api_production_list_sop_documents", "label": "list_sop_documents()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L324"}, {"id": "api_production_list_all_sop_documents", "label": "list_all_sop_documents()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L338"}, {"id": "api_production_create_sop_document", "label": "create_sop_document()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L348"}, {"id": "api_production_update_sop_document", "label": "update_sop_document()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L375"}, {"id": "api_production_delete_sop_document", "label": "delete_sop_document()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py", "source_location": "L404"}, {"id": "api_production_processcategorycreatebody", "label": "ProcessCategoryCreateBody", "file_type": "code", "source_file": "/Users/wuziloLine 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_bizsamplecode", "label": "BizSampleCode", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L400"}, {"id": "models_models_sysdicttype", "label": "SysDictType", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L428"}, {"id": "models_models_sysethnic", "label": "SysEthnic", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L447"}, {"id": "models_models_sysdictdata", "label": "SysDictData", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L466"}, {"id": "models_models_sysapirequestlog", "label": "SysApiRequestLog", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location"Line truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "label": "cell_product.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L1"}, {"id": "schemas_cell_product_cellproductcreate", "label": "CellProductCreate", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L6"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "schemas_cell_product_validate_viability", "label": "validate_viability()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L27"}, {"id": "schemas_cell_product_validate_passage", "label": "validate_passage()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L34"}, {"id": "schemas_cell_product_cellproductupdate", "label": "CellProductUpdate", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L43"}, {"id": "schemas_cell_product_validate_status", "label": "validate_status()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L79"}, {"id": "schemas_cell_product_cellproductlistquery", "label": "CellProductListQuery", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L85"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "pydantic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "schemas_cell_product_cellproductcreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L6", "weight": 1.0}, {"source": "schemas_cell_product_cellproductcreate", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "schemas_cell_product_validate_viability", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L27", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "schemas_cell_product_validate_passage", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L34", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "schemas_cell_product_cellproductupdate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L43", "weight": 1.0}, {"source": "schemas_cell_product_cellproductupdate", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L43", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "schemas_cell_product_validate_viability", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L62", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "target": "schemas_cell_product_validate_passage", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py", "source_location": "L69", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_schemas_cell_product_py", "targLine truncated
|
||||
@@ -2131,7 +2131,11 @@ class BizCellProduct(Base):
|
||||
spec_id = Column(String(64), nullable=True, comment="规格ID")
|
||||
batch_no = Column(String(64), nullable=True, comment="批号")
|
||||
storage_slot_id = Column(String(64), nullable=True, comment="库位ID")
|
||||
product_status = Column(String(16), nullable=True, default="zk", comment="产品状态 zk在库 ck出库")
|
||||
passage = Column(String(8), nullable=True, comment="代次(P1~P8)")
|
||||
freeze_date = Column(DateTime, nullable=True, comment="冻存日期")
|
||||
expected_cell_count = Column(Numeric(18, 4), nullable=True, comment="预计细胞数量(单位:亿)")
|
||||
viability = Column(Numeric(5, 2), nullable=True, comment="活性(百分比,0~100)")
|
||||
product_status = Column(String(16), nullable=True, default="frozen", comment="产品状态 frozen已冻存/sold已售卖/used已使用")
|
||||
source_type = Column(String(32), nullable=True, default="production", comment="来源类型 production生产 qc质检")
|
||||
production_task_id = Column(String(64), nullable=True, comment="生产任务ID")
|
||||
quantity = Column(Numeric(18, 4), nullable=True, comment="数量")
|
||||
|
||||
@@ -1,42 +1,100 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
|
||||
class CellProductCreate(BaseModel):
|
||||
product_code: str
|
||||
product_name: str
|
||||
product_type_id: Optional[str] = None
|
||||
spec_id: Optional[str] = None
|
||||
batch_no: Optional[str] = None
|
||||
storage_slot_id: Optional[str] = None
|
||||
product_status: Optional[str] = 'zk'
|
||||
source_type: Optional[str] = 'manual'
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
product_code: str = Field(..., alias="productCode")
|
||||
product_name: str = Field(..., alias="productName")
|
||||
product_type_id: Optional[str] = Field(None, alias="productTypeId")
|
||||
spec_id: Optional[str] = Field(None, alias="specId")
|
||||
batch_no: Optional[str] = Field(None, alias="batchNo")
|
||||
storage_slot_id: Optional[str] = Field(None, alias="storageSlotId")
|
||||
passage: Optional[str] = None
|
||||
freeze_date: Optional[datetime] = Field(None, alias="freezeDate")
|
||||
expected_cell_count: Optional[float] = Field(None, alias="expectedCellCount")
|
||||
viability: Optional[float] = None
|
||||
product_status: Optional[str] = Field("frozen", alias="productStatus")
|
||||
source_type: Optional[str] = Field("manual", alias="sourceType")
|
||||
quantity: Optional[float] = None
|
||||
unit: Optional[str] = None
|
||||
expiry_date: Optional[datetime] = None
|
||||
product_images: Optional[str] = None
|
||||
expiry_date: Optional[datetime] = Field(None, alias="expiryDate")
|
||||
product_images: Optional[str] = Field(None, alias="productImages")
|
||||
remark: Optional[str] = None
|
||||
|
||||
@field_validator("viability")
|
||||
@classmethod
|
||||
def validate_viability(cls, v):
|
||||
if v is not None and (v < 0 or v > 100):
|
||||
raise ValueError("活性必须在 0~100 之间")
|
||||
return v
|
||||
|
||||
@field_validator("passage")
|
||||
@classmethod
|
||||
def validate_passage(cls, v):
|
||||
if v is not None:
|
||||
valid = {f"P{i}" for i in range(1, 9)}
|
||||
if v.upper() not in valid:
|
||||
raise ValueError("代次必须为 P1~P8")
|
||||
return v.upper()
|
||||
return v
|
||||
|
||||
|
||||
class CellProductUpdate(BaseModel):
|
||||
product_name: Optional[str] = None
|
||||
product_type_id: Optional[str] = None
|
||||
spec_id: Optional[str] = None
|
||||
batch_no: Optional[str] = None
|
||||
storage_slot_id: Optional[str] = None
|
||||
product_status: Optional[str] = None
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
product_name: Optional[str] = Field(None, alias="productName")
|
||||
product_type_id: Optional[str] = Field(None, alias="productTypeId")
|
||||
spec_id: Optional[str] = Field(None, alias="specId")
|
||||
batch_no: Optional[str] = Field(None, alias="batchNo")
|
||||
storage_slot_id: Optional[str] = Field(None, alias="storageSlotId")
|
||||
passage: Optional[str] = None
|
||||
freeze_date: Optional[datetime] = Field(None, alias="freezeDate")
|
||||
expected_cell_count: Optional[float] = Field(None, alias="expectedCellCount")
|
||||
viability: Optional[float] = None
|
||||
product_status: Optional[str] = Field(None, alias="productStatus")
|
||||
quantity: Optional[float] = None
|
||||
unit: Optional[str] = None
|
||||
expiry_date: Optional[datetime] = None
|
||||
product_images: Optional[str] = None
|
||||
expiry_date: Optional[datetime] = Field(None, alias="expiryDate")
|
||||
product_images: Optional[str] = Field(None, alias="productImages")
|
||||
remark: Optional[str] = None
|
||||
|
||||
@field_validator("viability")
|
||||
@classmethod
|
||||
def validate_viability(cls, v):
|
||||
if v is not None and (v < 0 or v > 100):
|
||||
raise ValueError("活性必须在 0~100 之间")
|
||||
return v
|
||||
|
||||
@field_validator("passage")
|
||||
@classmethod
|
||||
def validate_passage(cls, v):
|
||||
if v is not None:
|
||||
valid = {f"P{i}" for i in range(1, 9)}
|
||||
if v.upper() not in valid:
|
||||
raise ValueError("代次必须为 P1~P8")
|
||||
return v.upper()
|
||||
return v
|
||||
|
||||
@field_validator("product_status")
|
||||
@classmethod
|
||||
def validate_status(cls, v):
|
||||
if v is not None and v not in ("frozen", "sold", "used"):
|
||||
raise ValueError("状态必须为 frozen/sold/used")
|
||||
return v
|
||||
|
||||
|
||||
class CellProductListQuery(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
page: int = 1
|
||||
page_size: int = 20
|
||||
product_code: Optional[str] = None
|
||||
product_name: Optional[str] = None
|
||||
product_type_id: Optional[str] = None
|
||||
product_status: Optional[str] = None
|
||||
page_size: int = Field(20, alias="pageSize")
|
||||
keyword: Optional[str] = None
|
||||
product_code: Optional[str] = Field(None, alias="productCode")
|
||||
product_name: Optional[str] = Field(None, alias="productName")
|
||||
product_type_id: Optional[str] = Field(None, alias="productTypeId")
|
||||
product_status: Optional[str] = Field(None, alias="productStatus")
|
||||
passage: Optional[str] = None
|
||||
File diff suppressed because it is too large.
Load diff
+1494
-1367
File diff suppressed because it is too large.
Load diff
@@ -1,12 +1,12 @@
|
||||
# Graph Report - app (2026-05-21)
|
||||
|
||||
## Corpus Check
|
||||
- 135 files · ~117,795 words
|
||||
- 135 files · ~118,210 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 2375 nodes · 9260 edges · 52 communities detected
|
||||
- Extraction: 42% EXTRACTED · 58% INFERRED · 0% AMBIGUOUS · INFERRED: 5364 edges (avg confidence: 0.64)
|
||||
- 2380 nodes · 9268 edges · 52 communities detected
|
||||
- Extraction: 42% EXTRACTED · 58% INFERRED · 0% AMBIGUOUS · INFERRED: 5366 edges (avg confidence: 0.64)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
@@ -64,7 +64,7 @@
|
||||
- [[_COMMUNITY_Community 53|Community 53]]
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `success_response()` - 376 edges
|
||||
1. `success_response()` - 377 edges
|
||||
2. `error_response()` - 302 edges
|
||||
3. `SysUser` - 217 edges
|
||||
4. `BizQcMaterialUsage` - 197 edges
|
||||
@@ -91,159 +91,159 @@
|
||||
|
||||
### Community 0 - "Community 0"
|
||||
Cohesion: 0.02
|
||||
Nodes (423): attachment_download_url(), create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post() (+415 more)
|
||||
Nodes (426): create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post(), create_role_management() (+418 more)
|
||||
|
||||
### Community 1 - "Community 1"
|
||||
Cohesion: 0.01
|
||||
Nodes (368): AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody, DictTypeUpdateBody, ExpressCompanyCreateBody (+360 more)
|
||||
Nodes (393): attachment_download_url(), AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody, DictTypeUpdateBody (+385 more)
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.06
|
||||
Nodes (196): InsuranceCompanyCreateBody, InsuranceCompanyInvoiceCreateBody, InsuranceCompanyInvoiceUpdateBody, InsuranceCompanyUpdateBody, InsuranceProjectPriceCreateBody, InsuranceProjectPriceUpdateBody, 保险公司及险种价格管理 API(保险公司 + 开票信息 + 险种价格), Base (+188 more)
|
||||
Nodes (213): InsuranceCompanyCreateBody, InsuranceCompanyInvoiceCreateBody, InsuranceCompanyInvoiceUpdateBody, InsuranceCompanyUpdateBody, InsuranceProjectPriceCreateBody, InsuranceProjectPriceUpdateBody, 保险公司及险种价格管理 API(保险公司 + 开票信息 + 险种价格), ProcessDefCreateBody (+205 more)
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.03
|
||||
Nodes (135): generate_uuid(), create_consumable_pack(), get_consumable_pack(), get_pack_detail(), _item_row_to_dict(), list_all_packs(), list_consumable_packs(), pack_code_exists() (+127 more)
|
||||
Cohesion: 0.02
|
||||
Nodes (153): generate_uuid(), create_consumable_pack(), get_consumable_pack(), get_pack_detail(), _item_row_to_dict(), list_all_packs(), list_consumable_packs(), pack_code_exists() (+145 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.03
|
||||
Nodes (123): list_collection_regions(), _persist_protocol_sub_resources(), list_ethnics_for_select(), list_access_logs(), apply_data_scope(), _get_child_dept_ids(), get_user_dept_id(), _resolve_user_role_scopes() (+115 more)
|
||||
Nodes (120): _persist_protocol_sub_resources(), list_ethnics_for_select(), _list_insurance_companies(), _total_pages(), list_access_logs(), apply_data_scope(), _get_child_dept_ids(), get_user_dept_id() (+112 more)
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.09
|
||||
Nodes (125): CellSampleTypeCreateBody, CellSampleTypeUpdateBody, CollectionRegionCreateBody, CollectionRegionUpdateBody, CustomerCreateBody, CustomerUpdateBody, HospitalCreateBody, HospitalUpdateBody (+117 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (126): AuditCreateBody, BatchDetailIdsBody, BatchRefundFinanceSubmitBody, FinanceConfirmBody, FullmoonTodoInsuranceBody, ProtocolCreateBody, ProtocolUpdateBody, 细胞存储 — 采集协议单 / 审核 / 财务确认 / 分期预警 API (+118 more)
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.05
|
||||
Nodes (83): _format_attachment_file_size(), get_protocol_nos_used_in_protocols(), urls_to_attachment_list(), complete_production_work_order(), create_production_work_order_from_reception(), _fmt_dt(), _generate_work_order_no(), get_production_work_order() (+75 more)
|
||||
Cohesion: 0.04
|
||||
Nodes (94): get_role_data_scope(), get_role_menus(), _format_attachment_file_size(), get_protocol_nos_used_in_protocols(), urls_to_attachment_list(), create_dict_type(), dict_type_code_exists(), get_dict_type() (+86 more)
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.04
|
||||
Nodes (80): activate_channel_agreement(), cell_product_price_code_exists(), cell_product_spec_code_exists(), cell_product_type_code_exists(), _channel_agreement_price_exists(), _channel_agreement_price_item_key(), checkup_package_code_exists(), create_cell_product_price() (+72 more)
|
||||
Cohesion: 0.03
|
||||
Nodes (54): get_designer_data(), BaseStorage, convert_heic_to_jpeg(), get_storage(), LocalStorage, MinIOStorage, OSSStorage, process_image_content() (+46 more)
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.06
|
||||
Nodes (61): _business_type_label(), _enrich_task_list(), get_business_all_tasks(), _get_business_form_fields(), get_designer_data(), get_instance_detail(), list_completed_tasks(), list_my_instances() (+53 more)
|
||||
Cohesion: 0.04
|
||||
Nodes (77): _avatar_url_field(), _build_user_info_payload(), _jwt_user_payload(), logout(), 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/zkxw.sql 基线), 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。, 与 web-admin `userInfo` 字段约定一致。, Web 端登录用 RSA 公钥(PKCS#1 v1.5,与 JSEncrypt 一致) (+69 more)
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.05
|
||||
Nodes (59): list_roles_for_select(), _avatar_url_field(), _build_user_info_payload(), get_web_auth_menu_codes(), _jwt_user_payload(), logout(), 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/zkxw.sql 基线), 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。 (+51 more)
|
||||
Cohesion: 0.07
|
||||
Nodes (67): AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, ExhibitionAppointmentCreateBody, ExhibitionAppointmentUpdateBody, list_storage_slots(), 运营支撑 API(洁净室、进出记录、仓储设施、储位、展厅预约) (+59 more)
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.07
|
||||
Nodes (66): AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, ExhibitionAppointmentCreateBody, ExhibitionAppointmentUpdateBody, list_storage_slots(), 运营支撑 API(洁净室、进出记录、仓储设施、储位、展厅预约) (+58 more)
|
||||
Cohesion: 0.29
|
||||
Nodes (53): ConsumableCreateBody, ConsumablePackCreateBody, ConsumablePackUpdateBody, ConsumableUpdateBody, OutputTypeCreateBody, OutputTypeUpdateBody, PackItemInput, ProcessCategoryCreateBody (+45 more)
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.05
|
||||
Nodes (26): BusinessException, InvalidStatusTransitionException, log_delivery_operation(), log_operation(), log_order_operation(), log_settlement_operation(), log_user_operation(), OrderLockedException (+18 more)
|
||||
Cohesion: 0.07
|
||||
Nodes (33): BaseHTTPMiddleware, ApiCryptoError, _b64url_decode(), _b64url_encode(), decrypt_json(), derive_key(), encrypt_json(), gen_nonce_hex() (+25 more)
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.06
|
||||
Nodes (35): BaseHTTPMiddleware, ApiCryptoError, _b64url_decode(), _b64url_encode(), decrypt_json(), derive_key(), encrypt_json(), gen_nonce_hex() (+27 more)
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.43
|
||||
Nodes (45): ConsumableCreateBody, ConsumablePackCreateBody, ConsumablePackUpdateBody, ConsumableUpdateBody, OutputTypeCreateBody, OutputTypeUpdateBody, PackItemInput, ProcessCategoryCreateBody (+37 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.14
|
||||
Nodes (35): list_research_donation_audits(), _audit_to_dict(), batch_delete_donations(), _collection_to_dict(), convert_to_storage(), _create_collection(), create_donation(), _create_party() (+27 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
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 16 - "Community 16"
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.17
|
||||
Nodes (12): BusinessException, InvalidStatusTransitionException, log_delivery_operation(), log_operation(), log_order_operation(), log_settlement_operation(), log_user_operation(), OrderLockedException (+4 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
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 15 - "Community 15"
|
||||
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 17 - "Community 17"
|
||||
### Community 16 - "Community 16"
|
||||
Cohesion: 0.25
|
||||
Nodes (13): batch_issue_protocol_nos(), batch_revoke_protocol_nos(), create_protocol_no(), get_protocol_no(), list_protocol_nos(), _parse_issued_time(), protocol_no_exists(), 采集协议号池 CRUD(biz_collection_protocol_no) (+5 more)
|
||||
Nodes (13): code_exists(), create_material(), _dec(), _fmt_dt(), get_material(), list_materials(), _norm_status(), options_list() (+5 more)
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
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 18 - "Community 18"
|
||||
Cohesion: 0.26
|
||||
Nodes (12): batch_issue_sample_codes(), batch_revoke_sample_codes(), create_sample_code(), get_sample_code(), list_sample_codes(), _parse_issued_time(), 样本编码池 CRUD(biz_sample_code), _resolve_issued_user_display_name() (+4 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.23
|
||||
Nodes (12): Config, ProductBase, ProductCategoryBase, ProductCategoryCreate, ProductCategoryResponse, ProductCreate, ProductResponse, ProductUnitBase (+4 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.29
|
||||
Nodes (11): batch_issue_sample_codes(), batch_revoke_sample_codes(), create_sample_code(), get_sample_code(), list_sample_codes(), _parse_issued_time(), _resolve_issued_user_display_name(), _row_to_dict() (+3 more)
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
Cohesion: 0.27
|
||||
Nodes (11): _build_tree(), _cascade_soft_delete(), _collect_with_ancestors(), create_dept(), get_dept(), list_depts(), list_depts_tree(), 保留匹配节点及其全部上级,供关键词检索后仍能正确组树。 (+3 more)
|
||||
Cohesion: 0.31
|
||||
Nodes (12): _code_exists(), create_material(), _dec(), _fmt_dt(), get_material(), list_materials(), options_list(), _row_to_dict() (+4 more)
|
||||
|
||||
### Community 21 - "Community 21"
|
||||
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)
|
||||
Cohesion: 0.31
|
||||
Nodes (11): batch_issue_protocol_nos(), batch_revoke_protocol_nos(), create_protocol_no(), get_protocol_no(), list_protocol_nos(), _parse_issued_time(), protocol_no_exists(), _resolve_issued_user_display_name() (+3 more)
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): consumable_code_exists(), create_consumable(), get_consumable(), list_consumables(), 耗材 CRUD(biz_consumable), _row_to_dict(), soft_delete_consumable(), update_consumable()
|
||||
Cohesion: 0.24
|
||||
Nodes (12): list_depts(), _build_tree(), _cascade_soft_delete(), _collect_with_ancestors(), create_dept(), get_dept(), list_depts(), list_depts_tree() (+4 more)
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): create_sop_document(), get_sop_document(), list_sop_documents(), SOP文档 CRUD(biz_sop_document), _row_to_dict(), soft_delete_sop_document(), sop_code_exists(), update_sop_document()
|
||||
Cohesion: 0.26
|
||||
Nodes (10): list_menus(), _build_tree(), _cascade_soft_delete(), create_menu(), get_menu(), list_menus(), list_menus_tree(), _row_to_dict() (+2 more)
|
||||
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.36
|
||||
Nodes (9): deduct_for_task(), _display_remark(), list_usages(), list_usages_by_task(), _parse_receiver_purpose_from_remark(), _resolve_receiver_purpose(), revert_task_material_usages(), _row_to_dict() (+1 more)
|
||||
Cohesion: 0.24
|
||||
Nodes (9): dict_data_options(), create_dict_data(), get_dict_data(), list_dict_data(), list_dict_data_options(), 字典数据 CRUD(sys_dict_data), _row_to_dict(), soft_delete_dict_data() (+1 more)
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): create_express_company(), express_code_exists(), get_express_company(), list_express_companies(), 快递公司 CRUD(biz_express_company), _row_to_dict(), soft_delete_express_company(), update_express_company()
|
||||
Nodes (8): consumable_code_exists(), create_consumable(), get_consumable(), list_consumables(), 耗材 CRUD(biz_consumable), _row_to_dict(), soft_delete_consumable(), update_consumable()
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): create_sop_document(), get_sop_document(), list_sop_documents(), SOP文档 CRUD(biz_sop_document), _row_to_dict(), soft_delete_sop_document(), sop_code_exists(), update_sop_document()
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
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 28 - "Community 28"
|
||||
Cohesion: 0.27
|
||||
Nodes (8): create_cell_product(), delete_cell_product(), get_cell_product(), get_next_code(), list_cell_products(), 细胞产品 CRUD(biz_cell_product), _row_to_dict(), update_cell_product()
|
||||
|
||||
### 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 27 - "Community 27"
|
||||
Cohesion: 0.27
|
||||
Nodes (8): create_dict_data(), get_dict_data(), list_dict_data(), list_dict_data_options(), 字典数据 CRUD(sys_dict_data), _row_to_dict(), soft_delete_dict_data(), update_dict_data()
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
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 29 - "Community 29"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): create_customer(), get_customer(), id_card_taken(), list_customers(), 客户 CRUD(biz_customer), _row_to_dict(), soft_delete_customer(), update_customer()
|
||||
|
||||
### Community 30 - "Community 30"
|
||||
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 31 - "Community 31"
|
||||
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 32 - "Community 32"
|
||||
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 31 - "Community 31"
|
||||
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 32 - "Community 32"
|
||||
Cohesion: 0.31
|
||||
Nodes (8): create_customer(), get_customer(), id_card_taken(), list_customers(), 客户 CRUD(biz_customer), _row_to_dict(), soft_delete_customer(), update_customer()
|
||||
|
||||
### Community 33 - "Community 33"
|
||||
Cohesion: 0.36
|
||||
Nodes (7): create_dict_type(), dict_type_code_exists(), get_dict_type(), list_dict_types(), _row_to_dict(), soft_delete_dict_type(), update_dict_type()
|
||||
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.36
|
||||
Nodes (7): create_post(), get_post(), list_posts(), post_code_exists(), _row_to_dict(), soft_delete_post(), update_post()
|
||||
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_reagent(), get_reagent(), list_reagents(), reagent_code_exists(), _row_to_dict(), soft_delete_reagent(), update_reagent()
|
||||
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.31
|
||||
Nodes (7): create_cell_product(), delete_cell_product(), get_cell_product(), list_cell_products(), 细胞产品 CRUD(biz_cell_product), _row_to_dict(), update_cell_product()
|
||||
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()
|
||||
Nodes (7): create_reagent(), get_reagent(), list_reagents(), reagent_code_exists(), _row_to_dict(), soft_delete_reagent(), update_reagent()
|
||||
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.36
|
||||
Nodes (7): create_tenant(), get_tenant(), list_tenants(), _row_to_dict(), soft_delete_tenant(), tenant_no_exists(), update_tenant()
|
||||
Nodes (7): create_site(), get_site(), list_sites(), _row_to_dict(), site_code_exists(), soft_delete_site(), update_site()
|
||||
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 0.29
|
||||
@@ -326,14 +326,14 @@ Nodes (1): 发送催单通知给配送员 Args: del
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `generate_uuid()` connect `Community 3` to `Community 0`, `Community 2`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 12`, `Community 14`, `Community 16`, `Community 17`, `Community 18`, `Community 20`, `Community 21`, `Community 22`, `Community 23`, `Community 24`, `Community 25`, `Community 26`, `Community 27`, `Community 28`, `Community 29`, `Community 30`, `Community 31`, `Community 32`, `Community 33`, `Community 34`, `Community 35`, `Community 36`, `Community 37`, `Community 38`?**
|
||||
_High betweenness centrality (0.096) - this node is a cross-community bridge._
|
||||
- **Why does `SysUser` connect `Community 1` to `Community 2`, `Community 3`, `Community 5`, `Community 8`, `Community 9`, `Community 10`, `Community 13`, `Community 17`, `Community 18`?**
|
||||
_High betweenness centrality (0.095) - this node is a cross-community bridge._
|
||||
- **Why does `success_response()` connect `Community 0` to `Community 1`, `Community 4`, `Community 8`, `Community 9`, `Community 10`, `Community 43`, `Community 14`?**
|
||||
_High betweenness centrality (0.075) - this node is a cross-community bridge._
|
||||
- **Are the 375 inferred relationships involving `success_response()` (e.g. with `web_login_rsa_public_key()` and `web_login()`) actually correct?**
|
||||
_`success_response()` has 375 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Why does `SysUser` connect `Community 1` to `Community 2`, `Community 5`, `Community 8`, `Community 9`, `Community 10`?**
|
||||
_High betweenness centrality (0.098) - this node is a cross-community bridge._
|
||||
- **Why does `generate_uuid()` connect `Community 3` to `Community 0`, `Community 1`, `Community 2`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 11`, `Community 14`, `Community 15`, `Community 16`, `Community 17`, `Community 19`, `Community 20`, `Community 21`, `Community 22`, `Community 23`, `Community 24`, `Community 25`, `Community 26`, `Community 27`, `Community 28`, `Community 29`, `Community 30`, `Community 31`, `Community 32`, `Community 33`, `Community 34`, `Community 35`, `Community 36`, `Community 37`, `Community 38`?**
|
||||
_High betweenness centrality (0.097) - this node is a cross-community bridge._
|
||||
- **Why does `success_response()` connect `Community 0` to `Community 1`, `Community 4`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 43`, `Community 22`, `Community 23`, `Community 24`?**
|
||||
_High betweenness centrality (0.065) - this node is a cross-community bridge._
|
||||
- **Are the 376 inferred relationships involving `success_response()` (e.g. with `web_login_rsa_public_key()` and `web_login()`) actually correct?**
|
||||
_`success_response()` has 376 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 348 inferred relationships involving `str` (e.g. with `extract_login_credentials()` and `._make_request()`) actually correct?**
|
||||
_`str` has 348 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 301 inferred relationships involving `error_response()` (e.g. with `_json_error_response()` and `web_login()`) actually correct?**
|
||||
|
||||
@@ -57,12 +57,12 @@
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">2375 nodes · 9260 edges · 58 communities</div>
|
||||
<div id="stats">2380 nodes · 9268 edges · 58 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": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "main.py", "community": 9, "community_name": "Community 9", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_lifespan", "label": "lifespan()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "lifespan()", "community": 9, "community_name": "Community 9", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "_mask_secret()", "community": 9, "community_name": "Community 9", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_root", "label": "root()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "root()", "community": 9, "community_name": "Community 9", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_health_check", "label": "health_check()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "health_check()", "community": 9, "community_name": "Community 9", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "tasks_init_py", "label": "__init__.py", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 9, "community_name": "Community 9", "source_file": "tasks/__init__.py", "file_type": "code", "degree": 2}, {"id": "tasks_init_init_scheduled_tasks", "label": "init_scheduled_tasks()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "init_scheduled_tasks()", "community": 9, "community_name": "Community 9", "source_file": "tasks/__init__.py", "file_type": "code", "degree": 2}, {"id": "tasks_init_shutdown_scheduler", "label": "shutdown_scheduler()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "shutdown_scheduler()", "community": 9, "community_name": "Community 9", "source_file": "tasks/__init__.py", "file_type": "code", "degree": 2}, {"id": "core_auth_py", "label": "auth.py", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 11.4, "font": {"size": 0, "color": "#ffffff"}, "title": "auth.py", "community": 9, "community_name": "Community 9", "source_file": "core/auth.py", "file_type": "code", "degree": 18}, {"id": "core_auth_redis_session_enabled", "label": "_redis_session_enabled()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "_redis_session_enabled()", "community": 9, "community_name": "Community 9", "source_file": "core/auth.py", "file_type": "code", "degree": 2}, {"id": "core_auth_get_redis_client", "label": "_get_redis_client()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.7, "font": {"size": 0, "color": "#ffffff"}, "title": "_get_redis_client()", "community": 9, "community_name": "Community 9", "source_file": "core/auth.py", "file_type": "code", "degree": 9}, {"id": "core_auth_session_key", "label": "_session_key()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "_session_key()", "community": 9, "community_name": "Community 9", "source_file": "core/auth.py", "file_type": "code", "degree": 5}, {"id": "core_auth_refresh_key", "label": "_refresh_key()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "boLine truncated
|
||||
const RAW_EDGES = [{"from": "main_py", "to": "app_main_lifespan", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_mask_secret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_root", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_health_check", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_lifespan", "to": "core_login_crypto_ensure_initialized", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_init_scheduled_tasks", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_shutdown_scheduler", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tasks_init_py", "to": "tasks_init_init_scheduled_tasks", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tasks_init_py", "to": "tasks_init_shutdown_scheduler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_redis_session_enabled", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_redis_client", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_session_key", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_refresh_key", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_store_session", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_revoke_session", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_extend_session", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_is_session_valid", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_store_refresh_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_is_refresh_token_valid", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_revoke_refresh_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_create_access_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_create_refresh_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_decode_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_current_user_by_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_current_user", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "Line truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 439}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 393}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 202}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 148}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 136}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 128}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 92}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 90}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 76}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 72}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 71}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 68}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 53}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 49}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 36}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 31}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 20}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 15}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 14}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 13}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 12}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 11}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 10}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 10}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 10}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 10}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 10}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 10}, {"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": 9}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 9}, {"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": 9}, {"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": "#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.3, "font": {"size": 0, "color": "#ffffff"}, "title": "main.py", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_lifespan", "label": "lifespan()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "lifespan()", "community": 8, "community_name": "Community 8", "source_file": "main.py", "file_type": "code", "degree": 4}, {"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": "tasks_init_py", "label": "__init__.py", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 8, "community_name": "Community 8", "source_file": "tasks/__init__.py", "file_type": "code", "degree": 2}, {"id": "tasks_init_init_scheduled_tasks", "label": "init_scheduled_tasks()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "init_scheduled_tasks()", "community": 8, "community_name": "Community 8", "source_file": "tasks/__init__.py", "file_type": "code", "degree": 2}, {"id": "tasks_init_shutdown_scheduler", "label": "shutdown_scheduler()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "shutdown_scheduler()", "community": 8, "community_name": "Community 8", "source_file": "tasks/__init__.py", "file_type": "code", "degree": 2}, {"id": "core_auth_py", "label": "auth.py", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 11.4, "font": {"size": 0, "color": "#ffffff"}, "title": "auth.py", "community": 8, "community_name": "Community 8", "source_file": "core/auth.py", "file_type": "code", "degree": 18}, {"id": "core_auth_redis_session_enabled", "label": "_redis_session_enabled()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "_redis_session_enabled()", "community": 8, "community_name": "Community 8", "source_file": "core/auth.py", "file_type": "code", "degree": 2}, {"id": "core_auth_get_redis_client", "label": "_get_redis_client()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.7, "font": {"size": 0, "color": "#ffffff"}, "title": "_get_redis_client()", "community": 8, "community_name": "Community 8", "source_file": "core/auth.py", "file_type": "code", "degree": 9}, {"id": "core_auth_session_key", "label": "_session_key()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "_session_key()", "community": 8, "community_name": "Community 8", "source_file": "core/auth.py", "file_type": "code", "degree": 5}, {"id": "core_auth_refresh_key", "label": "_refresh_key()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "boLine truncated
|
||||
const RAW_EDGES = [{"from": "main_py", "to": "app_main_lifespan", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_mask_secret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_root", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_health_check", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_lifespan", "to": "core_login_crypto_ensure_initialized", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_init_scheduled_tasks", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_shutdown_scheduler", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tasks_init_py", "to": "tasks_init_init_scheduled_tasks", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tasks_init_py", "to": "tasks_init_shutdown_scheduler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_redis_session_enabled", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_redis_client", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_session_key", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_refresh_key", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_store_session", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_revoke_session", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_extend_session", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_is_session_valid", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_store_refresh_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_is_refresh_token_valid", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_revoke_refresh_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_create_access_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_create_refresh_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_decode_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_current_user_by_token", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_current_user", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "Line truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 444}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 418}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 218}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 169}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 134}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 129}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 105}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 100}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 97}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 72}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 60}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 46}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 31}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 21}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 21}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 20}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 15}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 14}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 13}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 13}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 13}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 13}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 13}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 12}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 11}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 10}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 10}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 10}, {"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": 9}, {"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}];
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
|
||||
+2517
-2376
File diff suppressed because it is too large.
Load diff
@@ -25,7 +25,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": 1779249191.0814734,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py": 1779336613.0254703,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/__init__.py": 1779206668.0388827,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py": 1779177348.5945773,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/models/qc_material.py": 1779284411.5179992,
|
||||
@@ -48,7 +48,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/order.py": 1778578258.0960286,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/__init__.py": 1778578258.0864499,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/order_adjust.py": 1778578258.0963318,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py": 1779206912.4108655,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/cell_product.py": 1779336629.616835,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/menu.py": 1778578258.0957444,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/attachment.py": 1778763456.6244864,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/schemas/category_parameter.py": 1778578258.0944862,
|
||||
@@ -84,7 +84,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/express_company.py": 1779265659.3453207,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_lab_test_item.py": 1779265673.3888667,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/role.py": 1779265616.3701816,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py": 1779265684.1870236,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py": 1779336727.023542,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/menu.py": 1779265729.0381103,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_region.py": 1779277867.6408322,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/sample_reception_check_item.py": 1779007909.2933013,
|
||||
@@ -128,7 +128,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/workflow.py": 1779266232.4568832,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_reception.py": 1779304425.1104686,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/insurance_company.py": 1779281097.279193,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py": 1779265782.5075505,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py": 1779336678.7838151,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/api/leave.py": 1779266168.8693042,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/workflow_callback.py": 1778727966.7277644,
|
||||
"/Users/wuzilong/work/00code/zkxw/backend/app/services/workflow_engine.py": 1778634664.6293883,
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
-- 细胞产品库字段重设计迁移
|
||||
-- 日期: 2026-05-21
|
||||
-- 设计文档: docs/superpowers/specs/2026-05-21-cell-product-library-design.md
|
||||
|
||||
-- 1. 新增 4 个业务字段(放在 storage_slot_id 之后,product_status 之前)
|
||||
ALTER TABLE biz_cell_product
|
||||
ADD COLUMN `passage` VARCHAR(8) DEFAULT NULL COMMENT '代次(P1~P8)' AFTER `storage_slot_id`,
|
||||
ADD COLUMN `freeze_date` DATETIME DEFAULT NULL COMMENT '冻存日期' AFTER `passage`,
|
||||
ADD COLUMN `expected_cell_count` DECIMAL(18,4) DEFAULT NULL COMMENT '预计细胞数量(单位:亿)' AFTER `freeze_date`,
|
||||
ADD COLUMN `viability` DECIMAL(5,2) DEFAULT NULL COMMENT '活性(百分比,0~100)' AFTER `expected_cell_count`;
|
||||
|
||||
-- 2. 更新 product_status 默认值和注释
|
||||
ALTER TABLE biz_cell_product
|
||||
MODIFY COLUMN `product_status` VARCHAR(16) DEFAULT 'frozen' COMMENT '状态: frozen已冻存/sold已售卖/used已使用';
|
||||
|
||||
-- 3. 迁移旧状态数据(如有)
|
||||
UPDATE biz_cell_product SET product_status = 'frozen' WHERE product_status = 'zk';
|
||||
UPDATE biz_cell_product SET product_status = 'sold' WHERE product_status = 'yc';
|
||||
UPDATE biz_cell_product SET product_status = 'used' WHERE product_status = 'ysy';
|
||||
@@ -0,0 +1,168 @@
|
||||
-- 细胞产品库初始化测试数据(20 条,覆盖各种场景)
|
||||
-- 日期: 2026-05-21
|
||||
-- 前提: 已执行 2026-05-21-cell-product-alter.sql 迁移
|
||||
|
||||
-- 场景覆盖:
|
||||
-- 状态: frozen(12条) / sold(5条) / used(3条)
|
||||
-- 代次: P1~P8 均有覆盖
|
||||
-- 活性: 70.0 ~ 99.5,含 NULL
|
||||
-- 预计细胞数量: 0.5 ~ 50.0 亿,含 NULL
|
||||
-- 冻存日期: 有值 / NULL / 未来日期
|
||||
-- 有效期: 已过期 / 未过期 / NULL
|
||||
-- 产品图片: 有值 / NULL
|
||||
-- 备注: 有值 / NULL
|
||||
-- 数量/单位: 1~100 份
|
||||
|
||||
INSERT INTO biz_cell_product
|
||||
(id, product_code, product_name, product_type_id, spec_id, batch_no, storage_slot_id,
|
||||
passage, freeze_date, expected_cell_count, viability,
|
||||
product_status, source_type, production_task_id,
|
||||
quantity, unit, expiry_date, product_images,
|
||||
tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag)
|
||||
VALUES
|
||||
|
||||
-- ==================== 已冻存 frozen (12条) ====================
|
||||
|
||||
-- 1. 典型冻存产品:高活性、P2代次、有图片有备注
|
||||
('60eaac11fceb4fd6b62e58e8be2c51cc', 'CP20260501000001', '间充质干细胞-MSC-P2-001', NULL, NULL, 'B20260501-001', NULL,
|
||||
'P2', '2026-05-01 10:30:00', 5.0000, 95.50,
|
||||
'frozen', 'manual', NULL,
|
||||
10, '份', '2027-05-01 00:00:00', 'https://minio.example.com/cell-product/msc-p2-001.jpg',
|
||||
'zkxw', 1, '高活性批次,来源于健康供体', 'admin', '', '2026-05-01 10:30:00', 'admin', '2026-05-01 10:30:00', 0),
|
||||
|
||||
-- 2. P1初代产品:数量大、高活性
|
||||
('5ea198fede454198be443211d2687ab3', 'CP20260502000001', '脐带血造血干细胞-HSC-P1-002', NULL, NULL, 'B20260502-002', NULL,
|
||||
'P1', '2026-05-02 14:20:00', 10.0000, 98.00,
|
||||
'frozen', 'manual', NULL,
|
||||
20, '份', '2027-11-02 00:00:00', NULL,
|
||||
'zkxw', 2, NULL, 'admin', '', '2026-05-02 14:20:00', 'admin', '2026-05-02 14:20:00', 0),
|
||||
|
||||
-- 3. P3代次、低活性、无冻存日期
|
||||
('661bcbadd41c4f478b16f3b9dd577914', 'CP20260503000001', '脂肪干细胞-ADSC-P3-003', NULL, NULL, 'B20260503-003', NULL,
|
||||
'P3', NULL, 3.0000, 72.00,
|
||||
'frozen', 'manual', NULL,
|
||||
5, '份', '2026-08-03 00:00:00', NULL,
|
||||
'zkxw', 3, '活性偏低,需进一步检测', 'admin', '', '2026-05-03 09:00:00', 'admin', '2026-05-03 09:00:00', 0),
|
||||
|
||||
-- 4. P4、中等活性、无预计细胞数量
|
||||
('dd8d414f36a244bca611a51a96581a85', 'CP20260505000001', '神经干细胞-NSC-P4-004', NULL, NULL, 'B20260505-004', NULL,
|
||||
'P4', '2026-05-05 08:15:00', NULL, 88.00,
|
||||
'frozen', 'manual', NULL,
|
||||
8, '份', '2027-05-05 00:00:00', 'https://minio.example.com/cell-product/nsc-p4-004.jpg',
|
||||
'zkxw', 4, NULL, 'admin', '', '2026-05-05 08:15:00', 'admin', '2026-05-05 08:15:00', 0),
|
||||
|
||||
-- 5. P5、活性为NULL(未检测)
|
||||
('815d5312900140c99e453c685c6d81a6', 'CP20260506000001', '诱导多能干细胞-iPSC-P5-005', NULL, NULL, 'B20260506-005', NULL,
|
||||
'P5', '2026-05-06 16:45:00', 2.5000, NULL,
|
||||
'frozen', 'manual', NULL,
|
||||
3, '份', '2027-02-06 00:00:00', NULL,
|
||||
'zkxw', 5, '待活性检测', 'admin', '', '2026-05-06 16:45:00', 'admin', '2026-05-06 16:45:00', 0),
|
||||
|
||||
-- 6. P6、大数量、有效期已过期(异常数据)
|
||||
('da9b6201f2a74921b475c234e0d72841', 'CP20260507000001', '软骨细胞-CC-P6-006', NULL, NULL, 'B20260507-006', NULL,
|
||||
'P6', '2026-05-07 11:00:00', 1.2000, 85.00,
|
||||
'frozen', 'manual', NULL,
|
||||
15, '份', '2025-05-07 00:00:00', NULL,
|
||||
'zkxw', 6, '有效期已过,需处理', 'admin', '', '2026-05-07 11:00:00', 'admin', '2026-05-07 11:00:00', 0),
|
||||
|
||||
-- 7. P7、极小数量、极高活性
|
||||
('e26ac18706b84c3da114f24eb50ec7e9', 'CP20260508000001', '心肌细胞-CM-P7-007', NULL, NULL, 'B20260508-007', NULL,
|
||||
'P7', '2026-05-08 09:30:00', 0.5000, 99.50,
|
||||
'frozen', 'manual', NULL,
|
||||
1, '份', '2027-11-08 00:00:00', NULL,
|
||||
'zkxw', 7, NULL, 'admin', '', '2026-05-08 09:30:00', 'admin', '2026-05-08 09:30:00', 0),
|
||||
|
||||
-- 8. P8、最大代次、多张图片
|
||||
('177e808ce4b8454cb074e5965ed94bb1', 'CP20260509000001', '肝细胞-HC-P8-008', NULL, NULL, 'B20260509-008', NULL,
|
||||
'P8', '2026-05-09 13:00:00', 8.0000, 80.00,
|
||||
'frozen', 'manual', NULL,
|
||||
12, '份', '2027-05-09 00:00:00', 'https://minio.example.com/cell-product/hc-p8-008a.jpg,https://minio.example.com/cell-product/hc-p8-008b.jpg',
|
||||
'zkxw', 8, '代次较高,建议尽快使用', 'admin', '', '2026-05-09 13:00:00', 'admin', '2026-05-09 13:00:00', 0),
|
||||
|
||||
-- 9. P1、大预计细胞数量50亿
|
||||
('0fe62984ef6c4d3eafa8bcff70c6e151', 'CP20260510000001', 'NK细胞-NK-P1-009', NULL, NULL, 'B20260510-009', NULL,
|
||||
'P1', '2026-05-10 07:00:00', 50.0000, 96.00,
|
||||
'frozen', 'manual', NULL,
|
||||
30, '份', '2027-11-10 00:00:00', 'https://minio.example.com/cell-product/nk-p1-009.jpg',
|
||||
'zkxw', 9, '大批次生产', 'admin', '', '2026-05-10 07:00:00', 'admin', '2026-05-10 07:00:00', 0),
|
||||
|
||||
-- 10. P3、无有效期
|
||||
('cb8e8ea1581348f18c119e1611fba39f', 'CP20260511000001', 'T细胞-TC-P3-010', NULL, NULL, 'B20260511-010', NULL,
|
||||
'P3', '2026-05-11 15:30:00', 15.0000, 91.00,
|
||||
'frozen', 'manual', NULL,
|
||||
25, '份', NULL, NULL,
|
||||
'zkxw', 10, NULL, 'admin', '', '2026-05-11 15:30:00', 'admin', '2026-05-11 15:30:00', 0),
|
||||
|
||||
-- 11. P2、活性偏低70%
|
||||
('28c6b50ccd3d4cf8ae9bbbbffef96418', 'CP20260512000001', '树突状细胞-DC-P2-011', NULL, NULL, 'B20260512-011', NULL,
|
||||
'P2', '2026-05-12 10:00:00', 4.0000, 70.00,
|
||||
'frozen', 'manual', NULL,
|
||||
6, '份', '2026-11-12 00:00:00', NULL,
|
||||
'zkxw', 11, '活性偏低,需复检', 'admin', '', '2026-05-12 10:00:00', 'admin', '2026-05-12 10:00:00', 0),
|
||||
|
||||
-- 12. P4、未来冻存日期(计划冻存)
|
||||
('940c82c006954865adb09e31fae36038', 'CP20260513000001', '表皮细胞-EC-P4-012', NULL, NULL, 'B20260513-012', NULL,
|
||||
'P4', '2026-06-15 00:00:00', 6.0000, 92.50,
|
||||
'frozen', 'manual', NULL,
|
||||
4, '份', '2027-06-15 00:00:00', NULL,
|
||||
'zkxw', 12, '计划冻存,待入库', 'admin', '', '2026-05-13 08:00:00', 'admin', '2026-05-13 08:00:00', 0),
|
||||
|
||||
-- ==================== 已售卖 sold (5条) ====================
|
||||
|
||||
-- 13. P2、已售卖、高活性
|
||||
('338ae843fb4a4914a1eb672fd7a5ee38', 'CP20260420000001', '间充质干细胞-MSC-P2-S01', NULL, NULL, 'B20260420-S01', NULL,
|
||||
'P2', '2026-04-20 09:00:00', 5.0000, 97.00,
|
||||
'sold', 'manual', NULL,
|
||||
10, '份', '2027-04-20 00:00:00', 'https://minio.example.com/cell-product/msc-p2-s01.jpg',
|
||||
'zkxw', 13, '已出售给合作医院', 'admin', '', '2026-04-20 09:00:00', 'admin', '2026-05-15 14:00:00', 0),
|
||||
|
||||
-- 14. P1、已售卖、最大批次
|
||||
('237d80589852465180706d1f7a3d3586', 'CP20260418000001', '脐带血造血干细胞-HSC-P1-S02', NULL, NULL, 'B20260418-S02', NULL,
|
||||
'P1', '2026-04-18 11:30:00', 20.0000, 99.00,
|
||||
'sold', 'manual', NULL,
|
||||
50, '份', '2027-10-18 00:00:00', NULL,
|
||||
'zkxw', 14, NULL, 'admin', '', '2026-04-18 11:30:00', 'admin', '2026-05-16 09:30:00', 0),
|
||||
|
||||
-- 15. P3、已售卖、中活性
|
||||
('a6380097234e4c15b04349f27348a9dd', 'CP20260415000001', '脂肪干细胞-ADSC-P3-S03', NULL, NULL, 'B20260415-S03', NULL,
|
||||
'P3', '2026-04-15 08:00:00', 8.0000, 88.50,
|
||||
'sold', 'manual', NULL,
|
||||
15, '份', '2027-04-15 00:00:00', 'https://minio.example.com/cell-product/adsc-p3-s03a.jpg,https://minio.example.com/cell-product/adsc-p3-s03b.jpg',
|
||||
'zkxw', 15, '科研合作项目使用', 'admin', '', '2026-04-15 08:00:00', 'admin', '2026-05-17 10:00:00', 0),
|
||||
|
||||
-- 16. P5、已售卖、低活性
|
||||
('853e0e67632c4291bf9d111a43a17b71', 'CP20260410000001', '神经干细胞-NSC-P5-S04', NULL, NULL, 'B20260410-S04', NULL,
|
||||
'P5', '2026-04-10 14:00:00', 2.0000, 75.00,
|
||||
'sold', 'manual', NULL,
|
||||
5, '份', '2026-10-10 00:00:00', NULL,
|
||||
'zkxw', 16, '低价出售,活性一般', 'admin', '', '2026-04-10 14:00:00', 'admin', '2026-05-18 11:00:00', 0),
|
||||
|
||||
-- 17. P1、已售卖、未填活性
|
||||
('ec5309d6870f486695cf5b5f63fd91d1', 'CP20260405000001', 'NK细胞-NK-P1-S05', NULL, NULL, 'B20260405-S05', NULL,
|
||||
'P1', '2026-04-05 10:00:00', 30.0000, NULL,
|
||||
'sold', 'manual', NULL,
|
||||
20, '份', '2027-10-05 00:00:00', NULL,
|
||||
'zkxw', 17, NULL, 'admin', '', '2026-04-05 10:00:00', 'admin', '2026-05-19 16:00:00', 0),
|
||||
|
||||
-- ==================== 已使用 used (3条) ====================
|
||||
|
||||
-- 18. P3、已使用(用于生产分化)
|
||||
('5e1f8cf0bab14e3f964d5a7aafb09d0d', 'CP20260301000001', '间充质干细胞-MSC-P3-U01', NULL, NULL, 'B20260301-U01', NULL,
|
||||
'P3', '2026-03-01 08:30:00', 10.0000, 93.00,
|
||||
'used', 'manual', NULL,
|
||||
8, '份', '2027-03-01 00:00:00', 'https://minio.example.com/cell-product/msc-p3-u01.jpg',
|
||||
'zkxw', 18, '用于生产分化为软骨细胞', 'admin', '', '2026-03-01 08:30:00', 'admin', '2026-05-10 09:00:00', 0),
|
||||
|
||||
-- 19. P4、已使用、来源生产任务
|
||||
('292c2ec830084ba08daf151845043dba', 'CP20260215000001', '诱导多能干细胞-iPSC-P4-U02', NULL, NULL, 'B20260215-U02', NULL,
|
||||
'P4', '2026-02-15 12:00:00', 12.0000, 90.00,
|
||||
'used', 'production', 'task-uuid-placeholder-001',
|
||||
6, '份', '2027-02-15 00:00:00', NULL,
|
||||
'zkxw', 19, '生产任务产出的细胞被用于后续分化实验', 'admin', '', '2026-02-15 12:00:00', 'admin', '2026-04-20 15:00:00', 0),
|
||||
|
||||
-- 20. P6、已使用、高代次低活性(极限场景)
|
||||
('e1cb9f8cbe6a40998686a8bb8fb76c9a', 'CP20260201000001', '肝细胞-HC-P6-U03', NULL, NULL, 'B20260201-U03', NULL,
|
||||
'P6', '2026-02-01 09:00:00', 1.5000, 78.50,
|
||||
'used', 'manual', NULL,
|
||||
2, '份', '2026-08-01 00:00:00', 'https://minio.example.com/cell-product/hc-p6-u03.jpg,https://minio.example.com/cell-product/hc-p6-u03-report.pdf',
|
||||
'zkxw', 20, '高代次细胞,已用于药物毒性测试', 'admin', '', '2026-02-01 09:00:00', 'admin', '2026-03-15 10:00:00', 0);
|
||||
@@ -0,0 +1,913 @@
|
||||
# 细胞产品库字段重设计 实施计划
|
||||
|
||||
> **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:** 后端在现有 Model/Schema/CRUD/API 层增量修改;前端全面重写 cell-product/index.vue 页面(表格列、搜索栏、新增/编辑弹窗、查看弹窗)。编码生成采用实时自增模式(参考 `_generate_work_order_no`)。
|
||||
|
||||
**Tech Stack:** Python 3.9 + FastAPI + SQLAlchemy + Pydantic v2(后端);Vue 3 + TypeScript + Element Plus + Tailwind CSS 4(前端)
|
||||
|
||||
**Design Spec:** `docs/superpowers/specs/2026-05-21-cell-product-library-design.md`
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
| 操作 | 文件路径 | 职责 |
|
||||
|------|---------|------|
|
||||
| 新增 | `docs/sql/2026-05-21-cell-product-alter.sql` | 数据库迁移:新增 4 字段 + 更新状态默认值 |
|
||||
| 修改 | `backend/app/models/models.py` (BizCellProduct 类, L2122-2149) | 新增 4 个 Column,更新 product_status 默认值 |
|
||||
| 修改 | `backend/app/schemas/cell_product.py` | Create/Update schema 新增字段 + 状态校验 |
|
||||
| 修改 | `backend/app/crud/cell_product.py` | _row_to_dict 新增映射 + create/update 新增字段 + 新增 get_next_code |
|
||||
| 修改 | `backend/app/api/production.py` (L1550-1632) | 新增 next-code 端点 + update 端点增加状态校验 |
|
||||
| 修改 | `web-admin/src/api/cell-product.ts` | 新增 fetchNextCellProductCode 接口 |
|
||||
| 重写 | `web-admin/src/views/production/cell-product/index.vue` | 表格列 + 搜索 + 弹窗 + 查看弹窗 全面重写 |
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 数据库迁移 SQL
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/sql/2026-05-21-cell-product-alter.sql`
|
||||
|
||||
- [ ] **Step 1: 编写 ALTER TABLE SQL**
|
||||
|
||||
```sql
|
||||
-- 细胞产品库字段重设计迁移
|
||||
-- 日期: 2026-05-21
|
||||
|
||||
-- 1. 新增 4 个业务字段(放在 storage_slot_id 之后,product_status 之前)
|
||||
ALTER TABLE biz_cell_product
|
||||
ADD COLUMN `passage` VARCHAR(8) DEFAULT NULL COMMENT '代次(P1~P8)' AFTER `storage_slot_id`,
|
||||
ADD COLUMN `freeze_date` DATETIME DEFAULT NULL COMMENT '冻存日期' AFTER `passage`,
|
||||
ADD COLUMN `expected_cell_count` DECIMAL(18,4) DEFAULT NULL COMMENT '预计细胞数量(单位:亿)' AFTER `freeze_date`,
|
||||
ADD COLUMN `viability` DECIMAL(5,2) DEFAULT NULL COMMENT '活性(百分比,0~100)' AFTER `expected_cell_count`;
|
||||
|
||||
-- 2. 更新 product_status 默认值和注释
|
||||
ALTER TABLE biz_cell_product
|
||||
MODIFY COLUMN `product_status` VARCHAR(16) DEFAULT 'frozen' COMMENT '状态: frozen已冻存/sold已售卖/used已使用';
|
||||
|
||||
-- 3. 迁移旧状态数据(如有)
|
||||
UPDATE biz_cell_product SET product_status = 'frozen' WHERE product_status = 'zk';
|
||||
UPDATE biz_cell_product SET product_status = 'sold' WHERE product_status = 'yc';
|
||||
UPDATE biz_cell_product SET product_status = 'used' WHERE product_status = 'ysy';
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 在数据库执行 SQL(由 DBA 或手动执行)**
|
||||
|
||||
- [ ] **Step 3: 提交**
|
||||
|
||||
```bash
|
||||
git add docs/sql/2026-05-21-cell-product-alter.sql
|
||||
git commit -m "feat(cell-product): add migration SQL for new fields and status enum"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 后端 Model 更新
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/models/models.py` (BizCellProduct 类, 约第 2122-2149 行)
|
||||
|
||||
- [ ] **Step 1: 在 BizCellProduct 类中新增 4 个 Column,更新 product_status 默认值**
|
||||
|
||||
在 `storage_slot_id` 行之后、`product_status` 行之前插入新字段,同时更新 `product_status` 默认值:
|
||||
|
||||
```python
|
||||
# 在 storage_slot_id 行之后新增:
|
||||
passage = Column(String(8), nullable=True, comment="代次(P1~P8)")
|
||||
freeze_date = Column(DateTime, nullable=True, comment="冻存日期")
|
||||
expected_cell_count = Column(Numeric(18, 4), nullable=True, comment="预计细胞数量(单位:亿)")
|
||||
viability = Column(Numeric(5, 2), nullable=True, comment="活性(百分比,0~100)")
|
||||
|
||||
# 修改 product_status 行:
|
||||
product_status = Column(String(16), nullable=True, default="frozen", comment="产品状态 frozen已冻存/sold已售卖/used已使用")
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 验证无语法错误**
|
||||
|
||||
Run: `cd backend && source venv/bin/activate && python -c "from app.models.models import BizCellProduct; print('OK')"`
|
||||
Expected: `OK`
|
||||
|
||||
- [ ] **Step 3: 提交**
|
||||
|
||||
```bash
|
||||
git add backend/app/models/models.py
|
||||
git commit -m "feat(cell-product): add passage, freeze_date, expected_cell_count, viability columns to model"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 后端 Schema 更新
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/schemas/cell_product.py`
|
||||
|
||||
- [ ] **Step 1: 更新 CellProductCreate、CellProductUpdate、CellProductListQuery**
|
||||
|
||||
完整替换 `backend/app/schemas/cell_product.py`:
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, field_validator
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class CellProductCreate(BaseModel):
|
||||
product_code: str
|
||||
product_name: str
|
||||
product_type_id: Optional[str] = None
|
||||
spec_id: Optional[str] = None
|
||||
batch_no: Optional[str] = None
|
||||
storage_slot_id: Optional[str] = None
|
||||
passage: Optional[str] = None
|
||||
freeze_date: Optional[datetime] = None
|
||||
expected_cell_count: Optional[float] = None
|
||||
viability: Optional[float] = None
|
||||
product_status: Optional[str] = 'frozen'
|
||||
source_type: Optional[str] = 'manual'
|
||||
quantity: Optional[float] = None
|
||||
unit: Optional[str] = None
|
||||
expiry_date: Optional[datetime] = None
|
||||
product_images: Optional[str] = None
|
||||
remark: Optional[str] = None
|
||||
|
||||
@field_validator('viability')
|
||||
@classmethod
|
||||
def validate_viability(cls, v):
|
||||
if v is not None and (v < 0 or v > 100):
|
||||
raise ValueError('活性必须在 0~100 之间')
|
||||
return v
|
||||
|
||||
@field_validator('passage')
|
||||
@classmethod
|
||||
def validate_passage(cls, v):
|
||||
if v is not None:
|
||||
valid = {f'P{i}' for i in range(1, 9)}
|
||||
if v.upper() not in valid:
|
||||
raise ValueError('代次必须为 P1~P8')
|
||||
return v.upper()
|
||||
return v
|
||||
|
||||
|
||||
class CellProductUpdate(BaseModel):
|
||||
product_name: Optional[str] = None
|
||||
product_type_id: Optional[str] = None
|
||||
spec_id: Optional[str] = None
|
||||
batch_no: Optional[str] = None
|
||||
storage_slot_id: Optional[str] = None
|
||||
passage: Optional[str] = None
|
||||
freeze_date: Optional[datetime] = None
|
||||
expected_cell_count: Optional[float] = None
|
||||
viability: Optional[float] = None
|
||||
product_status: Optional[str] = None
|
||||
quantity: Optional[float] = None
|
||||
unit: Optional[str] = None
|
||||
expiry_date: Optional[datetime] = None
|
||||
product_images: Optional[str] = None
|
||||
remark: Optional[str] = None
|
||||
|
||||
@field_validator('viability')
|
||||
@classmethod
|
||||
def validate_viability(cls, v):
|
||||
if v is not None and (v < 0 or v > 100):
|
||||
raise ValueError('活性必须在 0~100 之间')
|
||||
return v
|
||||
|
||||
@field_validator('passage')
|
||||
@classmethod
|
||||
def validate_passage(cls, v):
|
||||
if v is not None:
|
||||
valid = {f'P{i}' for i in range(1, 9)}
|
||||
if v.upper() not in valid:
|
||||
raise ValueError('代次必须为 P1~P8')
|
||||
return v.upper()
|
||||
return v
|
||||
|
||||
@field_validator('product_status')
|
||||
@classmethod
|
||||
def validate_status(cls, v):
|
||||
if v is not None and v not in ('frozen', 'sold', 'used'):
|
||||
raise ValueError('状态必须为 frozen/sold/used')
|
||||
return v
|
||||
|
||||
|
||||
class CellProductListQuery(BaseModel):
|
||||
page: int = 1
|
||||
page_size: int = 20
|
||||
product_code: Optional[str] = None
|
||||
product_name: Optional[str] = None
|
||||
product_type_id: Optional[str] = None
|
||||
product_status: Optional[str] = None
|
||||
passage: Optional[str] = None
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 验证无语法错误**
|
||||
|
||||
Run: `cd backend && source venv/bin/activate && python -c "from app.schemas.cell_product import CellProductCreate, CellProductUpdate; print('OK')"`
|
||||
Expected: `OK`
|
||||
|
||||
- [ ] **Step 3: 提交**
|
||||
|
||||
```bash
|
||||
git add backend/app/schemas/cell_product.py
|
||||
git commit -m "feat(cell-product): update schemas with new fields, status validation, and passage validator"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 后端 CRUD 更新
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/crud/cell_product.py`
|
||||
|
||||
- [ ] **Step 1: 更新 `_row_to_dict` 新增 4 个字段映射**
|
||||
|
||||
在 `_row_to_dict` 函数中,在 `"storageSlotId"` 之后新增:
|
||||
|
||||
```python
|
||||
"passage": c.passage or "",
|
||||
"freezeDate": c.freeze_date.strftime("%Y-%m-%d %H:%M:%S") if c.freeze_date else "",
|
||||
"expectedCellCount": float(c.expected_cell_count) if c.expected_cell_count is not None else None,
|
||||
"viability": float(c.viability) if c.viability is not None else None,
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 更新 `create_cell_product` 新增字段写入**
|
||||
|
||||
在 `create_cell_product` 函数的 `BizCellProduct(...)` 构造中,在 `storage_slot_id=` 之后新增:
|
||||
|
||||
```python
|
||||
passage=(data.passage or "").strip() or None if hasattr(data, "passage") and data.passage else None,
|
||||
freeze_date=data.freeze_date if hasattr(data, "freeze_date") else None,
|
||||
expected_cell_count=data.expected_cell_count if hasattr(data, "expected_cell_count") else None,
|
||||
viability=data.viability if hasattr(data, "viability") else None,
|
||||
```
|
||||
|
||||
同时更新 `product_status` 默认值:
|
||||
```python
|
||||
product_status=data.product_status or "frozen",
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 更新 `update_cell_product` 新增字段处理 + 状态校验**
|
||||
|
||||
在 `update_cell_product` 函数中,在 `storage_slot_id` 处理之后新增:
|
||||
|
||||
```python
|
||||
if hasattr(data, "passage") and data.passage is not None:
|
||||
obj.passage = (data.passage or "").strip() or None
|
||||
if hasattr(data, "freeze_date") and data.freeze_date is not None:
|
||||
obj.freeze_date = data.freeze_date
|
||||
if hasattr(data, "expected_cell_count") and data.expected_cell_count is not None:
|
||||
obj.expected_cell_count = data.expected_cell_count
|
||||
if hasattr(data, "viability") and data.viability is not None:
|
||||
obj.viability = data.viability
|
||||
```
|
||||
|
||||
在 `product_status` 处理处增加状态流转校验:
|
||||
|
||||
```python
|
||||
if data.product_status is not None and data.product_status != obj.product_status:
|
||||
# 状态流转校验:只允许 frozen → sold/used,不可回退,不可互转
|
||||
allowed = {"frozen": {"sold", "used"}}
|
||||
from_status = obj.product_status
|
||||
to_status = data.product_status
|
||||
if from_status not in allowed or to_status not in allowed[from_status]:
|
||||
raise ValueError(f"不允许从状态 {from_status} 变更为 {to_status}")
|
||||
obj.product_status = data.product_status
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 新增 `get_next_code` 方法**
|
||||
|
||||
在文件末尾 `total_pages` 函数之前新增:
|
||||
|
||||
```python
|
||||
def get_next_code(db: Session, tenant_no: str) -> str:
|
||||
"""生成下一个产品编码: CP + YYYYMMDD + 6位序列号"""
|
||||
today_str = datetime.now().strftime("%Y%m%d")
|
||||
prefix = f"CP{today_str}"
|
||||
last = (
|
||||
db.query(BizCellProduct)
|
||||
.filter(
|
||||
BizCellProduct.tenant_no == tenant_no,
|
||||
BizCellProduct.product_code.like(f"{prefix}%"),
|
||||
BizCellProduct.del_flag == 0,
|
||||
)
|
||||
.order_by(BizCellProduct.product_code.desc())
|
||||
.first()
|
||||
)
|
||||
seq = 1
|
||||
if last and last.product_code:
|
||||
try:
|
||||
seq = int(last.product_code[-6:]) + 1
|
||||
except (ValueError, IndexError):
|
||||
seq = 1
|
||||
return f"{prefix}{seq:06d}"
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 更新 `list_cell_products` 支持 passage 筛选**
|
||||
|
||||
在 `list_cell_products` 函数签名中新增 `passage` 参数,在筛选逻辑中新增:
|
||||
|
||||
```python
|
||||
passage: Optional[str] = None,
|
||||
```
|
||||
|
||||
在 `product_status` 筛选之后新增:
|
||||
|
||||
```python
|
||||
if passage:
|
||||
q0 = q0.filter(BizCellProduct.passage == passage)
|
||||
```
|
||||
|
||||
- [ ] **Step 6: 验证无语法错误**
|
||||
|
||||
Run: `cd backend && source venv/bin/activate && python -c "from app.crud.cell_product import get_next_code, list_cell_products; print('OK')"`
|
||||
Expected: `OK`
|
||||
|
||||
- [ ] **Step 7: 提交**
|
||||
|
||||
```bash
|
||||
git add backend/app/crud/cell_product.py
|
||||
git commit -m "feat(cell-product): update CRUD with new fields, status validation, next-code generation"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: 后端 API 更新
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/api/production.py` (约第 1550-1632 行)
|
||||
|
||||
- [ ] **Step 1: 新增 `GET /cell-products/next-code` 端点**
|
||||
|
||||
在 `list_cell_products` 端点(`@router.get("/cell-products")`)**之前**新增:
|
||||
|
||||
```python
|
||||
@router.get("/cell-products/next-code")
|
||||
async def get_next_cell_product_code(
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
tenant_no = _get_tenant_no(db, user)
|
||||
code = cell_product_svc.get_next_code(db, tenant_no)
|
||||
return success_response({"code": code})
|
||||
```
|
||||
|
||||
**重要**: 此端点必须放在 `/cell-products` 之前(FastAPI 路由匹配顺序),否则 `{product_id}` 会匹配到 `next-code`。
|
||||
|
||||
- [ ] **Step 2: 更新 `list_cell_products` 端点新增 passage 参数**
|
||||
|
||||
在端点签名中新增:
|
||||
|
||||
```python
|
||||
passage: Optional[str] = None,
|
||||
```
|
||||
|
||||
在调用 `cell_product_svc.list_cell_products` 时新增参数:
|
||||
|
||||
```python
|
||||
passage=passage,
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 验证 API 启动无报错**
|
||||
|
||||
Run: `cd backend && source venv/bin/activate && python -c "from app.api.production import router; print('OK')"`
|
||||
Expected: `OK`
|
||||
|
||||
- [ ] **Step 4: 提交**
|
||||
|
||||
```bash
|
||||
git add backend/app/api/production.py
|
||||
git commit -m "feat(cell-product): add next-code endpoint and passage filter to list API"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 6: 前端 API 层更新
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/api/cell-product.ts`
|
||||
|
||||
- [ ] **Step 1: 新增 `fetchNextCellProductCode` 接口**
|
||||
|
||||
在文件末尾新增:
|
||||
|
||||
```typescript
|
||||
export function fetchNextCellProductCode() {
|
||||
return request.get<{ code: string }>({ url: '/web/admin/cell-products/next-code' })
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 提交**
|
||||
|
||||
```bash
|
||||
git add web-admin/src/api/cell-product.ts
|
||||
git commit -m "feat(cell-product): add fetchNextCellProductCode API"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 7: 前端页面全面重写
|
||||
|
||||
**Files:**
|
||||
- Rewrite: `web-admin/src/views/production/cell-product/index.vue`
|
||||
|
||||
**参考模板**: `src/views/system/order/index.vue`(复杂列表模式)
|
||||
**参考组件**: `src/views/cell-storage/protocol/ProtocolFormDialog.vue`(附件上传卡片样式)
|
||||
**下拉数据来源**:
|
||||
- 产品类型: `fetchCellProductTypeList` from `@/api/admin`
|
||||
- 规格: `fetchCellProductSpecList` from `@/api/admin`
|
||||
- 储物格: `fetchStorageSlotList` from `@/api/admin`
|
||||
- 代次: 前端硬编码 P1~P8
|
||||
|
||||
- [ ] **Step 1: 重写 `<template>` 部分**
|
||||
|
||||
主要改动点:
|
||||
1. **搜索栏**: 新增代次下拉筛选(P1~P8),状态选项改为 frozen/sold/used
|
||||
2. **表格列**: 新增代次、预计细胞数量(亿)、活性(%) 三列;状态 Tag 映射更新
|
||||
3. **新增/编辑弹窗**: 新增代次(下拉 P1~P8)、冻存日期(日期选择器)、预计细胞数量(数字输入)、活性(数字输入 0~100)、状态(编辑时可选);产品图片改为上传方式;产品编码新增时自动填充可编辑、编辑时只读
|
||||
4. **查看弹窗**: SystemViewDialog 新增代次、冻存日期、预计细胞数量、活性字段
|
||||
|
||||
**搜索栏状态选项更新**:
|
||||
```html
|
||||
<el-option label="已冻存" value="frozen" />
|
||||
<el-option label="已售卖" value="sold" />
|
||||
<el-option label="已使用" value="used" />
|
||||
```
|
||||
|
||||
**新增代次搜索筛选项**:
|
||||
```html
|
||||
<el-form-item label="代次">
|
||||
<el-select v-model="searchForm.passage" placeholder="全部" clearable style="width: 100%">
|
||||
<el-option v-for="i in 8" :key="i" :label="`P${i}`" :value="`P${i}`" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
```
|
||||
|
||||
**表格新增列**(插在批次号之后、储物格位置之后):
|
||||
```html
|
||||
<el-table-column prop="passage" label="代次" width="80" align="center" />
|
||||
<el-table-column prop="expectedCellCount" label="预计细胞数量(亿)" min-width="140" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.expectedCellCount ?? '—' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="viability" label="活性(%)" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.viability != null ? row.viability : '—' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
```
|
||||
|
||||
**状态 Tag 映射更新**:
|
||||
```typescript
|
||||
function productStatusTag(status: string) {
|
||||
const map: Record<string, { label: string; type: string }> = {
|
||||
frozen: { label: '已冻存', type: 'success' },
|
||||
sold: { label: '已售卖', type: 'warning' },
|
||||
used: { label: '已使用', type: 'info' },
|
||||
}
|
||||
return map[status] || { label: status, type: 'info' }
|
||||
}
|
||||
```
|
||||
|
||||
**表单新增字段**(在储物格之后插入新行):
|
||||
```html
|
||||
<el-form-item label="代次" prop="passage">
|
||||
<el-select v-model="formData.passage" placeholder="请选择代次" clearable style="width: 100%">
|
||||
<el-option v-for="i in 8" :key="i" :label="`P${i}`" :value="`P${i}`" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="预计细胞数量(亿)" prop="expectedCellCount">
|
||||
<el-input-number v-model="formData.expectedCellCount" :min="0" :precision="4" controls-position="right" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="活性(%)" prop="viability">
|
||||
<el-input-number v-model="formData.viability" :min="0" :max="100" :precision="1" controls-position="right" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="冻存日期" prop="freezeDate">
|
||||
<el-date-picker v-model="formData.freezeDate" type="date" placeholder="请选择冻存日期" value-format="YYYY-MM-DD" style="width: 100%" />
|
||||
</el-form-item>
|
||||
```
|
||||
|
||||
**状态字段(编辑时)**:
|
||||
```html
|
||||
<el-form-item v-if="isEdit" label="状态" prop="productStatus">
|
||||
<el-select v-model="formData.productStatus" :disabled="formData.productStatus !== 'frozen'" style="width: 100%">
|
||||
<el-option label="已冻存" value="frozen" :disabled="true" />
|
||||
<el-option label="已售卖" value="sold" />
|
||||
<el-option label="已使用" value="used" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
```
|
||||
|
||||
**产品编码字段**(新增时可编辑,编辑时只读):
|
||||
```html
|
||||
<el-form-item label="产品编码" prop="productCode">
|
||||
<el-input v-model="formData.productCode" placeholder="自动生成,可修改" :readonly="isEdit" />
|
||||
</el-form-item>
|
||||
```
|
||||
|
||||
**产品图片改为上传方式**(参考 ProtocolFormDialog 附件上传卡片样式):
|
||||
|
||||
```html
|
||||
<el-form-item label="产品图片" class="form-col-span-2">
|
||||
<div class="image-upload">
|
||||
<div class="image-list">
|
||||
<el-upload
|
||||
ref="imageUploadRef"
|
||||
:auto-upload="false"
|
||||
:show-file-list="false"
|
||||
:multiple="true"
|
||||
accept="image/*"
|
||||
@change="handleImageChange"
|
||||
>
|
||||
<div class="upload-card">
|
||||
<el-icon :size="28" color="#10b981"><Plus /></el-icon>
|
||||
<span class="upload-card-text">上传图片</span>
|
||||
</div>
|
||||
</el-upload>
|
||||
<div
|
||||
v-for="(img, index) in imageList"
|
||||
:key="img.id || index"
|
||||
class="image-item"
|
||||
>
|
||||
<div class="image-preview" @click="handlePreviewImage(img)">
|
||||
<el-image :src="img.fileUrl" fit="cover" class="preview-img" />
|
||||
</div>
|
||||
<div class="image-footer">
|
||||
<span class="image-name">{{ img.fileName }}</span>
|
||||
<div class="image-actions">
|
||||
<el-icon class="action-icon" @click="handleDeleteImage(index)"><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 重写 `<script setup>` 部分**
|
||||
|
||||
主要改动点:
|
||||
1. **import 新增**: `fetchNextCellProductCode` from `@/api/cell-product`;`fetchCellProductTypeList, fetchCellProductSpecList, fetchStorageSlotList` from `@/api/admin`;`fetchUploadAttachment` from `@/api/business`
|
||||
2. **formData 新增字段**: `passage`, `freezeDate`, `expectedCellCount`, `viability`, `productStatus`
|
||||
3. **searchForm 新增**: `passage`
|
||||
4. **下拉数据加载**: `onMounted` 中调用三个下拉接口填充 `productTypeOptions`、`specOptions`、`storageSlotOptions`
|
||||
5. **产品编码自动生成**: `handleAdd` 中调用 `fetchNextCellProductCode` 填充
|
||||
6. **图片上传**: 新增 `imageList` ref、`handleImageChange`、`handleDeleteImage`、`handlePreviewImage`
|
||||
7. **查看弹窗 sections**: 新增代次、冻存日期、预计细胞数量、活性字段
|
||||
8. **编辑时填充新字段**: `handleEdit` 中填充 passage/freezeDate/expectedCellCount/viability/productStatus
|
||||
9. **提交 payload**: 包含新字段
|
||||
10. **图片列表与 formData.productImages 的同步**: 上传/删除时同步更新逗号分隔 URL 字符串
|
||||
|
||||
**下拉数据加载**:
|
||||
```typescript
|
||||
async function loadOptions() {
|
||||
try {
|
||||
const [typeRes, specRes, slotRes] = await Promise.all([
|
||||
fetchCellProductTypeList({ page: 1, pageSize: 999 }),
|
||||
fetchCellProductSpecList({ page: 1, pageSize: 999 }),
|
||||
fetchStorageSlotList(),
|
||||
])
|
||||
productTypeOptions.value = (typeRes as any)?.list || []
|
||||
specOptions.value = (specRes as any)?.list || []
|
||||
storageSlotOptions.value = Array.isArray(slotRes) ? slotRes : (slotRes as any)?.list || []
|
||||
} catch { /* 静默 */ }
|
||||
}
|
||||
```
|
||||
|
||||
**编码自动生成**:
|
||||
```typescript
|
||||
async function handleAdd() {
|
||||
isEdit.value = false
|
||||
dialogTitle.value = '新增产品'
|
||||
resetForm()
|
||||
dialogVisible.value = true
|
||||
formRef.value?.clearValidate?.()
|
||||
// 自动生成编码
|
||||
try {
|
||||
const res = await fetchNextCellProductCode()
|
||||
formData.productCode = res.code || ''
|
||||
} catch { /* 静默 */ }
|
||||
}
|
||||
```
|
||||
|
||||
**图片上传处理**:
|
||||
```typescript
|
||||
const imageList = ref<Array<{ id: string; fileName: string; fileUrl: string; _uploading?: boolean }>>([])
|
||||
|
||||
async function handleImageChange(uploadFile: any) {
|
||||
const file = uploadFile.raw || uploadFile
|
||||
if (!file) return
|
||||
if (file.size / 1024 / 1024 > 10) {
|
||||
ElMessage.error('图片大小不能超过 10MB')
|
||||
return
|
||||
}
|
||||
const tempId = `temp_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
|
||||
imageList.value.push({ id: tempId, fileName: file.name, fileUrl: '', _uploading: true })
|
||||
const idx = imageList.value.length - 1
|
||||
try {
|
||||
const fd = new FormData()
|
||||
fd.append('folder', 'cell-product')
|
||||
fd.append('file', file)
|
||||
const res = await fetchUploadAttachment(fd)
|
||||
imageList.value[idx] = { id: res.id, fileName: res.fileName, fileUrl: res.fileUrl, _uploading: false }
|
||||
} catch {
|
||||
imageList.value.splice(idx, 1)
|
||||
ElMessage.error('图片上传失败')
|
||||
}
|
||||
}
|
||||
|
||||
function handleDeleteImage(index: number) {
|
||||
imageList.value.splice(index, 1)
|
||||
}
|
||||
|
||||
function handlePreviewImage(img: any) {
|
||||
if (img.fileUrl) window.open(img.fileUrl, '_blank')
|
||||
}
|
||||
|
||||
// 同步图片 URL 到 formData
|
||||
function syncImagesToForm() {
|
||||
formData.productImages = imageList.value.map((img) => img.fileUrl).filter(Boolean).join(',')
|
||||
}
|
||||
|
||||
// 从 formData.productImages 还原 imageList
|
||||
function syncFormToImages(imagesStr: string) {
|
||||
if (!imagesStr) { imageList.value = []; return }
|
||||
imageList.value = imagesStr.split(',').filter(Boolean).map((url, i) => ({
|
||||
id: `img_${i}`,
|
||||
fileName: url.split('/').pop() || `图片${i + 1}`,
|
||||
fileUrl: url,
|
||||
}))
|
||||
}
|
||||
```
|
||||
|
||||
**查看弹窗 sections 更新**:
|
||||
```typescript
|
||||
const viewSections = computed(() => {
|
||||
if (!viewRow.value) return []
|
||||
const row = viewRow.value
|
||||
return [
|
||||
{
|
||||
title: '基本信息',
|
||||
fields: [
|
||||
{ label: '产品编码', value: row.productCode },
|
||||
{ label: '产品名称', value: row.productName },
|
||||
{ label: '产品类型', value: row.productTypeName || '—' },
|
||||
{ label: '规格', value: row.specName || '—' },
|
||||
{ label: '代次', value: row.passage || '—' },
|
||||
{ label: '批次号', value: row.batchNo },
|
||||
{ label: '储物格位置', value: row.storageSlotName || '—' },
|
||||
{ label: '预计细胞数量(亿)', value: row.expectedCellCount ?? '—' },
|
||||
{ label: '活性(%)', value: row.viability != null ? row.viability : '—' },
|
||||
{ label: '数量', value: row.quantity ?? '—' },
|
||||
{ label: '单位', value: row.unit || '—' },
|
||||
{ label: '冻存日期', value: row.freezeDate || '—' },
|
||||
{ label: '有效期', value: row.expiryDate || '—' },
|
||||
{
|
||||
label: '状态',
|
||||
value: productStatusTag(row.productStatus).label,
|
||||
tagType: productStatusTag(row.productStatus).type,
|
||||
},
|
||||
{ label: '备注', value: row.remark || '—', span: true },
|
||||
],
|
||||
},
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**提交时同步图片**:
|
||||
```typescript
|
||||
async function handleSubmit() {
|
||||
await formRef.value?.validate?.()
|
||||
submitLoading.value = true
|
||||
try {
|
||||
syncImagesToForm()
|
||||
const payload = {
|
||||
productCode: formData.productCode.trim(),
|
||||
productName: formData.productName.trim(),
|
||||
productTypeId: formData.productTypeId || undefined,
|
||||
specId: formData.specId || undefined,
|
||||
batchNo: formData.batchNo.trim(),
|
||||
storageSlotId: formData.storageSlotId || undefined,
|
||||
passage: formData.passage || undefined,
|
||||
freezeDate: formData.freezeDate || undefined,
|
||||
expectedCellCount: formData.expectedCellCount ?? undefined,
|
||||
viability: formData.viability ?? undefined,
|
||||
productStatus: isEdit.value ? formData.productStatus || undefined : 'frozen',
|
||||
quantity: formData.quantity,
|
||||
unit: formData.unit?.trim() || undefined,
|
||||
expiryDate: formData.expiryDate || undefined,
|
||||
productImages: formData.productImages?.trim() || undefined,
|
||||
remark: formData.remark?.trim() || undefined,
|
||||
}
|
||||
if (isEdit.value && editingId.value) {
|
||||
await fetchUpdateCellProduct(editingId.value, payload)
|
||||
} else {
|
||||
await fetchCreateCellProduct(payload)
|
||||
}
|
||||
ElMessage.success(isEdit.value ? '更新成功' : '创建成功')
|
||||
dialogVisible.value = false
|
||||
await loadData()
|
||||
} catch {
|
||||
/* 校验或接口错误已由全局处理 */
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**编辑时填充新字段**(在 `handleEdit` 中):
|
||||
```typescript
|
||||
formData.passage = row.passage || ''
|
||||
formData.freezeDate = row.freezeDate || ''
|
||||
formData.expectedCellCount = row.expectedCellCount ?? undefined
|
||||
formData.viability = row.viability ?? undefined
|
||||
formData.productStatus = row.productStatus || 'frozen'
|
||||
syncFormToImages(row.productImages || '')
|
||||
```
|
||||
|
||||
**resetForm 新增字段重置**:
|
||||
```typescript
|
||||
function resetForm() {
|
||||
// ...existing fields...
|
||||
formData.passage = ''
|
||||
formData.freezeDate = ''
|
||||
formData.expectedCellCount = undefined
|
||||
formData.viability = undefined
|
||||
formData.productStatus = 'frozen'
|
||||
imageList.value = []
|
||||
editingId.value = null
|
||||
}
|
||||
```
|
||||
|
||||
**搜索参数传递更新**(在 `loadData` 中):
|
||||
```typescript
|
||||
const res = await fetchCellProductList({
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
productStatus: searchForm.productStatus || undefined,
|
||||
passage: searchForm.passage || undefined,
|
||||
})
|
||||
```
|
||||
|
||||
注意:需更新 `fetchCellProductList` 的 params 类型以支持 `productStatus` 和 `passage`。
|
||||
|
||||
- [ ] **Step 3: 编写 `<style>` 部分(图片上传卡片样式)**
|
||||
|
||||
在现有样式基础上新增图片上传卡片样式(参考 ProtocolFormDialog):
|
||||
|
||||
```scss
|
||||
.image-upload {
|
||||
.image-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.upload-card {
|
||||
width: 140px;
|
||||
height: 96px;
|
||||
border: 2px dashed #a7f3d0;
|
||||
border-radius: 8px;
|
||||
background: #f0fdf4;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s;
|
||||
&:hover {
|
||||
border-color: #10b981;
|
||||
}
|
||||
.upload-card-text {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
}
|
||||
}
|
||||
|
||||
.image-item {
|
||||
width: 140px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
transition: border-color 0.2s;
|
||||
&:hover {
|
||||
border-color: #10b981;
|
||||
}
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
width: 140px;
|
||||
height: 68px;
|
||||
background: #f8fafc;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
.preview-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.image-footer {
|
||||
padding: 4px 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.image-name {
|
||||
font-size: 11px;
|
||||
color: #64748b;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 90px;
|
||||
}
|
||||
.action-icon {
|
||||
cursor: pointer;
|
||||
color: #94a3b8;
|
||||
&:hover { color: #ef4444; }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 更新 `fetchCellProductList` 参数类型**
|
||||
|
||||
修改 `web-admin/src/api/cell-product.ts` 中的参数类型:
|
||||
|
||||
```typescript
|
||||
export function fetchCellProductList(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
productStatus?: string
|
||||
passage?: string
|
||||
}) {
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 验证前端编译无报错**
|
||||
|
||||
Run: `cd web-admin && pnpm build`
|
||||
Expected: 构建成功
|
||||
|
||||
- [ ] **Step 6: 提交**
|
||||
|
||||
```bash
|
||||
git add web-admin/src/views/production/cell-product/index.vue web-admin/src/api/cell-product.ts
|
||||
git commit -m "feat(cell-product): rewrite page with new fields, image upload, view dialog, and status lifecycle"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 8: 更新知识图谱
|
||||
|
||||
**Files:**
|
||||
- 执行: `./scripts/update-graph.sh all`
|
||||
|
||||
- [ ] **Step 1: 更新前后端知识图谱**
|
||||
|
||||
Run: `./scripts/update-graph.sh all`
|
||||
Expected: 图谱更新成功
|
||||
|
||||
- [ ] **Step 2: 提交图谱更新**
|
||||
|
||||
```bash
|
||||
git add backend/graphify-out/ web-admin/graphify-out/
|
||||
git commit -m "chore: update knowledge graphs after cell-product redesign"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Self-Review Checklist
|
||||
|
||||
### 1. Spec Coverage
|
||||
| Spec 需求 | 对应 Task |
|
||||
|-----------|----------|
|
||||
| 代次 P1~P8 下拉 | Task 2(Model) + Task 3(Schema) + Task 7(Frontend) |
|
||||
| 冻存日期 | Task 2 + Task 3 + Task 7 |
|
||||
| 预计细胞数量(亿) | Task 2 + Task 3 + Task 7 |
|
||||
| 活性(%) 0~100 | Task 2 + Task 3(Schema validator) + Task 7 |
|
||||
| 状态 frozen/sold/used | Task 1(SQL) + Task 2(Model) + Task 3(Schema) + Task 4(CRUD validation) + Task 7(Frontend) |
|
||||
| 产品编码自动生成 CP+YYYYMMDD+6位 | Task 4(get_next_code) + Task 5(API) + Task 6(Frontend API) + Task 7(handleAdd) |
|
||||
| 产品图片上传 | Task 7(Frontend image upload + SCSS) |
|
||||
| 查看弹窗 | Task 7(viewSections) |
|
||||
| 状态单向流转 | Task 4(update_cell_product status validation) |
|
||||
| 下拉数据来源(类型/规格/储物格) | Task 7(loadOptions) |
|
||||
| 搜索筛选(关键词+状态+代次) | Task 4(list_cell_products passage filter) + Task 5(API) + Task 7 |
|
||||
|
||||
### 2. Placeholder Scan
|
||||
- 无 TBD/TODO
|
||||
- 所有代码步骤均包含完整代码
|
||||
|
||||
### 3. Type Consistency
|
||||
- `passage`: Model `String(8)` → Schema `Optional[str]` → CRUD `str` → Frontend `string`
|
||||
- `freeze_date`: Model `DateTime` → Schema `Optional[datetime]` → Frontend `string(YYYY-MM-DD)`
|
||||
- `expected_cell_count`: Model `Numeric(18,4)` → Schema `Optional[float]` → CRUD `float()` → Frontend `number`
|
||||
- `viability`: Model `Numeric(5,2)` → Schema `Optional[float]` (validator 0~100) → Frontend `number`
|
||||
- `product_status`: Model `String(16) default='frozen'` → Schema `Optional[str]` (validator) → Frontend `string`
|
||||
- `_row_to_dict` 输出 camelCase key 与前端 formData 一致
|
||||
@@ -0,0 +1,274 @@
|
||||
# 细胞产品库(Cell Product Library)字段重设计
|
||||
|
||||
> 日期: 2026-05-21
|
||||
> 状态: 已确认,待实施
|
||||
> 范围: `web-admin/src/views/production/cell-product/` + `backend/app/` 相关文件
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
### 1.1 现状
|
||||
|
||||
`biz_cell_product` 表已有基本 CRUD 功能:产品编码、产品名称、产品类型、规格、批次号、储物格位置、数量、单位、有效期、产品图片、备注。状态字段使用 `zk`/`yc`/`ysy` 缩写且代码中存在不一致。
|
||||
|
||||
### 1.2 新需求
|
||||
|
||||
1. 细胞产品有**代次**(P1~P8,下拉选择)
|
||||
2. 有**冻存日期**(哪天开始冻存)
|
||||
3. 每份产品有**预计细胞数量**(单位:亿)
|
||||
4. 有**活性**百分比(用户填写 0~100 的数字)
|
||||
5. **状态**重新定义为:已冻存 / 已售卖 / 已使用
|
||||
6. **产品编码**自动生成(CP + YYYYMMDD + 6位序列号),生成后可编辑
|
||||
7. **产品图片**改为上传方式,参考【采集协议单录入】附件上传 UI 样式
|
||||
8. 新增**查看弹窗**(只读详情页)
|
||||
|
||||
### 1.3 不在本次范围
|
||||
|
||||
- 批量生成功能(后续对接生产模块时实现)
|
||||
- 生产任务自动生成细胞产品
|
||||
- 状态变更的审批流程
|
||||
|
||||
---
|
||||
|
||||
## 2. 数据库设计
|
||||
|
||||
### 2.1 新增字段
|
||||
|
||||
在 `biz_cell_product` 表中新增以下 4 个字段(放在业务字段区域,`tenant_no` 之前):
|
||||
|
||||
```sql
|
||||
ALTER TABLE biz_cell_product
|
||||
ADD COLUMN `passage` VARCHAR(8) DEFAULT NULL COMMENT '代次(P1~P8)' AFTER `storage_slot_id`,
|
||||
ADD COLUMN `freeze_date` DATETIME DEFAULT NULL COMMENT '冻存日期' AFTER `passage`,
|
||||
ADD COLUMN `expected_cell_count` DECIMAL(18,4) DEFAULT NULL COMMENT '预计细胞数量(单位:亿)' AFTER `freeze_date`,
|
||||
ADD COLUMN `viability` DECIMAL(5,2) DEFAULT NULL COMMENT '活性(百分比,0~100)' AFTER `expected_cell_count`;
|
||||
```
|
||||
|
||||
### 2.2 状态字段更新
|
||||
|
||||
`product_status` 字段(varchar(16))的值从 `zk`/`yc`/`ysy` 改为:
|
||||
|
||||
| 状态值 | 显示名 | Tag 颜色 | 说明 |
|
||||
|--------|--------|---------|------|
|
||||
| `frozen` | 已冻存 | `success`(绿色) | 新建时的默认状态 |
|
||||
| `sold` | 已售卖 | `warning`(橙色) | 通过编辑弹窗变更 |
|
||||
| `used` | 已使用 | `info`(灰色) | 通过编辑弹窗变更 |
|
||||
|
||||
```sql
|
||||
ALTER TABLE biz_cell_product
|
||||
MODIFY COLUMN `product_status` VARCHAR(16) DEFAULT 'frozen' COMMENT '状态: frozen已冻存/sold已售卖/used已使用';
|
||||
```
|
||||
|
||||
### 2.3 完整字段清单(按顺序)
|
||||
|
||||
| # | DB 列名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---------|------|:----:|--------|------|
|
||||
| 1 | `id` | varchar(64) PK | ✓ | UUID | 主键 |
|
||||
| 2 | `product_code` | varchar(64) | ✓ | 自动生成 | 产品编码 CP+YYYYMMDD+6位序号 |
|
||||
| 3 | `product_name` | varchar(200) | ✓ | | 产品名称 |
|
||||
| 4 | `product_type_id` | varchar(64) | | | 细胞产品类型ID (FK) |
|
||||
| 5 | `spec_id` | varchar(64) | | | 规格ID (FK) |
|
||||
| 6 | `batch_no` | varchar(64) | ✓ | | 批次号 |
|
||||
| 7 | `storage_slot_id` | varchar(64) | | | 储物格ID (FK) |
|
||||
| 8 | **`passage`** | varchar(8) | | | 代次 P1~P8 |
|
||||
| 9 | **`freeze_date`** | datetime | | | 冻存日期 |
|
||||
| 10 | **`expected_cell_count`** | decimal(18,4) | | | 预计细胞数量(亿) |
|
||||
| 11 | **`viability`** | decimal(5,2) | | | 活性(0~100%) |
|
||||
| 12 | `product_status` | varchar(16) | ✓ | `frozen` | 状态 |
|
||||
| 13 | `source_type` | varchar(20) | | `manual` | 来源 |
|
||||
| 14 | `production_task_id` | varchar(64) | | | 来源生产任务ID |
|
||||
| 15 | `quantity` | decimal(18,4) | | | 数量 |
|
||||
| 16 | `unit` | varchar(64) | | | 单位 |
|
||||
| 17 | `expiry_date` | datetime | | | 有效期 |
|
||||
| 18 | `product_images` | varchar(4000) | | | 产品图片URL(逗号分隔) |
|
||||
| — | `tenant_no` ~ `del_flag` | — | — | — | 公共字段 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 状态流转
|
||||
|
||||
```
|
||||
新建 → 已冻存 (frozen, 默认)
|
||||
├─→ 已售卖 (sold) [编辑弹窗]
|
||||
└─→ 已使用 (used) [编辑弹窗]
|
||||
```
|
||||
|
||||
规则:
|
||||
- 状态变更仅通过**编辑弹窗**操作
|
||||
- 已售卖/已使用**不可回退**为已冻存(单向流转)
|
||||
- 只有 `frozen` 状态的产品才能被编辑改为 `sold` 或 `used`
|
||||
- 已售卖和已使用之间**不可互转**
|
||||
|
||||
---
|
||||
|
||||
## 4. 产品编码自动生成
|
||||
|
||||
### 4.1 规则
|
||||
|
||||
```
|
||||
格式: CP + YYYYMMDD + 6位序列号(左补零)
|
||||
示例: CP20260521000001
|
||||
```
|
||||
|
||||
### 4.2 后端接口
|
||||
|
||||
新增 `GET /web/admin/cell-products/next-code`:
|
||||
|
||||
- 查询当天已有最大编码,+1 返回下一个编码
|
||||
- 如果当天无记录,返回 `CPYYYYMMDD000001`
|
||||
- 响应:`{ "code": "CP20260521000001" }`
|
||||
|
||||
### 4.3 前端交互
|
||||
|
||||
- 新增弹窗打开时,自动调用 next-code 接口填充产品编码
|
||||
- 产品编码字段可编辑,用户可手动修改
|
||||
- 编辑弹窗中产品编码只读
|
||||
|
||||
---
|
||||
|
||||
## 5. 前端界面设计
|
||||
|
||||
### 5.1 列表页
|
||||
|
||||
**页面路径**: `/production/cell-product`
|
||||
|
||||
**参考模板**: `src/views/system/order/index.vue`(复杂列表)
|
||||
|
||||
**表格列(14列)**:
|
||||
|
||||
| # | 列名 | 宽度 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 1 | 序号 | 60 | type=index |
|
||||
| 2 | 产品编码 | 180 | product_code |
|
||||
| 3 | 产品名称 | 160 | product_name |
|
||||
| 4 | 产品类型 | 120 | 关联显示类型名称 |
|
||||
| 5 | 规格 | 120 | 关联显示规格名称 |
|
||||
| 6 | 代次 | 80 | passage |
|
||||
| 7 | 批次号 | 140 | batch_no |
|
||||
| 8 | 储物格位置 | 140 | 关联显示储物格路径 |
|
||||
| 9 | 预计细胞数量(亿) | 140 | expected_cell_count |
|
||||
| 10 | 活性(%) | 90 | viability |
|
||||
| 11 | 状态 | 100 | `<el-tag>` Tag 展示 |
|
||||
| 12 | 有效期 | 120 | expiry_date, YYYY-MM-DD |
|
||||
| 13 | 操作 | ≥260 | fixed="right": 查看、编辑、删除 |
|
||||
|
||||
**搜索筛选栏**:
|
||||
- 关键词(模糊搜索,搜索产品编码/产品名称)
|
||||
- 产品状态下拉(已冻存/已售卖/已使用)
|
||||
- 代次下拉(P1~P8)
|
||||
|
||||
**工具栏**:
|
||||
- 已选 N 项
|
||||
- 新增按钮(`type="primary"`)
|
||||
- 删除按钮(批量)
|
||||
|
||||
### 5.2 新增/编辑弹窗
|
||||
|
||||
**布局**: `label-position="top"`, 2 列网格 (`.form-grid-2`)
|
||||
|
||||
**字段排列(左列 → 右列)**:
|
||||
|
||||
| 行 | 左列 | 右列 |
|
||||
|----|------|------|
|
||||
| 1 | 产品编码(自动填充,可编辑;编辑时只读) | 产品名称(必填) |
|
||||
| 2 | 产品类型(下拉) | 规格(下拉) |
|
||||
| 3 | 代次(下拉 P1~P8) | 批次号(必填) |
|
||||
| 4 | 储物格位置(下拉) | 预计细胞数量(数字输入,label 显示"预计细胞数量(亿)") |
|
||||
| 5 | 活性(数字输入 0~100,label 显示"活性(%)") | 冻存日期(日期选择器) |
|
||||
| 6 | 数量 | 单位 |
|
||||
| 7 | 有效期(日期选择器) | 状态(编辑时可选,新增时隐藏/固定为 frozen) |
|
||||
| 8 | 产品图片(跨2列,上传组件,参考采集协议单附件上传样式) | |
|
||||
| 9 | 备注(跨2列,textarea) | |
|
||||
|
||||
**下拉数据来源**:
|
||||
- 产品类型:`/web/admin/cell-product-types` 接口
|
||||
- 规格:`/web/admin/cell-product-specs` 接口
|
||||
- 储物格位置:库位管理接口,显示完整路径(` / `分隔)
|
||||
- 代次:前端硬编码选项 P1~P8
|
||||
|
||||
**编辑弹窗状态字段**:
|
||||
- 仅当当前状态为 `frozen` 时,显示状态下拉可改为 `sold` 或 `used`
|
||||
- 状态已为 `sold` 或 `used` 时,状态字段只读
|
||||
|
||||
### 5.3 查看弹窗
|
||||
|
||||
**布局**: 参考 `SystemViewDialog` 组件模式
|
||||
|
||||
**展示字段**:
|
||||
- 产品编码、产品名称
|
||||
- 产品类型(名称)、规格(名称)
|
||||
- 代次、批次号
|
||||
- 储物格位置(完整路径)
|
||||
- 预计细胞数量(亿)、活性(%)
|
||||
- 数量、单位
|
||||
- 冻存日期、有效期
|
||||
- 状态(`<el-tag>` 展示)
|
||||
- 产品图片(缩略图展示)
|
||||
- 备注
|
||||
|
||||
**状态字段** 使用 `<el-tag>` 渲染:
|
||||
- `frozen` → `<el-tag type="success" size="small">已冻存</el-tag>`
|
||||
- `sold` → `<el-tag type="warning" size="small">已售卖</el-tag>`
|
||||
- `used` → `<el-tag type="info" size="small">已使用</el-tag>`
|
||||
|
||||
### 5.4 产品图片上传
|
||||
|
||||
- 参考【采集协议单录入】模块的附件上传 UI 样式
|
||||
- 上传触发器为卡片式(虚线边框),inline 排列
|
||||
- 支持多图上传
|
||||
- 上传后显示缩略图卡片,支持预览和删除
|
||||
- 图片存储使用 MinIO 对象存储
|
||||
|
||||
---
|
||||
|
||||
## 6. 后端改动
|
||||
|
||||
### 6.1 Model(`backend/app/models/models.py` — BizCellProduct)
|
||||
|
||||
新增 4 个 Column:`passage`、`freeze_date`、`expected_cell_count`、`viability`
|
||||
|
||||
更新 `product_status` 默认值为 `'frozen'`
|
||||
|
||||
### 6.2 Schema(`backend/app/schemas/cell_product.py`)
|
||||
|
||||
- `CellProductCreate`: 新增 `passage`、`freeze_date`、`expected_cell_count`、`viability`(均 Optional)
|
||||
- `CellProductUpdate`: 同上 + `product_status`(可选,校验只能从 frozen→sold/used)
|
||||
- `CellProductListQuery`: 保持不变
|
||||
|
||||
### 6.3 CRUD(`backend/app/crud/cell_product.py`)
|
||||
|
||||
- `_row_to_dict`: 新增 4 个字段的映射
|
||||
- `create` / `update`: 新增字段处理
|
||||
- 新增 `get_next_code` 方法:查询当天最大编码 +1
|
||||
|
||||
### 6.4 API(`backend/app/api/production.py`)
|
||||
|
||||
- 新增 `GET /web/admin/cell-products/next-code` 端点
|
||||
- `create` 端点:新增字段写入
|
||||
- `update` 端点:状态变更校验(只允许 frozen→sold/used)
|
||||
|
||||
---
|
||||
|
||||
## 7. 涉及文件清单
|
||||
|
||||
| 层级 | 文件 | 改动类型 |
|
||||
|------|------|---------|
|
||||
| SQL | `docs/sql/` 新增迁移文件 | ALTER TABLE |
|
||||
| Model | `backend/app/models/models.py` BizCellProduct 类 | 新增 4 个 Column + 更新默认值 |
|
||||
| Schema | `backend/app/schemas/cell_product.py` | 新增字段 + 状态校验 |
|
||||
| CRUD | `backend/app/crud/cell_product.py` | 字段映射 + next-code 方法 |
|
||||
| API | `backend/app/api/production.py` | 新增 next-code 端点 + 状态校验 |
|
||||
| 前端页面 | `web-admin/src/views/production/cell-product/index.vue` | 全面重写(表格+表单+查看弹窗) |
|
||||
| 前端API | `web-admin/src/api/cell-product.ts` | 新增 next-code 接口 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 约定遵循
|
||||
|
||||
- UI 规范: `docs/web-admin-ui-spec-fresh-mint.md`(Fresh Mint 调色板)
|
||||
- 状态 Tag 颜色: `success`=已冻存, `warning`=已售卖, `info`=已使用
|
||||
- 弹窗表单: `label-position="top"`, 2列网格, `.dialog-form-layout`
|
||||
- 产品图片上传: 参考采集协议单附件上传卡片化布局
|
||||
- 公共字段: 遵循 `database-conventions`(id → 业务字段 → tenant_no ~ del_flag)
|
||||
- 编码生成: `CPYYYYMMDD` + 6位序号左补零
|
||||
File diff suppressed because it is too large.
Load diff
@@ -6249,28 +6249,35 @@
|
||||
"label": "fetchCellProductDetail()",
|
||||
"file_type": "code",
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L17"
|
||||
"source_location": "L19"
|
||||
},
|
||||
{
|
||||
"id": "api_cell_product_fetchcreatecellproduct",
|
||||
"label": "fetchCreateCellProduct()",
|
||||
"file_type": "code",
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L21"
|
||||
"source_location": "L23"
|
||||
},
|
||||
{
|
||||
"id": "api_cell_product_fetchupdatecellproduct",
|
||||
"label": "fetchUpdateCellProduct()",
|
||||
"file_type": "code",
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L25"
|
||||
"source_location": "L27"
|
||||
},
|
||||
{
|
||||
"id": "api_cell_product_fetchdeletecellproduct",
|
||||
"label": "fetchDeleteCellProduct()",
|
||||
"file_type": "code",
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L29"
|
||||
"source_location": "L31"
|
||||
},
|
||||
{
|
||||
"id": "api_cell_product_fetchnextcellproductcode",
|
||||
"label": "fetchNextCellProductCode()",
|
||||
"file_type": "code",
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L35"
|
||||
},
|
||||
{
|
||||
"id": "api_research_donation_ts",
|
||||
@@ -8267,19 +8274,26 @@
|
||||
"source_file": "views/production/process-route/index.vue",
|
||||
"source_location": "L1"
|
||||
},
|
||||
{
|
||||
"id": "process_route_index_if",
|
||||
"label": "if()",
|
||||
"file_type": "code",
|
||||
"source_file": "views/production/process-route/index.vue",
|
||||
"source_location": "L1024"
|
||||
},
|
||||
{
|
||||
"id": "process_route_index_get",
|
||||
"label": "get()",
|
||||
"file_type": "code",
|
||||
"source_file": "views/production/process-route/index.vue",
|
||||
"source_location": "L880"
|
||||
"source_location": "L1089"
|
||||
},
|
||||
{
|
||||
"id": "process_route_index_set",
|
||||
"label": "set()",
|
||||
"file_type": "code",
|
||||
"source_file": "views/production/process-route/index.vue",
|
||||
"source_location": "L890"
|
||||
"source_location": "L1099"
|
||||
},
|
||||
{
|
||||
"id": "views_production_sop_index_vue",
|
||||
@@ -20354,7 +20368,7 @@
|
||||
"relation": "contains",
|
||||
"confidence": "EXTRACTED",
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L17",
|
||||
"source_location": "L19",
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
@@ -20363,7 +20377,7 @@
|
||||
"relation": "contains",
|
||||
"confidence": "EXTRACTED",
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L21",
|
||||
"source_location": "L23",
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
@@ -20372,7 +20386,7 @@
|
||||
"relation": "contains",
|
||||
"confidence": "EXTRACTED",
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L25",
|
||||
"source_location": "L27",
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
@@ -20381,7 +20395,16 @@
|
||||
"relation": "contains",
|
||||
"confidence": "EXTRACTED",
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L29",
|
||||
"source_location": "L31",
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "api_cell_product_ts",
|
||||
"target": "api_cell_product_fetchnextcellproductcode",
|
||||
"relation": "contains",
|
||||
"confidence": "EXTRACTED",
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L35",
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
@@ -23750,13 +23773,22 @@
|
||||
"source_location": "L504",
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "views_production_process_route_index_vue",
|
||||
"target": "process_route_index_if",
|
||||
"relation": "contains",
|
||||
"confidence": "EXTRACTED",
|
||||
"source_file": "views/production/process-route/index.vue",
|
||||
"source_location": "L1024",
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "views_production_process_route_index_vue",
|
||||
"target": "process_route_index_get",
|
||||
"relation": "contains",
|
||||
"confidence": "EXTRACTED",
|
||||
"source_file": "views/production/process-route/index.vue",
|
||||
"source_location": "L880",
|
||||
"source_location": "L1089",
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
@@ -23765,7 +23797,7 @@
|
||||
"relation": "contains",
|
||||
"confidence": "EXTRACTED",
|
||||
"source_file": "views/production/process-route/index.vue",
|
||||
"source_location": "L890",
|
||||
"source_location": "L1099",
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
@@ -28963,7 +28995,7 @@
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.8,
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L8",
|
||||
"source_location": "L10",
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
@@ -28973,7 +29005,17 @@
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.8,
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L18",
|
||||
"source_location": "L20",
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"source": "api_cell_product_fetchnextcellproductcode",
|
||||
"target": "process_route_index_get",
|
||||
"relation": "calls",
|
||||
"confidence": "INFERRED",
|
||||
"confidence_score": 0.8,
|
||||
"source_file": "api/cell-product.ts",
|
||||
"source_location": "L36",
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Graph Report - src (2026-05-21)
|
||||
|
||||
## Corpus Check
|
||||
- Large corpus: 577 files · ~295,435 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
|
||||
- Large corpus: 577 files · ~296,820 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
|
||||
|
||||
## Summary
|
||||
- 1401 nodes · 1751 edges · 41 communities detected
|
||||
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 383 edges (avg confidence: 0.8)
|
||||
- 1403 nodes · 1754 edges · 45 communities detected
|
||||
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 384 edges (avg confidence: 0.8)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
@@ -33,11 +33,11 @@
|
||||
- [[_COMMUNITY_Community 21|Community 21]]
|
||||
- [[_COMMUNITY_Community 22|Community 22]]
|
||||
- [[_COMMUNITY_Community 23|Community 23]]
|
||||
- [[_COMMUNITY_Community 25|Community 25]]
|
||||
- [[_COMMUNITY_Community 24|Community 24]]
|
||||
- [[_COMMUNITY_Community 26|Community 26]]
|
||||
- [[_COMMUNITY_Community 27|Community 27]]
|
||||
- [[_COMMUNITY_Community 28|Community 28]]
|
||||
- [[_COMMUNITY_Community 29|Community 29]]
|
||||
- [[_COMMUNITY_Community 30|Community 30]]
|
||||
- [[_COMMUNITY_Community 31|Community 31]]
|
||||
- [[_COMMUNITY_Community 32|Community 32]]
|
||||
- [[_COMMUNITY_Community 33|Community 33]]
|
||||
@@ -49,10 +49,14 @@
|
||||
- [[_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 45|Community 45]]
|
||||
- [[_COMMUNITY_Community 53|Community 53]]
|
||||
- [[_COMMUNITY_Community 54|Community 54]]
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `get()` - 152 edges
|
||||
1. `get()` - 153 edges
|
||||
2. `WebSocketClient` - 26 edges
|
||||
3. `push()` - 18 edges
|
||||
4. `withFullscreenLoading()` - 16 edges
|
||||
@@ -66,14 +70,14 @@
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `handleBatchDelete()` --calls--> `withFullscreenLoading()` [INFERRED]
|
||||
views/system/site/index.vue → utils/fullscreen-loading.ts
|
||||
- `handleBatchDelete()` --calls--> `withFullscreenLoading()` [INFERRED]
|
||||
views/basic-info/sample-code/index.vue → utils/fullscreen-loading.ts
|
||||
- `handleBatchRevoke()` --calls--> `withFullscreenLoading()` [INFERRED]
|
||||
views/basic-info/sample-code/index.vue → utils/fullscreen-loading.ts
|
||||
- `handleBatchDelete()` --calls--> `withFullscreenLoading()` [INFERRED]
|
||||
views/basic-info/customer/index.vue → utils/fullscreen-loading.ts
|
||||
- `handleUnauthorizedResponse()` --calls--> `fetchRefreshToken()` [INFERRED]
|
||||
utils/http/index.ts → api/auth.ts
|
||||
- `fetchLeaveList()` --calls--> `get()` [INFERRED]
|
||||
api/leave.ts → views/production/process-route/index.vue
|
||||
- `fetchLeaveDetail()` --calls--> `get()` [INFERRED]
|
||||
api/leave.ts → views/production/process-route/index.vue
|
||||
|
||||
## Communities
|
||||
|
||||
@@ -83,7 +87,7 @@ Nodes (77): fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters()
|
||||
|
||||
### Community 1 - "Community 1"
|
||||
Cohesion: 0.03
|
||||
Nodes (56): fetchBatchGenerateProtocolNos(), fetchBatchGenerateSampleCodes(), fetchBatchIssueProtocolNos(), fetchBatchIssueSampleCodes(), fetchCollectionProtocolNoList(), fetchCreateCollectionProtocolNo(), fetchCreateSampleCode(), fetchDeleteCollectionProtocolNo() (+48 more)
|
||||
Nodes (53): fetchBatchGenerateProtocolNos(), fetchBatchIssueProtocolNos(), fetchCollectionProtocolNoList(), fetchCollectionRegionList(), fetchCreateCollectionProtocolNo(), fetchCreateCollectionRegion(), fetchCreateHospital(), fetchDeleteCollectionProtocolNo() (+45 more)
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.04
|
||||
@@ -91,11 +95,11 @@ Nodes (31): fetchGetUserInfo(), clickTab(), handleTouchEnd(), setTransition(), I
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.04
|
||||
Nodes (18): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents(), fetchAllSopDocuments(), fetchConsumableList() (+10 more)
|
||||
Nodes (33): fetchDeptTree(), fetchPostBoundUserIds(), reload(), collectIds(), formatUserLabel(), loadDeptData(), onPersonSelectChange(), RoutePermissionValidator (+25 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.05
|
||||
Nodes (32): fetchDeptTree(), fetchPostBoundUserIds(), FireworkSystem, reload(), formatUserLabel(), loadDeptData(), onPersonSelectChange(), subscribeTokenRefresh() (+24 more)
|
||||
Cohesion: 0.04
|
||||
Nodes (18): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents(), fetchAllSopDocuments(), fetchConsumableList() (+10 more)
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.05
|
||||
@@ -106,61 +110,61 @@ Cohesion: 0.09
|
||||
Nodes (5): handleReset(), handleSearch(), WebSocketClient, TableCache, emit()
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.06
|
||||
Nodes (12): collectIds(), useSettingsHandlers(), useSettingsPanel(), useSettingsState(), ComponentLoader, RoutePermissionValidator, RouteTransformer, useCeremony() (+4 more)
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.09
|
||||
Nodes (31): toLogin(), base64ToBytes(), bytesToBase64(), decryptJson(), deriveKey(), encryptJson(), fromBase64Url(), hexToBytes() (+23 more)
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.09
|
||||
Nodes (8): getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, getSystemStorage(), getSysVersion(), StorageKeyManager, StorageCompatibilityManager, validateStorageData()
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.07
|
||||
Nodes (13): fetchAttachmentDownloadUrl(), fetchOrderAdjusts(), fetchOrderDetail(), fetchOrderItems(), fetchOrderList(), fetchPriceVersionDetail(), fetchSystemConfig(), handleReceptionAttachmentDownload() (+5 more)
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.09
|
||||
Nodes (9): fetchGetAllUpgradeLogs(), fetchGetChinaMapData(), fetchGetComments(), fetchGetCurrentVersion(), fetchGetLatestUpgradeLog(), fetchGetSystemConfig(), fetchGetUpgradeLogs(), systemUpgrade() (+1 more)
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.07
|
||||
Nodes (15): fetchResearchDonationAuditList(), fetchResearchDonationDetail(), fetchResearchDonationList(), fetchApproveTask(), fetchBusinessAllTasks(), fetchCompletedTasks(), fetchDesignerData(), fetchInstanceDetail() (+7 more)
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.1
|
||||
Nodes (16): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateMenu(), postorder(), preorder(), applyTreeExpand(), handleAdd() (+8 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.1
|
||||
Nodes (8): fetchGetMenuList(), fetchGetMenuCodes(), fetchLogin(), fetchRefreshToken(), MenuProcessor, useAppMode(), useAuth(), buildWebEncryptedLoginBody()
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.1
|
||||
Nodes (13): fetchEthnicList(), addSample(), applyDonationBundleToForm(), confirmBatchTransportApply(), createEmptyTransport(), ensureDonationProtocolNoInOptions(), ensureEthnicOptionInList(), handleOpenForAdd() (+5 more)
|
||||
|
||||
### Community 16 - "Community 16"
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.1
|
||||
Nodes (18): fetchCollectionRegionList(), fetchCreateCollectionRegion(), fetchCreateHospital(), fetchDeleteCollectionRegion(), fetchDeleteHospital(), fetchHospitalList(), fetchUpdateCollectionRegion(), fetchUpdateHospital() (+10 more)
|
||||
Nodes (8): fetchGetMenuList(), fetchGetMenuCodes(), fetchLogin(), fetchRefreshToken(), MenuProcessor, useAppMode(), useAuth(), buildWebEncryptedLoginBody()
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.11
|
||||
Nodes (21): fetchBatchGenerateSampleCodes(), fetchBatchIssueSampleCodes(), fetchCreateSampleCode(), fetchDeleteSampleCode(), fetchSampleCodeList(), fetchUpdateSampleCode(), fetchUserOptions(), handleAdd() (+13 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.11
|
||||
Nodes (9): auditorDisplay(), dash(), expressName(), formatYm(), formatYmd(), sampleTypeName(), siteName(), unitName() (+1 more)
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
### Community 16 - "Community 16"
|
||||
Cohesion: 0.12
|
||||
Nodes (15): addCopyButton(), highlightCode(), insertLineNumbers(), isBlockProcessed(), markBlockAsProcessed(), processBlock(), setupHighlightDirective(), setupRippleDirective() (+7 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
### Community 17 - "Community 17"
|
||||
Cohesion: 0.14
|
||||
Nodes (17): fetchCreateUser(), fetchDeleteUser(), fetchResetPassword(), fetchUpdateUser(), fetchUserDetail(), formatUserDeptDisplay(), handleAdd(), handleDelete() (+9 more)
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
### Community 18 - "Community 18"
|
||||
Cohesion: 0.12
|
||||
Nodes (12): fetchApproveTask(), fetchBusinessAllTasks(), fetchCompletedTasks(), fetchDesignerData(), fetchInstanceDetail(), fetchMyInstances(), fetchPendingTasks(), fetchProcessDefList() (+4 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.16
|
||||
Nodes (10): useTable(), useTableImpl(), getColumnChecks(), useTableColumns(), createErrorHandler(), createSmartDebounce(), defaultResponseAdapter(), extractPagination() (+2 more)
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
Cohesion: 0.2
|
||||
Nodes (2): ComponentLoader, RouteTransformer
|
||||
|
||||
### Community 21 - "Community 21"
|
||||
Cohesion: 0.27
|
||||
Nodes (14): useChart(), useChartComponent(), useChartOps(), colourBlend(), getCssVar(), getDarkColor(), getLightColor(), handleElementThemeColor() (+6 more)
|
||||
@@ -171,117 +175,139 @@ Nodes (12): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), f
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.14
|
||||
Nodes (8): useSettingsHandlers(), useSettingsPanel(), useSettingsState(), useCeremony(), useTheme(), themeAnimation(), toggleTheme(), toggleTransition()
|
||||
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.14
|
||||
Nodes (2): fetchProductionTaskDetail(), fetchProductionTaskList()
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.17
|
||||
Nodes (3): fetchResearchDonationAuditList(), fetchResearchDonationDetail(), fetchResearchDonationList()
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
Cohesion: 0.18
|
||||
Nodes (3): fetchMaterialList(), fetchMaterialOptions(), fetchMaterialStockLogList()
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.2
|
||||
Nodes (2): fetchQcMaterialList(), fetchQcMaterialOptions()
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
### Community 29 - "Community 29"
|
||||
Cohesion: 0.28
|
||||
Nodes (1): FireworkSystem
|
||||
|
||||
### Community 31 - "Community 31"
|
||||
Cohesion: 0.39
|
||||
Nodes (6): isIgnorableScriptError(), normalizeErrorMessage(), registerPromiseErrorHandler(), registerResourceErrorHandler(), scriptErrorHandler(), setupErrorHandle()
|
||||
|
||||
### Community 29 - "Community 29"
|
||||
### Community 32 - "Community 32"
|
||||
Cohesion: 0.36
|
||||
Nodes (1): TableHeightCalculator
|
||||
|
||||
### Community 30 - "Community 30"
|
||||
### Community 33 - "Community 33"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): logApiCryptoBootInfo(), maskSecret()
|
||||
|
||||
### Community 31 - "Community 31"
|
||||
### Community 34 - "Community 34"
|
||||
Cohesion: 0.29
|
||||
Nodes (2): fetchLeaveDetail(), fetchLeaveList()
|
||||
|
||||
### Community 32 - "Community 32"
|
||||
### Community 35 - "Community 35"
|
||||
Cohesion: 0.47
|
||||
Nodes (3): isPaymentDueWithinWarnWindow(), parsePaymentDueYmd(), startOfLocalDay()
|
||||
|
||||
### Community 33 - "Community 33"
|
||||
### Community 36 - "Community 36"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchSampleReceptionCheckItemList(), fetchSampleReceptionCheckItemsActive()
|
||||
|
||||
### Community 34 - "Community 34"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcThirdPartyItemList(), fetchQcThirdPartyItemsActive()
|
||||
|
||||
### Community 35 - "Community 35"
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcThirdPartyCompanyList(), fetchQcThirdPartyCompanyOptions()
|
||||
|
||||
### Community 36 - "Community 36"
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcLabTestItemList(), fetchQcLabTestItemsActive()
|
||||
|
||||
### Community 37 - "Community 37"
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchQcTaskDetail(), fetchQcTaskList()
|
||||
|
||||
### Community 38 - "Community 38"
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 0.53
|
||||
Nodes (4): isEtaTodayOrEarlier(), parseEtaLocalDate(), sampleReceptionRowClassName(), startOfLocalDay()
|
||||
|
||||
### Community 39 - "Community 39"
|
||||
### Community 41 - "Community 41"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): focusInput(), handleKeydown()
|
||||
|
||||
### Community 40 - "Community 40"
|
||||
### Community 42 - "Community 42"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): if(), logSidebarMenu()
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
### Community 43 - "Community 43"
|
||||
Cohesion: 1.0
|
||||
Nodes (2): getSettingDefaults(), resetToDefaults()
|
||||
|
||||
### Community 43 - "Community 43"
|
||||
### Community 45 - "Community 45"
|
||||
Cohesion: 1.0
|
||||
Nodes (2): defaultAvatarPathByRole(), resolveUserAvatarUrl()
|
||||
|
||||
### Community 53 - "Community 53"
|
||||
Cohesion: 0.67
|
||||
Nodes (1): fetchQcItemParams()
|
||||
|
||||
### Community 54 - "Community 54"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): fetchDeleteProjectSystemItem(), if()
|
||||
|
||||
## Knowledge Gaps
|
||||
- **Thin community `Community 23`** (14 nodes): `fetchAddTaskStep()`, `fetchCreateProductionTask()`, `fetchDeleteTaskStep()`, `fetchProductionTaskDetail()`, `fetchProductionTaskList()`, `fetchReplaceStepConsumables()`, `fetchReplaceStepDataCollection()`, `fetchReplaceStepReagents()`, `fetchSetTaskInputs()`, `fetchSetTaskOutputs()`, `fetchUpdateProductionTask()`, `fetchUpdateProductionTaskStatus()`, `fetchUpdateTaskStep()`, `production-task.ts`
|
||||
- **Thin community `Community 20`** (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 26`** (10 nodes): `fetchBatchStockInQcMaterial()`, `fetchBatchStockOutQcMaterial()`, `fetchCreateQcMaterial()`, `fetchDeleteQcMaterial()`, `fetchQcMaterialList()`, `fetchQcMaterialOptions()`, `fetchStockInQcMaterial()`, `fetchStockOutQcMaterial()`, `fetchUpdateQcMaterial()`, `qc-material.ts`
|
||||
- **Thin community `Community 24`** (14 nodes): `fetchAddTaskStep()`, `fetchCreateProductionTask()`, `fetchDeleteTaskStep()`, `fetchProductionTaskDetail()`, `fetchProductionTaskList()`, `fetchReplaceStepConsumables()`, `fetchReplaceStepDataCollection()`, `fetchReplaceStepReagents()`, `fetchSetTaskInputs()`, `fetchSetTaskOutputs()`, `fetchUpdateProductionTask()`, `fetchUpdateProductionTaskStatus()`, `fetchUpdateTaskStep()`, `production-task.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 29`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
|
||||
- **Thin community `Community 28`** (10 nodes): `fetchBatchStockInQcMaterial()`, `fetchBatchStockOutQcMaterial()`, `fetchCreateQcMaterial()`, `fetchDeleteQcMaterial()`, `fetchQcMaterialList()`, `fetchQcMaterialOptions()`, `fetchStockInQcMaterial()`, `fetchStockOutQcMaterial()`, `fetchUpdateQcMaterial()`, `qc-material.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 30`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
|
||||
- **Thin community `Community 29`** (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 31`** (7 nodes): `fetchCreateLeave()`, `fetchDeleteLeave()`, `fetchLeaveDetail()`, `fetchLeaveList()`, `fetchSubmitLeave()`, `fetchUpdateLeave()`, `leave.ts`
|
||||
- **Thin community `Community 32`** (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 33`** (6 nodes): `fetchCreateSampleReceptionCheckItem()`, `fetchDeleteSampleReceptionCheckItem()`, `fetchSampleReceptionCheckItemList()`, `fetchSampleReceptionCheckItemsActive()`, `fetchUpdateSampleReceptionCheckItem()`, `sample-reception-check-item.ts`
|
||||
- **Thin community `Community 33`** (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 34`** (6 nodes): `fetchCreateQcThirdPartyItem()`, `fetchDeleteQcThirdPartyItem()`, `fetchQcThirdPartyItemList()`, `fetchQcThirdPartyItemsActive()`, `fetchUpdateQcThirdPartyItem()`, `qc-third-party-item.ts`
|
||||
- **Thin community `Community 34`** (7 nodes): `fetchCreateLeave()`, `fetchDeleteLeave()`, `fetchLeaveDetail()`, `fetchLeaveList()`, `fetchSubmitLeave()`, `fetchUpdateLeave()`, `leave.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 35`** (6 nodes): `fetchCreateQcThirdPartyCompany()`, `fetchDeleteQcThirdPartyCompany()`, `fetchQcThirdPartyCompanyList()`, `fetchQcThirdPartyCompanyOptions()`, `fetchUpdateQcThirdPartyCompany()`, `qc-third-party-company.ts`
|
||||
- **Thin community `Community 36`** (6 nodes): `fetchCreateSampleReceptionCheckItem()`, `fetchDeleteSampleReceptionCheckItem()`, `fetchSampleReceptionCheckItemList()`, `fetchSampleReceptionCheckItemsActive()`, `fetchUpdateSampleReceptionCheckItem()`, `sample-reception-check-item.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 36`** (6 nodes): `fetchCreateQcLabTestItem()`, `fetchDeleteQcLabTestItem()`, `fetchQcLabTestItemList()`, `fetchQcLabTestItemsActive()`, `fetchUpdateQcLabTestItem()`, `qc-lab-test-item.ts`
|
||||
- **Thin community `Community 37`** (6 nodes): `fetchCreateQcThirdPartyCompany()`, `fetchDeleteQcThirdPartyCompany()`, `fetchQcThirdPartyCompanyList()`, `fetchQcThirdPartyCompanyOptions()`, `fetchUpdateQcThirdPartyCompany()`, `qc-third-party-company.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 37`** (6 nodes): `fetchCompleteQcTask()`, `fetchQcTaskDetail()`, `fetchQcTaskList()`, `fetchStartQcTask()`, `fetchUpdateQcTaskAttachments()`, `qc-task.ts`
|
||||
- **Thin community `Community 38`** (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 39`** (5 nodes): `focusInput()`, `handleKeydown()`, `if()`, `search()`, `index.vue`
|
||||
- **Thin community `Community 39`** (6 nodes): `fetchCompleteQcTask()`, `fetchQcTaskDetail()`, `fetchQcTaskList()`, `fetchStartQcTask()`, `fetchUpdateQcTaskAttachments()`, `qc-task.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 40`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
|
||||
- **Thin community `Community 41`** (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 41`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
|
||||
- **Thin community `Community 42`** (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 43`** (3 nodes): `defaultAvatarPathByRole()`, `resolveUserAvatarUrl()`, `user-avatar.ts`
|
||||
- **Thin community `Community 43`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 45`** (3 nodes): `defaultAvatarPathByRole()`, `resolveUserAvatarUrl()`, `user-avatar.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 53`** (3 nodes): `fetchQcItemParams()`, `fetchSaveQcItemParams()`, `qc-item-param.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 54`** (3 nodes): `fetchDeleteProjectSystemItem()`, `if()`, `index.vue`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 5`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 14`, `Community 15`, `Community 16`, `Community 19`, `Community 22`, `Community 23`, `Community 25`, `Community 26`, `Community 31`, `Community 33`, `Community 34`, `Community 35`, `Community 36`, `Community 37`?**
|
||||
_High betweenness centrality (0.276) - this node is a cross-community bridge._
|
||||
- **Why does `push()` connect `Community 4` to `Community 0`, `Community 2`, `Community 6`, `Community 7`, `Community 11`, `Community 15`?**
|
||||
_High betweenness centrality (0.085) - this node is a cross-community bridge._
|
||||
- **Why does `fetchGetLatestUpgradeLog()` connect `Community 11` to `Community 0`?**
|
||||
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 5`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 14`, `Community 17`, `Community 18`, `Community 22`, `Community 24`, `Community 26`, `Community 27`, `Community 28`, `Community 34`, `Community 36`, `Community 37`, `Community 38`, `Community 39`, `Community 53`?**
|
||||
_High betweenness centrality (0.270) - this node is a cross-community bridge._
|
||||
- **Why does `push()` connect `Community 3` to `Community 0`, `Community 2`, `Community 6`, `Community 10`, `Community 12`, `Community 29`?**
|
||||
_High betweenness centrality (0.089) - this node is a cross-community bridge._
|
||||
- **Why does `fetchGetLatestUpgradeLog()` connect `Community 10` to `Community 0`?**
|
||||
_High betweenness centrality (0.042) - this node is a cross-community bridge._
|
||||
- **Are the 151 inferred relationships involving `get()` (e.g. with `buildTreePathLabelFromFlat()` and `alignFqPaymentDetailsForDisplay()`) actually correct?**
|
||||
_`get()` has 151 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 152 inferred relationships involving `get()` (e.g. with `buildTreePathLabelFromFlat()` and `alignFqPaymentDetailsForDisplay()`) actually correct?**
|
||||
_`get()` has 152 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 17 inferred relationships involving `push()` (e.g. with `fetchAllPagedRecords()` and `calcInstallmentDueAmounts()`) actually correct?**
|
||||
_`push()` has 17 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 15 inferred relationships involving `withFullscreenLoading()` (e.g. with `.close()` and `handleSubmit()`) actually correct?**
|
||||
|
||||
@@ -57,12 +57,12 @@
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">1401 nodes · 1751 edges · 237 communities</div>
|
||||
<div id="stats">1403 nodes · 1754 edges · 241 communities</div>
|
||||
</div>
|
||||
<script>
|
||||
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 30, "community_name": "Community 30", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 30, "community_name": "Community 30", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 30, "community_name": "Community 30", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 30, "community_name": "Community 30", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 30, "community_name": "Community 30", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 30, "community_name": "Community 30", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 74, "community_name": "Community 74", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 75, "community_name": "Community 75", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 18, "community_name": "Community 18", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.7, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 18, "community_name": "Community 18", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 18, "community_name": "Community 18", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 18, "community_name": "Community 18", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 18, "community_name": "Community 18", "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": 225}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 87}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 69}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 53}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 52}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 51}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 48}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 47}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 39}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 36}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 32}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 31}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 31}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 28}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 27}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 27}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 26}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 24}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 22}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 20}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 17}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 16}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 16}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 14}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 13}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 11}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 10}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 9}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 8}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 8}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 7}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 7}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 6}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 6}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 6}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 6}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 6}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 6}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 6}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 5}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 4}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 3}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 3}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 3}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 3}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 3}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 3}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 3}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 3}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 3}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 3}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 2}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 2}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 2}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 2}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 2}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 2}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 2}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 2}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 2}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 2}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 2}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 2}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 2}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 2}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 2}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 2}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 2}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 2}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 2}, {"cid": 70, "color": "#4E79A7", "label": "Community 70", "count": 2}, {"cidLine truncated
|
||||
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 33, "community_name": "Community 33", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 33, "community_name": "Community 33", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 33, "community_name": "Community 33", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 33, "community_name": "Community 33", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 33, "community_name": "Community 33", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 33, "community_name": "Community 33", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 78, "community_name": "Community 78", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 79, "community_name": "Community 79", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 16, "community_name": "Community 16", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.7, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 16, "community_name": "Community 16", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 16, "community_name": "Community 16", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 16, "community_name": "Community 16", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 16, "community_name": "Community 16", "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": 226}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 88}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 69}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 59}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 53}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 51}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 48}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 39}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 36}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 32}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 31}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 28}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 27}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 27}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 25}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 24}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 22}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 20}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 19}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 17}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 17}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 16}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 16}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 15}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 14}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 13}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 12}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 11}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 10}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 9}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 9}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 8}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 8}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 7}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 7}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 6}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 6}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 6}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 6}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 6}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 6}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 5}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 4}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 3}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 3}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 3}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 3}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 3}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 3}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 3}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 3}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 3}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 3}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 3}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 3}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 2}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 2}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 2}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 2}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 2}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 2}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 2}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 2}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 2}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 2}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 2}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 2}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 2}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 2}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 2}, {"cid": 70, "color": "#4E79A7", "label": "Community 70", "count": 2}, {"cLine truncated
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/common/index.ts": 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": 1779333640.1373396,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1779313245.9581928,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1779336687.830218,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1779336630.5292668,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/store/index.ts": 1778582068.0293276,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/router/index.ts": 1778775532.895603,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/locales/index.ts": 1778582068.004279,
|
||||
@@ -205,7 +205,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/admin.ts": 1779310973.2465198,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/ethnic.ts": 1778929297.3919344,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-lab-test-item.ts": 1779017838.8231559,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts": 1779207897.9650705,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts": 1779336699.268955,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/research-donation.ts": 1779160004.1431847,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts": 1779182848.881475,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-item-param.ts": 1779022632.5658252,
|
||||
@@ -269,8 +269,8 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/system/dict/index.vue": 1779259163.7560437,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/system/leave/index.vue": 1779257191.2768743,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/output-type/index.vue": 1779307917.5932443,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/index.vue": 1779227504.3581011,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue": 1779333730.1243677,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/index.vue": 1779337180.3946729,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue": 1779337296.3522038,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/sop/index.vue": 1779309609.6630545,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-task/index.vue": 1779269660.0717294,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/reagent/index.vue": 1779307562.93293,
|
||||
@@ -284,7 +284,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception-check-item/index.vue": 1779269589.0865154,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/lab-test-item/index.vue": 1779331328.5864854,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-material/index.vue": 1779284232.1223023,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue": 1779328630.8453777,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue": 1779333860.8573632,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-task/index.vue": 1779333720.422681,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-material-usage/index.vue": 1779285902.4727366,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/third-party-company/index.vue": 1779330250.9402645,
|
||||
|
||||
@@ -4,6 +4,8 @@ export function fetchCellProductList(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
productStatus?: string
|
||||
passage?: string
|
||||
}) {
|
||||
return request.get<{
|
||||
list: any[]
|
||||
@@ -29,3 +31,7 @@ export function fetchUpdateCellProduct(id: string, data: Record<string, any>) {
|
||||
export function fetchDeleteCellProduct(id: string) {
|
||||
return request.del({ url: `/web/admin/cell-products/${id}` })
|
||||
}
|
||||
|
||||
export function fetchNextCellProductCode() {
|
||||
return request.get<{ code: string }>({ url: '/web/admin/cell-products/next-code' })
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_process_route_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1"}, {"id": "process_route_index_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1024"}, {"id": "process_route_index_get", "label": "get()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1089"}, {"id": "process_route_index_set", "label": "set()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1099"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_process_route_index_vue", "target": "process_route_index_if", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1024", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_process_route_index_vue", "target": "process_route_index_get", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1089", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_process_route_index_vue", "target": "process_route_index_set", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1099", "weight": 1.0}], "raw_calls": [{"caller_nid": "process_route_index_if", "callee": "mapReagentOptionLabel", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1026"}, {"caller_nid": "process_route_index_get", "callee": "isArray", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1093"}, {"caller_nid": "process_route_index_get", "callee": "filter", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1093"}, {"caller_nid": "process_route_index_get", "callee": "filter", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1094"}, {"caller_nid": "process_route_index_get", "callee": "map", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1094"}, {"caller_nid": "process_route_index_get", "callee": "split", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1094"}, {"caller_nid": "process_route_index_get", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1094"}, {"caller_nid": "process_route_index_set", "callee": "join", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue", "source_location": "L1101"}]}
|
||||
+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_api_cell_product_ts", "label": "cell-product.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L1"}, {"id": "api_cell_product_fetchcellproductlist", "label": "fetchCellProductList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L3"}, {"id": "api_cell_product_fetchcellproductdetail", "label": "fetchCellProductDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L19"}, {"id": "api_cell_product_fetchcreatecellproduct", "label": "fetchCreateCellProduct()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L23"}, {"id": "api_cell_product_fetchupdatecellproduct", "label": "fetchUpdateCellProduct()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L27"}, {"id": "api_cell_product_fetchdeletecellproduct", "label": "fetchDeleteCellProduct()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L31"}, {"id": "api_cell_product_fetchnextcellproductcode", "label": "fetchNextCellProductCode()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L35"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_http", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchcellproductlist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchcellproductdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L19", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchcreatecellproduct", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L23", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchupdatecellproduct", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L27", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchdeletecellproduct", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L31", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_cell_product_ts", "target": "api_cell_product_fetchnextcellproductcode", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L35", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_cell_product_fetchcellproductlist", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L10"}, {"caller_nid": "api_cell_product_fetchcellproductdetail", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L20"}, {"caller_nid": "api_cell_product_fetchcreatecellproduct", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L24"}, {"caller_nid": "api_cell_product_fetchupdatecellproduct", "callee": "put", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L28"}, {"caller_nid": "api_cell_product_fetchdeletecellproduct", "callee": "del", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L32"}, {"caller_nid": "api_cell_product_fetchnextcellproductcode", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts", "source_location": "L36"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_sample_reception_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L1"}, {"id": "sample_reception_index_parseetalocaldate", "label": "parseEtaLocalDate()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L683"}, {"id": "sample_reception_index_startoflocalday", "label": "startOfLocalDay()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L697"}, {"id": "sample_reception_index_isetatodayorearlier", "label": "isEtaTodayOrEarlier()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L701"}, {"id": "sample_reception_index_samplereceptionrowclassname", "label": "sampleReceptionRowClassName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L707"}, {"id": "sample_reception_index_pad", "label": "pad()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L832"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_sample_reception_index_vue", "target": "sample_reception_index_parseetalocaldate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L683", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_sample_reception_index_vue", "target": "sample_reception_index_startoflocalday", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L697", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_sample_reception_index_vue", "target": "sample_reception_index_isetatodayorearlier", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L701", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_sample_reception_index_vue", "target": "sample_reception_index_samplereceptionrowclassname", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L707", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_sample_reception_index_vue", "target": "sample_reception_index_pad", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L832", "weight": 1.0}, {"source": "sample_reception_index_isetatodayorearlier", "target": "sample_reception_index_parseetalocaldate", "relation": "calls", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L702", "weight": 1.0}, {"source": "sample_reception_index_isetatodayorearlier", "target": "sample_reception_index_startoflocalday", "relation": "calls", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L704", "weight": 1.0}, {"source": "sample_reception_index_samplereceptionrowclassname", "target": "sample_reception_index_isetatodayorearlier", "relation": "calls", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L709", "weight": 1.0}], "raw_calls": [{"caller_nid": "sample_reception_index_parseetalocaldate", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L684"}, {"caller_nid": "sample_reception_index_parseetalocaldate", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/sample-reception/index.vue", "source_location": "L684"}, {"caller_nid": "sample_reception_index_parseetalocaldate", "callee": "slice", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/srLine truncated
|
||||
File diff suppressed because it is too large.
Load diff
@@ -403,9 +403,28 @@
|
||||
<el-input v-model="row.reagentCode" placeholder="编码" class="inner-cell-input" @change="saveReagents" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="试剂名称" min-width="120" align="center" header-align="center">
|
||||
<el-table-column label="试剂名称" min-width="160" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.reagentName" placeholder="名称" class="inner-cell-input" @change="saveReagents" />
|
||||
<el-select
|
||||
v-model="row.reagentId"
|
||||
placeholder="请选择试剂"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
class="inner-cell-select"
|
||||
:loading="reagentOptionsLoading"
|
||||
:remote-method="searchReagentOptions"
|
||||
@visible-change="(visible) => visible && searchReagentOptions('')"
|
||||
@change="(val) => onReagentRowSelect(row, val)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in reagentOptions"
|
||||
:key="item.id"
|
||||
:label="item.label"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规格" min-width="100" align="center" header-align="center">
|
||||
@@ -418,9 +437,28 @@
|
||||
<el-input v-model="row.standardUsage" placeholder="用量" class="inner-cell-input" @change="saveReagents" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="单位" min-width="80" align="center" header-align="center">
|
||||
<el-table-column label="单位" min-width="120" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.unit" placeholder="单位" class="inner-cell-input" @change="saveReagents" />
|
||||
<el-select
|
||||
v-model="row.unit"
|
||||
placeholder="请选择单位"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
class="inner-cell-select"
|
||||
:loading="itemUnitOptionsLoading"
|
||||
:remote-method="searchItemUnitOptions"
|
||||
@visible-change="(visible) => visible && searchItemUnitOptions('')"
|
||||
@change="saveReagents"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in itemUnitOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="关键物料" width="90" align="center" header-align="center">
|
||||
@@ -464,9 +502,28 @@
|
||||
<el-input v-model="row.consumableCode" placeholder="编码" class="inner-cell-input" @change="saveConsumables" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="耗材名称" min-width="120" align="center" header-align="center">
|
||||
<el-table-column label="耗材名称" min-width="160" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.consumableName" placeholder="名称" class="inner-cell-input" @change="saveConsumables" />
|
||||
<el-select
|
||||
v-model="row.consumableId"
|
||||
placeholder="请选择耗材"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
class="inner-cell-select"
|
||||
:loading="consumableOptionsLoading"
|
||||
:remote-method="searchConsumableOptions"
|
||||
@visible-change="(visible) => visible && searchConsumableOptions('')"
|
||||
@change="(val) => onConsumableRowSelect(row, val)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in consumableOptions"
|
||||
:key="item.id"
|
||||
:label="item.label"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规格型号" min-width="110" align="center" header-align="center">
|
||||
@@ -479,9 +536,28 @@
|
||||
<el-input v-model="row.standardUsage" placeholder="用量" class="inner-cell-input" @change="saveConsumables" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="单位" min-width="80" align="center" header-align="center">
|
||||
<el-table-column label="单位" min-width="120" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.unit" placeholder="单位" class="inner-cell-input" @change="saveConsumables" />
|
||||
<el-select
|
||||
v-model="row.unit"
|
||||
placeholder="请选择单位"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
class="inner-cell-select"
|
||||
:loading="itemUnitOptionsLoading"
|
||||
:remote-method="searchItemUnitOptions"
|
||||
@visible-change="(visible) => visible && searchItemUnitOptions('')"
|
||||
@change="saveConsumables"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in itemUnitOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="必需" width="80" align="center" header-align="center">
|
||||
@@ -580,16 +656,33 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="单位" min-width="120" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.unit" placeholder="如 °C、mL" class="inner-cell-input" @change="saveDataCollections" />
|
||||
<el-select
|
||||
v-model="row.unit"
|
||||
placeholder="请选择单位"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
class="inner-cell-select"
|
||||
:loading="itemUnitOptionsLoading"
|
||||
:remote-method="searchItemUnitOptions"
|
||||
@visible-change="(visible) => visible && searchItemUnitOptions('')"
|
||||
@change="saveDataCollections"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in itemUnitOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序号" min-width="100" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input-number
|
||||
<el-input
|
||||
v-model="row.orderNum"
|
||||
:min="0"
|
||||
:max="9999"
|
||||
controls-position="right"
|
||||
placeholder="排序号"
|
||||
class="inner-cell-input"
|
||||
@change="saveDataCollections"
|
||||
/>
|
||||
@@ -643,12 +736,14 @@
|
||||
fetchUpdateStepConsumables,
|
||||
fetchUpdateStepOutputs,
|
||||
fetchUpdateStepDataCollections,
|
||||
fetchReagentList,
|
||||
fetchConsumableList,
|
||||
fetchAllProcesses,
|
||||
fetchAllProcessCategories,
|
||||
fetchAllSopDocuments,
|
||||
fetchAllOutputTypes
|
||||
} from '@/api/production'
|
||||
import { fetchCellProductTypeList } from '@/api/admin'
|
||||
import { fetchCellProductTypeList, fetchItemUnitList } from '@/api/admin'
|
||||
|
||||
defineOptions({ name: 'ProductionProcessRoute' })
|
||||
|
||||
@@ -870,6 +965,234 @@
|
||||
const categoryOptions = ref<Record<string, any>[]>([])
|
||||
const sopOptions = ref<Record<string, any>[]>([])
|
||||
const outputTypeOptions = ref<Record<string, any>[]>([])
|
||||
const itemUnitOptions = ref<{ label: string; value: string }[]>([])
|
||||
const itemUnitOptionsLoading = ref(false)
|
||||
const reagentOptions = ref<{ id: string; label: string }[]>([])
|
||||
const reagentOptionsLoading = ref(false)
|
||||
const reagentMasterById = ref<Record<string, Record<string, any>>>({})
|
||||
const consumableOptions = ref<{ id: string; label: string }[]>([])
|
||||
const consumableOptionsLoading = ref(false)
|
||||
const consumableMasterById = ref<Record<string, Record<string, any>>>({})
|
||||
|
||||
function mapItemUnitOption(u: { unitName?: string; unitCode?: string }) {
|
||||
const name = (u.unitName || '').trim()
|
||||
const code = (u.unitCode || '').trim()
|
||||
return {
|
||||
label: code ? `${name}(${code})` : name,
|
||||
value: name
|
||||
}
|
||||
}
|
||||
|
||||
function ensureItemUnitOption(unitName: string) {
|
||||
const v = unitName?.trim()
|
||||
if (!v) return
|
||||
if (!itemUnitOptions.value.some((o) => o.value === v)) {
|
||||
itemUnitOptions.value = [{ label: v, value: v }, ...itemUnitOptions.value]
|
||||
}
|
||||
}
|
||||
|
||||
async function searchItemUnitOptions(query: string) {
|
||||
itemUnitOptionsLoading.value = true
|
||||
try {
|
||||
const res = await fetchItemUnitList({
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
keyword: query?.trim() || undefined
|
||||
})
|
||||
itemUnitOptions.value = (res.list || []).map(mapItemUnitOption).filter((o) => o.value)
|
||||
} catch {
|
||||
itemUnitOptions.value = []
|
||||
} finally {
|
||||
itemUnitOptionsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function mapReagentOptionLabel(r: { reagentName?: string; reagentCode?: string }) {
|
||||
const name = (r.reagentName || '').trim()
|
||||
const code = (r.reagentCode || '').trim()
|
||||
return code ? `${name}(${code})` : name
|
||||
}
|
||||
|
||||
function cacheReagentMasters(list: Record<string, any>[]) {
|
||||
const next = { ...reagentMasterById.value }
|
||||
for (const r of list) {
|
||||
if (r?.id) next[r.id] = r
|
||||
}
|
||||
reagentMasterById.value = next
|
||||
}
|
||||
|
||||
async function searchReagentOptions(query: string) {
|
||||
reagentOptionsLoading.value = true
|
||||
try {
|
||||
const res = await fetchReagentList({
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
keyword: query?.trim() || undefined
|
||||
})
|
||||
const list = res.list || []
|
||||
cacheReagentMasters(list)
|
||||
const options = list
|
||||
.filter((r) => (r.reagentName || '').trim() || (r.reagentCode || '').trim())
|
||||
.map((r) => ({ id: r.id, label: mapReagentOptionLabel(r) }))
|
||||
reagentOptions.value = options
|
||||
ensureAllStepReagentOptions()
|
||||
} catch {
|
||||
reagentOptions.value = []
|
||||
ensureAllStepReagentOptions()
|
||||
} finally {
|
||||
reagentOptionsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function ensureReagentOption(row: Record<string, any>) {
|
||||
if (row.reagentId && !String(row.reagentId).startsWith('legacy:')) {
|
||||
if (!reagentOptions.value.some((o) => o.id === row.reagentId)) {
|
||||
reagentOptions.value = [
|
||||
{ id: row.reagentId, label: mapReagentOptionLabel(row) },
|
||||
...reagentOptions.value
|
||||
]
|
||||
}
|
||||
return
|
||||
}
|
||||
const code = (row.reagentCode || '').trim()
|
||||
const name = (row.reagentName || '').trim()
|
||||
if (!code && !name) return
|
||||
const legacyId = `legacy:${code || name}`
|
||||
row.reagentId = legacyId
|
||||
if (!reagentOptions.value.some((o) => o.id === legacyId)) {
|
||||
reagentOptions.value = [{ id: legacyId, label: mapReagentOptionLabel(row) }, ...reagentOptions.value]
|
||||
}
|
||||
}
|
||||
|
||||
function ensureAllStepReagentOptions() {
|
||||
for (const step of stepList.value) {
|
||||
;(step.reagents || []).forEach((r: Record<string, any>) => ensureReagentOption(r))
|
||||
}
|
||||
}
|
||||
|
||||
function onReagentRowSelect(row: Record<string, any>, reagentId: string) {
|
||||
if (!reagentId) {
|
||||
row.reagentId = ''
|
||||
saveReagents()
|
||||
return
|
||||
}
|
||||
if (String(reagentId).startsWith('legacy:')) {
|
||||
saveReagents()
|
||||
return
|
||||
}
|
||||
const master = reagentMasterById.value[reagentId]
|
||||
if (!master) {
|
||||
saveReagents()
|
||||
return
|
||||
}
|
||||
row.reagentId = master.id
|
||||
row.reagentCode = master.reagentCode || ''
|
||||
row.reagentName = master.reagentName || ''
|
||||
row.spec = master.spec || ''
|
||||
row.standardUsage = master.standardUsage ?? ''
|
||||
row.unit = master.unit || ''
|
||||
row.remark = master.remark ?? master.description ?? ''
|
||||
ensureItemUnitOption(row.unit)
|
||||
ensureReagentOption(row)
|
||||
saveReagents()
|
||||
}
|
||||
|
||||
function mapConsumableOptionLabel(c: { consumableName?: string; consumableCode?: string }) {
|
||||
const name = (c.consumableName || '').trim()
|
||||
const code = (c.consumableCode || '').trim()
|
||||
return code ? `${name}(${code})` : name
|
||||
}
|
||||
|
||||
function cacheConsumableMasters(list: Record<string, any>[]) {
|
||||
const next = { ...consumableMasterById.value }
|
||||
for (const c of list) {
|
||||
if (c?.id) next[c.id] = c
|
||||
}
|
||||
consumableMasterById.value = next
|
||||
}
|
||||
|
||||
async function searchConsumableOptions(query: string) {
|
||||
consumableOptionsLoading.value = true
|
||||
try {
|
||||
const res = await fetchConsumableList({
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
keyword: query?.trim() || undefined
|
||||
})
|
||||
const list = res.list || []
|
||||
cacheConsumableMasters(list)
|
||||
consumableOptions.value = list
|
||||
.filter((c) => (c.consumableName || '').trim() || (c.consumableCode || '').trim())
|
||||
.map((c) => ({ id: c.id, label: mapConsumableOptionLabel(c) }))
|
||||
ensureAllStepConsumableOptions()
|
||||
} catch {
|
||||
consumableOptions.value = []
|
||||
ensureAllStepConsumableOptions()
|
||||
} finally {
|
||||
consumableOptionsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function ensureConsumableOption(row: Record<string, any>) {
|
||||
if (row.consumableId && !String(row.consumableId).startsWith('legacy:')) {
|
||||
if (!consumableOptions.value.some((o) => o.id === row.consumableId)) {
|
||||
consumableOptions.value = [
|
||||
{ id: row.consumableId, label: mapConsumableOptionLabel(row) },
|
||||
...consumableOptions.value
|
||||
]
|
||||
}
|
||||
return
|
||||
}
|
||||
const code = (row.consumableCode || '').trim()
|
||||
const name = (row.consumableName || '').trim()
|
||||
if (!code && !name) return
|
||||
const legacyId = `legacy:${code || name}`
|
||||
row.consumableId = legacyId
|
||||
if (!consumableOptions.value.some((o) => o.id === legacyId)) {
|
||||
consumableOptions.value = [{ id: legacyId, label: mapConsumableOptionLabel(row) }, ...consumableOptions.value]
|
||||
}
|
||||
}
|
||||
|
||||
function ensureAllStepConsumableOptions() {
|
||||
for (const step of stepList.value) {
|
||||
;(step.consumables || []).forEach((c: Record<string, any>) => ensureConsumableOption(c))
|
||||
}
|
||||
}
|
||||
|
||||
function onConsumableRowSelect(row: Record<string, any>, consumableId: string) {
|
||||
if (!consumableId) {
|
||||
row.consumableId = ''
|
||||
saveConsumables()
|
||||
return
|
||||
}
|
||||
if (String(consumableId).startsWith('legacy:')) {
|
||||
saveConsumables()
|
||||
return
|
||||
}
|
||||
const master = consumableMasterById.value[consumableId]
|
||||
if (!master) {
|
||||
saveConsumables()
|
||||
return
|
||||
}
|
||||
row.consumableId = master.id
|
||||
row.consumableCode = master.consumableCode || ''
|
||||
row.consumableName = master.consumableName || ''
|
||||
row.specModel = master.specModel || ''
|
||||
row.standardUsage = master.standardUsage ?? ''
|
||||
row.unit = master.unit || ''
|
||||
row.remark = master.remark ?? master.description ?? ''
|
||||
ensureItemUnitOption(row.unit)
|
||||
ensureConsumableOption(row)
|
||||
saveConsumables()
|
||||
}
|
||||
|
||||
function ensureAllStepUnitOptions() {
|
||||
for (const step of stepList.value) {
|
||||
;(step.reagents || []).forEach((r: Record<string, any>) => ensureItemUnitOption(r.unit))
|
||||
;(step.consumables || []).forEach((c: Record<string, any>) => ensureItemUnitOption(c.unit))
|
||||
;(step.dataCollections || []).forEach((d: Record<string, any>) => ensureItemUnitOption(d.unit))
|
||||
}
|
||||
}
|
||||
|
||||
const selectedStep = computed(() => {
|
||||
if (!selectedStepId.value) return null
|
||||
@@ -956,6 +1279,7 @@
|
||||
// 展开所有分类
|
||||
expandedCategories.value = Object.keys(catMap)
|
||||
processLibrary.value = Object.values(catMap)
|
||||
await Promise.all([searchItemUnitOptions(''), searchReagentOptions(''), searchConsumableOptions('')])
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
@@ -984,6 +1308,9 @@
|
||||
try {
|
||||
const detail = await fetchProcessRouteDetail(configRouteId.value)
|
||||
stepList.value = (detail.steps || []).map((s: Record<string, any>) => normalizeStepSubTables(s))
|
||||
ensureAllStepReagentOptions()
|
||||
ensureAllStepConsumableOptions()
|
||||
ensureAllStepUnitOptions()
|
||||
if (stepList.value.length > 0 && !selectedStepId.value) {
|
||||
selectedStepId.value = stepList.value[0].id
|
||||
}
|
||||
@@ -1103,6 +1430,7 @@
|
||||
if (!selectedStep.value) return
|
||||
if (!selectedStep.value.reagents) selectedStep.value.reagents = []
|
||||
selectedStep.value.reagents.push({
|
||||
reagentId: '',
|
||||
reagentCode: '',
|
||||
reagentName: '',
|
||||
spec: '',
|
||||
@@ -1144,6 +1472,7 @@
|
||||
if (!selectedStep.value) return
|
||||
if (!selectedStep.value.consumables) selectedStep.value.consumables = []
|
||||
selectedStep.value.consumables.push({
|
||||
consumableId: '',
|
||||
consumableCode: '',
|
||||
consumableName: '',
|
||||
specModel: '',
|
||||
@@ -1216,6 +1545,12 @@
|
||||
}
|
||||
|
||||
// --- 数据采集 ---
|
||||
function parseOrderNum(value: unknown): number {
|
||||
const n = Number.parseInt(String(value ?? '').trim(), 10)
|
||||
if (!Number.isFinite(n) || n < 0) return 0
|
||||
return Math.min(n, 9999)
|
||||
}
|
||||
|
||||
function addDataCollectionRow() {
|
||||
if (!selectedStep.value) return
|
||||
if (!selectedStep.value.dataCollections) selectedStep.value.dataCollections = []
|
||||
@@ -1241,7 +1576,7 @@
|
||||
items: (selectedStep.value.dataCollections || []).map((d: Record<string, any>) => ({
|
||||
collectionName: d.collectionName,
|
||||
unit: d.unit,
|
||||
orderNum: d.orderNum ?? 0,
|
||||
orderNum: parseOrderNum(d.orderNum),
|
||||
remark: d.remark || ''
|
||||
}))
|
||||
})
|
||||
@@ -1573,6 +1908,23 @@
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 步骤详情内嵌表格:单元格控件随列宽收缩 */
|
||||
.inner-table {
|
||||
width: 100%;
|
||||
|
||||
:deep(.inner-cell-input) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.inner-cell-select) {
|
||||
width: 100%;
|
||||
|
||||
.el-select__wrapper {
|
||||
min-height: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 路线图配置弹窗内的对话框滚动区域 */
|
||||
.route-config-dialog {
|
||||
:deep(.el-dialog__body) {
|
||||
|
||||
Reference in new issue
Block a user