This commit is contained in:
zlwu committed 2026-06-02 09:39:50 +08:00
1 parent 2e66e03792
commit 09afdb1d65
93 files changed
+22307 -15075

No files matched your search

BIN
View File
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
11399
19382
+2
View File
@@ -18,6 +18,7 @@ from app.api.material import router as material_router
from app.api.storage_release_review import router as storage_release_review_router
from app.api.sample_sms_notification import router as sample_sms_notification_router
from app.api.storage_entry_sms_notification import router as storage_entry_sms_notification_router
from app.api.qc_sms_notification import router as qc_sms_notification_router
from app.api.pilot_application import router as pilot_application_router
from app.api.pilot_checkup import router as pilot_checkup_router
from app.api.pilot_delivery import router as pilot_delivery_router
@@ -46,6 +47,7 @@ __all__ = [
"storage_release_review_router",
"sample_sms_notification_router",
"storage_entry_sms_notification_router",
"qc_sms_notification_router",
"pilot_application_router",
"pilot_checkup_router",
"pilot_delivery_router",
+7
View File
@@ -37,6 +37,13 @@ STATIC_MENU_TREE = [
"component": "/cell-storage/protocol-audit/index",
"meta": {"title": "采集协议单", "keepAlive": True, "menuCode": "biz:cellStorageProtocolAudit:list"},
},
{
"id": "50000000000000000000000000000013",
"name": "CellStorageSampleInfo",
"path": "sample-info",
"component": "/cell-storage/sample-info/index",
"meta": {"title": "样本信息管理", "keepAlive": True, "menuCode": "cell-storage:sample-info:list"},
},
{
"id": "50000000000000000000000000000004",
"name": "CellStoragePaymentConfirm",
+145
View File
@@ -0,0 +1,145 @@
"""样本质检短信通知 API"""
from typing import Optional
from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel, ConfigDict, Field
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.menu_guard import require_any_menu_code
from app.core.response import error_response, success_response
from app.crud import qc_sms_notification as svc
from app.crud.collection_protocol import total_pages
from app.models.models import SysUser
router = APIRouter(prefix="/web/admin", tags=["样本质检短信通知"])
_QC_SMS_MENU = require_any_menu_code(
"cell-storage:sample-info:list",
)
def _get_tenant_no(db: Session, user: dict) -> str:
user_id = user.get("user_id")
if not user_id:
raise PermissionError("用户身份信息缺失,无法确定租户")
sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
if not sys_user or not sys_user.tenant_no:
raise PermissionError("用户租户信息缺失")
return sys_user.tenant_no
def _get_current_user_id(user: dict) -> str:
user_id = user.get("user_id")
if not user_id:
raise PermissionError("用户身份信息缺失")
return str(user_id)
def _page_payload(items: list, total: int, page: int, page_size: int) -> dict:
return {
"list": items,
"total": total,
"page": page,
"pageSize": page_size,
"totalPages": total_pages(total, page_size),
}
class ToggleStatusBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
sms_notified: int = Field(..., alias="smsNotified")
qc_work_order_id: Optional[str] = Field(None, alias="qcWorkOrderId")
protocol_sample_id: Optional[str] = Field(None, alias="protocolSampleId")
@router.get("/qc-sms-notifications/list")
async def list_notifications(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100),
keyword: Optional[str] = None,
qcStatus: Optional[str] = None,
qcConclusion: Optional[str] = None,
smsNotified: Optional[int] = None,
qcCompleteTimeStart: Optional[str] = Query(None, alias="qcCompleteTimeStart"),
qcCompleteTimeEnd: Optional[str] = Query(None, alias="qcCompleteTimeEnd"),
db: Session = Depends(get_db),
user: dict = Depends(_QC_SMS_MENU),
):
try:
tenant_no = _get_tenant_no(db, user)
items, total = svc.list_notifications(
db,
page=page,
page_size=pageSize,
tenant_no=tenant_no,
keyword=keyword,
qc_status=qcStatus,
qc_conclusion=qcConclusion,
sms_notified=smsNotified,
qc_complete_time_start=qcCompleteTimeStart,
qc_complete_time_end=qcCompleteTimeEnd,
user_info=user,
)
return success_response(_page_payload(items, total, page, pageSize))
except PermissionError as e:
return error_response(403, str(e))
except Exception as e:
return error_response(400, str(e))
@router.put("/qc-sms-notifications/{notification_id}/toggle-status")
async def toggle_status(
notification_id: str,
body: ToggleStatusBody,
db: Session = Depends(get_db),
user: dict = Depends(_QC_SMS_MENU),
):
try:
tenant_no = _get_tenant_no(db, user)
user_id = _get_current_user_id(user)
result = svc.toggle_notification_status(
db,
notification_id=notification_id,
tenant_no=tenant_no,
sms_notified=body.sms_notified,
user_id=user_id,
qc_work_order_id=body.qc_work_order_id,
protocol_sample_id=body.protocol_sample_id,
)
if not result:
return error_response(404, "通知记录不存在")
return success_response(None)
except PermissionError as e:
return error_response(403, str(e))
except Exception as e:
return error_response(400, str(e))
@router.post("/qc-sms-notifications/{notification_id}/generate-sms")
async def generate_sms(
notification_id: str,
qcWorkOrderId: Optional[str] = Query(None),
protocolSampleId: Optional[str] = Query(None),
db: Session = Depends(get_db),
user: dict = Depends(_QC_SMS_MENU),
):
try:
tenant_no = _get_tenant_no(db, user)
user_id = _get_current_user_id(user)
content = svc.generate_sms_content(
db,
notification_id=notification_id,
tenant_no=tenant_no,
qc_work_order_id=qcWorkOrderId,
protocol_sample_id=protocolSampleId,
user_id=user_id,
)
if content is None:
return error_response(404, "通知记录不存在")
return success_response({"smsContent": content})
except PermissionError as e:
return error_response(403, str(e))
except Exception as e:
return error_response(400, str(e))
+9 -4
View File
@@ -6,7 +6,7 @@ from pydantic import BaseModel, ConfigDict, Field
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.menu_guard import require_menu_code
from app.core.menu_guard import require_any_menu_code
from app.core.response import error_response, success_response
from app.crud import sample_sms_notification as svc
from app.crud.collection_protocol import total_pages
@@ -14,6 +14,11 @@ from app.models.models import SysUser
router = APIRouter(prefix="/web/admin", tags=["样本接收短信通知"])
_SAMPLE_RECEPTION_MENU = require_any_menu_code(
"cell-storage:sample-info:list",
"cell-storage:sample-reception-info:list",
)
def _get_tenant_no(db: Session, user: dict) -> str:
user_id = user.get("user_id")
@@ -59,7 +64,7 @@ async def list_notifications(
receptionTimeStart: Optional[str] = Query(None, alias="receptionTimeStart"),
receptionTimeEnd: Optional[str] = Query(None, alias="receptionTimeEnd"),
db: Session = Depends(get_db),
user: dict = Depends(require_menu_code("cell-storage:sample-reception-info:list")),
user: dict = Depends(_SAMPLE_RECEPTION_MENU),
):
try:
tenant_no = _get_tenant_no(db, user)
@@ -87,7 +92,7 @@ async def toggle_status(
notification_id: str,
body: ToggleStatusBody,
db: Session = Depends(get_db),
user: dict = Depends(require_menu_code("cell-storage:sample-reception-info:list")),
user: dict = Depends(_SAMPLE_RECEPTION_MENU),
):
try:
tenant_no = _get_tenant_no(db, user)
@@ -114,7 +119,7 @@ async def generate_sms(
notification_id: str,
sampleReceptionId: Optional[str] = Query(None),
db: Session = Depends(get_db),
user: dict = Depends(require_menu_code("cell-storage:sample-reception-info:list")),
user: dict = Depends(_SAMPLE_RECEPTION_MENU),
):
try:
tenant_no = _get_tenant_no(db, user)
@@ -6,7 +6,7 @@ from pydantic import BaseModel, ConfigDict, Field
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.menu_guard import require_menu_code
from app.core.menu_guard import require_any_menu_code
from app.core.response import error_response, success_response
from app.crud import storage_entry_sms_notification as svc
from app.crud.collection_protocol import total_pages
@@ -14,6 +14,11 @@ from app.models.models import SysUser
router = APIRouter(prefix="/web/admin", tags=["样本入库短信通知"])
_STORAGE_ENTRY_MENU = require_any_menu_code(
"cell-storage:sample-info:list",
"cell-storage:storage-entry-info:list",
)
def _get_tenant_no(db: Session, user: dict) -> str:
user_id = user.get("user_id")
@@ -59,7 +64,7 @@ async def list_notifications(
storageTimeStart: Optional[str] = Query(None, alias="storageTimeStart"),
storageTimeEnd: Optional[str] = Query(None, alias="storageTimeEnd"),
db: Session = Depends(get_db),
user: dict = Depends(require_menu_code("cell-storage:storage-entry-info:list")),
user: dict = Depends(_STORAGE_ENTRY_MENU),
):
try:
tenant_no = _get_tenant_no(db, user)
@@ -87,7 +92,7 @@ async def toggle_status(
notification_id: str,
body: ToggleStatusBody,
db: Session = Depends(get_db),
user: dict = Depends(require_menu_code("cell-storage:storage-entry-info:list")),
user: dict = Depends(_STORAGE_ENTRY_MENU),
):
try:
tenant_no = _get_tenant_no(db, user)
@@ -114,7 +119,7 @@ async def generate_sms(
notification_id: str,
storageReviewId: Optional[str] = Query(None),
db: Session = Depends(get_db),
user: dict = Depends(require_menu_code("cell-storage:storage-entry-info:list")),
user: dict = Depends(_STORAGE_ENTRY_MENU),
):
try:
tenant_no = _get_tenant_no(db, user)
+19
View File
@@ -42,3 +42,22 @@ def require_menu_code(menu_code: str) -> Callable:
return current_user
return _dep
def require_any_menu_code(*menu_codes: str) -> Callable:
"""接口菜单权限守卫:拥有任一 menuCode 即可访问。super_admin 直接放行。"""
normalized = {(code or "").strip() for code in menu_codes if (code or "").strip()}
def _dep(
current_user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
role = current_user.get("role")
if role == SUPER_ADMIN_ROLE:
return current_user
codes = get_user_menu_codes(db, current_user.get("user_id"))
if not normalized.intersection(codes):
raise HTTPException(status_code=403, detail="无菜单访问权限")
return current_user
return _dep
+35 -2
View File
@@ -2,8 +2,8 @@
import uuid
import random
import string
from datetime import datetime
from typing import Optional
from datetime import date, datetime
from typing import Optional, Union
def generate_uuid() -> str:
@@ -45,6 +45,39 @@ def parse_datetime(dt_str: str) -> Optional[datetime]:
return None
def format_date(d: Optional[Union[date, datetime]]) -> str:
"""格式化日期为 YYYY-MM-DD"""
if d is None:
return ""
if isinstance(d, datetime):
d = d.date()
return d.strftime("%Y-%m-%d")
def parse_date(date_str: str) -> Optional[date]:
"""解析 YYYY-MM-DD 日期"""
if not date_str:
return None
try:
s = str(date_str).strip()
if not s:
return None
return datetime.fromisoformat(s[:10]).date()
except (ValueError, AttributeError):
return None
def optional_date(v: object) -> Optional[date]:
"""将字符串 / date / datetime 转为 date 或 None"""
if v is None or v == "":
return None
if isinstance(v, datetime):
return v.date()
if isinstance(v, date):
return v
return parse_date(str(v))
def get_file_size_display(size_bytes: int) -> str:
"""将字节数转换为可读的文件大小"""
if size_bytes is None:
+59 -1
View File
@@ -10,7 +10,7 @@ from typing import Any, Dict, List, Optional, Tuple
from sqlalchemy import and_, func, or_
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid, parse_datetime
from app.core.utils import generate_uuid, parse_datetime, format_date, optional_date
from app.crud.base import camel_to_snake
from app.crud.biz_no_generator import allocate_next_biz_no
from app.crud.protocol_donation_convert import (
@@ -445,6 +445,7 @@ def _party_customer_to_dict(p: BizProtocolPartyCustomer) -> Dict[str, Any]:
"fatherIdCard": p.father_id_card or "",
"newbornName": p.newborn_name or "",
"newbornIdCard": p.newborn_id_card or "",
"expectedDeliveryDate": format_date(p.expected_delivery_date),
"newbornDeliveryTime": _fmt_dt(p.newborn_delivery_time),
"newbornSex": p.newborn_sex or "",
"deliveryMode": p.delivery_mode or "",
@@ -555,6 +556,24 @@ def _format_newborn_info(pc: Optional[BizProtocolPartyCustomer]) -> str:
return " / ".join(parts)
def _format_sample_collect_summary(samples: List[BizProtocolSample]) -> str:
"""汇总协议单下各样本采集情况,如「1个已采集,1个未采集」。"""
collected = 0
not_collected = 0
for s in samples:
status = (s.sample_status or "").strip()
if status:
collected += 1
else:
not_collected += 1
parts: List[str] = []
if collected:
parts.append(f"{collected}个已采集")
if not_collected:
parts.append(f"{not_collected}个未采集")
return ",".join(parts)
def _format_storage_cert_sample_info(
samples: List[Dict[str, Any]], type_map: Dict[str, str]
) -> str:
@@ -912,6 +931,23 @@ def list_collection_protocols(
for u in db.query(SysUser.id, SysUser.nick_name).filter(SysUser.id.in_(all_user_ids)).all():
user_name_map[u.id] = u.nick_name or ""
# 批量加载协议样本(列表展示样本类型、样本编码)
sample_map: Dict[str, List[BizProtocolSample]] = {}
sample_type_name_map: Dict[str, str] = {}
if protocol_ids:
s_rows = (
db.query(BizProtocolSample)
.filter(
BizProtocolSample.collection_protocol_id.in_(protocol_ids),
BizProtocolSample.del_flag == 0,
)
.order_by(BizProtocolSample.order_num.asc(), BizProtocolSample.create_time.asc())
.all()
)
sample_type_name_map = _load_sample_type_name_map(db, s_rows)
for s in s_rows:
sample_map.setdefault(s.collection_protocol_id, []).append(s)
# 合并主表 + 子表数据
result = []
for r in rows:
@@ -927,6 +963,7 @@ def list_collection_protocols(
d["motherEthnic"] = pc.get("motherEthnic", "")
d["fatherName"] = pc.get("fatherName", "")
d["fatherPhone"] = pc.get("fatherPhone", "")
d["expectedDeliveryDate"] = pc.get("expectedDeliveryDate", "")
d["newbornDeliveryTime"] = pc.get("newbornDeliveryTime", "")
d["newbornSex"] = pc.get("newbornSex", "")
d["deliveryMode"] = pc.get("deliveryMode", "")
@@ -940,6 +977,7 @@ def list_collection_protocols(
d["motherEthnic"] = ""
d["fatherName"] = ""
d["fatherPhone"] = ""
d["expectedDeliveryDate"] = ""
d["newbornDeliveryTime"] = ""
d["newbornSex"] = ""
d["deliveryMode"] = ""
@@ -955,6 +993,19 @@ def list_collection_protocols(
d["hospitalName"] = ""
d["salesUserName"] = ""
d["sampleCollectTime"] = ""
protocol_samples = sample_map.get(r.id, [])
type_names: List[str] = []
codes: List[str] = []
for s in protocol_samples:
type_name = sample_type_name_map.get(s.sample_type_id or "", "")
if type_name:
type_names.append(type_name)
code = (s.sample_code or "").strip()
if code:
codes.append(code)
d["sampleTypeNames"] = ",".join(type_names)
d["sampleCodes"] = ",".join(codes)
d["sampleCollectSummary"] = _format_sample_collect_summary(protocol_samples)
result.append(d)
return result, int(total)
@@ -2030,6 +2081,7 @@ def upsert_party_customer(
]
_INT_FIELDS = ["birth_order", "newborn_weight_gram"]
_DEC_FIELDS = ["apgar_1min", "apgar_5min"]
_DATE_FIELDS = ["expected_delivery_date"]
_DT_FIELDS = ["newborn_delivery_time"]
if obj:
for k in _STR_FIELDS:
@@ -2041,6 +2093,9 @@ def upsert_party_customer(
for k in _DEC_FIELDS:
if k in fields:
setattr(obj, k, _optional_decimal(fields[k]))
for k in _DATE_FIELDS:
if k in fields:
setattr(obj, k, optional_date(fields[k]))
for k in _DT_FIELDS:
if k in fields:
setattr(obj, k, fields[k])
@@ -2074,6 +2129,9 @@ def upsert_party_customer(
for k in _DEC_FIELDS:
if k in fields:
setattr(obj, k, _optional_decimal(fields[k]))
for k in _DATE_FIELDS:
if k in fields:
setattr(obj, k, optional_date(fields[k]))
for k in _DT_FIELDS:
if k in fields:
setattr(obj, k, fields[k])
+618
View File
@@ -0,0 +1,618 @@
"""样本质检短信通知 CRUD"""
from __future__ import annotations
import math
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
from sqlalchemy import and_, case, func, or_
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid
from app.models.models import (
BizCellSampleType,
BizCollectionProtocol,
BizProtocolPartyCustomer,
BizProtocolSample,
BizQcSmsNotification,
BizQcTask,
BizQcWorkOrder,
SysUser,
)
# biz_qc_work_order / biz_qc_task 为 general_ci;与 unicode_ci 表 JOIN 时需 collate 对齐
_UNICODE_CI = "utf8mb4_unicode_ci"
def _unicode_ci(col):
return col.collate(_UNICODE_CI)
def _eq_ci(left, right):
"""列与列比较时两侧 collate;与字面量比较时仅对列侧 collate。"""
if isinstance(left, str):
return left == (_unicode_ci(right) if not isinstance(right, str) else right)
if isinstance(right, str):
return _unicode_ci(left) == right
return _unicode_ci(left) == _unicode_ci(right)
def total_pages(total: int, page_size: int) -> int:
if total <= 0:
return 0
return int(math.ceil(total / float(page_size)))
def _fmt_dt(t: Optional[datetime]) -> str:
return t.strftime("%Y-%m-%d %H:%M:%S") if t else ""
def _normalize_date_bound(value: str, *, end_of_day: bool = False) -> str:
val = (value or "").strip()
if len(val) == 10:
return f"{val} 23:59:59" if end_of_day else f"{val} 00:00:00"
return val
def _derive_qc_conclusion(tasks: List[BizQcTask]) -> str:
if not tasks:
return ""
if any((t.conclusion or "").strip() == "btg" for t in tasks):
return "btg"
if all((t.conclusion or "").strip() == "tg" for t in tasks):
return "tg"
return ""
def _qc_status_label(
wo: Optional[BizQcWorkOrder],
*,
qc_conclusion: str = "",
) -> Tuple[str, str]:
if not wo:
return "dzj", "待质检"
st = (wo.work_order_status or "").strip()
if st == "yzf":
return "yzf", "已作废"
if st == "ypz":
return "zjz", "质检中"
if st == "ywc":
if qc_conclusion == "btg":
return "btg", "不通过"
if qc_conclusion == "tg":
return "tg", "通过"
return "zjz", "质检中"
return "dzj", "待质检"
def _fetch_completed_tasks(db: Session, work_order_id: str, tenant_no: str) -> List[BizQcTask]:
if not work_order_id:
return []
return (
db.query(BizQcTask)
.filter(
BizQcTask.work_order_id == work_order_id,
BizQcTask.tenant_no == tenant_no,
BizQcTask.del_flag == 0,
BizQcTask.task_status == "ywc",
)
.all()
)
def _qc_complete_time(tasks: List[BizQcTask], wo: Optional[BizQcWorkOrder]) -> Optional[datetime]:
times = [t.completed_time for t in tasks if t.completed_time]
if times:
return max(times)
return wo.update_time if wo else None
def _row_to_dict(
*,
notification_id: str = "",
qc_work_order_id: str = "",
protocol_sample_id: str = "",
protocol_id: str = "",
sms_notified: int = 0,
sms_content: str = "",
protocol_no: str = "",
mother_name: str = "",
newborn_name: str = "",
sample_code: str = "",
sample_type_name: str = "",
qc_complete_time: str = "",
qc_status: str = "",
qc_status_label: str = "",
qc_conclusion: str = "",
collection_protocol_id: str = "",
protocol_status: str = "",
) -> Dict[str, Any]:
return {
"id": notification_id,
"qcWorkOrderId": qc_work_order_id,
"protocolSampleId": protocol_sample_id,
"protocolId": protocol_id,
"protocolNo": protocol_no,
"protocolStatus": protocol_status,
"motherName": mother_name,
"newbornName": newborn_name,
"sampleCode": sample_code,
"sampleTypeName": sample_type_name,
"qcCompleteTime": qc_complete_time,
"qcStatus": qc_status,
"qcStatusLabel": qc_status_label,
"qcConclusion": qc_conclusion,
"qcConclusionLabel": qc_status_label if qc_status in ("tg", "btg") else "",
"smsNotified": sms_notified,
"smsContent": sms_content,
"collectionProtocolId": collection_protocol_id,
}
def _base_query(db: Session, tenant_no: str):
return (
db.query(
BizProtocolSample,
BizQcWorkOrder,
BizQcSmsNotification,
BizCollectionProtocol,
BizProtocolPartyCustomer,
)
.outerjoin(
BizQcWorkOrder,
and_(
_eq_ci(BizQcWorkOrder.sample_code, BizProtocolSample.sample_code),
BizQcWorkOrder.tenant_no == tenant_no,
BizQcWorkOrder.del_flag == 0,
BizQcWorkOrder.reception_source == "cell_storage",
BizQcWorkOrder.qc_biz_type == "inbound",
),
)
.outerjoin(
BizQcSmsNotification,
and_(
_eq_ci(BizQcSmsNotification.protocol_sample_id, BizProtocolSample.id),
BizQcSmsNotification.tenant_no == tenant_no,
BizQcSmsNotification.del_flag == "0",
),
)
.outerjoin(
BizCollectionProtocol,
and_(
BizCollectionProtocol.id == BizProtocolSample.collection_protocol_id,
BizCollectionProtocol.del_flag == 0,
),
)
.outerjoin(
BizProtocolPartyCustomer,
and_(
BizProtocolPartyCustomer.collection_protocol_id == BizCollectionProtocol.id,
BizProtocolPartyCustomer.del_flag == 0,
),
)
.filter(
BizProtocolSample.tenant_no == tenant_no,
BizProtocolSample.del_flag == 0,
)
)
def _ensure_notification(
db: Session,
psample: BizProtocolSample,
tenant_no: str,
user_id: Optional[str] = None,
*,
wo: Optional[BizQcWorkOrder] = None,
) -> BizQcSmsNotification:
existing = (
db.query(BizQcSmsNotification)
.filter(
BizQcSmsNotification.protocol_sample_id == psample.id,
BizQcSmsNotification.tenant_no == tenant_no,
BizQcSmsNotification.del_flag == "0",
)
.first()
)
if existing:
if wo and not existing.qc_work_order_id:
existing.qc_work_order_id = wo.id
existing.protocol_id = wo.collection_protocol_id or psample.collection_protocol_id or ""
existing.update_time = datetime.now()
db.commit()
db.refresh(existing)
return existing
obj = BizQcSmsNotification(
id=generate_uuid(),
protocol_sample_id=psample.id,
qc_work_order_id=wo.id if wo else None,
protocol_id=(wo.collection_protocol_id if wo else psample.collection_protocol_id) or "",
sms_notified=0,
tenant_no=tenant_no,
create_by=user_id,
update_by=user_id,
)
db.add(obj)
db.flush()
db.commit()
db.refresh(obj)
return obj
def resolve_notification(
db: Session,
*,
notification_id: str,
tenant_no: str,
qc_work_order_id: Optional[str] = None,
protocol_sample_id: Optional[str] = None,
user_id: Optional[str] = None,
) -> Optional[BizQcSmsNotification]:
notif = (
db.query(BizQcSmsNotification)
.filter(
BizQcSmsNotification.id == notification_id,
BizQcSmsNotification.tenant_no == tenant_no,
BizQcSmsNotification.del_flag == "0",
)
.first()
)
if notif:
return notif
psample = None
if protocol_sample_id:
psample = (
db.query(BizProtocolSample)
.filter(
BizProtocolSample.id == protocol_sample_id,
BizProtocolSample.tenant_no == tenant_no,
BizProtocolSample.del_flag == 0,
)
.first()
)
elif qc_work_order_id:
wo = (
db.query(BizQcWorkOrder)
.filter(
BizQcWorkOrder.id == qc_work_order_id,
BizQcWorkOrder.tenant_no == tenant_no,
BizQcWorkOrder.del_flag == 0,
)
.first()
)
if wo and wo.sample_code:
psample = (
db.query(BizProtocolSample)
.filter(
_eq_ci(BizProtocolSample.sample_code, wo.sample_code),
BizProtocolSample.tenant_no == tenant_no,
BizProtocolSample.del_flag == 0,
)
.first()
)
if not psample:
return None
wo = None
if qc_work_order_id:
wo = (
db.query(BizQcWorkOrder)
.filter(
BizQcWorkOrder.id == qc_work_order_id,
BizQcWorkOrder.tenant_no == tenant_no,
BizQcWorkOrder.del_flag == 0,
)
.first()
)
return _ensure_notification(db, psample, tenant_no=tenant_no, user_id=user_id, wo=wo)
def _task_stats_subquery(db: Session, tenant_no: str):
return (
db.query(
BizQcTask.work_order_id.label("work_order_id"),
func.max(case((BizQcTask.conclusion == "btg", 1), else_=0)).label("has_btg"),
func.count(BizQcTask.id).label("task_count"),
func.max(BizQcTask.completed_time).label("max_completed_time"),
)
.filter(
BizQcTask.tenant_no == tenant_no,
BizQcTask.del_flag == 0,
BizQcTask.task_status == "ywc",
)
.group_by(BizQcTask.work_order_id)
.subquery()
)
def _apply_qc_status_filter(q, qc_status: str, task_stats):
if qc_status == "dzj":
return q.filter(
or_(
BizQcWorkOrder.id.is_(None),
BizQcWorkOrder.work_order_status == "dpz",
)
)
if qc_status == "zjz":
return q.filter(BizQcWorkOrder.work_order_status == "ypz")
if qc_status == "yzf":
return q.filter(BizQcWorkOrder.work_order_status == "yzf")
if qc_status == "btg":
return q.filter(
BizQcWorkOrder.work_order_status == "ywc",
task_stats.c.has_btg == 1,
)
if qc_status == "tg":
return q.filter(
BizQcWorkOrder.work_order_status == "ywc",
task_stats.c.has_btg == 0,
task_stats.c.task_count > 0,
)
return q
def list_notifications(
db: Session,
*,
page: int = 1,
page_size: int = 10,
tenant_no: str,
keyword: Optional[str] = None,
qc_status: Optional[str] = None,
qc_conclusion: Optional[str] = None,
sms_notified: Optional[int] = None,
qc_complete_time_start: Optional[str] = None,
qc_complete_time_end: Optional[str] = None,
user_info=None,
) -> Tuple[List[Dict[str, Any]], int]:
if not tenant_no:
return [], 0
status_filter = (qc_status or qc_conclusion or "").strip()
task_stats = _task_stats_subquery(db, tenant_no)
q = _base_query(db, tenant_no).outerjoin(
task_stats,
_eq_ci(task_stats.c.work_order_id, BizQcWorkOrder.id),
)
if keyword and keyword.strip():
kw = f"%{keyword.strip()}%"
q = q.filter(
or_(
BizCollectionProtocol.protocol_no.like(kw),
BizProtocolPartyCustomer.mother_name.like(kw),
BizProtocolSample.sample_code.like(kw),
)
)
if status_filter:
q = _apply_qc_status_filter(q, status_filter, task_stats)
if sms_notified is not None:
if sms_notified == 0:
q = q.filter(
or_(
BizQcSmsNotification.sms_notified == 0,
BizQcSmsNotification.id.is_(None),
)
)
else:
q = q.filter(BizQcSmsNotification.sms_notified == sms_notified)
if qc_complete_time_start:
q = q.filter(
BizProtocolSample.create_time >= _normalize_date_bound(qc_complete_time_start)
)
if qc_complete_time_end:
q = q.filter(
BizProtocolSample.create_time
<= _normalize_date_bound(qc_complete_time_end, end_of_day=True)
)
if user_info:
from app.core.data_scope import apply_data_scope
q = apply_data_scope(q, BizProtocolSample, user_info, db, tenant_no)
total = q.count()
page = max(1, page)
page_size = min(max(1, page_size), 100)
rows = (
q.order_by(
BizProtocolSample.create_time.desc(),
BizProtocolSample.id.desc(),
)
.offset((page - 1) * page_size)
.limit(page_size)
.all()
)
sample_type_ids = list({
psample.sample_type_id
for psample, _, _, _, _ in rows
if psample and psample.sample_type_id
})
type_map: Dict[str, str] = {}
if sample_type_ids:
for t in (
db.query(BizCellSampleType)
.filter(BizCellSampleType.id.in_(sample_type_ids), BizCellSampleType.del_flag == 0)
.all()
):
type_map[t.id] = t.type_name or ""
items: List[Dict[str, Any]] = []
for psample, wo, notif, proto, party in rows:
if notif is None:
notif = _ensure_notification(db, psample, tenant_no=tenant_no, wo=wo)
tasks = _fetch_completed_tasks(db, wo.id if wo else "", tenant_no)
conclusion = _derive_qc_conclusion(tasks) if wo else ""
status_code, status_label = _qc_status_label(wo, qc_conclusion=conclusion)
complete_dt = _qc_complete_time(tasks, wo) if status_code in ("tg", "btg") else None
sample_type_name = ""
if psample.sample_type_id:
sample_type_name = type_map.get(psample.sample_type_id, "")
items.append(
_row_to_dict(
notification_id=notif.id,
qc_work_order_id=(wo.id if wo else ""),
protocol_sample_id=psample.id,
protocol_id=(notif.protocol_id or "") if notif else "",
sms_notified=(notif.sms_notified or 0) if notif else 0,
sms_content=(notif.sms_content or "") if notif else "",
protocol_no=(proto.protocol_no or "") if proto else "",
mother_name=(party.mother_name or "") if party else "",
newborn_name=(party.newborn_name or "") if party else "",
sample_code=psample.sample_code or (wo.sample_code if wo else "") or "",
sample_type_name=sample_type_name,
qc_complete_time=_fmt_dt(complete_dt) if complete_dt else "",
qc_status=status_code,
qc_status_label=status_label,
qc_conclusion=conclusion,
collection_protocol_id=(proto.id or "") if proto else "",
protocol_status=(proto.protocol_status or "") if proto else "",
)
)
return items, int(total)
def toggle_notification_status(
db: Session,
*,
notification_id: str,
tenant_no: str,
sms_notified: int,
user_id: Optional[str] = None,
qc_work_order_id: Optional[str] = None,
protocol_sample_id: Optional[str] = None,
) -> Optional[BizQcSmsNotification]:
notif = resolve_notification(
db,
notification_id=notification_id,
tenant_no=tenant_no,
qc_work_order_id=qc_work_order_id,
protocol_sample_id=protocol_sample_id,
user_id=user_id,
)
if not notif:
return None
notif.sms_notified = sms_notified
if sms_notified == 1:
notif.notified_by = user_id
notif.notified_time = datetime.now()
_user = db.query(SysUser.nick_name).filter(SysUser.id == user_id).first()
notif.notified_by_name = _user.nick_name if _user else None
else:
notif.notified_by = None
notif.notified_by_name = None
notif.notified_time = None
notif.update_by = user_id
notif.update_time = datetime.now()
db.commit()
db.refresh(notif)
return notif
def generate_sms_content(
db: Session,
*,
notification_id: str,
tenant_no: str,
qc_work_order_id: Optional[str] = None,
protocol_sample_id: Optional[str] = None,
user_id: Optional[str] = None,
) -> Optional[str]:
notif = resolve_notification(
db,
notification_id=notification_id,
tenant_no=tenant_no,
qc_work_order_id=qc_work_order_id,
protocol_sample_id=protocol_sample_id,
user_id=user_id,
)
if not notif:
return None
psample = (
db.query(BizProtocolSample)
.filter(
BizProtocolSample.id == notif.protocol_sample_id,
BizProtocolSample.tenant_no == tenant_no,
BizProtocolSample.del_flag == 0,
)
.first()
)
wo = None
if notif.qc_work_order_id:
wo = (
db.query(BizQcWorkOrder)
.filter(
_eq_ci(BizQcWorkOrder.id, notif.qc_work_order_id),
BizQcWorkOrder.tenant_no == tenant_no,
BizQcWorkOrder.del_flag == 0,
)
.first()
)
if not wo and psample and psample.sample_code:
wo = (
db.query(BizQcWorkOrder)
.filter(
_eq_ci(BizQcWorkOrder.sample_code, psample.sample_code),
BizQcWorkOrder.tenant_no == tenant_no,
BizQcWorkOrder.del_flag == 0,
BizQcWorkOrder.reception_source == "cell_storage",
BizQcWorkOrder.qc_biz_type == "inbound",
)
.first()
)
tasks = _fetch_completed_tasks(db, wo.id if wo else "", tenant_no)
conclusion = _derive_qc_conclusion(tasks)
if not conclusion:
status_code, status_label = _qc_status_label(wo, qc_conclusion="")
if status_code == "dzj":
return "暂无短信内容,样本尚未开始质检"
if status_code == "zjz":
return "暂无短信内容,样本质检尚未完成"
return "暂无短信内容,样本尚未完成质检确认"
mother_name = ""
proto_id = (wo.collection_protocol_id if wo else psample.collection_protocol_id) if psample else ""
if proto_id:
party = (
db.query(BizProtocolPartyCustomer)
.filter(
BizProtocolPartyCustomer.collection_protocol_id == proto_id,
BizProtocolPartyCustomer.del_flag == 0,
)
.first()
)
if party:
mother_name = party.mother_name or ""
sample_code = (psample.sample_code if psample else "") or (wo.sample_code if wo else "") or ""
if conclusion == "tg":
content = (
f"尊敬的{mother_name}女士,您的样本(编码:{sample_code})"
f"已完成质检,结果合格。如有疑问请联系客服。"
)
else:
content = (
f"尊敬的{mother_name}女士,您的样本(编码:{sample_code})"
f"质检未通过。如有疑问请联系客服。"
)
notif.sms_content = content
if wo and not notif.qc_work_order_id:
notif.qc_work_order_id = wo.id
notif.update_time = datetime.now()
db.commit()
db.refresh(notif)
return content
+288 -251
View File
@@ -1022,14 +1022,16 @@ def get_work_order_detail(
return out
def _soft_delete_pending_work_order_tasks(
db: Session, work_order_id: str, tenant_no: str
def _soft_delete_tasks_by_source_line_ids(
db: Session, source_line_ids: List[str], tenant_no: str
) -> None:
"""调整检测前软删该工单下全部质检任务(含进行中/已完成)及其检测结果。"""
"""软删指定明细行关联的质检任务及其检测结果。"""
if not source_line_ids:
return
tasks = (
db.query(BizQcTask)
.filter(
BizQcTask.work_order_id == work_order_id,
BizQcTask.source_line_id.in_(source_line_ids),
BizQcTask.tenant_no == tenant_no,
BizQcTask.del_flag == 0,
)
@@ -1039,21 +1041,256 @@ def _soft_delete_pending_work_order_tasks(
return
now = datetime.now()
task_ids = [t.id for t in tasks]
if task_ids:
db.query(BizQcTaskResult).filter(
BizQcTaskResult.task_id.in_(task_ids),
BizQcTaskResult.tenant_no == tenant_no,
BizQcTaskResult.del_flag == 0,
).update(
{"del_flag": 1, "update_time": now},
synchronize_session="fetch",
)
db.query(BizQcTaskResult).filter(
BizQcTaskResult.task_id.in_(task_ids),
BizQcTaskResult.tenant_no == tenant_no,
BizQcTaskResult.del_flag == 0,
).update(
{"del_flag": 1, "update_time": now},
synchronize_session="fetch",
)
for t in tasks:
t.del_flag = 1
t.update_time = now
db.add(t)
def _get_task_by_source_line_id(
db: Session, source_line_id: str, tenant_no: str
) -> Optional[BizQcTask]:
return (
db.query(BizQcTask)
.filter(
BizQcTask.source_line_id == source_line_id,
BizQcTask.tenant_no == tenant_no,
BizQcTask.del_flag == 0,
)
.first()
)
def _sync_work_order_lab_items(
db: Session,
wo: BizQcWorkOrder,
*,
order_source: str,
lab_item_ids: List[str],
tenant_no: str,
user_id: Optional[str],
create_dept_id: str,
seq_start: int = 0,
) -> int:
"""比对同步实验室项目明细:保留已有任务数据,仅增删变更项。"""
now = datetime.now()
existing_rows = (
db.query(BizQcWorkOrderLabItem)
.filter(
BizQcWorkOrderLabItem.work_order_id == wo.id,
BizQcWorkOrderLabItem.order_source == order_source,
BizQcWorkOrderLabItem.del_flag == 0,
)
.all()
)
existing_by_item_id = {r.lab_test_item_id: r for r in existing_rows}
new_id_set = set(lab_item_ids)
old_id_set = set(existing_by_item_id.keys())
remove_line_ids = [existing_by_item_id[i].id for i in old_id_set - new_id_set]
for item_id in old_id_set - new_id_set:
line = existing_by_item_id[item_id]
line.del_flag = 1
line.update_by = user_id
line.update_time = now
db.add(line)
_soft_delete_tasks_by_source_line_ids(db, remove_line_ids, tenant_no)
seq = seq_start
for lid in lab_item_ids:
seq += 1
if lid in existing_by_item_id and lid in new_id_set:
line = existing_by_item_id[lid]
line.order_num = seq
line.update_by = user_id
line.update_time = now
db.add(line)
task = _get_task_by_source_line_id(db, line.id, tenant_no)
if task:
task.order_num = seq
task.update_by = user_id
task.update_time = now
db.add(task)
else:
task_svc.create_task_for_line(
db,
work_order=wo,
task_type="sysz",
source_line_id=line.id,
item_code=line.item_code,
item_name=line.item_name,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
seq=seq,
order_source=order_source,
)
continue
item = lab_item_svc.get_lab_item(db, lid, tenant_no=tenant_no)
if not item or item.status != "1":
raise ValueError("实验室项目无效或已停用")
line = BizQcWorkOrderLabItem(
id=generate_uuid(),
work_order_id=wo.id,
order_source=order_source,
lab_test_item_id=item.id,
item_code=item.item_code,
item_name=item.item_name,
tenant_no=tenant_no,
order_num=seq,
create_by=user_id,
create_dept_id=create_dept_id or "",
create_time=now,
update_by=user_id,
update_time=now,
del_flag=0,
)
db.add(line)
db.flush()
task_svc.create_task_for_line(
db,
work_order=wo,
task_type="sysz",
source_line_id=line.id,
item_code=line.item_code,
item_name=line.item_name,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
seq=seq,
order_source=order_source,
)
return seq
def _sync_work_order_third_party_items(
db: Session,
wo: BizQcWorkOrder,
*,
order_source: str,
third_party_item_ids: List[str],
tenant_no: str,
user_id: Optional[str],
create_dept_id: str,
seq_start: int = 0,
) -> Tuple[int, Decimal]:
"""比对同步第三方项目明细:保留已有任务数据,仅增删变更项。"""
now = datetime.now()
existing_rows = (
db.query(BizQcWorkOrderThirdItem)
.filter(
BizQcWorkOrderThirdItem.work_order_id == wo.id,
BizQcWorkOrderThirdItem.order_source == order_source,
BizQcWorkOrderThirdItem.del_flag == 0,
)
.all()
)
existing_by_item_id = {r.third_party_item_id: r for r in existing_rows}
new_id_set = set(third_party_item_ids)
old_id_set = set(existing_by_item_id.keys())
remove_line_ids = [existing_by_item_id[i].id for i in old_id_set - new_id_set]
for item_id in old_id_set - new_id_set:
line = existing_by_item_id[item_id]
line.del_flag = 1
line.update_by = user_id
line.update_time = now
db.add(line)
_soft_delete_tasks_by_source_line_ids(db, remove_line_ids, tenant_no)
fee_total = Decimal("0")
seq = seq_start
for tid in third_party_item_ids:
seq += 1
if tid in existing_by_item_id and tid in new_id_set:
line = existing_by_item_id[tid]
line.order_num = seq
line.update_by = user_id
line.update_time = now
db.add(line)
fee_total += line.fee_amount or Decimal("0")
task = _get_task_by_source_line_id(db, line.id, tenant_no)
if task:
task.order_num = seq
task.update_by = user_id
task.update_time = now
db.add(task)
else:
task_svc.create_task_for_line(
db,
work_order=wo,
task_type="dsfjc",
source_line_id=line.id,
item_code=line.item_code,
item_name=line.item_name,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
seq=seq,
company_id=line.company_id,
company_name=line.company_name,
fee_amount=line.fee_amount,
order_source=order_source,
)
continue
item = third_item_svc.get_item(db, tid, tenant_no=tenant_no)
if not item or item.status != "1":
raise ValueError("第三方项目无效或已停用")
comp = get_company(db, item.company_id, tenant_no=tenant_no)
if not comp:
raise ValueError("第三方公司不存在")
fee = item.fee_amount or Decimal("0")
fee_total += fee
line = BizQcWorkOrderThirdItem(
id=generate_uuid(),
work_order_id=wo.id,
order_source=order_source,
third_party_item_id=item.id,
company_id=comp.id,
company_name=comp.company_name,
item_code=item.item_code,
item_name=item.item_name,
fee_amount=fee,
tenant_no=tenant_no,
order_num=seq,
create_by=user_id,
create_dept_id=create_dept_id or "",
create_time=now,
update_by=user_id,
update_time=now,
del_flag=0,
)
db.add(line)
db.flush()
task_svc.create_task_for_line(
db,
work_order=wo,
task_type="dsfjc",
source_line_id=line.id,
item_code=line.item_code,
item_name=line.item_name,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
seq=seq,
company_id=comp.id,
company_name=comp.company_name,
fee_amount=fee,
order_source=order_source,
)
return seq, fee_total
def configure_work_order(
db: Session,
work_order_id: str,
@@ -1076,8 +1313,6 @@ def configure_work_order(
order_source = "outbound"
else:
order_source = "inbound"
if wo.work_order_status != "dpz":
_soft_delete_pending_work_order_tasks(db, wo.id, tenant_no)
if not has_lab and not has_third_party:
raise ValueError("请至少选择一种检测方式")
@@ -1090,107 +1325,25 @@ def configure_work_order(
if not has_third_party:
third_party_item_ids = []
# 清除旧明细
for row in (
db.query(BizQcWorkOrderLabItem)
.filter(BizQcWorkOrderLabItem.work_order_id == wo.id, BizQcWorkOrderLabItem.del_flag == 0)
.all()
):
row.del_flag = 1
for row in (
db.query(BizQcWorkOrderThirdItem)
.filter(BizQcWorkOrderThirdItem.work_order_id == wo.id, BizQcWorkOrderThirdItem.del_flag == 0)
.all()
):
row.del_flag = 1
fee_total = Decimal("0")
seq = 0
for lid in lab_item_ids:
item = lab_item_svc.get_lab_item(db, lid, tenant_no=tenant_no)
if not item or item.status != "1":
raise ValueError("实验室项目无效或已停用")
seq += 1
line = BizQcWorkOrderLabItem(
id=generate_uuid(),
work_order_id=wo.id,
order_source=order_source,
lab_test_item_id=item.id,
item_code=item.item_code,
item_name=item.item_name,
tenant_no=tenant_no,
order_num=seq,
create_by=user_id,
create_dept_id=create_dept_id or "",
create_time=datetime.now(),
update_by=user_id,
update_time=datetime.now(),
del_flag=0,
)
db.add(line)
db.flush()
task_svc.create_task_for_line(
db,
work_order=wo,
task_type="sysz",
source_line_id=line.id,
item_code=line.item_code,
item_name=line.item_name,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
seq=seq,
order_source=order_source,
)
for tid in third_party_item_ids:
item = third_item_svc.get_item(db, tid, tenant_no=tenant_no)
if not item or item.status != "1":
raise ValueError("第三方项目无效或已停用")
comp = get_company(db, item.company_id, tenant_no=tenant_no)
if not comp:
raise ValueError("第三方公司不存在")
seq += 1
fee = item.fee_amount or Decimal("0")
fee_total += fee
line = BizQcWorkOrderThirdItem(
id=generate_uuid(),
work_order_id=wo.id,
order_source=order_source,
third_party_item_id=item.id,
company_id=comp.id,
company_name=comp.company_name,
item_code=item.item_code,
item_name=item.item_name,
fee_amount=fee,
tenant_no=tenant_no,
order_num=seq,
create_by=user_id,
create_dept_id=create_dept_id or "",
create_time=datetime.now(),
update_by=user_id,
update_time=datetime.now(),
del_flag=0,
)
db.add(line)
db.flush()
task_svc.create_task_for_line(
db,
work_order=wo,
task_type="dsfjc",
source_line_id=line.id,
item_code=line.item_code,
item_name=line.item_name,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
seq=seq,
company_id=comp.id,
company_name=comp.company_name,
fee_amount=fee,
order_source=order_source,
)
seq = _sync_work_order_lab_items(
db,
wo,
order_source=order_source,
lab_item_ids=lab_item_ids,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
)
seq, fee_total = _sync_work_order_third_party_items(
db,
wo,
order_source=order_source,
third_party_item_ids=third_party_item_ids,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
seq_start=seq,
)
wo.has_lab = "1" if has_lab else "0"
wo.has_third_party = "1" if has_third_party else "0"
@@ -1494,33 +1647,6 @@ def configure_temp_qc_work_order(
if not wo:
raise ValueError("工单不存在")
if wo.work_order_status != "dpz":
tasks = (
db.query(BizQcTask)
.filter(
BizQcTask.work_order_id == wo.id,
BizQcTask.order_source == "temporary",
BizQcTask.tenant_no == tenant_no,
BizQcTask.del_flag == 0,
)
.all()
)
now = datetime.now()
task_ids = [t.id for t in tasks]
if task_ids:
db.query(BizQcTaskResult).filter(
BizQcTaskResult.task_id.in_(task_ids),
BizQcTaskResult.tenant_no == tenant_no,
BizQcTaskResult.del_flag == 0,
).update(
{"del_flag": 1, "update_time": now},
synchronize_session="fetch",
)
for t in tasks:
t.del_flag = 1
t.update_time = now
db.add(t)
if not has_lab and not has_third_party:
raise ValueError("请至少选择一种检测方式")
if has_lab and not lab_item_ids:
@@ -1532,114 +1658,25 @@ def configure_temp_qc_work_order(
if not has_third_party:
third_party_item_ids = []
for row in (
db.query(BizQcWorkOrderLabItem)
.filter(
BizQcWorkOrderLabItem.work_order_id == wo.id,
BizQcWorkOrderLabItem.order_source == "temporary",
BizQcWorkOrderLabItem.del_flag == 0,
)
.all()
):
row.del_flag = 1
for row in (
db.query(BizQcWorkOrderThirdItem)
.filter(
BizQcWorkOrderThirdItem.work_order_id == wo.id,
BizQcWorkOrderThirdItem.order_source == "temporary",
BizQcWorkOrderThirdItem.del_flag == 0,
)
.all()
):
row.del_flag = 1
fee_total = Decimal("0")
seq = 0
for lid in lab_item_ids:
item = lab_item_svc.get_lab_item(db, lid, tenant_no=tenant_no)
if not item or item.status != "1":
raise ValueError("实验室项目无效或已停用")
seq += 1
line = BizQcWorkOrderLabItem(
id=generate_uuid(),
work_order_id=wo.id,
order_source="temporary",
lab_test_item_id=item.id,
item_code=item.item_code,
item_name=item.item_name,
tenant_no=tenant_no,
order_num=seq,
create_by=user_id,
create_dept_id=create_dept_id or "",
create_time=datetime.now(),
update_by=user_id,
update_time=datetime.now(),
del_flag=0,
)
db.add(line)
db.flush()
task_svc.create_task_for_line(
db,
work_order=wo,
task_type="sysz",
source_line_id=line.id,
item_code=line.item_code,
item_name=line.item_name,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
seq=seq,
order_source="temporary",
)
for tid in third_party_item_ids:
item = third_item_svc.get_item(db, tid, tenant_no=tenant_no)
if not item or item.status != "1":
raise ValueError("第三方项目无效或已停用")
comp = get_company(db, item.company_id, tenant_no=tenant_no)
if not comp:
raise ValueError("第三方公司不存在")
seq += 1
fee = item.fee_amount or Decimal("0")
fee_total += fee
line = BizQcWorkOrderThirdItem(
id=generate_uuid(),
work_order_id=wo.id,
order_source="temporary",
third_party_item_id=item.id,
company_id=comp.id,
company_name=comp.company_name,
item_code=item.item_code,
item_name=item.item_name,
fee_amount=fee,
tenant_no=tenant_no,
order_num=seq,
create_by=user_id,
create_dept_id=create_dept_id or "",
create_time=datetime.now(),
update_by=user_id,
update_time=datetime.now(),
del_flag=0,
)
db.add(line)
db.flush()
task_svc.create_task_for_line(
db,
work_order=wo,
task_type="dsfjc",
source_line_id=line.id,
item_code=line.item_code,
item_name=line.item_name,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
seq=seq,
company_id=comp.id,
company_name=comp.company_name,
fee_amount=fee,
order_source="temporary",
)
seq = _sync_work_order_lab_items(
db,
wo,
order_source="temporary",
lab_item_ids=lab_item_ids,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
)
seq, fee_total = _sync_work_order_third_party_items(
db,
wo,
order_source="temporary",
third_party_item_ids=third_party_item_ids,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
seq_start=seq,
)
wo.has_lab = "1" if has_lab else "0"
wo.has_third_party = "1" if has_third_party else "0"
+45 -1
View File
@@ -9,13 +9,15 @@ from typing import Any, Dict, List, Optional, Tuple
from sqlalchemy import and_, func, or_
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid, parse_datetime
from app.core.utils import generate_uuid, parse_datetime, format_date, optional_date
from app.crud.base import camel_to_snake
from app.crud.biz_no_generator import allocate_next_biz_no
from app.crud.collection_protocol import (
attachments_to_urls,
urls_to_attachment_list,
validate_sample_codes_not_used,
_format_sample_collect_summary,
_load_sample_type_name_map,
)
from app.crud.protocol_donation_convert import (
assert_biz_no_available,
@@ -218,6 +220,7 @@ def _party_to_dict(p: BizResearchDonationParty) -> Dict[str, Any]:
"fatherIdCard": p.father_id_card or "",
"newbornName": p.newborn_name or "",
"newbornIdCard": p.newborn_id_card or "",
"expectedDeliveryDate": format_date(p.expected_delivery_date),
"newbornDeliveryTime": _fmt_dt(p.newborn_delivery_time),
"newbornSex": p.newborn_sex or "",
"deliveryMode": p.delivery_mode or "",
@@ -523,6 +526,26 @@ def list_donations(
collector_ids = list({r.collector_user_id for r in rows if r.collector_user_id})
user_name_map = _user_nick_name_map(db, list(set(collector_ids + sales_user_ids)))
# 批量加载捐赠样本(列表展示样本类型、样本编码、采集情况)
sample_map: Dict[str, List[BizResearchDonationSample]] = {}
sample_type_name_map: Dict[str, str] = {}
if donation_ids:
s_rows = (
db.query(BizResearchDonationSample)
.filter(
BizResearchDonationSample.research_donation_id.in_(donation_ids),
BizResearchDonationSample.del_flag == 0,
)
.order_by(
BizResearchDonationSample.order_num.asc(),
BizResearchDonationSample.create_time.asc(),
)
.all()
)
sample_type_name_map = _load_sample_type_name_map(db, s_rows)
for s in s_rows:
sample_map.setdefault(s.research_donation_id, []).append(s)
result = []
for r in rows:
d = _donation_to_dict(r, db, tenant_no)
@@ -533,6 +556,7 @@ def list_donations(
d["motherPhone"] = pc.get("motherPhone", "")
d["motherIdCard"] = pc.get("motherIdCard", "")
d["fatherName"] = pc.get("fatherName", "")
d["expectedDeliveryDate"] = pc.get("expectedDeliveryDate", "")
d["newbornSex"] = pc.get("newbornSex", "")
d["deliveryMode"] = pc.get("deliveryMode", "")
d["newbornWeightGram"] = pc.get("newbornWeightGram")
@@ -541,6 +565,7 @@ def list_donations(
d["motherPhone"] = ""
d["motherIdCard"] = ""
d["fatherName"] = ""
d["expectedDeliveryDate"] = ""
d["newbornSex"] = ""
d["deliveryMode"] = ""
d["newbornWeightGram"] = None
@@ -555,6 +580,19 @@ def list_donations(
d["hospitalName"] = ""
d["salesUserName"] = ""
d["sampleCollectTime"] = ""
donation_samples = sample_map.get(r.id, [])
type_names: List[str] = []
codes: List[str] = []
for s in donation_samples:
type_name = sample_type_name_map.get(s.sample_type_id or "", "")
if type_name:
type_names.append(type_name)
code = (s.sample_code or "").strip()
if code:
codes.append(code)
d["sampleTypeNames"] = ",".join(type_names)
d["sampleCodes"] = ",".join(codes)
d["sampleCollectSummary"] = _format_sample_collect_summary(donation_samples)
result.append(d)
return {
@@ -1253,6 +1291,7 @@ def convert_from_storage(
father_id_card=src_party.father_id_card,
newborn_name=src_party.newborn_name,
newborn_id_card=src_party.newborn_id_card,
expected_delivery_date=src_party.expected_delivery_date,
newborn_delivery_time=src_party.newborn_delivery_time,
newborn_sex=src_party.newborn_sex,
delivery_mode=src_party.delivery_mode,
@@ -1492,6 +1531,7 @@ def convert_to_storage(
father_id_card=src_party.father_id_card,
newborn_name=src_party.newborn_name,
newborn_id_card=src_party.newborn_id_card,
expected_delivery_date=src_party.expected_delivery_date,
newborn_delivery_time=src_party.newborn_delivery_time,
newborn_sex=src_party.newborn_sex,
delivery_mode=src_party.delivery_mode,
@@ -1624,6 +1664,7 @@ _PARTY_STR_FIELDS = [
]
_PARTY_INT_FIELDS = ["birth_order", "newborn_weight_gram"]
_PARTY_DEC_FIELDS = ["apgar_1min", "apgar_5min"]
_PARTY_DATE_FIELDS = ["expected_delivery_date"]
_PARTY_DT_FIELDS = ["newborn_delivery_time"]
@@ -1657,6 +1698,9 @@ def _create_party(
for k in _PARTY_DEC_FIELDS:
if k in raw:
setattr(obj, k, _optional_decimal(raw[k]))
for k in _PARTY_DATE_FIELDS:
if k in raw:
setattr(obj, k, optional_date(raw[k]))
for k in _PARTY_DT_FIELDS:
if k in raw:
val = raw[k]
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_main_py", "label": "main.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L1"}, {"id": "app_main_lifespan", "label": "lifespan()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L20"}, {"id": "app_main_error_json", "label": "_error_json()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L67"}, {"id": "app_main_sqlalchemy_exception_handler", "label": "sqlalchemy_exception_handler()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L80"}, {"id": "app_main_unhandled_exception_handler", "label": "unhandled_exception_handler()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L91"}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L130"}, {"id": "app_main_root", "label": "root()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L152"}, {"id": "app_main_health_check", "label": "health_check()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L157"}, {"id": "app_main_rationale_81", "label": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L81"}, {"id": "app_main_rationale_92", "label": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L92"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_main_py", "target": "contextlib", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_main_py", "target": "logging", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_main_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_main_py", "target": "fastapi", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_main_py", "target": "fastapi_middleware_cors", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L7", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_main_py", "target": "fastapi_responses", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L8", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_main_py", "target": "sqlalchemy_exc", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_main_py", "target": "app_core_config", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L11", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_main_py", "target": "app_core_database", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L12", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_main_py", "target": "app_core_api_request_log_middleware", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py", "source_location": "L13", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_main_py", "target": "app_core_api_crypto_middleware", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/main.py"Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_collection_protocol_py", "label": "collection_protocol.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L1"}, {"id": "crud_collection_protocol_get_protocol_nos_used_in_protocols", "label": "get_protocol_nos_used_in_protocols()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L51"}, {"id": "crud_collection_protocol_get_sample_codes_used_in_protocol_samples", "label": "get_sample_codes_used_in_protocol_samples()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L85"}, {"id": "crud_collection_protocol_validate_sample_codes_not_used", "label": "validate_sample_codes_not_used()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L119"}, {"id": "crud_collection_protocol_total_pages", "label": "total_pages()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L152"}, {"id": "crud_collection_protocol_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L158"}, {"id": "crud_collection_protocol_dec", "label": "_dec()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L162"}, {"id": "crud_collection_protocol_optional_decimal", "label": "_optional_decimal()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L170"}, {"id": "crud_collection_protocol_today_yyyymmdd", "label": "_today_yyyymmdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L176"}, {"id": "crud_collection_protocol_normalize_yyyymmdd_date", "label": "_normalize_yyyymmdd_date()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L180"}, {"id": "crud_collection_protocol_normalize_fields", "label": "_normalize_fields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L199"}, {"id": "crud_collection_protocol_pop_attachment_urls", "label": "_pop_attachment_urls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L210"}, {"id": "crud_collection_protocol_attachments_to_urls", "label": "attachments_to_urls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L221"}, {"id": "crud_collection_protocol_normalize_attachment_url_key", "label": "_normalize_attachment_url_key()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L240"}, {"id": "crud_collection_protocol_format_attachment_file_size", "label": "_format_attachment_file_size()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L249"}, {"id": "crud_collection_protocol_lookup_attachment_by_url", "label": "_lookup_attachment_by_url()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L257"}, {"id": "crud_collection_protocol_urls_to_attachment_list", "label": "urls_to_attachment_list()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L281"}, {"id": "crud_collection_protocol_user_nick_name_map", "label": "_user_nick_name_map()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L313"}, {"id": "crud_collection_protocol_protocol_to_dict", "label": "_protocol_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L321"}, {"id": "crud_collection_protocol_payment_to_dict", "label": "_payment_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L346"}, {"id": "crud_collection_protocol_detail_to_dict", "label": "_detail_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L364"}, {"id": "crud_collection_protocol_audit_to_dict", "label": "_audit_to_dict()", "file_type": "code", "source_Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_models_models_py", "label": "models.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L1"}, {"id": "models_models_userrole", "label": "UserRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L10"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_models_sysuser", "label": "SysUser", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L22"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_models_sysrole", "label": "SysRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L48"}, {"id": "models_models_sysuserrole", "label": "SysUserRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L68"}, {"id": "models_models_sysrolemenu", "label": "SysRoleMenu", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L87"}, {"id": "models_models_sysroledatascopedetail", "label": "SysRoleDataScopeDetail", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L106"}, {"id": "models_models_sysmenu", "label": "SysMenu", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L126"}, {"id": "models_models_sysdept", "label": "SysDept", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L152"}, {"id": "models_models_systenant", "label": "SysTenant", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L175"}, {"id": "models_models_syssite", "label": "SysSite", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L195"}, {"id": "models_models_syspost", "label": "SysPost", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L220"}, {"id": "models_models_sysuserpost", "label": "SysUserPost", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L240"}, {"id": "models_models_bizitemunit", "label": "BizItemUnit", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L259"}, {"id": "models_models_bizexpresscompany", "label": "BizExpressCompany", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L278"}, {"id": "models_models_bizcustomer", "label": "BizCustomer", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L297"}, {"id": "models_models_bizcellsampletype", "label": "BizCellSampleType", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L320"}, {"id": "models_models_bizcollectionregion", "label": "BizCollectionRegion", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L341"}, {"id": "models_models_bizcollectionhospital", "label": "BizCollectionHospital", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L359"}, {"id": "models_models_bizcollectionprotocolno", "label": "BizCollectionProtocolNo", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L378"}, {"id": "models_models_bizbiznosequence", "label": "BizBizNoSequence", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L400"}, {"id": "models_models_bizsamplecode", "label": "BizSampleCode", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L420"}, {"id": "models_models_sysdicttype", "label": "SysDictType", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L448"}, {"id": "models_models_sysethnic", "label": "SysEthnic", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L467"}, {"id": "models_models_sysdictdata", "label": "SysDictData", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location"Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_core_utils_py", "label": "utils.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L1"}, {"id": "core_utils_generate_uuid", "label": "generate_uuid()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L9"}, {"id": "core_utils_generate_id", "label": "generate_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L14"}, {"id": "core_utils_generate_random_password", "label": "generate_random_password()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L20"}, {"id": "core_utils_get_current_time", "label": "get_current_time()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L26"}, {"id": "core_utils_format_datetime", "label": "format_datetime()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L31"}, {"id": "core_utils_parse_datetime", "label": "parse_datetime()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L38"}, {"id": "core_utils_format_date", "label": "format_date()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L48"}, {"id": "core_utils_parse_date", "label": "parse_date()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L57"}, {"id": "core_utils_optional_date", "label": "optional_date()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L70"}, {"id": "core_utils_get_file_size_display", "label": "get_file_size_display()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L81"}, {"id": "core_utils_rationale_71", "label": "\u5c06\u5b57\u7b26\u4e32 / date / datetime \u8f6c\u4e3a date \u6216 None", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L71"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_core_utils_py", "target": "uuid", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_utils_py", "target": "random", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_utils_py", "target": "string", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_utils_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_utils_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_utils_py", "target": "core_utils_generate_uuid", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_utils_py", "target": "core_utils_generate_id", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L14", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_utils_py", "target": "core_utils_generate_random_password", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L20", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_utils_py", "target": "core_utils_get_current_time", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py", "source_location": "L26", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_utils_py", "target": "core_utils_format_datetime", "relation": "contains", "confidence": "EXTRACTELine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_models_models_py", "label": "models.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L1"}, {"id": "models_models_userrole", "label": "UserRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L10"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_models_sysuser", "label": "SysUser", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L22"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_models_sysrole", "label": "SysRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L48"}, {"id": "models_models_sysuserrole", "label": "SysUserRole", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L68"}, {"id": "models_models_sysrolemenu", "label": "SysRoleMenu", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L87"}, {"id": "models_models_sysroledatascopedetail", "label": "SysRoleDataScopeDetail", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L106"}, {"id": "models_models_sysmenu", "label": "SysMenu", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L126"}, {"id": "models_models_sysdept", "label": "SysDept", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L152"}, {"id": "models_models_systenant", "label": "SysTenant", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L175"}, {"id": "models_models_syssite", "label": "SysSite", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L195"}, {"id": "models_models_syspost", "label": "SysPost", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L220"}, {"id": "models_models_sysuserpost", "label": "SysUserPost", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L240"}, {"id": "models_models_bizitemunit", "label": "BizItemUnit", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L259"}, {"id": "models_models_bizexpresscompany", "label": "BizExpressCompany", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L278"}, {"id": "models_models_bizcustomer", "label": "BizCustomer", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L297"}, {"id": "models_models_bizcellsampletype", "label": "BizCellSampleType", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L320"}, {"id": "models_models_bizcollectionregion", "label": "BizCollectionRegion", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L341"}, {"id": "models_models_bizcollectionhospital", "label": "BizCollectionHospital", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L359"}, {"id": "models_models_bizcollectionprotocolno", "label": "BizCollectionProtocolNo", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L378"}, {"id": "models_models_bizbiznosequence", "label": "BizBizNoSequence", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L400"}, {"id": "models_models_bizsamplecode", "label": "BizSampleCode", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L420"}, {"id": "models_models_sysdicttype", "label": "SysDictType", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L448"}, {"id": "models_models_sysethnic", "label": "SysEthnic", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location": "L467"}, {"id": "models_models_sysdictdata", "label": "SysDictData", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py", "source_location"Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_research_donation_py", "label": "research_donation.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L1"}, {"id": "crud_research_donation_total_pages", "label": "total_pages()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L56"}, {"id": "crud_research_donation_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L62"}, {"id": "crud_research_donation_normalize_date_bound", "label": "_normalize_date_bound()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L66"}, {"id": "crud_research_donation_dec", "label": "_dec()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L73"}, {"id": "crud_research_donation_optional_decimal", "label": "_optional_decimal()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L81"}, {"id": "crud_research_donation_normalize_fields", "label": "_normalize_fields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L93"}, {"id": "crud_research_donation_merge_comma_separated_urls", "label": "_merge_comma_separated_urls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L104"}, {"id": "crud_research_donation_resolve_donation_payload", "label": "_resolve_donation_payload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L120"}, {"id": "crud_research_donation_user_nick_name_map", "label": "_user_nick_name_map()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L138"}, {"id": "crud_research_donation_donation_to_dict", "label": "_donation_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L151"}, {"id": "crud_research_donation_audit_to_dict", "label": "_audit_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L185"}, {"id": "crud_research_donation_party_to_dict", "label": "_party_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L207"}, {"id": "crud_research_donation_collection_to_dict", "label": "_collection_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L240"}, {"id": "crud_research_donation_sample_to_dict", "label": "_sample_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L258"}, {"id": "crud_research_donation_transport_to_dict", "label": "_transport_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L281"}, {"id": "crud_research_donation_get_party", "label": "get_party()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L306"}, {"id": "crud_research_donation_get_collection", "label": "get_collection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L322"}, {"id": "crud_research_donation_list_samples", "label": "list_samples()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L338"}, {"id": "crud_research_donation_list_sample_transports", "label": "list_sample_transports()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L358"}, {"id": "crud_research_donation_list_donations", "label": "list_donations()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L383"}, {"id": "crud_research_donation_get_donation_detail", "label": "get_donation_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L612"}, {"id": "crud_research_donation_create_donation", "label": "create_donation()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/cLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_sms_notification_py", "label": "qc_sms_notification.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L1"}, {"id": "crud_qc_sms_notification_unicode_ci", "label": "_unicode_ci()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L26"}, {"id": "crud_qc_sms_notification_total_pages", "label": "total_pages()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L30"}, {"id": "crud_qc_sms_notification_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L36"}, {"id": "crud_qc_sms_notification_normalize_date_bound", "label": "_normalize_date_bound()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L40"}, {"id": "crud_qc_sms_notification_qc_conclusion_label", "label": "_qc_conclusion_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L47"}, {"id": "crud_qc_sms_notification_derive_qc_conclusion", "label": "_derive_qc_conclusion()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L51"}, {"id": "crud_qc_sms_notification_qc_complete_time", "label": "_qc_complete_time()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L61"}, {"id": "crud_qc_sms_notification_fetch_tasks", "label": "_fetch_tasks()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L68"}, {"id": "crud_qc_sms_notification_row_to_dict", "label": "_row_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L81"}, {"id": "crud_qc_sms_notification_base_query", "label": "_base_query()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L117"}, {"id": "crud_qc_sms_notification_ensure_notification", "label": "_ensure_notification()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L167"}, {"id": "crud_qc_sms_notification_resolve_notification", "label": "resolve_notification()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L201"}, {"id": "crud_qc_sms_notification_task_stats_subquery", "label": "_task_stats_subquery()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L238"}, {"id": "crud_qc_sms_notification_list_notifications", "label": "list_notifications()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L256"}, {"id": "crud_qc_sms_notification_toggle_notification_status", "label": "toggle_notification_status()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L383"}, {"id": "crud_qc_sms_notification_generate_sms_content", "label": "generate_sms_content()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L419"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_sms_notification_py", "target": "math", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_sms_notification_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_sms_notification_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_sms_notification_py", "target": "sqlalchemy", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_sms_notification.py", "source_location": "L8Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_sms_notification_py", "label": "qc_sms_notification.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L1"}, {"id": "api_qc_sms_notification_get_tenant_no", "label": "_get_tenant_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L22"}, {"id": "api_qc_sms_notification_get_current_user_id", "label": "_get_current_user_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L32"}, {"id": "api_qc_sms_notification_page_payload", "label": "_page_payload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L39"}, {"id": "api_qc_sms_notification_togglestatusbody", "label": "ToggleStatusBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L49"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "api_qc_sms_notification_list_notifications", "label": "list_notifications()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L57"}, {"id": "api_qc_sms_notification_toggle_status", "label": "toggle_status()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L90"}, {"id": "api_qc_sms_notification_generate_sms", "label": "generate_sms()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L117"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_sms_notification_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_sms_notification_py", "target": "fastapi", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_sms_notification_py", "target": "pydantic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_sms_notification_py", "target": "sqlalchemy_orm", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_sms_notification_py", "target": "app_core_database", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L8", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_sms_notification_py", "target": "app_core_menu_guard", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_sms_notification_py", "target": "app_core_response", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L10", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_sms_notification_py", "target": "app_crud", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L11", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_sms_notification_py", "target": "app_crud_collection_protocol", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L12", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_sms_notification_py", "target": "app_models_models", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py", "source_location": "L13", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_qc_sms_notification_py", "target": "apiLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_storage_entry_sms_notification_py", "label": "storage_entry_sms_notification.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L1"}, {"id": "api_storage_entry_sms_notification_get_tenant_no", "label": "_get_tenant_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L23"}, {"id": "api_storage_entry_sms_notification_get_current_user_id", "label": "_get_current_user_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L33"}, {"id": "api_storage_entry_sms_notification_page_payload", "label": "_page_payload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L40"}, {"id": "api_storage_entry_sms_notification_togglestatusbody", "label": "ToggleStatusBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L50"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "api_storage_entry_sms_notification_list_notifications", "label": "list_notifications()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L58"}, {"id": "api_storage_entry_sms_notification_toggle_status", "label": "toggle_status()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L91"}, {"id": "api_storage_entry_sms_notification_generate_sms", "label": "generate_sms()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L118"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_api_storage_entry_sms_notification_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_storage_entry_sms_notification_py", "target": "fastapi", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_storage_entry_sms_notification_py", "target": "pydantic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_storage_entry_sms_notification_py", "target": "sqlalchemy_orm", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_storage_entry_sms_notification_py", "target": "app_core_database", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L8", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_storage_entry_sms_notification_py", "target": "app_core_menu_guard", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_storage_entry_sms_notification_py", "target": "app_core_response", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L10", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_storage_entry_sms_notification_py", "target": "app_crud", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L11", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_storage_entry_sms_notification_py", "target": "app_crud_collection_protocol", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py", "source_location": "L12", "weight": 1.0}, {"source": "usersLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_models_research_donation_py", "label": "research_donation.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L1"}, {"id": "models_research_donation_bizresearchdonation", "label": "BizResearchDonation", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L9"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_research_donation_bizresearchdonationaudit", "label": "BizResearchDonationAudit", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L42"}, {"id": "models_research_donation_bizresearchdonationparty", "label": "BizResearchDonationParty", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L63"}, {"id": "models_research_donation_bizresearchdonationcollection", "label": "BizResearchDonationCollection", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L102"}, {"id": "models_research_donation_bizresearchdonationsample", "label": "BizResearchDonationSample", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L126"}, {"id": "models_research_donation_bizresearchdonationsampletransport", "label": "BizResearchDonationSampleTransport", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L155"}, {"id": "models_research_donation_bizprotocoldonationconvert", "label": "BizProtocolDonationConvert", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L183"}, {"id": "models_research_donation_rationale_10", "label": "\u79d1\u7814\u6350\u8d60\u4e3b\u8868 biz_research_donation", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L10"}, {"id": "models_research_donation_rationale_43", "label": "\u79d1\u7814\u6350\u8d60\u5ba1\u6838\u8bb0\u5f55 biz_research_donation_audit", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L43"}, {"id": "models_research_donation_rationale_64", "label": "\u79d1\u7814\u6350\u8d60\u5f53\u4e8b\u4eba\u4fe1\u606f biz_research_donation_party", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L64"}, {"id": "models_research_donation_rationale_103", "label": "\u79d1\u7814\u6350\u8d60\u91c7\u96c6\u4fe1\u606f biz_research_donation_collection", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L103"}, {"id": "models_research_donation_rationale_127", "label": "\u79d1\u7814\u6350\u8d60\u6837\u672c\u4fe1\u606f biz_research_donation_sample\uff08\u65e0\u91d1\u989d\u5b57\u6bb5\uff09", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L127"}, {"id": "models_research_donation_rationale_156", "label": "\u79d1\u7814\u6350\u8d60\u6837\u672c\u8fd0\u8f93 biz_research_donation_sample_transport", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L156"}, {"id": "models_research_donation_rationale_184", "label": "\u7ec6\u80de\u5b58\u50a8\u534f\u8bae\u4e0e\u79d1\u7814\u6350\u8d60\u8f6c\u79fb\u5173\u8054 biz_protocol_donation_convert", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L184"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_models_research_donation_py", "target": "datetime", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_models_research_donation_py", "target": "sqlalchemy", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_models_research_donation_py", "target": "app_models_base", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py", "source_location": "L6", "weLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_core_menu_guard_py", "label": "menu_guard.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L1"}, {"id": "core_menu_guard_require_admin_or_super_admin", "label": "require_admin_or_super_admin()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L15"}, {"id": "core_menu_guard_get_user_menu_codes", "label": "get_user_menu_codes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L23"}, {"id": "core_menu_guard_require_menu_code", "label": "require_menu_code()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L28"}, {"id": "core_menu_guard_require_any_menu_code", "label": "require_any_menu_code()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L47"}, {"id": "core_menu_guard_rationale_1", "label": "\u83dc\u5355 code \u6743\u9650\u5b88\u536b\uff08V0.3\uff1a\u901a\u8fc7 sys_user_role \u2192 sys_role_menu \u2192 sys_menu.perms\uff09", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L1"}, {"id": "core_menu_guard_rationale_16", "label": "\u8fd0\u8425\u7aef\u89d2\u8272\u5b88\u536b\uff1aadmin / super_admin \u53ef\u8bbf\u95ee\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L16"}, {"id": "core_menu_guard_rationale_24", "label": "\u8bfb\u53d6\u7528\u6237\u6388\u6743\u7684\u83dc\u5355\u6743\u9650\u6807\u8bc6\u96c6\u5408\uff08\u4e0e\u524d\u7aef meta.menuCode / perms \u5bf9\u9f50\uff09\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L24"}, {"id": "core_menu_guard_rationale_29", "label": "\u63a5\u53e3\u83dc\u5355\u6743\u9650\u5b88\u536b\u3002super_admin \u76f4\u63a5\u653e\u884c\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L29"}, {"id": "core_menu_guard_rationale_48", "label": "\u63a5\u53e3\u83dc\u5355\u6743\u9650\u5b88\u536b\uff1a\u62e5\u6709\u4efb\u4e00 menuCode \u5373\u53ef\u8bbf\u95ee\u3002super_admin \u76f4\u63a5\u653e\u884c\u3002", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L48"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_core_menu_guard_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_menu_guard_py", "target": "fastapi", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_menu_guard_py", "target": "sqlalchemy_orm", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_menu_guard_py", "target": "app_core_auth", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L7", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_menu_guard_py", "target": "app_core_database", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L8", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_menu_guard_py", "target": "app_services_web_auth_roles", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_menu_guard_py", "target": "core_menu_guard_require_admin_or_super_admin", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L15", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_core_menu_guard_py", "target": "core_menu_guard_get_user_menu_codes", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py", "source_location": "L23", "weight": 1.0}, {"sourcLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_collection_protocol_py", "label": "collection_protocol.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L1"}, {"id": "crud_collection_protocol_get_protocol_nos_used_in_protocols", "label": "get_protocol_nos_used_in_protocols()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L51"}, {"id": "crud_collection_protocol_get_sample_codes_used_in_protocol_samples", "label": "get_sample_codes_used_in_protocol_samples()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L85"}, {"id": "crud_collection_protocol_validate_sample_codes_not_used", "label": "validate_sample_codes_not_used()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L119"}, {"id": "crud_collection_protocol_total_pages", "label": "total_pages()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L152"}, {"id": "crud_collection_protocol_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L158"}, {"id": "crud_collection_protocol_dec", "label": "_dec()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L162"}, {"id": "crud_collection_protocol_optional_decimal", "label": "_optional_decimal()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L170"}, {"id": "crud_collection_protocol_today_yyyymmdd", "label": "_today_yyyymmdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L176"}, {"id": "crud_collection_protocol_normalize_yyyymmdd_date", "label": "_normalize_yyyymmdd_date()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L180"}, {"id": "crud_collection_protocol_normalize_fields", "label": "_normalize_fields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L199"}, {"id": "crud_collection_protocol_pop_attachment_urls", "label": "_pop_attachment_urls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L210"}, {"id": "crud_collection_protocol_attachments_to_urls", "label": "attachments_to_urls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L221"}, {"id": "crud_collection_protocol_normalize_attachment_url_key", "label": "_normalize_attachment_url_key()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L240"}, {"id": "crud_collection_protocol_format_attachment_file_size", "label": "_format_attachment_file_size()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L249"}, {"id": "crud_collection_protocol_lookup_attachment_by_url", "label": "_lookup_attachment_by_url()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L257"}, {"id": "crud_collection_protocol_urls_to_attachment_list", "label": "urls_to_attachment_list()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L281"}, {"id": "crud_collection_protocol_user_nick_name_map", "label": "_user_nick_name_map()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L313"}, {"id": "crud_collection_protocol_protocol_to_dict", "label": "_protocol_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L321"}, {"id": "crud_collection_protocol_payment_to_dict", "label": "_payment_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L346"}, {"id": "crud_collection_protocol_detail_to_dict", "label": "_detail_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L364"}, {"id": "crud_collection_protocol_audit_to_dict", "label": "_audit_to_dict()", "file_type": "code", "source_Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_qc_work_order_py", "label": "qc_work_order.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L1"}, {"id": "crud_qc_work_order_resolve_outbound_biz_type_for_schedule", "label": "resolve_outbound_biz_type_for_schedule()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L70"}, {"id": "crud_qc_work_order_dec", "label": "_dec()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L111"}, {"id": "crud_qc_work_order_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L117"}, {"id": "crud_qc_work_order_normalize_date_bound", "label": "_normalize_date_bound()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L121"}, {"id": "crud_qc_work_order_reception_source_label", "label": "_reception_source_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L128"}, {"id": "crud_qc_work_order_qc_biz_type_label", "label": "_qc_biz_type_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L133"}, {"id": "crud_qc_work_order_work_order_qc_biz_type", "label": "_work_order_qc_biz_type()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L138"}, {"id": "crud_qc_work_order_validate_cell_product_id", "label": "_validate_cell_product_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L145"}, {"id": "crud_qc_work_order_enrich_work_order_cell_products", "label": "_enrich_work_order_cell_products()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L157"}, {"id": "crud_qc_work_order_enrich_outbound_work_orders", "label": "_enrich_outbound_work_orders()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L186"}, {"id": "crud_qc_work_order_outbound_qc_work_order_ids_by_keyword", "label": "_outbound_qc_work_order_ids_by_keyword()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L276"}, {"id": "crud_qc_work_order_accept_conclusion_label", "label": "_accept_conclusion_label()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L321"}, {"id": "crud_qc_work_order_load_sample_type_name_map", "label": "_load_sample_type_name_map()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L326"}, {"id": "crud_qc_work_order_effective_reception_source", "label": "_effective_reception_source()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L338"}, {"id": "crud_qc_work_order_effective_donation_sample_id", "label": "_effective_donation_sample_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L347"}, {"id": "crud_qc_work_order_effective_protocol_sample_id", "label": "_effective_protocol_sample_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L356"}, {"id": "crud_qc_work_order_sample_type_name_for_item", "label": "_sample_type_name_for_item()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L364"}, {"id": "crud_qc_work_order_sample_type_name_for_reception", "label": "_sample_type_name_for_reception()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L382"}, {"id": "crud_qc_work_order_enrich_work_order_list_items", "label": "_enrich_work_order_list_items()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L405"}, {"id": "crud_qc_work_order_gen_daily_no", "label": "_gen_daily_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "L536"}, {"id": "crud_qc_work_order_user_nick_name_map", "label": "_user_nick_name_map()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py", "source_location": "LLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_collection_protocol_py", "label": "collection_protocol.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L1"}, {"id": "crud_collection_protocol_get_protocol_nos_used_in_protocols", "label": "get_protocol_nos_used_in_protocols()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L51"}, {"id": "crud_collection_protocol_get_sample_codes_used_in_protocol_samples", "label": "get_sample_codes_used_in_protocol_samples()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L85"}, {"id": "crud_collection_protocol_validate_sample_codes_not_used", "label": "validate_sample_codes_not_used()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L119"}, {"id": "crud_collection_protocol_total_pages", "label": "total_pages()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L152"}, {"id": "crud_collection_protocol_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L158"}, {"id": "crud_collection_protocol_dec", "label": "_dec()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L162"}, {"id": "crud_collection_protocol_optional_decimal", "label": "_optional_decimal()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L170"}, {"id": "crud_collection_protocol_today_yyyymmdd", "label": "_today_yyyymmdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L176"}, {"id": "crud_collection_protocol_normalize_yyyymmdd_date", "label": "_normalize_yyyymmdd_date()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L180"}, {"id": "crud_collection_protocol_normalize_fields", "label": "_normalize_fields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L199"}, {"id": "crud_collection_protocol_pop_attachment_urls", "label": "_pop_attachment_urls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L210"}, {"id": "crud_collection_protocol_attachments_to_urls", "label": "attachments_to_urls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L221"}, {"id": "crud_collection_protocol_normalize_attachment_url_key", "label": "_normalize_attachment_url_key()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L240"}, {"id": "crud_collection_protocol_format_attachment_file_size", "label": "_format_attachment_file_size()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L249"}, {"id": "crud_collection_protocol_lookup_attachment_by_url", "label": "_lookup_attachment_by_url()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L257"}, {"id": "crud_collection_protocol_urls_to_attachment_list", "label": "urls_to_attachment_list()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L281"}, {"id": "crud_collection_protocol_user_nick_name_map", "label": "_user_nick_name_map()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L313"}, {"id": "crud_collection_protocol_protocol_to_dict", "label": "_protocol_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L321"}, {"id": "crud_collection_protocol_payment_to_dict", "label": "_payment_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L346"}, {"id": "crud_collection_protocol_detail_to_dict", "label": "_detail_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py", "source_location": "L364"}, {"id": "crud_collection_protocol_audit_to_dict", "label": "_audit_to_dict()", "file_type": "code", "source_Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_menu_py", "label": "menu.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py", "source_location": "L1"}, {"id": "api_menu_get_menu_list", "label": "get_menu_list()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py", "source_location": "L656"}, {"id": "api_menu_rationale_1", "label": "\u8fd0\u8425\u7aef\u83dc\u5355\u63a5\u53e3\uff08\u4e0e web-admin \u524d\u7aef\u9759\u6001\u8def\u7531 sqxp.ts \u5bf9\u9f50\uff0c13 \u4e2a\u4e00\u7ea7\u83dc\u5355\uff09", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_api_menu_py", "target": "fastapi", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_menu_py", "target": "app_core_menu_guard", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_menu_py", "target": "app_core_response", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_menu_py", "target": "api_menu_get_menu_list", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py", "source_location": "L656", "weight": 1.0}, {"source": "api_menu_rationale_1", "target": "users_wuzilong_work_00code_zkxw_backend_app_api_menu_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py", "source_location": "L1", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_menu_get_menu_list", "callee": "success_response", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py", "source_location": "L658"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L1"}, {"id": "api_init_rationale_1", "label": "API \u8def\u7531\u5305\uff08\u9aa8\u67b6\uff1a\u516c\u5171\u9274\u6743 + \u9759\u6001\u83dc\u5355 + \u8fd0\u8425\u7aef\u5360\u4f4d\uff09", "file_type": "rationale", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_public", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_menu", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_workflow", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_basic_info", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_collection_protocol", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L7", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_leave", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L8", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_operations", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_ethnic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L10", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_sample_reception", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L11", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_qc", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L12", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_research_donation", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L13", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_production", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L14", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_pilot_service", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L15", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_insurance_company", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L16", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_init_py", "target": "app_api_material", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py", "source_location": "L17", "weight": 1.0}, {"source": "usLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_api_sample_sms_notification_py", "label": "sample_sms_notification.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L1"}, {"id": "api_sample_sms_notification_get_tenant_no", "label": "_get_tenant_no()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L23"}, {"id": "api_sample_sms_notification_get_current_user_id", "label": "_get_current_user_id()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L33"}, {"id": "api_sample_sms_notification_page_payload", "label": "_page_payload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L40"}, {"id": "api_sample_sms_notification_togglestatusbody", "label": "ToggleStatusBody", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L50"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "api_sample_sms_notification_list_notifications", "label": "list_notifications()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L58"}, {"id": "api_sample_sms_notification_toggle_status", "label": "toggle_status()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L91"}, {"id": "api_sample_sms_notification_generate_sms", "label": "generate_sms()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L118"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_backend_app_api_sample_sms_notification_py", "target": "typing", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_sample_sms_notification_py", "target": "fastapi", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L4", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_sample_sms_notification_py", "target": "pydantic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L5", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_sample_sms_notification_py", "target": "sqlalchemy_orm", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_sample_sms_notification_py", "target": "app_core_database", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L8", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_sample_sms_notification_py", "target": "app_core_menu_guard", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_sample_sms_notification_py", "target": "app_core_response", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L10", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_sample_sms_notification_py", "target": "app_crud", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L11", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_sample_sms_notification_py", "target": "app_crud_collection_protocol", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py", "source_location": "L12", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_backend_app_api_sample_sms_notification_py", "target": "app_models_models", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notificatioLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_backend_app_crud_research_donation_py", "label": "research_donation.py", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L1"}, {"id": "crud_research_donation_total_pages", "label": "total_pages()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L54"}, {"id": "crud_research_donation_fmt_dt", "label": "_fmt_dt()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L60"}, {"id": "crud_research_donation_normalize_date_bound", "label": "_normalize_date_bound()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L64"}, {"id": "crud_research_donation_dec", "label": "_dec()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L71"}, {"id": "crud_research_donation_optional_decimal", "label": "_optional_decimal()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L79"}, {"id": "crud_research_donation_normalize_fields", "label": "_normalize_fields()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L91"}, {"id": "crud_research_donation_merge_comma_separated_urls", "label": "_merge_comma_separated_urls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L102"}, {"id": "crud_research_donation_resolve_donation_payload", "label": "_resolve_donation_payload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L118"}, {"id": "crud_research_donation_user_nick_name_map", "label": "_user_nick_name_map()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L136"}, {"id": "crud_research_donation_donation_to_dict", "label": "_donation_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L149"}, {"id": "crud_research_donation_audit_to_dict", "label": "_audit_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L183"}, {"id": "crud_research_donation_party_to_dict", "label": "_party_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L205"}, {"id": "crud_research_donation_collection_to_dict", "label": "_collection_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L238"}, {"id": "crud_research_donation_sample_to_dict", "label": "_sample_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L256"}, {"id": "crud_research_donation_transport_to_dict", "label": "_transport_to_dict()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L279"}, {"id": "crud_research_donation_get_party", "label": "get_party()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L304"}, {"id": "crud_research_donation_get_collection", "label": "get_collection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L320"}, {"id": "crud_research_donation_list_samples", "label": "list_samples()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L336"}, {"id": "crud_research_donation_list_sample_transports", "label": "list_sample_transports()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L356"}, {"id": "crud_research_donation_list_donations", "label": "list_donations()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L381"}, {"id": "crud_research_donation_get_donation_detail", "label": "get_donation_detail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py", "source_location": "L575"}, {"id": "crud_research_donation_create_donation", "label": "create_donation()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/backend/app/cLine truncated
+2 -1
View File
@@ -13,7 +13,7 @@ from app.core.database import SessionLocal
from app.core.api_request_log_middleware import ApiRequestLogMiddleware
from app.core.api_crypto_middleware import ApiCryptoMiddleware
from app.models import models # noqa: F401
from app.api import public_router, menu_router, admin_router, workflow_router, basic_info_router, collection_protocol_router, leave_router, operations_router, ethnic_router, sample_reception_router, qc_router, research_donation_router, production_router, pilot_service_router, insurance_company_router, material_router, storage_release_review_router, sample_sms_notification_router, storage_entry_sms_notification_router, pilot_application_router, pilot_checkup_router, pilot_delivery_router, pilot_infusion_confirm_router, pilot_infusion_schedule_mgmt_router, outbound_release_review_router, clinical_payment_router
from app.api import public_router, menu_router, admin_router, workflow_router, basic_info_router, collection_protocol_router, leave_router, operations_router, ethnic_router, sample_reception_router, qc_router, research_donation_router, production_router, pilot_service_router, insurance_company_router, material_router, storage_release_review_router, sample_sms_notification_router, storage_entry_sms_notification_router, qc_sms_notification_router, pilot_application_router, pilot_checkup_router, pilot_delivery_router, pilot_infusion_confirm_router, pilot_infusion_schedule_mgmt_router, outbound_release_review_router, clinical_payment_router
@asynccontextmanager
@@ -117,6 +117,7 @@ app.include_router(material_router, prefix=settings.API_V1_PREFIX)
app.include_router(storage_release_review_router, prefix=settings.API_V1_PREFIX)
app.include_router(sample_sms_notification_router, prefix=settings.API_V1_PREFIX)
app.include_router(storage_entry_sms_notification_router, prefix=settings.API_V1_PREFIX)
app.include_router(qc_sms_notification_router, prefix=settings.API_V1_PREFIX)
app.include_router(pilot_application_router, prefix=settings.API_V1_PREFIX)
app.include_router(pilot_checkup_router, prefix=settings.API_V1_PREFIX)
app.include_router(pilot_delivery_router, prefix=settings.API_V1_PREFIX)
+27 -1
View File
@@ -2,7 +2,7 @@
from datetime import datetime
import enum
from sqlalchemy import Column, String, DateTime, Integer, Text, CHAR, SmallInteger, Numeric
from sqlalchemy import Column, String, DateTime, Date, Integer, Text, CHAR, SmallInteger, Numeric
from app.core.database import Base
@@ -890,6 +890,7 @@ class BizProtocolPartyCustomer(Base):
father_id_card = Column(String(32), nullable=True, comment="父亲身份证号")
newborn_name = Column(String(100), nullable=True, comment="新生儿姓名")
newborn_id_card = Column(String(32), nullable=True, comment="新生儿身份证号")
expected_delivery_date = Column(Date, nullable=True, comment="预产期")
newborn_delivery_time = Column(DateTime, nullable=True, comment="新生儿分娩时间")
newborn_sex = Column(CHAR(1), nullable=True, comment="新生儿性别")
delivery_mode = Column(String(16), nullable=True, comment="分娩方式")
@@ -1137,6 +1138,31 @@ class BizSampleSmsNotification(Base):
del_flag = Column(String(1), default="0")
class BizQcSmsNotification(Base):
"""样本质检短信通知 biz_qc_sms_notification"""
__tablename__ = "biz_qc_sms_notification"
id = Column(String(64), primary_key=True)
qc_work_order_id = Column(String(64), nullable=True, comment="关联 biz_qc_work_order.id")
protocol_sample_id = Column(String(64), nullable=True, comment="关联 biz_protocol_sample.id")
protocol_id = Column(String(64), comment="关联采集协议单ID")
sms_content = Column(String(500), comment="生成的短信内容")
sms_notified = Column(SmallInteger, default=0, comment="0=未通知 1=已通知")
notified_by = Column(String(64), comment="通知操作人ID")
notified_by_name = Column(String(64), comment="通知操作人姓名")
notified_time = Column(DateTime, comment="通知时间")
tenant_no = Column(String(32))
order_num = Column(Integer, default=0)
remark = Column(String(500))
create_by = Column(String(64))
create_dept_id = Column(String(64))
create_time = Column(DateTime, default=datetime.now)
update_by = Column(String(64))
update_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
del_flag = Column(String(1), default="0")
class BizStorageEntrySmsNotification(Base):
"""样本入库短信通知 biz_storage_entry_sms_notification"""
+2 -1
View File
@@ -1,7 +1,7 @@
"""科研捐赠管理 — 数据模型"""
from datetime import datetime
from sqlalchemy import Column, DateTime, Integer, Numeric, SmallInteger, String
from sqlalchemy import Column, Date, DateTime, Integer, Numeric, SmallInteger, String
from app.models.base import Base
@@ -79,6 +79,7 @@ class BizResearchDonationParty(Base):
father_id_card = Column(String(32), nullable=True, comment="父亲身份证号")
newborn_name = Column(String(100), nullable=True, comment="新生儿姓名")
newborn_id_card = Column(String(32), nullable=True, comment="新生儿身份证号")
expected_delivery_date = Column(Date, nullable=True, comment="预产期")
newborn_delivery_time = Column(DateTime, nullable=True, comment="新生儿分娩时间")
newborn_sex = Column(String(1), nullable=True, comment="新生儿性别")
delivery_mode = Column(String(16), nullable=True, comment="分娩方式")
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+152 -127
View File
@@ -1,12 +1,12 @@
# Graph Report - app (2026-05-28)
# Graph Report - app (2026-06-01)
## Corpus Check
- 172 files · ~180,865 words
- 174 files · ~182,957 words
- Verdict: corpus is large enough that graph structure adds value.
## Summary
- 3288 nodes · 14677 edges · 51 communities detected
- Extraction: 37% EXTRACTED · 63% INFERRED · 0% AMBIGUOUS · INFERRED: 9181 edges (avg confidence: 0.61)
- 3328 nodes · 14848 edges · 56 communities detected
- Extraction: 38% EXTRACTED · 62% INFERRED · 0% AMBIGUOUS · INFERRED: 9280 edges (avg confidence: 0.61)
- Token cost: 0 input · 0 output
## Community Hubs (Navigation)
@@ -55,24 +55,29 @@
- [[_COMMUNITY_Community 42|Community 42]]
- [[_COMMUNITY_Community 43|Community 43]]
- [[_COMMUNITY_Community 44|Community 44]]
- [[_COMMUNITY_Community 45|Community 45]]
- [[_COMMUNITY_Community 46|Community 46]]
- [[_COMMUNITY_Community 47|Community 47]]
- [[_COMMUNITY_Community 48|Community 48]]
- [[_COMMUNITY_Community 49|Community 49]]
- [[_COMMUNITY_Community 50|Community 50]]
- [[_COMMUNITY_Community 51|Community 51]]
- [[_COMMUNITY_Community 52|Community 52]]
- [[_COMMUNITY_Community 53|Community 53]]
- [[_COMMUNITY_Community 54|Community 54]]
- [[_COMMUNITY_Community 55|Community 55]]
- [[_COMMUNITY_Community 56|Community 56]]
- [[_COMMUNITY_Community 57|Community 57]]
## God Nodes (most connected - your core abstractions)
1. `success_response()` - 518 edges
2. `error_response()` - 418 edges
3. `SysUser` - 347 edges
4. `BizQcTaskResult` - 268 edges
5. `BizQcMaterialUsage` - 262 edges
6. `BizQcMaterial` - 260 edges
7. `BizMaterialStockLog` - 252 edges
8. `BizPilotPayment` - 251 edges
9. `BizMaterial` - 249 edges
10. `BizQcItemParam` - 247 edges
1. `success_response()` - 521 edges
2. `error_response()` - 421 edges
3. `SysUser` - 351 edges
4. `BizQcTaskResult` - 272 edges
5. `BizQcMaterialUsage` - 264 edges
6. `BizQcMaterial` - 262 edges
7. `BizMaterialStockLog` - 254 edges
8. `BizPilotPayment` - 253 edges
9. `BizMaterial` - 251 edges
10. `BizQcItemParam` - 249 edges
## Surprising Connections (you probably didn't know these)
- `统一记录 API 请求/响应出入参的中间件` --uses--> `SysApiRequestLog` [INFERRED]
@@ -90,248 +95,268 @@
### Community 0 - "Community 0"
Cohesion: 0.01
Nodes (604): attachment_download_url(), create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post() (+596 more)
Nodes (596): attachment_download_url(), create_dept(), create_dict_data(), create_dict_type(), create_express_company(), create_item_unit(), create_menu(), create_post() (+588 more)
### Community 1 - "Community 1"
Cohesion: 0.01
Nodes (493): AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody, DictTypeUpdateBody, ExpressCompanyCreateBody (+485 more)
Nodes (466): AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody, DictTypeUpdateBody, ExpressCompanyCreateBody (+458 more)
### Community 2 - "Community 2"
Cohesion: 0.06
Nodes (270): ProcessDefCreateBody, ProcessDefUpdateBody, PublishVersionBody, 审批意见:前端传 commentText,兼容 comment。, StartInstanceBody, TaskActionBody, Base, ApiRequestLogCRUD (+262 more)
Cohesion: 0.05
Nodes (316): AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, ExhibitionAppointmentCreateBody, ExhibitionAppointmentUpdateBody, OccupancyCreateBody, 运营支撑 API(洁净室、进出记录、仓储设施、储位、展厅预约) (+308 more)
### Community 3 - "Community 3"
Cohesion: 0.05
Nodes (244): AuditCreateBody, BatchDetailIdsBody, BatchRefundFinanceSubmitBody, FinanceConfirmBody, FullmoonTodoInsuranceBody, ProtocolCreateBody, ProtocolUpdateBody, 细胞存储 — 采集协议单 / 审核 / 财务确认 / 分期预警 API (+236 more)
Cohesion: 0.02
Nodes (241): generate_uuid(), _apply_cell_product_status_change(), batch_stock_in(), batch_stock_out(), consumable_code_exists(), create_consumable(), _dec(), get_consumable() (+233 more)
### Community 4 - "Community 4"
Cohesion: 0.02
Nodes (168): generate_uuid(), _apply_cell_product_status_change(), batch_stock_in(), batch_stock_out(), consumable_code_exists(), create_consumable(), _dec(), get_consumable() (+160 more)
Nodes (203): eq_unicode(), like_unicode(), MySQL 字符串比较/模糊匹配时统一排序规则,避免 Illegal mix of collations。, 跨表字符串等值比较(JOIN / WHERE)时统一为 utf8mb4_unicode_ci。, 将列显式设为 utf8mb4_unicode_ci。, unicode_ci(), delete(), get_multi_with_filters() (+195 more)
### Community 5 - "Community 5"
Cohesion: 0.02
Nodes (146): _ensure_customer_for_mother(), _persist_protocol_sub_resources(), delete(), get_multi_with_filters(), _add_months_yyyymmdd(), align_fq_payment_details_payload(), _apply_payment_detail_list_filters(), _apply_submit_receipt_finance() (+138 more)
Cohesion: 0.07
Nodes (198): CellSampleTypeCreateBody, CellSampleTypeUpdateBody, CollectionRegionCreateBody, CollectionRegionUpdateBody, CustomerCreateBody, CustomerUpdateBody, HospitalCreateBody, HospitalUpdateBody (+190 more)
### Community 6 - "Community 6"
Cohesion: 0.02
Nodes (144): list_ethnics_for_select(), apply_data_scope(), _get_child_dept_ids(), get_user_dept_id(), _resolve_user_role_scopes(), list_ethnics(), 民族码表 CRUD(全局 sys_ethnic), _row_to_dict() (+136 more)
Nodes (105): get_designer_data(), _error_json(), 数据库异常:返回 JSON 并保留 CORS 头,避免浏览器只报跨域错误, 未捕获异常:统一 JSON 500,确保跨域场景下仍有 Access-Control-Allow-Origin, sqlalchemy_exception_handler(), unhandled_exception_handler(), BaseHTTPMiddleware, ApiCryptoError (+97 more)
### Community 7 - "Community 7"
Cohesion: 0.02
Nodes (73): _error_json(), lifespan(), 数据库异常:返回 JSON 并保留 CORS 头,避免浏览器只报跨域错误, 未捕获异常:统一 JSON 500,确保跨域场景下仍有 Access-Control-Allow-Origin, sqlalchemy_exception_handler(), unhandled_exception_handler(), BaseHTTPMiddleware, parse_admin_request_json() (+65 more)
Cohesion: 0.04
Nodes (107): _persist_protocol_sub_resources(), list_ethnics_for_select(), apply_data_scope(), _get_child_dept_ids(), get_user_dept_id(), _resolve_user_role_scopes(), _add_months_yyyymmdd(), align_fq_payment_details_payload() (+99 more)
### Community 8 - "Community 8"
Cohesion: 0.04
Nodes (122): eq_unicode(), like_unicode(), MySQL 字符串比较/模糊匹配时统一排序规则,避免 Illegal mix of collations。, 跨表字符串等值比较(JOIN / WHERE)时统一为 utf8mb4_unicode_ci。, 将列显式设为 utf8mb4_unicode_ci。, unicode_ci(), _format_attachment_file_size(), urls_to_attachment_list() (+114 more)
Cohesion: 0.03
Nodes (97): generate_id(), camel_to_snake(), CRUDBase, get_model_attr(), HistoryCRUD, get_protocol_nos_used_in_protocols(), create_dict_type(), dict_type_code_exists() (+89 more)
### Community 9 - "Community 9"
Cohesion: 0.04
Nodes (77): get_protocol_nos_used_in_protocols(), create_dict_type(), dict_type_code_exists(), get_dict_type(), list_dict_types(), _row_to_dict(), soft_delete_dict_type(), update_dict_type() (+69 more)
Cohesion: 0.06
Nodes (66): api_save_application(), auto_generate_schedules(), complete_application(), create_application(), create_infusion_plan(), create_schedule(), _create_schedule_products(), _format_yyyy_mm_dd() (+58 more)
### Community 10 - "Community 10"
Cohesion: 0.07
Nodes (68): AccessLogCreateBody, AccessLogUpdateBody, CleanRoomCreateBody, CleanRoomUpdateBody, ExhibitionAppointmentCreateBody, ExhibitionAppointmentUpdateBody, OccupancyCreateBody, 运营支撑 API(洁净室、进出记录、仓储设施、储位、展厅预约) (+60 more)
Cohesion: 0.05
Nodes (60): _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)。, 获取当前用户菜单权限标识(sys_menu.perms,经角色继承)。 (+52 more)
### Community 11 - "Community 11"
Cohesion: 0.35
Nodes (61): BatchStockInBody, BatchStockInItem, BatchStockOutBody, BatchStockOutItem, ConsumableCreateBody, ConsumablePackCreateBody, ConsumablePackUpdateBody, ConsumableUpdateBody (+53 more)
### Community 12 - "Community 12"
Cohesion: 0.06
Nodes (54): _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 一致) (+46 more)
Cohesion: 0.07
Nodes (58): batch_delete_research_donations(), change_donation_status(), convert_from_storage(), convert_to_storage(), create_research_donation(), delete_research_donation(), _get_current_user_id(), get_research_donation_detail() (+50 more)
### Community 13 - "Community 13"
Cohesion: 0.06
Nodes (44): get_designer_data(), list_params_by_item(), _row_to_dict(), save_params_for_item(), list_results_by_task(), _list_saved_results_by_task(), _merge_saved_into_template(), _resolve_task_item_ref() (+36 more)
Cohesion: 0.08
Nodes (44): map_payments_by_schedule_ids(), _fmt_dt(), get_handover_by_schedule(), get_outbound_handover(), get_outbound_handover_view(), _handover_row_to_dict(), _handover_view_dict(), apply_handover_inventory() (+36 more)
### Community 14 - "Community 14"
Cohesion: 0.08
Nodes (53): auto_generate_schedules(), complete_application(), create_infusion_plan(), create_schedule(), _create_schedule_products(), _format_yyyy_mm_dd(), _generate_application_no(), get_application() (+45 more)
### Community 15 - "Community 15"
Cohesion: 0.09
Nodes (48): allocate_next_biz_no(), _format_biz_no(), _prefix_for(), 业务协议号自动生成:XBCC / JZCC + YYYYMMDD + 6 位序号, 原子分配下一个业务协议号。 须在 create 事务内调用;使用 MySQL LAST_INSERT_ID 保证并发安全。, create_collection_protocol(), _active_link_query(), assert_biz_no_available() (+40 more)
### Community 16 - "Community 16"
Cohesion: 0.12
Nodes (32): get_next_cell_product_code(), _ancestor_link_from_cell_product_input(), _ancestor_sample_chain_link(), _build_ancestor_chain(), _build_descendant_chain(), _build_facility_path_label(), build_split_product_codes(), create_cell_products_batch() (+24 more)
### Community 17 - "Community 17"
### Community 15 - "Community 15"
Cohesion: 0.16
Nodes (32): _create_insurance_company(), _create_insurance_company_invoice(), _create_insurance_project_price(), delete_insurance_company(), delete_insurance_company_invoice(), delete_insurance_project_price(), _fmt_dt(), _generate_uuid() (+24 more)
### Community 18 - "Community 18"
### Community 16 - "Community 16"
Cohesion: 0.12
Nodes (11): get_wechat_pay_client(), get_wechat_pay_v2(), 微信支付工具模块 支持微信支付 V3 API 文档参考: https://pay.weixin.qq.com/docs/v3/apis/index.ht, 统一下单接口 (V3) Args: out_trade_no: 商户订单号 total, 申请退款 Args: out_trade_no: 商户订单号 total_amount, 小程序调起支付的二次签名参数(与公众号 JSAPI 规则一致), 统一下单 (V2 API) Args: out_trade_no: 商户订单号 tot, 生成签名 V3 (SHA256 with RSA) (+3 more)
### Community 19 - "Community 19"
### Community 17 - "Community 17"
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 18 - "Community 18"
Cohesion: 0.18
Nodes (18): company_code_exists(), create_company(), get_company(), list_companies(), list_company_options(), _row_to_dict(), soft_delete_company(), update_company() (+10 more)
### Community 19 - "Community 19"
Cohesion: 0.21
Nodes (15): batch_generate_protocol_nos(), batch_issue_protocol_nos(), batch_revoke_protocol_nos(), create_protocol_no(), get_protocol_no(), list_protocol_nos(), _parse_issued_time(), protocol_no_exists() (+7 more)
### Community 20 - "Community 20"
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)
Cohesion: 0.22
Nodes (14): batch_generate_sample_codes(), batch_issue_sample_codes(), batch_revoke_sample_codes(), create_sample_code(), get_sample_code(), list_sample_codes(), _parse_issued_time(), 样本编码池 CRUD(biz_sample_code) (+6 more)
### Community 21 - "Community 21"
Cohesion: 0.2
Nodes (14): deduct_for_task(), _display_remark(), list_usages(), list_usages_by_task(), _parse_receiver_purpose_from_remark(), 查询质检任务关联的物料使用记录(task_complete)。, 撤销任务此前 task_complete 扣减,便于重新填报物料使用。, 兼容旧数据:领用人/用途曾拼接在 remark 中。 (+6 more)
### Community 22 - "Community 22"
Cohesion: 0.21
Nodes (13): create_collection_region(), create_hospital(), get_collection_region(), get_hospital(), _hospital_names_by_region_ids(), _hospital_to_dict(), list_collection_regions(), list_hospitals() (+5 more)
### Community 23 - "Community 23"
Cohesion: 0.25
Nodes (13): code_exists(), create_material(), _dec(), _fmt_dt(), get_material(), list_materials(), _norm_status(), options_list() (+5 more)
### Community 24 - "Community 24"
Cohesion: 0.22
Nodes (12): create_access_log(), create_clean_room(), get_access_log(), get_clean_room(), list_access_logs(), list_clean_rooms(), room_code_exists(), _row_to_dict() (+4 more)
### Community 25 - "Community 25"
Cohesion: 0.26
Nodes (11): _base_query(), _ensure_notification(), _fmt_dt(), generate_sms_content(), list_notifications(), _normalize_date_bound(), resolve_notification(), _row_to_dict() (+3 more)
### Community 22 - "Community 22"
Cohesion: 0.26
Nodes (12): batch_issue_sample_codes(), batch_revoke_sample_codes(), create_sample_code(), get_sample_code(), list_sample_codes(), _parse_issued_time(), 样本编码池 CRUD(biz_sample_code), _resolve_issued_user_display_name() (+4 more)
### Community 23 - "Community 23"
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 24 - "Community 24"
### Community 26 - "Community 26"
Cohesion: 0.27
Nodes (11): _accept_conclusion_label(), _base_query(), _ensure_notification(), _fmt_dt(), generate_sms_content(), list_notifications(), _normalize_date_bound(), resolve_notification() (+3 more)
### Community 25 - "Community 25"
### Community 27 - "Community 27"
Cohesion: 0.24
Nodes (9): 微信消息通知服务 支持微信小程序模板消息推送 使用方式: from app.core.wechat_message import Wech, 发送模板消息 Args: openid: 用户openid templ, send_delivery_notice(), send_delivery_warning(), send_order_status(), send_payment_success(), send_refund_result(), send_urge_notification() (+1 more)
### Community 26 - "Community 26"
Cohesion: 0.23
Nodes (12): Config, ProductBase, ProductCategoryBase, ProductCategoryCreate, ProductCategoryResponse, ProductCreate, ProductResponse, ProductUnitBase (+4 more)
### Community 28 - "Community 28"
Cohesion: 0.24
Nodes (12): appointment_no_exists(), create_exhibition_appointment(), _format_visit_date(), _generate_appointment_no(), get_exhibition_appointment(), list_exhibition_appointments(), 展览预约 CRUD(biz_exhibition_appointment), 生成预约编号:YYYYMMDD + 6位序号(如 20260515000001) (+4 more)
### Community 27 - "Community 27"
### Community 29 - "Community 29"
Cohesion: 0.24
Nodes (11): deduct_for_step(), _display_remark(), list_stock_logs(), _parse_receiver_purpose_from_remark(), 试剂变动记录 CRUD(biz_reagent_stock_log), 撤销步骤此前 step_save 扣减,便于重新填报。, 扣减试剂库存并生成变动记录。调用方控制事务,本函数不 commit。, _resolve_receiver_purpose() (+3 more)
### Community 30 - "Community 30"
Cohesion: 0.3
Nodes (10): create_consumable_pack(), get_consumable_pack(), get_pack_detail(), _item_row_to_dict(), list_all_packs(), list_consumable_packs(), pack_code_exists(), _row_to_dict() (+2 more)
### Community 31 - "Community 31"
Cohesion: 0.27
Nodes (11): _build_tree(), _cascade_soft_delete(), _collect_with_ancestors(), create_dept(), get_dept(), list_depts(), list_depts_tree(), 保留匹配节点及其全部上级,供关键词检索后仍能正确组树。 (+3 more)
### Community 28 - "Community 28"
Cohesion: 0.29
Nodes (9): _build_tree(), _cascade_soft_delete(), create_menu(), get_menu(), list_menus(), list_menus_tree(), _row_to_dict(), soft_delete_menu() (+1 more)
### Community 29 - "Community 29"
Cohesion: 0.36
Nodes (9): deduct_for_task(), _display_remark(), list_usages(), list_usages_by_task(), _parse_receiver_purpose_from_remark(), _resolve_receiver_purpose(), revert_task_material_usages(), _row_to_dict() (+1 more)
### Community 30 - "Community 30"
Cohesion: 0.31
Nodes (8): create_express_company(), express_code_exists(), get_express_company(), list_express_companies(), 快递公司 CRUD(biz_express_company), _row_to_dict(), soft_delete_express_company(), update_express_company()
### Community 31 - "Community 31"
Cohesion: 0.38
Nodes (9): create_check_item(), get_check_item(), item_code_exists(), list_active_check_items(), list_check_items(), _order_query(), _row_to_dict(), soft_delete_check_item() (+1 more)
### Community 32 - "Community 32"
Cohesion: 0.27
Nodes (8): create_dict_data(), get_dict_data(), list_dict_data(), list_dict_data_options(), 字典数据 CRUD(sys_dict_data), _row_to_dict(), soft_delete_dict_data(), update_dict_data()
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.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()
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 34 - "Community 34"
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 35 - "Community 35"
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 36 - "Community 36"
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 37 - "Community 37"
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 38 - "Community 38"
Cohesion: 0.31
Nodes (8): create_cell_sample_type(), get_cell_sample_type(), list_cell_sample_types(), 细胞样本类型 CRUD(biz_cell_sample_type), _row_to_dict(), soft_delete_cell_sample_type(), type_code_exists(), update_cell_sample_type()
### Community 35 - "Community 35"
### Community 39 - "Community 39"
Cohesion: 0.31
Nodes (8): create_output_type(), get_output_type(), list_output_types(), 工艺产出物类型 CRUD(biz_output_type), _row_to_dict(), soft_delete_output_type(), type_code_exists(), update_output_type()
### Community 36 - "Community 36"
Cohesion: 0.39
Nodes (8): create_lab_item(), get_lab_item(), item_code_exists(), list_active_lab_items(), list_lab_items(), _row_to_dict(), soft_delete_lab_item(), update_lab_item()
### Community 40 - "Community 40"
Cohesion: 0.36
Nodes (7): create_post(), get_post(), list_posts(), post_code_exists(), _row_to_dict(), soft_delete_post(), update_post()
### Community 37 - "Community 37"
### Community 41 - "Community 41"
Cohesion: 0.36
Nodes (7): create_tenant(), get_tenant(), list_tenants(), _row_to_dict(), soft_delete_tenant(), tenant_no_exists(), update_tenant()
### Community 42 - "Community 42"
Cohesion: 0.36
Nodes (7): create_site(), get_site(), list_sites(), _row_to_dict(), site_code_exists(), soft_delete_site(), update_site()
### Community 38 - "Community 38"
### Community 43 - "Community 43"
Cohesion: 0.29
Nodes (2): BaseModel, SoftDeleteModel
### Community 39 - "Community 39"
### Community 44 - "Community 44"
Cohesion: 0.38
Nodes (6): derive_legacy_status_from_three(), derive_three_status_from_legacy(), 阶段A兼容:从旧 status 推导三字段。 约束:旧 status 本身混合了支付/配送/订单生命周期,因此只能尽力推断; 若业务侧已有更精确, 阶段A兼容:从三字段反推旧 status(用于旧前端/旧筛选参数兼容)。, ThreeStatus, _to_decimal()
### Community 40 - "Community 40"
### Community 45 - "Community 45"
Cohesion: 0.5
Nodes (3): BaseSettings, Config, Settings
### Community 41 - "Community 41"
### Community 46 - "Community 46"
Cohesion: 0.5
Nodes (2): _auto_fill_create_dept_id(), ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID
### Community 42 - "Community 42"
### Community 47 - "Community 47"
Cohesion: 0.67
Nodes (2): get_menu_list(), 运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,13 个一级菜单)
### Community 43 - "Community 43"
### Community 48 - "Community 48"
Cohesion: 1.0
Nodes (1): 请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传
### Community 44 - "Community 44"
### Community 49 - "Community 49"
Cohesion: 1.0
Nodes (1): API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)
### Community 47 - "Community 47"
### Community 52 - "Community 52"
Cohesion: 1.0
Nodes (1): 发送订单状态通知 Args: openid: 用户openid ord
### Community 48 - "Community 48"
### Community 53 - "Community 53"
Cohesion: 1.0
Nodes (1): 发送支付成功通知 Args: openid: 用户openid ord
### Community 49 - "Community 49"
### Community 54 - "Community 54"
Cohesion: 1.0
Nodes (1): 发送配送通知 Args: openid: 配送员openid task
### Community 50 - "Community 50"
### Community 55 - "Community 55"
Cohesion: 1.0
Nodes (1): 发送配送时效预警 Args: openid: 配送员openid ta
### Community 51 - "Community 51"
### Community 56 - "Community 56"
Cohesion: 1.0
Nodes (1): 发送退款结果通知 Args: openid: 用户openid ord
### Community 52 - "Community 52"
### Community 57 - "Community 57"
Cohesion: 1.0
Nodes (1): 发送催单通知给配送员 Args: deliver_openid: 配送员openid
## Knowledge Gaps
- **97 isolated node(s):** `刷新会话 TTL(refreshToken 续期;已登录用户每次 API 校验通过后滑动续期)`, `写入 refreshToken(用于 one-time 使用/吊销)`, `根据 token 获取当前用户(包含 Redis 会话校验;会话滑动续期)`, `登录凭据 RSA 解密(与前端 JSEncrypt PKCS#1 v1.5 兼容)。`, `Base64 密文 -> JSON 对象(须含 username、password、ts 毫秒时间戳)。` (+92 more)
- **99 isolated node(s):** `刷新会话 TTL(refreshToken 续期;已登录用户每次 API 校验通过后滑动续期)`, `写入 refreshToken(用于 one-time 使用/吊销)`, `根据 token 获取当前用户(包含 Redis 会话校验;会话滑动续期)`, `登录凭据 RSA 解密(与前端 JSEncrypt PKCS#1 v1.5 兼容)。`, `Base64 密文 -> JSON 对象(须含 username、password、ts 毫秒时间戳)。` (+94 more)
These have ≤1 connection - possible missing edges or undocumented components.
- **Thin community `Community 38`** (8 nodes): `BaseModel`, `.to_dict()`, `get_active()`, `base.py`, `SoftDeleteModel`, `.restore()`, `.soft_delete()`, `__tablename__()`
- **Thin community `Community 43`** (8 nodes): `BaseModel`, `.to_dict()`, `get_active()`, `base.py`, `SoftDeleteModel`, `.restore()`, `.soft_delete()`, `__tablename__()`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 41`** (4 nodes): `_auto_fill_create_dept_id()`, `get_db()`, `database.py`, `ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID`
- **Thin community `Community 46`** (4 nodes): `_auto_fill_create_dept_id()`, `get_db()`, `database.py`, `ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 42`** (3 nodes): `get_menu_list()`, `menu.py`, `运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,13 个一级菜单)`
- **Thin community `Community 47`** (3 nodes): `get_menu_list()`, `menu.py`, `运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,13 个一级菜单)`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 43`** (2 nodes): `context.py`, `请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传`
- **Thin community `Community 48`** (2 nodes): `context.py`, `请求级别的用户上下文变量 通过 contextvars 在请求处理链路中传递当前用户信息, 供 SQLAlchemy 事件监听器等底层机制使用,避免逐层手动传`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 44`** (2 nodes): `__init__.py`, `API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)`
- **Thin community `Community 49`** (2 nodes): `__init__.py`, `API 路由包(骨架:公共鉴权 + 静态菜单 + 运营端占位)`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 47`** (1 nodes): `发送订单状态通知 Args: openid: 用户openid ord`
- **Thin community `Community 52`** (1 nodes): `发送订单状态通知 Args: openid: 用户openid ord`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 48`** (1 nodes): `发送支付成功通知 Args: openid: 用户openid ord`
- **Thin community `Community 53`** (1 nodes): `发送支付成功通知 Args: openid: 用户openid ord`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 49`** (1 nodes): `发送配送通知 Args: openid: 配送员openid task`
- **Thin community `Community 54`** (1 nodes): `发送配送通知 Args: openid: 配送员openid task`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 50`** (1 nodes): `发送配送时效预警 Args: openid: 配送员openid ta`
- **Thin community `Community 55`** (1 nodes): `发送配送时效预警 Args: openid: 配送员openid ta`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 51`** (1 nodes): `发送退款结果通知 Args: openid: 用户openid ord`
- **Thin community `Community 56`** (1 nodes): `发送退款结果通知 Args: openid: 用户openid ord`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 52`** (1 nodes): `发送催单通知给配送员 Args: deliver_openid: 配送员openid`
- **Thin community `Community 57`** (1 nodes): `发送催单通知给配送员 Args: deliver_openid: 配送员openid`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `SysUser` connect `Community 1` to `Community 2`, `Community 3`, `Community 4`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 17`, `Community 20`, `Community 22`?**
_High betweenness centrality (0.123) - this node is a cross-community bridge._
- **Why does `success_response()` connect `Community 0` to `Community 1`, `Community 6`, `Community 42`, `Community 12`, `Community 13`, `Community 16`, `Community 17`?**
_High betweenness centrality (0.088) - this node is a cross-community bridge._
- **Why does `generate_uuid()` connect `Community 4` to `Community 0`, `Community 1`, `Community 2`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 12`, `Community 13`, `Community 14`, `Community 15`, `Community 16`, `Community 19`, `Community 20`, `Community 21`, `Community 22`, `Community 23`, `Community 24`, `Community 27`, `Community 28`, `Community 29`, `Community 30`, `Community 31`, `Community 32`, `Community 33`, `Community 34`, `Community 35`, `Community 36`, `Community 37`?**
_High betweenness centrality (0.059) - this node is a cross-community bridge._
- **Are the 517 inferred relationships involving `success_response()` (e.g. with `list_storage_release_reviews()` and `get_storage_release_review_detail()`) actually correct?**
_`success_response()` has 517 INFERRED edges - model-reasoned connections that need verification._
- **Are the 505 inferred relationships involving `str` (e.g. with `unhandled_exception_handler()` and `extract_login_credentials()`) actually correct?**
_`str` has 505 INFERRED edges - model-reasoned connections that need verification._
- **Are the 417 inferred relationships involving `error_response()` (e.g. with `_json_error_response()` and `list_storage_release_reviews()`) actually correct?**
_`error_response()` has 417 INFERRED edges - model-reasoned connections that need verification._
- **Are the 345 inferred relationships involving `SysUser` (e.g. with `数据权限过滤(V0.3:基于角色 data_scope 的查询级行级过滤) data_scope 值: 1 = 全部数据 2 = 本部门数据 3` and `从 SysUser 读取用户的 dept_id。`) actually correct?**
_`SysUser` has 345 INFERRED edges - model-reasoned connections that need verification._
- **Why does `SysUser` connect `Community 1` to `Community 2`, `Community 3`, `Community 5`, `Community 8`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 15`, `Community 19`, `Community 20`, `Community 21`, `Community 29`?**
_High betweenness centrality (0.118) - this node is a cross-community bridge._
- **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 13`, `Community 14`, `Community 17`, `Community 18`, `Community 19`, `Community 20`, `Community 21`, `Community 22`, `Community 23`, `Community 24`, `Community 25`, `Community 26`, `Community 28`, `Community 29`, `Community 30`, `Community 31`, `Community 32`, `Community 33`, `Community 34`, `Community 35`, `Community 36`, `Community 37`, `Community 38`, `Community 39`, `Community 40`, `Community 41`, `Community 42`?**
_High betweenness centrality (0.068) - this node is a cross-community bridge._
- **Why does `success_response()` connect `Community 0` to `Community 1`, `Community 6`, `Community 7`, `Community 9`, `Community 10`, `Community 12`, `Community 14`, `Community 47`, `Community 15`?**
_High betweenness centrality (0.064) - this node is a cross-community bridge._
- **Are the 520 inferred relationships involving `success_response()` (e.g. with `list_storage_release_reviews()` and `get_storage_release_review_detail()`) actually correct?**
_`success_response()` has 520 INFERRED edges - model-reasoned connections that need verification._
- **Are the 511 inferred relationships involving `str` (e.g. with `unhandled_exception_handler()` and `extract_login_credentials()`) actually correct?**
_`str` has 511 INFERRED edges - model-reasoned connections that need verification._
- **Are the 420 inferred relationships involving `error_response()` (e.g. with `_json_error_response()` and `list_storage_release_reviews()`) actually correct?**
_`error_response()` has 420 INFERRED edges - model-reasoned connections that need verification._
- **Are the 349 inferred relationships involving `SysUser` (e.g. with `数据权限过滤(V0.3:基于角色 data_scope 的查询级行级过滤) data_scope 值: 1 = 全部数据 2 = 本部门数据 3` and `从 SysUser 读取用户的 dept_id。`) actually correct?**
_`SysUser` has 349 INFERRED edges - model-reasoned connections that need verification._
+4 -4
View File
@@ -57,12 +57,12 @@
</div>
<div id="legend"></div>
</div>
<div id="stats">3288 nodes &middot; 14677 edges &middot; 57 communities</div>
<div id="stats">3328 nodes &middot; 14848 edges &middot; 62 communities</div>
</div>
<script>
const RAW_NODES = [{"id": "init_py", "label": "__init__.py", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 45, "community_name": "Community 45", "source_file": "__init__.py", "file_type": "code", "degree": 0}, {"id": "main_py", "label": "main.py", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.py", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 7}, {"id": "app_main_lifespan", "label": "lifespan()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "lifespan()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_error_json", "label": "_error_json()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "_error_json()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 3}, {"id": "app_main_sqlalchemy_exception_handler", "label": "sqlalchemy_exception_handler()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "sqlalchemy_exception_handler()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_unhandled_exception_handler", "label": "unhandled_exception_handler()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "unhandled_exception_handler()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 5}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "_mask_secret()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_root", "label": "root()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "root()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_health_check", "label": "health_check()", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "health_check()", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_rationale_81", "label": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "app_main_rationale_92", "label": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "community": 7, "community_name": "Community 7", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "tasks_init_py", "label": "__init__.py", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 7, "community_name": "Community 7", "source_file": "tasks/__init__.py", "file_type": "code", "degLine truncated
const RAW_EDGES = [{"from": "main_py", "to": "app_main_lifespan", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_error_json", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_sqlalchemy_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_unhandled_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_mask_secret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_root", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_health_check", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_lifespan", "to": "core_login_crypto_ensure_initialized", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_init_scheduled_tasks", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_shutdown_scheduler", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_error_json", "to": "app_main_sqlalchemy_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_error_json", "to": "app_main_unhandled_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "app_main_rationale_81", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "app_main_rationale_92", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_unhandled_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "str", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tasks_init_py", "to": "tasks_init_init_scheduled_tasks", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tasks_init_py", "to": "tasks_init_shutdown_scheduler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_redis_session_enabled", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_redis_client", "labeLine truncated
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 625}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 531}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 276}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 249}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 187}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 167}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 160}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 136}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 132}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 89}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 72}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 68}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 64}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 57}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 55}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 52}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 34}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 33}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 31}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 20}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 15}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 14}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 14}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 14}, {"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": 13}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 12}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 11}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 10}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 10}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 10}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 10}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 10}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 10}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 10}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 9}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 9}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 8}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 7}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 4}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 4}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 3}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 2}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 2}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 1}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 1}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 1}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 1}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 1}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 1}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 1}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 1}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 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": 0}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 0}];
const RAW_NODES = [{"id": "init_py", "label": "__init__.py", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 50, "community_name": "Community 50", "source_file": "__init__.py", "file_type": "code", "degree": 0}, {"id": "main_py", "label": "main.py", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.py", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 7}, {"id": "app_main_lifespan", "label": "lifespan()", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "lifespan()", "community": 10, "community_name": "Community 10", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_error_json", "label": "_error_json()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "_error_json()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 3}, {"id": "app_main_sqlalchemy_exception_handler", "label": "sqlalchemy_exception_handler()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "sqlalchemy_exception_handler()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 4}, {"id": "app_main_unhandled_exception_handler", "label": "unhandled_exception_handler()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "unhandled_exception_handler()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 5}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "_mask_secret()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_root", "label": "root()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "root()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_health_check", "label": "health_check()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "health_check()", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "code", "degree": 1}, {"id": "app_main_rationale_81", "label": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "app_main_rationale_92", "label": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "community": 6, "community_name": "Community 6", "source_file": "main.py", "file_type": "rationale", "degree": 3}, {"id": "tasks_init_py", "label": "__init__.py", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "__init__.py", "community": 10, "community_name": "Community 10", "source_file": "tasks/__init__.py", "file_type": "code", Line truncated
const RAW_EDGES = [{"from": "main_py", "to": "app_main_lifespan", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_error_json", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_sqlalchemy_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_unhandled_exception_handler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_mask_secret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_root", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_py", "to": "app_main_health_check", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_lifespan", "to": "core_login_crypto_ensure_initialized", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_init_scheduled_tasks", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_lifespan", "to": "tasks_init_shutdown_scheduler", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_error_json", "to": "app_main_sqlalchemy_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_error_json", "to": "app_main_unhandled_exception_handler", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "app_main_rationale_81", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_sqlalchemy_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "app_main_rationale_92", "label": "rationale_for", "title": "rationale_for [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_main_unhandled_exception_handler", "to": "exception", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_unhandled_exception_handler", "to": "str", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_81", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_request_log_middleware_apirequestlogmiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "app_main_rationale_92", "to": "core_api_crypto_middleware_apicryptomiddleware", "label": "uses", "title": "uses [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "tasks_init_py", "to": "tasks_init_init_scheduled_tasks", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "tasks_init_py", "to": "tasks_init_shutdown_scheduler", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_redis_session_enabled", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_py", "to": "core_auth_get_redis_client", "labeLine truncated
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 618}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 501}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 322}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 263}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 222}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 201}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 170}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 120}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 119}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 70}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 68}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 68}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 67}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 48}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 34}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 33}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 31}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 21}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 20}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 17}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 16}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 15}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 15}, {"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": 14}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 14}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 13}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 13}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 12}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 12}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 12}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 11}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 10}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 10}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 10}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 10}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 10}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 10}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 10}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 9}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 9}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 9}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 8}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 7}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 4}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 4}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 3}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 2}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 2}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 1}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 1}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 1}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 1}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 1}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 1}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 1}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 1}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 1}];
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
function esc(s) {
File diff suppressed because it is too large. Load diff
+14 -12
View File
@@ -1,6 +1,6 @@
{
"/Users/wuzilong/work/00code/zkxw/backend/app/__init__.py": 1778578257.989357,
"/Users/wuzilong/work/00code/zkxw/backend/app/main.py": 1779835904.870218,
"/Users/wuzilong/work/00code/zkxw/backend/app/main.py": 1780326020.4099948,
"/Users/wuzilong/work/00code/zkxw/backend/app/tasks/__init__.py": 1778579841.437791,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/auth.py": 1779245791.6811426,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/api_crypto.py": 1778578258.039314,
@@ -13,10 +13,10 @@
"/Users/wuzilong/work/00code/zkxw/backend/app/core/request_payload.py": 1778578258.04292,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/__init__.py": 1778578258.028834,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/response.py": 1779928224.7450857,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py": 1778580098.1876886,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/menu_guard.py": 1780325524.7932978,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/db_collation.py": 1779890253.2250955,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/context.py": 1779242263.6923044,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py": 1778578258.045583,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/utils.py": 1780305790.0009735,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/storage.py": 1779159580.3795292,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/order_status_compat.py": 1778578258.0426462,
"/Users/wuzilong/work/00code/zkxw/backend/app/core/exceptions.py": 1778578258.0413945,
@@ -26,9 +26,9 @@
"/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": 1779882388.7305768,
"/Users/wuzilong/work/00code/zkxw/backend/app/models/models.py": 1780325981.2282472,
"/Users/wuzilong/work/00code/zkxw/backend/app/models/__init__.py": 1779418058.876012,
"/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py": 1779177348.5945773,
"/Users/wuzilong/work/00code/zkxw/backend/app/models/research_donation.py": 1780305799.8604646,
"/Users/wuzilong/work/00code/zkxw/backend/app/models/qc_material.py": 1779928228.734251,
"/Users/wuzilong/work/00code/zkxw/backend/app/models/base.py": 1778578258.0821667,
"/Users/wuzilong/work/00code/zkxw/backend/app/models/clinical_payment.py": 1779834956.9588954,
@@ -89,7 +89,7 @@
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/production_task.py": 1779927441.9434412,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_third_party_item.py": 1779265661.482352,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/reagent.py": 1779512669.9847593,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py": 1779882417.575858,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_protocol.py": 1780309408.7138562,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_material_usage.py": 1779332036.2049248,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/biz_no_generator.py": 1779882385.4674172,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/pilot_infusion_confirm.py": 1779828818.7646794,
@@ -102,6 +102,7 @@
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/pilot_application.py": 1779944020.3458025,
"/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/qc_sms_notification.py": 1780326057.839839,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/cell_product.py": 1779927536.8881981,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/menu.py": 1779265729.0381103,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/collection_region.py": 1779277867.6408322,
@@ -110,12 +111,12 @@
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/site.py": 1779265643.0128026,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/api_request_log.py": 1778578258.0614743,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/dict_data.py": 1779265627.276101,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py": 1779892801.1659443,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/research_donation.py": 1780309643.070291,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/ethnic.py": 1779265849.547566,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/pilot_checkup.py": 1779935785.233911,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/process_category.py": 1779265700.0606413,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/item_unit.py": 1779265653.7504313,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py": 1779965562.108948,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/qc_work_order.py": 1780307555.4017696,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/outbound_handover_inventory.py": 1779928420.2494187,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/outbound_release_material.py": 1779928413.9677577,
"/Users/wuzilong/work/00code/zkxw/backend/app/crud/process.py": 1779309113.0447981,
@@ -149,11 +150,12 @@
"/Users/wuzilong/work/00code/zkxw/backend/app/api/basic_info.py": 1779882001.7519956,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/pilot_infusion_confirm.py": 1779657043.1389203,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/pilot_infusion_schedule_mgmt.py": 1779940938.18027,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py": 1779835904.868773,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py": 1779691738.9150457,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/__init__.py": 1780326013.8238828,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/storage_entry_sms_notification.py": 1780325524.9170487,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/pilot_application.py": 1779940538.2296197,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/qc_sms_notification.py": 1780326012.745348,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/operations.py": 1779685679.1959367,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py": 1779944598.163366,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/menu.py": 1780325524.7933207,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/pilot_delivery.py": 1779655584.820777,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/admin.py": 1779882001.7516146,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/research_donation.py": 1779883570.5354397,
@@ -161,7 +163,7 @@
"/Users/wuzilong/work/00code/zkxw/backend/app/api/pilot_checkup.py": 1779935751.2658868,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/pilot_service.py": 1779712984.6961803,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/workflow.py": 1779266232.4568832,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py": 1779691678.688495,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_sms_notification.py": 1780325524.907156,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/sample_reception.py": 1779692499.6698253,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/insurance_company.py": 1779281097.279193,
"/Users/wuzilong/work/00code/zkxw/backend/app/api/production.py": 1779924318.5910363,
-83
View File
@@ -1,83 +0,0 @@
-- 民族码表(国标 GB/T 3304,仅数字编码条目,不含字母编码重复项)
-- 执行前请确认库中无同名表;与 docs/sql/zkxw.sql 全量基线可并存,亦可合并进全量导出
DROP TABLE IF EXISTS `sys_ethnic`;
CREATE TABLE `sys_ethnic` (
`id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '主键ID',
`ethnic_name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '民族名称',
`ethnic_code` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '民族编码',
`tenant_no` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '租户编号(空=全局码表)',
`order_num` int(11) DEFAULT NULL COMMENT '排序号',
`remark` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注',
`create_by` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '创建人id',
`create_dept_id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '创建人部门ID',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '更新人id',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag` tinyint(4) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_sys_ethnic_code` (`ethnic_code`,`del_flag`),
KEY `idx_sys_ethnic_name` (`ethnic_name`,`del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='民族码表';
BEGIN;
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-01', '汉族', '01', '', 1, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-02', '蒙古族', '02', '', 2, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-03', '回族', '03', '', 3, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-04', '藏族', '04', '', 4, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-05', '维吾尔族', '05', '', 5, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-06', '苗族', '06', '', 6, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-07', '彝族', '07', '', 7, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-08', '壮族', '08', '', 8, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-09', '布依族', '09', '', 9, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-10', '朝鲜族', '10', '', 10, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-11', '满族', '11', '', 11, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-12', '侗族', '12', '', 12, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-13', '瑶族', '13', '', 13, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-14', '白族', '14', '', 14, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-15', '土家族', '15', '', 15, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-16', '哈尼族', '16', '', 16, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-17', '哈萨克族', '17', '', 17, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-18', '傣族', '18', '', 18, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-19', '黎族', '19', '', 19, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-20', '傈僳族', '20', '', 20, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-21', '佤族', '21', '', 21, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-22', '畲族', '22', '', 22, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-23', '高山族', '23', '', 23, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-24', '拉祜族', '24', '', 24, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-25', '水族', '25', '', 25, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-26', '东乡族', '26', '', 26, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-27', '纳西族', '27', '', 27, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-28', '景颇族', '28', '', 28, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-29', '柯尔克孜族', '29', '', 29, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-30', '土族', '30', '', 30, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-31', '达斡尔族', '31', '', 31, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-32', '仫佬族', '32', '', 32, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-33', '羌族', '33', '', 33, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-34', '布朗族', '34', '', 34, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-35', '撒拉族', '35', '', 35, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-36', '毛难族', '36', '', 36, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-37', '仡佬族', '37', '', 37, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-38', '锡伯族', '38', '', 38, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-39', '阿昌族', '39', '', 39, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-40', '普米族', '40', '', 40, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-41', '塔吉克族', '41', '', 41, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-42', '怒族', '42', '', 42, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-43', '乌孜别克族', '43', '', 43, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-44', '俄罗斯族', '44', '', 44, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-45', '鄂温克族', '45', '', 45, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-46', '德昂族', '46', '', 46, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-47', '保安族', '47', '', 47, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-48', '裕固族', '48', '', 48, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-49', '京族', '49', '', 49, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-50', '塔塔尔族', '50', '', 50, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-51', '独龙族', '51', '', 51, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-52', '鄂伦春族', '52', '', 52, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-53', '赫哲族', '53', '', 53, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-54', '门巴族', '54', '', 54, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-55', '珞巴族', '55', '', 55, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-56', '基诺族', '56', '', 56, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-81', '穿青人族', '81', '', 57, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-97', '其他', '97', '', 58, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
INSERT INTO `sys_ethnic` (`id`, `ethnic_name`, `ethnic_code`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('ethnic-98', '外国血统中国籍人士', '98', '', 59, NULL, NULL, '', '2026-05-16 00:00:00', NULL, '2026-05-16 00:00:00', 0);
COMMIT;
+1133 -532
View File
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,306 @@
# 样本质检信息 Tab — 短信通知功能设计
> 状态:已实现
> 日期:2026-06-01
> 需求来源:样本信息管理页新增「样本质检信息」Tab,质检完成后向客户发送短信(线下复制发送)
## 1. 背景与目标
### 1.1 现状
「样本信息管理」页面(`/#/cell-storage/sample-info`)当前有两个 Tab:
| 顺序 | Tab | 能力 |
|------|-----|------|
| 1 | 样本接收信息 | 接收结论 + 短信提取/标记通知 |
| 2 | 样本入库信息 | 入库结论 + 短信提取/标记通知 |
业务链路:**接收 → 质检 → 入库**。质检环节完成后同样需要通知客户,但当前缺少对应 Tab 与后端能力。
### 1.2 目标
在「样本接收信息」与「样本入库信息」之间插入 **样本质检信息** Tab,交互与「样本入库信息」一致:
- 筛选 + 分页列表
- 查看协议单(`ProtocolViewDialog`)
- **提取短信**(复制到剪贴板)
- **标记已/未通知**
**关键约束**(与现有两个 Tab 一致):系统不自动发短信,仅生成内容供运营线下发送。
### 1.3 参考实现
| 层级 | 样本入库信息(克隆源) |
|------|------------------------|
| 前端 Tab | `StorageEntryInfoTab.vue` |
| 前端 API | `storage-entry-sms-notification.ts` |
| 后端 API | `storage_entry_sms_notification.py` |
| CRUD | `storage_entry_sms_notification.py` |
| 通知表 | `biz_storage_entry_sms_notification` |
| 业务数据源 | `biz_storage_release_review` |
设计文档参考:`docs/superpowers/specs/2025-05-23-storage-entry-sms-notification-design.md`
---
## 2. 数据范围
### 2.1 主数据源
**`biz_qc_work_order`(质检工单)**,筛选条件:
| 字段 | 值 | 说明 |
|------|-----|------|
| `reception_source` | `cell_storage` | 仅细胞存储协议样本,不含科研捐赠 |
| `qc_biz_type` | `inbound` | 入库质检(接收后自动创建的工单类型) |
| `work_order_status` | `ywc` | 工单已完成(所有质检任务均完成) |
| `del_flag` | `0` | 未删除 |
不展示:`dpz`(待配置)、`ypz`(已配置未完成)、`yzf`(已作废)。
### 2.2 质检结论(派生字段)
工单表无单一「综合结论」字段,需从 **`biz_qc_task`** 派生:
```
若任一已完成任务的 conclusion = 'btg' → 综合结论 = 不通过 (btg)
否则(全部任务 conclusion = 'tg')→ 综合结论 = 通过 (tg)
```
任务结论码:`tg` / `btg`(与 `status-tag-registry.ts` 中 `qcConclusion` 一致)。
### 2.3 质检完成时间(展示字段)
取该工单下所有 `task_status = 'ywc'` 任务的 **`completed_time` 最大值**;若无则回退工单 `update_time`(状态变为 `ywc` 时更新)。
### 2.4 关联键
与现有细胞存储跨表约定一致:**`tenant_no` + `sample_code`** 关联协议样本、当事人信息(参见 OpenSpec `api-conventions` § 细胞存储样本跨表关联键)。
联查路径:
```
BizQcWorkOrder
→ BizProtocolSample (sample_code + tenant_no)
→ BizCollectionProtocol
→ BizProtocolPartyCustomer
→ BizQcSmsNotification (懒创建,qc_work_order_id)
```
---
## 3. 方案对比
| 方案 | 描述 | 优点 | 缺点 | 建议 |
|------|------|------|------|------|
| **A. 全量克隆入库短信模块(推荐)** | 新建 `biz_qc_sms_notification` 表 + CRUD + API + Tab | 与现有模式一致;隔离清晰;改动面可控 | 需新建表与 5+ 文件 | ✅ 采用 |
| B. 扩展质检工单列表 API | 在 `qc_work_order` 列表加 SMS 字段 | 少一个 API 模块 | 职责混杂;权限与筛选语义不同;改动质检模块风险高 | ❌ |
| C. 合并到样本接收/入库通知表 | 一张表多类型 | 表少 | 破坏现有独立表设计;联查与模板逻辑耦合 | ❌ |
**推荐方案 A**:与 2025-05-23 入库短信设计同一套路,团队已有成熟模板。
---
## 4. 后端设计
### 4.1 新建表 `biz_qc_sms_notification`
```sql
CREATE TABLE biz_qc_sms_notification (
id VARCHAR(64) NOT NULL COMMENT 'UUID主键',
qc_work_order_id VARCHAR(64) NOT NULL COMMENT '关联 biz_qc_work_order.id',
protocol_id VARCHAR(64) DEFAULT NULL COMMENT '冗余协议单ID',
sms_content VARCHAR(500) DEFAULT NULL COMMENT '生成的短信内容',
sms_notified TINYINT(1) NOT NULL DEFAULT 0 COMMENT '0=未通知 1=已通知',
notified_by VARCHAR(64) DEFAULT NULL,
notified_by_name VARCHAR(64) DEFAULT NULL,
notified_time DATETIME DEFAULT NULL,
tenant_no VARCHAR(64) DEFAULT NULL,
order_num INT DEFAULT 0,
remark VARCHAR(512) DEFAULT NULL,
create_by VARCHAR(64) DEFAULT NULL,
create_dept_id VARCHAR(64) DEFAULT NULL,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64) DEFAULT NULL,
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
del_flag CHAR(1) DEFAULT '0',
PRIMARY KEY (id),
KEY idx_qc_work_order_id (qc_work_order_id),
KEY idx_tenant_no (tenant_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='样本质检短信通知';
```
### 4.2 CRUD 要点(`qc_sms_notification.py`)
- **list_notifications**:联查 + 租户隔离 + `apply_data_scope`
- **懒创建**:列表加载时为已完成工单自动插入 `sms_notified=0` 记录
- **toggle_notification_status**:标记已/未通知,记录操作人与时间
- **generate_sms_content**:按综合结论生成模板并持久化到 `sms_content`
列表 `_row_to_dict` 返回字段(驼峰):
| 字段 | 说明 |
|------|------|
| id | 通知记录 ID |
| qcWorkOrderId | 质检工单 ID |
| collectionProtocolId | 协议单 ID |
| protocolNo / protocolStatus | 协议号与状态 |
| motherName / newbornName | 当事人 |
| sampleCode / sampleTypeName | 样本 |
| qcCompleteTime | 质检完成时间 |
| qcConclusion / qcConclusionLabel | tg/btg 及中文标签 |
| smsNotified / smsContent | 通知状态与内容 |
### 4.3 短信模板(初稿,待产品确认)
```
通过:尊敬的{母亲}女士,您的样本(编码:{code})已完成质检,结果合格。如有疑问请联系客服。
不通过:尊敬的{母亲}女士,您的样本(编码:{code})质检未通过。如有疑问请联系客服。
```
变量:`mother_name` ← 当事人表;`code` ← 工单 `sample_code`;日期可选加入完成日期。
### 4.4 API 端点
前缀 `/api/web/admin`:
| 方法 | 路径 | 功能 |
|------|------|------|
| GET | `/qc-sms-notifications/list` | 分页列表 |
| PUT | `/qc-sms-notifications/{id}/toggle-status` | 切换通知状态 |
| POST | `/qc-sms-notifications/{id}/generate-sms` | 生成短信 |
**权限码**(与样本信息管理 Tab 共用,无需新菜单):
```python
require_any_menu_code(
"cell-storage:sample-info:list",
"cell-storage:sample-qc-info:list", # 可选:预留独立权限
)
```
初期建议仅 `cell-storage:sample-info:list`,与入库/接收 API 策略一致。
Query 参数:
| 参数 | 说明 |
|------|------|
| keyword | 协议号/姓名/样本编码 |
| qcConclusion | `tg` / `btg` |
| smsNotified | `0` / `1` |
| qcCompleteTimeStart / qcCompleteTimeEnd | 完成时间范围 |
默认时间范围:**近 30 天**(与另外两个 Tab 一致)。
---
## 5. 前端设计
### 5.1 Tab 入口
修改 `web-admin/src/views/cell-storage/sample-info/index.vue`:
| 顺序 | key | 标题 | 图标建议 |
|------|-----|------|----------|
| 1 | sample-reception | 样本接收信息 | Box |
| 2 | **sample-qc** | **样本质检信息** | **DocumentChecked** |
| 3 | storage-entry | 样本入库信息 | FolderOpened |
`VALID_TABS` 增加 `sample-qc`;样式类由 `--dual` 改为 `--triple`(三 Tab 布局)。
### 5.2 新建组件
`web-admin/src/views/cell-storage/protocol-audit/SampleQcInfoTab.vue`
(与 `SampleReceptionInfoTab` / `StorageEntryInfoTab` 同目录,便于复用)
**筛选区**:
| 字段 | 控件 | 绑定 |
|------|------|------|
| 关键词 | el-input | keyword |
| 质检结论 | el-select | qcConclusion(通过 tg / 不通过 btg) |
| 通知状态 | el-select | smsNotified |
| 质检完成时间 | daterange | qcCompleteTimeRange |
**表格列**(全部 `min-width`,居中,状态用 `el-tag`):
协议号、协议状态、母亲姓名、新生儿姓名、样本编码、样本类型、**质检完成时间**、**质检结论**、通知状态、操作(查看 / 提取短信 / 标记通知)。
**查看**:`ProtocolViewDialog`(`show-audit-history` 等同入库 Tab)。
### 5.3 新建 API 模块
`web-admin/src/api/qc-sms-notification.ts` — 3 个函数,镜像 `storage-entry-sms-notification.ts`。
---
## 6. 业务流程图
```mermaid
flowchart LR
A[样本接收 js] --> B[创建入库质检工单]
B --> C[配置并执行质检任务]
C --> D{全部任务完成?}
D -->|是| E[工单状态 ywc]
E --> F[样本质检信息 Tab 展示]
F --> G[提取短信 / 标记已通知]
G --> H[运营线下发送]
E --> I[后续入库放行...]
```
---
## 7. 边界情况
| 场景 | 处理 |
|------|------|
| 工单 ywc 但部分任务无 conclusion | 不纳入列表,或结论显示「待确认」;实现时需明确(建议:无 conclusion 不展示) |
| 科研捐赠样本 | `reception_source != cell_storage` 过滤排除 |
| 出库/临时质检 | `qc_biz_type != inbound` 过滤排除 |
| 缺少协议单 | 查看按钮提示,不打开弹窗 |
| 旧书签 `?tab=sample-qc` | sample-info 页 onMounted 解析 query |
---
## 8. 文件清单(预估)
### 新建
| 文件 | 说明 |
|------|------|
| `docs/sql/biz_qc_sms_notification.sql` | 建表 DDL |
| `docs/sql/migration-2026-06-01-qc-sms-notification.sql` | 增量迁移 |
| `backend/app/crud/qc_sms_notification.py` | CRUD |
| `backend/app/api/qc_sms_notification.py` | API |
| `web-admin/src/api/qc-sms-notification.ts` | 前端 API |
| `web-admin/src/views/cell-storage/protocol-audit/SampleQcInfoTab.vue` | Tab 组件 |
### 修改
| 文件 | 修改 |
|------|------|
| `backend/app/models/models.py` | `BizQcSmsNotification` 模型 |
| `backend/app/api/__init__.py` / `main.py` | 注册路由 |
| `web-admin/src/views/cell-storage/sample-info/index.vue` | 增加 Tab |
| `docs/sql/zkxw.sql` | 全量基线同步 |
**不做的事**:不自动发短信;不改动质检工单执行逻辑;不修改接收/入库 Tab。
---
## 9. 待确认项(评审门禁)
1. **短信文案**:上述通过/不通过模板是否可用?是否需要包含完成日期?
2. **列表范围**:是否仅「工单已完成 ywc」?是否还需要展示「进行中 ypz」供提前通知?(建议:仅 ywc,与入库 Tab 只展示终态一致)
3. **权限**:是否沿用 `cell-storage:sample-info:list`,无需新菜单权限?
---
## 10. 工作量评估
| 模块 | 预估 |
|------|------|
| 后端(表+CRUD+API) | 0.5~1 天 |
| 前端 Tab + API | 0.5 天 |
| 联调与边界验证 | 0.5 天 |
| **合计** | **约 1.5~2 天** |
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+68 -94
View File
@@ -1,10 +1,10 @@
# Graph Report - src (2026-05-28)
# Graph Report - src (2026-06-01)
## Corpus Check
- Large corpus: 672 files · ~418,385 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
- Large corpus: 672 files · ~418,769 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
## Summary
- 1934 nodes · 2494 edges · 50 communities detected
- 1938 nodes · 2502 edges · 46 communities detected
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 553 edges (avg confidence: 0.8)
- Token cost: 0 input · 0 output
@@ -39,7 +39,7 @@
- [[_COMMUNITY_Community 27|Community 27]]
- [[_COMMUNITY_Community 28|Community 28]]
- [[_COMMUNITY_Community 29|Community 29]]
- [[_COMMUNITY_Community 30|Community 30]]
- [[_COMMUNITY_Community 31|Community 31]]
- [[_COMMUNITY_Community 32|Community 32]]
- [[_COMMUNITY_Community 33|Community 33]]
- [[_COMMUNITY_Community 35|Community 35]]
@@ -47,18 +47,14 @@
- [[_COMMUNITY_Community 37|Community 37]]
- [[_COMMUNITY_Community 38|Community 38]]
- [[_COMMUNITY_Community 39|Community 39]]
- [[_COMMUNITY_Community 40|Community 40]]
- [[_COMMUNITY_Community 41|Community 41]]
- [[_COMMUNITY_Community 44|Community 44]]
- [[_COMMUNITY_Community 42|Community 42]]
- [[_COMMUNITY_Community 43|Community 43]]
- [[_COMMUNITY_Community 45|Community 45]]
- [[_COMMUNITY_Community 46|Community 46]]
- [[_COMMUNITY_Community 47|Community 47]]
- [[_COMMUNITY_Community 48|Community 48]]
- [[_COMMUNITY_Community 49|Community 49]]
- [[_COMMUNITY_Community 50|Community 50]]
- [[_COMMUNITY_Community 51|Community 51]]
- [[_COMMUNITY_Community 52|Community 52]]
- [[_COMMUNITY_Community 54|Community 54]]
- [[_COMMUNITY_Community 56|Community 56]]
## God Nodes (most connected - your core abstractions)
1. `get()` - 203 edges
@@ -73,26 +69,26 @@
10. `buildOutboundPilotContextSections()` - 12 edges
## Surprising Connections (you probably didn't know these)
- `handleBatchDelete()` --calls--> `withFullscreenLoading()` [INFERRED]
views/basic-info/customer/index.vue → utils/fullscreen-loading.ts
- `subscribeTokenRefresh()` --calls--> `push()` [INFERRED]
utils/http/index.ts → views/operations/storage-facility/index.vue
- `handleUnauthorizedResponse()` --calls--> `fetchRefreshToken()` [INFERRED]
utils/http/index.ts → api/auth.ts
- `fetchLeaveList()` --calls--> `get()` [INFERRED]
api/leave.ts → views/production/process/ProcessRouteTab.vue
- `fetchLeaveDetail()` --calls--> `get()` [INFERRED]
api/leave.ts → views/production/process/ProcessRouteTab.vue
- `fetchSampleReceptionCheckItemList()` --calls--> `get()` [INFERRED]
api/sample-reception-check-item.ts → views/production/process/ProcessRouteTab.vue
- `fetchSampleReceptionCheckItemsActive()` --calls--> `get()` [INFERRED]
api/sample-reception-check-item.ts → views/production/process/ProcessRouteTab.vue
## Communities
### Community 0 - "Community 0"
Cohesion: 0.01
Nodes (104): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchCellSampleTypeList() (+96 more)
Nodes (112): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchCellSampleTypeList() (+104 more)
### Community 1 - "Community 1"
Cohesion: 0.03
Nodes (85): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchCheckupInstitutionProjects(), fetchPilotCheckupDetail(), markPilotCheckupChecked(), savePilotCheckup() (+77 more)
Nodes (83): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionList(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchCheckupInstitutionProjects(), fetchPilotCheckupDetail(), markPilotCheckupChecked() (+75 more)
### Community 2 - "Community 2"
Cohesion: 0.03
@@ -100,27 +96,27 @@ Nodes (40): fetchGetMenuList(), fetchGetMenuCodes(), fetchGetUserInfo(), fetchLo
### Community 3 - "Community 3"
Cohesion: 0.03
Nodes (36): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllConsumableStockLogs(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents(), fetchAllReagentStockLogs() (+28 more)
Nodes (50): fetchCollectionRegionList(), fetchCreateCollectionRegion(), fetchCreateHospital(), fetchDeleteCollectionRegion(), fetchDeleteHospital(), fetchHospitalList(), fetchUpdateCollectionRegion(), fetchUpdateHospital() (+42 more)
### Community 4 - "Community 4"
Cohesion: 0.03
Nodes (37): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), submitOutboundReleaseReview(), fetchStorageReleaseReviewDetail(), fetchStorageReleaseReviewList(), submitStorageReleaseReview() (+29 more)
Nodes (36): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllConsumableStockLogs(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents(), fetchAllReagentStockLogs() (+28 more)
### Community 5 - "Community 5"
Cohesion: 0.04
Nodes (33): handleBlur(), handleFocus(), handleInput(), formatAmount(), fmtMoney(), auditorDisplay(), dash(), expressName() (+25 more)
### Community 6 - "Community 6"
Cohesion: 0.06
Nodes (34): toLogin(), base64ToBytes(), bytesToBase64(), decryptJson(), deriveKey(), encryptJson(), fromBase64Url(), hexToBytes() (+26 more)
### Community 7 - "Community 7"
Cohesion: 0.04
Nodes (28): fetchAttachmentDownloadUrl(), fullFileUrl(), handleDownloadAttachment(), handlePreviewAttachment(), isVideoFile(), handleReceptionAttachmentDownload(), handleDownloadAttachment(), attachmentFullUrl() (+20 more)
### Community 7 - "Community 7"
Cohesion: 0.06
Nodes (34): toLogin(), base64ToBytes(), bytesToBase64(), decryptJson(), deriveKey(), encryptJson(), fromBase64Url(), hexToBytes() (+26 more)
### Community 8 - "Community 8"
Cohesion: 0.05
Nodes (30): fetchCollectionRegionList(), fetchCreateCollectionRegion(), fetchCreateHospital(), fetchDeleteCollectionRegion(), fetchDeleteHospital(), fetchHospitalList(), fetchUpdateCollectionRegion(), fetchUpdateHospital() (+22 more)
Nodes (23): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateMenu(), collectIds(), postorder(), preorder(), applyTreeExpand() (+15 more)
### Community 9 - "Community 9"
Cohesion: 0.08
@@ -132,7 +128,7 @@ Nodes (28): fetchFullmoonTodoList(), fetchUpdateFullmoonTodoInsurance(), fetchCo
### Community 11 - "Community 11"
Cohesion: 0.06
Nodes (27): for(), set(), walk(), annotateForkEdges(), chainApiToElements(), walkAncestorBranch(), walkAncestorParents(), if() (+19 more)
Nodes (29): for(), set(), walk(), annotateForkEdges(), chainApiToElements(), walkAncestorBranch(), walkAncestorParents(), if() (+21 more)
### Community 12 - "Community 12"
Cohesion: 0.09
@@ -140,7 +136,7 @@ Nodes (8): getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, get
### Community 13 - "Community 13"
Cohesion: 0.07
Nodes (20): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateMenu(), collectIds(), postorder(), preorder(), applyTreeExpand() (+12 more)
Nodes (24): fetchCreateSite(), fetchDeleteSite(), fetchSiteList(), fetchUpdateSite(), fetchUserList(), formatNowDatetime(), formatHandoverUserLabel(), formatNowDatetime() (+16 more)
### Community 14 - "Community 14"
Cohesion: 0.07
@@ -160,63 +156,63 @@ Nodes (20): fetchCreateUser(), fetchDeleteUser(), fetchResetPassword(), fetchUpd
### Community 18 - "Community 18"
Cohesion: 0.12
Nodes (19): fetchCreateSite(), fetchDeleteSite(), fetchSiteList(), fetchUpdateSite(), fetchUserList(), remoteSearchHandoverUsers(), formatContactUserLabel(), handleAdd() (+11 more)
### Community 19 - "Community 19"
Cohesion: 0.12
Nodes (15): addCopyButton(), highlightCode(), insertLineNumbers(), isBlockProcessed(), markBlockAsProcessed(), processBlock(), setupHighlightDirective(), setupRippleDirective() (+7 more)
### Community 20 - "Community 20"
### Community 19 - "Community 19"
Cohesion: 0.1
Nodes (6): fetchProductionTaskDetail(), fetchProductionTaskList(), fetchUpdateProductionTask(), handleClose(), handleSubmit(), loadTaskDetail()
### Community 20 - "Community 20"
Cohesion: 0.15
Nodes (16): fetchPilotCheckupList(), canEditActualCheckupInfo(), canEditReserve(), canFillCheckupInfo(), canMarkChecked(), handleDropdownCommand(), handleEditActual(), handleEditReserve() (+8 more)
### Community 21 - "Community 21"
Cohesion: 0.14
Nodes (16): fetchCheckupInstitutionList(), fetchPilotCheckupList(), canEditCheckup(), canFillCheckupInfo(), canMarkChecked(), handleDropdownCommand(), handleEdit(), handleReset() (+8 more)
### Community 22 - "Community 22"
Cohesion: 0.09
Nodes (5): fetchMaterialList(), fetchMaterialOptions(), fetchMaterialStockLogList(), fetchQcMaterialList(), fetchQcMaterialOptions()
### Community 23 - "Community 23"
Cohesion: 0.12
Nodes (12): fetchApproveTask(), fetchBusinessAllTasks(), fetchCompletedTasks(), fetchDesignerData(), fetchInstanceDetail(), fetchMyInstances(), fetchPendingTasks(), fetchProcessDefList() (+4 more)
### Community 24 - "Community 24"
### Community 22 - "Community 22"
Cohesion: 0.15
Nodes (11): fetchEthnicList(), addSample(), applyDonationBundleToForm(), confirmBatchTransportApply(), createEmptyTransport(), ensureEthnicOptionInList(), handleOpenForAdd(), loadEthnicOptions() (+3 more)
### Community 25 - "Community 25"
### Community 23 - "Community 23"
Cohesion: 0.13
Nodes (8): fetchOutboundReleaseMaterial(), fetchOutboundReleaseReviewDetail(), fetchOutboundReleaseReviewList(), fetchReleaseReviewList(), handleReset(), handleSearch(), loadData(), onReviewSubmitted()
### Community 26 - "Community 26"
### Community 24 - "Community 24"
Cohesion: 0.16
Nodes (14): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), handleAdd(), handleBatchDelete(), handleDelete(), handleDropdownCommand() (+6 more)
### Community 25 - "Community 25"
Cohesion: 0.16
Nodes (10): useTable(), useTableImpl(), getColumnChecks(), useTableColumns(), createErrorHandler(), createSmartDebounce(), defaultResponseAdapter(), extractPagination() (+2 more)
### Community 27 - "Community 27"
### Community 26 - "Community 26"
Cohesion: 0.2
Nodes (2): ComponentLoader, RouteTransformer
### Community 28 - "Community 28"
### Community 27 - "Community 27"
Cohesion: 0.27
Nodes (14): useChart(), useChartComponent(), useChartOps(), colourBlend(), getCssVar(), getDarkColor(), getLightColor(), handleElementThemeColor() (+6 more)
### Community 29 - "Community 29"
### Community 28 - "Community 28"
Cohesion: 0.14
Nodes (8): useSettingsHandlers(), useSettingsPanel(), useSettingsState(), useCeremony(), useTheme(), themeAnimation(), toggleTheme(), toggleTransition()
### Community 30 - "Community 30"
### Community 29 - "Community 29"
Cohesion: 0.18
Nodes (5): fetchServiceOrderTxnList(), handleReset(), handleSearch(), handleTabChange(), loadData()
### Community 32 - "Community 32"
### Community 31 - "Community 31"
Cohesion: 0.17
Nodes (3): fetchResearchDonationAuditList(), fetchResearchDonationDetail(), fetchResearchDonationList()
### Community 32 - "Community 32"
Cohesion: 0.18
Nodes (3): fetchMaterialList(), fetchMaterialOptions(), fetchMaterialStockLogList()
### Community 33 - "Community 33"
Cohesion: 0.28
Nodes (1): FireworkSystem
Cohesion: 0.2
Nodes (2): fetchQcMaterialList(), fetchQcMaterialOptions()
### Community 35 - "Community 35"
Cohesion: 0.39
@@ -231,100 +227,78 @@ Cohesion: 0.25
Nodes (2): fetchQcTaskDetail(), fetchQcTaskList()
### Community 38 - "Community 38"
Cohesion: 0.25
Nodes (3): fetchOutboundQcDetail(), fetchQcWorkOrderDetail(), fetchQcWorkOrderList()
### Community 39 - "Community 39"
Cohesion: 0.33
Nodes (2): logApiCryptoBootInfo(), maskSecret()
### Community 40 - "Community 40"
Cohesion: 0.29
Nodes (2): fetchLeaveDetail(), fetchLeaveList()
### Community 41 - "Community 41"
### Community 39 - "Community 39"
Cohesion: 0.47
Nodes (3): isPaymentDueWithinWarnWindow(), parsePaymentDueYmd(), startOfLocalDay()
### Community 44 - "Community 44"
### Community 42 - "Community 42"
Cohesion: 0.33
Nodes (2): fetchSampleReceptionCheckItemList(), fetchSampleReceptionCheckItemsActive()
### Community 45 - "Community 45"
Cohesion: 0.33
Nodes (2): fetchQcThirdPartyItemList(), fetchQcThirdPartyItemsActive()
### Community 46 - "Community 46"
### Community 43 - "Community 43"
Cohesion: 0.33
Nodes (2): fetchQcThirdPartyCompanyList(), fetchQcThirdPartyCompanyOptions()
### Community 48 - "Community 48"
### Community 45 - "Community 45"
Cohesion: 0.5
Nodes (3): reload(), handleMenuJump(), openExternalLink()
### Community 49 - "Community 49"
### Community 46 - "Community 46"
Cohesion: 0.5
Nodes (2): focusInput(), handleKeydown()
### Community 50 - "Community 50"
### Community 47 - "Community 47"
Cohesion: 0.67
Nodes (2): if(), logSidebarMenu()
### Community 51 - "Community 51"
Cohesion: 0.5
Nodes (1): fetchStorageEntrySmsList()
### Community 52 - "Community 52"
### Community 48 - "Community 48"
Cohesion: 0.5
Nodes (1): fetchSampleSmsNotificationList()
### Community 54 - "Community 54"
### Community 50 - "Community 50"
Cohesion: 1.0
Nodes (2): getSettingDefaults(), resetToDefaults()
### Community 56 - "Community 56"
### Community 52 - "Community 52"
Cohesion: 1.0
Nodes (2): defaultAvatarPathByRole(), resolveUserAvatarUrl()
## Knowledge Gaps
- **Thin community `Community 27`** (17 nodes): `ComponentLoader`, `.constructor()`, `.createEmptyComponent()`, `.createErrorComponent()`, `.load()`, `.loadIframe()`, `.loadLayout()`, `.load()`, `RouteTransformer`, `.extractFirstSegment()`, `.handleFirstLevelRoute()`, `.handleIframeRoute()`, `.handleNormalRoute()`, `.isFirstLevelRoute()`, `.transform()`, `ComponentLoader.ts`, `RouteTransformer.ts`
- **Thin community `Community 26`** (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 33`** (9 nodes): `FireworkSystem`, `.constructor()`, `.createFirework()`, `.createParticle()`, `.getAvailableParticle()`, `.initializePool()`, `.preloadAllImages()`, `.preloadImage()`, `index.vue`
- **Thin community `Community 33`** (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 36`** (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 37`** (8 nodes): `fetchCompleteQcTask()`, `fetchCreateQcTask()`, `fetchDeleteQcTask()`, `fetchQcTaskDetail()`, `fetchQcTaskList()`, `fetchStartQcTask()`, `fetchUpdateQcTaskAttachments()`, `qc-task.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 39`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
- **Thin community `Community 38`** (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 40`** (7 nodes): `fetchCreateLeave()`, `fetchDeleteLeave()`, `fetchLeaveDetail()`, `fetchLeaveList()`, `fetchSubmitLeave()`, `fetchUpdateLeave()`, `leave.ts`
- **Thin community `Community 42`** (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 44`** (6 nodes): `fetchCreateSampleReceptionCheckItem()`, `fetchDeleteSampleReceptionCheckItem()`, `fetchSampleReceptionCheckItemList()`, `fetchSampleReceptionCheckItemsActive()`, `fetchUpdateSampleReceptionCheckItem()`, `sample-reception-check-item.ts`
- **Thin community `Community 43`** (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 45`** (6 nodes): `fetchCreateQcThirdPartyItem()`, `fetchDeleteQcThirdPartyItem()`, `fetchQcThirdPartyItemList()`, `fetchQcThirdPartyItemsActive()`, `fetchUpdateQcThirdPartyItem()`, `qc-third-party-item.ts`
- **Thin community `Community 46`** (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 46`** (6 nodes): `fetchCreateQcThirdPartyCompany()`, `fetchDeleteQcThirdPartyCompany()`, `fetchQcThirdPartyCompanyList()`, `fetchQcThirdPartyCompanyOptions()`, `fetchUpdateQcThirdPartyCompany()`, `qc-third-party-company.ts`
- **Thin community `Community 47`** (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 49`** (5 nodes): `focusInput()`, `handleKeydown()`, `if()`, `search()`, `index.vue`
- **Thin community `Community 48`** (4 nodes): `fetchGenerateSms()`, `fetchSampleSmsNotificationList()`, `fetchToggleSmsNotified()`, `sample-sms-notification.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 50`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
- **Thin community `Community 50`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 51`** (4 nodes): `fetchGenerateStorageEntrySms()`, `fetchStorageEntrySmsList()`, `fetchToggleStorageEntrySmsNotified()`, `storage-entry-sms-notification.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 52`** (4 nodes): `fetchGenerateSms()`, `fetchSampleSmsNotificationList()`, `fetchToggleSmsNotified()`, `sample-sms-notification.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 54`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 56`** (3 nodes): `defaultAvatarPathByRole()`, `resolveUserAvatarUrl()`, `user-avatar.ts`
- **Thin community `Community 52`** (3 nodes): `defaultAvatarPathByRole()`, `resolveUserAvatarUrl()`, `user-avatar.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 8`, `Community 10`, `Community 11`, `Community 13`, `Community 14`, `Community 16`, `Community 17`, `Community 18`, `Community 20`, `Community 21`, `Community 22`, `Community 23`, `Community 24`, `Community 25`, `Community 30`, `Community 32`, `Community 37`, `Community 38`, `Community 40`, `Community 44`, `Community 45`, `Community 46`, `Community 51`, `Community 52`?**
_High betweenness centrality (0.269) - this node is a cross-community bridge._
- **Why does `push()` connect `Community 1` to `Community 0`, `Community 33`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 9`, `Community 10`, `Community 11`, `Community 15`, `Community 48`, `Community 18`, `Community 24`?**
_High betweenness centrality (0.122) - this node is a cross-community bridge._
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 8`, `Community 10`, `Community 11`, `Community 13`, `Community 14`, `Community 16`, `Community 17`, `Community 19`, `Community 20`, `Community 21`, `Community 22`, `Community 23`, `Community 24`, `Community 29`, `Community 31`, `Community 32`, `Community 33`, `Community 37`, `Community 42`, `Community 43`, `Community 48`?**
_High betweenness centrality (0.268) - this node is a cross-community bridge._
- **Why does `push()` connect `Community 1` to `Community 0`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 9`, `Community 10`, `Community 11`, `Community 45`, `Community 13`, `Community 15`, `Community 22`?**
_High betweenness centrality (0.117) - this node is a cross-community bridge._
- **Are the 202 inferred relationships involving `get()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `buildTreePathLabelFromFlat()`) actually correct?**
_`get()` has 202 INFERRED edges - model-reasoned connections that need verification._
- **Are the 35 inferred relationships involving `push()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `fetchAllPagedRecords()`) actually correct?**
+4 -4
View File
@@ -57,12 +57,12 @@
</div>
<div id="legend"></div>
</div>
<div id="stats">1934 nodes &middot; 2494 edges &middot; 295 communities</div>
<div id="stats">1938 nodes &middot; 2502 edges &middot; 291 communities</div>
</div>
<script>
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 39, "community_name": "Community 39", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 39, "community_name": "Community 39", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 39, "community_name": "Community 39", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 39, "community_name": "Community 39", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 39, "community_name": "Community 39", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 39, "community_name": "Community 39", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#FF9DA7", "border": "#FF9DA7", "highlight": {"background": "#ffffff", "border": "#FF9DA7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 87, "community_name": "Community 87", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 88, "community_name": "Community 88", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 19, "community_name": "Community 19", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 19, "community_name": "Community 19", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 19, "community_name": "Community 19", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 19, "community_name": "Community 19", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 19, "community_name": "Community 19", "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": 308}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 118}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 104}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 81}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 76}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 64}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 57}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 57}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 54}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 51}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 45}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 43}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 37}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 37}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 35}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 31}, {"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": 24}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 22}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 22}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 22}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 21}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 19}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 19}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 18}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 17}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 17}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 16}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 15}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 14}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 13}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 12}, {"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": 8}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 8}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 8}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 8}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 7}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 7}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 6}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 6}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 6}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 6}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 6}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 6}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 6}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 5}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 5}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 4}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 4}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 4}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 4}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 3}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 3}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 3}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 3}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 3}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 3}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 3}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 3}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 3}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 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": 2Line truncated
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 38, "community_name": "Community 38", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 38, "community_name": "Community 38", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 38, "community_name": "Community 38", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 38, "community_name": "Community 38", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 38, "community_name": "Community 38", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 38, "community_name": "Community 38", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 83, "community_name": "Community 83", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 84, "community_name": "Community 84", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#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.5, "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.3, "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.2, "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.2, "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": 333}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 118}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 104}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 97}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 81}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 64}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 57}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 57}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 52}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 51}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 45}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 45}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 37}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 35}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 35}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 31}, {"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": 22}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 22}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 19}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 19}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 18}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 18}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 17}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 17}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 16}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 15}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 14}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 13}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 12}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 11}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 10}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 9}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 8}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 8}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 8}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 7}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 6}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 6}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 6}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 6}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 6}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 6}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 5}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 5}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 4}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 4}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 4}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 3}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 3}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 3}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 3}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 3}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 3}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 3}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 3}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 3}, {"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": Line truncated
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
function esc(s) {
+14 -14
View File
@@ -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": 1779968658.3992856,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1779965275.9913518,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1780309724.4413683,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1780309689.6547496,
"/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,
@@ -56,7 +56,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/category-path-display.ts": 1779790340.9231393,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-labels.ts": 1779199108.173778,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/loginRsa.ts": 1778582068.0373487,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts": 1779790341.1822743,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts": 1780310646.0954366,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/download-attachment.ts": 1779159591.1376455,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/ui/colors.ts": 1778582068.046773,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/ui/emojo.ts": 1778582068.0469406,
@@ -239,9 +239,9 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/refund-confirm/index.vue": 1779866933.9349332,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/index.vue": 1779859546.0906804,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolStatusChangeDialog.vue": 1779525781.613681,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue": 1779790347.193558,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue": 1780305875.3456032,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue": 1779525781.6162472,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue": 1779882482.5887764,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue": 1780310650.4481847,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolAuditDialog.vue": 1779525781.6193507,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/sample-reception-info/index.vue": 1779868497.86612,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/payment-info/index.vue": 1779868497.867598,
@@ -251,7 +251,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol-audit/SampleReceptionInfoTab.vue": 1779868409.0059524,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol-audit/StorageCertTab.vue": 1779868926.5850313,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol-audit/FullmoonTodoTab.vue": 1779868452.5295193,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol-audit/ProtocolAuditTab.vue": 1779868352.051264,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol-audit/ProtocolAuditTab.vue": 1780309406.4299293,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol-audit/PaymentInfoTab.vue": 1779884638.4477615,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/material/index.vue": 1779864743.0373998,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/material/MaterialStockLogTab.vue": 1779864756.1772933,
@@ -265,11 +265,11 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/clean-room/index.vue": 1779859632.4029214,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/storage-facility/index.vue": 1779893362.9148128,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/operations/exhibition-appointment/index.vue": 1779859537.3908546,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/audit/index.vue": 1779859635.6573696,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/audit/index.vue": 1780309643.0702963,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/index.vue": 1779859565.175567,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationAuditDialog.vue": 1779525781.6319423,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue": 1779790364.8471587,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue": 1779883571.8349173,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue": 1780305877.034227,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue": 1780305873.3308973,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationStatusChangeDialog.vue": 1779525781.6357327,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/dashboard/console/index.vue": 1779857063.389745,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/system/tenant/index.vue": 1779858296.9440098,
@@ -312,10 +312,10 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/reagent/index.vue": 1779863928.5798419,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue": 1779968582.0555966,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts": 1779790360.26504,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue": 1779968053.649664,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue": 1780306770.0831616,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/CompleteProductionTaskDialog.vue": 1779790359.5464847,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskInputEnhancedTable.vue": 1779967895.2461958,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue": 1779968052.0510938,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue": 1780307249.480838,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/EditTaskInfoDialog.vue": 1779925648.9018784,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputList.vue": 1779967896.0077794,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue": 1779925648.243228,
@@ -377,7 +377,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationViewDialog.vue": 1779944085.8337502,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/InfusionScheduleTab.vue": 1779969771.7272167,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ApplicationFormDialog.vue": 1779940036.5255854,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue": 1779940970.6155307,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue": 1780307989.1142402,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/ClinicalPaymentTab.vue": 1779944565.962619,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/cell-product-price/index.vue": 1779864955.5971668,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/index.vue": 1779935807.47013,
@@ -386,8 +386,8 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupRegisterDialog.vue": 1779790354.7432914,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupDetailDialog.vue": 1779790354.4793391,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/checkup-reserve-items.ts": 1779923701.3416343,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue": 1779790354.549774,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue": 1779923727.345238,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue": 1780307966.803123,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue": 1780308025.8246984,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/clinical-payment-info/index.vue": 1779944563.635542,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/channel-service-order-finance/index.vue": 1779857021.6808643,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/project-price-system/index.vue": 1779864957.7299743,
+48
View File
@@ -0,0 +1,48 @@
import request from '@/utils/http'
type PageList<T> = {
list: T[]
total: number
page: number
pageSize: number
totalPages: number
}
/** 查询列表(联查 qc_work_order + sms_notification,每个样本一条) */
export function fetchQcSmsList(params?: {
page?: number
pageSize?: number
keyword?: string
qcStatus?: string
qcConclusion?: string
smsNotified?: string
qcCompleteTimeStart?: string
qcCompleteTimeEnd?: string
}) {
return request.get<PageList<Record<string, unknown>>>({
url: '/web/admin/qc-sms-notifications/list',
params
})
}
/** 切换通知状态 */
export function fetchToggleQcSmsNotified(
id: string,
data: { smsNotified: number; qcWorkOrderId?: string; protocolSampleId?: string }
) {
return request.put({
url: `/web/admin/qc-sms-notifications/${id}/toggle-status`,
data
})
}
/** 生成短信内容 */
export function fetchGenerateQcSms(
id: string,
params?: { qcWorkOrderId?: string; protocolSampleId?: string }
) {
return request.post<{ smsContent: string }>({
url: `/web/admin/qc-sms-notifications/${id}/generate-sms`,
params: params || undefined
})
}
@@ -100,8 +100,8 @@
/>
<el-table-column label="状态" min-width="90" align="center" header-align="center">
<template #default="{ row }">
<el-tag :type="productStatusTagType(row.productStatus)" size="small">
{{ productStatusLabel(row.productStatus) }}
<el-tag :type="cellProductStatusTagType(row.productStatus)" size="small">
{{ cellProductStatusLabel(row.productStatus) }}
</el-tag>
</template>
</el-table-column>
@@ -119,6 +119,7 @@
import type { ViewSection } from '@/components/business/system-view-dialog/index.vue'
import { fetchProductionTaskDetail } from '@/api/production-task'
import { productionConclusionLabel, productionConclusionTagType } from '@/utils/production-labels'
import { cellProductStatusLabel, cellProductStatusTagType } from '@/utils/status-tag-registry'
const props = defineProps<{
visible: boolean
@@ -189,26 +190,6 @@
return 'info' as const
}
function productStatusTagType(status?: string) {
const map: Record<string, 'success' | 'warning' | 'danger' | 'info'> = {
frozen: 'success',
in_production: 'warning',
voided: 'danger',
thawed: 'info'
}
return map[status || ''] || 'info'
}
function productStatusLabel(status?: string) {
const map: Record<string, string> = {
frozen: '已冻存',
in_production: '生产中',
voided: '已作废',
thawed: '已复苏'
}
return map[status || ''] || status || '—'
}
function formatDateOnly(val: unknown) {
if (!val) return '—'
const s = String(val)
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_taskexecutiondialog_vue", "label": "TaskExecutionDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "label": "ProtocolFormDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1"}, {"id": "protocol_protocolformdialog_fmtmoney", "label": "fmtMoney()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1192"}, {"id": "protocol_protocolformdialog_createemptytransport", "label": "createEmptyTransport()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1254"}, {"id": "protocol_protocolformdialog_fullfileurl", "label": "fullFileUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1274"}, {"id": "protocol_protocolformdialog_loadethnicoptions", "label": "loadEthnicOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1281"}, {"id": "protocol_protocolformdialog_ensureethnicoptioninlist", "label": "ensureEthnicOptionInList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1292"}, {"id": "protocol_protocolformdialog_expressname", "label": "expressName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1320"}, {"id": "protocol_protocolformdialog_for", "label": "for()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1961"}, {"id": "protocol_protocolformdialog_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L2494"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1140", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1141", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_collection_protocol", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1153", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1159", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_download_attachment", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1160", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1161", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_ethnic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1173", "weight": 1.0}, {"source":Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "label": "ProtocolFormDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1"}, {"id": "protocol_protocolformdialog_fmtmoney", "label": "fmtMoney()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1189"}, {"id": "protocol_protocolformdialog_createemptytransport", "label": "createEmptyTransport()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1251"}, {"id": "protocol_protocolformdialog_fullfileurl", "label": "fullFileUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1271"}, {"id": "protocol_protocolformdialog_loadethnicoptions", "label": "loadEthnicOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1278"}, {"id": "protocol_protocolformdialog_ensureethnicoptioninlist", "label": "ensureEthnicOptionInList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1289"}, {"id": "protocol_protocolformdialog_expressname", "label": "expressName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1317"}, {"id": "protocol_protocolformdialog_for", "label": "for()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1995"}, {"id": "protocol_protocolformdialog_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L2528"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1140", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1141", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_collection_protocol", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1153", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1159", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_download_attachment", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1160", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1161", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_ethnic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1173", "weight": 1.0}, {"source":Line truncated
@@ -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": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_audit_protocolaudittab_vue", "label": "ProtocolAuditTab.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol-audit/ProtocolAuditTab.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationformdialog_vue", "label": "DonationFormDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1"}, {"id": "list_donationformdialog_createemptytransport", "label": "createEmptyTransport()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1002"}, {"id": "list_donationformdialog_fullfileurl", "label": "fullFileUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1022"}, {"id": "list_donationformdialog_loadethnicoptions", "label": "loadEthnicOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1029"}, {"id": "list_donationformdialog_ensureethnicoptioninlist", "label": "ensureEthnicOptionInList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1040"}, {"id": "list_donationformdialog_samplerowlabel", "label": "sampleRowLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1068"}, {"id": "list_donationformdialog_resetform", "label": "resetForm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1149"}, {"id": "list_donationformdialog_scrolltosection", "label": "scrollToSection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1203"}, {"id": "list_donationformdialog_normalizesamplerow", "label": "normalizeSampleRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1211"}, {"id": "list_donationformdialog_openbatchtransportdialog", "label": "openBatchTransportDialog()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1234"}, {"id": "list_donationformdialog_confirmbatchtransportapply", "label": "confirmBatchTransportApply()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1242"}, {"id": "list_donationformdialog_addsample", "label": "addSample()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1256"}, {"id": "list_donationformdialog_removesample", "label": "removeSample()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1270"}, {"id": "list_donationformdialog_handleopenforadd", "label": "handleOpenForAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1274"}, {"id": "list_donationformdialog_applydonationbundletoform", "label": "applyDonationBundleToForm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1322"}, {"id": "list_donationformdialog_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1937"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationformdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L912", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationformdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L913", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_research_donation", "relation": "imports_from", "confidLine truncated
@@ -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": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_audit_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/audit/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_pilot_application_checkupmanagementtab_vue", "label": "CheckupManagementTab.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L1"}, {"id": "pilot_application_checkupmanagementtab_isrowselectable", "label": "isRowSelectable()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L323"}, {"id": "pilot_application_checkupmanagementtab_handleselectionchange", "label": "handleSelectionChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L325"}, {"id": "pilot_application_checkupmanagementtab_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L342"}, {"id": "pilot_application_checkupmanagementtab_loadinstitutions", "label": "loadInstitutions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L363"}, {"id": "pilot_application_checkupmanagementtab_handlesearch", "label": "handleSearch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L373"}, {"id": "pilot_application_checkupmanagementtab_handlereset", "label": "handleReset()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L378"}, {"id": "pilot_application_checkupmanagementtab_canfillcheckupinfo", "label": "canFillCheckupInfo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L389"}, {"id": "pilot_application_checkupmanagementtab_canmarkchecked", "label": "canMarkChecked()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L393"}, {"id": "pilot_application_checkupmanagementtab_caneditreserve", "label": "canEditReserve()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L396"}, {"id": "pilot_application_checkupmanagementtab_caneditactualcheckupinfo", "label": "canEditActualCheckupInfo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L399"}, {"id": "pilot_application_checkupmanagementtab_hasprimarycheckupactions", "label": "hasPrimaryCheckupActions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L402"}, {"id": "pilot_application_checkupmanagementtab_hasmorecheckupactions", "label": "hasMoreCheckupActions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L406"}, {"id": "pilot_application_checkupmanagementtab_handledropdowncommand", "label": "handleDropdownCommand()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L413"}, {"id": "pilot_application_checkupmanagementtab_handlefill", "label": "handleFill()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L427"}, {"id": "pilot_application_checkupmanagementtab_handleeditreserve", "label": "handleEditReserve()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L434"}, {"id": "pilot_application_checkupmanagementtab_handleeditactual", "label": "handleEditActual()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "L441"}, {"id": "pilot_application_checkupmanagementtab_onfillsuccess", "label": "onFillSuccess()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/pilot-application/CheckupManagementTab.vue", "source_location": "LLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_checkup_management_checkupmarkcheckeddialog_vue", "label": "CheckupMarkCheckedDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L1"}, {"id": "checkup_management_checkupmarkcheckeddialog_parselist", "label": "parseList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L501"}, {"id": "checkup_management_checkupmarkcheckeddialog_projectstatuslabel", "label": "projectStatusLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L505"}, {"id": "checkup_management_checkupmarkcheckeddialog_projectstatustagtype", "label": "projectStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L509"}, {"id": "checkup_management_checkupmarkcheckeddialog_loadinstitutioncatalog", "label": "loadInstitutionCatalog()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L518"}, {"id": "checkup_management_checkupmarkcheckeddialog_requireinstitution", "label": "requireInstitution()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L537"}, {"id": "checkup_management_checkupmarkcheckeddialog_handleopenprojectselector", "label": "handleOpenProjectSelector()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L555"}, {"id": "checkup_management_checkupmarkcheckeddialog_isprojectalreadyinactual", "label": "isProjectAlreadyInActual()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L565"}, {"id": "checkup_management_checkupmarkcheckeddialog_confirmprojectselect", "label": "confirmProjectSelect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L568"}, {"id": "checkup_management_checkupmarkcheckeddialog_handleopenpackageselector", "label": "handleOpenPackageSelector()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L593"}, {"id": "checkup_management_checkupmarkcheckeddialog_confirmpackageselect", "label": "confirmPackageSelect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L603"}, {"id": "checkup_management_checkupmarkcheckeddialog_handlepackageview", "label": "handlePackageView()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L635"}, {"id": "checkup_management_checkupmarkcheckeddialog_formatnowdatetime", "label": "formatNowDatetime()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L657"}, {"id": "checkup_management_checkupmarkcheckeddialog_fullfileurl", "label": "fullFileUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L664"}, {"id": "checkup_management_checkupmarkcheckeddialog_isimagefile", "label": "isImageFile()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L672"}, {"id": "checkup_management_checkupmarkcheckeddialog_parseattachmenturls", "label": "parseAttachmentUrls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L681"}, {"id": "checkup_management_checkupmarkcheckeddialog_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L693"}, {"id": "checkup_management_checkupmarkcheckLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolviewdialog_vue", "label": "ProtocolViewDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1"}, {"id": "protocol_protocolviewdialog_fullmoontodostatuslabel", "label": "fullmoonTodoStatusLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1348"}, {"id": "protocol_protocolviewdialog_fullmoontodostatustagtype", "label": "fullmoonTodoStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1352"}, {"id": "protocol_protocolviewdialog_insurancesubscribedlabel", "label": "insuranceSubscribedLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1356"}, {"id": "protocol_protocolviewdialog_insurancesubscribedtagtype", "label": "insuranceSubscribedTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1360"}, {"id": "protocol_protocolviewdialog_fmtmoney", "label": "fmtMoney()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1365"}, {"id": "protocol_protocolviewdialog_storagecertmakestatuslabel", "label": "storageCertMakeStatusLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1370"}, {"id": "protocol_protocolviewdialog_storagecertmakestatustagtype", "label": "storageCertMakeStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1374"}, {"id": "protocol_protocolviewdialog_dash", "label": "dash()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1433"}, {"id": "protocol_protocolviewdialog_formatmetric", "label": "formatMetric()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1438"}, {"id": "protocol_protocolviewdialog_formatymd", "label": "formatYmd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1444"}, {"id": "protocol_protocolviewdialog_formatym", "label": "formatYm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1450"}, {"id": "protocol_protocolviewdialog_paydetailcolorclass", "label": "payDetailColorClass()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1456"}, {"id": "protocol_protocolviewdialog_isreceiptfinanceconfirmed", "label": "isReceiptFinanceConfirmed()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1464"}, {"id": "protocol_protocolviewdialog_financeconfirmattachmentfiles", "label": "financeConfirmAttachmentFiles()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1724"}, {"id": "protocol_protocolviewdialog_refundattachmentfiles", "label": "refundAttachmentFiles()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1731"}, {"id": "protocol_protocolviewdialog_refundfinanceconfirmattachmentfiles", "label": "refundFinanceConfirmAttachmentFiles()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1738"}, {"id": "protocol_protocolviewdialog_hasfinanceconfirmattachments", "label": "hasFinanceConfirmAttachments()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1762"}, {"id": "protocol_protocolviewdialog_hasrefundapplyinfo", "label": "hasRefundApplyInfo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_locationLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_checkup_management_checkupfilldialog_vue", "label": "CheckupFillDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L1"}, {"id": "checkup_management_checkupfilldialog_parselist", "label": "parseList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L387"}, {"id": "checkup_management_checkupfilldialog_projectstatuslabel", "label": "projectStatusLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L391"}, {"id": "checkup_management_checkupfilldialog_projectstatustagtype", "label": "projectStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L395"}, {"id": "checkup_management_checkupfilldialog_loadinstitutions", "label": "loadInstitutions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L401"}, {"id": "checkup_management_checkupfilldialog_loadinstitutioncatalog", "label": "loadInstitutionCatalog()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L426"}, {"id": "checkup_management_checkupfilldialog_oninstitutionchange", "label": "onInstitutionChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L445"}, {"id": "checkup_management_checkupfilldialog_requireinstitution", "label": "requireInstitution()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L455"}, {"id": "checkup_management_checkupfilldialog_handleopenprojectselector", "label": "handleOpenProjectSelector()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L474"}, {"id": "checkup_management_checkupfilldialog_isprojectalreadyinreserve", "label": "isProjectAlreadyInReserve()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L484"}, {"id": "checkup_management_checkupfilldialog_confirmprojectselect", "label": "confirmProjectSelect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L490"}, {"id": "checkup_management_checkupfilldialog_handleopenpackageselector", "label": "handleOpenPackageSelector()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L516"}, {"id": "checkup_management_checkupfilldialog_confirmpackageselect", "label": "confirmPackageSelect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L526"}, {"id": "checkup_management_checkupfilldialog_handlepackageview", "label": "handlePackageView()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L559"}, {"id": "checkup_management_checkupfilldialog_handlesubmit", "label": "handleSubmit()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L576"}, {"id": "checkup_management_checkupfilldialog_loadeditdata", "label": "loadEditData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L616"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_checkup_management_checkupfilldialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupFillDialog.vue", "source_location": "L352", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_checkup_management_checkupfilldialog_vue", "target": "icons_vue", "relation": Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "label": "ProtocolFormDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1"}, {"id": "protocol_protocolformdialog_fmtmoney", "label": "fmtMoney()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1189"}, {"id": "protocol_protocolformdialog_createemptytransport", "label": "createEmptyTransport()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1251"}, {"id": "protocol_protocolformdialog_fullfileurl", "label": "fullFileUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1271"}, {"id": "protocol_protocolformdialog_loadethnicoptions", "label": "loadEthnicOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1278"}, {"id": "protocol_protocolformdialog_ensureethnicoptioninlist", "label": "ensureEthnicOptionInList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1289"}, {"id": "protocol_protocolformdialog_expressname", "label": "expressName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1317"}, {"id": "protocol_protocolformdialog_for", "label": "for()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1971"}, {"id": "protocol_protocolformdialog_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L2504"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1140", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1141", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_collection_protocol", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1153", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1159", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_download_attachment", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1160", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1161", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_ethnic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1173", "weight": 1.0}, {"source":Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_installment_ts", "label": "protocol-payment-installment.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L1"}, {"id": "utils_protocol_payment_installment_addmonthsymd", "label": "addMonthsYmd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L3"}, {"id": "utils_protocol_payment_installment_adddaysymd", "label": "addDaysYmd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L17"}, {"id": "utils_protocol_payment_installment_calcfqinstallmentduedate", "label": "calcFqInstallmentDueDate()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L32"}, {"id": "utils_protocol_payment_installment_calcinstallmentdueamounts", "label": "calcInstallmentDueAmounts()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L44"}, {"id": "utils_protocol_payment_installment_alignfqpaymentdetailsfordisplay", "label": "alignFqPaymentDetailsForDisplay()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L70"}, {"id": "utils_protocol_payment_installment_sortfqpaymentdetails", "label": "sortFqPaymentDetails()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L137"}, {"id": "utils_protocol_payment_installment_syncfqpaymentdetailrowcount", "label": "syncFqPaymentDetailRowCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L147"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_installment_ts", "target": "utils_protocol_payment_installment_addmonthsymd", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L3", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_installment_ts", "target": "utils_protocol_payment_installment_adddaysymd", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L17", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_installment_ts", "target": "utils_protocol_payment_installment_calcfqinstallmentduedate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L32", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_installment_ts", "target": "utils_protocol_payment_installment_calcinstallmentdueamounts", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L44", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_installment_ts", "target": "utils_protocol_payment_installment_alignfqpaymentdetailsfordisplay", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L70", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_installment_ts", "target": "utils_protocol_payment_installment_sortfqpaymentdetails", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L137", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_installment_ts", "target": "utils_protocol_payment_installment_syncfqpaymentdetailrowcount", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L147", "weight": 1.0}, {"source": "utils_protocol_payment_installment_calcfqinstallmentduedate", "target": "utils_protocol_payment_installment_addmonthsymd", "relation": "calls", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L37", "weight": 1.0}, {"source": "utils_protocol_Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "label": "ProtocolFormDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1"}, {"id": "protocol_protocolformdialog_fmtmoney", "label": "fmtMoney()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1179"}, {"id": "protocol_protocolformdialog_createemptytransport", "label": "createEmptyTransport()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1241"}, {"id": "protocol_protocolformdialog_fullfileurl", "label": "fullFileUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1261"}, {"id": "protocol_protocolformdialog_loadethnicoptions", "label": "loadEthnicOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1268"}, {"id": "protocol_protocolformdialog_ensureethnicoptioninlist", "label": "ensureEthnicOptionInList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1279"}, {"id": "protocol_protocolformdialog_expressname", "label": "expressName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1307"}, {"id": "protocol_protocolformdialog_for", "label": "for()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1930"}, {"id": "protocol_protocolformdialog_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L2462"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1130", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1131", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_collection_protocol", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1143", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1149", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_download_attachment", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1150", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1151", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_ethnic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1163", "weight": 1.0}, {"source":Line truncated
@@ -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": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "label": "StepDetailPanel.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L1"}, {"id": "production_work_order_stepdetailpanel_for", "label": "for()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L732"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_stepdetailpanel_vue", "target": "production_work_order_stepdetailpanel_for", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L732", "weight": 1.0}], "raw_calls": [{"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "push", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L734"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "decodeURIComponent", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L737"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "pop", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L737"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "split", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L737"}, {"caller_nid": "production_work_order_stepdetailpanel_for", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue", "source_location": "L737"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationviewdialog_vue", "label": "DonationViewDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L1"}, {"id": "list_donationviewdialog_dash", "label": "dash()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L787"}, {"id": "list_donationviewdialog_formatmetric", "label": "formatMetric()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L792"}, {"id": "list_donationviewdialog_formatymd", "label": "formatYmd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L798"}, {"id": "list_donationviewdialog_formatym", "label": "formatYm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L804"}, {"id": "list_donationviewdialog_auditordisplay", "label": "auditorDisplay()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L810"}, {"id": "list_donationviewdialog_sampletypename", "label": "sampleTypeName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L816"}, {"id": "list_donationviewdialog_unitname", "label": "unitName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L820"}, {"id": "list_donationviewdialog_sitename", "label": "siteName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L824"}, {"id": "list_donationviewdialog_expressname", "label": "expressName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L828"}, {"id": "list_donationviewdialog_samplereceptionchecklist", "label": "sampleReceptionCheckList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L832"}, {"id": "list_donationviewdialog_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L854"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationviewdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_money_format", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L611", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationviewdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L612", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationviewdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolattachmentreadonly_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L613", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationviewdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_sample_qc_info_cards_index_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L614", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationviewdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_sample_production_info_cards_index_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationViewDialog.vue", "source_location": "L615", Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_pilot_service_checkup_management_checkupmarkcheckeddialog_vue", "label": "CheckupMarkCheckedDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L1"}, {"id": "checkup_management_checkupmarkcheckeddialog_parselist", "label": "parseList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L498"}, {"id": "checkup_management_checkupmarkcheckeddialog_projectstatuslabel", "label": "projectStatusLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L502"}, {"id": "checkup_management_checkupmarkcheckeddialog_projectstatustagtype", "label": "projectStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L506"}, {"id": "checkup_management_checkupmarkcheckeddialog_loadinstitutioncatalog", "label": "loadInstitutionCatalog()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L515"}, {"id": "checkup_management_checkupmarkcheckeddialog_requireinstitution", "label": "requireInstitution()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L534"}, {"id": "checkup_management_checkupmarkcheckeddialog_handleopenprojectselector", "label": "handleOpenProjectSelector()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L552"}, {"id": "checkup_management_checkupmarkcheckeddialog_isprojectalreadyinactual", "label": "isProjectAlreadyInActual()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L562"}, {"id": "checkup_management_checkupmarkcheckeddialog_confirmprojectselect", "label": "confirmProjectSelect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L565"}, {"id": "checkup_management_checkupmarkcheckeddialog_handleopenpackageselector", "label": "handleOpenPackageSelector()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L590"}, {"id": "checkup_management_checkupmarkcheckeddialog_confirmpackageselect", "label": "confirmPackageSelect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L600"}, {"id": "checkup_management_checkupmarkcheckeddialog_handlepackageview", "label": "handlePackageView()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L632"}, {"id": "checkup_management_checkupmarkcheckeddialog_formatnowdatetime", "label": "formatNowDatetime()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L654"}, {"id": "checkup_management_checkupmarkcheckeddialog_fullfileurl", "label": "fullFileUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L661"}, {"id": "checkup_management_checkupmarkcheckeddialog_isimagefile", "label": "isImageFile()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L669"}, {"id": "checkup_management_checkupmarkcheckeddialog_parseattachmenturls", "label": "parseAttachmentUrls()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L678"}, {"id": "checkup_management_checkupmarkcheckeddialog_loaddata", "label": "loadData()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/pilot-service/checkup-management/CheckupMarkCheckedDialog.vue", "source_location": "L690"}, {"id": "checkup_management_checkupmarkcheckLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_audit_protocolaudittab_vue", "label": "ProtocolAuditTab.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol-audit/ProtocolAuditTab.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "label": "ProtocolFormDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1"}, {"id": "protocol_protocolformdialog_fmtmoney", "label": "fmtMoney()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1189"}, {"id": "protocol_protocolformdialog_createemptytransport", "label": "createEmptyTransport()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1251"}, {"id": "protocol_protocolformdialog_fullfileurl", "label": "fullFileUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1271"}, {"id": "protocol_protocolformdialog_loadethnicoptions", "label": "loadEthnicOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1278"}, {"id": "protocol_protocolformdialog_ensureethnicoptioninlist", "label": "ensureEthnicOptionInList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1289"}, {"id": "protocol_protocolformdialog_expressname", "label": "expressName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1317"}, {"id": "protocol_protocolformdialog_for", "label": "for()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1943"}, {"id": "protocol_protocolformdialog_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L2476"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1140", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1141", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_collection_protocol", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1153", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1159", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_download_attachment", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1160", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_admin", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1161", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_ethnic", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1173", "weight": 1.0}, {"source":Line truncated
@@ -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": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationformdialog_vue", "label": "DonationFormDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1"}, {"id": "list_donationformdialog_createemptytransport", "label": "createEmptyTransport()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1012"}, {"id": "list_donationformdialog_fullfileurl", "label": "fullFileUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1032"}, {"id": "list_donationformdialog_loadethnicoptions", "label": "loadEthnicOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1039"}, {"id": "list_donationformdialog_ensureethnicoptioninlist", "label": "ensureEthnicOptionInList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1050"}, {"id": "list_donationformdialog_samplerowlabel", "label": "sampleRowLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1078"}, {"id": "list_donationformdialog_resetform", "label": "resetForm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1160"}, {"id": "list_donationformdialog_scrolltosection", "label": "scrollToSection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1215"}, {"id": "list_donationformdialog_normalizesamplerow", "label": "normalizeSampleRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1223"}, {"id": "list_donationformdialog_openbatchtransportdialog", "label": "openBatchTransportDialog()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1246"}, {"id": "list_donationformdialog_confirmbatchtransportapply", "label": "confirmBatchTransportApply()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1254"}, {"id": "list_donationformdialog_addsample", "label": "addSample()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1268"}, {"id": "list_donationformdialog_removesample", "label": "removeSample()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1282"}, {"id": "list_donationformdialog_handleopenforadd", "label": "handleOpenForAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1286"}, {"id": "list_donationformdialog_applydonationbundletoform", "label": "applyDonationBundleToForm()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1334"}, {"id": "list_donationformdialog_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L1951"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationformdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L922", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationformdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/research-donation/list/DonationFormDialog.vue", "source_location": "L923", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_research_donation_list_donationformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_research_donation", "relation": "imports_from", "confidLine truncated
+11
View File
@@ -45,6 +45,17 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
menuCode: 'biz:cellStorageProtocolAudit:list'
}
},
{
id: '50000000000000000000000000000013',
name: 'CellStorageSampleInfo',
path: 'sample-info',
component: '/cell-storage/sample-info/index',
meta: {
title: '样本信息管理',
keepAlive: true,
menuCode: 'cell-storage:sample-info:list'
}
},
{
id: '904b5173519411f1944300163e3bdd96',
name: 'CellStoragePaymentInfo',
@@ -13,6 +13,34 @@ export function addMonthsYmd(dateStr: string, months: number): string {
return `${yy}${mm}${dd}`
}
/** 日期加 N 天,返回 YYYYMMDD(入参支持 YYYYMMDD 或 YYYY-MM-DD) */
export function addDaysYmd(dateStr: string, days: number): string {
const compact = String(dateStr || '').replace(/-/g, '')
if (compact.length !== 8) return ''
const y = parseInt(compact.slice(0, 4), 10)
const m = parseInt(compact.slice(4, 6), 10) - 1
const d = parseInt(compact.slice(6, 8), 10)
const date = new Date(y, m, d)
date.setDate(date.getDate() + days)
const yy = date.getFullYear()
const mm = String(date.getMonth() + 1).padStart(2, '0')
const dd = String(date.getDate()).padStart(2, '0')
return `${yy}${mm}${dd}`
}
/** 分期应缴费时间:第 1 期=开始时间,第 2 期起在按月递增基础上提前 10 天 */
export function calcFqInstallmentDueDate(
startDate: string,
index: number,
intervalMonths: number
): string {
const base = addMonthsYmd(startDate, index * intervalMonths)
if (index >= 1) {
return addDaysYmd(base, -10)
}
return base
}
export function calcInstallmentDueAmounts(
contractAmount: number | null | undefined,
count: number
@@ -87,14 +115,15 @@ export function alignFqPaymentDetailsForDisplay(
if (i < unnumbered.length) {
const raw = { ...unnumbered[i], installmentNo: no }
if (!raw.installmentDueDate && startDate && interval) {
raw.installmentDueDate = addMonthsYmd(startDate, i * interval)
raw.installmentDueDate = calcFqInstallmentDueDate(startDate, i, interval)
}
result.push(raw)
continue
}
result.push({
installmentNo: no,
installmentDueDate: startDate && interval ? addMonthsYmd(startDate, i * interval) : '',
installmentDueDate:
startDate && interval ? calcFqInstallmentDueDate(startDate, i, interval) : '',
dueAmount: amounts[i] ?? null,
payStatus: 'dfj',
transferType: '',
@@ -155,6 +155,21 @@
>
</template>
</el-table-column>
<el-table-column
prop="expectedDeliveryDate"
label="预产期"
min-width="120"
align="center"
header-align="center"
/>
<el-table-column
prop="sampleCollectSummary"
label="是否已采集"
min-width="160"
align="center"
header-align="center"
show-overflow-tooltip
/>
<el-table-column
prop="registerDate"
label="登记日期"
@@ -219,6 +234,22 @@
align="center"
header-align="center"
/>
<el-table-column
prop="sampleTypeNames"
label="样本类型"
min-width="140"
align="center"
header-align="center"
show-overflow-tooltip
/>
<el-table-column
prop="sampleCodes"
label="样本编码"
min-width="160"
align="center"
header-align="center"
show-overflow-tooltip
/>
<el-table-column
prop="regionName"
label="采集地区"
@@ -0,0 +1,364 @@
<!-- 样本信息管理 · 样本质检信息 Tab -->
<template>
<div class="sample-qc-info-tab">
<div class="filter-block">
<el-form :model="searchForm" class="filter-form" @submit.prevent>
<div class="filter-grid">
<el-form-item label="关键词">
<el-input v-model="searchForm.keyword" placeholder="协议号/姓名/样本编码" clearable />
</el-form-item>
<el-form-item label="质检状态">
<el-select
v-model="searchForm.qcStatus"
placeholder="全部"
clearable
style="width: 100%"
>
<el-option label="待质检" value="dzj" />
<el-option label="质检中" value="zjz" />
<el-option label="通过" value="tg" />
<el-option label="不通过" value="btg" />
<el-option label="已作废" value="yzf" />
</el-select>
</el-form-item>
<el-form-item label="通知状态">
<el-select
v-model="searchForm.smsNotified"
placeholder="全部"
clearable
style="width: 100%"
>
<el-option label="已通知" value="1" />
<el-option label="未通知" value="0" />
</el-select>
</el-form-item>
<el-form-item label="样本时间">
<el-date-picker
v-model="sampleTimeRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
</div>
<div class="filter-actions-row">
<span class="filter-hint"
>展示全部协议样本(每个样本一条);支持按协议号、姓名、样本编码检索;默认展示近 30 天内创建的样本。</span
>
<div class="filter-actions-end">
<el-button class="btn-ghost" @click="handleReset">
<el-icon><RefreshLeft /></el-icon>重置
</el-button>
<el-button class="btn-main" type="primary" @click="handleSearch">
<el-icon><Search /></el-icon>搜索
</el-button>
</div>
</div>
</el-form>
</div>
<div class="list-body list-wrap">
<el-table
class="list-table"
:data="tableData"
v-loading="loading"
stripe
row-key="id"
@row-dblclick="handleView"
>
<el-table-column
type="index"
label="序号"
min-width="68"
align="center"
header-align="center"
:index="(i) => (pagination.page - 1) * pagination.pageSize + i + 1"
/>
<el-table-column
prop="protocolNo"
label="协议号"
min-width="140"
align="center"
header-align="center"
/>
<el-table-column
prop="protocolStatus"
label="协议状态"
min-width="100"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-tag
:type="protocolStatusTagType(String(row.protocolStatus || ''))"
size="small"
>{{ protocolStatusLabel(String(row.protocolStatus || '')) }}</el-tag
>
</template>
</el-table-column>
<el-table-column
prop="motherName"
label="母亲姓名"
min-width="100"
align="center"
header-align="center"
/>
<el-table-column
prop="newbornName"
label="新生儿姓名"
min-width="110"
align="center"
header-align="center"
show-overflow-tooltip
/>
<el-table-column
prop="sampleCode"
label="样本编码"
min-width="130"
align="center"
header-align="center"
/>
<el-table-column
prop="sampleTypeName"
label="样本类型"
min-width="110"
align="center"
header-align="center"
/>
<el-table-column
prop="qcCompleteTime"
label="质检完成时间"
min-width="170"
align="center"
header-align="center"
/>
<el-table-column
prop="qcStatusLabel"
label="质检状态"
min-width="100"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-tag :type="qcStatusTagType(String(row.qcStatus || ''))" size="small">
{{ row.qcStatusLabel || '待质检' }}
</el-tag>
</template>
</el-table-column>
<el-table-column
prop="smsNotified"
label="通知状态"
min-width="100"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-tag :type="row.smsNotified == 1 ? 'success' : 'info'" size="small">
{{ row.smsNotified == 1 ? '已通知' : '未通知' }}
</el-tag>
</template>
</el-table-column>
<el-table-column
label="操作"
min-width="360"
fixed="right"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-button class="btn-op-item primary" @click="handleView(row)">
<el-icon><View /></el-icon>查看
</el-button>
<el-button class="btn-op-item" @click="handleExtractSms(row)">
<el-icon><ChatDotRound /></el-icon>提取短信
</el-button>
<el-button class="btn-op-item" @click="handleToggleNotified(row)">
<el-icon><Bell /></el-icon>{{ row.smsNotified == 1 ? '标记未通知' : '标记已通知' }}
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination list-pager-bar">
<el-pagination
:current-page="pagination.page"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next"
@size-change="(val) => ((pagination.page = 1), (pagination.pageSize = val), loadData())"
@current-change="(val) => ((pagination.page = val), loadData())"
/>
</div>
</div>
<ProtocolViewDialog
v-model="viewVisible"
:protocol-id="viewProtocolId"
:list-row="viewRow"
show-audit-history
show-storage-cert
show-fullmoon-insurance
/>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { Search, RefreshLeft, View, ChatDotRound, Bell } from '@element-plus/icons-vue'
import { useClipboard } from '@vueuse/core'
import ProtocolViewDialog from '../protocol/ProtocolViewDialog.vue'
import {
fetchQcSmsList,
fetchToggleQcSmsNotified,
fetchGenerateQcSms
} from '@/api/qc-sms-notification'
import { type CollectionProtocolRow } from '@/api/collection-protocol'
import {
protocolStatusLabel,
protocolStatusTagType
} from '@/utils/status-tag-registry'
defineOptions({ name: 'CellStorageSampleQcInfoTab' })
function qcStatusTagType(status: string) {
const map: Record<string, 'success' | 'warning' | 'danger' | 'info'> = {
dzj: 'info',
zjz: 'warning',
tg: 'success',
btg: 'danger',
yzf: 'danger'
}
return map[status] || 'info'
}
function isQcCompleted(row: Record<string, unknown>) {
return row.qcStatus === 'tg' || row.qcStatus === 'btg'
}
function formatLocalDate(d: Date): string {
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${y}-${m}-${day}`
}
function getDefaultSampleTimeRange(): [string, string] {
const end = new Date()
const start = new Date()
start.setDate(start.getDate() - 30)
return [formatLocalDate(start), formatLocalDate(end)]
}
const searchForm = reactive({ keyword: '', qcStatus: '', smsNotified: '' })
const sampleTimeRange = ref<[string, string] | null>(getDefaultSampleTimeRange())
const tableData = ref<any[]>([])
const loading = ref(false)
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
const viewVisible = ref(false)
const viewProtocolId = ref<string | null>(null)
const viewRow = ref<CollectionProtocolRow | null>(null)
const { copy } = useClipboard()
async function loadData() {
loading.value = true
try {
const result = await fetchQcSmsList({
page: pagination.page,
pageSize: pagination.pageSize,
keyword: searchForm.keyword || undefined,
qcStatus: searchForm.qcStatus || undefined,
smsNotified: searchForm.smsNotified || undefined,
qcCompleteTimeStart: sampleTimeRange.value?.[0] || undefined,
qcCompleteTimeEnd: sampleTimeRange.value?.[1] || undefined
})
const res = (result as any) || {}
tableData.value = res.list || []
pagination.total = res.total || 0
} finally {
loading.value = false
}
}
function handleSearch() {
pagination.page = 1
loadData()
}
function handleReset() {
Object.assign(searchForm, { keyword: '', qcStatus: '', smsNotified: '' })
sampleTimeRange.value = getDefaultSampleTimeRange()
handleSearch()
}
function handleView(row: Record<string, unknown>) {
const pid = String(row.collectionProtocolId || row.protocolId || '')
if (!pid) {
ElMessage.warning('缺少关联协议单,无法查看')
return
}
viewProtocolId.value = pid
viewRow.value = {
id: pid,
protocolNo: row.protocolNo,
motherName: row.motherName,
newbornName: row.newbornName
}
viewVisible.value = true
}
async function handleExtractSms(row: any) {
try {
const result = await fetchGenerateQcSms(row.id, {
qcWorkOrderId: row.qcWorkOrderId,
protocolSampleId: row.protocolSampleId
})
const content = (result as any)?.smsContent || ''
if (!content || content.startsWith('暂无短信内容')) {
ElMessage.warning(content || '短信内容为空')
return
}
await copy(content)
ElMessage.success('短信内容已复制到剪贴板')
} catch {
ElMessage.error('提取短信失败')
}
}
async function handleToggleNotified(row: any) {
if (!isQcCompleted(row)) {
ElMessage.warning('质检尚未完成,暂不可标记通知状态')
return
}
const newVal = row.smsNotified == 1 ? 0 : 1
try {
await fetchToggleQcSmsNotified(row.id, {
smsNotified: newVal,
qcWorkOrderId: row.qcWorkOrderId,
protocolSampleId: row.protocolSampleId
})
ElMessage.success(newVal === 1 ? '已标记为已通知' : '已标记为未通知')
loadData()
} catch {
ElMessage.error('操作失败')
}
}
watchDebounced(
[searchForm, sampleTimeRange],
() => {
pagination.page = 1
loadData()
},
{ debounce: 300, deep: true }
)
onMounted(() => {
loadData()
})
</script>
@@ -1,4 +1,4 @@
<!-- 采集协议单管理 · 样本接收信息 Tab -->
<!-- 样本信息管理 · 样本接收信息 Tab -->
<template>
<div class="sample-reception-info-tab">
<div class="filter-block">
@@ -1,4 +1,4 @@
<!-- 采集协议单管理 · 样本入库信息 Tab -->
<!-- 样本信息管理 · 样本入库信息 Tab -->
<template>
<div class="storage-entry-info-tab">
<div class="filter-block">
@@ -1,4 +1,4 @@
<!-- 采集协议单管理(协议单 / 缴费 / 样本接收 / 入库 / 储存证 / 满月待办) -->
<!-- 采集协议单管理(协议单 / 缴费 / 储存证 / 满月待办) -->
<template>
<div class="page-container">
<section class="panel">
@@ -29,8 +29,6 @@
<ProtocolAuditTab v-if="activeTab === 'protocol'" />
<PaymentInfoTab v-else-if="activeTab === 'payment-info'" />
<SampleReceptionInfoTab v-else-if="activeTab === 'sample-reception'" />
<StorageEntryInfoTab v-else-if="activeTab === 'storage-entry'" />
<StorageCertTab v-else-if="activeTab === 'storage-cert'" />
<FullmoonTodoTab v-else-if="activeTab === 'fullmoon-todo'" />
</section>
@@ -39,24 +37,17 @@
<script setup lang="ts">
import type { Component } from 'vue'
import { Document, Wallet, Box, FolderOpened, Medal, Calendar } from '@element-plus/icons-vue'
import { Document, Wallet, Medal, Calendar } from '@element-plus/icons-vue'
import ProtocolAuditTab from './ProtocolAuditTab.vue'
import PaymentInfoTab from './PaymentInfoTab.vue'
import SampleReceptionInfoTab from './SampleReceptionInfoTab.vue'
import StorageEntryInfoTab from './StorageEntryInfoTab.vue'
import StorageCertTab from './StorageCertTab.vue'
import FullmoonTodoTab from './FullmoonTodoTab.vue'
defineOptions({ name: 'CellStorageProtocolAudit' })
const VALID_TABS = [
'protocol',
'payment-info',
'sample-reception',
'storage-entry',
'storage-cert',
'fullmoon-todo'
] as const
const LEGACY_SAMPLE_TABS = ['sample-reception', 'storage-entry'] as const
const VALID_TABS = ['protocol', 'payment-info', 'storage-cert', 'fullmoon-todo'] as const
type EntityTabKey = (typeof VALID_TABS)[number]
@@ -78,18 +69,6 @@
desc: '缴费计划与到账查询',
icon: Wallet
},
{
key: 'sample-reception',
title: '样本接收信息',
desc: '接收结论与短信通知',
icon: Box
},
{
key: 'storage-entry',
title: '样本入库信息',
desc: '样本入库记录查询',
icon: FolderOpened
},
{
key: 'storage-cert',
title: '储存证管理',
@@ -105,10 +84,18 @@
]
const route = useRoute()
const router = useRouter()
const activeTab = ref<EntityTabKey>('protocol')
onMounted(() => {
const tab = String(route.query.tab || '')
if (LEGACY_SAMPLE_TABS.includes(tab as (typeof LEGACY_SAMPLE_TABS)[number])) {
router.replace({
name: 'CellStorageSampleInfo',
query: { ...route.query, tab }
})
return
}
if (VALID_TABS.includes(tab as EntityTabKey)) {
activeTab.value = tab as EntityTabKey
}
@@ -285,7 +285,17 @@
<el-radio label="0">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="新生儿分娩时间" class="form-col-span-2">
<el-form-item label="预产期">
<el-date-picker
v-model="formData.expectedDeliveryDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择预产期"
clearable
style="width: 100%"
/>
</el-form-item>
<el-form-item label="新生儿分娩时间">
<el-date-picker
v-model="formData.newbornDeliveryTime"
type="datetime"
@@ -469,11 +479,11 @@
:disabled="!selectedSamples.length"
@click="openBatchTransportDialog"
>
应用到选中样本
批量配置运输信息
</el-button>
</div>
<p v-if="formData.samples.length" class="sample-transport-hint"
>勾选样本后,点击「应用到选中样本」可批量填写运输信息。点击展开可编辑单个运输信息。</p
>勾选样本后,点击「批量配置运输信息」可统一填写运输信息。点击展开可编辑单个运输信息。</p
>
<!-- Sample Cards -->
@@ -1162,7 +1172,10 @@
} from '@/api/admin'
import { fetchEthnicList, type EthnicOption } from '@/api/ethnic'
import { useUserStore } from '@/store/modules/user'
import { syncFqPaymentDetailRowCount } from '@/utils/protocol-payment-installment'
import {
calcFqInstallmentDueDate,
syncFqPaymentDetailRowCount
} from '@/utils/protocol-payment-installment'
import AmountInput from '@/components/common/amount-input/index.vue'
import { formatMoneyDisplay } from '@/utils/money-format'
import {
@@ -1434,6 +1447,7 @@
fatherIdCard: '',
newbornName: '',
newbornIdCard: '',
expectedDeliveryDate: '',
newbornDeliveryTime: '',
newbornSex: '',
deliveryMode: '',
@@ -1487,6 +1501,7 @@
fatherIdCard: '',
newbornName: '',
newbornIdCard: '',
expectedDeliveryDate: '',
newbornDeliveryTime: '',
newbornSex: '',
deliveryMode: '',
@@ -1634,17 +1649,46 @@
syncPaymentDueAmounts()
}
/** 日期加 N 个月,返回 YYYYMMDD 格式(入参支持 YYYYMMDD 或 YYYY-MM-DD) */
function addMonths(dateStr: string, months: number): string {
const compact = dateStr.replace(/-/g, '')
const y = parseInt(compact.slice(0, 4), 10)
const m = parseInt(compact.slice(4, 6), 10) - 1
const d = parseInt(compact.slice(6, 8), 10)
const date = new Date(y, m + months, d)
const yy = date.getFullYear()
const mm = String(date.getMonth() + 1).padStart(2, '0')
const dd = String(date.getDate()).padStart(2, '0')
return `${yy}${mm}${dd}`
/** 分期开始时间默认值:新生儿分娩时间 > 预产期 > 当前日期(YYYYMMDD) */
function defaultInstallmentStartDateYmd(): string {
const deliveryYmd = datetimeToYmd(formData.newbornDeliveryTime)
if (deliveryYmd) return deliveryYmd
const expectedYmd = datetimeToYmd(formData.expectedDeliveryDate)
if (expectedYmd) return expectedYmd
const now = new Date()
const pad = (n: number) => String(n).padStart(2, '0')
return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}`
}
function datetimeToYmd(val: string): string {
const compact = String(val || '')
.trim()
.replace(/[-:\sT]/g, '')
.slice(0, 8)
return /^\d{8}$/.test(compact) ? compact : ''
}
function isFqNumericFieldEmpty(val: unknown): boolean {
if (val == null || val === '') return true
const n = Number(val)
return !Number.isFinite(n) || n < 1
}
/**
* 分期默认:期数、每期间隔均为 6;开始时间为空时按分娩/预产期/今日填充。
* resetCountInterval:切换到分期时强制重置期数与间隔(与新增一致)。
*/
function applyFqPaymentDefaults(options?: { resetCountInterval?: boolean }) {
const reset = options?.resetCountInterval ?? false
if (reset || isFqNumericFieldEmpty(formData.installmentCount)) {
formData.installmentCount = 6
}
if (reset || isFqNumericFieldEmpty(formData.installmentIntervalMonths)) {
formData.installmentIntervalMonths = 6
}
if (!formData.installmentStartDate) {
formData.installmentStartDate = defaultInstallmentStartDateYmd()
}
}
function toIntOrUndefined(val: unknown): number | undefined {
@@ -1676,7 +1720,7 @@
syncPaymentDueAmounts()
formData.paymentDetails.forEach((d, i) => {
d.installmentNo = i + 1
d.installmentDueDate = addMonths(startDate, i * interval)
d.installmentDueDate = calcFqInstallmentDueDate(startDate, i, interval)
})
return
}
@@ -1691,7 +1735,7 @@
transferTime: '',
payStatus: 'dfj',
installmentNo: i + 1,
installmentDueDate: addMonths(startDate, i * interval),
installmentDueDate: calcFqInstallmentDueDate(startDate, i, interval),
attachments: [] as Array<{
id?: string
fileName: string
@@ -1710,6 +1754,7 @@
/** 缴费模式切换回调 */
function onPayModeChange(val: string) {
if (val === 'fq') {
applyFqPaymentDefaults({ resetCountInterval: true })
tryGenerateInstallmentDetails()
} else {
// 趸交模式:将趸交截止时间同步到所有明细的应缴费时间
@@ -1798,6 +1843,7 @@
formData.fatherIdCard = String(pc.fatherIdCard || '')
formData.newbornName = String(pc.newbornName || '')
formData.newbornIdCard = String(pc.newbornIdCard || '')
formData.expectedDeliveryDate = String(pc.expectedDeliveryDate || '')
formData.newbornDeliveryTime = String(pc.newbornDeliveryTime || '')
formData.newbornSex = String(pc.newbornSex ?? '')
formData.deliveryMode = String(pc.deliveryMode || '')
@@ -1831,6 +1877,9 @@
formData.installmentCount = pay.installmentCount ?? null
formData.installmentIntervalMonths = pay.installmentIntervalMonths ?? null
formData.installmentStartDate = String(pay.installmentStartDate || '')
if (formData.payMode === 'fq') {
applyFqPaymentDefaults()
}
}
const pd = bundle.paymentDetails as Array<Record<string, any>> | null
@@ -1971,6 +2020,7 @@
fatherIdCard: formData.fatherIdCard || undefined,
newbornName: formData.newbornName || undefined,
newbornIdCard: formData.newbornIdCard || undefined,
expectedDeliveryDate: formData.expectedDeliveryDate || undefined,
newbornDeliveryTime: formData.newbornDeliveryTime || undefined,
newbornSex: formData.newbornSex || undefined,
deliveryMode: formData.deliveryMode || undefined,
@@ -2531,8 +2581,8 @@
sc: Api.BizSampleCode.SampleCodeItem,
row: Record<string, any>
) {
if (!sc.usedInProtocol) return false
return String(row.sampleCodeId || '') !== sc.id
if (sc.usedInProtocol && String(row.sampleCodeId || '') !== sc.id) return true
return formData.samples.some((s) => s !== row && String(s.sampleCodeId || '') === sc.id)
}
function onSampleCodeChange(row: Record<string, any>) {
@@ -352,6 +352,12 @@
><div class="data-label">新生儿身份证</div
><div class="data-value">{{ dash(partyCustomer?.newbornIdCard) }}</div></div
>
<div class="data-item"
><div class="data-label">预产期</div
><div class="data-value">{{
dash(partyCustomer?.expectedDeliveryDate)
}}</div></div
>
<div class="data-item"
><div class="data-label">新生儿分娩时间</div
><div class="data-value">{{
@@ -0,0 +1,188 @@
<!-- 样本信息管理(样本接收 / 样本质检 / 样本入库) -->
<template>
<div class="page-container">
<section class="panel">
<div
class="panel-entity-switch panel-entity-switch--triple"
role="tablist"
aria-label="视图类型"
>
<button
v-for="item in entityTabs"
:key="item.key"
type="button"
class="entity-switch-card"
:class="{ 'is-active': activeTab === item.key }"
role="tab"
:aria-selected="activeTab === item.key"
@click="activeTab = item.key"
>
<span class="entity-switch-card__icon"
><el-icon><component :is="item.icon" /></el-icon
></span>
<span class="entity-switch-card__main">
<span class="entity-switch-card__title">{{ item.title }}</span>
<span class="entity-switch-card__desc">{{ item.desc }}</span>
</span>
</button>
</div>
<SampleReceptionInfoTab v-if="activeTab === 'sample-reception'" />
<SampleQcInfoTab v-else-if="activeTab === 'sample-qc'" />
<StorageEntryInfoTab v-else-if="activeTab === 'storage-entry'" />
</section>
</div>
</template>
<script setup lang="ts">
import type { Component } from 'vue'
import { Box, DocumentChecked, FolderOpened } from '@element-plus/icons-vue'
import SampleReceptionInfoTab from '../protocol-audit/SampleReceptionInfoTab.vue'
import SampleQcInfoTab from '../protocol-audit/SampleQcInfoTab.vue'
import StorageEntryInfoTab from '../protocol-audit/StorageEntryInfoTab.vue'
defineOptions({ name: 'CellStorageSampleInfo' })
const VALID_TABS = ['sample-reception', 'sample-qc', 'storage-entry'] as const
type EntityTabKey = (typeof VALID_TABS)[number]
const entityTabs: Array<{
key: EntityTabKey
title: string
desc: string
icon: Component
}> = [
{
key: 'sample-reception',
title: '样本接收信息',
desc: '接收结论与短信通知',
icon: Box
},
{
key: 'sample-qc',
title: '样本质检信息',
desc: '质检结论与短信通知',
icon: DocumentChecked
},
{
key: 'storage-entry',
title: '样本入库信息',
desc: '样本入库记录查询',
icon: FolderOpened
}
]
const route = useRoute()
const activeTab = ref<EntityTabKey>('sample-reception')
onMounted(() => {
const tab = String(route.query.tab || '')
if (VALID_TABS.includes(tab as EntityTabKey)) {
activeTab.value = tab as EntityTabKey
}
})
</script>
<style scoped lang="scss">
.panel-entity-switch {
display: flex;
justify-content: center;
gap: 12px;
padding: 16px 16px 12px;
}
.panel-entity-switch--triple {
flex-wrap: wrap;
.entity-switch-card {
flex: 0 1 200px;
min-width: 180px;
max-width: 240px;
padding: 12px 14px;
}
.entity-switch-card__icon {
width: 36px;
height: 36px;
font-size: 18px;
}
.entity-switch-card__title {
font-size: 13px;
}
.entity-switch-card__desc {
font-size: 11px;
}
}
.entity-switch-card {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 18px;
border: 1px solid var(--mint-border, #d9e8e2);
border-radius: 10px;
background: var(--surface, #fff);
cursor: pointer;
text-align: left;
transition:
border-color 0.2s ease,
background-color 0.2s ease,
box-shadow 0.2s ease;
&:hover:not(.is-active) {
border-color: #a7f3d0;
background: #f8fafc;
}
&.is-active {
border-color: var(--primary, #10b981);
background: var(--primary-bg, #ecfdf5);
box-shadow: 0 0 0 1px rgb(16 185 129 / 12%);
}
}
.entity-switch-card__icon {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
flex-shrink: 0;
border-radius: 8px;
background: #f1f5f9;
color: #64748b;
font-size: 20px;
.entity-switch-card.is-active & {
background: #fff;
color: var(--primary-dark, #059669);
}
}
.entity-switch-card__main {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
.entity-switch-card__title {
font-size: 14px;
font-weight: 600;
color: var(--text, #1e293b);
line-height: 1.4;
.entity-switch-card.is-active & {
color: var(--primary-dark, #059669);
}
}
.entity-switch-card__desc {
font-size: 12px;
color: var(--mint-text-muted, #64748b);
line-height: 1.4;
}
</style>
@@ -1,4 +1,4 @@
<!-- 旧「样本接收信息」菜单入口:重定向至采集协议单管理 · 样本接收 Tab -->
<!-- 旧「样本接收信息」菜单入口:重定向至样本信息管理 · 样本接收 Tab -->
<template>
<div />
</template>
@@ -11,7 +11,7 @@
onMounted(() => {
router.replace({
name: 'CellStorageProtocolAudit',
name: 'CellStorageSampleInfo',
query: { ...route.query, tab: 'sample-reception' }
})
})
@@ -1,4 +1,4 @@
<!-- 旧「样本入库信息」菜单入口:重定向至采集协议单管理 · 样本入库 Tab -->
<!-- 旧「样本入库信息」菜单入口:重定向至样本信息管理 · 样本入库 Tab -->
<template>
<div />
</template>
@@ -11,7 +11,7 @@
onMounted(() => {
router.replace({
name: 'CellStorageProtocolAudit',
name: 'CellStorageSampleInfo',
query: { ...route.query, tab: 'storage-entry' }
})
})
@@ -2,7 +2,7 @@
<template>
<el-dialog
:model-value="modelValue"
:title="(isEditMode ? '编辑体检信息' : '填写体检信息') + ' — ' + patientName"
:title="(isEditMode ? '编辑预约信息' : '填写体检信息') + ' — ' + patientName"
width="1080px"
class="dialog-form-layout checkup-fill-dialog"
align-center
@@ -2,7 +2,7 @@
<template>
<el-dialog
:model-value="modelValue"
:title="'标记已体检 — ' + (patientName || '')"
:title="(editMode ? '编辑体检信息' : '标记已体检') + ' — ' + (patientName || '')"
width="1080px"
class="dialog-form-layout checkup-mark-checked-dialog"
align-center
@@ -158,7 +158,11 @@
<el-icon><Close /></el-icon>取消
</el-button>
<el-button class="btn-main" type="primary" :loading="submitLoading" @click="handleSubmit">
<el-icon><CircleCheck /></el-icon>确认标记已体检
<el-icon>
<Check v-if="editMode" />
<CircleCheck v-else />
</el-icon>
{{ editMode ? '确定' : '确认标记已体检' }}
</el-button>
</template>
</el-dialog>
@@ -480,6 +484,8 @@
modelValue: boolean
checkupId: string
patientName?: string
/** 编辑模式:仅保存体检登记信息,不变更体检状态 */
editMode?: boolean
}>()
const emit = defineEmits(['update:modelValue', 'success'])
@@ -530,7 +536,7 @@
const requireInstitution = () => {
if (!checkupInstitutionId.value) {
ElMessage.warning('该记录未关联体检机构,请先在「编辑体检信息」中选择机构')
ElMessage.warning('该记录未关联体检机构,请先在「编辑预约信息」中选择机构')
return false
}
return true
@@ -814,8 +820,10 @@
checkupRemark: checkupRemark.value || undefined,
actualCheckupFee: actualTotal.value || undefined
})
await markPilotCheckupChecked({ id: props.checkupId })
ElMessage.success('已标记为已体检')
if (!props.editMode) {
await markPilotCheckupChecked({ id: props.checkupId })
}
ElMessage.success(props.editMode ? '保存成功' : '已标记为已体检')
emit('update:modelValue', false)
emit('success')
} catch (e: any) {
@@ -221,8 +221,11 @@
<el-dropdown-item v-if="hasPrimaryCheckupActions(row)" command="view">
<el-icon><View /></el-icon>查看
</el-dropdown-item>
<el-dropdown-item v-if="canEditCheckup(row)" command="edit">
<el-icon><EditPen /></el-icon>编辑
<el-dropdown-item v-if="canEditReserve(row)" command="editReserve">
<el-icon><EditPen /></el-icon>编辑预约信息
</el-dropdown-item>
<el-dropdown-item v-if="canEditActualCheckupInfo(row)" command="editActual">
<el-icon><Edit /></el-icon>编辑体检信息
</el-dropdown-item>
</el-dropdown-menu>
</template>
@@ -251,7 +254,7 @@
@success="onBatchReserveSuccess"
/>
<!-- 填写 / 编辑体检信息弹窗 -->
<!-- 填写 / 编辑预约信息弹窗 -->
<CheckupFillDialog
v-model="fillDialogVisible"
:checkup-id="currentCheckupId"
@@ -263,11 +266,12 @@
<!-- 查看弹窗 -->
<CheckupViewDialog v-model="viewDialogVisible" :checkup-row="viewCheckupRow" />
<!-- 标记已体检弹窗 -->
<!-- 标记已体检 / 编辑体检登记信息弹窗 -->
<CheckupMarkCheckedDialog
v-model="markCheckedVisible"
:checkup-id="currentCheckupId"
:patient-name="currentPatientName"
:edit-mode="markCheckedEditMode"
@success="loadData"
/>
</div>
@@ -330,6 +334,7 @@
const viewDialogVisible = ref(false)
const viewCheckupRow = ref<any>(null)
const markCheckedVisible = ref(false)
const markCheckedEditMode = ref(false)
const currentCheckupId = ref('')
const currentPatientName = ref('')
@@ -387,8 +392,11 @@
/** 待体检且已填写机构信息时可标记已体检 */
const canMarkChecked = (row: any) => row.checkupStatus === 'dtj' && !!row.institutionName
/** 已填写机构信息时可编辑 */
const canEditCheckup = (row: any) => !!row.institutionName
/** 已填写机构信息时可编辑预约 */
const canEditReserve = (row: any) => !!row.institutionName
/** 已体检时可编辑体检登记信息 */
const canEditActualCheckupInfo = (row: any) => row.checkupStatus === 'ytj'
/** 是否存在填写体检信息 / 标记已体检主操作 */
const hasPrimaryCheckupActions = (row: any) =>
@@ -397,9 +405,9 @@
/** 更多菜单是否展示 */
const hasMoreCheckupActions = (row: any) => {
if (hasPrimaryCheckupActions(row)) {
return canEditCheckup(row) || canMarkChecked(row)
return canEditReserve(row) || canMarkChecked(row)
}
return canEditCheckup(row)
return canEditReserve(row) || canEditActualCheckupInfo(row)
}
const handleDropdownCommand = (command: string, row: any) => {
@@ -407,8 +415,11 @@
case 'view':
handleView(row)
break
case 'edit':
handleEdit(row)
case 'editReserve':
handleEditReserve(row)
break
case 'editActual':
handleEditActual(row)
break
}
}
@@ -420,13 +431,20 @@
fillDialogVisible.value = true
}
const handleEdit = (row: any) => {
const handleEditReserve = (row: any) => {
currentCheckupId.value = row.id
currentPatientName.value = row.patientName || ''
fillEditRow.value = { ...row }
fillDialogVisible.value = true
}
const handleEditActual = (row: any) => {
currentCheckupId.value = row.id
currentPatientName.value = row.patientName || ''
markCheckedEditMode.value = true
markCheckedVisible.value = true
}
const onFillSuccess = () => {
fillEditRow.value = null
loadData()
@@ -461,6 +479,7 @@
const handleMarkChecked = (row: any) => {
currentCheckupId.value = row.id
currentPatientName.value = row.patientName || ''
markCheckedEditMode.value = false
markCheckedVisible.value = true
}
@@ -24,8 +24,7 @@
</el-button>
<el-button
v-if="editor.selectedStep.value.stepStatus === 'jxz'"
class="btn-op-item"
size="small"
class="btn-main task-exec-toolbar-btn"
type="success"
:loading="editor.stepActionLoading.value"
:disabled="editor.manualSaveLoading.value"
@@ -331,7 +331,7 @@
:is-completed-edit="completeConclusionIsEdit"
:initial-conclusion="completeConclusionInitial.conclusion"
:initial-remark="completeConclusionInitial.remark"
@submit="submitCompleteWithConclusion"
@submit="handleCompleteSubmit"
/>
</div>
</template>
@@ -386,10 +386,16 @@
)
function handleClose() {
dialogVisible.value = false
emit('success')
}
async function handleCompleteSubmit(payload: { conclusion: string; remark?: string }) {
await submitCompleteWithConclusion(payload)
if (taskDetail.value?.taskStatus === 'ywc') {
dialogVisible.value = false
}
}
function stepSeqClass(status: string) {
if (status === 'ywc') return 'seq-done'
if (status === 'jxz') return 'seq-running'
@@ -156,6 +156,21 @@
>
</template>
</el-table-column>
<el-table-column
prop="expectedDeliveryDate"
label="预产期"
min-width="120"
align="center"
header-align="center"
/>
<el-table-column
prop="sampleCollectSummary"
label="是否已采集"
min-width="160"
align="center"
header-align="center"
show-overflow-tooltip
/>
<el-table-column
prop="donationDate"
label="捐赠日期"
@@ -220,6 +235,22 @@
align="center"
header-align="center"
/>
<el-table-column
prop="sampleTypeNames"
label="样本类型"
min-width="140"
align="center"
header-align="center"
show-overflow-tooltip
/>
<el-table-column
prop="sampleCodes"
label="样本编码"
min-width="160"
align="center"
header-align="center"
show-overflow-tooltip
/>
<el-table-column
prop="regionName"
label="采集地区"
@@ -212,7 +212,17 @@
<el-radio label="0">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="新生儿分娩时间" class="form-col-span-2">
<el-form-item label="预产期">
<el-date-picker
v-model="formData.expectedDeliveryDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择预产期"
clearable
style="width: 100%"
/>
</el-form-item>
<el-form-item label="新生儿分娩时间">
<el-date-picker
v-model="formData.newbornDeliveryTime"
type="datetime"
@@ -396,11 +406,11 @@
:disabled="!selectedSamples.length"
@click="openBatchTransportDialog"
>
应用到选中样本
批量配置运输信息
</el-button>
</div>
<p v-if="formData.samples.length" class="sample-transport-hint"
>勾选样本后,点击「应用到选中样本」可批量填写运输信息。点击展开可编辑单个运输信息。</p
>勾选样本后,点击「批量配置运输信息」可统一填写运输信息。点击展开可编辑单个运输信息。</p
>
<!-- Sample Cards -->
@@ -1121,6 +1131,7 @@
fatherIdCard: '',
newbornName: '',
newbornIdCard: '',
expectedDeliveryDate: '',
newbornDeliveryTime: '',
newbornSex: '',
deliveryMode: '',
@@ -1166,6 +1177,7 @@
fatherIdCard: '',
newbornName: '',
newbornIdCard: '',
expectedDeliveryDate: '',
newbornDeliveryTime: '',
newbornSex: '',
deliveryMode: '',
@@ -1343,6 +1355,7 @@
formData.fatherIdCard = String(pc.fatherIdCard || '')
formData.newbornName = String(pc.newbornName || '')
formData.newbornIdCard = String(pc.newbornIdCard || '')
formData.expectedDeliveryDate = String(pc.expectedDeliveryDate || '')
formData.newbornDeliveryTime = String(pc.newbornDeliveryTime || '')
formData.newbornSex = String(pc.newbornSex ?? '')
formData.deliveryMode = String(pc.deliveryMode || '')
@@ -1496,6 +1509,7 @@
fatherIdCard: formData.fatherIdCard || undefined,
newbornName: formData.newbornName || undefined,
newbornIdCard: formData.newbornIdCard || undefined,
expectedDeliveryDate: formData.expectedDeliveryDate || undefined,
newbornDeliveryTime: formData.newbornDeliveryTime || undefined,
newbornSex: formData.newbornSex || undefined,
deliveryMode: formData.deliveryMode || undefined,
@@ -1965,8 +1979,8 @@
sc: Api.BizSampleCode.SampleCodeItem,
row: Record<string, any>
) {
if (!sc.usedInProtocol) return false
return String(row.sampleCodeId || '') !== sc.id
if (sc.usedInProtocol && String(row.sampleCodeId || '') !== sc.id) return true
return formData.samples.some((s) => s !== row && String(s.sampleCodeId || '') === sc.id)
}
function onSampleCodeChange(row: Record<string, any>) {
@@ -276,6 +276,10 @@
><div class="data-label">新生儿身份证</div
><div class="data-value">{{ dash(party?.newbornIdCard) }}</div></div
>
<div class="data-item"
><div class="data-label">预产期</div
><div class="data-value">{{ dash(party?.expectedDeliveryDate) }}</div></div
>
<div class="data-item"
><div class="data-label">新生儿分娩时间</div
><div class="data-value">{{ dash(party?.newbornDeliveryTime) }}</div></div